Commit Graph
512 Commits
Author SHA1 Message Date
vicrodh 9a95a54e0f fix(queue): prevent ghost next_track after context switch
Auto-advance from a previous track could arrive after the user
switched to a new album/playlist, advancing the new queue's index
and skipping a track (observed: Sorceress track skipped).

Added queue epoch counter that increments on setQueue/clearQueue.
nextTrackGuarded() captures epoch before the invoke and discards
the result if the queue changed while in-flight. Applied to all
auto-advance paths (track-end, gapless transition) but not to
manual skip (user-initiated).

cc
2026-04-06 11:42:28 -06:00
AdamArstall c85fff4902 Delay firstId variable declaration until needed 2026-04-06 11:12:30 +01:00
AdamArstall 4c786c86fd Moved logic to repeat current track gapless from backend to frontent 2026-04-06 10:24:43 +01:00
Afonso Jorge Ramos b71284187b refactor: migrate platform detection to Tauri OS plugin utility 2026-04-03 13:58:11 +02:00
vicrodh 34a18093d0 fix: restore albumId/artistId on session resume for player bar navigation
setCurrentTrack during session restore was missing albumId and artistId,
causing Go to Album / Go to Artist clicks to silently fail until a new
track was played. Also restore isLocal, source, and parental_warning for
full parity with the normal playback path.

Closes #252

cc
2026-04-02 11:54:02 -06:00
Afonso Jorge Ramos 8283bec614 feat: add Cmd+, keyboard shortcut to open settings 2026-04-01 14:38:06 +02:00
Afonso Jorge Ramos 684dd55887 fix(macos): scope title bar padding to non-home views only 2026-04-01 03:27:25 +02:00
Afonso Jorge Ramos cd2472f5d9 fix(macos): add top padding to clear native overlay title bar 2026-04-01 02:29:33 +02:00
vicrodh a87e35d167 fix: restore MPRIS metadata and playback context on session resume
- Send track metadata to MPRIS on session restore so playerctl
  shows title/artist/album immediately after app restart
- Persist playback context (album, playlist, etc.) to localStorage
  on session save and restore it on startup
- Add buffer_progress to frontend PlaybackEvent type

Closes #240

cc
2026-03-31 16:33:07 -06:00
vicrodh 6acd843891 feat: add streaming buffer progress indicator to seekbar
Show a subtle buffer progress bar in the seekbar when streaming
tracks (before they are fully cached). The bar disappears once
the track is fully buffered.

Backend: expose buffer_progress from BufferedMediaSource through
SharedState -> PlaybackEvent -> playerStore.
Frontend: render .seekbar-buffer bar behind the playback fill.

cc
2026-03-31 16:02:07 -06:00
vicrodh b315b23b61 fix: F11 fullscreen toggle and ESC exit work globally
F11 now toggles window fullscreen from anywhere in the app, not just
inside the immersive player. ESC exits window fullscreen when no UI
overlays are open.

Closes #202

cc
2026-03-31 15:34:27 -06:00
victorrhgap 84c9b69359 style: fix indentation and missing semicolon from PR #230
cc
2026-03-30 13:29:29 -06:00
AdamArstall fafd547311 Fix scroll position not being saved when navigating without scrolling 2026-03-28 21:10:21 +00:00
victorrhgap e966f35b30 feat(ui): wire QualityFallbackModal into global layout
Listen for 'quality-fallback-prompt' custom events dispatched by
playbackService, open the modal with track context, and handle
try-lower / skip / close actions.

cc
2026-03-25 15:29:27 -06:00
victorrhgap 9f7304b35b Merge branch 'pr-181' into pre-release 2026-03-24 19:28:57 -06:00
vicrodh 8316e1f4c9 fix: logout spinner hang and last_user_id preservation
Two bugs:

