c58183b4fb
Phase 3: Overlay Refactor - 2 plan(s) in 2 wave(s) - Sequential execution (Plan 02 depends on Plan 01) - Ready for execution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
209 lines
9.9 KiB
Markdown
209 lines
9.9 KiB
Markdown
---
|
|
phase: 03-overlay-refactor
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- lib/services/overlay_service.dart
|
|
- lib/models/overlay_message.dart
|
|
- lib/config/overlay_constants.dart
|
|
- lib/config/timing_constants.dart
|
|
- pubspec.yaml
|
|
autonomous: true
|
|
|
|
must_haves:
|
|
truths:
|
|
- "OverlayService class encapsulates all FlutterOverlayWindow platform calls"
|
|
- "OverlayMessage includes timestamp field serialized as millisecondsSinceEpoch"
|
|
- "Staleness thresholds (3s dim, 10s dashes) and grace period (30s) defined as named constants"
|
|
- "retry package added to dependencies for exponential backoff"
|
|
artifacts:
|
|
- path: "lib/services/overlay_service.dart"
|
|
provides: "Platform channel wrapper with retry logic for show/close/shareData/isActive/overlayListener"
|
|
min_lines: 60
|
|
- path: "lib/models/overlay_message.dart"
|
|
provides: "Timestamp field in OverlayMessage model with toMap/fromMap serialization"
|
|
contains: "timestamp"
|
|
- path: "lib/config/overlay_constants.dart"
|
|
provides: "STALENESS_DIM_THRESHOLD, STALENESS_DASH_THRESHOLD, STALENESS_DIM_OPACITY constants"
|
|
contains: "STALENESS"
|
|
- path: "lib/config/timing_constants.dart"
|
|
provides: "GPS_GRACE_PERIOD constant (30 seconds)"
|
|
contains: "GPS_GRACE_PERIOD"
|
|
- path: "pubspec.yaml"
|
|
provides: "retry package dependency"
|
|
contains: "retry"
|
|
key_links:
|
|
- from: "lib/services/overlay_service.dart"
|
|
to: "flutter_overlay_window"
|
|
via: "import and method delegation"
|
|
pattern: "FlutterOverlayWindow"
|
|
- from: "lib/services/overlay_service.dart"
|
|
to: "retry"
|
|
via: "RetryOptions for showOverlay and closeOverlay"
|
|
pattern: "RetryOptions"
|
|
- from: "lib/models/overlay_message.dart"
|
|
to: "overlay_service.dart consumers"
|
|
via: "timestamp field in toMap/fromMap"
|
|
pattern: "millisecondsSinceEpoch"
|
|
---
|
|
|
|
<objective>
|
|
Create the foundation building blocks for overlay refactor: OverlayService wrapper, timestamp-enhanced OverlayMessage, and staleness/grace period constants.
|
|
|
|
Purpose: Isolate all flutter_overlay_window platform calls behind a service with retry logic and error handling, add timestamp tracking to overlay messages for staleness detection, and define the constants that Plan 02 will use for staleness UI and GPS grace period.
|
|
|
|
Output: Three new/modified files providing the service layer, enhanced model, and constants that Plan 02 will integrate into OverlayProvider, overlay screen, and SpeedometerScreen.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@C:\Users\SKSup\.claude/get-shit-done/workflows/execute-plan.md
|
|
@C:\Users\SKSup\.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/03-overlay-refactor/03-CONTEXT.md
|
|
@.planning/phases/03-overlay-refactor/03-RESEARCH.md
|
|
@lib/services/overlay_service.dart
|
|
@lib/models/overlay_message.dart
|
|
@lib/config/overlay_constants.dart
|
|
@lib/config/timing_constants.dart
|
|
@lib/services/logger.dart
|
|
@pubspec.yaml
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create OverlayService and add retry dependency</name>
|
|
<files>
|
|
lib/services/overlay_service.dart
|
|
lib/config/overlay_constants.dart
|
|
lib/config/timing_constants.dart
|
|
pubspec.yaml
|
|
</files>
|
|
<action>
|
|
1. Add `retry: ^3.1.2` to pubspec.yaml under dependencies (after shared_preferences). Run `flutter pub get` to install.
|
|
|
|
2. Create `lib/services/overlay_service.dart` — a service class that wraps all FlutterOverlayWindow platform calls:
|
|
|
|
- **Constructor:** No parameters needed. Create a static `RetryOptions` with maxAttempts: 3 and delayFactor: Duration(milliseconds: 200).
|
|
|
|
- **showOverlay({required int width, required int height})** → Future<bool>:
|
|
- Uses retry to call FlutterOverlayWindow.showOverlay with enableDrag: true, overlayTitle: "Speedometer", overlayContent: 'Speedo overlay active', flag: OverlayFlag.defaultFlag, visibility: NotificationVisibility.visibilityPublic, positionGravity: PositionGravity.none, plus width/height params.
|
|
- After showOverlay completes, calls FlutterOverlayWindow.isActive() to verify overlay actually opened.
|
|
- Returns true if verified active, false if not.
|
|
- On exception after retries exhausted, logs via Logger.error and returns false.
|
|
- retryIf should catch Exception (broad, since platform exceptions vary).
|
|
|
|
- **closeOverlay()** → Future<bool>:
|
|
- Uses retry to call FlutterOverlayWindow.closeOverlay().
|
|
- Returns true on success, false on failure after retries.
|
|
- Logs errors via Logger.error.
|
|
|
|
- **shareData(Map<String, dynamic> data)** → Future<void>:
|
|
- Calls FlutterOverlayWindow.shareData(data).
|
|
- Catches exceptions and logs via Logger.warn (NOT error — data loss is expected and handled by staleness).
|
|
- Does NOT retry — fire-and-forget by design (user decision: forward every tick, staleness handles drops).
|
|
|
|
- **isActive()** → Future<bool>:
|
|
- Delegates to FlutterOverlayWindow.isActive() with try-catch.
|
|
- Returns false on error.
|
|
|
|
- **get overlayListener** → Stream<dynamic>:
|
|
- Returns FlutterOverlayWindow.overlayListener (direct delegation).
|
|
|
|
- **checkPermission()** → Future<bool>:
|
|
- Uses Permission.systemAlertWindow.isGranted from permission_handler.
|
|
- Returns the boolean result.
|
|
|
|
Import: flutter_overlay_window, retry, permission_handler, logger.dart.
|
|
Use Logger with caller tag 'OverlayService' for all log calls.
|
|
|
|
3. Add staleness constants to `lib/config/overlay_constants.dart`:
|
|
- `static const Duration STALENESS_DIM_THRESHOLD = Duration(seconds: 3);` — time after which overlay dims speed display (user decision: 3 seconds, NOT 2)
|
|
- `static const Duration STALENESS_DASH_THRESHOLD = Duration(seconds: 10);` — time after which overlay shows "--" dashes
|
|
- `static const double STALENESS_DIM_OPACITY = 0.5;` — opacity value for dimmed stale state
|
|
- `static const Duration STALENESS_CHECK_INTERVAL = Duration(seconds: 1);` — how often overlay checks for staleness
|
|
|
|
4. Add GPS grace period constant to `lib/config/timing_constants.dart`:
|
|
- `static const Duration GPS_GRACE_PERIOD = Duration(seconds: 30);` — GPS continues 30s after overlay close when backgrounded (user decision)
|
|
</action>
|
|
<verify>
|
|
Run `flutter pub get` to confirm retry dependency resolves. Run `flutter analyze` to confirm no analysis errors in new/modified files. Verify overlay_service.dart imports compile correctly.
|
|
</verify>
|
|
<done>
|
|
OverlayService exists with showOverlay, closeOverlay, shareData, isActive, overlayListener, and checkPermission methods. retry package installed. Staleness constants (3s/10s/0.5 opacity/1s check) and GPS_GRACE_PERIOD (30s) defined in their respective config files. No analysis errors.
|
|
</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Add timestamp field to OverlayMessage model</name>
|
|
<files>lib/models/overlay_message.dart</files>
|
|
<action>
|
|
Extend the existing OverlayMessage class to include a timestamp field:
|
|
|
|
1. Add `final DateTime timestamp;` field to the class.
|
|
|
|
2. Update the **primary constructor** to include `required this.timestamp` as a required parameter. Remove `const` from the constructor since DateTime.now() is not a compile-time constant.
|
|
|
|
3. Update **OverlayMessage.updateDisplay** factory:
|
|
- Add `timestamp: DateTime.now()` in the returned OverlayMessage.
|
|
- No changes to parameters (timestamp is auto-generated, not passed in).
|
|
|
|
4. Update **OverlayMessage.longPressClose** factory:
|
|
- Remove `const` from the returned value.
|
|
- Add `timestamp: DateTime.now()`.
|
|
|
|
5. Update **OverlayMessage.overlayClosed** factory:
|
|
- Remove `const` from the returned value.
|
|
- Add `timestamp: DateTime.now()`.
|
|
|
|
6. Update **toMap()**:
|
|
- Add `map['timestamp'] = timestamp.millisecondsSinceEpoch;` (always include — timestamp is never null).
|
|
|
|
7. Update **fromMap()**:
|
|
- Parse timestamp: `timestamp: DateTime.fromMillisecondsSinceEpoch(map['timestamp'] as int? ?? DateTime.now().millisecondsSinceEpoch)`.
|
|
- Fallback to DateTime.now() if timestamp missing (backward compatibility with any in-flight messages during upgrade).
|
|
|
|
8. Update **copyWith()**:
|
|
- Add `DateTime? timestamp` parameter.
|
|
- Add `timestamp: timestamp ?? this.timestamp` in the returned OverlayMessage.
|
|
|
|
Do NOT change any existing field names, types, or factory parameter signatures. The timestamp is purely additive.
|
|
</action>
|
|
<verify>
|
|
Run `flutter analyze` to confirm no analysis errors. Verify OverlayMessage can be constructed with all three factories. Verify toMap() includes 'timestamp' key. Verify fromMap() parses timestamp correctly and handles missing timestamp gracefully.
|
|
</verify>
|
|
<done>
|
|
OverlayMessage has timestamp field, auto-populated by all factory constructors via DateTime.now(), serialized as int via millisecondsSinceEpoch in toMap(), parsed with fallback in fromMap(), and included in copyWith(). No breaking changes to existing API.
|
|
</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
1. `flutter pub get` succeeds with retry dependency added
|
|
2. `flutter analyze` shows no new errors or warnings (existing SCREAMING_SNAKE info-level warnings are expected)
|
|
3. lib/services/overlay_service.dart exists and contains OverlayService class
|
|
4. lib/models/overlay_message.dart contains `timestamp` field
|
|
5. lib/config/overlay_constants.dart contains STALENESS_DIM_THRESHOLD, STALENESS_DASH_THRESHOLD, STALENESS_DIM_OPACITY, STALENESS_CHECK_INTERVAL
|
|
6. lib/config/timing_constants.dart contains GPS_GRACE_PERIOD
|
|
7. pubspec.yaml contains retry dependency
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- OverlayService wraps all FlutterOverlayWindow calls with retry for show/close and error handling for all methods
|
|
- OverlayMessage timestamp field serializes/deserializes correctly
|
|
- All staleness and grace period constants defined with user-decision values (3s dim, 10s dashes, 30s grace)
|
|
- No compilation errors, no breaking changes to existing API
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/03-overlay-refactor/03-01-SUMMARY.md`
|
|
</output>
|