summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorxAlpharax <42233094+xAlpharax@users.noreply.github.com>2023-09-28 19:02:06 +0300
committerxAlpharax <42233094+xAlpharax@users.noreply.github.com>2023-09-28 19:02:06 +0300
commit7606ef1d9872ca0466e57779aeaf0ce690cac69b (patch)
tree65c985972734ed2bb146abd578eaf8ced3c2eb1e /lib
parent549a51b021217a25426625a962ede562bb069191 (diff)
Getting basic functionalities over from the OCR app like the camera.
Changes to be committed: modified: lib/main.dart new file: lib/result_screen.dart modified: pubspec.lock modified: pubspec.yaml modified: test/widget_test.dart
Diffstat (limited to 'lib')
-rw-r--r--lib/main.dart284
-rw-r--r--lib/result_screen.dart19
2 files changed, 232 insertions, 71 deletions
diff --git a/lib/main.dart b/lib/main.dart
index d7cd012..30c90ef 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,107 +1,249 @@
import 'package:camera/camera.dart';
import 'package:permission_handler/permission_handler.dart';
+import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart';
+import 'package:google_mlkit_object_detection/google_mlkit_object_detection.dart';
import 'package:flutter_tflite/flutter_tflite.dart';
import 'package:flutter_tts/flutter_tts.dart';
+import 'package:yolo/result_screen.dart';
import 'package:flutter/material.dart';
import 'dart:io';
void main() {
- runApp(const MyApp());
+ runApp(const App());
}
-class MyApp extends StatelessWidget {
- const MyApp({super.key});
+class App extends StatelessWidget {
+ const App({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: 'Flutter Demo',
+ title: 'MegaView',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurpleAccent),
useMaterial3: true,
),
debugShowCheckedModeBanner: false,
- home: const MyHomePage(title: 'Flutter Demo Home Page'),
+ home: const MainScreen(),
);
}
}
-class MyHomePage extends StatefulWidget {
- const MyHomePage({super.key, required this.title});
-
- final String title;
+class MainScreen extends StatefulWidget {
+ const MainScreen({super.key});
@override
- State<MyHomePage> createState() => _MyHomePageState();
+ State<MainScreen> createState() => _MainScreenState();
}
-class _MyHomePageState extends State<MyHomePage> {
- int _counter = 0;
-
- void _incrementCounter() {
- setState(() {
- // This call to setState tells the Flutter framework that something has
- // changed in this State, which causes it to rerun the build method below
- // so that the display can reflect the updated values. If we changed
- // _counter without calling setState(), then the build method would not be
- // called again, and so nothing would appear to happen.
- _counter++;
- });
+class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
+ bool _isPermissionGranted = false;
+
+ late final Future<void> _future;
+ CameraController? _cameraController;
+
+ final textRecognizer = TextRecognizer();
+
+ FlutterTts flutterTts = FlutterTts(); // TTS
+
+ @override
+ void initState() {
+ super.initState();
+ initTTS(); // TTS
+
+ WidgetsBinding.instance.addObserver(this);
+
+ _future = _requestCameraPermission();
+ }
+
+ Future<void> initTTS() async { // TTS
+ await flutterTts.setLanguage("en-US"); // Set the language you want
+ await flutterTts.setSpeechRate(0.5); // Adjust speech rate (1.0 is normal but too fast for my liking)
+ await flutterTts.setVolume(1.0); // Adjust volume (0.0 to 1.0)
+ await flutterTts.setPitch(1.0); // Adjust pitch (1.0 is normal)
+
+ // You can set other configurations as well
+
+ // Check if TTS is available
+ // bool isAvailable = await flutterTts.isLanguageAvailable("en-US");
+ // print("TTS is available: $isAvailable");
+ }
+
+ Future<void> speak(String text) async {
+ await flutterTts.speak(text); // TTS
+ }
+
+ @override
+ void dispose() {
+ WidgetsBinding.instance.removeObserver(this);
+ _stopCamera();
+ textRecognizer.close();
+ flutterTts.stop(); // TTS Stop
+ super.dispose();
+ }
+
+ @override
+ void didChangeAppLifecycleState(AppLifecycleState state) {
+ if (_cameraController == null || !_cameraController!.value.isInitialized) {
+ return;
+ }
+
+ if (state == AppLifecycleState.inactive) {
+ _stopCamera();
+ } else if (state == AppLifecycleState.resumed &&
+ _cameraController != null &&
+ _cameraController!.value.isInitialized) {
+ _startCamera();
+ }
}
@override
Widget build(BuildContext context) {
- // This method is rerun every time setState is called, for instance as done
- // by the _incrementCounter method above.
- //
- // The Flutter framework has been optimized to make rerunning build methods
- // fast, so that you can just rebuild anything that needs updating rather
- // than having to individually change instances of widgets.
- return Scaffold(
- appBar: AppBar(
- // TRY THIS: Try changing the color here to a specific color (to
- // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
- // change color while the other colors stay the same.
- backgroundColor: Theme.of(context).colorScheme.inversePrimary,
- // Here we take the value from the MyHomePage object that was created by
- // the App.build method, and use it to set our appbar title.
- title: Text(widget.title),
- ),
- body: Center(
- // Center is a layout widget. It takes a single child and positions it
- // in the middle of the parent.
- child: Column(
- // Column is also a layout widget. It takes a list of children and
- // arranges them vertically. By default, it sizes itself to fit its
- // children horizontally, and tries to be as tall as its parent.
- //
- // Column has various properties to control how it sizes itself and
- // how it positions its children. Here we use mainAxisAlignment to
- // center the children vertically; the main axis here is the vertical
- // axis because Columns are vertical (the cross axis would be
- // horizontal).
- //
- // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
- // action in the IDE, or press "p" in the console), to see the
- // wireframe for each widget.
- mainAxisAlignment: MainAxisAlignment.center,
- children: <Widget>[
- const Text(
- 'You have pushed the button this many times:',
- ),
- Text(
- '$_counter',
- style: Theme.of(context).textTheme.headlineMedium,
+ return FutureBuilder(
+ future: _future,
+ builder: (context, snapshot) {
+ return Stack(
+ children: [
+ if (_isPermissionGranted)
+ FutureBuilder<List<CameraDescription>>(
+ future: availableCameras(),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ _initCameraController(snapshot.data!);
+
+ return Center(child: CameraPreview(_cameraController!));
+ } else {
+ return const LinearProgressIndicator();
+ }
+ },
+ ),
+ Scaffold(
+ appBar: AppBar(
+ backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+ title: const Text('MegaView Text Recognition'),
+ ),
+ backgroundColor: _isPermissionGranted ? Colors.transparent : null,
+ body: _isPermissionGranted
+ ? Column(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Container(),
+ Container(
+ color: Theme.of(context).colorScheme.inversePrimary,
+ alignment: Alignment.center,
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8.0),
+ child: ElevatedButton(
+ onPressed: _scanImage,
+ style: ButtonStyle(
+ minimumSize: MaterialStateProperty.all<Size>(
+ const Size(256, 64), // Set the desired width and height
+ ),
+ ),
+ child: const Text('Scan text'),
+ ),
+ ),
+ ),
+ ],
+ )
+ : Center(
+ child: Container(
+ padding: const EdgeInsets.only(left: 24.0, right: 24.0),
+ child: const Text(
+ 'Camera permission denied',
+ textAlign: TextAlign.center,
+ ),
+ ),
+ ),
),
],
- ),
- ),
- floatingActionButton: FloatingActionButton(
- onPressed: _incrementCounter,
- tooltip: 'Increment',
- child: const Icon(Icons.add),
- ), // This trailing comma makes auto-formatting nicer for build methods.
+ );
+ },
);
}
-}
+
+ Future<void> _requestCameraPermission() async {
+ final status = await Permission.camera.request();
+ _isPermissionGranted = status == PermissionStatus.granted;
+ }
+
+ void _startCamera() {
+ if (_cameraController != null) {
+ _cameraSelected(_cameraController!.description);
+ }
+ }
+
+ void _stopCamera() {
+ if (_cameraController != null) {
+ _cameraController?.dispose();
+ }
+ }
+
+ void _initCameraController(List<CameraDescription> cameras) {
+ if (_cameraController != null) {
+ return;
+ }
+
+ // Select the first rear camera.
+ CameraDescription? camera;
+ for (var i = 0; i < cameras.length; i++) {
+ final CameraDescription current = cameras[i];
+ if (current.lensDirection == CameraLensDirection.back) {
+ camera = current;
+ break;
+ }
+ }
+
+ if (camera != null) {
+ _cameraSelected(camera);
+ }
+ }
+
+ Future<void> _cameraSelected(CameraDescription camera) async {
+ _cameraController = CameraController(
+ camera,
+ ResolutionPreset.high,
+ enableAudio: false,
+ );
+
+ await _cameraController!.initialize();
+ await _cameraController!.setFlashMode(FlashMode.off);
+
+ if (!mounted) {
+ return;
+ }
+ setState(() {});
+ }
+
+ Future<void> _scanImage() async {
+ if (_cameraController == null) return;
+
+ final navigator = Navigator.of(context);
+
+ try {
+ final pictureFile = await _cameraController!.takePicture();
+
+ final file = File(pictureFile.path);
+
+ final inputImage = InputImage.fromFile(file);
+ final recognizedText = await textRecognizer.processImage(inputImage);
+
+ speak(recognizedText.text);
+
+ await navigator.push(
+ MaterialPageRoute(
+ builder: (BuildContext context) =>
+ ResultScreen(text: recognizedText.text)
+ ),
+ );
+ } catch (e) {
+ // ignore: use_build_context_synchronously
+ ScaffoldMessenger.of(context).showSnackBar(
+ const SnackBar(
+ content: Text('An error occurred when scanning text'),
+ ),
+ );
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/result_screen.dart b/lib/result_screen.dart
new file mode 100644
index 0000000..d5a64ea
--- /dev/null
+++ b/lib/result_screen.dart
@@ -0,0 +1,19 @@
+import 'package:flutter/material.dart';
+
+class ResultScreen extends StatelessWidget {
+ final String text;
+
+ const ResultScreen({super.key, required this.text});
+
+ @override
+ Widget build(BuildContext context) => Scaffold(
+ appBar: AppBar(
+ //backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+ title: const Text('Result'),
+ ),
+ body: Container(
+ padding: const EdgeInsets.all(30.0),
+ child: Text(text),
+ ),
+ );
+} \ No newline at end of file