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>
10 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, decisions, metrics
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-overlay-refactor | 01 | overlay-infrastructure |
|
|
|
|
|
|
|
|
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:
- Isolating all flutter_overlay_window platform calls behind OverlayService with retry logic
- Adding timestamp tracking to OverlayMessage for staleness detection
- 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 cleanupshareData(Map)- Fire-and-forget with warn-level logging (no retry)isActive()- Error-safe overlay status checkoverlayListener- Direct stream delegationcheckPermission()- Permission status helper
Retry Configuration:
- 3 attempts maximum
- 200ms delay factor (exponential backoff)
- Removed unnecessary
retryIfchecks (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
constmodifiers (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:
- Replace FlutterOverlayWindow.showOverlay in OverlayProvider with OverlayService.showOverlay
- Replace FlutterOverlayWindow.closeOverlay with OverlayService.closeOverlay
- Replace FlutterOverlayWindow.shareData with OverlayService.shareData
- Add staleness detection timer in overlay screen using STALENESS_CHECK_INTERVAL
- Implement dim/dash logic using STALENESS_DIM_THRESHOLD and STALENESS_DASH_THRESHOLD
- 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:
- Integrate OverlayService into OverlayProvider
- Add staleness detection timer and UI feedback in overlay screen
- Implement GPS grace period logic in SpeedometerScreen
- Replace all direct FlutterOverlayWindow calls with OverlayService methods
Estimated complexity: Medium (refactor existing OverlayProvider and overlay screen)
Blockers: None - all foundation infrastructure complete
Commits
-
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)
-
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