Files
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

6.1 KiB

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