using DeepDrftModels.DTOs; using DeepDrftPublic.Client.Services; namespace DeepDrftPublic.Client.ViewModels; /// /// State for a single-release detail page (Session, Mix). Loads the release and resolves its /// playable track. The release read surface exposes no track entry directly, so the playable track /// is resolved through the existing track gallery filtered by the release's id (an exact join) — for /// Session/Mix that yields the single track. Scoped; reset every flag per so a /// reused instance never bleeds across navigations. /// public class ReleaseDetailViewModel { private readonly IReleaseDataService _releaseData; private readonly ITrackDataService _trackData; public ReleaseDto? Release { get; private set; } public TrackDto? Track { get; private set; } public bool IsLoading { get; private set; } = true; public bool NotFound { get; private set; } public ReleaseDetailViewModel(IReleaseDataService releaseData, ITrackDataService trackData) { _releaseData = releaseData; _trackData = trackData; } /// Seed state directly from a bridged prerender payload — no fetch. public void Restore(ReleaseDto release, TrackDto? track) { Release = release; Track = track; NotFound = false; IsLoading = false; } public async Task Load(long releaseId) { IsLoading = true; NotFound = false; Release = null; Track = null; try { var releaseResult = await _releaseData.GetById(releaseId); if (releaseResult is not { Success: true, Value: { } release }) { NotFound = true; return; } Release = release; // Resolve the playable track via the releaseId-filtered track page — an exact join, not a // title string (which collides across same-titled releases and breaks on rename). Session/Mix // releases carry a single track; take the first. A release with no streamable track simply // leaves Track null (the detail page hides the play affordance). var trackResult = await _trackData.GetPage( pageNumber: 1, pageSize: 1, releaseId: release.Id); if (trackResult is { Success: true, Value: { Items: { } items } }) Track = items.FirstOrDefault(); } finally { IsLoading = false; } } }