feat: update backend OCR parser, web app, mobile app camera/preview UI, tests, and documentation with sample images

This commit is contained in:
Rafhan Mazaya Fathurrahman committed 2026-07-02 13:33:57 +07:00
1 parent aa3233e411
commit bdb3a49742
71 files changed
+3360 -764

No files matched your search

+1 -64
View File
@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:image/image.dart' as img;
import '../../config/app_config.dart';
import '../documents/pending_documents_provider.dart';
import 'blur_detector.dart';
@@ -162,51 +161,7 @@ class _ImagePreviewScreenState extends ConsumerState<ImagePreviewScreen> {
}
}
Future<void> _rotateImage() async {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const Center(
child: CircularProgressIndicator(color: AppConfig.primaryColor),
),
);
try {
final bytes = await File(_currentImagePath).readAsBytes();
final decoded = img.decodeImage(bytes);
if (decoded != null) {
// Rotate 90 degrees clockwise
final rotated = img.copyRotate(decoded, angle: 90);
final encoded = img.encodeJpg(rotated);
final dir = Directory(_currentImagePath).parent.path;
final name = _currentImagePath.split('/').last.split('\\').last;
final newPath = '$dir/rotated_${DateTime.now().millisecondsSinceEpoch}_$name';
await File(newPath).writeAsBytes(encoded);
// Delete old rotated files to prevent memory leaks/leftovers
if (_currentImagePath.contains('rotated_')) {
try {
await File(_currentImagePath).delete();
} catch (_) {}
}
if (mounted) {
setState(() {
_currentImagePath = newPath;
_analyzing = true;
});
Navigator.pop(context); // Close loading dialog
_detectBlur(); // Re-run blur analysis
}
} else {
if (mounted) Navigator.pop(context);
}
} catch (e) {
if (mounted) Navigator.pop(context);
}
}
@override
Widget build(BuildContext context) {
@@ -214,13 +169,6 @@ class _ImagePreviewScreenState extends ConsumerState<ImagePreviewScreen> {
backgroundColor: AppConfig.backgroundColor,
appBar: AppBar(
title: const Text('Konfirmasi Foto'),
actions: [
IconButton(
icon: const Icon(Icons.rotate_right),
onPressed: _rotateImage,
tooltip: 'Putar 90°',
),
],
),
body: SafeArea(
child: Column(
@@ -259,17 +207,6 @@ class _ImagePreviewScreenState extends ConsumerState<ImagePreviewScreen> {
),
),
),
Positioned(
bottom: 24,
right: 24,
child: FloatingActionButton.small(
heroTag: 'rotate_button',
backgroundColor: Colors.white.withOpacity(0.9),
foregroundColor: AppConfig.primaryColor,
onPressed: _rotateImage,
child: const Icon(Icons.rotate_right),
),
),
],
),
),
@@ -346,7 +283,7 @@ class _ImagePreviewScreenState extends ConsumerState<ImagePreviewScreen> {
// Confirm & Sync Button
Expanded(
child: ElevatedButton(
onPressed: (!_analyzing && _blurResult != null && !_blurResult!.isBlur) ? () {
onPressed: !_analyzing ? () {
ref.read(pendingDocumentsProvider.notifier).addDocument(
_currentImagePath,
latitude: widget.latitude,