# Schedule Timer System The OnTime app includes an automatic timer system within the `ScheduleBloc` that manages precise timing for schedule start notifications. This system ensures that schedule start events are triggered at the exact scheduled time. ## 🎯 Overview The timer system automatically: - Starts when an upcoming schedule is received - Triggers a `ScheduleStarted` event at exactly x minute 00 seconds - Handles proper cleanup and timer management - Ensures thread-safety and prevents memory leaks ## 🔄 Timer Flow ```mermaid sequenceDiagram participant UC as UseCase participant SB as ScheduleBloc participant Timer as Timer participant State as State UC->>SB: ScheduleUpcomingReceived(schedule) SB->>SB: Cancel existing timer SB->>SB: _startScheduleTimer(schedule) SB->>Timer: Create Timer(targetTime) Note over Timer: Timer set for schedule.scheduleTime
at x minute 00 seconds SB->>State: emit(ScheduleState.upcoming/ongoing) Timer-->>SB: Timer fires at exact minute SB->>SB: add(ScheduleStarted()) SB->>SB: _onScheduleStarted() SB->>State: emit(ScheduleState.started) Note over SB: Timer cleanup on close()
or new schedule received ``` ## 📋 Implementation Details ### Key Components 1. **Timer Management** - `_scheduleStartTimer`: Dart Timer instance that handles the countdown - `_currentScheduleId`: Tracks the active schedule to prevent stale events 2. **Event Handling** - `ScheduleUpcomingReceived`: Triggers timer setup - `ScheduleStarted`: Fired when timer completes 3. **State Transitions** - `upcoming` → `started`: When timer fires for upcoming schedules - `ongoing` → `started`: When timer fires for preparation-in-progress schedules ### Timer Calculation The timer calculates the exact target time as: ```dart final targetTime = DateTime( scheduleTime.year, scheduleTime.month, scheduleTime.day, scheduleTime.hour, scheduleTime.minute, 0, // Always trigger at 00 seconds 0, // 0 milliseconds ); ``` ### Safety Features - **Timer Cancellation**: Previous timers are automatically cancelled when new schedules arrive - **Bloc State Validation**: Timer callbacks verify the bloc is still active before firing events - **Schedule ID Matching**: Events only fire for the currently tracked schedule - **Proper Cleanup**: All timers are cancelled when the bloc is disposed ## 🛡️ Error Handling The system includes several safety mechanisms: 1. **Past Schedule Protection**: Timers are not set for schedules in the past 2. **Bloc Lifecycle Management**: Timer callbacks check `isClosed` before adding events 3. **Memory Leak Prevention**: All timers are properly cancelled in `close()` 4. **Race Condition Prevention**: Schedule ID tracking prevents stale timer events ## 📱 Usage Example The timer system works automatically within the `ScheduleBloc`: ```dart // When a new schedule is received bloc.add(ScheduleSubscriptionRequested()); // The bloc will: // 1. Listen for upcoming schedules // 2. Automatically start timers for each schedule // 3. Emit ScheduleStarted events at the exact scheduled time // 4. Transition to 'started' state // Listen for state changes bloc.stream.listen((state) { if (state.status == ScheduleStatus.started) { // Handle schedule start (e.g., show notification, start tracking) } }); ``` ## 🔧 Configuration The timer system requires no additional configuration and works automatically with: - Any `ScheduleWithPreparationEntity` that has a valid `scheduleTime` - Both upcoming and ongoing schedule states - All timezone-aware DateTime calculations ## 📊 Performance Considerations - **Single Timer**: Only one timer runs at a time per bloc instance - **Minimal Memory Footprint**: Timers are created/destroyed as needed - **Precise Timing**: Uses Dart's native Timer for accurate scheduling - **Efficient Cleanup**: No lingering resources after bloc disposal ## 🚀 Future Enhancements Potential improvements to consider: - Multiple concurrent schedule timers - Configurable timer precision (seconds vs milliseconds) - Timer persistence across app restarts - Integration with system-level scheduling APIs