Skip to content

Commit 1627506

Browse files
committed
refactor: complete app simplification and UI enhancement
- Remove terminal logging and camera preview complexity - Implement clean UI with instructional design - Maintain full OCR functionality with multi-language support - Focus on reliable image picker-based text recognition"
1 parent 86007ae commit 1627506

File tree

4 files changed

+59
-135
lines changed

4 files changed

+59
-135
lines changed

lib/camera/camera_new.dart

Lines changed: 42 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,39 @@
11
import 'dart:ui';
2-
32
import 'package:flutter/material.dart';
4-
import 'package:camera/camera.dart';
53
import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart';
64
import 'package:image_picker/image_picker.dart';
75

8-
class CameraScreen extends StatefulWidget {
9-
const CameraScreen({super.key, required this.cameras});
10-
final List<CameraDescription> cameras;
6+
class TextRecognitionScreen extends StatefulWidget {
7+
const TextRecognitionScreen({super.key});
118

129
@override
13-
_CameraScreenState createState() => _CameraScreenState();
10+
_TextRecognitionScreenState createState() => _TextRecognitionScreenState();
1411
}
1512

16-
class _CameraScreenState extends State<CameraScreen> {
17-
late CameraController _controller;
13+
class _TextRecognitionScreenState extends State<TextRecognitionScreen> {
1814
late TextRecognizer _textRecognizer;
19-
String _recognizedText = 'Tekan capture untuk scan teks';
15+
String _recognizedText = 'Pilih gambar untuk memulai scan teks';
2016
bool _isProcessing = false;
2117

2218
TextRecognitionScript _currentScript = TextRecognitionScript.latin;
2319

2420
@override
2521
void initState() {
2622
super.initState();
27-
_initializeCamera();
28-
// _textRecognizer = TextRecognizer(script: TextRecognitionScript.latin);
2923
_textRecognizer = TextRecognizer(script: _currentScript);
3024
}
3125

3226
// Method untuk ganti bahasa
3327
void _changeLanguage(TextRecognitionScript newScript) {
3428
_textRecognizer.close();
3529

36-
// buat recognizer baru dengan bahasa yang ingin dipilih
3730
setState(() {
3831
_currentScript = newScript;
3932
_textRecognizer = TextRecognizer(script: _currentScript);
4033
});
4134
}
4235

43-
void _initializeCamera() async {
44-
_controller = CameraController(
45-
widget.cameras[0],
46-
ResolutionPreset.max
47-
);
48-
49-
await _controller.initialize();
50-
if (mounted) setState(() {});
51-
}
52-
53-
void _captureAndRecognize() async {
54-
if (_isProcessing) return;
55-
56-
setState(() {
57-
_isProcessing = true;
58-
_recognizedText = 'Memproses gambar...';
59-
});
60-
61-
try {
62-
final XFile picture = await _controller.takePicture();
63-
await _processImageForTextRecognition(picture.path);
64-
final inputImage = InputImage.fromFilePath(picture.path);
65-
final RecognizedText recognizedText = await _textRecognizer.processImage(inputImage);
66-
67-
String fullText = '';
68-
for (TextBlock block in recognizedText.blocks) {
69-
for (TextLine line in block.lines) {
70-
fullText += '${line.text}\n';
71-
}
72-
}
73-
74-
setState(() {
75-
_recognizedText = fullText.isEmpty ? 'Tidak ada teks terdeteksi' : fullText;
76-
});
77-
} catch (e) {
78-
setState(() {
79-
_recognizedText = 'Error: $e';
80-
});
81-
} finally {
82-
setState(() => _isProcessing = false);
83-
}
84-
}
85-
86-
void _showLanguageSelection() { // Dialog Language Selection
36+
void _showLanguageSelection() {
8737
showDialog(
8838
barrierDismissible: false,
8939
context: context,
@@ -139,7 +89,7 @@ class _CameraScreenState extends State<CameraScreen> {
13989
);
14090
}
14191

142-
// memilih sumber gambar
92+
// memilih sumber gambar (galeri atau camera)
14393
void _showImageSourceSelection() {
14494
showModalBottomSheet(
14595
context: context,
@@ -177,10 +127,9 @@ class _CameraScreenState extends State<CameraScreen> {
177127
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
178128

179129
if (image != null) {
180-
_processImageForTextRecognition(image.path);
130+
await _processImageForTextRecognition(image.path);
181131
}
182132
} catch (e) {
183-
print('Error picking image from gallery: $e');
184133
setState(() {
185134
_recognizedText = 'Error: Gagal memilih gambar dari galeri';
186135
});
@@ -194,17 +143,16 @@ class _CameraScreenState extends State<CameraScreen> {
194143
final XFile? image = await picker.pickImage(source: ImageSource.camera);
195144

196145
if (image != null) {
197-
_processImageForTextRecognition(image.path);
146+
await _processImageForTextRecognition(image.path);
198147
}
199148
} catch (e) {
200-
print('Error taking picture: $e');
201149
setState(() {
202150
_recognizedText = 'Error: Gagal mengambil gambar';
203151
});
204152
}
205153
}
206154

207-
// memproses gambar dan print ke terminal
155+
// memproses gambar
208156
Future<void> _processImageForTextRecognition(String imagePath) async {
209157
if (_isProcessing) return;
210158

@@ -215,49 +163,23 @@ class _CameraScreenState extends State<CameraScreen> {
215163

216164
try {
217165
final inputImage = InputImage.fromFilePath(imagePath);
218-
final textRecognizer = TextRecognizer(
219-
script: TextRecognitionScript.latin,
220-
);
221-
final RecognizedText recognizedText = await textRecognizer.processImage(
222-
inputImage,
223-
);
224-
166+
final RecognizedText recognizedText = await _textRecognizer.processImage(inputImage);
225167
String fullText = '';
226168

227-
// Loop melalui semua blok teks yang terdeteksi
169+
// gunakan variable recognizedText untuk ekstraksi teks
228170
for (TextBlock block in recognizedText.blocks) {
229-
print('=== BLOCK TEXT ===');
230-
print(block.text);
231-
print('==================');
232-
233171
for (TextLine line in block.lines) {
234172
fullText += '${line.text}\n';
235-
236-
// Print setiap line ke terminal
237-
print('Line: ${line.text}');
238-
239-
// Jika ingin detail lebih lanjut, bisa print setiap element
240-
for (TextElement element in line.elements) {
241-
print(' Element: ${element.text}');
242-
}
243173
}
244174
}
245175

246-
// Print keseluruhan teks ke terminal
247-
print('=== HASIL EKSTRAKSI TEKS LENGKAP ===');
248-
print(fullText);
249-
print('=====================================');
250-
251176
setState(() {
252177
_recognizedText = fullText.isEmpty
253178
? 'Tidak ada teks terdeteksi'
254179
: fullText;
255180
});
256181

257-
// Tutup text recognizer untuk menghindari memory leak
258-
textRecognizer.close();
259182
} catch (e) {
260-
print('Error processing image: $e');
261183
setState(() {
262184
_recognizedText = 'Error: Gagal memproses gambar';
263185
});
@@ -268,19 +190,14 @@ class _CameraScreenState extends State<CameraScreen> {
268190

269191
@override
270192
Widget build(BuildContext context) {
271-
if (!_controller.value.isInitialized) {
272-
return const Scaffold(
273-
body: Center(child: CircularProgressIndicator()),
274-
);
275-
}
276-
277193
return Scaffold(
278194
appBar: AppBar(
195+
backgroundColor: Colors.blue,
279196
actions: [
280-
DropdownButton<TextRecognitionScript>( //* Dropdown button untuk pilihan bahasa
197+
DropdownButton<TextRecognitionScript>(
281198
value: _currentScript,
282199
icon: const Icon(Icons.language, color: Colors.black),
283-
dropdownColor: Colors.blue,
200+
dropdownColor: Colors.white,
284201
onChanged: (TextRecognitionScript? newScript) {
285202
if (newScript != null) {
286203
_changeLanguage(newScript);
@@ -309,19 +226,35 @@ class _CameraScreenState extends State<CameraScreen> {
309226
),
310227
],
311228
),
312-
const SizedBox(width: 20),
229+
const SizedBox(width: 16),
313230
],
314231
),
315232
body: Column(
316233
children: [
317-
Expanded(
318-
flex: 3,
319-
child: CameraPreview(_controller),
234+
// Header dengan instruksi
235+
Container(
236+
padding: const EdgeInsets.all(16),
237+
child: const Column(
238+
children: [
239+
SizedBox(height: 8),
240+
Text(
241+
'Pilih gambar dari galeri atau ambil foto baru untuk mengekstrak teks',
242+
textAlign: TextAlign.center,
243+
style: TextStyle(fontSize: 14, color: Colors.grey),
244+
),
245+
],
246+
),
320247
),
248+
249+
// Area hasil teks
321250
Expanded(
322-
flex: 1,
323251
child: Container(
252+
margin: const EdgeInsets.all(16),
324253
padding: const EdgeInsets.all(16),
254+
decoration: BoxDecoration(
255+
border: Border.all(color: Colors.grey.shade400),
256+
borderRadius: BorderRadius.circular(12),
257+
),
325258
child: SingleChildScrollView(
326259
child: Text(
327260
_recognizedText,
@@ -333,29 +266,23 @@ class _CameraScreenState extends State<CameraScreen> {
333266
],
334267
),
335268
floatingActionButton: Padding(
336-
padding: const EdgeInsets.only(left: 30),
269+
padding: const EdgeInsets.only(bottom: 20),
337270
child: Row(
338271
mainAxisAlignment: MainAxisAlignment.center,
339272
children: [
340-
FloatingActionButton(
341-
onPressed: _captureAndRecognize,
342-
backgroundColor: _isProcessing ? Colors.grey: Colors.blue,
343-
elevation: 20, // biar ada shadow effect pada icon
344-
child: _isProcessing
345-
? const CircularProgressIndicator(color: Colors.white)
346-
: const Icon(Icons.camera)
347-
),
348273
const SizedBox(width: 20),
349274
FloatingActionButton(
350275
onPressed: _showImageSourceSelection,
351-
backgroundColor: Colors.green,
352-
child: const Icon(Icons.photo_library)
276+
backgroundColor: Colors.blue,
277+
elevation: 10,
278+
child: const Icon(Icons.add_photo_alternate, color: Colors.black)
353279
),
354280
const SizedBox(width: 20),
355281
FloatingActionButton(
356282
onPressed: _showLanguageSelection,
357283
backgroundColor: Colors.orange,
358-
child: const Icon(Icons.language)
284+
elevation: 10,
285+
child: const Icon(Icons.language, color: Colors.black)
359286
),
360287
],
361288
),
@@ -365,7 +292,6 @@ class _CameraScreenState extends State<CameraScreen> {
365292

366293
@override
367294
void dispose() {
368-
_controller.dispose();
369295
_textRecognizer.close();
370296
super.dispose();
371297
}

lib/main.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ Future<void> main() async {
1111
await Permission.camera.request(); // permission_handler
1212
await Permission.storage.request();
1313

14-
cameras = await availableCameras();
1514
runApp(const MyApp());
1615
}
1716

@@ -20,10 +19,9 @@ class MyApp extends StatelessWidget {
2019

2120
@override
2221
Widget build(BuildContext context) {
23-
return MaterialApp(
22+
return const MaterialApp(
2423
debugShowCheckedModeBanner: false,
25-
title: 'Flutter Text Recognition',
26-
home: CameraScreen(cameras: cameras),
24+
home: TextRecognitionScreen(),
2725
);
2826
}
2927
}

pubspec.lock

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,34 +45,34 @@ packages:
4545
dependency: "direct main"
4646
description:
4747
name: camera
48-
sha256: "87a27e0553e3432119c1c2f6e4b9a1bbf7d2c660552b910bfa59185a9facd632"
48+
sha256: eefad89f262a873f38d21e5eec853461737ea074d7c9ede39f3ceb135d201cab
4949
url: "https://pub.dev"
5050
source: hosted
51-
version: "0.11.2+1"
51+
version: "0.11.3"
5252
camera_android_camerax:
5353
dependency: transitive
5454
description:
5555
name: camera_android_camerax
56-
sha256: dfa51247e911c5171d5d96327250b00cd4424c7e9874c1becb37447d530a6546
56+
sha256: b68b638e5e0ede21155e670493ac568981a8f56c5f636d720935a916a1c5a0ef
5757
url: "https://pub.dev"
5858
source: hosted
59-
version: "0.6.23+4"
59+
version: "0.6.24"
6060
camera_avfoundation:
6161
dependency: transitive
6262
description:
6363
name: camera_avfoundation
64-
sha256: "75bd22c0cf97d89a528d505e0f10bc8a0d08f0e218ca999812af1076c72d5907"
64+
sha256: "34bcd5db30e52414f1f0783c5e3f566909fab14141a21b3b576c78bd35382bf6"
6565
url: "https://pub.dev"
6666
source: hosted
67-
version: "0.9.22+3"
67+
version: "0.9.22+4"
6868
camera_platform_interface:
6969
dependency: transitive
7070
description:
7171
name: camera_platform_interface
72-
sha256: ea1ef6ba79cdbed93df2d3eeef11542a90dec24dbcd9cde574926b86d7a09a10
72+
sha256: "98cfc9357e04bad617671b4c1f78a597f25f08003089dd94050709ae54effc63"
7373
url: "https://pub.dev"
7474
source: hosted
75-
version: "2.11.0"
75+
version: "2.12.0"
7676
camera_web:
7777
dependency: transitive
7878
description:
@@ -125,18 +125,18 @@ packages:
125125
dependency: transitive
126126
description:
127127
name: cross_file
128-
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
128+
sha256: "942a4791cd385a68ccb3b32c71c427aba508a1bb949b86dff2adbe4049f16239"
129129
url: "https://pub.dev"
130130
source: hosted
131-
version: "0.3.4+2"
131+
version: "0.3.5"
132132
crypto:
133133
dependency: transitive
134134
description:
135135
name: crypto
136-
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
136+
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
137137
url: "https://pub.dev"
138138
source: hosted
139-
version: "3.0.6"
139+
version: "3.0.7"
140140
csslib:
141141
dependency: transitive
142142
description:
@@ -300,10 +300,10 @@ packages:
300300
dependency: transitive
301301
description:
302302
name: image_picker_android
303-
sha256: "58a85e6f09fe9c4484d53d18a0bd6271b72c53fce1d05e6f745ae36d8c18efca"
303+
sha256: ca2a3b04d34e76157e9ae680ef16014fb4c2d20484e78417eaed6139330056f6
304304
url: "https://pub.dev"
305305
source: hosted
306-
version: "0.8.13+5"
306+
version: "0.8.13+7"
307307
image_picker_for_web:
308308
dependency: transitive
309309
description:

0 commit comments

Comments
 (0)