refactor: hoist Moscow offset + sport labels into shared helpers (HIGH)

* New Marathon.Domain.ValueObjects.MoscowTime with Offset, Now, and
  EndOfMoscowDay(DateOnly) — replaces ~15 inline TimeSpan.FromHours(3)
  literals across Domain/Application/Infrastructure/UI.
* New Marathon.UI.Services.SportLabels.Resolve(IStringLocalizer, int) —
  replaces 6 near-identical SportLabel switch bodies in EventListShell,
  Events/Detail, Anomalies/AnomalyFeed, Results/ResultsList,
  Results/ResultsLoader, and AnomalyCard. Single source of truth for the
  6/11/22723/43658 sport-code mapping. Pages keep a one-liner wrapper so
  the call sites stay terse.
This commit is contained in:
2026-05-09 15:40:35 +03:00
parent d1e6ce7ce2
commit fed3a09695
18 changed files with 92 additions and 96 deletions
+1 -8
View File
@@ -215,14 +215,7 @@
_ => kind.ToString(),
};
private string SportLabel(int code) => code switch
{
6 => L["Sport.Basketball"],
11 => L["Sport.Football"],
22723 => L["Sport.Tennis"],
43658 => L["Sport.Hockey"],
_ => string.Format(System.Globalization.CultureInfo.InvariantCulture, "Sport {0}", code),
};
private string SportLabel(int code) => SportLabels.Resolve(L, code);
private static string FormatRate(decimal? r) => r is { } v
? v.ToString("0.00", System.Globalization.CultureInfo.InvariantCulture)
@@ -113,7 +113,7 @@
protected override void OnInitialized()
{
var moscow = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(3));
var moscow = MoscowTime.Now;
_from = InitialFrom ?? moscow.AddDays(-1).Date;
_to = InitialTo ?? moscow.AddDays(1).Date;
_kind = InitialKind;
@@ -140,10 +140,9 @@
try
{
// Use Moscow offset to match domain ScheduledAt invariant.
var moscow = TimeSpan.FromHours(3);
var range = new AppDateRange(
new DateTimeOffset(_from.Value.Date, moscow),
new DateTimeOffset(_to.Value.Date.AddDays(1).AddSeconds(-1), moscow));
new DateTimeOffset(_from.Value.Date, MoscowTime.Offset),
MoscowTime.EndOfMoscowDay(DateOnly.FromDateTime(_to.Value.Date)));
var path = await ExportUseCase.ExecuteAsync(range, _kind, CancellationToken.None);
Dialog.Close(DialogResult.Ok(path));