< Summary

Information
Class: Pomodoro.Web.Components.TimerDisplayBase
Assembly: Pomodoro.Web
File(s): /home/runner/work/Pomodoro/Pomodoro/src/Pomodoro.Web/Components/TimerDisplay.razor.cs
Line coverage
100%
Covered lines: 64
Uncovered lines: 0
Coverable lines: 64
Total lines: 147
Line coverage: 100%
Branch coverage
100%
Covered branches: 10
Total branches: 10
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_TimerService()100%11100%
get_Logger()100%11100%
get_RemainingTime()100%11100%
get_SessionType()100%11100%
get_IsRunning()100%11100%
get_CurrentRemainingTime()100%11100%
get_CurrentSessionType()100%11100%
get_CurrentIsRunning()100%11100%
OnInitialized()100%11100%
UpdateDisplay()100%11100%
HandleStateChangeError()100%11100%
OnTimerTick()100%11100%
OnTimerStateChanged()100%11100%
Dispose()100%11100%
FormatTime(...)100%11100%
GetSessionTypeLabel()100%44100%
GetTimerClass()100%66100%

File(s)

/home/runner/work/Pomodoro/Pomodoro/src/Pomodoro.Web/Components/TimerDisplay.razor.cs

#LineLine coverage
 1using Microsoft.AspNetCore.Components;
 2using Microsoft.Extensions.Logging;
 3using Pomodoro.Web.Models;
 4using Pomodoro.Web.Services;
 5
 6namespace Pomodoro.Web.Components;
 7
 8/// <summary>
 9/// Code-behind for TimerDisplay component
 10/// Reads directly from TimerService for real-time updates
 11/// </summary>
 12public class TimerDisplayBase : ComponentBase, IDisposable
 13{
 14    #region Dependencies
 15
 16    [Inject]
 319217    protected ITimerService TimerService { get; set; } = default!;
 18
 19    [Inject]
 56620    protected ILogger<TimerDisplayBase> Logger { get; set; } = default!;
 21
 22    #endregion
 23
 24    #region Parameters (for initial/override values only)
 25
 26    [Parameter]
 32527    public TimeSpan? RemainingTime { get; set; }
 28
 29    [Parameter]
 32530    public SessionType? SessionType { get; set; }
 31
 32    [Parameter]
 32533    public bool? IsRunning { get; set; }
 34
 35    #endregion
 36
 37    #region Private Fields
 38
 39    #endregion
 40
 41    #region Properties - Always read from service for real-time updates
 42
 37443    protected TimeSpan CurrentRemainingTime => TimerService.RemainingTime;
 75644    protected SessionType CurrentSessionType => TimerService.CurrentSessionType;
 37845    protected bool CurrentIsRunning => TimerService.IsRunning;
 46
 47    #endregion
 48
 49    #region Lifecycle Methods
 50
 51    protected override void OnInitialized()
 28052    {
 53        // Subscribe to timer service events
 28054        TimerService.OnTick += OnTimerTick;
 28055        TimerService.OnStateChanged += OnTimerStateChanged;
 28056    }
 57
 58    protected virtual void UpdateDisplay()
 159    {
 160        StateHasChanged();
 161    }
 62
 263    protected virtual void HandleStateChangeError() { }
 64
 65    private async void OnTimerTick()
 566    {
 67        try
 568        {
 569            await InvokeAsync(StateHasChanged);
 470        }
 171        catch (Exception ex)
 172        {
 173            Logger.LogError(ex, "Error in OnTimerTick");
 174        }
 575    }
 76
 77    private async void OnTimerStateChanged()
 878    {
 79        try
 880        {
 881            await InvokeAsync(StateHasChanged);
 782        }
 183        catch (Exception ex)
 184        {
 185            Logger.LogError(ex, "Error in OnTimerStateChanged");
 186        }
 887    }
 88
 89    public void Dispose()
 28090    {
 28091        TimerService.OnTick -= OnTimerTick;
 28092        TimerService.OnStateChanged -= OnTimerStateChanged;
 28093    }
 94
 95    #endregion
 96
 97    #region Business Logic Methods
 98
 99    /// <summary>
 100    /// Formats the remaining time as MM:SS
 101    /// </summary>
 102    protected string FormatTime(TimeSpan time)
 374103    {
 374104        return string.Format(Constants.TimeFormats.TimerFormat, (int)time.TotalMinutes, time.Seconds);
 374105    }
 106
 107    /// <summary>
 108    /// Gets the display label for the current session type
 109    /// </summary>
 110    protected string GetSessionTypeLabel()
 378111    {
 378112        var sessionType = CurrentSessionType;
 378113        return sessionType switch
 378114        {
 355115            Models.SessionType.Pomodoro => Constants.SessionTypes.PomodoroUppercase,
 12116            Models.SessionType.ShortBreak => Constants.SessionTypes.ShortBreakUppercase,
 8117            Models.SessionType.LongBreak => Constants.SessionTypes.LongBreakUppercase,
 3118            _ => Constants.SessionTypes.PomodoroUppercase
 378119        };
 378120    }
 121
 122    /// <summary>
 123    /// Gets the CSS class based on timer state and session type
 124    /// Returns both session class and paused state to allow session color with reduced opacity
 125    /// </summary>
 126    protected string GetTimerClass()
 378127    {
 128        // Get session class (matches PIP window behavior)
 378129        var sessionClass = CurrentSessionType switch
 378130        {
 355131            Models.SessionType.Pomodoro => Constants.SessionTypes.PomodoroClass,
 12132            Models.SessionType.ShortBreak => Constants.SessionTypes.ShortBreakClass,
 8133            Models.SessionType.LongBreak => Constants.SessionTypes.LongBreakClass,
 3134            _ => Constants.SessionTypes.PomodoroClass
 378135        };
 136
 137        // Add paused class if not running (allows session color + reduced opacity)
 378138        if (!CurrentIsRunning)
 357139        {
 357140            return $"{sessionClass} {Constants.SessionTypes.PausedState}";
 141        }
 142
 21143        return sessionClass;
 378144    }
 145
 146    #endregion
 147}