1. mainContentEl teardown crash on logout — the $effect cleanup used
   non-null assertion (!) on an element that becomes null when the DOM
   is destroyed during logout. Changed to optional chaining (?.).
   This TypeError was blocking the render, causing the spinner to hang
   instead of showing the login form.

2. deactivate_session was clearing last_user_id, which broke offline
   mode after logout. The user's data stays on disk — only factory
   reset should clear the last_user_id marker.

cc
2026-03-21 14:25:28 -06:00
vicrodh fb74f318a1 fix: restore offline mode — use last known user profile
Three bugs prevented offline mode from working after V2 migration:

1. activate_offline_session used user_id=0 (empty profile) instead of
   the last known user_id, so the user's library/settings were invisible

2. setManualOffline was called BEFORE activate_offline_session, but it
   requires the offline store to be initialized (which happens during
   session activation). Reordered: activate session first, then set
   manual offline.

3. LoginView called setManualOffline directly instead of delegating to
   the parent's handleStartOffline which has the correct order.

Also added "noPreviousSession" i18n message for users who never logged
in — they need to create a profile first before offline mode works.

cc
2026-03-21 11:01:25 -06:00
vicrodh dde7c192dc fix: allow volume control when QConnect peer renderer is active on ALSA hw:
When ALSA Direct hw: is active but a remote device (phone, speaker) is
the active renderer via QConnect, volume changes go to the remote device
not the local DAC. The 100% lock should only apply to local playback.

cc
2026-03-20 17:34:47 -06:00
Afonso Jorge Ramos 6017cc70de fix(macos): gate drag region to macOS only 2026-03-20 01:14:47 +01:00
Afonso Jorge Ramos 00147dc7fb feat(macos): adapt frontend for native title bar
- Add macOS platform detection (html.macos class)
- Prevent pinch-to-zoom gestures in WKWebView
- Hide custom title bar on macOS (uses native overlay title bar)
- Add 32px top padding to sidebar for traffic light buttons
- Add drag region for window movement
2026-03-20 00:45:16 +01:00
vicrodh d0476dd5ab fix(qconnect): fix renderer handoff args and TransportConnected type check
QconnectBadge was passing { rendererId } instead of
{ request: { renderer_id: rendererId } } to v2_qconnect_set_active_renderer,
causing "missing required key request" error on every handoff attempt.

Also fixed TypeError when event.payload is a string ("TransportConnected")
instead of an object — the 'in' operator requires an object operand.

cc
2026-03-19 16:43:32 -06:00
vicrodh 8a8c709c1b feat: lock volume at 100% when ALSA Direct hw: is active
With ALSA Direct hw: there is no software mixer — volume must be
controlled at the DAC/hardware level. Software volume attenuation
would reduce bit depth and defeat the purpose of bit-perfect playback.

Backend: v2_set_volume forces volume to 1.0 when backend=Alsa+plugin=Hw
Frontend: volume slider disabled (grayed out at 100%), mute/step buttons
hidden, handleVolumeChange and handleToggleMute return early.
Settings callbacks notify +page.svelte when backend/plugin changes to
update the lock state in real-time.

i18n: volumeLockedHw tooltip added to all 5 locales.

cc
2026-03-19 00:10:59 -06:00
vicrodh bf91822b4d feat: add QConnect dev toggle and device name settings
Developer Mode: toggle to show/hide QConnect dev panel button in
the player bar (hidden by default, persisted in localStorage).

Integrations: editable device name input for Qobuz Connect with
default "Qbz - {hostname}". Backend commands v2_qconnect_get/set
_device_name and v2_get_hostname. Custom name is used during the
WS bootstrap handshake.

cc
2026-03-18 21:31:11 -06:00
vicrodh 2953b86062 feat: add QconnectBadge as full-height badge in song card
Place QConnect badge as direct child of badges-group with 3px gap
matching DAC/EXC spacing. Two-row vertical layout: icon on top,
Qobuz/Connect text below. Wire props from +page.svelte to both
NowPlayingBar instances. Add qconnect i18n keys to de/fr/pt locales.

