Add mobile reliability fixes, Bahasa Indonesia UI, and continue OCR accuracy tuning
Reliability/PoC hardening: dedupe uploads by file_hash, surface editor sync failures instead of a false success SnackBar with a retry-without-re-OCR path, bound the OCR pipeline fetches with timeouts, share a single ApiClient/Dio instance app-wide, tune capture JPEG quality, and add an opt-in docker-compose.demo.yml for a production-mode run ahead of client demos. Translate all Flutter-side user-facing text (screens, validators, SnackBars, the printed delivery receipt, and shared API error messages) to Bahasa Indonesia. Also includes in-progress OCR parser/accuracy-tuning work from the same session: table column/unit normalization fixes, store/customer master data, accuracy history log, and test-image renaming/cleanup. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eRAsLqN9Sg1b9YPz22Lxz
This commit is contained in:
1 parent
095dd4cb8b
commit
4808a798fb
78 files changed
+8069
-584
No files matched your search
@@ -6,7 +6,7 @@ import '../../core/location/location_service.dart';
|
||||
import '../../core/network/api_client.dart';
|
||||
import '../../config/app_config.dart';
|
||||
|
||||
enum PendingDocumentStatus { uploading, processing, success, error }
|
||||
enum PendingDocumentStatus { uploading, processing, success, error, syncFailed }
|
||||
|
||||
class PendingDocument {
|
||||
final String id;
|
||||
@@ -50,7 +50,9 @@ class PendingDocument {
|
||||
}
|
||||
|
||||
class PendingDocumentsNotifier extends StateNotifier<List<PendingDocument>> {
|
||||
PendingDocumentsNotifier() : super([]);
|
||||
PendingDocumentsNotifier(this._ref) : super([]);
|
||||
|
||||
final Ref _ref;
|
||||
|
||||
void addDocument(String imagePath, {double? latitude, double? longitude}) {
|
||||
final id = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
@@ -96,7 +98,7 @@ class PendingDocumentsNotifier extends StateNotifier<List<PendingDocument>> {
|
||||
|
||||
try {
|
||||
// API call to upload and process
|
||||
final apiClient = ApiClient();
|
||||
final apiClient = _ref.read(apiClientProvider);
|
||||
final formData = FormData.fromMap({
|
||||
'image': await MultipartFile.fromFile(
|
||||
imagePath,
|
||||
@@ -192,7 +194,56 @@ class PendingDocumentsNotifier extends StateNotifier<List<PendingDocument>> {
|
||||
void removeDocument(String id) {
|
||||
state = state.where((item) => item.id != id).toList();
|
||||
}
|
||||
|
||||
|
||||
/// Marks a pending item as failed to sync after an editor save, keeping the
|
||||
/// finalized [doc] so [retrySync] can resend it without re-running OCR.
|
||||
void markSyncFailed(String id, DocumentModel doc, String message) {
|
||||
state = [
|
||||
for (final item in state)
|
||||
if (item.id == id)
|
||||
item.copyWith(status: PendingDocumentStatus.syncFailed, document: doc, errorMessage: message)
|
||||
else
|
||||
item
|
||||
];
|
||||
}
|
||||
|
||||
/// Resends a previously-failed editor save. Unlike [retryUpload], this never
|
||||
/// re-uploads the image or re-runs OCR - it only retries the PUT with the
|
||||
/// already-corrected [PendingDocument.document].
|
||||
Future<void> retrySync(String id) async {
|
||||
final matches = state.where((item) => item.id == id);
|
||||
if (matches.isEmpty) return;
|
||||
final doc = matches.first.document;
|
||||
if (doc == null) return;
|
||||
|
||||
state = [
|
||||
for (final item in state)
|
||||
if (item.id == id)
|
||||
item.copyWith(status: PendingDocumentStatus.uploading, errorMessage: null)
|
||||
else
|
||||
item
|
||||
];
|
||||
|
||||
try {
|
||||
final apiClient = _ref.read(apiClientProvider);
|
||||
await apiClient.client.put(
|
||||
'${AppConfig.fetchDocumentsEndpoint}/${doc.id}',
|
||||
data: doc.toPutPayload(),
|
||||
);
|
||||
if (!mounted) return;
|
||||
removeDocument(id);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
state = [
|
||||
for (final item in state)
|
||||
if (item.id == id)
|
||||
item.copyWith(status: PendingDocumentStatus.syncFailed, errorMessage: 'Gagal sinkronisasi ke server: ${e.toString()}')
|
||||
else
|
||||
item
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
void retryUpload(String id) {
|
||||
final doc = state.firstWhere((item) => item.id == id);
|
||||
final lat = doc.latitude;
|
||||
@@ -212,5 +263,5 @@ class PendingDocumentsNotifier extends StateNotifier<List<PendingDocument>> {
|
||||
}
|
||||
|
||||
final pendingDocumentsProvider = StateNotifierProvider<PendingDocumentsNotifier, List<PendingDocument>>((ref) {
|
||||
return PendingDocumentsNotifier();
|
||||
return PendingDocumentsNotifier(ref);
|
||||
});
|
||||
Reference in new issue
Block a user