import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import 'package:signature/signature.dart'; class TimedPoint { final DateTime time; final Point point; const TimedPoint({ required this.time, required this.point, }); } class HandwritingRequest { final double appVersion; final String apiLevel; String? device; final int inputType; final String options; final int writingAreaWidth; final int writingAreaHeight; final String preContext; final int maxNumResults; final int maxCompletions; final String language; final List> ink; HandwritingRequest({ this.appVersion = 0.4, this.apiLevel = '537.36', this.device, this.inputType = 0, this.options = 'enable_pre_space', required this.writingAreaWidth, required this.writingAreaHeight, this.preContext = '', this.maxNumResults = 10, this.maxCompletions = 0, this.language = 'ja', required this.ink, }); List> get formattedInk => ink .map( (stroke) => [ stroke.map((tp) => tp.point.offset.dx).toList(), stroke.map((tp) => tp.point.offset.dy).toList(), stroke .map((tp) => tp.time.difference(stroke.first.time).inMilliseconds) .toList(), ], ) .toList(); Map toJson() => { 'app_version': appVersion, 'api_level': apiLevel, 'device': device, 'input_type': inputType, 'options': options, 'requests': [ { 'writing_guide': { 'writing_area_width': writingAreaWidth, 'writing_area_height': writingAreaHeight }, 'pre_context': preContext, 'max_num_results': maxNumResults, 'max_completions': maxCompletions, 'language': language, 'ink': formattedInk, } ] }; Future> fetch() async { device ??= HttpClient().userAgent; final response = await http.post( Uri.parse( 'https://inputtools.google.com/request?itc=ja-t-i0-handwrit&app=translate', ), headers: { 'Content-Type': 'application/json; charset=UTF-8', }, body: jsonEncode(this), ); final List json = jsonDecode(response.body); // TODO: add a more detailed error. if (response.statusCode != 200 || json[0] != 'SUCCESS') throw Error(); return (((json[1] as List)[0] as List)[1] as List) .map((e) => e as String) .toList(); } }