feat: format-aware download status in album detail view

Download checkmarks now only show for the currently selected format.
In-memory store tracks formatId per album download, and the album
detail view checks track.downloaded_format_ids from backend against
the selected format dropdown. Switching quality hides checkmarks
from a different format's downloads.
This commit is contained in:
vicrodh committed 2026-02-24 15:09:16 -06:00
1 parent 4073b9fd35
commit 6067eb280b
4 files changed
+31 -8

No files matched your search

@@ -8,7 +8,7 @@
import Dropdown from '../Dropdown.svelte';
import ViewTransition from '../ViewTransition.svelte';
import { getAlbumDetail, getFormats } from '$lib/services/purchases';
import { purchaseDownloads, startAlbumDownload, startTrackDownload } from '$lib/stores/purchaseDownloadStore';
import { purchaseDownloads, startAlbumDownload, startTrackDownload, getAlbumDownloadFormatId } from '$lib/stores/purchaseDownloadStore';
import type { TrackDownloadStatus } from '$lib/stores/purchaseDownloadStore';
import { formatDuration, getQobuzImage } from '$lib/adapters/qobuzAdapters';
import { showToast } from '$lib/stores/toastStore';
@@ -45,7 +45,11 @@
const albumDlState = $derived($purchaseDownloads[albumId] ?? null);
const downloadStatuses = $derived(albumDlState?.trackStatuses ?? {});
const isDownloadingAll = $derived(albumDlState?.isDownloadingAll ?? false);
const allComplete = $derived(albumDlState?.allComplete ?? false);
// Only show "all complete" if the download was for the currently selected format
const allComplete = $derived(
(albumDlState?.allComplete ?? false) &&
(albumDlState?.formatId === undefined || albumDlState?.formatId === selectedFormatId)
);
const downloadDestination = $derived(albumDlState?.destination ?? null);
let addingToLibrary = $state(false);
@@ -92,7 +96,14 @@
}
function getTrackStatus(trackId: number): TrackDownloadStatus | null {
return downloadStatuses[trackId] || null;
const status = downloadStatuses[trackId] || null;
if (!status) return null;
// Only show 'complete' if the in-memory download was for the currently selected format
if (status === 'complete') {
const dlFormatId = getAlbumDownloadFormatId(albumId);
if (dlFormatId !== undefined && dlFormatId !== selectedFormatId) return null;
}
return status;
}
function groupByDisc(trackList: PurchasedTrack[]): Map<number, PurchasedTrack[]> {
@@ -358,7 +369,8 @@
{#each discTracks as track (track.id)}
{@const status = getTrackStatus(track.id)}
{@const isActive = activeTrackId === track.id}
{@const isDownloaded = track.downloaded || status === 'complete'}
{@const isDownloadedForFormat = selectedFormatId !== null && (track.downloaded_format_ids ?? []).includes(selectedFormatId)}
{@const isDownloaded = isDownloadedForFormat || status === 'complete'}
<div
class="track-row"
class:downloading={status === 'downloading'}
+4 -2
View File
@@ -139,12 +139,14 @@ export async function getDownloadedTrackIds(): Promise<Set<number>> {
export async function markTrackDownloaded(
trackId: number,
albumId: string | undefined,
filePath: string
filePath: string,
formatId: number = 0
): Promise<void> {
return invoke<void>('v2_purchases_mark_downloaded', {
trackId,
albumId: albumId ?? null,
filePath
filePath,
formatId
});
}
+10 -2
View File
@@ -8,6 +8,7 @@ interface AlbumDownloadState {
isDownloadingAll: boolean;
allComplete: boolean;
destination?: string;
formatId?: number;
}
// Persistent store: albumId -> download state (survives component unmount)
@@ -38,6 +39,11 @@ function updateAlbumState(
});
}
/** Get the format ID that was used for the most recent download of this album. */
export function getAlbumDownloadFormatId(albumId: string): number | undefined {
return get(purchaseDownloads)[albumId]?.formatId;
}
export function startAlbumDownload(
albumId: string,
trackIds: number[],
@@ -50,6 +56,7 @@ export function startAlbumDownload(
isDownloadingAll: true,
allComplete: false,
destination,
formatId,
}));
executeAlbumDownload(albumId, trackIds, formatId, destination, qualityDir);
}
@@ -73,7 +80,7 @@ async function executeAlbumDownload(
...state,
trackStatuses: { ...state.trackStatuses, [trackId]: 'complete' },
}));
await markTrackDownloaded(trackId, albumId, filePath).catch(() => {});
await markTrackDownloaded(trackId, albumId, filePath, formatId).catch(() => {});
} catch {
updateAlbumState(albumId, (state) => ({
...state,
@@ -106,6 +113,7 @@ export function startTrackDownload(
updateAlbumState(albumId, (state) => ({
...state,
trackStatuses: { ...state.trackStatuses, [trackId]: 'downloading' },
formatId,
}));
executeSingleTrackDownload(albumId, trackId, formatId, destination, qualityDir);
}
@@ -123,7 +131,7 @@ async function executeSingleTrackDownload(
...state,
trackStatuses: { ...state.trackStatuses, [trackId]: 'complete' },
}));
await markTrackDownloaded(trackId, albumId, filePath).catch(() => {});
await markTrackDownloaded(trackId, albumId, filePath, formatId).catch(() => {});
} catch {
updateAlbumState(albumId, (state) => ({
...state,
+1
View File
@@ -51,6 +51,7 @@ export interface PurchasedTrack {
maximum_sampling_rate?: number;
streamable: boolean;
downloaded?: boolean;
downloaded_format_ids?: number[];
purchased_at?: number;
}