PlotDirector/PlotLine/ViewModels/CoreViewModels.cs

2469 lines
96 KiB
C#

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Rendering;
using PlotLine.Models;
namespace PlotLine.ViewModels;
public sealed class ProjectEditViewModel
{
public int ProjectID { get; set; }
[Required, StringLength(200)]
[Display(Name = "Project / Series name")]
public string ProjectName { get; set; } = string.Empty;
public string? Description { get; set; }
[Display(Name = "Genre / Metric Preset")]
public string GenreMetricPresetKey { get; set; } = "Custom";
public IReadOnlyList<SelectListItem> GenreMetricPresetOptions { get; set; } = [];
}
public sealed class ProjectIndexViewModel
{
public IReadOnlyList<ProjectIndexCardViewModel> ActiveProjects { get; init; } = [];
public IReadOnlyList<ProjectIndexCardViewModel> ArchivedProjects { get; init; } = [];
public TrialVisibilityViewModel? Trial { get; init; }
public OnboardingNudgeViewModel OnboardingNudge { get; init; } = new();
public StoryIntelligenceDashboardViewModel StoryIntelligence { get; init; } = new();
}
public sealed class ProjectIndexCardViewModel
{
public int ProjectID { get; set; }
public string ProjectName { get; set; } = string.Empty;
public string? Description { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime UpdatedDate { get; set; }
public bool IsArchived { get; set; }
public DateTime? ArchivedDate { get; set; }
public string AccessRole { get; set; } = "Owner";
public bool IsOwner => string.Equals(AccessRole, "Owner", StringComparison.OrdinalIgnoreCase);
public int BookCount { get; set; }
public int TotalWords { get; set; }
public DateTime? LastBookUpdatedDate { get; set; }
public IReadOnlyList<string> CoverThumbnailPaths { get; set; } = [];
}
public sealed class ProjectDetailViewModel
{
public Project Project { get; set; } = new();
public ProjectDashboardSummaryViewModel Summary { get; set; } = new();
public ProjectDashboardSeriesProgressViewModel SeriesProgress { get; set; } = new();
public IReadOnlyList<ProjectDashboardActivityItemViewModel> RecentActivity { get; set; } = [];
public ProjectDashboardAttentionViewModel NeedsAttention { get; set; } = new();
public IReadOnlyList<ProjectDashboardBookCardViewModel> Books { get; set; } = [];
}
public sealed class ProjectDashboardSummaryViewModel
{
public int TotalBooks { get; set; }
public int PublishedBooks { get; set; }
public int DraftingBooks { get; set; }
public int PlanningBooks { get; set; }
public int TotalWords { get; set; }
public int CharacterCount { get; set; }
public int LocationCount { get; set; }
public int ActivePlotThreadCount { get; set; }
public int ContinuityWarningCount { get; set; }
}
public sealed class ProjectDashboardBookCardViewModel
{
public int BookID { get; set; }
public int BookNumber { get; set; }
public string BookTitle { get; set; } = string.Empty;
public string? Subtitle { get; set; }
public string Status { get; set; } = BookStatuses.Planning;
public string StatusCssClass { get; set; } = "dashboard-status-planning";
public int CurrentWordCount { get; set; }
public int? TargetWordCount { get; set; }
public decimal? ProgressPercentage { get; set; }
public int ChapterCount { get; set; }
public int SceneCount { get; set; }
public DateTime UpdatedDate { get; set; }
public string CoverThumbnailPath { get; set; } = "/images/placeholders/book-cover.svg";
public string WordCountLabel => TargetWordCount is > 0
? $"{CurrentWordCount:N0} / {TargetWordCount.Value:N0} words"
: $"{CurrentWordCount:N0} words";
}
public sealed class ProjectDashboardSeriesProgressViewModel
{
public decimal Percentage { get; set; }
public string SupportingLine { get; set; } = string.Empty;
public string CalculationLabel { get; set; } = string.Empty;
}
public sealed class ProjectDashboardActivityItemViewModel
{
public string ActivityType { get; set; } = string.Empty;
public string EntityType { get; set; } = string.Empty;
public string? EntityName { get; set; }
public string? Description { get; set; }
public string UserLabel { get; set; } = string.Empty;
public string TimeLabel { get; set; } = string.Empty;
public string IconLabel { get; set; } = string.Empty;
}
public sealed class ProjectDashboardAttentionViewModel
{
public IReadOnlyList<ProjectDashboardWarningItemViewModel> Warnings { get; set; } = [];
public IReadOnlyList<ProjectDashboardThreadItemViewModel> Threads { get; set; } = [];
public IReadOnlyList<ProjectDashboardOverdueBookViewModel> OverdueBooks { get; set; } = [];
public IReadOnlyList<ProjectDashboardBookAttentionItemViewModel> BookItems { get; set; } = [];
public bool ShowMissingSchedulePrompt { get; set; }
public bool HasItems => Warnings.Any() || Threads.Any() || OverdueBooks.Any() || BookItems.Any() || ShowMissingSchedulePrompt;
}
public sealed class ProjectDashboardWarningItemViewModel
{
public string SeverityName { get; set; } = string.Empty;
public string WarningTypeName { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
public string? LocationLabel { get; set; }
}
public sealed class ProjectDashboardThreadItemViewModel
{
public int PlotThreadID { get; set; }
public string ThreadTitle { get; set; } = string.Empty;
public string PlotLineName { get; set; } = string.Empty;
public string ThreadStatusName { get; set; } = string.Empty;
public int Importance { get; set; }
public string AttentionLabel { get; set; } = string.Empty;
}
public sealed class ProjectDashboardOverdueBookViewModel
{
public int BookID { get; set; }
public string BookTitle { get; set; } = string.Empty;
public DateTime TargetCompletionDate { get; set; }
}
public sealed class ProjectDashboardBookAttentionItemViewModel
{
public int BookID { get; set; }
public string BookTitle { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
public string Label { get; set; } = "Worth a look";
}
public sealed class ProjectCollaboratorsViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<ProjectCollaborator> Collaborators { get; set; } = [];
public IReadOnlyList<ProjectInvitation> PendingInvitations { get; set; } = [];
public ProjectCollaboratorInviteViewModel Invite { get; set; } = new();
}
public sealed class ProjectCollaboratorInviteViewModel
{
public int ProjectID { get; set; }
[Required, EmailAddress, StringLength(256)]
[Display(Name = "Collaborator email")]
public string EmailAddress { get; set; } = string.Empty;
}
public sealed class ProjectActivityViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<ProjectActivity> Activities { get; set; } = [];
}
public sealed class BookEditViewModel
{
public int BookID { get; set; }
public int ProjectID { get; set; }
[Required, StringLength(200)]
[Display(Name = "Book title")]
public string BookTitle { get; set; } = string.Empty;
[StringLength(200)]
public string? Subtitle { get; set; }
[StringLength(300)]
public string? Tagline { get; set; }
[Display(Name = "Short description")]
public string? ShortDescription { get; set; }
[Required, StringLength(50)]
public string Status { get; set; } = BookStatuses.Planning;
[Display(Name = "Book number")]
public int BookNumber { get; set; } = 1;
[Display(Name = "Target word count")]
[Range(1, int.MaxValue, ErrorMessage = "Target word count must be greater than zero.")]
public int? TargetWordCount { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Writing start date")]
public DateTime? WritingStartDate { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Target completion date")]
public DateTime? TargetCompletionDate { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Publication date")]
public DateTime? PublicationDate { get; set; }
[Display(Name = "Uses explicit scenes")]
public bool UsesExplicitScenes { get; set; }
[Display(Name = "Cover image")]
public IFormFile? CoverUpload { get; set; }
public string CoverThumbnailPath { get; set; } = "/images/placeholders/book-cover.svg";
public string? CoverStandardPath { get; set; }
public string? Description { get; set; }
public Project? Project { get; set; }
public IReadOnlyList<SelectListItem> StatusOptions { get; set; } = [];
}
public sealed class BookDetailViewModel
{
public Project Project { get; set; } = new();
public Book Book { get; set; } = new();
public ManuscriptDocumentModel? ManuscriptDocument { get; set; }
public IReadOnlyList<Chapter> Chapters { get; set; } = [];
}
public sealed class ChapterEditViewModel
{
public int ChapterID { get; set; }
public int BookID { get; set; }
[Display(Name = "Chapter number")]
public decimal ChapterNumber { get; set; } = 1;
[Required, StringLength(200)]
[Display(Name = "Chapter title")]
public string ChapterTitle { get; set; } = string.Empty;
public string? Summary { get; set; }
[Display(Name = "Revision status")]
public int RevisionStatusID { get; set; }
public bool IsLinkedToManuscript { get; set; }
public Book? Book { get; set; }
public Project? Project { get; set; }
public IReadOnlyList<SelectListItem> RevisionStatuses { get; set; } = [];
}
public sealed class ChapterDetailViewModel
{
public Project Project { get; set; } = new();
public Book Book { get; set; } = new();
public Chapter Chapter { get; set; } = new();
public IReadOnlyList<Scene> Scenes { get; set; } = [];
public int PendingCharacterSuggestionCount { get; set; }
public int PendingAssetSuggestionCount { get; set; }
public int PendingLocationSuggestionCount { get; set; }
}
public sealed class SceneEditViewModel
{
public int SceneID { get; set; }
public int ChapterID { get; set; }
[Display(Name = "Scene number")]
public decimal SceneNumber { get; set; } = 1;
[Required, StringLength(200)]
[Display(Name = "Scene title")]
public string SceneTitle { get; set; } = string.Empty;
public string? Summary { get; set; }
[Display(Name = "POV character")]
public int? POVCharacterID { get; set; }
[Display(Name = "Time mode")]
public int TimeModeID { get; set; }
public string TimeModeName { get; set; } = string.Empty;
[Display(Name = "Start date/time")]
public DateTime? StartDateTime { get; set; }
[Display(Name = "End date/time")]
public DateTime? EndDateTime { get; set; }
[Display(Name = "Duration")]
public decimal? DurationAmount { get; set; }
[Display(Name = "Duration unit")]
public int? DurationUnitID { get; set; }
[Display(Name = "Relative time")]
public string? RelativeTimeText { get; set; }
[Display(Name = "Time confidence")]
public int TimeConfidenceID { get; set; }
[Display(Name = "Purpose notes")]
public string? ScenePurposeNotes { get; set; }
[Display(Name = "Outcome notes")]
public string? SceneOutcomeNotes { get; set; }
[Display(Name = "Revision status")]
public int RevisionStatusID { get; set; }
public bool IsLinkedToManuscript { get; set; }
[Display(Name = "Primary location")]
public int? PrimaryLocationID { get; set; }
[Display(Name = "Floor plan")]
public int? FloorPlanID { get; set; }
[Display(Name = "Initial floor")]
public int? InitialFloorPlanFloorID { get; set; }
[Display(Name = "Scene purposes")]
public List<int> SelectedPurposeTypeIds { get; set; } = [];
public List<SceneMetricInputViewModel> Metrics { get; set; } = [];
public IReadOnlyList<ThreadEvent> ThreadEvents { get; set; } = [];
public ThreadEventCreateViewModel NewThreadEvent { get; set; } = new();
public IReadOnlyList<AssetEvent> AssetEvents { get; set; } = [];
public IReadOnlyList<AssetCustodyEvent> AssetCustodyEvents { get; set; } = [];
public IReadOnlyList<SceneAssetLocation> SceneAssetLocations { get; set; } = [];
public AssetEventCreateViewModel NewAssetEvent { get; set; } = new();
public AssetCustodyCreateViewModel NewAssetCustodyEvent { get; set; } = new();
public SceneAssetLocationCreateViewModel NewSceneAssetLocation { get; set; } = new();
public IReadOnlyList<SceneCharacter> SceneCharacters { get; set; } = [];
public IReadOnlyList<SceneCharacterSuggestion> CharacterSuggestions { get; set; } = [];
public IReadOnlyList<SceneAssetSuggestion> AssetSuggestions { get; set; } = [];
public IReadOnlyList<SceneLocationSuggestion> LocationSuggestions { get; set; } = [];
public IReadOnlyList<CharacterAttributeEvent> CharacterAttributeEvents { get; set; } = [];
public IReadOnlyList<CharacterKnowledgeItem> CharacterKnowledge { get; set; } = [];
public IReadOnlyList<RelationshipEvent> RelationshipEvents { get; set; } = [];
public SceneCharacterCreateViewModel NewSceneCharacter { get; set; } = new();
public CharacterAttributeEventCreateViewModel NewCharacterAttributeEvent { get; set; } = new();
public CharacterKnowledgeCreateViewModel NewCharacterKnowledge { get; set; } = new();
public RelationshipEventCreateViewModel NewRelationshipEvent { get; set; } = new();
public IReadOnlyList<SelectListItem> PlotLineOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> PlotThreadOptions { get; set; } = [];
public IReadOnlyList<PlotLineItem> PlotLineEventOptions { get; set; } = [];
public IReadOnlyList<PlotThread> PlotThreadEventOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ThreadTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ThreadEventTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> PlotEventTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetKindOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetStateOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetEventTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetCustodyEventTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> CustodyRoleOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> CharacterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> CharacterRoleOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> PresenceTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> CharacterAttributeTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> KnowledgeStateOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> RelationshipOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> RelationshipTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> RelationshipStateOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> LocationOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ChapterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneDependencyTypeOptions { get; set; } = [];
public IReadOnlyList<string> AssetDependencyMessages { get; set; } = [];
public IReadOnlyList<string> LocationConsistencyMessages { get; set; } = [];
public IReadOnlyList<ContinuityWarning> Warnings { get; set; } = [];
public IReadOnlyList<ContinuityWarning> AgeContinuityWarnings { get; set; } = [];
public IReadOnlyList<SceneDependency> DependenciesThisSceneNeeds { get; set; } = [];
public IReadOnlyList<SceneDependency> DependenciesNeedingThisScene { get; set; } = [];
public SceneDependencyCreateViewModel NewDependency { get; set; } = new();
public SceneMoveRequestViewModel MoveRequest { get; set; } = new();
public SceneWorkflow Workflow { get; set; } = new();
public IReadOnlyList<SceneNote> Notes { get; set; } = [];
public IReadOnlyList<SceneChecklistItem> ChecklistItems { get; set; } = [];
public IReadOnlyList<SceneAttachment> Attachments { get; set; } = [];
public SceneNoteEditViewModel NewNote { get; set; } = new();
public SceneChecklistItemEditViewModel NewChecklistItem { get; set; } = new();
public SceneAttachmentEditViewModel NewAttachment { get; set; } = new();
public IReadOnlyList<SelectListItem> SceneNoteTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneAttachmentTypeOptions { get; set; } = [];
public StorageUsage? StorageUsage { get; set; }
public StoryStateViewModel StoryState { get; set; } = new();
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
public bool ReturnToTimeline { get; set; }
public Chapter? Chapter { get; set; }
public Book? Book { get; set; }
public Project? Project { get; set; }
public IReadOnlyList<SelectListItem> RevisionStatuses { get; set; } = [];
public IReadOnlyList<SelectListItem> TimeModes { get; set; } = [];
public IReadOnlyList<SelectListItem> DurationUnits { get; set; } = [];
public IReadOnlyList<SelectListItem> TimeConfidences { get; set; } = [];
public IReadOnlyList<ScenePurposeType> ScenePurposeTypes { get; set; } = [];
}
public sealed class SceneDetailsSaveViewModel
{
public int SceneID { get; set; }
[Display(Name = "Scene number")]
public decimal SceneNumber { get; set; }
[Required, StringLength(200)]
[Display(Name = "Scene title")]
public string SceneTitle { get; set; } = string.Empty;
[Display(Name = "Revision status")]
public int RevisionStatusID { get; set; }
[Display(Name = "POV character")]
public int? POVCharacterID { get; set; }
[Display(Name = "Primary location")]
public int? PrimaryLocationID { get; set; }
[Display(Name = "Synopsis")]
public string? Summary { get; set; }
[Display(Name = "Time mode")]
public int TimeModeID { get; set; }
[Display(Name = "Time confidence")]
public int TimeConfidenceID { get; set; }
[Display(Name = "Start date/time")]
public DateTime? StartDateTime { get; set; }
[Display(Name = "End date/time")]
public DateTime? EndDateTime { get; set; }
[Display(Name = "Duration")]
public decimal? DurationAmount { get; set; }
[Display(Name = "Duration unit")]
public int? DurationUnitID { get; set; }
[Display(Name = "Relative time")]
public string? RelativeTimeText { get; set; }
}
public sealed class ScenePurposeSaveViewModel
{
public int SceneID { get; set; }
public List<int> SelectedPurposeTypeIds { get; set; } = [];
[Display(Name = "Purpose notes")]
public string? ScenePurposeNotes { get; set; }
[Display(Name = "Outcome notes")]
public string? SceneOutcomeNotes { get; set; }
}
public sealed class SceneMetricsSaveViewModel
{
public int SceneID { get; set; }
public List<SceneMetricInputViewModel> Metrics { get; set; } = [];
}
public sealed class SceneCharactersSaveViewModel
{
public int SceneID { get; set; }
public int? POVCharacterID { get; set; }
public List<SceneCharacterParticipationInputViewModel> Characters { get; set; } = [];
public SceneCharacterCreateViewModel NewCharacter { get; set; } = new();
}
public sealed class SceneLocationsSaveViewModel
{
public int SceneID { get; set; }
public int? PrimaryLocationID { get; set; }
}
public sealed class SceneAssetsSaveViewModel
{
public int SceneID { get; set; }
public List<SceneAssetEventInputViewModel> AssetEvents { get; set; } = [];
public AssetEventCreateViewModel NewAssetEvent { get; set; } = new();
}
public sealed class SceneAssetEventInputViewModel
{
public int AssetEventID { get; set; }
public int StoryAssetID { get; set; }
public bool Remove { get; set; }
}
public sealed class SceneNotesSaveViewModel
{
public int SceneID { get; set; }
public List<SceneNoteInputViewModel> Notes { get; set; } = [];
public SceneNoteEditViewModel NewNote { get; set; } = new();
}
public sealed class SceneNoteInputViewModel
{
public int SceneNoteID { get; set; }
public int SceneID { get; set; }
public int SceneNoteTypeID { get; set; }
public string? NoteTitle { get; set; }
public string NoteText { get; set; } = string.Empty;
public int? SortOrder { get; set; }
public bool IsPinned { get; set; }
public bool IsResolved { get; set; }
public bool Remove { get; set; }
}
public sealed class SceneChecklistSaveViewModel
{
public int SceneID { get; set; }
public List<SceneChecklistItemInputViewModel> ChecklistItems { get; set; } = [];
public SceneChecklistItemEditViewModel NewChecklistItem { get; set; } = new();
}
public sealed class SceneChecklistItemInputViewModel
{
public int SceneChecklistItemID { get; set; }
public int SceneID { get; set; }
public string ItemText { get; set; } = string.Empty;
public bool IsCompleted { get; set; }
public int? SortOrder { get; set; }
public bool Remove { get; set; }
}
public sealed class SceneCharacterParticipationInputViewModel
{
public int SceneCharacterID { get; set; }
public int SceneID { get; set; }
public int CharacterID { get; set; }
public bool Remove { get; set; }
public int? RoleInSceneTypeID { get; set; }
public int? PresenceTypeID { get; set; }
public int? LocationID { get; set; }
public int? EntryLocationID { get; set; }
public int? ExitLocationID { get; set; }
public string? AppearanceNotes { get; set; }
public string? OutfitDescription { get; set; }
public string? PhysicalCondition { get; set; }
public string? EmotionalState { get; set; }
}
public sealed class StoryStateViewModel
{
public List<CharacterStoryStateViewModel> Characters { get; set; } = [];
public List<AssetStoryStateViewModel> Assets { get; set; } = [];
public List<LocationStoryStateViewModel> Locations { get; set; } = [];
}
public sealed class CharacterStoryStateViewModel
{
public int CharacterID { get; set; }
public string CharacterName { get; set; } = string.Empty;
public int? LocationID { get; set; }
public string CurrentLocation { get; set; } = "Unknown";
public string State { get; set; } = "Unknown";
public int? LastConfirmedSceneID { get; set; }
public string LastConfirmed { get; set; } = "Never";
}
public sealed class AssetStoryStateViewModel
{
public int StoryAssetID { get; set; }
public string AssetName { get; set; } = string.Empty;
public int? LocationID { get; set; }
public string CurrentHolderOrLocation { get; set; } = "Unknown";
public string State { get; set; } = "Unknown";
public int? LastConfirmedSceneID { get; set; }
public string LastConfirmed { get; set; } = "Never";
}
public sealed class LocationStoryStateViewModel
{
public int LocationID { get; set; }
public string LocationName { get; set; } = string.Empty;
public string LocationPath { get; set; } = string.Empty;
public List<string> CharactersPresent { get; set; } = [];
public List<string> AssetsPresent { get; set; } = [];
}
public sealed class ContinuityFilter
{
public int ProjectID { get; set; }
public List<string> EntityTypes { get; set; } = ["Characters", "Assets", "Locations"];
public List<int> CharacterIDs { get; set; } = [];
public List<int> AssetIDs { get; set; } = [];
public List<int> LocationIDs { get; set; } = [];
public string SceneRangeMode { get; set; } = "EntireProject";
public int? BookID { get; set; }
public int? ChapterID { get; set; }
public int? StartSceneID { get; set; }
public int? EndSceneID { get; set; }
public string DisplayMode { get; set; } = "StoryState";
public int? SelectedSceneID { get; set; }
public bool ShowAcknowledgedWarnings { get; set; }
public bool IncludeCharacters => EntityTypes.Contains("Characters", StringComparer.OrdinalIgnoreCase);
public bool IncludeAssets => EntityTypes.Contains("Assets", StringComparer.OrdinalIgnoreCase);
public bool IncludeLocations => EntityTypes.Contains("Locations", StringComparer.OrdinalIgnoreCase);
}
public sealed class ContinuityExplorerViewModel
{
public Project Project { get; set; } = new();
public ContinuityFilter Filter { get; set; } = new();
public StoryStateViewModel StoryState { get; set; } = new();
public IReadOnlyList<CharacterJourneyViewModel> CharacterJourney { get; set; } = [];
public IReadOnlyList<AssetJourneyViewModel> AssetJourney { get; set; } = [];
public IReadOnlyList<LocationActivityViewModel> LocationActivity { get; set; } = [];
public IReadOnlyList<ContinuityWarningViewModel> ContinuityWarnings { get; set; } = [];
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ChapterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> CharacterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> LocationOptions { get; set; } = [];
public bool ShowBookContext { get; set; }
public bool ShowChapterContext { get; set; }
}
public sealed class ContinuityWarningViewModel
{
public string WarningKey { get; set; } = string.Empty;
public string WarningType { get; set; } = string.Empty;
public string WarningTypeDisplayName { get; set; } = string.Empty;
public string Severity { get; set; } = "Information";
public string Message { get; set; } = string.Empty;
public int? CharacterID { get; set; }
public string CharacterName { get; set; } = string.Empty;
public int? AssetID { get; set; }
public int? BookID { get; set; }
public int? ChapterID { get; set; }
public int? SceneID { get; set; }
public string SceneDisplayName { get; set; } = string.Empty;
public string ContextSceneDisplayName { get; set; } = string.Empty;
public string BookDisplayName { get; set; } = string.Empty;
public string ChapterDisplayName { get; set; } = string.Empty;
public bool IsAcknowledged { get; set; }
public string? AcknowledgementNotes { get; set; }
public int? KnowledgeId { get; set; }
public string KnowledgeTitle { get; set; } = string.Empty;
public string KnowledgeDescription { get; set; } = string.Empty;
public string PreviousKnowledgeState { get; set; } = string.Empty;
public string CurrentKnowledgeState { get; set; } = string.Empty;
public int? PreviousBookId { get; set; }
public int? PreviousChapterId { get; set; }
public int? PreviousSceneId { get; set; }
public string PreviousSceneDisplayName { get; set; } = string.Empty;
public string PreviousContextSceneDisplayName { get; set; } = string.Empty;
public int? CurrentBookId { get; set; }
public int? CurrentChapterId { get; set; }
public int? CurrentSceneId { get; set; }
public string CurrentSceneDisplayName { get; set; } = string.Empty;
public string CurrentContextSceneDisplayName { get; set; } = string.Empty;
public int? EstablishedSceneId { get; set; }
public string EstablishedSceneDisplayName { get; set; } = string.Empty;
public string EstablishedContextSceneDisplayName { get; set; } = string.Empty;
public int? ReferencedSceneId { get; set; }
public string ReferencedSceneDisplayName { get; set; } = string.Empty;
public string ReferencedContextSceneDisplayName { get; set; } = string.Empty;
public string InvestigationDisplayMode { get; set; } = string.Empty;
public int? InvestigationSceneId { get; set; }
public bool CanInvestigate { get; set; }
}
public sealed class CharacterJourneyViewModel
{
public int CharacterID { get; set; }
public string CharacterName { get; set; } = string.Empty;
public int BookID { get; set; }
public string BookDisplayName { get; set; } = string.Empty;
public int ChapterID { get; set; }
public string ChapterDisplayName { get; set; } = string.Empty;
public int SceneID { get; set; }
public string SceneTitle { get; set; } = string.Empty;
public string SceneLabel { get; set; } = string.Empty;
public string SceneDisplayName { get; set; } = string.Empty;
public string Location { get; set; } = string.Empty;
}
public sealed class AssetJourneyViewModel
{
public int StoryAssetID { get; set; }
public string AssetName { get; set; } = string.Empty;
public int BookID { get; set; }
public string BookDisplayName { get; set; } = string.Empty;
public int ChapterID { get; set; }
public string ChapterDisplayName { get; set; } = string.Empty;
public int SceneID { get; set; }
public string SceneTitle { get; set; } = string.Empty;
public string SceneLabel { get; set; } = string.Empty;
public string SceneDisplayName { get; set; } = string.Empty;
public string HolderOrLocation { get; set; } = string.Empty;
}
public sealed class LocationActivityViewModel
{
public int LocationID { get; set; }
public string LocationName { get; set; } = string.Empty;
public int BookID { get; set; }
public string BookDisplayName { get; set; } = string.Empty;
public int ChapterID { get; set; }
public string ChapterDisplayName { get; set; } = string.Empty;
public int SceneID { get; set; }
public string SceneTitle { get; set; } = string.Empty;
public string SceneLabel { get; set; } = string.Empty;
public string SceneDisplayName { get; set; } = string.Empty;
public string CharactersPresent { get; set; } = string.Empty;
public string AssetsPresent { get; set; } = string.Empty;
public List<LocationActivityEntityViewModel> Characters { get; set; } = [];
public List<LocationActivityEntityViewModel> Assets { get; set; } = [];
}
public sealed class LocationActivityEntityViewModel
{
public int EntityID { get; set; }
public string EntityName { get; set; } = string.Empty;
public string EntityType { get; set; } = string.Empty;
public string StateType { get; set; } = string.Empty;
public int? LastConfirmedSceneID { get; set; }
public string LastConfirmedSceneDisplayName { get; set; } = string.Empty;
public string? Note { get; set; }
}
public sealed class SceneWorkflowEditViewModel
{
public int SceneID { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
public string DraftStatus { get; set; } = "Planned";
public int? EstimatedWordCount { get; set; }
public int? ActualWordCount { get; set; }
public DateTime? DraftedDate { get; set; }
public DateTime? LastWorkedOn { get; set; }
public bool ReadyForDraft { get; set; }
public bool ReadyForRevision { get; set; }
public bool ReadyForPolish { get; set; }
public bool IsBlocked { get; set; }
public string? BlockedReason { get; set; }
public int? Priority { get; set; }
}
public sealed class SceneNoteEditViewModel
{
public int SceneNoteID { get; set; }
public int SceneID { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
public int SceneNoteTypeID { get; set; }
public string? NoteTitle { get; set; }
public string NoteText { get; set; } = string.Empty;
public int? SortOrder { get; set; }
public bool IsPinned { get; set; }
public bool IsResolved { get; set; }
}
public sealed class SceneChecklistItemEditViewModel
{
public int SceneChecklistItemID { get; set; }
public int SceneID { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
public string ItemText { get; set; } = string.Empty;
public bool IsCompleted { get; set; }
public int? SortOrder { get; set; }
}
public sealed class SceneAttachmentEditViewModel
{
public int SceneAttachmentID { get; set; }
public int SceneID { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
public int SceneAttachmentTypeID { get; set; }
public string Title { get; set; } = string.Empty;
public string? FilePath { get; set; }
public string? ExternalUrl { get; set; }
public string? Notes { get; set; }
public IFormFile? UploadedFile { get; set; }
}
public sealed class ChapterGoalEditViewModel
{
public int ChapterGoalID { get; set; }
public int ChapterID { get; set; }
public string? GoalSummary { get; set; }
public string? EmotionalGoal { get; set; }
public string? ReaderTakeaway { get; set; }
public string? MustInclude { get; set; }
public string? RisksOrConcerns { get; set; }
}
public sealed class ChapterWorkflowViewModel
{
public Project Project { get; set; } = new();
public Book Book { get; set; } = new();
public Chapter Chapter { get; set; } = new();
public ChapterGoal Goal { get; set; } = new();
public IReadOnlyList<ChapterWorkflowScene> Scenes { get; set; } = [];
}
public sealed class WriterDashboardViewModel
{
public int? ProjectID { get; set; }
public IReadOnlyList<SelectListItem> ProjectOptions { get; set; } = [];
public WritingScheduleDashboardViewModel WritingSchedule { get; set; } = new();
public IReadOnlyList<WriterDashboardScene> WriteNext { get; set; } = [];
public IReadOnlyList<WriterDashboardScene> ContinueWriting { get; set; } = [];
public IReadOnlyList<WriterDashboardScene> RevisionQueue { get; set; } = [];
public IReadOnlyList<WriterDashboardScene> PolishingQueue { get; set; } = [];
public IReadOnlyList<StoryBibleAttentionItem> StoryHealthReminders { get; set; } = [];
}
public sealed class WritingScheduleDashboardViewModel
{
public int ActivePlanCount { get; set; }
public int RebalancePlanCount { get; set; }
public IReadOnlyList<WritingScheduleDashboardItem> TodayTasks { get; set; } = [];
public IReadOnlyList<WritingScheduleDashboardItem> UpcomingTasks { get; set; } = [];
public int TotalPlannedTasks { get; set; }
public int CompletedTasks { get; set; }
public int SkippedTasks { get; set; }
public int RemainingTasks { get; set; }
public DateTime? ProjectedFinishDate { get; set; }
public bool HasActivePlans => ActivePlanCount > 0;
public bool HasActiveSchedule => TotalPlannedTasks > 0;
}
public sealed class WritingPlanViewModel
{
public int WritingPlanID { get; set; }
public int UserID { get; set; }
public int ProjectID { get; set; }
public int? BookID { get; set; }
public string PlanName { get; set; } = string.Empty;
public string GoalType { get; set; } = string.Empty;
public DateTime StartDate { get; set; }
public DateTime DeadlineDate { get; set; }
public string AvailableDaysJson { get; set; } = string.Empty;
public int SessionLengthMinutes { get; set; }
public bool IncludeBlockedScenes { get; set; }
public string RebalanceMode { get; set; } = "Ask";
public bool IsActive { get; set; } = true;
public DateTime CreatedDateUtc { get; set; }
public DateTime ModifiedDateUtc { get; set; }
}
public sealed class WritingPlansManagementViewModel
{
public IReadOnlyList<WritingPlanManagementItem> Plans { get; set; } = [];
}
public sealed class WritingDayAvailabilityViewModel
{
public string Day { get; set; } = string.Empty;
public bool IsAvailable { get; set; }
public int Minutes { get; set; } = 60;
}
public sealed class WritingPlanSettingsEditViewModel
{
public int WritingPlanID { get; set; }
[Required, StringLength(200)]
public string PlanName { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
public string BookName { get; set; } = "All Books";
public string GoalType { get; set; } = string.Empty;
[DataType(DataType.Date)]
public DateTime StartDate { get; set; }
[DataType(DataType.Date)]
public DateTime DeadlineDate { get; set; }
[Range(1, int.MaxValue, ErrorMessage = "Session length minutes must be greater than zero.")]
public int SessionLengthMinutes { get; set; }
public List<string> SelectedWritingDays { get; set; } = [];
public List<WritingDayAvailabilityViewModel> WritingDayAvailability { get; set; } = [];
public bool IncludeBlockedScenes { get; set; }
public string RebalanceMode { get; set; } = "Ask";
public bool IsActive { get; set; }
public IReadOnlyList<SelectListItem> RebalanceModeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SessionLengthOptions { get; set; } = [];
public IReadOnlyList<string> WritingDayOptions { get; set; } =
[
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
];
}
public sealed class WritingScheduleItemViewModel
{
public int WritingScheduleItemID { get; set; }
public int WritingPlanID { get; set; }
public int SceneID { get; set; }
public DateTime ScheduledDate { get; set; }
public string TaskType { get; set; } = string.Empty;
public int? EstimatedMinutes { get; set; }
public int? TargetWords { get; set; }
public string ScheduleStatus { get; set; } = string.Empty;
public DateTime? CompletedDateUtc { get; set; }
public string? Notes { get; set; }
public DateTime CreatedDateUtc { get; set; }
public DateTime ModifiedDateUtc { get; set; }
}
public sealed class WritingSchedulePreviewViewModel
{
public int? SelectedWritingPlanID { get; set; }
public IReadOnlyList<WritingPlanSummary> Plans { get; set; } = [];
public IReadOnlyList<WritingPlanSummary> PlansRequiringRebalance { get; set; } = [];
public WritingPlanSummary? SelectedPlan { get; set; }
public IReadOnlyList<WritingSchedulePreviewItem> Items { get; set; } = [];
public WritingScheduleRebalancePreviewViewModel? RebalancePreview { get; set; }
public bool SelectedPlanRequiresRebalance => SelectedWritingPlanID.HasValue
&& PlansRequiringRebalance.Any(x => x.WritingPlanID == SelectedWritingPlanID.Value);
public int TotalTasks => Items.Count;
public int DraftTasks => Items.Count(x => x.TaskType == "Draft");
public int RevisionTasks => Items.Count(x => x.TaskType == "Revise");
public int PolishTasks => Items.Count(x => x.TaskType == "Polish");
public int TotalEstimatedMinutes => Items.Sum(x => x.EstimatedMinutes ?? 0);
public DateTime? ProjectedFinishDate => Items.Count == 0 ? null : Items.Max(x => x.ScheduledDate);
}
public sealed class WritingScheduleRebalancePreviewViewModel
{
public int WritingPlanID { get; set; }
public DateTime? OriginalFinishDate { get; set; }
public DateTime? ProposedFinishDate { get; set; }
public IReadOnlyList<WritingScheduleRebalanceChangeViewModel> Changes { get; set; } = [];
public int TasksAffected => Changes.Count;
}
public sealed class WritingScheduleRebalanceChangeViewModel
{
public int WritingScheduleItemID { get; set; }
public string TaskType { get; set; } = string.Empty;
public string SceneName { get; set; } = string.Empty;
public DateTime CurrentDate { get; set; }
public DateTime ProposedDate { get; set; }
}
public sealed class WritingScheduleSetupViewModel
{
[Required, StringLength(200)]
public string PlanName { get; set; } = "Writing Schedule";
[Required]
public int? ProjectID { get; set; }
public int? BookID { get; set; }
[Required]
public string GoalType { get; set; } = "FirstDraft";
[DataType(DataType.Date)]
public DateTime StartDate { get; set; } = DateTime.Today;
[DataType(DataType.Date)]
public DateTime DeadlineDate { get; set; } = DateTime.Today.AddMonths(1);
public List<string> SelectedWritingDays { get; set; } = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"];
[Range(1, int.MaxValue, ErrorMessage = "Session length minutes must be greater than zero.")]
public int SessionLengthMinutes { get; set; } = 60;
public List<WritingDayAvailabilityViewModel> WritingDayAvailability { get; set; } = [];
public bool IncludeBlockedScenes { get; set; }
[Required]
public string RebalanceMode { get; set; } = "Ask";
public IReadOnlyList<SelectListItem> ProjectOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> GoalTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> RebalanceModeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SessionLengthOptions { get; set; } = [];
public IReadOnlyList<string> WritingDayOptions { get; set; } =
[
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
];
}
public sealed class WritingScheduleSetupResult
{
public int WritingPlanID { get; init; }
public int GeneratedItemCount { get; init; }
public string? ValidationMessage { get; init; }
}
public sealed class CharacterArcViewModel
{
public Project Project { get; set; } = new();
public Character Character { get; set; } = new();
public IReadOnlyList<CharacterArcPoint> ArcPoints { get; set; } = [];
public IReadOnlyList<RelationshipEvent> RelationshipEvents { get; set; } = [];
public IReadOnlyList<CharacterKnowledgeItem> KnowledgeEvents { get; set; } = [];
public IReadOnlyList<DynamicsIssue> Issues { get; set; } = [];
}
public sealed class RelationshipEvolutionViewModel
{
public Project Project { get; set; } = new();
public CharacterRelationship Relationship { get; set; } = new();
public IReadOnlyList<RelationshipProgressionPoint> Events { get; set; } = [];
public IReadOnlyList<DynamicsIssue> Issues { get; set; } = [];
}
public sealed class KnowledgeTimelineViewModel
{
public Project Project { get; set; } = new();
public Character Character { get; set; } = new();
public IReadOnlyList<CharacterKnowledgeItem> KnowledgeEvents { get; set; } = [];
public IReadOnlyList<DynamicsIssue> Issues { get; set; } = [];
}
public sealed class StoryDynamicsViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<CharacterPairingSummary> Pairings { get; set; } = [];
public IReadOnlyList<DynamicsIssue> Issues { get; set; } = [];
}
public sealed class ScenarioListViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<Scenario> Scenarios { get; set; } = [];
}
public sealed class ScenarioCreateViewModel
{
public int ProjectID { get; set; }
public int? BookID { get; set; }
public string ScenarioName { get; set; } = string.Empty;
public string? Description { get; set; }
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
}
public sealed class ScenarioTimelineViewModel
{
public Project Project { get; set; } = new();
public Scenario Scenario { get; set; } = new();
public IReadOnlyList<Book> Books { get; set; } = [];
public IReadOnlyList<Chapter> Chapters { get; set; } = [];
public IReadOnlyList<ScenarioScene> Scenes { get; set; } = [];
public IReadOnlyList<ScenarioWarning> Warnings { get; set; } = [];
public IReadOnlyList<SelectListItem> ChapterOptions { get; set; } = [];
}
public sealed class ScenarioCompareViewModel
{
public Project Project { get; set; } = new();
public Scenario Scenario { get; set; } = new();
public IReadOnlyList<ScenarioComparisonRow> MovedScenes { get; set; } = [];
public IReadOnlyList<ScenarioWarning> ScenarioWarnings { get; set; } = [];
}
public sealed class ArchivedItemsViewModel
{
public int? ProjectID { get; set; }
public string? EntityType { get; set; }
public IReadOnlyList<SelectListItem> ProjectOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> EntityTypeOptions { get; set; } = [];
public IReadOnlyList<ArchivedItem> Items { get; set; } = [];
}
public sealed class Phase1AcceptanceViewModel
{
public int? ProjectID { get; set; }
public string? ProjectName { get; set; }
public IReadOnlyList<SelectListItem> ProjectOptions { get; set; } = [];
public IReadOnlyList<Phase1AcceptanceChecklistItem> Items { get; set; } = [];
public int PassCount => Items.Count(x => x.Status == "Pass");
public int ReviewCount => Items.Count(x => x.Status == "Review");
public int BlockedCount => Items.Count(x => x.Status == "Blocked");
}
public sealed class TimelineViewModel
{
public Project Project { get; set; } = new();
public ProjectTimelineSettings Settings { get; set; } = new();
public int? SelectedBookID { get; set; }
public int? SelectedSceneID { get; set; }
public SceneEditViewModel? SelectedScene { get; set; }
public TimelineFilterViewModel Filter { get; set; } = new();
public IReadOnlyList<BookTimelineViewModel> Books { get; set; } = [];
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ChapterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ChapterFromOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ChapterToOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneFromOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneToOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> PlotLineOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> PlotThreadOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetOptions { get; set; } = [];
public IReadOnlyList<StoryAsset> QuickAddAssets { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetEventTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetStateOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetDependencyTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> CharacterOptions { get; set; } = [];
public IReadOnlyList<Character> QuickAddCharacters { get; set; } = [];
public IReadOnlyList<SelectListItem> CharacterRoleOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> PresenceTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> PovCharacterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> LocationOptions { get; set; } = [];
public IReadOnlyList<LocationItem> QuickAddLocations { get; set; } = [];
public IReadOnlyList<SelectListItem> LocationRelationshipTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> WarningSeverityOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> WarningTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> RevisionStatusOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ScenePurposeOptions { get; set; } = [];
public IReadOnlyList<TimelineViewPreset> ViewPresets { get; set; } = [];
public IReadOnlyList<Scene> OrderedScenes { get; set; } = [];
public IReadOnlyList<MetricGraphViewModel> MetricGraphs { get; set; } = [];
public IReadOnlyList<PlotLineLaneViewModel> PlotLanes { get; set; } = [];
public IReadOnlyList<AssetLaneViewModel> AssetLanes { get; set; } = [];
public IReadOnlyList<CharacterLaneViewModel> CharacterLanes { get; set; } = [];
public IReadOnlyDictionary<int, TimelineSceneOverviewViewModel> SceneOverviews { get; set; } = new Dictionary<int, TimelineSceneOverviewViewModel>();
public IReadOnlyDictionary<int, IReadOnlyList<ContinuityWarning>> WarningsByScene { get; set; } = new Dictionary<int, IReadOnlyList<ContinuityWarning>>();
public IReadOnlySet<int> MatchingSceneIDs { get; set; } = new HashSet<int>();
public IReadOnlySet<int> FocusSceneIDs { get; set; } = new HashSet<int>();
public IReadOnlyDictionary<int, string> ScenePovLabels { get; set; } = new Dictionary<int, string>();
public string? FocusLabel { get; set; }
public ContinuityValidationSummary? LastValidationSummary { get; set; }
}
public sealed class TimelineSettingsViewModel
{
public int ProjectID { get; set; }
public string ProjectName { get; set; } = string.Empty;
public bool ShowSceneCards { get; set; } = true;
public bool ShowMetricShape { get; set; } = true;
public bool ShowPlotLines { get; set; } = true;
public bool ShowStoryAssets { get; set; }
public bool ShowCharacterAppearances { get; set; }
public bool ShowWarnings { get; set; } = true;
public List<int> SelectedMetricTypeIDs { get; set; } = [];
public IReadOnlyList<TimelineMetricSettingOptionViewModel> MetricOptions { get; set; } = [];
}
public sealed class TimelineMetricSettingOptionViewModel
{
public int MetricTypeID { get; set; }
public string MetricName { get; set; } = string.Empty;
public string? Description { get; set; }
[Display(Name = "Level")]
[Range(-10, 50)]
public int SortOrder { get; set; }
public bool IsSelected { get; set; }
}
public sealed class TimelineSceneOverviewViewModel
{
public IReadOnlyList<TimelineSceneCharacterOverviewViewModel> Characters { get; set; } = [];
public IReadOnlyList<TimelineSceneAssetOverviewViewModel> Assets { get; set; } = [];
public IReadOnlyList<string> Locations { get; set; } = [];
}
public sealed class TimelineSceneCharacterOverviewViewModel
{
public int CharacterID { get; set; }
public string CharacterName { get; set; } = string.Empty;
public bool IsPov { get; set; }
}
public sealed class TimelineSceneAssetOverviewViewModel
{
public int StoryAssetID { get; set; }
public string AssetName { get; set; } = string.Empty;
public int Importance { get; set; }
public string? EventTypeName { get; set; }
}
public sealed class ProjectSceneMetricsViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<SceneMetricType> Metrics { get; set; } = [];
public SceneMetricTypeEditViewModel NewMetric { get; set; } = new();
public bool HasEnabledMetrics => Metrics.Any(x => x.IsEnabledForProject && x.IsActive);
}
public sealed class ProjectRestorePointListViewModel
{
public Project Project { get; init; } = new();
public IReadOnlyList<ProjectRestorePoint> RestorePoints { get; init; } = [];
}
public sealed class SceneMetricTypeEditViewModel
{
public int MetricTypeID { get; set; }
public int ProjectID { get; set; }
[Required, StringLength(100)]
[Display(Name = "Metric name")]
public string MetricName { get; set; } = string.Empty;
public string? Description { get; set; }
[Display(Name = "Minimum value")]
public int MinValue { get; set; } = 1;
[Display(Name = "Maximum value")]
public int MaxValue { get; set; } = 10;
[Display(Name = "Default value")]
public int DefaultValue { get; set; } = 5;
[Display(Name = "Sort order")]
public int SortOrder { get; set; } = 100;
[Display(Name = "Active")]
public bool IsActive { get; set; } = true;
}
public sealed class StoryBibleViewModel
{
public Project Project { get; set; } = new();
public string? Query { get; set; }
public IReadOnlyList<StoryBibleCharacterSummary> Characters { get; set; } = [];
public IReadOnlyList<StoryBibleThreadSummary> PlotThreads { get; set; } = [];
public IReadOnlyList<StoryBibleAssetSummary> Assets { get; set; } = [];
public IReadOnlyList<StoryBibleRelationshipSummary> Relationships { get; set; } = [];
public IReadOnlyList<StoryBibleLocationSummary> Locations { get; set; } = [];
public IReadOnlyList<StoryBibleTimelineSummary> Timeline { get; set; } = [];
public IReadOnlyList<StoryBibleAttentionItem> OpenQuestions { get; set; } = [];
public IReadOnlyList<StoryBibleRevisionItem> RevisionItems { get; set; } = [];
public IReadOnlyList<StoryBibleSearchResult> SearchResults { get; set; } = [];
}
public sealed class TimelineFilterViewModel
{
public int ProjectID { get; set; }
public int? BookID { get; set; }
public int? SelectedSceneID { get; set; }
public int? ChapterFromID { get; set; }
public int? ChapterToID { get; set; }
public int? SceneFromID { get; set; }
public int? SceneToID { get; set; }
public int? PlotLineID { get; set; }
public int? PlotThreadID { get; set; }
public int? StoryAssetID { get; set; }
public int? CharacterID { get; set; }
public int? LocationID { get; set; }
public int? WarningSeverityID { get; set; }
public int? WarningTypeID { get; set; }
public int? RevisionStatusID { get; set; }
public int? ScenePurposeTypeID { get; set; }
public int? POVCharacterID { get; set; }
public string? FocusType { get; set; }
public int? FocusID { get; set; }
public bool ShowSceneCards { get; set; } = true;
public bool ShowPlotLines { get; set; } = true;
public bool ShowAssets { get; set; } = true;
public bool ShowCharacters { get; set; } = true;
public bool ShowLocations { get; set; } = true;
public bool ShowWarnings { get; set; } = true;
public bool ShowMetrics { get; set; } = true;
public bool ShowWarningsOnly { get; set; }
public bool IncludeDismissedWarnings { get; set; }
public bool IncludeIntentionalWarnings { get; set; }
}
public sealed class TimelinePresetSaveViewModel
{
public int ProjectID { get; set; }
public int? BookID { get; set; }
public string PresetName { get; set; } = string.Empty;
public TimelineFilterViewModel Filter { get; set; } = new();
public string VisibilityJson { get; set; } = "{}";
}
public sealed class TimelineSceneDropMoveViewModel
{
public int ProjectID { get; set; }
public int? BookID { get; set; }
public int SceneID { get; set; }
public int AnchorSceneID { get; set; }
public int? TargetChapterID { get; set; }
public string Position { get; set; } = "After";
public int? ReturnSelectedSceneID { get; set; }
}
public sealed class TimelineSceneCharacterDropViewModel
{
public int SceneID { get; set; }
public int? CharacterID { get; set; }
public int? RoleInSceneTypeID { get; set; }
public int? PresenceTypeID { get; set; }
public int? LocationID { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class TimelineAssetEventDropViewModel
{
public int SceneID { get; set; }
public int? StoryAssetID { get; set; }
public int AssetEventTypeID { get; set; }
public int? FromStateID { get; set; }
public int? ToStateID { get; set; }
public string EventTitle { get; set; } = string.Empty;
public string? EventDescription { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
public int? LocationID { get; set; }
public string? CustodyNote { get; set; }
}
public sealed class TimelineAssetDependencyDropViewModel
{
public int ProjectID { get; set; }
public int SourceAssetID { get; set; }
public int TargetAssetID { get; set; }
public int AssetDependencyTypeID { get; set; }
public int? SourceRequiredStateID { get; set; }
public int? TargetBlockedStateID { get; set; }
public string? Description { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class TimelineLocationRelationshipDropViewModel
{
public int ProjectID { get; set; }
public int FromLocationID { get; set; }
public int ToLocationID { get; set; }
public int LocationRelationshipTypeID { get; set; }
public bool IsBidirectional { get; set; }
public int? Strength { get; set; }
public bool CanHearNormalSpeech { get; set; }
public bool CanHearLoudNoise { get; set; }
public bool CanSeeMovement { get; set; }
public bool CanSeeClearly { get; set; }
public bool CanTravelDirectly { get; set; }
public string? Notes { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class BookTimelineViewModel
{
public Book Book { get; set; } = new();
public IReadOnlyList<ChapterTimelineViewModel> Chapters { get; set; } = [];
}
public sealed class ChapterTimelineViewModel
{
public Chapter Chapter { get; set; } = new();
public IReadOnlyList<Scene> Scenes { get; set; } = [];
}
public sealed class SceneMetricInputViewModel
{
public int MetricTypeID { get; set; }
public string MetricName { get; set; } = string.Empty;
public string? Description { get; set; }
public int MinValue { get; set; }
public int MaxValue { get; set; }
public int Value { get; set; }
public string? Notes { get; set; }
}
public sealed class MetricGraphViewModel
{
public int MetricTypeID { get; set; }
public string MetricName { get; set; } = string.Empty;
public int MinValue { get; set; }
public int MaxValue { get; set; }
public IReadOnlyList<MetricGraphPointViewModel> Points { get; set; } = [];
}
public sealed class SceneMetricValueUpdateViewModel
{
public int SceneID { get; set; }
public int MetricTypeID { get; set; }
public int MetricID { get; set; }
public int Value { get; set; }
}
public sealed class MetricGraphPointViewModel
{
public int SceneID { get; set; }
public decimal SceneNumber { get; set; }
public string SceneTitle { get; set; } = string.Empty;
public int Value { get; set; }
public int Percent { get; set; }
}
public sealed class PlotLineEditViewModel : IValidatableObject
{
public int PlotLineID { get; set; }
public int ProjectID { get; set; }
[Required, StringLength(200)]
[Display(Name = "Plot line name")]
public string PlotLineName { get; set; } = string.Empty;
[Display(Name = "Type")]
public int PlotLineTypeID { get; set; }
[Range(1, int.MaxValue, ErrorMessage = "Choose a plot importance.")]
[Display(Name = "Importance")]
public int PlotImportanceID { get; set; } = 2;
public int? BookID { get; set; }
public string? Description { get; set; }
[Display(Name = "Parent plot line")]
public int? ParentPlotLineID { get; set; }
[Display(Name = "Emerges from plot line")]
public int? EmergesFromPlotLineID { get; set; }
[Display(Name = "Sort order")]
public int SortOrder { get; set; }
[Display(Name = "Colour")]
public string Colour { get; set; } = "#2f6f63";
[Display(Name = "Visible on timeline")]
public bool IsVisibleOnTimeline { get; set; } = true;
public Project? Project { get; set; }
public IReadOnlyList<SelectListItem> PlotImportance { get; set; } = [];
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ParentPlotLineOptions { get; set; } = [];
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (PlotLineID > 0 && EmergesFromPlotLineID == PlotLineID)
{
yield return new ValidationResult(
"A plot line cannot emerge from itself.",
[nameof(EmergesFromPlotLineID)]);
}
}
}
public sealed class PlotLineListViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<PlotLineItem> PlotLines { get; set; } = [];
}
public sealed class PlotThreadEditViewModel
{
public int PlotThreadID { get; set; }
public int ProjectID { get; set; }
[Display(Name = "Plot line")]
public int PlotLineID { get; set; }
[Required, StringLength(200)]
[Display(Name = "Thread title")]
public string ThreadTitle { get; set; } = string.Empty;
[Display(Name = "Type")]
public int ThreadTypeID { get; set; }
[Display(Name = "Status")]
public int ThreadStatusID { get; set; }
[Range(1, 10)]
public int Importance { get; set; } = 5;
public string? Summary { get; set; }
[Display(Name = "Introduced scene")]
public int? IntroducedSceneID { get; set; }
[Display(Name = "Planned resolution scene")]
public int? PlannedResolutionSceneID { get; set; }
[Display(Name = "Actual resolution scene")]
public int? ActualResolutionSceneID { get; set; }
public Project? Project { get; set; }
public IReadOnlyList<SelectListItem> PlotLineOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ThreadTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ThreadStatusOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneOptions { get; set; } = [];
}
public sealed class PlotThreadListViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<PlotThread> PlotThreads { get; set; } = [];
}
public sealed class ThreadEventCreateViewModel
{
public int SceneID { get; set; }
public int? PlotLineID { get; set; }
public int? PlotThreadID { get; set; }
public string? NewThreadTitle { get; set; }
public int? NewThreadTypeID { get; set; }
public int EventTypeID { get; set; }
[Range(1, int.MaxValue, ErrorMessage = "Choose an event type.")]
public int PlotEventTypeID { get; set; } = 2;
public int? TargetPlotLineID { get; set; }
public List<int> SelectedTargetPlotLineIDs { get; set; } = [];
public string EventTitle { get; set; } = string.Empty;
public string? EventDescription { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class ThreadEventEditViewModel
{
public int ThreadEventID { get; set; }
public int SceneID { get; set; }
public int PlotThreadID { get; set; }
public int EventTypeID { get; set; }
[Range(1, int.MaxValue, ErrorMessage = "Choose an event type.")]
public int PlotEventTypeID { get; set; } = 2;
public int? TargetPlotLineID { get; set; }
public List<int> SelectedTargetPlotLineIDs { get; set; } = [];
public string EventTitle { get; set; } = string.Empty;
public string? EventDescription { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class PlotLineLaneViewModel
{
public PlotLineItem PlotLine { get; set; } = new();
public IReadOnlyList<PlotLaneSceneViewModel> SceneSlots { get; set; } = [];
}
public sealed class PlotLaneSceneViewModel
{
public Scene Scene { get; set; } = new();
public IReadOnlyList<ThreadEvent> Events { get; set; } = [];
}
public sealed class StoryAssetListViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<StoryAsset> Assets { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetDependencyTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetStateOptions { get; set; } = [];
}
public sealed class StoryAssetEditViewModel
{
public int StoryAssetID { get; set; }
public int ProjectID { get; set; }
[Required, StringLength(200)]
[Display(Name = "Asset name")]
public string AssetName { get; set; } = string.Empty;
public List<string> Aliases { get; set; } = [];
[Display(Name = "Kind")]
public int AssetKindID { get; set; }
public string? Description { get; set; }
[Range(1, 10)]
public int Importance { get; set; } = 5;
[Display(Name = "Current state")]
public int? CurrentStateID { get; set; }
[Display(Name = "Current location")]
public int? CurrentLocationID { get; set; }
[Display(Name = "Resolved")]
public bool IsResolved { get; set; }
[Display(Name = "Show in Quick Add Bar")]
public bool ShowInQuickAddBar { get; set; }
public string? ImagePath { get; set; }
public string? ThumbnailPath { get; set; }
[Display(Name = "Upload image")]
public IFormFile? ImageUpload { get; set; }
[Display(Name = "Remove image")]
public bool RemoveImage { get; set; }
public Project? Project { get; set; }
public IReadOnlyList<SelectListItem> AssetKindOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetStateOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> LocationOptions { get; set; } = [];
}
public sealed class StoryAssetDetailViewModel
{
public Project Project { get; set; } = new();
public StoryAsset Asset { get; set; } = new();
public IReadOnlyList<StoryAsset> ProjectAssets { get; set; } = [];
public IReadOnlyList<AssetEvent> Events { get; set; } = [];
public IReadOnlyList<AssetDependency> Dependencies { get; set; } = [];
public IReadOnlyList<AssetCustodyEvent> CustodyEvents { get; set; } = [];
public AssetDependencyEditViewModel NewDependency { get; set; } = new();
public IReadOnlyList<SelectListItem> AssetOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetDependencyTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> AssetStateOptions { get; set; } = [];
}
public sealed class AssetEventCreateViewModel
{
public int SceneID { get; set; }
public int? StoryAssetID { get; set; }
public string? NewAssetName { get; set; }
public int? NewAssetKindID { get; set; }
public int AssetEventTypeID { get; set; }
public int? FromStateID { get; set; }
public int? ToStateID { get; set; }
public string EventTitle { get; set; } = string.Empty;
public string? EventDescription { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class AssetCustodyCreateViewModel
{
public int SceneID { get; set; }
public int StoryAssetID { get; set; }
public int AssetCustodyEventTypeID { get; set; }
public int CustodyRoleID { get; set; }
public List<int> CustodianCharacterIds { get; set; } = [];
public string CustodianNames { get; set; } = string.Empty;
public string? Description { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class SceneAssetLocationCreateViewModel
{
public int SceneAssetLocationID { get; set; }
public int SceneID { get; set; }
public int StoryAssetID { get; set; }
public int LocationID { get; set; }
public string? Description { get; set; }
public bool UpdateCurrentLocation { get; set; } = true;
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class AssetDependencyEditViewModel
{
public int AssetDependencyID { get; set; }
public int ProjectID { get; set; }
public int SourceAssetID { get; set; }
public int TargetAssetID { get; set; }
public int AssetDependencyTypeID { get; set; }
public int? SourceRequiredStateID { get; set; }
public int? TargetBlockedStateID { get; set; }
public string? Description { get; set; }
}
public sealed class AssetLaneViewModel
{
public StoryAsset Asset { get; set; } = new();
public IReadOnlyList<AssetLaneSceneViewModel> SceneSlots { get; set; } = [];
}
public sealed class AssetLaneSceneViewModel
{
public Scene Scene { get; set; } = new();
public IReadOnlyList<AssetEvent> Events { get; set; } = [];
}
public sealed class CharacterListViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<Character> Characters { get; set; } = [];
}
public sealed class CharacterEditViewModel
{
public const int CustomSexValue = -1;
public int CharacterID { get; set; }
public int ProjectID { get; set; }
[Required, StringLength(200)]
[Display(Name = "Display name")]
public string CharacterName { get; set; } = string.Empty;
public List<string> Aliases { get; set; } = [];
[Display(Name = "Sex")]
public int? SexValueID { get; set; }
public string? Sex { get; set; }
[Display(Name = "Add custom sex")]
[StringLength(100)]
public string? CustomSex { get; set; }
[Display(Name = "Birth date")]
public DateTime? BirthDate { get; set; }
[Display(Name = "Age at series start")]
public int? AgeAtSeriesStart { get; set; }
public string? Height { get; set; }
[Display(Name = "Eye colour")]
public string? EyeColour { get; set; }
[Display(Name = "Story importance")]
public int? CharacterImportance { get; set; }
[Display(Name = "Show in Quick Add Bar")]
public bool ShowInQuickAddBar { get; set; }
[Display(Name = "Default description")]
public string? DefaultDescription { get; set; }
public string? ImagePath { get; set; }
public string? ThumbnailPath { get; set; }
public int? AvatarSourceCharacterImageID { get; set; }
public string? AvatarImagePath { get; set; }
public string? AvatarThumbnailPath { get; set; }
[Display(Name = "Upload image")]
public IFormFile? ImageUpload { get; set; }
[Display(Name = "Remove image")]
public bool RemoveImage { get; set; }
public IReadOnlyList<SelectListItem> ImportanceOptions { get; set; } =
[
new("Use timeline fallback", string.Empty),
new("Major", "10"),
new("Secondary / Supporting", "6"),
new("Minor", "2")
];
public IReadOnlyList<SelectListItem> SexOptions { get; set; } = [];
public Project? Project { get; set; }
}
public sealed class CharacterDetailViewModel
{
public Project Project { get; set; } = new();
public Character Character { get; set; } = new();
public IReadOnlyList<CharacterAlias> Aliases { get; set; } = [];
public IReadOnlyList<Character> ProjectCharacters { get; set; } = [];
public IReadOnlyList<CharacterImage> Images { get; set; } = [];
public string DisplayAge { get; set; } = "Unknown";
public IReadOnlyList<SceneCharacter> Appearances { get; set; } = [];
public IReadOnlyList<CharacterAttributeEvent> AttributeEvents { get; set; } = [];
public IReadOnlyList<CharacterKnowledgeItem> KnowledgeItems { get; set; } = [];
public IReadOnlyList<CharacterRelationship> InitialRelationships { get; set; } = [];
public IReadOnlyList<CurrentRelationshipViewModel> CurrentRelationships { get; set; } = [];
public IReadOnlyList<RelationshipEvent> RelationshipEvents { get; set; } = [];
public InitialRelationshipEditViewModel NewInitialRelationship { get; set; } = new();
public IReadOnlyList<SelectListItem> CharacterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> RelationshipTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> RelationshipStateOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
}
public sealed class CharacterImageUploadViewModel
{
public int CharacterID { get; set; }
[Display(Name = "Image")]
public IFormFile? ImageUpload { get; set; }
[StringLength(500)]
public string? Caption { get; set; }
}
public sealed class CharacterAvatarCropViewModel
{
public int CharacterID { get; set; }
public int CharacterImageID { get; set; }
public string CharacterName { get; set; } = string.Empty;
public string ImagePath { get; set; } = string.Empty;
public string? Caption { get; set; }
public int CropX { get; set; }
public int CropY { get; set; }
public int CropSize { get; set; }
}
public sealed class CurrentRelationshipViewModel
{
public CharacterRelationship Relationship { get; set; } = new();
public RelationshipEvent? LatestEvent { get; set; }
public IReadOnlyList<RelationshipEvent> Events { get; set; } = [];
public string CurrentStateName => LatestEvent?.RelationshipStateName
?? Relationship.InitialRelationshipStateName
?? Relationship.RelationshipTypeName;
public int? CurrentIntensity => LatestEvent?.Intensity ?? Relationship.InitialIntensity;
public string? CurrentNotes => LatestEvent?.Description ?? Relationship.Notes;
}
public sealed class RelationshipMapViewModel
{
public Project Project { get; set; } = new();
public int? BookID { get; set; }
public int? ChapterID { get; set; }
public int? SceneID { get; set; }
public int? FocusCharacterID { get; set; }
public bool ShowFullNetwork { get; set; }
public string StoryPointLabel { get; set; } = "Project Start";
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ChapterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SceneOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> CharacterOptions { get; set; } = [];
public IReadOnlyList<RelationshipMapCategoryViewModel> Categories { get; set; } = [];
public IReadOnlyList<RelationshipMapNodeViewModel> Nodes { get; set; } = [];
public IReadOnlyList<RelationshipMapLinkViewModel> Links { get; set; } = [];
public IReadOnlyList<RelationshipMapRelationshipViewModel> Relationships { get; set; } = [];
}
public sealed class RelationshipMapCategoryViewModel
{
public int RelationshipCategoryID { get; set; }
public string CategoryName { get; set; } = string.Empty;
public string CssClass { get; set; } = "relationship-category-other";
}
public sealed class RelationshipMapNodeViewModel
{
public int CharacterID { get; set; }
public string CharacterName { get; set; } = string.Empty;
public int? CharacterImportance { get; set; }
public string? AvatarImagePath { get; set; }
public string? AvatarThumbnailPath { get; set; }
public string? ImagePath { get; set; }
public string? ThumbnailPath { get; set; }
public bool IsFocus { get; set; }
}
public sealed class RelationshipMapLinkViewModel
{
public int CharacterRelationshipID { get; set; }
public int SourceCharacterID { get; set; }
public int TargetCharacterID { get; set; }
public string RelationshipLabel { get; set; } = string.Empty;
public string CategoryName { get; set; } = "Other";
public string CssClass { get; set; } = "relationship-category-other";
public int? Intensity { get; set; }
}
public sealed class RelationshipMapRelationshipViewModel
{
public int CharacterRelationshipID { get; set; }
public int CharacterAID { get; set; }
public string CharacterAName { get; set; } = string.Empty;
public int CharacterBID { get; set; }
public string CharacterBName { get; set; } = string.Empty;
public string RelationshipTypeName { get; set; } = string.Empty;
public string RelationshipCategoryName { get; set; } = "Other";
public string CssClass { get; set; } = "relationship-category-other";
public string InitialStateName { get; set; } = string.Empty;
public string CurrentStateName { get; set; } = string.Empty;
public int? InitialIntensity { get; set; }
public int? CurrentIntensity { get; set; }
public bool IsReciprocal { get; set; }
public string? Notes { get; set; }
public IReadOnlyList<RelationshipMapHistoryItemViewModel> History { get; set; } = [];
}
public sealed class RelationshipMapHistoryItemViewModel
{
public string Label { get; set; } = string.Empty;
public string StateName { get; set; } = string.Empty;
public int? Intensity { get; set; }
public string? Notes { get; set; }
public int? SceneID { get; set; }
}
public sealed class InitialRelationshipEditViewModel
{
public int CharacterRelationshipID { get; set; }
public int ProjectID { get; set; }
public int CharacterID { get; set; }
public int? ReturnCharacterID { get; set; }
public int RelatedCharacterID { get; set; }
public int RelationshipTypeID { get; set; }
public int? InitialBookID { get; set; }
public int? InitialRelationshipStateID { get; set; }
public int? InitialIntensity { get; set; }
public bool IsReciprocal { get; set; }
public bool ReaderInitiallyKnows { get; set; }
public string? Notes { get; set; }
}
public sealed class SceneCharacterCreateViewModel
{
public int SceneID { get; set; }
public int? CharacterID { get; set; }
public string? NewCharacterName { get; set; }
public int? RoleInSceneTypeID { get; set; }
public int? PresenceTypeID { get; set; }
public int? LocationID { get; set; }
public int? EntryLocationID { get; set; }
public int? ExitLocationID { get; set; }
public string? AppearanceNotes { get; set; }
public string? OutfitDescription { get; set; }
public string? PhysicalCondition { get; set; }
public string? EmotionalState { get; set; }
public string? KnowledgeNotes { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class SceneCharacterEditViewModel
{
public int SceneCharacterID { get; set; }
public int SceneID { get; set; }
public int CharacterID { get; set; }
public int? RoleInSceneTypeID { get; set; }
public int? PresenceTypeID { get; set; }
public int? LocationID { get; set; }
public int? EntryLocationID { get; set; }
public int? ExitLocationID { get; set; }
public string? AppearanceNotes { get; set; }
public string? OutfitDescription { get; set; }
public string? PhysicalCondition { get; set; }
public string? EmotionalState { get; set; }
public string? KnowledgeNotes { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class CharacterAttributeEventCreateViewModel
{
public int CharacterAttributeEventID { get; set; }
public int SceneID { get; set; }
public int CharacterID { get; set; }
public int CharacterAttributeTypeID { get; set; }
public string AttributeValue { get; set; } = string.Empty;
public string? Description { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class CharacterKnowledgeCreateViewModel
{
public int CharacterKnowledgeID { get; set; }
public int SceneID { get; set; }
public int CharacterID { get; set; }
public int? StoryAssetID { get; set; }
public int? PlotThreadID { get; set; }
public int KnowledgeStateID { get; set; }
public int? SourceEventID { get; set; }
public string? Description { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class RelationshipEventCreateViewModel
{
public int RelationshipEventID { get; set; }
public int SceneID { get; set; }
public int? CharacterRelationshipID { get; set; }
public int? CharacterAID { get; set; }
public int? CharacterBID { get; set; }
public int? RelationshipTypeID { get; set; }
public int RelationshipStateID { get; set; }
public int? Intensity { get; set; }
public bool IsKnownToOtherCharacter { get; set; }
public string? Description { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class CharacterLaneViewModel
{
public Character Character { get; set; } = new();
public IReadOnlyList<CharacterLaneSceneViewModel> SceneSlots { get; set; } = [];
}
public sealed class CharacterLaneSceneViewModel
{
public Scene Scene { get; set; } = new();
public IReadOnlyList<SceneCharacter> Appearances { get; set; } = [];
}
public sealed class LocationListViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<LocationItem> Locations { get; set; } = [];
public IReadOnlyList<SelectListItem> RelationshipTypeOptions { get; set; } = [];
}
public sealed class LocationEditViewModel
{
public int LocationID { get; set; }
public int ProjectID { get; set; }
public int? ParentLocationID { get; set; }
[Required, StringLength(200)]
[Display(Name = "Location name")]
public string LocationName { get; set; } = string.Empty;
public List<string> Aliases { get; set; } = [];
[Display(Name = "Location type")]
public int? LocationTypeID { get; set; }
public string? Description { get; set; }
[Display(Name = "Show in Quick Add Bar")]
public bool ShowInQuickAddBar { get; set; }
[Display(Name = "Exclude from Word Companion detection")]
public bool ExcludeFromCompanionDetection { get; set; }
[Display(Name = "Detection priority")]
[Range(0, 1000, ErrorMessage = "Detection priority must be between 0 and 1000.")]
public int DetectionPriority { get; set; } = 50;
public Project? Project { get; set; }
public IReadOnlyList<SelectListItem> ParentLocationOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> LocationTypeOptions { get; set; } = [];
}
public sealed class LocationDetailViewModel
{
public Project Project { get; set; } = new();
public LocationItem Location { get; set; } = new();
public IReadOnlyList<LocationItem> ChildLocations { get; set; } = [];
public IReadOnlyList<LocationRelationship> Relationships { get; set; } = [];
public IReadOnlyList<Scene> Scenes { get; set; } = [];
public IReadOnlyList<SceneCharacter> Characters { get; set; } = [];
public IReadOnlyList<SceneAssetLocation> Assets { get; set; } = [];
public LocationRelationshipEditViewModel NewRelationship { get; set; } = new();
public IReadOnlyList<SelectListItem> LocationOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> RelationshipTypeOptions { get; set; } = [];
}
public sealed class LocationRelationshipEditViewModel
{
public int LocationRelationshipID { get; set; }
public int ProjectID { get; set; }
public int FromLocationID { get; set; }
public int ToLocationID { get; set; }
public int LocationRelationshipTypeID { get; set; }
public bool IsBidirectional { get; set; }
public int? Strength { get; set; }
public bool CanHearNormalSpeech { get; set; }
public bool CanHearLoudNoise { get; set; }
public bool CanSeeMovement { get; set; }
public bool CanSeeClearly { get; set; }
public bool CanTravelDirectly { get; set; }
public string? Notes { get; set; }
}
public sealed class FloorPlanListViewModel
{
public Project Project { get; set; } = new();
public IReadOnlyList<FloorPlan> FloorPlans { get; set; } = [];
public FloorPlanEditViewModel NewFloorPlan { get; set; } = new();
public IReadOnlyList<SelectListItem> LocationOptions { get; set; } = [];
}
public sealed class FloorPlanEditViewModel
{
public int FloorPlanID { get; set; }
public int ProjectID { get; set; }
public int? LocationID { get; set; }
public string? LocationName { get; set; }
public string? LocationPath { get; set; }
[Required, StringLength(200)]
public string Name { get; set; } = string.Empty;
public string? Description { get; set; }
}
public sealed class FloorPlanEditorViewModel
{
public Project Project { get; set; } = new();
public FloorPlanEditViewModel FloorPlan { get; set; } = new();
public List<FloorPlanFloorEditViewModel> Floors { get; set; } = [];
public List<FloorPlanBlockEditViewModel> Blocks { get; set; } = [];
public List<FloorPlanTransitionEditViewModel> Transitions { get; set; } = [];
public FloorPlanFloorEditViewModel NewFloor { get; set; } = new();
public FloorPlanBlockEditViewModel NewBlock { get; set; } = new();
public FloorPlanTransitionEditViewModel NewTransition { get; set; } = new();
public IReadOnlyList<SelectListItem> LocationOptions { get; set; } = [];
public IReadOnlyList<LocationItem> Locations { get; set; } = [];
public IReadOnlyList<SelectListItem> BlockTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> TransitionTypeOptions { get; set; } = [];
public IReadOnlyList<FloorPlanOccupancySceneViewModel> OccupancyScenes { get; set; } = [];
public IReadOnlyList<FloorPlanOccupancyTokenViewModel> OccupancyTokens { get; set; } = [];
public IReadOnlyList<FloorPlanOccupancyWarningViewModel> OccupancyWarnings { get; set; } = [];
}
public sealed class FloorPlanOccupancySceneViewModel
{
public int SceneID { get; set; }
public int? InitialFloorPlanFloorID { get; set; }
public string Label { get; set; } = string.Empty;
}
public sealed class FloorPlanOccupancyTokenViewModel
{
public int SceneID { get; set; }
public int FloorPlanFloorID { get; set; }
public int LocationID { get; set; }
public string LocationName { get; set; } = string.Empty;
public string EntityType { get; set; } = string.Empty;
public int EntityID { get; set; }
public string DisplayName { get; set; } = string.Empty;
public string? ImagePath { get; set; }
public string? ThumbnailPath { get; set; }
}
public sealed class FloorPlanOccupancyWarningViewModel
{
public int SceneID { get; set; }
public int? FloorPlanFloorID { get; set; }
public string Severity { get; set; } = "warning";
public string Message { get; set; } = string.Empty;
}
public sealed class FloorPlanFloorEditViewModel
{
public int FloorPlanFloorID { get; set; }
public int FloorPlanID { get; set; }
public int? LocationID { get; set; }
public string? LocationName { get; set; }
public string? LocationPath { get; set; }
[Required, StringLength(100)]
public string Name { get; set; } = string.Empty;
public string? Description { get; set; }
public int SortOrder { get; set; }
[Range(8, 80)]
public int GridWidth { get; set; } = 24;
[Range(8, 80)]
public int GridHeight { get; set; } = 16;
public string? BackgroundImagePath { get; set; }
public string? BackgroundImageOriginalFileName { get; set; }
[Range(0.05, 1.0)]
public decimal BackgroundOpacity { get; set; } = 0.35m;
[Range(0.1, 5.0)]
public decimal BackgroundScale { get; set; } = 1m;
[Range(-10000, 10000)]
public decimal BackgroundOffsetX { get; set; }
[Range(-10000, 10000)]
public decimal BackgroundOffsetY { get; set; }
public bool BackgroundLocked { get; set; } = true;
}
public sealed class FloorPlanFloorBackgroundSettingsViewModel
{
public int FloorPlanID { get; set; }
public int FloorPlanFloorID { get; set; }
[Range(0.05, 1.0)]
public decimal BackgroundOpacity { get; set; } = 0.35m;
[Range(0.1, 5.0)]
public decimal BackgroundScale { get; set; } = 1m;
[Range(-10000, 10000)]
public decimal BackgroundOffsetX { get; set; }
[Range(-10000, 10000)]
public decimal BackgroundOffsetY { get; set; }
public bool BackgroundLocked { get; set; } = true;
}
public sealed class FloorPlanBlockEditViewModel
{
public int FloorPlanBlockID { get; set; }
public int FloorPlanFloorID { get; set; }
public int? LocationID { get; set; }
public string AddBlockLocationMode { get; set; } = "Existing";
public string? NewLocationName { get; set; }
public string LocationName { get; set; } = string.Empty;
public string LocationPath { get; set; } = string.Empty;
[Range(0, 79)]
public int X { get; set; }
[Range(0, 79)]
public int Y { get; set; }
[Range(1, 80)]
public int WidthCells { get; set; } = 2;
[Range(1, 80)]
public int HeightCells { get; set; } = 1;
[Required, StringLength(40)]
public string BlockType { get; set; } = FloorPlanBlockTypes.Room;
// Future L-shape support should add ShapeType, FootWidthCells, FootHeightCells, and CornerPosition
// only when the database, save/load flow, rendering, and collision checks can move together.
[StringLength(200)]
public string? LabelOverride { get; set; }
public string? Notes { get; set; }
public string DisplayLabel => string.IsNullOrWhiteSpace(LabelOverride) ? LocationName : LabelOverride;
}
public sealed class FloorPlanTransitionEditViewModel
{
public int FloorPlanTransitionID { get; set; }
public int FloorPlanFloorID { get; set; }
[Required]
public int? FromLocationID { get; set; }
public string FromLocationName { get; set; } = string.Empty;
public string FromLocationPath { get; set; } = string.Empty;
[Required]
public int? ToLocationID { get; set; }
public string ToLocationName { get; set; } = string.Empty;
public string ToLocationPath { get; set; } = string.Empty;
[Required, StringLength(50)]
public string TransitionType { get; set; } = FloorPlanTransitionTypes.Door;
public string? Notes { get; set; }
public bool IsLocked { get; set; }
[StringLength(255)]
public string? DisplayLabel { get; set; }
[StringLength(20)]
public string PositionWithinLocation { get; set; } = FloorPlanTransitionPositions.Centre;
public string Label => string.IsNullOrWhiteSpace(DisplayLabel) ? TransitionType : DisplayLabel;
}
public sealed class AvatarViewModel
{
public string DisplayName { get; set; } = string.Empty;
public string? ImagePath { get; set; }
public string? ThumbnailPath { get; set; }
public string Size { get; set; } = "md";
public string? CssClass { get; set; }
public bool Lazy { get; set; } = true;
}
public sealed class WarningDashboardViewModel
{
public Project Project { get; set; } = new();
public int? BookID { get; set; }
public int? ChapterID { get; set; }
public int? SceneID { get; set; }
public int? WarningTypeID { get; set; }
public int? WarningSeverityID { get; set; }
public string? EntityType { get; set; }
public string? Category { get; set; }
public bool IncludeDismissed { get; set; }
public bool IncludeIntentional { get; set; }
public bool ShowAcknowledgedWarnings { get; set; }
public IReadOnlyList<ContinuityWarning> Warnings { get; set; } = [];
public IReadOnlyList<ProjectWarningViewModel> ProjectWarnings { get; set; } = [];
public IReadOnlyList<WarningSeverityGroupViewModel> WarningGroups { get; set; } = [];
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> ChapterOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> WarningTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> SeverityOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> EntityTypeOptions { get; set; } = [];
public IReadOnlyList<SelectListItem> CategoryOptions { get; set; } = [];
public IReadOnlyDictionary<string, int> CountsBySeverity { get; set; } = new Dictionary<string, int>();
public IReadOnlyDictionary<string, int> CountsByType { get; set; } = new Dictionary<string, int>();
public ContinuityValidationSummary? LastValidationSummary { get; set; }
public bool HasAnyWarnings { get; set; }
}
public sealed class SceneContinuityEditorViewModel
{
public SceneEditViewModel Scene { get; set; } = new();
public WarningDashboardViewModel Dashboard { get; set; } = new();
}
public sealed class WarningSeverityGroupViewModel
{
public string Severity { get; set; } = string.Empty;
public bool IsExpanded { get; set; }
public IReadOnlyList<ProjectWarningViewModel> Warnings { get; set; } = [];
}
public sealed class ProjectWarningViewModel
{
public string Source { get; set; } = "Persisted";
public int? ContinuityWarningID { get; set; }
public string WarningType { get; set; } = string.Empty;
public string WarningTypeDisplayName { get; set; } = string.Empty;
public string Category { get; set; } = "General";
public string Severity { get; set; } = "Information";
public string Message { get; set; } = string.Empty;
public string? Details { get; set; }
public int? BookID { get; set; }
public string BookDisplayName { get; set; } = string.Empty;
public int? ChapterID { get; set; }
public string ChapterDisplayName { get; set; } = string.Empty;
public int? SceneID { get; set; }
public string SceneDisplayName { get; set; } = string.Empty;
public string ContextSceneDisplayName { get; set; } = string.Empty;
public int? CharacterID { get; set; }
public string CharacterName { get; set; } = string.Empty;
public int? AssetID { get; set; }
public string EntityType { get; set; } = string.Empty;
public bool IsDismissed { get; set; }
public bool IsIntentional { get; set; }
public bool IsAcknowledged { get; set; }
public string? AcknowledgementNotes { get; set; }
public string WarningKey { get; set; } = string.Empty;
public int? KnowledgeId { get; set; }
public string KnowledgeTitle { get; set; } = string.Empty;
public string KnowledgeDescription { get; set; } = string.Empty;
public string PreviousKnowledgeState { get; set; } = string.Empty;
public string CurrentKnowledgeState { get; set; } = string.Empty;
public int? PreviousBookId { get; set; }
public int? PreviousChapterId { get; set; }
public int? PreviousSceneId { get; set; }
public string PreviousSceneDisplayName { get; set; } = string.Empty;
public string PreviousContextSceneDisplayName { get; set; } = string.Empty;
public int? CurrentBookId { get; set; }
public int? CurrentChapterId { get; set; }
public int? CurrentSceneId { get; set; }
public string CurrentSceneDisplayName { get; set; } = string.Empty;
public string CurrentContextSceneDisplayName { get; set; } = string.Empty;
public int? EstablishedSceneId { get; set; }
public string EstablishedSceneDisplayName { get; set; } = string.Empty;
public string EstablishedContextSceneDisplayName { get; set; } = string.Empty;
public int? ReferencedSceneId { get; set; }
public string ReferencedSceneDisplayName { get; set; } = string.Empty;
public string ReferencedContextSceneDisplayName { get; set; } = string.Empty;
public string InvestigationDisplayMode { get; set; } = string.Empty;
public int? InvestigationSceneId { get; set; }
public bool CanInvestigate { get; set; }
public DateTime LastDetectedDate { get; set; }
}
public sealed class WarningDashboardReturnFilter
{
public int ProjectID { get; set; }
public int? BookID { get; set; }
public int? ChapterID { get; set; }
public int? SceneID { get; set; }
public int? WarningTypeID { get; set; }
public int? WarningSeverityID { get; set; }
public string? EntityType { get; set; }
public string? Category { get; set; }
public bool IncludeDismissed { get; set; }
public bool IncludeIntentional { get; set; }
public bool ShowAcknowledgedWarnings { get; set; }
}
public sealed class SceneDependencyCreateViewModel
{
public int SceneDependencyID { get; set; }
public int ProjectID { get; set; }
public int CurrentSceneID { get; set; }
public int RelatedSceneID { get; set; }
public string Direction { get; set; } = "CurrentDependsOnRelated";
public int SceneDependencyTypeID { get; set; }
public bool IsHardDependency { get; set; }
public string? Description { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
}
public sealed class SceneMoveRequestViewModel
{
public int SceneID { get; set; }
public int TargetChapterID { get; set; }
public string Position { get; set; } = "End";
public bool RenumberScenes { get; set; }
public int? ReturnProjectID { get; set; }
public int? ReturnBookID { get; set; }
public string? ReturnUrl { get; set; }
}
public sealed class SceneMovePreviewViewModel
{
public SceneMovePreview Preview { get; set; } = new();
public SceneMoveRequestViewModel Request { get; set; } = new();
public IReadOnlyList<ContinuityWarning> CurrentWarnings { get; set; } = [];
}
public sealed class AnalyticsViewModel
{
public Project Project { get; set; } = new();
public int? BookID { get; set; }
public decimal? StartChapterNumber { get; set; }
public decimal? EndChapterNumber { get; set; }
public decimal? StartSceneNumber { get; set; }
public decimal? EndSceneNumber { get; set; }
public IReadOnlyList<SelectListItem> BookOptions { get; set; } = [];
public IReadOnlyList<AnalyticsMetricGraphViewModel> MetricGraphs { get; set; } = [];
public IReadOnlyList<AnalyticsRevisionSummary> RevisionSummary { get; set; } = [];
public IReadOnlyList<AnalyticsRevisionScene> RevisionAttentionScenes { get; set; } = [];
public IReadOnlyList<AnalyticsPurposeSummary> PurposeSummary { get; set; } = [];
public IReadOnlyList<AnalyticsSceneGap> SceneGaps { get; set; } = [];
public IReadOnlyList<AnalyticsThreadHealth> ThreadHealth { get; set; } = [];
public IReadOnlyList<AnalyticsAssetHealth> AssetHealth { get; set; } = [];
public IReadOnlyList<AnalyticsWarningSeverityCount> WarningSeverityCounts { get; set; } = [];
public IReadOnlyList<AnalyticsWarningTypeCount> WarningTypeCounts { get; set; } = [];
public IReadOnlyList<AnalyticsWarningHotspot> WarningHotspots { get; set; } = [];
public IReadOnlyList<AnalyticsPovSummary> PovSummary { get; set; } = [];
public IReadOnlyList<AnalyticsMultiPovChapter> MultiPovChapters { get; set; } = [];
public IReadOnlyList<AnalyticsCharacterAppearance> CharacterAppearances { get; set; } = [];
public IReadOnlyList<AnalyticsBusyScene> BusyScenes { get; set; } = [];
public IReadOnlyList<AnalyticsLocationUsage> LocationUsage { get; set; } = [];
public IReadOnlyList<AnalyticsReviewNote> PacingReviewNotes { get; set; } = [];
}
public sealed class AnalyticsMetricGraphViewModel
{
public string MetricName { get; set; } = string.Empty;
public IReadOnlyList<AnalyticsMetricPoint> Points { get; set; } = [];
}
public sealed class AnalyticsReviewNote
{
public string MetricName { get; set; } = string.Empty;
public string SceneRange { get; set; } = string.Empty;
public string ValuePattern { get; set; } = string.Empty;
public string ReviewNote { get; set; } = string.Empty;
public int? SceneID { get; set; }
}