# palm_oil_mobile

A Flutter app that runs on-device YOLO26 (NMS-free) inference to detect palm oil fresh fruit bunch (FFB) ripeness against MPOB grading standards — fully offline, no server or network calls required. Built for FFB harvesters to scan bunches in the field and compare their own judgment against the model's.

## Detection classes

`Ripe`, `Unripe`, `Underripe`, `Overripe`, `Abnormal`, `Empty_Bunch` (MPOB standard).

## Features

- **Three capture modes**:
  - **Analyze Gallery** — pick one or more photos from the gallery and run inference on each as a batch.
  - **Snap & Analyze** — manual high-res camera capture.
  - **Live Inference** — real-time "point-and-scan": an auto-lock state machine detects a steady target, captures a high-res still, and analyzes it automatically.
- **Batch reporting** — every scan is grouped into a batch (one per capture-screen visit, or per multi-image gallery pick). Batches show a KPI dashboard (frame count, total detections, avg confidence, avg inference time), an MPOB class-distribution bar, and a frame thumbnail grid.
- **History Vault** — grouped, filterable, sortable history of every batch, with swipe-to-delete and date-range filtering.
- **Harvester ground-truth corrections** — on any photo's detail screen, a harvester can compare the AI's inference against their own judgment and correct individual detected fruit. Corrections are additive: the AI's original inference is never edited or overwritten, and a photo can be re-corrected any number of times, each one recorded separately — intended to eventually feed a cloud-based retraining pipeline.
- **Light/dark theme** — a custom teal-green/amber palette with a system-following default and an in-app toggle (Light/Dark/System), persisted across launches.

## Getting started

```bash
flutter pub get
flutter run                      # run on a connected device/emulator
flutter build apk --debug        # debug build
flutter build apk                # release build
flutter analyze                  # static analysis
```

The bundled model (`assets/best.tflite`) and labels (`assets/labels.txt`) are loaded at runtime — no backend to start, no network required.

### Regenerating the app icon

The launcher icon is generated from `assets/icon_light.png` via `flutter_launcher_icons` (config lives in `pubspec.yaml`). After changing the source image, regenerate with:

```bash
dart run flutter_launcher_icons
```

## Architecture

See [CLAUDE.md](CLAUDE.md) for a detailed breakdown of the isolate-based inference pipeline, the live-capture auto-lock state machine, the SQLite schema (batches, corrections), and screen-by-screen notes — written for AI coding agents working in this repo, but equally useful as an architecture reference for humans.

## Requirements

- Flutter SDK `^3.11.1`
- Android (primary target — this is where the app is actively tested); iOS builds are untested (no current access to iOS hardware)
