import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart'; import 'package:prasule/main.dart'; import 'package:prasule/network/tessdata.dart'; import 'package:prasule/pw/platformbutton.dart'; import 'package:prasule/pw/platformdialog.dart'; class TessdataListView extends StatefulWidget { const TessdataListView({super.key}); @override State createState() => _TessdataListViewState(); } class _TessdataListViewState extends State { final _tessdata = [ {"eng": true} ]; @override void didChangeDependencies() { super.didChangeDependencies(); loadAllTessdata(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("OCR data")), body: Center( child: SizedBox( width: MediaQuery.of(context).size.width * 0.9, height: MediaQuery.of(context).size.height, child: (_tessdata.length == 1) ? const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 80, height: 80, child: CircularProgressIndicator(), ), ], ) : ListView.builder( itemBuilder: (context, i) => ListTile( title: Text(_tessdata[i].keys.first), trailing: TextButton( child: Text(_tessdata[i][_tessdata[i].keys.first]! ? "Downloaded" : "Download"), onPressed: () async { var lang = _tessdata[i].keys.first; if (_tessdata[i][lang]!) { // deleting data showDialog( context: context, builder: (context) => PlatformDialog( title: "Warning", content: Text( "Do you want to delete '$lang' OCR data?\nYou will not be able to utilize this language when using the OCR functions."), actions: [ PlatformButton( text: "Yes", onPressed: () async { await TessdataApi.deleteData(lang); _tessdata[i][lang] = true; if (mounted) Navigator.of(context).pop(); }, ), PlatformButton( text: "No", onPressed: () { Navigator.of(context).pop(); }, ), ], ), ); setState(() {}); return; } // TODO: handle wifi errors //* downloading traineddata var progressStream = StreamController(); showDialog( context: context, builder: (c) => PlatformDialog( title: "Downloading $lang, please wait...", content: StreamBuilder( builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } if (snapshot.hasError) { return const Text("Error"); } return Text( "Download progress: ${snapshot.data} %"); }, stream: progressStream.stream, ), ), ); await TessdataApi.downloadData(lang, callback: (a, b) { if (progressStream.isClosed) return; var p = a / b * 1000; progressStream.add(p.roundToDouble() / 10); if (p / 10 >= 100) { logger.i("Done"); Navigator.of(context, rootNavigator: true) .pop("dialog"); _tessdata[i][lang] = true; progressStream.close(); } setState(() {}); }); }, ), ), itemCount: _tessdata.length, ), ), ), ); } /// Used to find which `.traineddata` is already downloaded and which not /// so we can show it to the user void loadAllTessdata() async { var d = await TessdataApi.getAvailableData(); var dataStatus = >[]; for (var data in d) { var e = {}; e[data] = false; dataStatus.add(e); } var appDir = Directory(await FlutterTesseractOcr.getTessdataPath()).listSync(); for (var file in appDir) { if (file is! File || !file.path.endsWith("traineddata") || file.path.endsWith("eng.traineddata")) continue; logger.i(file.path); var filename = file.path.split("/").last; dataStatus[dataStatus.indexWhere((element) => element.keys.first == filename.replaceAll(".traineddata", ""))] [filename.replaceAll(".traineddata", "")] = true; } _tessdata.addAll(dataStatus); setState(() {}); } }