@@ -23,16 +23,21 @@ import 'package:whph/presentation/ui/shared/services/abstraction/i_translation_s
2323import 'package:whph/presentation/ui/shared/utils/app_theme_helper.dart' ;
2424
2525class AppTimer extends StatefulWidget {
26- final Function (Duration )? onTick; // For UI updates only - receives current elapsed/remaining time
26+ /// Callback invoked on each timer tick with the logical elapsed increment.
27+ /// In debug mode, the increment is 1 minute per tick; in release, 1 second per tick.
28+ /// Callers must use the elapsedIncrement parameter instead of assuming a fixed 1 second.
29+ final void Function (Duration elapsedIncrement)? onTick;
2730 final VoidCallback ? onTimerStart;
28- final Function (Duration )? onTimerStop; // For data persistence - receives total elapsed duration
29- final bool isMiniLayout; // Use compact layout for detail tables
31+ final Function (Duration )? onTimerStop;
32+ final Function (Duration )? onWorkSessionComplete;
33+ final bool isMiniLayout;
3034
3135 const AppTimer ({
3236 super .key,
3337 this .onTick,
3438 this .onTimerStart,
3539 this .onTimerStop,
40+ this .onWorkSessionComplete,
3641 this .isMiniLayout = false ,
3742 });
3843
@@ -96,7 +101,8 @@ class _AppTimerState extends State<AppTimer> {
96101 bool _isAlarmPlaying = false ;
97102 TimerMode _timerMode = TimerMode .pomodoro;
98103 Duration _elapsedTime = const Duration (); // For stopwatch mode
99- Duration _sessionTotalElapsed = const Duration (); // Total elapsed time for the entire session
104+ Duration _sessionTotalElapsed = const Duration ();
105+ Duration _currentWorkSessionElapsed = const Duration (); // Track current work session duration
100106
101107 int _getTotalDurationInSeconds () {
102108 if (_timerMode == TimerMode .normal) {
@@ -281,10 +287,9 @@ class _AppTimerState extends State<AppTimer> {
281287 void _startTimer () {
282288 if (_isRunning || _isAlarmPlaying) return ;
283289
284- // Reset session total elapsed time for new session
285290 _sessionTotalElapsed = const Duration ();
291+ _currentWorkSessionElapsed = const Duration ();
286292
287- // Call the onTimerStart callback if provided
288293 widget.onTimerStart? .call ();
289294
290295 if (mounted) {
@@ -295,7 +300,6 @@ class _AppTimerState extends State<AppTimer> {
295300 _updateSystemTrayTimer ();
296301 if (_tickingEnabled) _startTicking ();
297302
298- // Enable wakelock if the setting is enabled
299303 if (_keepScreenAwake) {
300304 _wakelockService.enable ();
301305 }
@@ -311,28 +315,25 @@ class _AppTimerState extends State<AppTimer> {
311315 _timer = Timer .periodic (const Duration (seconds: 1 ), (timer) {
312316 if (! mounted) return ;
313317
314- // Calculate the actual elapsed time increment for debug vs production
315- final elapsedIncrement = kDebugMode
316- ? const Duration (minutes: 1 ) // In debug mode, 1 minute of progress per second
317- : const Duration (seconds: 1 ); // In production, 1 second of progress per second
318+ final elapsedIncrement = kDebugMode ? const Duration (minutes: 1 ) : const Duration (seconds: 1 );
318319
319320 setState (() {
320321 if (_timerMode == TimerMode .stopwatch) {
321- // Stopwatch mode: count up indefinitely
322322 _elapsedTime += elapsedIncrement;
323323 } else {
324- // Normal and Pomodoro modes: count down
325324 _remainingTime -= elapsedIncrement;
326325 }
327326 });
328327
329- // Update session total elapsed time
330328 _sessionTotalElapsed += elapsedIncrement;
331329
332- // Call onTick for UI updates (passes current elapsed/remaining time, not increments)
330+ // Track current work session duration separately
331+ if (_isWorking) {
332+ _currentWorkSessionElapsed += elapsedIncrement;
333+ }
334+
333335 if (widget.onTick != null ) {
334- final timeToDisplay = _timerMode == TimerMode .stopwatch ? _elapsedTime : _remainingTime;
335- widget.onTick !(timeToDisplay);
336+ widget.onTick !(elapsedIncrement);
336337 }
337338 _updateSystemTrayTimer ();
338339
@@ -386,37 +387,35 @@ class _AppTimerState extends State<AppTimer> {
386387
387388 setState (() {
388389 _isRunning = false ;
389- _isAlarmPlaying = false ; // Reset alarm state
390+ _isAlarmPlaying = false ;
390391
391392 if (_timerMode == TimerMode .stopwatch) {
392- _elapsedTime = const Duration (); // Reset stopwatch
393+ _elapsedTime = const Duration ();
393394 } else {
394395 if (_timerMode == TimerMode .pomodoro) {
395396 if (! _isWorking) {
396- // If in break mode, switch back to work mode
397397 _isWorking = true ;
398398 }
399- _completedSessions = 0 ; // Reset completed sessions
400- _isLongBreak = false ; // Reset long break flag
399+ _completedSessions = 0 ;
400+ _isLongBreak = false ;
401401 }
402402
403403 _remainingTime = Duration (
404- seconds: _getTimeInSeconds (_workDuration), // Always set to work duration
404+ seconds: _getTimeInSeconds (_workDuration),
405405 );
406406 }
407407
408- // Stop timer
408+ // Reset work session duration when timer stops
409+ _currentWorkSessionElapsed = Duration .zero;
409410 _timer.cancel ();
410411
411- _soundManagerService.stopAll (); // Stop any playing sounds
412+ _soundManagerService.stopAll ();
412413 });
413414
414415 _resetSystemTrayIcon ();
415416 _removeTimerMenuItems ();
416- // Reset system tray title/body when stopping timer
417417 _resetSystemTrayToDefault ();
418418
419- // Call the onTimerStop callback with total elapsed duration for the session
420419 if (widget.onTimerStop != null ) {
421420 widget.onTimerStop !(_sessionTotalElapsed);
422421 }
@@ -437,7 +436,6 @@ class _AppTimerState extends State<AppTimer> {
437436 _stopAlarm ();
438437
439438 if (_timerMode == TimerMode .stopwatch) {
440- // In stopwatch mode, just restart the timer
441439 setState (() {
442440 _elapsedTime = const Duration ();
443441 });
@@ -446,36 +444,43 @@ class _AppTimerState extends State<AppTimer> {
446444 }
447445
448446 if (_timerMode == TimerMode .normal) {
449- // In normal mode, just restart the timer
450447 setState (() {
451448 _remainingTime = Duration (seconds: _getTimeInSeconds (_workDuration));
452449 });
453450 _startTimer ();
454451 return ;
455452 }
456453
457- // Pomodoro mode logic
454+ // Pass the current work session duration when work completes
455+ if (_isWorking && _currentWorkSessionElapsed > Duration .zero) {
456+ widget.onWorkSessionComplete? .call (_currentWorkSessionElapsed);
457+ }
458+
458459 setState (() {
459460 if (_isWorking) {
460- // Work session completed
461461 _completedSessions++ ;
462462 _isWorking = false ;
463463 _isLongBreak = _completedSessions >= _sessionsCount;
464464
465465 if (_isLongBreak) {
466- _completedSessions = 0 ; // Reset session count after long break
466+ _completedSessions = 0 ;
467467 }
468468
469469 _remainingTime = Duration (
470470 seconds: _getTimeInSeconds (_isLongBreak ? _longBreakDuration : _breakDuration),
471471 );
472+
473+ // Reset work session duration when starting break
474+ _currentWorkSessionElapsed = Duration .zero;
472475 } else {
473- // Break completed, start work
474476 _isWorking = true ;
475477 _isLongBreak = false ;
476478 _remainingTime = Duration (
477479 seconds: _getTimeInSeconds (_workDuration),
478480 );
481+
482+ // Reset work session duration when starting new work session
483+ _currentWorkSessionElapsed = Duration .zero;
479484 }
480485 });
481486 _startTimer ();
0 commit comments