using Spectre.Console; namespace FCPModUpdater.UI; public static class ProgressReporter { public static async Task WithStatusAsync(string status, Func> action) { return await AnsiConsole.Status() .Spinner(Spinner.Known.Dots) .SpinnerStyle(Style.Parse("blue")) .StartAsync(status, async _ => await action()); } public static async Task WithStatusAsync(string status, Func action) { await AnsiConsole.Status() .Spinner(Spinner.Known.Dots) .SpinnerStyle(Style.Parse("blue")) .StartAsync(status, async _ => await action()); } public static async Task WithProgressAsync( string description, IEnumerable<(string Name, Func Action)> tasks) { await AnsiConsole.Progress() .Columns( new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn(), new SpinnerColumn()) .StartAsync(async ctx => { var taskList = tasks.ToList(); var progressTasks = taskList .Select(t => (Task: ctx.AddTask(t.Name), t.Action)) .ToList(); foreach ((ProgressTask task, var action) in progressTasks) { await action(task); task.Value = 100; } }); } public static async Task> WithBatchProgressAsync( string description, IReadOnlyList items, Func nameSelector, Func, Task<(bool Success, string? Error)>> action) { var itemTasks = new List(); await AnsiConsole.Progress() .Columns( new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn(), new SpinnerColumn()) .StartAsync(async ctx => { ProgressTask overallTask = ctx.AddTask($"[bold]{description}[/]", maxValue: items.Count); foreach (T item in items) { var name = nameSelector(item); ProgressTask itemTask = ctx.AddTask($" {name}"); itemTasks.Add(itemTask); var progress = new Progress(p => itemTask.Value = p); try { var (success, error) = await action(item, progress); itemTask.Tag(new BatchResult(name, success, error)); itemTask.Value = 100; itemTask.Description = success ? $" [green]{name}[/]" : $" [red]{name}[/]"; } catch (Exception ex) { itemTask.Tag(new BatchResult(name, false, ex.Message)); itemTask.Value = 100; itemTask.Description = $" [red]{name}[/]"; } overallTask.Increment(1); } }); return itemTasks .Select(t => (BatchResult)t.Tag!) .Select(r => (r.Name, r.Success, r.Error)) .ToList(); } private record BatchResult(string Name, bool Success, string? Error); }