Commit Graph
4231 Commits
Author SHA1 Message Date
vicrodh a912ced3d0 build: bump Node 20 to Node 24 across CI workflows and Flatpak manifest
Cherry-picked from PR #377 (thanks @Mar0xy) — Node-only portion, no
Discord IPC additions:

- 4 workflows (release-{linux,linux-aarch64,macos,flatpak}.yml) now
  install Node 24
- packaging/flatpak/com.blitzfc.qbz.yml: SDK extension node20 → node24,
  build append-path and npm_config_nodedir aligned

Forcing function: @icons-pack/svelte-simple-icons@7.x already in use
declares engines.node >=24, so Node 20 produces an EBADENGINE warning
in CI. Node 20 also reached EOL on 2026-04-30. Node 24 has been LTS
since October 2025 (~7 months of maturity).

Discord IPC permissions and qbz-wrapper script from #377 were
intentionally NOT cherry-picked — there's no Discord RPC feature in
QBZ today (#336 is still planned but not implemented), so adding the
sandbox permission and the launch wrapper now would expand the
attack surface for nothing. They'll land together with the actual
feature when it ships.

cc
2026-05-05 12:10:07 -06:00
vicrodh 0b181b0530 Merge branch 'feature/internal/multiselect-album-detail-381' into pre-release
Adds full multi-select coverage to the local library album detail view
per #381 — select-all checkbox, shift-click range, and Ctrl/Cmd+A
scoped to the open album with cross-view selection preserved.

cc
2026-05-05 12:01:21 -06:00
vicrodh 19a426f8ad feat(local-library): full multi-select coverage in album detail view (#381)
The album detail view (after drilling into a local album) had the
select-mode toggle button but was missing the rest of the multi-select
UX:

- Select-all checkbox in the track-list-header (only renders when
  select mode is active). State is derived from albumTracks vs
  selectedTrackIds so it accurately reflects partial / all / none
  for the currently-open album.
- Shift-click range support: TrackRow's onToggleSelect now passes
  the MouseEvent up. A new toggleAlbumDetailTrackSelect computes
  the absolute index in albumTracks (so ranges work across discs)
  and reuses applyShiftRange.
- Ctrl/Cmd+A while in album detail now scopes to the open album
  and unions with any selection already built up in other views,
  rather than replacing with library-wide tracks.

The toggle button itself (SquareCheckBig) was already wired — only
the missing pieces are added here. Cross-view selection composition
(tracks tab + album detail share selectedTrackIds) is preserved.

cc
2026-05-05 11:51:39 -06:00
vicrodh 05d7d8645d Merge branch 'bugfix/internal/playlist-duplicate-track-selection' into pre-release
Fixes #386 (duplicate-track selection collapse in playlist editing) plus
two related multi-select issues found while testing:
- Left-click on TrackRow checkbox now reliably toggles selection
  (input made pointer-transparent, parent div owns the click).
- Selected row background bumped from 12% to 22% accent so the
  visual cue is readable next to the saturated checkbox.

cc
2026-05-05 11:39:51 -06:00
vicrodh afb058119f fix(track-row): make checkbox input pointer-transparent + bump selected highlight
Two related issues uncovered while testing the playlist duplicate-track
fix in multi-select mode:

1) Left-click on the checkbox did nothing while right-click marked it.
   The input had onclick={(e) => e.preventDefault()} to suppress the
   browser's native toggle, relying on the parent div's onclick to
   dispatch onToggleSelect. Under webkit2gtk this combination
   intermittently absorbed the left-click without bubbling cleanly.
   Replace with style="pointer-events: none" on the input — clicks pass
   straight through to the parent div, which owns the toggle. The input
   is now purely visual, the div is the only event target. No more
   bubble-vs-default-action conflict.

2) Selected row background was too subtle to read against the heavy
   accent-coloured checkbox. Bump TrackRow's .track-row.selected from
   12% to 22% (hovered variant 20% to 30%) and align
   PlaylistDetailView's .track-row-wrapper.multi-selected wrapper
   rule to 22% so the two sources of truth stay in sync.

Affects every view that uses TrackRow with selectable=true — Album,
Artist, FavQ, Playlist, etc — all benefit from the consistent
pointer-events pattern and more visible selected state.

