PlotDirector/PlotLine/ViewModels/StoryIntelligenceGlobalProgressViewModels.cs

86 lines
3.8 KiB
C#

using PlotLine.Models;
namespace PlotLine.ViewModels;
public sealed class StoryIntelligenceGlobalProgressViewModel
{
public IReadOnlyList<StoryIntelligenceGlobalProgressBookViewModel> Books { get; init; } = [];
public bool HasActiveWork => Books.Any(book => book.HasActiveRuns);
public int ActiveBookCount => Books.Count(book => book.HasActiveRuns);
public int ActiveRunCount => Books.Sum(book => book.PendingRunCount + book.RunningRunCount);
public int TotalExpectedScenes => Books.Sum(book => book.TotalExpectedScenes);
public int TotalDetectedScenes => TotalExpectedScenes;
public int CompletedScenes => Books.Sum(book => book.CompletedScenes);
public int FailedScenes => Books.Sum(book => book.FailedScenes);
public int ActiveScenes => Books.Sum(book => book.ActiveScenes);
public int ProgressPercent => TotalExpectedScenes <= 0
? 0
: Math.Clamp(Convert.ToInt32(Math.Round(CompletedScenes * 100m / TotalExpectedScenes)), 0, 100);
public string Status => Books.Any(book => book.Status == "Finalising")
? "Finalising"
: Books.Any(book => book.HasFailures)
? StoryIntelligenceRunStatuses.CompletedWithWarnings
: Books.Any(book => book.HasActiveRuns)
? StoryIntelligenceRunStatuses.Running
: StoryIntelligenceRunStatuses.Completed;
public string SummaryText => ActiveBookCount switch
{
0 => string.Empty,
1 => Books.First(book => book.HasActiveRuns).SummaryText,
_ => $"{ActiveBookCount:N0} books analysing"
};
}
public sealed class StoryIntelligenceGlobalProgressBookViewModel
{
public int? ProjectID { get; init; }
public int? BookID { get; init; }
public string BookTitle { get; init; } = "Book";
public int RunCount { get; init; }
public int PendingRunCount { get; init; }
public int RunningRunCount { get; init; }
public int CompletedRunCount { get; init; }
public int FailedRunCount { get; init; }
public int TotalExpectedScenes { get; init; }
public int TotalDetectedScenes => TotalExpectedScenes;
public int CompletedScenes { get; init; }
public int FailedScenes { get; init; }
public int ActiveScenes { get; init; }
public string Status { get; init; } = StoryIntelligenceRunStatuses.Pending;
public long TotalDurationMs { get; init; }
public DateTime UpdatedUtc { get; init; }
public bool HasActiveRuns => PendingRunCount > 0 || RunningRunCount > 0;
public bool HasFailures => FailedRunCount > 0 || FailedScenes > 0;
public int ProgressPercent => TotalExpectedScenes <= 0
? 0
: Math.Clamp(Convert.ToInt32(Math.Round(CompletedScenes * 100m / TotalExpectedScenes)), 0, 100);
public string SummaryText => $"{BookTitle}: {CompletedScenes:N0}/{Math.Max(TotalExpectedScenes, CompletedScenes):N0} scenes";
public string EstimatedRemaining => Status == "Finalising"
? "Finalising"
: EstimateRemaining(TotalDurationMs, CompletedScenes, FailedScenes, TotalExpectedScenes);
private static string EstimateRemaining(long elapsedMs, int completedScenes, int failedScenes, int totalScenes)
{
if (totalScenes <= 0 || completedScenes <= 0)
{
return "Calculating";
}
var remainingScenes = Math.Max(0, totalScenes - completedScenes - failedScenes);
if (remainingScenes == 0)
{
return "Finalising";
}
var averageSceneMs = elapsedMs / Math.Max(1, completedScenes);
var remaining = TimeSpan.FromMilliseconds(averageSceneMs * remainingScenes);
if (remaining.TotalMinutes >= 1)
{
return $"{Math.Max(1, (int)Math.Round(remaining.TotalMinutes)):N0} min";
}
return $"{Math.Max(1, (int)Math.Round(remaining.TotalSeconds)):N0} sec";
}
}