diff --git a/crates/qbz-slint/src/local_library.rs b/crates/qbz-slint/src/local_library.rs index c232e69c3..5842a5e91 100644 --- a/crates/qbz-slint/src/local_library.rs +++ b/crates/qbz-slint/src/local_library.rs @@ -603,6 +603,13 @@ fn tracks_current() -> std::sync::MutexGuard<'static, Vec Vec { + tracks_current().clone() +} + fn fmt_duration(secs: u64) -> String { format!("{}:{:02}", secs / 60, secs % 60) } diff --git a/crates/qbz-slint/src/main.rs b/crates/qbz-slint/src/main.rs index fb2e8c7c4..f065f7891 100644 --- a/crates/qbz-slint/src/main.rs +++ b/crates/qbz-slint/src/main.rs @@ -4456,23 +4456,24 @@ fn main() -> Result<(), Box> { match action.as_str() { "play" => { if let Ok(row_id) = id.parse::() { - // Queue the current (searched) list so playback - // continues down it from the clicked row. - let query = weak - .upgrade() - .map(|w| { - w.global::() - .get_tracks_search() - .to_string() - }) - .unwrap_or_default(); - playback::play_local_tracks_from( - runtime.clone(), - weak.clone(), - handle.clone(), - query, - row_id, - ); + // Queue the already-loaded rows (instant — no DB + // re-query / cover-fill that delayed the queue) so + // playback continues down the list from the click. + let tracks = local_library::tracks_current_snapshot(); + if !tracks.is_empty() { + let start = tracks + .iter() + .position(|t| t.id == row_id) + .unwrap_or(0); + playback::play_local_tracks( + runtime.clone(), + weak.clone(), + handle.clone(), + tracks, + start, + false, + ); + } } } "toggle-select" => { diff --git a/crates/qbz-slint/src/playback.rs b/crates/qbz-slint/src/playback.rs index 956294aeb..36cba1611 100644 --- a/crates/qbz-slint/src/playback.rs +++ b/crates/qbz-slint/src/playback.rs @@ -332,6 +332,9 @@ pub fn play_local_folder_tracks_from( /// Play the Tracks-tab list starting at `start_track_id`: the matching set /// (current search) becomes the queue, so playback continues down the list. +/// (Superseded by the instant in-memory-cache path; kept for the full-list +/// option.) +#[allow(dead_code)] pub fn play_local_tracks_from( runtime: Runtime, weak: slint::Weak, diff --git a/crates/qbz-slint/ui/discover/AlbumCard.slint b/crates/qbz-slint/ui/discover/AlbumCard.slint index dbb66459a..64142bb4e 100644 --- a/crates/qbz-slint/ui/discover/AlbumCard.slint +++ b/crates/qbz-slint/ui/discover/AlbumCard.slint @@ -13,7 +13,7 @@ import { Theme } from "../foundation/semantic-colors.slint"; import { Typography } from "../foundation/typography.slint"; import { Radius } from "../foundation/radius.slint"; import { Spacing } from "../foundation/spacing.slint"; -import { AlbumCardItem } from "../state.slint"; +import { AlbumCardItem, NavState } from "../state.slint"; import { QbzIcon } from "../primitives/QbzIcon.slint"; import { QualityBadge } from "../primitives/QualityBadge.slint"; import { ContextMenu } from "../primitives/ContextMenu.slint"; @@ -56,6 +56,16 @@ component OverlayButton inherits Rectangle { clicked => { root.clicked(); } + // Forward the mouse back/forward buttons to history nav (a TouchArea + // swallows them, so they never reach the AppShell catcher). + pointer-event(e) => { + if (e.kind == PointerEventKind.down && e.button == PointerEventButton.back) { + NavState.request-back(); + } + if (e.kind == PointerEventKind.down && e.button == PointerEventButton.forward) { + NavState.request-forward(); + } + } } } diff --git a/crates/qbz-slint/ui/primitives/ExpandableSearch.slint b/crates/qbz-slint/ui/primitives/ExpandableSearch.slint index 86fa85a67..edccc6dd1 100644 --- a/crates/qbz-slint/ui/primitives/ExpandableSearch.slint +++ b/crates/qbz-slint/ui/primitives/ExpandableSearch.slint @@ -12,7 +12,9 @@ import { QbzIcon } from "QbzIcon.slint"; export component ExpandableSearch inherits Rectangle { in property placeholder: "Search…"; - in property max-open-width: 216px; + // Trimmed 20px so the open field doesn't ride over the controls to its + // left on small screens. + in property max-open-width: 196px; in-out property open: false; in-out property query; // Bootstrap-style small variant. Default is the standard size. diff --git a/crates/qbz-slint/ui/primitives/QbzSelect.slint b/crates/qbz-slint/ui/primitives/QbzSelect.slint index eb2f70e7f..1fae64bd0 100644 --- a/crates/qbz-slint/ui/primitives/QbzSelect.slint +++ b/crates/qbz-slint/ui/primitives/QbzSelect.slint @@ -53,8 +53,8 @@ export component QbzSelect inherits Rectangle { callback selected(int); // Toolbar (sm) selects — Group / Sort / filter — were unnecessarily wide; - // trim 20px from the effective width (button + list). - private property eff-width: root.menu-width - (root.sm ? 20px : 0px); + // trim 40px from the effective width (button + list). + private property eff-width: root.menu-width - (root.sm ? 40px : 0px); // Resolved width of the open list. private property list-width: root.popup-width > root.eff-width ? root.popup-width : root.eff-width; diff --git a/crates/qbz-slint/ui/primitives/TrackRow.slint b/crates/qbz-slint/ui/primitives/TrackRow.slint index dc6459f3d..f622eab9e 100644 --- a/crates/qbz-slint/ui/primitives/TrackRow.slint +++ b/crates/qbz-slint/ui/primitives/TrackRow.slint @@ -18,7 +18,7 @@ import { Theme } from "../foundation/semantic-colors.slint"; import { Typography } from "../foundation/typography.slint"; import { Radius } from "../foundation/radius.slint"; -import { TrackItem, DragActions, NowPlayingState } from "../state.slint"; +import { TrackItem, DragActions, NowPlayingState, NavState } from "../state.slint"; import { QbzIcon } from "QbzIcon.slint"; import { TrackPlayCell } from "TrackPlayCell.slint"; import { TrackContextMenu } from "TrackContextMenu.slint"; @@ -81,6 +81,15 @@ export component TrackRow inherits Rectangle { property down-y; property dragging: false; pointer-event(e) => { + // The mouse back/forward buttons drive history nav. A TouchArea + // swallows these (they never reach the AppShell catcher), so each + // interactive row forwards them itself. + if (e.kind == PointerEventKind.down && e.button == PointerEventButton.back) { + NavState.request-back(); + } + if (e.kind == PointerEventKind.down && e.button == PointerEventButton.forward) { + NavState.request-forward(); + } if (e.kind == PointerEventKind.down) { ta.down-x = root.absolute-position.x + ta.mouse-x; ta.down-y = root.absolute-position.y + ta.mouse-y;