PlotDirector/PlotLine/Controllers/TimelineController.cs
Nick Beckley cb7405c0e8 Phase 1N
2026-06-01 11:20:24 +01:00

108 lines
4.1 KiB
C#

using Microsoft.AspNetCore.Mvc;
using PlotLine.Models;
using PlotLine.Services;
using PlotLine.ViewModels;
namespace PlotLine.Controllers;
public sealed class TimelineController(ITimelineService timeline) : Controller
{
public async Task<IActionResult> Index([FromQuery] TimelineFilterViewModel filter)
{
if (filter.ProjectID == 0)
{
return BadRequest("ProjectID is required.");
}
var model = await timeline.GetAsync(filter);
return model is null ? NotFound() : View(model);
}
[HttpPost]
public async Task<IActionResult> SavePreset(TimelinePresetSaveViewModel model)
{
await timeline.SavePresetAsync(model);
return RedirectToAction(nameof(Index), new { projectId = model.ProjectID, bookId = model.BookID });
}
public async Task<IActionResult> LoadPreset(int id)
{
var preset = await timeline.GetPresetAsync(id);
if (preset is null)
{
return NotFound();
}
var filter = System.Text.Json.JsonSerializer.Deserialize<TimelineFilterViewModel>(preset.FilterJson) ?? new TimelineFilterViewModel();
filter.ProjectID = preset.ProjectID;
filter.BookID = preset.BookID;
filter.FocusType = preset.FocusType;
filter.FocusID = preset.FocusID;
return RedirectToAction(nameof(Index), filter);
}
[HttpPost]
public async Task<IActionResult> DeletePreset(int id, int projectId, int? bookId)
{
await timeline.ArchivePresetAsync(id);
return RedirectToAction(nameof(Index), new { projectId, bookId });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DropMoveScene(TimelineSceneDropMoveViewModel model)
{
var summary = await timeline.MoveSceneByDropAsync(model);
if (summary is not null)
{
TempData["TimelineDragMessage"] = $"Scene moved. Validation found {summary.WarningCount} warning{(summary.WarningCount == 1 ? "" : "s")}.";
}
return RedirectToAction(nameof(Index), new { projectId = model.ProjectID, bookId = model.BookID, selectedSceneId = model.SceneID });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DropCharacter(TimelineSceneCharacterDropViewModel model)
{
await RunDropActionAsync(() => timeline.AddCharacterByDropAsync(model), "Character added to scene.");
return RedirectToAction(nameof(Index), new { projectId = model.ReturnProjectID, bookId = model.ReturnBookID, selectedSceneId = model.SceneID });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DropAssetEvent(TimelineAssetEventDropViewModel model)
{
await RunDropActionAsync(() => timeline.AddAssetEventByDropAsync(model), "Asset event added to scene.");
return RedirectToAction(nameof(Index), new { projectId = model.ReturnProjectID, bookId = model.ReturnBookID, selectedSceneId = model.SceneID });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DropAssetDependency(TimelineAssetDependencyDropViewModel model)
{
await RunDropActionAsync(() => timeline.AddAssetDependencyByDropAsync(model), "Asset dependency saved.");
return RedirectToAction(nameof(Index), new { projectId = model.ReturnProjectID, bookId = model.ReturnBookID });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DropLocationRelationship(TimelineLocationRelationshipDropViewModel model)
{
await RunDropActionAsync(() => timeline.AddLocationRelationshipByDropAsync(model), "Location relationship saved.");
return RedirectToAction(nameof(Index), new { projectId = model.ProjectID, bookId = model.ReturnBookID });
}
private async Task RunDropActionAsync(Func<Task> action, string successMessage)
{
try
{
await action();
TempData["TimelineDragMessage"] = successMessage;
}
catch (InvalidOperationException ex)
{
TempData["TimelineDragMessage"] = ex.Message;
}
}
}