Queue Panel:
- Fix scroll by constraining panel between TitleBar and NowPlayingBar
- Add search bar to filter entire queue (not just first 20)
- Reduce font sizes by 1px for compact layout
- Reduce item height from 48px to 40px
TrackRow:
- Add album prop to display album column
PlaylistDetailView:
- Pass album data to TrackRow for album column display
- Fix clicking another playlist from sidebar while on playlist view
(was not notifying listeners because view type hadn't changed)
- Use $effect to reload playlist data when playlistId prop changes
- Reduce playlist title from 48px to 24px
- Reduce album title from 26px to 24px
- Max font size is now 24px (same as home greeting)
- Add 200ms delay between API calls to avoid 429 Too Many Requests
- Reduce chunk size from 50 to 20 (Tidal API limit for filter[id])
- Improve error messages to include response body for debugging
Cherry-pick and integrate playlist import from playlist-import-impl branch:
- Add playlist_import Rust module with providers (Spotify, Apple, Tidal, Deezer)
- Add track matching algorithm (ISRC first, then fuzzy matching)
- Add PlaylistImportModal.svelte with progress log UI
- Wire up import button in Sidebar
- Add modal state management in uiStore
- Register Tauri commands for preview and execute
Original implementation by Codex, integrated manually due to branch divergence.
Changed quality-indicator to column flex layout with badges row below
the QualityBadge. Both badges now expand to fill the width equally,
matching the QualityBadge width.
Session restore:
- Add pendingSessionRestore state to playerStore
- When restored track is played, load from Qobuz first
- Seek to saved position after track loads
Audio badges:
- Always show DAC/EXC badges (very muted when off)
- Adjust margins and sizing for better alignment
- Validate device has supported output configs before using
- Fall back to default if saved device is invalid
- Reduces polling frequency to 10 seconds
UI:
- Cover art now has 2px margin vs song-card edges
- Quality badges have 2px margin on right side
Audio:
- Track consecutive sink failures to detect broken streams
- Stop playback gracefully after 3 failures
- Add AudioOutputBadges component showing DAC/Exclusive mode status
- Badges are reactive to actual player state, not just settings
- Add device tooltip on hover showing current output device
- Create audioDeviceNames helper for ALSA name to friendly name mapping
- Use pretty names in Settings dropdown while storing raw names
- Add get_audio_output_status backend command
- Store current device name in player SharedState
- Player::new() now accepts optional device name
- Uses OutputStream::try_from_device() for specific device
- AppState reads saved device from audio settings on startup
- SettingsView loads/saves audio settings to backend
- Changes take effect on app restart
Backend:
- Create config/audio_settings.rs with SQLite persistence
- Store output_device, exclusive_mode, dac_passthrough, sample_rate
- Add Tauri commands: get_audio_settings, set_audio_*
- Register state and commands in lib.rs
Note: Player modification to USE these settings is pending.
See HANDOFF.md for implementation details.
Backend (Rust):
- Create session_store module with SQLite database
- Store queue tracks, current index, position, volume, shuffle/repeat
- Add Tauri commands: save_session_state, load_session_state, etc.
- Use WAL mode for better concurrent access
Frontend (TypeScript):
- Create sessionService.ts with save/load functions
- Restore session after login (queue, track info, volume, modes)
- Save session on beforeunload and visibility change
- Clear session on logout
- Debounced position saving during playback
Users can now close the app and resume where they left off.
- Use startDragging() API for reliable window dragging
- Create dedicated drag-region div for consistent drag behavior
- Double-click to maximize/restore
- Cleaner Discord/Spotify-inspired minimal design
- Reduce height to 32px for more content space
- Use Maximize2/Minimize2 icons for clearer visual feedback
- Fix button event handlers with proper async/await
- Disable native window decorations in tauri.conf.json
- Create TitleBar component with minimize/maximize/close controls
- Add drag region for window movement
- Integrate TitleBar into main layout and LoginView
- Adjust content heights to account for 36px title bar
- Prepare for future mini player implementation
- Use Tauri opener plugin for all external links in About modal
- Convert anchor tags to buttons with openUrl() for proper browser opening
- Add GTK_USE_PORTAL=1 for native file dialogs on Linux (KDE Plasma)
- Add Tux.svg and mexico-flag.svg for About modal signature
- Replace avatar with app logo (72x72 icon)
- Add hover glow effect on logo without layout shift
- Click logo opens About modal with:
- App description and links (GitHub, website)
- Version, license, build info
- Library/API attributions (Qobuz, Tauri, Svelte, etc.)
- Author credit and signature message
- Add compact prop to TrackRow: smaller height (44px), artist as column
- Apply compact mode to Continue Listening section in Home
- Reduces vertical space and improves scannability
- Add Heart icon button next to artist name
- Check favorite status on mount from get_favorites API
- Toggle favorite with add_favorite/remove_favorite API
- Show filled heart when artist is favorited
- Create api_cache module with TTL-based expiration (24h default)
- Cache get_album, get_track, and get_artist responses
- Check cache before API calls, store results after fetch
- Reduces API calls and speeds up Recently Played loading
Instead of relying solely on pre-computed scores (trained on login),
now merge the 4 most recent plays with scored items. This ensures
newly played tracks appear at the top without waiting for retraining.
- Create favoritesStore.ts for centralized favorites state management
- Refactor TrackRow to be self-sufficient with internal favorites handling
- TrackRow now subscribes to store and toggles favorites internally
- Remove redundant favoriteTrackIds state from AlbumDetailView and PlaylistDetailView
- Remove manual onAddFavorite prop drilling from all views
- Add trackId prop to TrackRow for store lookup (optional for local tracks)
- Add hideFavorite prop for local tracks that don't have Qobuz IDs
- Load favorites once on app init in +page.svelte
Loading overlay:
- Wait for ALL visible sections to finish loading before hiding overlay
- Count total visible sections and track when each finishes
- Content renders behind overlay, then overlay fades out smoothly
Continue Listening:
- Add menuActions with onAddFavorite to TrackRow
- Import handleAddToFavorites from trackActions service
- Favorite button now works in Continue Listening section
TrackRow:
- Convert favorite indicator div to interactive button
- Add stopPropagation to prevent row click (play) when clicking favorite
- Add hover state and proper button styling
HomeView:
- Add loading overlay that waits for at least 2 sections to load
- Overlay fades out smoothly when content is ready
- Prevents jarring "sections appearing and reordering" effect
- Add min-height: 0 and height: 100% to .right-section for proper
flex constraint cascade
- Add overflow: hidden to .lyrics-container for mask effect
- Add max-height: 100% and overflow-y: auto to .lyrics-lines
- Fix reset effect to track content changes vs array reference
- Remove debug console.logs
- Add startActiveLineUpdates() trigger to ExpandedPlayer
- Reduce transition times (200ms instead of 400ms) to fix lag
- Simplify karaoke gradient for clearer visual effect