345 lines
14 KiB
C#
345 lines
14 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using PlotLine.Models;
|
|
|
|
namespace PlotLine.ViewModels;
|
|
|
|
public sealed class OnboardingWizardViewModel
|
|
{
|
|
public string CurrentStep { get; set; } = OnboardingSteps.Welcome;
|
|
public int StepNumber { get; set; } = 1;
|
|
public int TotalSteps { get; set; } = 6;
|
|
public string? WritingJourney { get; set; }
|
|
public string? WritingSoftware { get; set; }
|
|
public int? ProjectID { get; set; }
|
|
public int? BookID { get; set; }
|
|
public string? SelectedProjectName { get; set; }
|
|
public string? SelectedBookTitle { get; set; }
|
|
public bool IsMicrosoftWordPath => string.Equals(WritingSoftware, WritingSoftwareValues.MicrosoftWord, StringComparison.Ordinal);
|
|
public CompanionPresenceViewModel CompanionPresence { get; set; } = new();
|
|
public ManuscriptScanStateViewModel ScanState { get; set; } = new();
|
|
public IReadOnlyList<OnboardingOptionViewModel> Options { get; set; } = [];
|
|
public IReadOnlyList<OnboardingProjectOptionViewModel> ProjectOptions { get; set; } = [];
|
|
public IReadOnlyList<OnboardingBookOptionViewModel> BookOptions { get; set; } = [];
|
|
public ProjectOnboardingForm ProjectForm { get; set; } = new();
|
|
public BookOnboardingForm BookForm { get; set; } = new();
|
|
}
|
|
|
|
public sealed class OnboardingOptionViewModel
|
|
{
|
|
public string Value { get; init; } = string.Empty;
|
|
public string Title { get; init; } = string.Empty;
|
|
public string Description { get; init; } = string.Empty;
|
|
public string? Badge { get; init; }
|
|
}
|
|
|
|
public sealed class OnboardingJourneyHeaderViewModel
|
|
{
|
|
public int CurrentStep { get; init; }
|
|
public int TotalSteps { get; init; } = 9;
|
|
public string AriaLabel { get; init; } = "Manuscript import progress";
|
|
}
|
|
|
|
public sealed class WritingJourneyOnboardingForm
|
|
{
|
|
[Required(ErrorMessage = "Choose the closest writing stage before continuing.")]
|
|
public string? WritingJourney { get; set; }
|
|
}
|
|
|
|
public sealed class WritingSoftwareOnboardingForm
|
|
{
|
|
[Required(ErrorMessage = "Choose the software you write in before continuing.")]
|
|
public string? WritingSoftware { get; set; }
|
|
}
|
|
|
|
public static class OnboardingSelectionModes
|
|
{
|
|
public const string Create = "Create";
|
|
public const string Select = "Select";
|
|
}
|
|
|
|
public sealed class ProjectOnboardingForm
|
|
{
|
|
[Required]
|
|
public string Mode { get; set; } = OnboardingSelectionModes.Create;
|
|
|
|
public int? SelectedProjectID { get; set; }
|
|
|
|
[StringLength(200)]
|
|
public string? ProjectName { get; set; }
|
|
|
|
public string? Description { get; set; }
|
|
}
|
|
|
|
public sealed class BookOnboardingForm
|
|
{
|
|
[Required]
|
|
public string Mode { get; set; } = OnboardingSelectionModes.Create;
|
|
|
|
public int? SelectedBookID { get; set; }
|
|
|
|
[StringLength(200)]
|
|
public string? BookTitle { get; set; }
|
|
|
|
[StringLength(200)]
|
|
public string? Subtitle { get; set; }
|
|
|
|
[Range(1, int.MaxValue, ErrorMessage = "Target word count must be greater than zero.")]
|
|
public int? TargetWordCount { get; set; }
|
|
}
|
|
|
|
public sealed class OnboardingProjectOptionViewModel
|
|
{
|
|
public int ProjectID { get; init; }
|
|
public string ProjectName { get; init; } = string.Empty;
|
|
public string Description { get; init; } = string.Empty;
|
|
}
|
|
|
|
public sealed class OnboardingBookOptionViewModel
|
|
{
|
|
public int BookID { get; init; }
|
|
public string DisplayTitle { get; init; } = string.Empty;
|
|
public string Detail { get; init; } = string.Empty;
|
|
}
|
|
|
|
public sealed class OnboardingNudgeViewModel
|
|
{
|
|
public bool ShouldShow { get; init; }
|
|
public string ButtonText { get; init; } = "Start setup";
|
|
public string Title { get; init; } = "Set up PlotDirector around the way you write";
|
|
public string Description { get; init; } = "Answer a few quick questions so PlotDirector can guide your first project.";
|
|
public bool IsCompanionPresence { get; init; }
|
|
public bool CompanionConnected { get; init; }
|
|
}
|
|
|
|
public sealed class StoryIntelligenceOverviewViewModel
|
|
{
|
|
public Guid? PreviewID { get; init; }
|
|
public int? ProjectID { get; init; }
|
|
public int? BookID { get; init; }
|
|
public string? SelectedProjectName { get; init; }
|
|
public string? SelectedBookTitle { get; init; }
|
|
public int ApprovedChapterCount { get; init; }
|
|
public int ApprovedWordCount { get; init; }
|
|
public int MissingChapterTextCount { get; init; }
|
|
public string? Message { get; init; }
|
|
public Guid? ExistingBatchID { get; init; }
|
|
public StoryIntelligenceJobProgress? ExistingJob { get; init; }
|
|
public bool CanStart { get; init; }
|
|
}
|
|
|
|
public sealed class StoryIntelligenceProgressViewModel
|
|
{
|
|
public StoryIntelligenceJobProgress Job { get; init; } = new();
|
|
public Guid? BatchID { get; init; }
|
|
public Guid? PreviewID { get; init; }
|
|
public int ProjectID { get; init; }
|
|
public int BookID { get; init; }
|
|
public string? ProjectName { get; init; }
|
|
public string? BookTitle { get; init; }
|
|
public IReadOnlyList<StoryIntelligenceOnboardingChapterViewModel> Chapters { get; init; } = [];
|
|
public int ChapterCount => Chapters.Count;
|
|
public int CompletedChapterCount => Chapters.Count(chapter => chapter.IsRunComplete);
|
|
public int CommittedChapterCount => Chapters.Count(chapter => chapter.HasCompletedCommit);
|
|
public int FailedChapterCount => Chapters.Count(chapter => chapter.IsFailed);
|
|
public int TotalDetectedScenes => Chapters.Sum(chapter => chapter.TotalDetectedScenes ?? 0);
|
|
public int TotalCompletedScenes => Chapters.Sum(chapter => chapter.CompletedScenes ?? 0);
|
|
public int TotalFailedScenes => Chapters.Sum(chapter => chapter.FailedScenes ?? 0);
|
|
public int TotalAnalysedWords => Chapters.Sum(chapter => chapter.SourceWordCount ?? 0);
|
|
public decimal? TotalEstimatedCostUSD => Chapters.Any(chapter => chapter.EstimatedCostUSD.HasValue) ? Chapters.Sum(chapter => chapter.EstimatedCostUSD ?? 0m) : null;
|
|
public long TotalDurationMs => Chapters.Sum(chapter => chapter.TotalDurationMs ?? 0);
|
|
public bool HasActiveRuns => Chapters.Any(chapter => chapter.IsActive);
|
|
public bool AllCommitted => Chapters.Count > 0 && Chapters.All(chapter => chapter.HasCompletedCommit);
|
|
public bool HasReadyScenesToCreate => Chapters.Any(chapter => chapter.CanCommit);
|
|
}
|
|
|
|
public sealed class StoryIntelligenceCompletionViewModel
|
|
{
|
|
public StoryIntelligenceJobProgress Job { get; init; } = new();
|
|
public Guid? BatchID { get; init; }
|
|
public int ProjectID { get; init; }
|
|
public int BookID { get; init; }
|
|
public int? FirstChapterID { get; init; }
|
|
public string? ProjectName { get; init; }
|
|
public string? BookTitle { get; init; }
|
|
public int ChaptersCommitted { get; init; }
|
|
public int ScenesCreated { get; init; }
|
|
}
|
|
|
|
public sealed class StoryIntelligenceOnboardingChapterViewModel
|
|
{
|
|
public string TemporaryChapterKey { get; init; } = string.Empty;
|
|
public int ChapterNumber { get; init; }
|
|
public string ChapterTitle { get; init; } = string.Empty;
|
|
public int ChapterID { get; init; }
|
|
public int RunID { get; init; }
|
|
public string Status { get; init; } = string.Empty;
|
|
public string? CurrentStage { get; init; }
|
|
public string? CurrentMessage { get; init; }
|
|
public int? TotalDetectedScenes { get; init; }
|
|
public int? CompletedScenes { get; init; }
|
|
public int? FailedScenes { get; init; }
|
|
public int? SourceWordCount { get; init; }
|
|
public int? TotalTokens { get; init; }
|
|
public long? TotalDurationMs { get; init; }
|
|
public decimal? EstimatedCostUSD { get; init; }
|
|
public decimal? EstimatedCostGBP { get; init; }
|
|
public string? FailureStage { get; init; }
|
|
public string? ErrorMessage { get; init; }
|
|
public string? LatestSceneSummary { get; init; }
|
|
public bool HasCompletedCommit { get; init; }
|
|
public bool CanCommit { get; init; }
|
|
public int ScenesCreated { get; init; }
|
|
public string? CommitMessage { get; init; }
|
|
public IReadOnlyList<string> Blockers { get; init; } = [];
|
|
public IReadOnlyList<string> Warnings { get; init; } = [];
|
|
public IReadOnlyList<StoryIntelligenceOnboardingScenePreviewViewModel> Scenes { get; init; } = [];
|
|
public decimal? AverageConfidence => Scenes.Count == 0 ? null : Scenes.Average(scene => scene.Confidence ?? 0m);
|
|
public bool IsActive => Status is StoryIntelligenceRunStatuses.Pending or StoryIntelligenceRunStatuses.Running;
|
|
public bool IsRunComplete => Status is StoryIntelligenceRunStatuses.Completed or StoryIntelligenceRunStatuses.CompletedWithWarnings;
|
|
public bool IsFailed => Status is StoryIntelligenceRunStatuses.Failed or StoryIntelligenceRunStatuses.Cancelled;
|
|
}
|
|
|
|
public sealed class StoryIntelligenceOnboardingScenePreviewViewModel
|
|
{
|
|
public int SceneNumber { get; init; }
|
|
public string Summary { get; init; } = string.Empty;
|
|
public string? Pov { get; init; }
|
|
public string? Setting { get; init; }
|
|
public decimal? Confidence { get; init; }
|
|
public bool HasWarnings { get; init; }
|
|
}
|
|
|
|
public sealed class StoryIntelligenceDashboardViewModel
|
|
{
|
|
public bool ShouldShow { get; init; }
|
|
public string Title { get; init; } = "Story Intelligence available";
|
|
public string Description { get; init; } = "Prepare the optional analysis framework for your manuscript.";
|
|
public string ButtonText { get; init; } = "Set up Story Intelligence";
|
|
public StoryIntelligenceJobProgress? Job { get; init; }
|
|
}
|
|
|
|
public sealed class CompanionPresenceViewModel
|
|
{
|
|
public bool IsConnected { get; init; }
|
|
public bool DocumentOpen { get; init; }
|
|
public string Status { get; init; } = "Offline";
|
|
public string? CompanionVersion { get; init; }
|
|
public string? CurrentDocumentName { get; init; }
|
|
public DateTime? LastHeartbeatUtc { get; init; }
|
|
}
|
|
|
|
public sealed class ManuscriptScanStateViewModel
|
|
{
|
|
public string Status { get; init; } = ManuscriptScanStatuses.NotStarted;
|
|
public string ReviewStatus { get; init; } = ManuscriptScanReviewStatuses.ScanComplete;
|
|
public string Message { get; init; } = string.Empty;
|
|
public int? PercentComplete { get; init; }
|
|
public int ChapterCount { get; init; }
|
|
public int SceneCount { get; init; }
|
|
public int CharacterCandidateCount { get; init; }
|
|
public int TotalWordCount { get; init; }
|
|
public Guid? PreviewID { get; init; }
|
|
public bool IsRunning => string.Equals(Status, ManuscriptScanStatuses.Running, StringComparison.Ordinal);
|
|
public bool IsComplete => string.Equals(Status, ManuscriptScanStatuses.Complete, StringComparison.Ordinal);
|
|
public bool IsFailed => string.Equals(Status, ManuscriptScanStatuses.Failed, StringComparison.Ordinal);
|
|
}
|
|
|
|
public sealed class ManuscriptScanReviewViewModel
|
|
{
|
|
public Guid PreviewID { get; init; }
|
|
public string ReviewStatus { get; init; } = ManuscriptScanReviewStatuses.ScanComplete;
|
|
public string DocumentTitle { get; init; } = "Word manuscript";
|
|
public string SelectedProjectName { get; init; } = string.Empty;
|
|
public string SelectedBookTitle { get; init; } = string.Empty;
|
|
public int TotalWordCount { get; init; }
|
|
public int ChapterCount { get; init; }
|
|
public int SceneCount { get; init; }
|
|
public int CharacterCandidateCount { get; init; }
|
|
public int SelectedChapterCount { get; init; }
|
|
public int SelectedSceneCount { get; init; }
|
|
public int SelectedCharacterCount { get; init; }
|
|
public int SelectedWordCount { get; init; }
|
|
public IReadOnlyList<ManuscriptScanReviewChapterViewModel> Chapters { get; init; } = [];
|
|
public IReadOnlyList<ManuscriptScanReviewCharacterViewModel> CharacterCandidates { get; init; } = [];
|
|
public IReadOnlyList<ManuscriptScanExistingCharacterOptionViewModel> ExistingCharacterOptions { get; init; } = [];
|
|
}
|
|
|
|
public sealed class ManuscriptScanReviewChapterViewModel
|
|
{
|
|
public string TemporaryChapterKey { get; init; } = string.Empty;
|
|
public int ChapterNumber { get; init; }
|
|
public string Title { get; init; } = string.Empty;
|
|
public string ReviewTitle { get; init; } = string.Empty;
|
|
public bool Include { get; init; }
|
|
public int WordCount { get; init; }
|
|
public IReadOnlyList<ManuscriptScanReviewSceneViewModel> Scenes { get; init; } = [];
|
|
}
|
|
|
|
public sealed class ManuscriptScanReviewSceneViewModel
|
|
{
|
|
public string TemporarySceneKey { get; init; } = string.Empty;
|
|
public string TemporaryChapterKey { get; init; } = string.Empty;
|
|
public int SceneNumberWithinChapter { get; init; }
|
|
public string? Title { get; init; }
|
|
public string? ReviewTitle { get; init; }
|
|
public bool Include { get; init; }
|
|
public int WordCount { get; init; }
|
|
public string? OpeningTextPreview { get; init; }
|
|
}
|
|
|
|
public sealed class ManuscriptScanReviewCharacterViewModel
|
|
{
|
|
public string TemporaryCharacterKey { get; init; } = string.Empty;
|
|
public string Name { get; init; } = string.Empty;
|
|
public string ReviewName { get; init; } = string.Empty;
|
|
public bool Include { get; init; }
|
|
public int MentionCount { get; init; }
|
|
public int QualityScore { get; init; }
|
|
public string Category { get; init; } = "PossibleCharacter";
|
|
public string? Reason { get; init; }
|
|
public int? ExistingCharacterID { get; init; }
|
|
public string? ExistingCharacterName { get; init; }
|
|
public bool IsExistingCharacterMatch => ExistingCharacterID.HasValue;
|
|
}
|
|
|
|
public sealed class ManuscriptScanExistingCharacterOptionViewModel
|
|
{
|
|
public int CharacterID { get; init; }
|
|
public string CharacterName { get; init; } = string.Empty;
|
|
}
|
|
|
|
public sealed class ManuscriptScanReviewForm
|
|
{
|
|
public Guid PreviewID { get; set; }
|
|
public List<ManuscriptScanChapterReviewFormItem> Chapters { get; set; } = [];
|
|
public List<ManuscriptScanSceneReviewFormItem> Scenes { get; set; } = [];
|
|
public List<ManuscriptScanCharacterReviewFormItem> Characters { get; set; } = [];
|
|
}
|
|
|
|
public sealed class ManuscriptScanChapterReviewFormItem
|
|
{
|
|
public string TemporaryChapterKey { get; set; } = string.Empty;
|
|
public bool Include { get; set; }
|
|
public string Title { get; set; } = string.Empty;
|
|
public int ChapterNumber { get; set; }
|
|
}
|
|
|
|
public sealed class ManuscriptScanSceneReviewFormItem
|
|
{
|
|
public string TemporarySceneKey { get; set; } = string.Empty;
|
|
public string TemporaryChapterKey { get; set; } = string.Empty;
|
|
public bool Include { get; set; }
|
|
public string? Title { get; set; }
|
|
public int SceneNumberWithinChapter { get; set; }
|
|
public bool AllowZeroWords { get; set; }
|
|
}
|
|
|
|
public sealed class ManuscriptScanCharacterReviewFormItem
|
|
{
|
|
public string TemporaryCharacterKey { get; set; } = string.Empty;
|
|
public bool Include { get; set; }
|
|
public string Name { get; set; } = string.Empty;
|
|
public string Category { get; set; } = "PossibleCharacter";
|
|
public int? ExistingCharacterID { get; set; }
|
|
}
|