cc
2026-05-05 11:38:47 -06:00
vicrodh 6c8bfa4473 fix(playlist): align multi-select with TrackRow pattern (checkbox sync)
The explicit checkbox+label markup with onclick+preventDefault on the
input desynced the input's internal checked state from the rendered
checked attribute on click. Result: row background highlighted but
checkbox stayed visually unchecked.

Replace with the standard TrackRow.selectable/selected/onToggleSelect
pattern used by AlbumDetailView, FavQView, ArtistDetailView. Side
benefits:
- Shift/ctrl+click on row body now works for range/toggle multi-select,
  matching UX in those other views
- Single source of truth for the checkbox visual (TrackRow internal),
  no two-checkboxes risk
- Custom-order-mode checkbox preserved as-is - it uses onchange not
  onclick and was never affected

cc
2026-05-05 11:13:01 -06:00
vicrodh f5705cc8c3 fix(playlist): include index in track-selection key for duplicates (#386)
Bulk-edit selection used `${trackId}:${isLocal}` as the Set key. Two
duplicate tracks (same trackId+isLocal appearing twice in a playlist)
collapsed into a single entry, causing:

- clicking duplicate A selected duplicate B and vice versa
- background highlight and checkbox indicator desynced
- bulk delete removed both duplicates instead of the selected one

Fix: include the row index in getTrackKey so duplicates get distinct
selection keys. All 18 call sites updated to pass the index from the
local iteration context. The {#each} key was already index-aware
(visibleTrackRange.start + loopIdx + track.id) so Svelte's element
tracking is unaffected.

For Qobuz tracks the existing remove path uses playlistTrackId
(per-entry unique) so the correct entry is removed. Local-track
duplicates depend on backend semantics of v2_playlist_remove_local_track
keyed by localTrackId — that's a separate consideration outside this
UI fix.

Closes #386.

cc
2026-05-05 10:25:34 -06:00
vicrodh 1be46f1a24 Merge branch 'feature/internal/titlebar-mode-selector' into pre-release
Adds the 4-value titlebar mode selector (qbz | system | plasma | hidden)
replacing the three mutually-conflicting boolean toggles. Plasma mode
delivers KDE-native SSD via Xwayland on Wayland sessions; system mode
now also mounts a stripped strip below OS chrome when the user has
search-in-titlebar or any titlebar-nav item enabled.

cc
2026-05-05 09:46:18 -06:00
vicrodh 5369425d91 chore(deps): bump mdns-sd from 0.11.5 to 0.19.1 in /src-tauri
Bumped only for src-tauri's qconnect-discovery path. qbz-cast (chromecast/
DLNA) stays on 0.11 because mdns-sd 0.19 changed the address API
(HashSet<IpAddr> → HashSet<ScopedIp>) and adapting qbz-cast is real
work outside dependabot scope. Workspace now carries both versions
in the graph; both compile and operate independently.

cc
2026-05-05 09:37:59 -06:00
vicrodh ba98697da7 chore(deps): bump sha2 from 0.10.9 to 0.11.0 in /src-tauri
cc
2026-05-05 09:17:25 -06:00
Afonso Jorge Ramos 468a421e26 fix(audio): gate 50ms post-stop sleep behind cfg(target_os = "linux") 2026-05-05 17:11:28 +02:00
vicrodh f38141c034 chore(deps): bump notify-rust from 4.16.0 to 4.16.1 in /src-tauri
cc
2026-05-05 08:21:47 -06:00
vicrodh a370bfb34d chore(deps-dev): bump @sveltejs/kit from 2.57.1 to 2.58.0
cc
2026-05-05 08:07:28 -06:00
vicrodh 3329d56c58 chore(deps-dev): bump jsdom from 29.0.2 to 29.1.0
cc
2026-05-05 08:06:40 -06:00
vicrodh 4ca0faf378 chore(deps): bump tokio from 1.50.0 to 1.52.1 in /src-tauri
cc
2026-05-05 08:05:50 -06:00
vicrodh 71b2d18967 chore(deps): bump axum from 0.8.8 to 0.8.9 in /src-tauri
cc
2026-05-05 07:58:16 -06:00
dependabot[bot] f21be0f2f4 chore(deps-dev): bump svelte from 5.55.4 to 5.55.5 (#370)
Bumps [svelte](https://github.com/sveltejs/svelte/tree/HEAD/packages/svelte) from 5.55.4 to 5.55.5.
- [Release notes](https://github.com/sveltejs/svelte/releases)
- [Changelog](https://github.com/sveltejs/svelte/blob/main/packages/svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/svelte/commits/svelte@5.55.5/packages/svelte)

---
updated-dependencies:
- dependency-name: svelte
  dependency-version: 5.55.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 07:49:00 -06:00
Victor RH 2bc14e7ab8 Merge pull request #385 from afonsojramos/bugfix/internal/macos-output-device-picker
fix(audio): populate macOS output device picker
2026-05-05 07:12:25 -06:00
vicrodh a5a6f0dcac feat(titlebar): system mode now mounts stripped strip when content is enabled
Plasma and system mode become structurally symmetric — both render OS
chrome on top (KWin SSD via Xwayland for plasma, GTK CSD / WM SSD for
system) plus an optional stripped QBZ strip below for search and nav.

Same content-driven rule applies to both: the strip mounts only if the
user has search-in-titlebar enabled OR any titlebar-nav item enabled.
With both off, the user sees just the bare OS chrome, matching the
previous system-mode behavior.

Effective rules table:
- showWindowControls / matchSystemChrome: user pref in qbz only
- searchBarLocation / titlebarNav: user pref in qbz/plasma/system,
  forced/n-a only in hidden

i18n disabledHint strings updated to reflect the new rules across all
five locales.

cc
2026-05-05 01:50:15 -06:00
vicrodh dab72cd588 fix(titlebar): hide stripped strip in plasma when empty
If the user has search-in-titlebar off AND no titlebar-nav items
enabled, plasma mode would render an empty 42px strip below the KWin
SSD. Gate shouldShowTitleBar() in plasma on whether either is enabled.
+page.svelte's search-location and titlebar-nav subscriptions now
also recompute showTitleBar so the layout reflows immediately when
the user toggles those settings.

cc
2026-05-04 16:25:26 -06:00
vicrodh f23cee9ecf fix(titlebar): bump plasma stripped variant to 42px
The 32px guess from the spec left the search input touching the bottom
edge — no breathing room. 42px gives proper vertical centering matching
the qbz variant's visual rhythm. Tested visually on KDE+Wayland.

cc
2026-05-04 15:13:51 -06:00
vicrodh e4835b6c55 fix(i18n): move titlebar block from settings.appearance to settings root
The Task 9 SettingsView consumer reads settings.titlebar.* directly
(see lines 1030, 1037, 4666, 4678 of SettingsView.svelte). The original
Task 11 commit placed the block under settings.appearance.titlebar
which would not resolve. Moving the block one level up.

cc
2026-05-03 20:30:25 -06:00
vicrodh 4e854072fa i18n(titlebar): add mode labels, disabled hints, sandbox caveat
Five locale files updated in lockstep: en, es, de, fr, pt. Mexican
Spanish dialect for es.json per project convention.

cc
2026-05-03 20:26:02 -06:00
vicrodh 0546dbf5cb feat(layout): mount TitleBar by mode + Sidebar consumes effective getters
The +page.svelte mount gate now reads shouldShowTitleBar() so layout
reacts to mode changes. Sidebar reads the effective search-location
and titlebar-nav getters so search and nav fall back to the sidebar
in system/hidden modes regardless of user pref. miniplayerService
reads getMode() instead of the removed legacy boolean.

cc
2026-05-03 20:14:23 -06:00
vicrodh d69c67ad34 fix(settings): include current mode in fallback availableModes
When v2_available_titlebar_modes fails, the dropdown's selected value
may not appear in its options. Include the user's current titlebarMode
in the fallback list to ensure the selected value is always present.

cc
2026-05-03 20:09:49 -06:00
vicrodh b7c686e99c feat(settings): mode dropdown replaces hide/system toggles
Single Dropdown drives the titlebar mode. Orthogonal toggles
(window controls, match-chrome, search location, titlebar nav) are
shown disabled with explanatory tooltips when the active mode does
not apply them. Sandbox caveat is shown inline when Plasma mode is
selected inside Flatpak/Snap.

cc
2026-05-03 20:01:36 -06:00
Afonso Jorge Ramos 1e3f5ab981 fix(audio): populate macOS output device picker 2026-05-04 00:31:21 +02:00
vicrodh b8ef96d600 fix(titlebar-store): align getTitleBarHeight with rendered CSS
The CSS at .titlebar / .titlebar.variant-full was already 44px before
this branch, and +page.svelte / Sidebar.svelte hardcode 44px in their
calc() reservations. The store was returning 40 — a latent lie waiting
for Task 10's layout consumers. Change qbz mode to return 44 so all
sources agree before they get wired together.

cc
2026-05-03 15:42:17 -06:00
vicrodh a811e2b032 feat(titlebar): variant-aware rendering (full vs stripped)
The full variant matches current behavior. The stripped variant (used
in plasma mode) drops drag region, dblclick maximize, window controls,
and rounded chrome — KWin SSD owns those. Search and per-item nav
remain in the strip below the SSD.

cc
2026-05-03 15:35:31 -06:00
vicrodh b47222d8cb feat(stores): effective getters that read titlebar mode
Search bar falls back to sidebar in system/hidden modes regardless of
user pref. Titlebar nav is N/A outside qbz/plasma. Both getters are
non-destructive: the user's persisted preference is preserved and
resumes when the mode allows it again.

cc
2026-05-03 15:30:30 -06:00
vicrodh 8d9e38d3ab fix(titlebar-store): pessimistic setMode + drop unconditional backend sync
Two issues raised in code review on Task 6:
1. setMode now invokes the backend before mutating local state, so a
   backend rejection leaves frontend state untouched and consistent.
2. Drop the unconditional v2_set_titlebar_mode invoke in initTitleBarStore.
   The migration path already covers the legitimate divergence case;
   firing it on every launch was overhead with no functional benefit.

cc
2026-05-03 15:27:46 -06:00
vicrodh 0dd509305b feat(titlebar-store): mode-based store with legacy migration
Replaces hideTitleBar/useSystemTitleBar booleans with a single mode
enum. First-run migration reads localStorage legacy keys, derives the
new mode deterministically, and pushes it to the backend. setMode
restarts the app only when the change crosses the decoration boundary.

cc
2026-05-03 15:21:31 -06:00
vicrodh 2794860bc0 feat(main): set GDK_BACKEND=x11 when titlebar_mode is Plasma
Reads the persisted titlebar mode at startup via WindowSettingsStore::new_readonly()
then composes the X11-forcing condition with the existing graphics force_x11
setting. Plasma mode now produces real KWin SSD on Wayland sessions without
requiring users to set the env var externally.

cc
2026-05-03 15:16:23 -06:00
vicrodh 4215b075a2 feat(lib): wire titlebar_mode into window builder, register new v2 commands
Window builder now derives decorations from TitlebarMode::wants_decorations()
which returns true for System and Plasma. Transparency gate now requires
mode=Qbz so plasma/system/hidden modes do not build a transparent window
that would leak through KDE/system chrome. The v2 command registry is
updated to expose the new mode commands and drops the legacy boolean
setter.

cc
2026-05-03 15:11:34 -06:00
vicrodh e444d3594d feat(commands-v2): add v2 titlebar-mode commands, drop v2_set_use_system_titlebar
The new commands cover get, set, and platform availability. The legacy
boolean setter is removed because the mode enum is now authoritative.

cc
2026-05-03 15:03:50 -06:00
vicrodh dae22574a6 feat(window-settings): add available_titlebar_modes and is_sandboxed helpers
Detection of KDE+Wayland for Plasma-mode availability. The is_sandboxed
helper drives the frontend caveat hint about Flatpak/Snap.

cc
2026-05-03 14:50:04 -06:00
vicrodh 045236f716 feat(window-settings): add TitlebarMode enum and titlebar_mode column
Adds a 4-value mode enum (Qbz | System | Plasma | Hidden) to the existing
WindowSettings store, with column migration that infers mode from the
legacy use_system_titlebar flag. Setter is write-through so the legacy
column stays consistent for any remaining readers.

cc
2026-05-03 14:44:41 -06:00
DoubleGateandCopilot Autofix powered by AI c46922c408 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-03 02:29:24 -04:00
DoubleGate 6578e81712 fix(sidebar): skip isOffline $effect on initial subscription
Svelte 5's $effect on a derived store fires on its initial
subscription, causing loadUserPlaylists() to run a second time
right after onMount(). Guard with a flag so the effect only fires
on actual offline -> online transitions.

Refs #382
2026-05-03 02:21:45 -04:00
vicrodh 773fa390eb i18n(settings): make qconnect startup-mode title explicit
"Auto-connect on startup" → "Auto-connect Qobuz Connect on startup"
(and equivalents in es/de/fr/pt). The earlier wording was ambiguous —
it could read as auto-connecting QBZ itself, not the QConnect feature.

cc
2026-05-01 16:01:51 -06:00
vicrodh 63745a480f fix(qconnect): trigger startup auto-connect after OAuth restore, not during setup
The auto-connect spawn was firing at the end of the Tauri setup hook,
before the frontend invoked runtime_bootstrap. At that point the API
client is not yet initialized (bundle tokens not extracted, no auth),
so service.connect always failed silently and the lifecycle stayed Off
even when startup_mode was On or Remember-last-on.

Move the trigger into v2_runtime_bootstrap, right after the OAuth token
restore + session activation + CoreBridge auth complete. The CLI
override (--enable-qconnect / --disable-qconnect) is exposed via a
managed QconnectCliOverride wrapper so bootstrap can read it.

cc
2026-05-01 15:58:14 -06:00
vicrodh 74775aaebf Merge branch 'feature/internal/qconnect-startup-persistence' into pre-release 2026-05-01 14:25:59 -06:00
vicrodh aa0f3c97eb i18n(settings): add qconnect startup mode strings (en/es/de/fr/pt)
Six new keys under settings.integrations.qconnect.startupMode covering
the dropdown labels, description, and local-library compatibility note.

cc
2026-05-01 13:34:11 -06:00
vicrodh 56951c6510 feat(settings-ui): qconnect startup mode dropdown + local-library hint
Adds the three-state dropdown to Settings > Integrations next to the
device-name field, plus a permanent compatibility note about local
library being incompatible with QConnect.

cc
2026-05-01 13:30:23 -06:00
vicrodh a6fb1cd018 feat(qconnect): write-through last_known_state on connect/disconnect
When startup_mode == RememberLast, persist the latest on/off state so
the next launch can restore it. No-op for Off/On modes.

cc
2026-05-01 13:10:39 -06:00
vicrodh 7bbe68d5b0 feat(qconnect): register v2_qconnect_get/set_startup_mode in invoke handler
cc
2026-05-01 13:08:57 -06:00
vicrodh 398b4ea807 feat(qconnect): add v2_qconnect_get/set_startup_mode commands
String-typed wire shape for predictable serde behavior across the
Tauri invoke boundary. Validates against QconnectStartupMode::from_str.

cc
2026-05-01 12:39:43 -06:00
vicrodh d5ae31aa1b fix(qconnect): move startup auto-connect to end of setup hook
The auto-connect spawn was running on a worker thread before CoreBridge
inner init completed, risking undefined behavior in service.connect.
Moving it to the end of setup ensures all init runs first.

cc
2026-05-01 12:37:48 -06:00
vicrodh 6f38362b9f feat(qconnect): apply startup_mode + CLI override during app setup
Spawns a background auto-connect task during the Tauri setup hook when
the effective startup decision says so. Failures log a warn and leave
lifecycle in Off; no infinite reconnect loop on first-time failure.

cc
2026-05-01 12:30:32 -06:00
vicrodh 27cb2ab6cc feat(qconnect): parse --enable-qconnect / --disable-qconnect CLI flags
Volatile per-launch override. Both flags together → enable wins
deterministically with a warn log. The override is threaded into
lib::run() and consumed in the next task.

cc
2026-05-01 12:20:35 -06:00