diff --git a/src-tauri/crates/app/src/commands/browse.rs b/src-tauri/crates/app/src/commands/browse.rs index 3c46b14b..fb3059d2 100644 --- a/src-tauri/crates/app/src/commands/browse.rs +++ b/src-tauri/crates/app/src/commands/browse.rs @@ -970,6 +970,23 @@ pub struct AlbumTrack { /// for DSF/DFF tracks where bit_depth=1 would otherwise look /// like junk to the badge logic. pub codec: Option, + // The remaining fields exist so the Properties modal opened from + // this view shows the same Audio / File sections it shows + // everywhere else. AlbumDetailView has to synthesise a full + // `Track` for the context menu, and anything missing here became + // a hard-coded null there — which is exactly what left those + // sections blank on the album page only (issue #458). + pub year: Option, + pub bitrate: Option, + pub channels: Option, + pub musical_key: Option, + pub file_size: i64, + pub added_at: i64, + /// Half-star rating (POPM round-trip). Selected so the context + /// menu's rating submenu reflects reality here: it is enabled by + /// default, so a hard-coded `null` made an already-rated track + /// read as unrated on this view. + pub rating: Option, } #[derive(FromRow)] @@ -988,6 +1005,13 @@ struct AlbumTrackRaw { bit_depth: Option, sample_rate: Option, codec: Option, + year: Option, + bitrate: Option, + channels: Option, + musical_key: Option, + file_size: i64, + added_at: i64, + rating: Option, } /// Return full album detail: header (with Deezer-cached label), genres, @@ -1094,6 +1118,8 @@ pub async fn get_album_detail( t.duration_ms, t.track_number, t.disc_number, t.file_path, t.bit_depth, t.sample_rate, t.codec, + t.year, t.bitrate, t.channels, t.musical_key, + t.file_size, t.added_at, t.rating, aw.hash AS artwork_hash, aw.format AS artwork_format FROM ranked r JOIN track t ON t.id = r.id @@ -1138,6 +1164,13 @@ pub async fn get_album_detail( bit_depth: row.bit_depth, sample_rate: row.sample_rate, codec: row.codec, + year: row.year, + bitrate: row.bitrate, + channels: row.channels, + musical_key: row.musical_key, + file_size: row.file_size, + added_at: row.added_at, + rating: row.rating, } }) .collect(); diff --git a/src/components/views/AlbumDetailView.tsx b/src/components/views/AlbumDetailView.tsx index 6eb80142..cfacd8e9 100644 --- a/src/components/views/AlbumDetailView.tsx +++ b/src/components/views/AlbumDetailView.tsx @@ -169,7 +169,16 @@ export function AlbumDetailView({ if (!album) return ; // loading - // Build playable Track[] from AlbumTrack[] for the player + // Build playable Track[] from AlbumTrack[] for the player AND for the + // track context menu — which is what feeds the Properties modal. Every + // field the modal reads must come from the row rather than a + // placeholder: hard-coded nulls here are what left the Audio and File + // sections blank on this view alone (issue #458). + // + // That includes `rating`: the context menu's rating submenu is on by + // default here, so the previous placeholder made an already-rated + // track show up as unrated — the exact misreport `enableRating: + // false` exists to prevent on surfaces that genuinely lack it. const playableTracks = album.tracks.map((at) => ({ id: at.id, library_id: 0, @@ -182,20 +191,22 @@ export function AlbumDetailView({ duration_ms: at.duration_ms, track_number: at.track_number, disc_number: at.disc_number, - year: album.year, - bitrate: null, + // The track's own year, falling back to the album's — a + // compilation can carry a per-track year the album header doesn't. + year: at.year ?? album.year, + bitrate: at.bitrate, sample_rate: at.sample_rate, - channels: null, + channels: at.channels, bit_depth: at.bit_depth, - codec: null, - musical_key: null, + codec: at.codec, + musical_key: at.musical_key, file_path: at.file_path, - file_size: 0, - added_at: 0, + file_size: at.file_size, + added_at: at.added_at, artwork_path: at.artwork_path, artwork_path_1x: at.artwork_path_1x, artwork_path_2x: at.artwork_path_2x, - rating: null, + rating: at.rating, })); const handlePlayAll = async () => { diff --git a/src/lib/tauri/detail.ts b/src/lib/tauri/detail.ts index 5eb312e4..d68e5ef0 100644 --- a/src/lib/tauri/detail.ts +++ b/src/lib/tauri/detail.ts @@ -19,6 +19,19 @@ export interface AlbumTrack { bit_depth: number | null; sample_rate: number | null; codec: string | null; + /** Carried so AlbumDetailView can build a complete `Track` for the + * context menu — the Properties modal reads these, and anything + * missing here used to be hard-coded to null there (issue #458). */ + year: number | null; + bitrate: number | null; + channels: number | null; + musical_key: string | null; + file_size: number; + added_at: number; + /** Half-star rating. The context menu's rating submenu is on by + * default, so a placeholder here made a rated track read as + * unrated on the album page. */ + rating: number | null; } export interface AlbumDetail {