feat(claude-do): [A4] WeeklyReport, DailyPrep und Planning-Aktionen auf OperationStatus umstellen
WeeklyReportModalViewModel.Generate, PrepPanelViewModel.PlanDayAsync und die beiden Planning-Aktionen (QueuePlanningSubtasksAsync, FinalizePlanningSessionAsync) laufen jetzt durch je eine OperationStatus + OperationIndicator statt handgebauter Spinner. Die beiden Planning-Aktionen teilen sich eine Instanz, angezeigt im Tasks-Island-Header, weil sie aus einem sofort schliessenden Kontextmenue ausgeloest werden und es keine dauerhafte Pro-Zeilen-Flaeche gibt, an die ein Indikator gehaengt werden koennte.
This commit is contained in:
@@ -9,24 +9,32 @@ public sealed partial class WeeklyReportModalViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IWorkerClient _worker;
|
||||
|
||||
public WeeklyReportModalViewModel(IWorkerClient worker) => _worker = worker;
|
||||
public WeeklyReportModalViewModel(IWorkerClient worker)
|
||||
{
|
||||
_worker = worker;
|
||||
// OperationStatus is a nested ObservableObject — [NotifyCanExecuteChangedFor] can't see
|
||||
// into it, so IsRunning changes are relayed by hand.
|
||||
GenerateOperation.PropertyChanged += (_, e) =>
|
||||
{
|
||||
if (e.PropertyName != nameof(OperationStatus.IsRunning)) return;
|
||||
GenerateCommand.NotifyCanExecuteChanged();
|
||||
OnPropertyChanged(nameof(EmptyStateVisible));
|
||||
};
|
||||
}
|
||||
|
||||
public OperationStatus GenerateOperation { get; } = new();
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(HasReport))]
|
||||
[NotifyPropertyChangedFor(nameof(EmptyStateVisible))]
|
||||
private string? _reportMarkdown;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(EmptyStateVisible))]
|
||||
[NotifyCanExecuteChangedFor(nameof(GenerateCommand))]
|
||||
private bool _isBusy;
|
||||
|
||||
[ObservableProperty] private DateTime? _startDate;
|
||||
[ObservableProperty] private DateTime? _endDate;
|
||||
[ObservableProperty] private string _statusMessage = "";
|
||||
|
||||
public bool HasReport => !string.IsNullOrWhiteSpace(ReportMarkdown);
|
||||
public bool EmptyStateVisible => !HasReport && !IsBusy;
|
||||
public bool EmptyStateVisible => !HasReport && !GenerateOperation.IsRunning;
|
||||
|
||||
public Action? CloseAction { get; set; }
|
||||
[RelayCommand] private void Close() => CloseAction?.Invoke();
|
||||
@@ -68,21 +76,19 @@ public sealed partial class WeeklyReportModalViewModel : ViewModelBase
|
||||
catch (Exception ex) { StatusMessage = ex.Message; }
|
||||
}
|
||||
|
||||
private bool CanGenerate() => !IsBusy;
|
||||
private bool CanGenerate() => !GenerateOperation.IsRunning;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanGenerate))]
|
||||
private async Task Generate()
|
||||
{
|
||||
if (!RangeValid) { StatusMessage = Loc.T("vm.weeklyReport.invalidRange"); return; }
|
||||
IsBusy = true;
|
||||
StatusMessage = Loc.T("vm.weeklyReport.generating");
|
||||
using var op = GenerateOperation.Begin(Loc.T("ops.reports.generatingWeekly"));
|
||||
StatusMessage = "";
|
||||
try
|
||||
{
|
||||
ReportMarkdown = await _worker.GenerateWeekReportAsync(
|
||||
DateOnly.FromDateTime(StartDate!.Value), DateOnly.FromDateTime(EndDate!.Value));
|
||||
StatusMessage = "";
|
||||
}
|
||||
catch (Exception ex) { StatusMessage = Loc.T("vm.weeklyReport.error", ex.Message); }
|
||||
finally { IsBusy = false; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user