cc
2026-03-18 21:03:56 -06:00
vicrodh 8e87b414db feat(qconnect): route volume/mute to peer renderer when remote is active
New _if_remote backend commands for set_volume and mute_volume.
handleVolumeChange and handleToggleMute in both main view and miniplayer
now check for peer renderer before setting volume locally.  Media
control set_volume also routed through the guard.  When no peer is
active, volume is set locally and reported to QConnect server.
2026-03-15 09:14:07 -06:00
vicrodh 1fc2e79391 feat(qconnect): add stop_if_remote guard for media control stop action
When a peer renderer is active, the MPRIS/media-key stop command now
sends SetPlayerState(STOPPED) to the QConnect server instead of stopping
local playback.  Falls back to local stop on error or when no peer is
active.
2026-03-15 07:27:32 -06:00
vicrodh 6bb416f854 refactor: centralize mute in ImmersivePlayer and Miniplayer via playerStore.toggleMute
Replace local isMuted/previousVolume state in PlayerControlsCompact and
MiniPlayerFooter with the global toggleMute from playerStore.  Muted
state is now derived from volume === 0, matching NowPlayingBar behavior.
Pre-mute volume is persisted in localStorage by the store.
2026-03-14 22:53:43 -06:00
vicrodh d21f2253bc feat(qconnect): add QConnect guards to shuffle, repeat, queue play, and history play handlers
When a peer renderer is active, shuffle/repeat/queue-play/history-play
commands are now routed to the QConnect server instead of being applied
locally.  Two new backend commands (toggle_shuffle_if_remote,
cycle_repeat_if_remote) follow the existing _if_remote pattern.
Guards added to both +page.svelte (main + immersive) and miniplayer.
2026-03-14 22:44:31 -06:00
vicrodh 311b7269ee fix(qconnect): keep gapless enabled for local renderer
cx
2026-03-14 17:57:46 -06:00
vicrodh 8a468ed725 fix(qconnect): restore local repeat renderer flow
cx
2026-03-14 13:09:23 -06:00
vicrodh 0529f355e8 fix(qconnect): reanchor repeat state before toggles
cx
2026-03-14 07:55:42 -06:00
vicrodh 017aa9a6b1 fix(qconnect): sync remote renderer into qbz ui
cx
2026-03-13 12:51:33 -06:00
vicrodh 65a0d523bb fix(qconnect): track active remote renderer state for skip and seekbar
cx
2026-03-13 11:55:48 -06:00
vicrodh 145974c292 fix(qconnect): harden renderer handoff identity
cx
2026-03-13 10:20:54 -06:00
vicrodh 3c688f129e fix(qconnect): backendize remote skip handoff
cx
2026-03-13 09:59:19 -06:00
vicrodh 4629e776f1 fix(qconnect): hand off play toggle to active renderer
cx
2026-03-12 23:49:33 -06:00
vicrodh a2c4017607 fix(qconnect): treat remote queue tracks as qobuz playback
cx
2026-03-12 19:48:17 -06:00
vicrodh bb110f3654 fix(qconnect): unify queue replacement through shared helper
cx
2026-03-12 17:36:18 -06:00
vicrodh 674fff996b refactor(qconnect): extract runtime helpers from page\n\ncx 2026-03-12 17:21:50 -06:00
vicrodh c026fce2ca fix(qconnect): avoid stale local report drift
cx
2026-03-12 17:08:18 -06:00
vicrodh 5cb4574e37 fix(qconnect): instrument runtime and anchor play next
cx
2026-03-12 15:54:52 -06:00
vicrodh 02155f54fe merge(pre-release): sync qconnect-poc-v3 with latest local integration state
cx
2026-03-12 15:23:32 -06:00
vicrodh 104e38e630 fix(nav): Discover menu items now navigate to correct home tab
navigateTo() was passing the tab id to the navigation store but never
setting the local homeTab state that HomeView reads. Editor's Picks
and For You always landed on Tab-Home.
2026-03-12 15:06:57 -06:00
vicrodh 9d6c2f7eba fix: harden session restore/persist to prevent ghost CSS errors
When last_view pointed to a view with incomplete context (e.g.
album without selectedAlbum data), the Svelte CSS extraction
pipeline would corrupt and produce PostCSS "Unknown word" errors
that survived cache cleans and npm ci.

