Commit Graph
5734 Commits
Author SHA1 Message Date
vicrodh 1a7853d9c6 feat(discover): Most Played Albums carousel in Home + For You
Wires the rail (top-20 by play count) into both tabs, mirroring the favoriteAlbums pattern: HomeState/ForYouState.most-played-albums DiscoverSection; foryou::most_played_album_cards maps the ranked rows onto AlbumCard; home.rs builds it inline (local, no fetch) and For You rides the favorites branch; HomeMostPlayedAlbum/ForYouMostPlayedAlbum artwork targets + apply arms; render arms in HomeView/ForYouView (self-hide while empty); title in 8 locales. slintcheck green. View-all page (search + play count) is the next increment.

cc
2026-07-14 01:06:54 -06:00
vicrodh abb529e22b feat(discover): Most Played Albums — play-count store, hook, section id
Data foundation for the new Most Played Albums rail. New qbz-app store album_play_history (SQLite, mirrors play_history): one album_play_event row per track-start + an album_meta side table; top_albums(n)/all_albums() rank by COUNT(*) GROUP BY album_id, tie-broken by most-recent play. Hooked in playback::record_recent next to the recently/artist stores, same album identity. Registers the mostPlayedAlbums section id in discover_prefs (Home + For You, default off). The Qobuz API exposes no most-played endpoint (verified vs the inferred OpenAPI), so the ranking is local. 15 unit tests green (store 5 + prefs 10).

cc
2026-07-13 23:30:28 -06:00
vicrodh bf29892aa4 fix(dsd): DsdErrorReport holds SharedState, not Arc<SharedState>
The merged #599 typed DsdErrorReport.state as Arc<SharedState>, but the audio thread passes thread_state — a SharedState, which is itself a #[derive(Clone)] handle of Arc<Atomic..> fields (a clone already shares the state). The extra Arc broke the qbz-player build in the combined pre-release (E0308 at the four DoP / native-DSD wrap sites), failing the test-crates CI. Switches the field + new() to SharedState and drops the now-redundant Arc::new in the two DSD tests. Verified with scripts/cargo-test.sh (workspace, no UI): all crates green.

cc
2026-07-13 21:15:22 -06:00
vicrodh 8c50c16faa fix(offline): clarify that Clear cache keeps downloaded albums
After #606 the offline Clear-cache purges only the transient cache dirs (tracks/tracks-cmaf/artwork), never the organized downloaded albums — those are removed per-item from the offline manager. The old copy ('Remove every downloaded track. This cannot be undone.') was misleading. Relabels the row 'Clear cache', rewrites the description to say downloads are kept and point to the manager, and softens the toasts to 'Cache cleared' / 'Couldn't clear the cache'. 8 locales.

