81 lines
3.1 KiB
C#
81 lines
3.1 KiB
C#
using DeepDrftModels.DTOs;
|
|
using DeepDrftPublic.Client.Services;
|
|
|
|
namespace DeepDrftPublic.Client.ViewModels;
|
|
|
|
/// <summary>
|
|
/// State for the Cut album-detail page (/cuts/{entryKey}). Unlike <see cref="ReleaseDetailViewModel"/>
|
|
/// (which resolves a single playable track for Session/Mix), a Cut is multi-track: it loads the
|
|
/// release and the full ordered track list for that release. The list is fetched through the
|
|
/// existing releaseId-filtered track page sorted by TrackNumber — the explicit 1-based ordinal
|
|
/// (Phase 8) that the public read both sorts on and projects onto TrackDto. Scoped; every flag is
|
|
/// reset per <see cref="Load"/> so a reused instance never bleeds across navigations.
|
|
/// </summary>
|
|
public class CutDetailViewModel
|
|
{
|
|
private readonly IReleaseDataService _releaseData;
|
|
private readonly ITrackDataService _trackData;
|
|
|
|
// A Cut covers the whole album in one page. Matches the gallery's page-size convention; a single
|
|
// album never approaches this ceiling (the API caps PageSize at 100 regardless).
|
|
private const int AlbumPageSize = 100;
|
|
|
|
public ReleaseDto? Release { get; private set; }
|
|
public IReadOnlyList<TrackDto> Tracks { get; private set; } = [];
|
|
public bool IsLoading { get; private set; } = true;
|
|
public bool NotFound { get; private set; }
|
|
|
|
public CutDetailViewModel(IReleaseDataService releaseData, ITrackDataService trackData)
|
|
{
|
|
_releaseData = releaseData;
|
|
_trackData = trackData;
|
|
}
|
|
|
|
/// <summary>Seed state directly from a bridged prerender payload — no fetch.</summary>
|
|
public void Restore(ReleaseDto release, IReadOnlyList<TrackDto> tracks)
|
|
{
|
|
Release = release;
|
|
Tracks = tracks;
|
|
NotFound = false;
|
|
IsLoading = false;
|
|
}
|
|
|
|
public async Task Load(string entryKey)
|
|
{
|
|
IsLoading = true;
|
|
NotFound = false;
|
|
Release = null;
|
|
Tracks = [];
|
|
|
|
try
|
|
{
|
|
var releaseResult = await _releaseData.GetByEntryKey(entryKey);
|
|
if (releaseResult is not { Success: true, Value: { } release })
|
|
{
|
|
NotFound = true;
|
|
return;
|
|
}
|
|
|
|
Release = release;
|
|
|
|
// The album's tracks via the releaseId-filtered page — an exact join, not a title string
|
|
// (which collides across same-titled releases and breaks on rename). The public page
|
|
// addresses the release by EntryKey; the track→release join stays on the internal int FK
|
|
// (Phase 11 §3e), so use the resolved release.Id here. Sorted by TrackNumber so rows render
|
|
// in saved order. A Cut with no streamable tracks simply leaves the list empty (the page
|
|
// renders the header with no rows).
|
|
var trackResult = await _trackData.GetPage(
|
|
pageNumber: 1,
|
|
pageSize: AlbumPageSize,
|
|
sortColumn: "TrackNumber",
|
|
releaseId: release.Id);
|
|
if (trackResult is { Success: true, Value: { Items: { } items } })
|
|
Tracks = items.ToList();
|
|
}
|
|
finally
|
|
{
|
|
IsLoading = false;
|
|
}
|
|
}
|
|
}
|