docs(03-01): complete overlay foundation plan
Tasks completed: 2/2 - Task 1: Create OverlayService and add retry dependency - Task 2: Add timestamp field to OverlayMessage model SUMMARY: .planning/phases/03-overlay-refactor/03-01-SUMMARY.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+33
-21
@@ -5,23 +5,23 @@
|
|||||||
See: .planning/PROJECT.md (updated 2026-02-09)
|
See: .planning/PROJECT.md (updated 2026-02-09)
|
||||||
|
|
||||||
**Core value:** Reliable, lag-free GPS speed display that coexists politely with other Android apps
|
**Core value:** Reliable, lag-free GPS speed display that coexists politely with other Android apps
|
||||||
**Current focus:** Phase 2 - Provider Migration (COMPLETE)
|
**Current focus:** Phase 3 - Overlay Refactor (IN PROGRESS)
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 2 of 4 (Provider Migration)
|
Phase: 3 of 4 (Overlay Refactor)
|
||||||
Plan: 2 of 2 complete
|
Plan: 1 of 2 complete
|
||||||
Status: Phase complete — ready for Phase 3 planning
|
Status: In progress
|
||||||
Last activity: 2026-02-10 — Completed 02-02-PLAN.md
|
Last activity: 2026-02-11 — Completed 03-01-PLAN.md
|
||||||
|
|
||||||
Progress: [███░░░░░░░] 50% (Phase 2: 2/2 plans)
|
Progress: [████░░░░░░] 55% (Phase 3: 1/2 plans)
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
**Velocity:**
|
**Velocity:**
|
||||||
- Total plans completed: 4
|
- Total plans completed: 5
|
||||||
- Average duration: 7.6 minutes
|
- Average duration: 6.9 minutes
|
||||||
- Total execution time: 0.51 hours
|
- Total execution time: 0.58 hours
|
||||||
|
|
||||||
**By Phase:**
|
**By Phase:**
|
||||||
|
|
||||||
@@ -29,10 +29,11 @@ Progress: [███░░░░░░░] 50% (Phase 2: 2/2 plans)
|
|||||||
|-------|-------|-------|----------|
|
|-------|-------|-------|----------|
|
||||||
| 1. Foundation | 2 | 19.6 min | 9.8 min |
|
| 1. Foundation | 2 | 19.6 min | 9.8 min |
|
||||||
| 2. Provider Migration | 2 | 11.5 min | 5.75 min |
|
| 2. Provider Migration | 2 | 11.5 min | 5.75 min |
|
||||||
|
| 3. Overlay Refactor | 1 | 4.0 min | 4.0 min |
|
||||||
|
|
||||||
**Recent Trend:**
|
**Recent Trend:**
|
||||||
- Last 5 plans: 01-01 (12.8 min), 01-02 (6.8 min), 02-01 (7.7 min), 02-02 (3.8 min)
|
- Last 5 plans: 01-02 (6.8 min), 02-01 (7.7 min), 02-02 (3.8 min), 03-01 (4.0 min)
|
||||||
- Trend: Accelerating (50% faster on plan 4 vs plan 1)
|
- Trend: Continuing acceleration (4.0 min on latest plan)
|
||||||
|
|
||||||
*Updated after each plan completion*
|
*Updated after each plan completion*
|
||||||
|
|
||||||
@@ -60,6 +61,11 @@ Recent decisions affecting current work:
|
|||||||
| 02 | 02 | Speed Selector uses context.read<SettingsProvider>() | Implemented |
|
| 02 | 02 | Speed Selector uses context.read<SettingsProvider>() | Implemented |
|
||||||
| 02 | 02 | Background heartbeat stays in screen (not provider) | Implemented |
|
| 02 | 02 | Background heartbeat stays in screen (not provider) | Implemented |
|
||||||
| 02 | 02 | _isInBackground direct assignment (no setState) | Implemented |
|
| 02 | 02 | _isInBackground direct assignment (no setState) | Implemented |
|
||||||
|
| 03 | 01 | OverlayService wraps all FlutterOverlayWindow calls | Implemented |
|
||||||
|
| 03 | 01 | showOverlay verifies with isActive() post-call | Implemented |
|
||||||
|
| 03 | 01 | shareData fire-and-forget (no retry, warn logging) | Implemented |
|
||||||
|
| 03 | 01 | Staleness thresholds: 3s dim, 10s dash | Implemented |
|
||||||
|
| 03 | 01 | Timestamp auto-populated in OverlayMessage factories | Implemented |
|
||||||
| 04 | TBD | Speed-adaptive GPS precision (~10 km/h threshold) | Pending |
|
| 04 | TBD | Speed-adaptive GPS precision (~10 km/h threshold) | Pending |
|
||||||
| 04 | TBD | Background GPS only when overlay visible | Pending |
|
| 04 | TBD | Background GPS only when overlay visible | Pending |
|
||||||
|
|
||||||
@@ -78,8 +84,12 @@ Recent decisions affecting current work:
|
|||||||
- [ ] Manual testing: Settings persistence, theme/unit cycling, overlay toggle, background heartbeat
|
- [ ] Manual testing: Settings persistence, theme/unit cycling, overlay toggle, background heartbeat
|
||||||
- [ ] Manual testing: Verify no "setState after dispose" or "ChangeNotifier after dispose" errors
|
- [ ] Manual testing: Verify no "setState after dispose" or "ChangeNotifier after dispose" errors
|
||||||
|
|
||||||
**Phase 3 Pending:**
|
**Phase 3 In Progress:**
|
||||||
- [ ] Plan Phase 3 (Overlay Refactor) next
|
- [x] 03-01 complete — Overlay foundation infrastructure (4.0 min)
|
||||||
|
- [x] OverlayService wrapper with retry logic created
|
||||||
|
- [x] OverlayMessage enhanced with timestamp tracking
|
||||||
|
- [x] Staleness constants and GPS grace period defined
|
||||||
|
- [ ] 03-02 next — Integrate OverlayService and staleness detection
|
||||||
|
|
||||||
### Blockers/Concerns
|
### Blockers/Concerns
|
||||||
|
|
||||||
@@ -96,11 +106,13 @@ Recent decisions affecting current work:
|
|||||||
- RESOLVED: Zero setState calls for shared state (theme, unit, GPS data, overlay status)
|
- RESOLVED: Zero setState calls for shared state (theme, unit, GPS data, overlay status)
|
||||||
- INFO: Manual testing needed to verify settings persistence and provider lifecycle
|
- INFO: Manual testing needed to verify settings persistence and provider lifecycle
|
||||||
|
|
||||||
**Phase 3 (Overlay Refactor) — Next:**
|
**Phase 3 (Overlay Refactor) — In Progress:**
|
||||||
- MEDIUM RISK: flutter_overlay_window 0.5.0 has known communication issues
|
- RESOLVED: OverlayService foundation complete with retry logic
|
||||||
- May need testing on multiple Android versions for reliability
|
- RESOLVED: Timestamp tracking in OverlayMessage for staleness detection
|
||||||
- Overlay status polling alternative needs research (event-based vs 5s polling)
|
- RESOLVED: Staleness constants defined (3s dim, 10s dash, 30s GPS grace)
|
||||||
- Data staleness issue to fix (data stops updating after running for a while)
|
- MEDIUM RISK: flutter_overlay_window 0.5.0 has known communication issues (mitigated by retry + verification)
|
||||||
|
- INFO: Plan 03-02 will integrate OverlayService and implement staleness UI feedback
|
||||||
|
- INFO: Manual testing needed after 03-02 to verify overlay reliability improvements
|
||||||
|
|
||||||
**Phase 4 (GPS Optimization):**
|
**Phase 4 (GPS Optimization):**
|
||||||
- Speed thresholds (8/12 km/h) need field testing validation
|
- Speed thresholds (8/12 km/h) need field testing validation
|
||||||
@@ -108,7 +120,7 @@ Recent decisions affecting current work:
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-02-10 (Plan 02-02 execution complete)
|
Last session: 2026-02-11 (Plan 03-01 execution complete)
|
||||||
Stopped at: Completed 02-02-PLAN.md — Phase 2 complete
|
Stopped at: Completed 03-01-PLAN.md — Phase 3 Plan 1 complete
|
||||||
Resume file: None
|
Resume file: None
|
||||||
Next action: Plan Phase 3 (Overlay Refactor)
|
Next action: Execute 03-02-PLAN.md (Overlay integration)
|
||||||
|
|||||||
@@ -0,0 +1,255 @@
|
|||||||
|
---
|
||||||
|
phase: 03-overlay-refactor
|
||||||
|
plan: 01
|
||||||
|
subsystem: overlay-infrastructure
|
||||||
|
tags: [service-layer, ipc, staleness-detection, retry-logic]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- 02-02: Provider pattern infrastructure for overlay state management
|
||||||
|
|
||||||
|
provides:
|
||||||
|
- OverlayService wrapper isolating all flutter_overlay_window platform calls
|
||||||
|
- Timestamp tracking in OverlayMessage for staleness detection
|
||||||
|
- Staleness threshold constants (3s dim, 10s dash) for UI feedback
|
||||||
|
- GPS grace period constant (30s) for background GPS lifecycle
|
||||||
|
|
||||||
|
affects:
|
||||||
|
- 03-02: OverlayProvider will use OverlayService instead of direct FlutterOverlayWindow calls
|
||||||
|
- 03-02: Overlay screen will consume staleness constants for visual feedback
|
||||||
|
- 03-02: SpeedometerScreen will use GPS_GRACE_PERIOD for background GPS management
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added:
|
||||||
|
- retry: ^3.1.2
|
||||||
|
patterns:
|
||||||
|
- Service wrapper pattern for platform channel isolation
|
||||||
|
- Exponential backoff retry (3 attempts, 200ms delay factor)
|
||||||
|
- Fire-and-forget with warn-level logging for non-critical failures
|
||||||
|
- Timestamp-based staleness detection via millisecondsSinceEpoch serialization
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- lib/services/overlay_service.dart
|
||||||
|
modified:
|
||||||
|
- lib/models/overlay_message.dart
|
||||||
|
- lib/config/overlay_constants.dart
|
||||||
|
- lib/config/timing_constants.dart
|
||||||
|
- pubspec.yaml
|
||||||
|
|
||||||
|
decisions:
|
||||||
|
- id: OVL-01
|
||||||
|
choice: OverlayService wraps all FlutterOverlayWindow calls
|
||||||
|
rationale: Isolate platform-specific code, centralize retry logic and error handling
|
||||||
|
status: implemented
|
||||||
|
- id: OVL-02
|
||||||
|
choice: showOverlay verifies overlay opened via isActive() call
|
||||||
|
rationale: Platform channel may succeed but overlay fail to appear - explicit verification required
|
||||||
|
status: implemented
|
||||||
|
- id: OVL-03
|
||||||
|
choice: shareData is fire-and-forget with warn-level logging
|
||||||
|
rationale: User decision - send every GPS tick, staleness detection handles drops, no retry needed
|
||||||
|
status: implemented
|
||||||
|
- id: OVL-04
|
||||||
|
choice: Staleness thresholds are 3s dim, 10s dash (NOT 2s/10s)
|
||||||
|
rationale: User specified 3 seconds for dim threshold in plan
|
||||||
|
status: implemented
|
||||||
|
- id: OVL-05
|
||||||
|
choice: Timestamp auto-populated by DateTime.now() in factories
|
||||||
|
rationale: Timestamp is metadata, not user data - automatic population prevents caller errors
|
||||||
|
status: implemented
|
||||||
|
- id: OVL-06
|
||||||
|
choice: Remove const from OverlayMessage constructors
|
||||||
|
rationale: DateTime.now() is runtime value, cannot be const - necessary for timestamp field
|
||||||
|
status: implemented
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
duration: 4.0 minutes
|
||||||
|
completed: 2026-02-11
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 03 Plan 01: Overlay Foundation Infrastructure Summary
|
||||||
|
|
||||||
|
**One-liner:** OverlayService wrapper with retry logic, timestamp-enhanced OverlayMessage, and staleness constants (3s dim, 10s dash, 30s GPS grace period).
|
||||||
|
|
||||||
|
## Objective Achieved
|
||||||
|
|
||||||
|
Created the foundation building blocks for overlay refactor by:
|
||||||
|
1. Isolating all flutter_overlay_window platform calls behind OverlayService with retry logic
|
||||||
|
2. Adding timestamp tracking to OverlayMessage for staleness detection
|
||||||
|
3. Defining staleness thresholds (3s dim, 10s dash) and GPS grace period (30s) as named constants
|
||||||
|
|
||||||
|
These components provide the service layer, enhanced model, and constants that Plan 02 will integrate into OverlayProvider, overlay screen, and SpeedometerScreen.
|
||||||
|
|
||||||
|
## Tasks Completed
|
||||||
|
|
||||||
|
| Task | Description | Commit | Files Modified |
|
||||||
|
|------|-------------|--------|----------------|
|
||||||
|
| 1 | Create OverlayService and add retry dependency | 505219c | overlay_service.dart, overlay_constants.dart, timing_constants.dart, pubspec.yaml |
|
||||||
|
| 2 | Add timestamp field to OverlayMessage model | 9e3decc | overlay_message.dart |
|
||||||
|
|
||||||
|
## Implementation Details
|
||||||
|
|
||||||
|
### OverlayService Architecture
|
||||||
|
|
||||||
|
**Platform Channel Wrapper:**
|
||||||
|
- `showOverlay({width, height})` - Retry logic with post-verification via isActive()
|
||||||
|
- `closeOverlay()` - Retry logic for robust cleanup
|
||||||
|
- `shareData(Map)` - Fire-and-forget with warn-level logging (no retry)
|
||||||
|
- `isActive()` - Error-safe overlay status check
|
||||||
|
- `overlayListener` - Direct stream delegation
|
||||||
|
- `checkPermission()` - Permission status helper
|
||||||
|
|
||||||
|
**Retry Configuration:**
|
||||||
|
- 3 attempts maximum
|
||||||
|
- 200ms delay factor (exponential backoff)
|
||||||
|
- Removed unnecessary `retryIf` checks (analyzer warnings fixed)
|
||||||
|
|
||||||
|
**Error Handling Strategy:**
|
||||||
|
- showOverlay/closeOverlay: Logger.error after exhausted retries, return false
|
||||||
|
- shareData: Logger.warn on failure, no retry (staleness detection handles drops)
|
||||||
|
- isActive: Logger.error + return false on exception
|
||||||
|
|
||||||
|
### OverlayMessage Enhancements
|
||||||
|
|
||||||
|
**Timestamp Field:**
|
||||||
|
- Auto-populated via `DateTime.now()` in all factory constructors
|
||||||
|
- No manual timestamp passing required from callers
|
||||||
|
- Serialized as `millisecondsSinceEpoch` (int) in toMap()
|
||||||
|
- Deserialized with fallback to `DateTime.now()` in fromMap() for backward compatibility
|
||||||
|
|
||||||
|
**Breaking Change Mitigation:**
|
||||||
|
- Removed `const` modifiers (DateTime.now() is runtime value)
|
||||||
|
- Added timestamp to copyWith() for completeness
|
||||||
|
- All existing factory APIs unchanged (timestamp is additive metadata)
|
||||||
|
|
||||||
|
### Constants Configuration
|
||||||
|
|
||||||
|
**Staleness Thresholds (overlay_constants.dart):**
|
||||||
|
- `STALENESS_DIM_THRESHOLD`: 3 seconds (dim speed display)
|
||||||
|
- `STALENESS_DASH_THRESHOLD`: 10 seconds (show dashes instead of speed)
|
||||||
|
- `STALENESS_DIM_OPACITY`: 0.5 (dimmed state opacity)
|
||||||
|
- `STALENESS_CHECK_INTERVAL`: 1 second (check frequency)
|
||||||
|
|
||||||
|
**GPS Grace Period (timing_constants.dart):**
|
||||||
|
- `GPS_GRACE_PERIOD`: 30 seconds (continue GPS after overlay close when backgrounded)
|
||||||
|
|
||||||
|
## Verification Results
|
||||||
|
|
||||||
|
**flutter pub get:**
|
||||||
|
- retry package (^3.1.2) installed successfully
|
||||||
|
- All dependencies resolved
|
||||||
|
|
||||||
|
**flutter analyze:**
|
||||||
|
- 26 info-level warnings (SCREAMING_SNAKE constants - expected per project convention)
|
||||||
|
- 0 errors or warnings in new code
|
||||||
|
- Fixed 2 unnecessary type check warnings in OverlayService retry logic
|
||||||
|
|
||||||
|
**Code Quality:**
|
||||||
|
- OverlayService: 93 lines with comprehensive error handling
|
||||||
|
- OverlayMessage timestamp integration: 15 lines added across all methods
|
||||||
|
- All must-have requirements satisfied
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None - plan executed exactly as written.
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
**OVL-01: Service Wrapper Pattern**
|
||||||
|
- All flutter_overlay_window calls isolated in OverlayService
|
||||||
|
- Benefits: Centralized retry logic, single error handling point, easier testing
|
||||||
|
- Impact: Plan 02 will migrate OverlayProvider to use OverlayService
|
||||||
|
|
||||||
|
**OVL-02: Post-Verification in showOverlay**
|
||||||
|
- Added isActive() verification after FlutterOverlayWindow.showOverlay() completes
|
||||||
|
- Addresses: Platform channel may report success but overlay fails to appear
|
||||||
|
- Prevents: False positive overlay status in OverlayProvider
|
||||||
|
|
||||||
|
**OVL-03: Fire-and-Forget shareData**
|
||||||
|
- No retry logic for data sharing (user decision: forward every tick)
|
||||||
|
- Staleness detection handles dropped messages via timestamp tracking
|
||||||
|
- Warn-level logging prevents error log noise from expected occasional failures
|
||||||
|
|
||||||
|
**OVL-04: Staleness Timing**
|
||||||
|
- 3 seconds for dim (NOT 2 seconds as in some research notes)
|
||||||
|
- 10 seconds for dashes (consistent across all references)
|
||||||
|
- User explicitly specified 3s in plan MUST_HAVES
|
||||||
|
|
||||||
|
**OVL-05: Automatic Timestamp Population**
|
||||||
|
- DateTime.now() called in factory constructors, not passed by callers
|
||||||
|
- Prevents caller errors (forgetting timestamp, using wrong time source)
|
||||||
|
- Ensures consistency (all timestamps from same clock source)
|
||||||
|
|
||||||
|
**OVL-06: Remove const Modifiers**
|
||||||
|
- Required to allow DateTime.now() runtime values
|
||||||
|
- Trade-off: Lose compile-time const optimization for timestamp functionality
|
||||||
|
- Impact: Negligible (OverlayMessage instances are short-lived IPC data)
|
||||||
|
|
||||||
|
## Technical Debt
|
||||||
|
|
||||||
|
**None identified.**
|
||||||
|
|
||||||
|
All code follows project conventions:
|
||||||
|
- SCREAMING_SNAKE for behavioral constants
|
||||||
|
- Logger with caller tags for all logging
|
||||||
|
- Error handling with graceful degradation
|
||||||
|
- Type-safe OverlayMessage serialization
|
||||||
|
|
||||||
|
## Integration Readiness
|
||||||
|
|
||||||
|
**Ready for Plan 02:**
|
||||||
|
- OverlayService provides all needed platform operations
|
||||||
|
- OverlayMessage timestamp field ready for staleness calculation
|
||||||
|
- Constants defined and accessible for UI feedback logic
|
||||||
|
|
||||||
|
**Migration Path for Plan 02:**
|
||||||
|
1. Replace FlutterOverlayWindow.showOverlay in OverlayProvider with OverlayService.showOverlay
|
||||||
|
2. Replace FlutterOverlayWindow.closeOverlay with OverlayService.closeOverlay
|
||||||
|
3. Replace FlutterOverlayWindow.shareData with OverlayService.shareData
|
||||||
|
4. Add staleness detection timer in overlay screen using STALENESS_CHECK_INTERVAL
|
||||||
|
5. Implement dim/dash logic using STALENESS_DIM_THRESHOLD and STALENESS_DASH_THRESHOLD
|
||||||
|
6. Add GPS grace period logic in SpeedometerScreen using GPS_GRACE_PERIOD
|
||||||
|
|
||||||
|
## Artifacts Generated
|
||||||
|
|
||||||
|
**Service Layer:**
|
||||||
|
- `lib/services/overlay_service.dart` (93 lines)
|
||||||
|
|
||||||
|
**Enhanced Model:**
|
||||||
|
- `lib/models/overlay_message.dart` (+18 lines, -3 lines)
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
- `lib/config/overlay_constants.dart` (+12 lines)
|
||||||
|
- `lib/config/timing_constants.dart` (+3 lines)
|
||||||
|
|
||||||
|
**Dependencies:**
|
||||||
|
- `pubspec.yaml` (+3 lines - retry package)
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
Plan 02 will:
|
||||||
|
1. Integrate OverlayService into OverlayProvider
|
||||||
|
2. Add staleness detection timer and UI feedback in overlay screen
|
||||||
|
3. Implement GPS grace period logic in SpeedometerScreen
|
||||||
|
4. Replace all direct FlutterOverlayWindow calls with OverlayService methods
|
||||||
|
|
||||||
|
**Estimated complexity:** Medium (refactor existing OverlayProvider and overlay screen)
|
||||||
|
|
||||||
|
**Blockers:** None - all foundation infrastructure complete
|
||||||
|
|
||||||
|
## Commits
|
||||||
|
|
||||||
|
1. **505219c** - feat(03-01): create OverlayService and add retry dependency
|
||||||
|
- Added retry package (^3.1.2)
|
||||||
|
- Created OverlayService wrapper with showOverlay, closeOverlay, shareData, isActive, overlayListener, checkPermission
|
||||||
|
- Implemented 3-attempt retry with 200ms exponential backoff
|
||||||
|
- Added staleness constants: 3s dim, 10s dash, 0.5 opacity, 1s check interval
|
||||||
|
- Added GPS_GRACE_PERIOD constant (30 seconds)
|
||||||
|
|
||||||
|
2. **9e3decc** - feat(03-01): add timestamp field to OverlayMessage model
|
||||||
|
- Added timestamp field with auto-population via DateTime.now()
|
||||||
|
- Updated all factory constructors (updateDisplay, longPressClose, overlayClosed)
|
||||||
|
- Serialized timestamp as millisecondsSinceEpoch in toMap()
|
||||||
|
- Deserialized with fallback to DateTime.now() in fromMap()
|
||||||
|
- Added timestamp parameter to copyWith()
|
||||||
|
- Removed const modifiers for runtime timestamp values
|
||||||
Reference in New Issue
Block a user