Files
gps-speedo/.planning/PROJECT.md
Mikkeli Matlock 64d210af5c docs: initialize project
Restructure GPS speedometer: modular architecture, Provider state management, overlay reliability fixes, speed-adaptive GPS precision, cooperative Android GPS access.
2026-02-09 19:14:32 +09:00

103 lines
6.1 KiB
Markdown

# GPS Speedometer — Restructure & Android QoL
## What this is
A restructure of the existing Flutter GPS speedometer app, splitting a 1,075-line monolithic `main.dart` into a modular architecture with proper state management, and improving Android quality of life — particularly the floating window overlay reliability, GPS response latency, and power behavior. This is not a feature expansion. It is a foundation rebuild for the same app.
## Core value
Reliable, lag-free GPS speed display that coexists politely with other Android apps.
## Requirements
### Validated
These exist and work in the current codebase.
- ✓ Real-time GPS speed tracking with accuracy monitoring — existing
- ✓ Speed units (km/h, mph, knots) with quick selector — existing
- ✓ Dual display styles: digital speedometer + analog gauge — existing
- ✓ Dark/light theme support with cycling — existing
- ✓ Optional metrics panel: coordinates, distance, trip time, accuracy — existing
- ✓ Trip reset functionality — existing
- ✓ Portrait/landscape orientation support — existing
- ✓ Android permissions handling (FINE_LOCATION, COARSE_LOCATION, SYSTEM_ALERT_WINDOW) — existing
- ✓ Floating window overlay showing speed + heading — existing (buggy)
- ✓ GpsDataManager singleton for centralized GPS processing — existing
- ✓ Haptic feedback on main UI interactions — existing
- ✓ Heading display with compass bearing — existing
### Active
Architecture:
- [ ] Modularize code into `screens/`, `widgets/`, `services/`, `providers/`, `models/` directories
- [ ] Replace raw `setState()` with proper Provider pattern (ChangeNotifier/Consumer)
- [ ] Extract overlay management from SpeedometerScreen into dedicated controller/service
- [ ] Define typed message schema for main↔overlay communication (replace unvalidated Maps)
- [ ] Replace unconditional `print()` calls with conditional debug logging (`customDebugPrint`)
Overlay reliability:
- [ ] Fix overlay data pipeline — data stops updating after running for a while
- [ ] Surface overlay errors to user (snackbar/toast instead of silent catch)
- [ ] Verify overlay creation succeeded before setting `_isOverlayActive = true`
- [ ] Remove or fix unreliable overlay status polling (1-second timer workaround)
GPS performance:
- [ ] Eliminate lag between GPS hardware fix and display update
- [ ] Speed-adaptive GPS precision: HIGH_ACCURACY above ~10 km/h, BALANCED_POWER below, with hysteresis (~8/12 km/h thresholds)
- [ ] Non-exclusive, non-locking GPS access — other apps use location normally
Power & background:
- [ ] Smart background GPS: active when overlay is visible, stopped when not
- [ ] Stop heartbeat timer when not needed (foreground + no overlay)
- [ ] Remove unnecessary wake locks — only hold when actively tracking with overlay
- [ ] Cache overlay size calculation instead of recalculating on every build
### Out of scope
- New features or UI additions — this is a restructure, not a feature release
- Dedicated settings screen — inline toggles stay as-is
- GPS interpolation or prediction between hardware fixes — display what hardware gives, instantly
- iOS testing or optimization — Android primary
- New overlay content — speed + unit + heading stays
- Comprehensive unit/integration test suite — important but separate milestone
- Dependency version upgrades — keep current versions stable
## Context
The app is a working GPS speedometer at v2.3.0-dev on the `feature/gps-manager-architecture` branch. The core problem is architectural: `main.dart` is a monolith where `SpeedometerScreen` alone is ~780 lines managing GPS subscriptions, overlay lifecycle, theme cycling, unit cycling, haptic feedback, background heartbeat, overlay status polling, and gesture handling. This makes every fix a surgical operation in a crowded file.
The `flutter_overlay_window` package has known limitations — bidirectional communication is unreliable, and the current heartbeat/polling approach is a workaround for message-based detection failures. The data pipeline going stale is likely related to timer lifecycle and stream subscription management.
Provider is already a dependency but unused — the app relies on `setState()` throughout. The restructure should wire Provider properly so state flows reactively across extracted widgets.
The GPS cooperative access constraint is important: the app uses Android's Fused Location Provider (via geolocator), which is inherently shared. But holding continuous HIGH_ACCURACY streams with wake locks is aggressive. Speed-adaptive precision reduces this to "high when actually moving, balanced when not."
SharedPreferences is mentioned in CLAUDE.md as implemented but is not actually integrated — settings reset on app restart. This is a known gap but out of scope for this restructure.
## Constraints
- **Platform**: Android primary — iOS exists but is untested and not a target
- **GPS bus**: Must be non-exclusive, non-locking — other apps access location normally
- **Power**: Mixed use — sometimes charging (car), sometimes battery (cycling, walking)
- **Overlay library**: `flutter_overlay_window 0.5.0` has known bidirectional communication issues — design around them
- **Tech stack**: Flutter/Dart, keep existing dependency set — no new major dependencies
- **Backward compatibility**: All current features must continue to work after restructure
## Key decisions
| Decision | Rationale | Outcome |
|----------|-----------|---------|
| Speed-adaptive GPS precision (~10 km/h threshold with hysteresis) | Balances responsiveness when moving with cooperative behavior when stationary | — Pending |
| Provider pattern for state management | Already a dependency, fits Flutter idiom, enables reactive updates across extracted widgets | — Pending |
| Background GPS only when overlay visible | No reason to track location if user can't see the data | — Pending |
| Directory structure: screens/, widgets/, services/, providers/, models/ | Standard Flutter convention, separates concerns cleanly | — Pending |
| No new dependencies | Stability — restructure existing code, don't introduce new moving parts | — Pending |
---
*Last updated: 2026-02-09 after initialization*