Skip to content

Latest commit

 

History

History
98 lines (78 loc) · 3.96 KB

File metadata and controls

98 lines (78 loc) · 3.96 KB

Fix: Activity Upload Time Mismatch

Issue

Activity uploads to Intervals.icu (and potentially other platforms) showed incorrect workout durations - typically 2 minutes shorter than the actual workout time displayed in the app for a 30-minute workout.

Root Cause

The workout system maintained two independent time tracking mechanisms:

  1. elapsedSeconds + _previouslyElapsedTime: Tracked wall-clock time using DateTime.now(), including system overhead
  2. _workoutProgressTime: Incremented by exactly 0.1s per timer tick (the "intended" workout time)
  3. Track points: Used DateTime.now() timestamps

This created a discrepancy:

  • App UI showed elapsedSeconds (wall-clock time with overhead)
  • Exported FIT files calculated duration from track point timestamps (also wall-clock time)
  • Timer overhead accumulated over time, causing the ~2 minute drift

Solution

Refactored to use _workoutProgressTime as the single source of truth:

Changes Made

workout_controller.dart

  • ✅ Converted elapsedSeconds from variable to computed getter: int get elapsedSeconds => _workoutProgressTime.round()
  • ✅ Removed _previouslyElapsedTime variable (no longer needed)
  • ✅ Changed _lastTrackPointTime from DateTime? to double (workout progress seconds)
  • ✅ Updated track point timestamp calculation: _workoutStartTime + Duration(milliseconds: workoutProgressTime * 1000)
  • ✅ Simplified pause/resume logic (no more wall-clock segment tracking)
  • ✅ Removed overhead-prone DateTime.now() calls during workout execution

workout_storage.dart

  • ✅ Removed elapsedSeconds parameter from state persistence
  • ✅ Removed _elapsedSecondsKey constant
  • ✅ Cleaned up state save/load logic

Impact

Fixed

  • ✅ Workout duration consistency across app display and file uploads
  • ✅ Eliminated ~2 minute time drift for 30-minute workouts
  • ✅ Track point timestamps now accurately reflect workout progress
  • ✅ FIT file durations match displayed elapsed time

Preserved

  • ✅ Pause/resume functionality works correctly
  • ✅ Background workout continuation works
  • ✅ Workout state persistence works
  • ✅ Navigation away from workout screen and back works
  • ✅ All existing features maintain compatibility

Code Quality

  • Net -26 lines of code (simplified by removing duplicate system)
  • 0 new warnings from flutter analyze
  • All tests pass (existing + new comprehensive tests)
  • Better maintainability (single source of truth is easier to debug)

Testing

Automated Tests

  1. test/erg_workout_test.dart: Validates GPX/FIT file generation (passing)
  2. test/timing_consistency_test.dart: Validates time consistency (new, passing)
    • Elapsed seconds equals workout progress seconds
    • Track point timestamps based on workout progress
    • Time tracking consistent after pause/resume

Recommended Manual Testing

  1. Complete 30-minute workout without pausing

    • Verify app shows 30:00 elapsed time
    • Upload to Intervals.icu
    • Verify uploaded workout shows 30:00 duration ✓
  2. Complete 30-minute workout with 2 pause cycles

    • Verify app shows 30:00 elapsed time
    • Upload to Intervals.icu
    • Verify uploaded workout shows 30:00 duration ✓
  3. Navigate away and back during workout

    • Start workout, wait 10 minutes
    • Navigate to another screen
    • Navigate back to workout screen
    • Verify timer continues correctly
    • Complete workout and upload
    • Verify uploaded duration matches ✓

Technical Documentation

See TIMING_FIX_EXPLANATION.md for detailed technical documentation including:

  • Architecture comparison (before/after)
  • Code flow diagrams
  • Migration notes
  • Testing guidelines

Migration Notes

  • No user action required - change is transparent to end users
  • No data migration needed - existing workout states load correctly
  • Backward compatible - old saved states are gracefully handled

Related Issue

Fixes issue reported in #85 by @Lunchtime0614