cc
2026-07-13 21:01:48 -06:00
vicrodh af1ccce398 chore(scripts): add prune-incremental.sh for stale incremental caches
Keeps only the most-recently-modified incremental-compilation dir per crate under crates/target and prunes the rest (slint-run.sh's per-RAM-tier RUSTFLAGS spawn a new hash dir each time; Cargo never GCs them). Release builds do not use incremental, so unaffected.

cc
2026-07-13 21:01:48 -06:00
vicrodh ba7be747a7 fix(immersive): persist volume on drag-end
The immersive VolumeBar only called set-volume (live) and never persist-volume, so a volume set in the immersive view was lost on restart/track-change. Adds a released(float) callback emitted on pointer-up, wired to NowPlayingState.persist-volume — parity with the NPB sliders. Pure .slint; persist-volume already exists in Rust.

cc
2026-07-13 21:01:48 -06:00
vicrodh 41f8578b78 feat(home): sort control for the Library Albums rail
Adds a compact dropdown in the Library Albums (favoriteAlbums) row header, left of the page chevrons: Recently added (default), First added (reverse), Random (shuffle). Reorders the cached base list in Rust with no re-fetch and re-fires artwork by the new index. Also corrects the stale HomeView comment that claimed the recently-played refresh lives in the toolbar (it is a row-header button). 8 locales updated.

cc
2026-07-13 21:01:48 -06:00
vicrodh dfc74fb6d4 Merge branch 'pr/606' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:27:23 -06:00
vicrodh 12dcedbc0f Merge branch 'pr/611' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:14:09 -06:00
vicrodh 0a4a6b6367 Merge branch 'pr/610' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:13:57 -06:00
vicrodh 30c57c9f54 Merge branch 'pr/608' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:13:57 -06:00
vicrodh 97ab577778 Merge branch 'pr/598' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:13:57 -06:00
vicrodh 3f974752ae Merge branch 'pr/595' into integration/pr-review-smoke-2026-07-13
# Conflicts:
#	crates/qbz-player/src/player/mod.rs
2026-07-13 14:13:47 -06:00
vicrodh 83c47933cb Merge branch 'pr/594' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:12:49 -06:00
vicrodh 7b0b2ed7da Merge branch 'pr/599' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:12:39 -06:00
vicrodh c2e23dfa95 Merge branch 'pr/593' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:12:39 -06:00
vicrodh 116fe38476 Merge branch 'pr/607' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:08:28 -06:00
vicrodh d4522c3585 Merge branch 'pr/604' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:08:28 -06:00
vicrodh 62dc3f55aa Merge branch 'pr/601' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:08:28 -06:00
vicrodh a88a38c644 Merge branch 'pr/600' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:08:28 -06:00
vicrodh 4051f76970 merge: 2.0.2 follow-ups (renderer #558, circle-actions, palette, home refresh, np source)
cc
2026-07-13 13:12:05 -06:00
vicrodh b3d12e6b2c fix(playback): give the now-playing "source" button a per-track context
The "playing from" button read a single global context set once at play time;
refresh_now_playing_meta never republished it, so it went stale across track
changes (previous track's album) and single-track plays fell back to the
current track's album instead of the playlist it came from. Add per-track
context_kind/context_id to QueueTrack (serde-default None, back-compat), stamp
the real container at every play path (album/artist/playlist/label), and
republish the context from the current track on EVERY track change (gapless
included) — never cached. open-context routes all stamped kinds.

cc
2026-07-13 13:11:43 -06:00
vicrodh a174e06119 feat(home): auto-refresh recently-played rails + a row refresh button
Home's recently-played albums/tracks only populated on a full home load, so
tracks played mid-session never appeared until restart. Re-read the LOCAL
store into the rails when a track is recorded while Home is visible, and on
Home re-mount if it went dirty — event-driven, no polling, cheap (small JSON
read + cached artwork). Also add a manual refresh button in each recently-
played row header next to the page chevrons (moved off the top toolbar, where
it crowded the discovery tab bar).

cc
2026-07-13 13:11:43 -06:00
vicrodh 8df8c18ab0 fix(theme): sync std-widgets Palette to the active QBZ theme
Native std-widgets (LineEdit/TextEdit) render from Slint's own Palette, which
we never synced to the QBZ theme, so on a light theme their text collided with
its own background (Settings input fields, effectively invisible). Add
Theme.is-dark (computed in Rust from the surface luminance, so it is correct
for static/auto/custom themes) and drive Palette.color-scheme from it in the
AppWindow: light/dark follow the theme, System stays `unknown` (follows the
OS). Reactive on theme change.

cc
2026-07-13 13:11:12 -06:00
vicrodh a9dff18d25 fix(ui): make CircleAction buttons visible on light themes
CircleAction defaults to hardcoded light-on-dark colors, so every instance
sitting on the normal page background (not over artwork) vanished on light
themes. Set on-surface: true on those clusters — Popular Tracks (artist +
label), the PlaylistView hero row, LocalAlbumView, AwardView,
PurchaseDetailView, MixtapeDetailView, FavoritesView, LocalLibraryView — so
they use theme-appropriate colors. Buttons over artwork/dark headers keep the
light-on-dark defaults.

cc
2026-07-13 13:11:12 -06:00
vicrodh 80088b6a0b fix(renderer): keep the app alive when the wgpu surface goes Outdated (#558)
At a non-default UI scale, SLINT_SCALE_FACTOR changes the physical surface
size and the first frames race the winit resize/scale-factor event that
reconfigures the swapchain, so get_current_texture() returns Outdated. The
vendored femtovg-wgpu backend reconfigured and retried once, then propagated a
second Outdated via `?`, which killed the event loop and left the app unable
to start at any interface size other than default. Treat a persistent Outdated
like the #540 timeout: skip the frame and back off briefly; the next
resize/redraw reconfigures cleanly. wgpu now survives the scale race without
depending on the degradation ladder falling back to GL.

cc
2026-07-13 13:11:12 -06:00
vicrodh 957ac6503a merge: 2.0.2 fixes into pre-release
Kiosk polish + volume fluidity + playlist drag-reorder + quality badge, and
issue fixes: #491/#519 album/artist header, #534 snap audio, #573 plex sync,
#578 gpu tier, #588 trackpad scroll, #588/#590 quality, #591/#592 pipewire.

cc
2026-07-13 09:40:53 -06:00
Afonso Jorge Ramos ec69bce17e feat(ui): open album from grid card title click 2026-07-13 16:45:42 +02:00
Afonso Jorge Ramos b4450965df fix(player): surface stream feeder failures to BufferWriter
CMAF and remote download tasks now error the streaming buffer on failure
so readers do not hang waiting for complete/error forever.
2026-07-13 16:16:14 +02:00
Afonso Jorge Ramos 4ce075beaa docs: tombstone Remote Control OpenAPI for 2.0 Slint
The LAN REST/SSE server is not in the shipping binary; fix license/repo
metadata and mark the document historical while retaining path schemas.
2026-07-13 16:13:05 +02:00
Afonso Jorge Ramos c9b9aea118 fix(scrobble): skip tracks shorter than 30 seconds 2026-07-13 16:12:06 +02:00
Afonso Jorge Ramos 68317f5a34 fix(dsd): treat demux I/O errors as sticky failures, not clean EOF
Only Ok(0) ends the stream cleanly; mid-file read errors set io_error.
2026-07-13 16:11:02 +02:00
vicrodh fa161be525 fix(header): gradient height = header container (ends at divider), artist-page parity, action buttons readable with gradient off
The album header gradient was a fixed px that overshot the header/track-list divider on tall (description-bearing) headers; bind its height to the divider's y so it ends exactly at the header container's bottom at any size. Apply the same readable-text + gradient-to-boundary treatment to the artist page. And CircleAction gains an on-surface variant (theme-colored fill/border/icon) driven by the gradient toggle, so when the header gradient is off the action buttons are visible on light themes instead of white-on-white. Below-divider content untouched. Extends #491/#519.

cc
2026-07-13 07:50:46 -06:00
Afonso Jorge Ramos 21c4817fcf fix(player): bump play generation on stop, DSD, and streaming
Non-play_track entry points must supersede in-flight play_track so a
slow fetch cannot clobber stop or a later source.
2026-07-13 13:50:06 +02:00
Afonso Jorge Ramos 61df66c529 fix(offline): purge only allowlisted cache layout directories
Stop recursive-deleting arbitrary siblings of the offline root so a
mis-set cache path cannot wipe unrelated folders on a shared mount.
2026-07-13 13:49:55 +02:00
Afonso Jorge Ramos 542ee8050f fix(player): clear streaming loaded state on streaming setup failures
Buffer timeout, engine creation failure, and incremental source failure
no longer leave has_loaded_audio true with no engine; each records a
user-visible stream error.
2026-07-13 13:49:34 +02:00
Afonso Jorge Ramos e153673acf fix(cmaf): fail init parse when raw_data length exceeds payload
Do not advance the cursor by an unclamped raw_len after a truncated slice.
2026-07-13 13:48:40 +02:00
Afonso Jorge Ramos 39dccd8b01 fix(credentials): tighten permissions of existing secret files on load 2026-07-13 13:48:30 +02:00
Afonso Jorge Ramos c1bb5b3dc2 fix(audio): fail closed when ALSA exclusive rate is not exact
Read back the hardware rate after hw_params for PCM, DoP, and native DSD
and refuse silent nearest-rate mismatches.
2026-07-13 13:47:43 +02:00
Afonso Jorge Ramos e1c34005e0 fix(credentials): write secret files with mode 0o600 on Unix
Salt, machine-id fallback, encrypted credentials, and OAuth token files
must not inherit a permissive umask.
2026-07-13 13:47:18 +02:00
vicrodh d0a7ded531 fix(audio): superseded plays skip the 60s initial-buffer wait; non-streaming path falls back to legacy
Follow-ups to #591/#592. The streaming initial-buffer wait blocked the audio thread up to 60s even when the play had been superseded by a newer track, which fed the stop/restart-loop feel; play_generation moved onto SharedState and threaded through PlayStreaming so a superseded wait exits in ~50ms (the 60s timeout stays for genuine slow networks). And the non-streaming Play path gained the same legacy-CPAL fallback the streaming path got, instead of dead-ending on backend-init failure (macOS keeps surfacing the error). Control flow only; sample path untouched.

cc
2026-07-13 05:01:22 -06:00
vicrodh c3523722f4 feat(local-library): add a Plex sync button to refresh media without restarting
Fetching new Plex music required restarting QBZ. Add a sync button in the Local Library header (gated on plex-available, with a busy spinner) that triggers the existing Plex re-sync (new plex_auth::sync_now over the persisted selected libraries) and refreshes the view. Strings in all 8 locales. Resolves #573.

cc
2026-07-13 04:44:08 -06:00
vicrodh 99cf738a4c fix(scroll): boost Wayland trackpad scroll speed in the vendored Flickable
Trackpad PixelDelta events arrive divided by the HiDPI scale factor, making trackpad scrolling far slower than other apps on scaled Wayland desktops. In FlickableData::scroll_delta, distinguish line-based wheel deltas (always exact multiples of 60) from pixel-precise trackpad deltas and apply a 2.75x factor to the latter only; wheel and fling scrolling are unchanged. Resolves #588.

cc
2026-07-13 04:44:08 -06:00
vicrodh f8a256c62d fix(audio): don't require pactl for PipeWire, and fall back to legacy on streaming init failure
Two stacked defects broke playback under sandboxes (Snap/Flatpak/minimal .deb) in 2.0.1: PipeWireBackend::is_available() probed only `pactl info`, which those images don't ship, so PipeWire reported unavailable even though it was running (native pw-dump enumeration succeeded in the same log). And the streaming stream-init path had no legacy fallback (unlike init_device), so a failure dead-ended into a stuck spinner until the 45s watchdog. is_available() now checks the pipewire-0 socket + pw-dump (both time-bounded, fail-fast) with pactl kept as a last fallback; the StartStreaming path falls back to legacy CPAL on non-macOS. Sample path untouched (no gain/resample/rate change). Addresses #591/#592.

cc
2026-07-13 04:44:08 -06:00
vicrodh 0f88361427 fix(album): readable header text on light themes + gradient reaches the divider
The header sits on the always-dark art atmosphere, but its text used Theme.text-* which is dark on a light theme = unreadable. Route the header title/artist/meta/description through hdr-strong/hdr-body colors that go white over the gradient and fall back to the theme colors when the gradient is off; below-divider text is untouched. The atmosphere also faded out above the divider on description-bearing headers — raise its height to 440px and push the fade start to 74% so it reaches the header/track-list divider. Addresses #491/#519.

cc
2026-07-13 04:28:26 -06:00
vicrodh f5a8afc0f2 fix(playlist): reorder via the existing row drag gesture, not a bespoke grip
The prior reorder reused only the DragGhost but re-implemented the drag gesture with its own grip + absolute-position math, which placed the ghost several px off the cursor. Remove the grip entirely and drive reorder off the SAME row-body drag that already adds a track to a sidebar playlist: it captures the source index on start, the shared DragGhost (positioned by the Rust DragActions path) follows the cursor exactly, the drop slot is read from DragState.pointer-y against the ListView's absolute-position (no row double-count), and releasing WITHIN the list reorders while releasing on a sidebar playlist still adds. Reverted the sidebar drop suppression + removed DragState.reorder.

cc
2026-07-13 02:45:10 -06:00
vicrodh 85e11d284a feat(quality): downgrade arrow + true-quality tooltip on the Now Playing badge
Follow-up to #590: playback now downgrades to the streaming-quality setting but the badge still showed the catalog max with no indicator. The poll loop already received the delivered stream's sample-rate/bit-depth in PlaybackEvent but dropped them; publish them plus a quality-downgraded flag (effective < catalog max, DSD-exempt on depth) and the true effective detail string. AudioStamp shows an amber down-arrow glyph when downgraded and a Source/Output hover tooltip; mirrored to the miniplayer. Strings translated in all 8 locales.

cc
2026-07-13 01:49:18 -06:00
vicrodh 6e58682aa6 fix(playlist): reuse the shared drag ghost for custom-order reorder
The bespoke reorder ghost read a row's absolute-position inside a ListView, which double-counts the row's own offset, so it only sat at the cursor for row 0 and flew off for the rest. Drive the app-wide DragState directly from the reorder gesture so the shared DragGhost (positioned in AppShell at the proven window coords) renders the reorder ghost; a new DragState.reorder flag keeps the sidebar from claiming it as an add-to-playlist drop and keeps the Rust DragActions path out of it. Removed the buggy local ghost. Reorder logic + persistence unchanged. (state.slint also carries the quality-badge fields for the next commit.)

cc
2026-07-13 01:29:09 -06:00
dependabot[bot] 144428ed89 chore(deps): bump softprops/action-gh-release from 2 to 3 (#577)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-13 00:39:52 -06:00
dependabot[bot] caa9a682ef chore(deps): bump peter-evans/repository-dispatch from 3 to 4 (#576)
Bumps [peter-evans/repository-dispatch](https://github.com/peter-evans/repository-dispatch) from 3 to 4.
- [Release notes](https://github.com/peter-evans/repository-dispatch/releases)
- [Commits](https://github.com/peter-evans/repository-dispatch/compare/v3...v4)

---
updated-dependencies:
- dependency-name: peter-evans/repository-dispatch
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-13 00:39:49 -06:00