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

+73 -3
View File
@@ -3,6 +3,19 @@ import 'package:geolocator/geolocator.dart';
class LocationService {
static Future<Position?> Function()? mockDeterminator;
static Stream<Position>? mockStream;
static Stream<Position> getPositionStream() {
if (mockStream != null) {
return mockStream!;
}
return Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 1, // update only when moved 1 meter
),
);
}
static Future<Position?> determinePosition() async {
if (mockDeterminator != null) {
@@ -29,14 +42,70 @@ class LocationService {
return null;
}
// Strategy 1: Try balanced/network-based location (fast, works indoors)
try {
return await Geolocator.getCurrentPosition(
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.medium,
timeLimit: const Duration(seconds: 7),
);
debugPrint(
'GPS balanced/indoor fix: ${position.latitude}, ${position.longitude} '
'(accuracy: ${position.accuracy.toStringAsFixed(1)}m)',
);
return position;
} catch (e) {
debugPrint('getCurrentPosition balanced failed: $e. Trying high accuracy...');
}
// Strategy 2: Try high accuracy (GPS satellites) with forceAndroidLocationManager to bypass cache
try {
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
forceAndroidLocationManager: true,
timeLimit: const Duration(seconds: 10),
);
debugPrint(
'GPS high fix: ${position.latitude}, ${position.longitude} '
'(accuracy: ${position.accuracy.toStringAsFixed(1)}m)',
);
return position;
} catch (e) {
debugPrint('getCurrentPosition high failed: $e. Checking last known position...');
}
// Strategy 3: Use last known position ONLY if it is super recent (within 2 minutes)
final lastKnown = await Geolocator.getLastKnownPosition();
if (lastKnown != null) {
final age = DateTime.now().difference(lastKnown.timestamp);
if (age.inMinutes <= 2) {
debugPrint(
'Using recent last-known position (${age.inSeconds}s old): '
'${lastKnown.latitude}, ${lastKnown.longitude}',
);
return lastKnown;
}
debugPrint(
'Last-known position is too stale (${age.inMinutes}m old) — '
'retrying low accuracy GPS fix...',
);
}
// Strategy 4: Last resort — bypass Google Fused Location and try low accuracy
// forceAndroidLocationManager forces a real hardware GPS read if enabled
try {
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.low,
forceAndroidLocationManager: true,
timeLimit: const Duration(seconds: 5),
);
debugPrint(
'GPS low fix via LocationManager: ${position.latitude}, ${position.longitude} '
'(accuracy: ${position.accuracy.toStringAsFixed(1)}m)',
);
return position;
} catch (e) {
debugPrint('getCurrentPosition failed: $e. Attempting getLastKnownPosition...');
return await Geolocator.getLastKnownPosition();
debugPrint('All GPS strategies failed: $e');
return null;
}
} catch (e) {
debugPrint('Error in LocationService: $e');
@@ -44,3 +113,4 @@ class LocationService {
}
}
}