refactor(claude-do): merge Dedupe: FormatRemaining aus UsagePill und UsageMonitorModal

ClaudeDo-Task: 94ea71ad-22a1-4612-8743-425d5fb43d75
This commit is contained in:
Mika Kuns
2026-08-24 10:02:22 +02:00
3 changed files with 24 additions and 25 deletions
@@ -0,0 +1,19 @@
using System;
using ClaudeDo.Ui.Localization;
namespace ClaudeDo.Ui.Services;
/// <summary>Shared "Xh Ym" formatting for usage-reset countdowns (pill tooltip + usage monitor gauges).</summary>
public static class UsageTimeFormat
{
public static string FormatRemaining(DateTimeOffset resetsAt)
{
var remaining = resetsAt - DateTimeOffset.UtcNow;
if (remaining < TimeSpan.Zero) remaining = TimeSpan.Zero;
var hours = (int)remaining.TotalHours;
var minutes = remaining.Minutes;
return hours > 0
? Loc.T("usage.pill.durationHoursMinutes", hours, minutes)
: Loc.T("usage.pill.durationMinutes", minutes);
}
}
@@ -391,8 +391,10 @@ public sealed partial class UsageGaugeRowViewModel : ObservableObject
public bool IsWarnSeverity => !string.Equals(Severity, "normal", StringComparison.OrdinalIgnoreCase);
// Includes the absolute HH:mm alongside the countdown, unlike the pill tooltip's shorter
// "resetIn" line (usage.pill.resetIn) — the modal has room for the detail, the tooltip doesn't.
public string ResetText => ResetsAt is { } r
? Loc.T("modals.usageMonitor.resetIn", FormatRemaining(r), r.ToLocalTime().ToString("HH:mm"))
? Loc.T("modals.usageMonitor.resetIn", UsageTimeFormat.FormatRemaining(r), r.ToLocalTime().ToString("HH:mm"))
: "";
/// <summary>Live values from a fresh snapshot, without replacing the row instance mid-view.</summary>
@@ -437,17 +439,6 @@ public sealed partial class UsageGaugeRowViewModel : ObservableObject
return Commit();
}
private static string FormatRemaining(DateTimeOffset resetsAt)
{
var remaining = resetsAt - DateTimeOffset.UtcNow;
if (remaining < TimeSpan.Zero) remaining = TimeSpan.Zero;
var hours = (int)remaining.TotalHours;
var minutes = remaining.Minutes;
return hours > 0
? Loc.T("usage.pill.durationHoursMinutes", hours, minutes)
: Loc.T("usage.pill.durationMinutes", minutes);
}
}
/// <summary>
@@ -96,9 +96,9 @@ public sealed partial class UsagePillViewModel : ViewModelBase
var lines = new List<string>();
if (s.FiveHourResetsAt is { } fiveReset)
lines.Add(Loc.T("usage.pill.resetIn", Loc.T("usage.pill.fiveHourLabel"), FormatRemaining(fiveReset)));
lines.Add(Loc.T("usage.pill.resetIn", Loc.T("usage.pill.fiveHourLabel"), UsageTimeFormat.FormatRemaining(fiveReset)));
if (s.SevenDayResetsAt is { } sevenReset)
lines.Add(Loc.T("usage.pill.resetIn", Loc.T("usage.pill.sevenDayLabel"), FormatRemaining(sevenReset)));
lines.Add(Loc.T("usage.pill.resetIn", Loc.T("usage.pill.sevenDayLabel"), UsageTimeFormat.FormatRemaining(sevenReset)));
if (s.IsGateBlocked && !string.IsNullOrEmpty(s.GateReason))
lines.Add(Loc.T("usage.pill.blockedReason", s.GateReason));
else if (s.EffectiveSlots < s.ConfiguredSlots)
@@ -120,15 +120,4 @@ public sealed partial class UsagePillViewModel : ViewModelBase
"seven_day" => Loc.T("usage.pill.sevenDayLabel"),
_ => "",
};
private static string FormatRemaining(DateTimeOffset resetsAt)
{
var remaining = resetsAt - DateTimeOffset.UtcNow;
if (remaining < TimeSpan.Zero) remaining = TimeSpan.Zero;
var hours = (int)remaining.TotalHours;
var minutes = remaining.Minutes;
return hours > 0
? Loc.T("usage.pill.durationHoursMinutes", hours, minutes)
: Loc.T("usage.pill.durationMinutes", minutes);
}
}