- Add isSessionRestoreSafeView() whitelist for context-free views
- Add getSessionFallbackView() for graceful degradation
- Centralize persist logic in getPersistedSessionViewState()
- Only persist views that have valid context data
- Add purchase-album to restore path
- Add dev:reset-last-view script to reset session.db
- Fix AlbumCreditsModal.svelte event handler typing
2026-03-11 17:02:29 -06:00
vicrodh 0b870e6ddb fix: prevent black screen on session restore with missing view data
Add defensive fallback conditions for artist and playlist views
when activeView is set but data hasn't loaded yet (race condition
during session restore). Also add a catch-all fallback at the end
of the view chain so no combination of state can result in an
empty/black main content area.
2026-03-11 15:35:51 -06:00
vicrodh 80bff83c42 fix: proxy all artwork through backend cache for AppImage TLS compat (#163)
When WebKitGTK's GnuTLS can't find system trust store (common in
AppImage on some distros), direct HTTPS image loads fail. Home page
worked because AlbumCard already used cachedSrc which proxies through
the Rust backend (reqwest with its own TLS).

Apply cachedSrc to all remaining artwork displays:
- PlaylistCollage (playlist grid covers)
- NowPlayingBar (current track artwork + hover preview)
- ImmersiveArtwork (fullscreen player)
- QueuePanel (sidebar + immersive queue/history)
- CoverflowPanel, HistoryPanel, FocusMode

Also resolve artwork URL in +page.svelte via getCachedImageUrl before
passing to NowPlayingBar/ImmersivePlayer, so all downstream immersive
panels receive pre-cached asset:// URLs.
2026-03-11 08:13:51 -06:00
vicrodh 99d02c4477 feat: per-item titlebar nav toggles, purchases dropdown, error fix, layout tuning
- Refactor titlebar nav to per-item toggles (Discover, Favorites, Library, Purchases)
- Add Purchases dropdown with Albums/Tracks items
- Fix "Browse Library" label to "Local Library" using $t('library.title')
- Fix Purchases "TypeError: Load failed" to show friendly i18n message
- Increase titlebar height to 44px (+2px padding-top, +2px element height)
- Nav buttons 26px -> 28px, search input 28px -> 30px
- Reduce sidebar top padding from 12px to 6px
- Update height calculations for new titlebar size
2026-03-10 11:17:34 -06:00
vicrodh a288517d03 fix: Discover dropdown navigates to Home tabs instead of separate views
The Discover dropdown items (Home, Editor's Picks, For You) now
correctly navigate to the three tabs of the Home/Discover view
using navigateTo('home', tabId) instead of navigating to unrelated
discover-* view pages.
2026-03-10 10:56:39 -06:00
vicrodh 9c03a85a33 feat: add edge margin to nav buttons and show/hide window controls setting
Nav buttons get 8px padding on the edge side (matching folder spacing).
New opt-out toggle to hide window control buttons (min/max/close) for
window manager users who want the titlebar for nav and search only.
2026-03-10 10:54:50 -06:00
vicrodh 1871b0db1d feat: add navigation buttons (Discover, Favorites, Library) to titlebar
Opt-in setting (off by default) that moves Discover, Favorites, and
Local Library from the sidebar to the custom titlebar. Includes
dropdown menus for Discover and Favorites sub-items. Navigation
button position defaults to opposite of window controls but is
user-configurable. Items are hidden from sidebar when shown in
titlebar.
2026-03-10 10:36:47 -06:00