first commit
This commit is contained in:
commit
e630f2a3ec
80 changed files with 3889 additions and 0 deletions
93
README.md
Normal file
93
README.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Fuel Tax Tracker
|
||||
|
||||
A Flutter app (Android + iOS) for logging fuel purchases per vehicle. Snap a
|
||||
photo of a gas receipt, it OCRs the gallons/price-per-gallon/total on-device,
|
||||
you confirm or correct the numbers, and it's saved alongside the receipt
|
||||
photo to a data file in a folder you choose.
|
||||
|
||||
## Features
|
||||
|
||||
- Manage a list of vehicles (make, model, color, license plate).
|
||||
- Capture a fuel receipt photo per vehicle and OCR it on-device with Google
|
||||
ML Kit — no internet connection or API key required.
|
||||
- Review/edit the parsed gallons, price per gallon, and total cost before
|
||||
saving (OCR on printed receipts is usually good but not perfect).
|
||||
- Per-vehicle fuel log with running gallons total, tap-to-zoom receipt
|
||||
photos, and delete.
|
||||
- Settings screen to choose where receipt photos and the data file are
|
||||
stored (defaults to the app's own documents folder; existing data is
|
||||
copied over when you change it).
|
||||
|
||||
## Project layout
|
||||
|
||||
```
|
||||
lib/
|
||||
models/ Vehicle, FuelEntry — plain data classes with JSON (de)serialization
|
||||
services/
|
||||
app_state.dart In-memory state + CRUD, backed by StorageService, exposed via Provider
|
||||
storage_service.dart Owns the data.json file + receipts/ folder and the configurable save path
|
||||
ocr_service.dart Thin wrapper around google_mlkit_text_recognition
|
||||
receipt_parser.dart Regex-based extraction of gallons/price/total from OCR text
|
||||
screens/ One file per screen (vehicle list, add/edit vehicle, vehicle detail,
|
||||
confirm fuel entry, receipt viewer, settings)
|
||||
```
|
||||
|
||||
Data is stored as a single `fuel_tax_data.json` file plus a `receipts/`
|
||||
subfolder of photos, both inside whatever directory Settings points at.
|
||||
|
||||
## Running it
|
||||
|
||||
```
|
||||
flutter pub get
|
||||
flutter run # with a device/emulator connected or a simulator booted
|
||||
```
|
||||
|
||||
To build release artifacts:
|
||||
|
||||
```
|
||||
flutter build apk --release # Android
|
||||
flutter build ios --release # iOS (requires a full Xcode install + signing setup)
|
||||
```
|
||||
|
||||
This was scaffolded and verified with Flutter 3.44.9. `flutter analyze` and
|
||||
`flutter test` are clean, and `flutter build apk --debug` has been confirmed
|
||||
to produce a working APK.
|
||||
|
||||
## Permissions
|
||||
|
||||
- **Camera**: `NSCameraUsageDescription` (iOS, `ios/Runner/Info.plist`) and
|
||||
`android.permission.CAMERA` (Android, `AndroidManifest.xml`) are already
|
||||
set up for receipt capture.
|
||||
- **Storage**: no explicit storage permission is declared. The default save
|
||||
location is inside the app's own sandbox (no permission needed). If you
|
||||
point Settings at a location outside the sandbox, the OS-native folder
|
||||
picker (via `file_picker`) is what grants access — see the caveat below.
|
||||
|
||||
## Known caveats / things to revisit
|
||||
|
||||
- **`file_picker` is pinned to `10.3.10`**, not the latest release. Versions
|
||||
11.0.0–11.0.3 skip applying the Kotlin Gradle plugin when they detect AGP
|
||||
9+ (assuming AGP's built-in Kotlin support handles it), but that isn't
|
||||
actually wired up for library modules in this Flutter/AGP combination yet,
|
||||
so the plugin's own Kotlin sources never get compiled and the build fails
|
||||
with `cannot find symbol: FilePickerPlugin`. 10.3.11 fixes that but is
|
||||
retracted on pub.dev, hence 10.3.10. Worth revisiting this pin next time
|
||||
you bump dependencies — check the package's CHANGELOG for when this is
|
||||
properly resolved upstream.
|
||||
- **iOS folder picking and app restarts**: `file_picker`'s directory picker
|
||||
on iOS uses `UIDocumentPickerViewController`, which hands back a
|
||||
security-scoped URL. This app does not currently persist a security-scoped
|
||||
bookmark for that URL, so if you pick a folder outside the app's own
|
||||
sandbox (e.g. an iCloud Drive folder) on iOS, continued write access after
|
||||
an app restart is not guaranteed. Picking the default in-sandbox location,
|
||||
or a folder on Android, does not have this limitation. If cross-restart
|
||||
external storage on iOS matters for your use case, this needs a proper
|
||||
bookmark implementation (`NSURL` bookmarkData + `startAccessingSecurityScopedResource`).
|
||||
- **Receipt parsing is best-effort regex matching** on the OCR'd text
|
||||
(`lib/services/receipt_parser.dart`), tuned against common receipt phrasing
|
||||
("GALLONS", "PRICE/GAL", "PPG", "TOTAL", etc.). Unusual receipt layouts may
|
||||
parse partially or not at all — the confirm screen always lets you fill in
|
||||
or correct whatever wasn't found.
|
||||
- No automated tests exercise the OCR or camera capture path itself (that
|
||||
requires a real device/emulator with a camera); `receipt_parser_test.dart`
|
||||
covers the parsing logic against fixed OCR text.
|
||||
Loading…
Add table
Add a link
Reference in a new issue