Commit Graph
100 Commits
Author SHA1 Message Date
vicrodh 6cd9cb43c4 Fix ALSA utils SHA256 checksum for Flatpak build 2026-01-19 15:39:55 -06:00
vicrodh 8fecbf80a6 Merge feature/app-id-rename: App ID rename and Flatpak improvements
BREAKING CHANGE: App ID changed from com.blitzkriegfc.qbz to com.blitzfc.qbz

Changes:
- Renamed Flatpak App ID and all metadata files
- Fixed MPRIS name: qbz_nix → qbz
- Added NAS support permissions: /mnt, /media, /run/media
- Updated CI workflow for new filenames
- Updated tauri.conf.json bundle identifier

Flatpak features:
- Runtime detection (/.flatpak-info check)
- Automatic data migration from old App ID
  - Migrates config, data, and cache directories
  - Non-destructive (preserves old directories)
  - Runs on startup before any other initialization
- New Settings section (Flatpak-only)
  - Filesystem permission guidance
  - Copy-paste ready commands for NAS/SSHFS
  - Professional UX per Flatpak best practices

Migration is automatic and transparent for existing users.
2026-01-19 15:17:32 -06:00
vicrodh 8175e14fb0 Add Flatpak sandbox section in Settings UI
Features:
- New Settings section that appears ONLY when running in Flatpak
- Displays clear instructions for granting filesystem permissions
- Copy-paste ready commands for common scenarios (NAS, SSHFS)
- Explains Flatseal as GUI alternative
- Professional, defensive UX per prompt requirements

The section is completely hidden when not in Flatpak.
Users see actionable guidance with examples.
2026-01-19 15:17:05 -06:00
vicrodh a0467fb10a Add Flatpak detection and automatic data migration
Features:
- Flatpak runtime detection (/.flatpak-info check)
- Automatic migration of user data from old App ID to new ID
  - Config: ~/.config/com.blitzkriegfc.qbz → ~/.config/qbz
  - Data: ~/.local/share/com.blitzkriegfc.qbz → ~/.local/share/qbz
  - Cache: ~/.cache/com.blitzkriegfc.qbz → ~/.cache/qbz
- Migration runs on startup before any other initialization
- Old directories are preserved (manual cleanup required)
- Tauri commands for frontend integration:
  - is_running_in_flatpak()
  - get_flatpak_help_text()

Migration is non-destructive and idempotent.
2026-01-19 15:14:14 -06:00
vicrodh d2f61974d8 Rename App ID: com.blitzkriegfc.qbz → com.blitzfc.qbz
Changes:
- Renamed Flatpak manifest, desktop file, and AppStream metainfo
- Updated App ID in all metadata files
- Fixed MPRIS name: qbz_nix → qbz
- Added NAS support permissions: /mnt, /media, /run/media
- Updated CI workflow to use new filenames
- Updated tauri.conf.json bundle identifier

BREAKING CHANGE: Users will need to migrate data from old App ID directories
Data migration will be implemented in next commit
2026-01-19 15:12:21 -06:00
vicrodh e2afc25175 Merge feature/ux-improvements-180226: UX improvements and playback context
Major UX improvements:
- Playback context tracking from albums/playlists/artists/favorites/home/search
- Stack icon showing context origin with clickable navigation
- Autoplay behavior setting with persistence
- Context menu actions (Play track only, Play from here)
- Track row pause on hover across all views
- Volume indicators while dragging (all 4 players)
- Favorites customization (custom icon, background, sticky nav, search)
- Theme expansion (Nord, Dracula, Tokyo Night, Catppuccin, Rosé Pine, Breeze, Adwaita)
- Layout fix: NowPlayingBar moved outside app-body flex row

Database migrations (safe for existing users 1.1.5+):
- playback_preferences table (autoplay + show_context_icon)
- favorites_preferences table (custom_icon_path, preset, icon_background, tab_order)
- Favorites icon now stored in cache dir with auto-migration

Audio backend: ✅ UNTOUCHED (bit-perfect playback preserved)

Known gaps (to fix in next branch):
- Track focus on context navigation not implemented
- Volume indicator in FocusMode/MiniPlayer not confirmed tested

# Conflicts:
#	src/lib/components/AlbumCard.svelte
2026-01-19 15:04:12 -06:00
vicrodh b172b55bcf fix(favorites): migrate custom icon storage to cache
cx
2026-01-19 14:51:18 -06:00
vicrodh 7d9071442f fix(layout): keep NowPlayingBar out of app-body
cx
2026-01-19 14:51:14 -06:00
vicrodh 8cf462e240 Merge feature/alsa-direct: ALSA Direct backend for bit-perfect audio
Implements native ALSA hw: device support for bit-perfect playback with:
- Direct PCM access bypassing PipeWire/Pulse resampling
- Automatic format detection (S16_LE, S24_LE, S32_LE, FLOAT_LE)
- Optional hardware mixer volume control via ALSA
- HW badge indicator for ALSA Direct mode
- DAC badge improvements with device name tooltip
- Lightweight hardware status polling for sample rate verification

Database migrations are safe for existing users (1.1.5+):
- alsa_hardware_volume column added with NULL-safe handling
- Defaults to disabled for backwards compatibility

UI improvements:
- Improved ticker animation on album cards and tooltips
- Badge tooltip shows actual device name with scrolling
- Fixed badge width consistency across quality types
2026-01-19 13:58:30 -06:00
vicrodh ebe5f0f187 Fix badge width: ensure min-width regardless of quality badge size
Added min-width: 70px to .audio-badges-row to prevent badges from becoming too narrow when QualityBadge is small (e.g., MP3 on local library).
2026-01-19 13:57:33 -06:00
vicrodh 80d349e9b0 Apply improved ticker animation to album cards (same as badge tooltip)
Changes:
- Reduced speed from 80 to 40 pixels per second for better readability
- Added typewriter-style animation with pauses and fast return
- Slow scroll (50% of time), pause, then quick return (10% of time)

IMPORTANT FOR MERGE: If this conflicts with other branches modifying the same animation, THIS VERSION should be kept as it provides better UX (tested and approved by user).
2026-01-19 13:43:07 -06:00
vicrodh ebbf5a6e3a Make ticker return faster like typewriter carriage
Adjusted keyframes so scroll is slow (50% of time) and return is quick (10% of time), mimicking mechanical typewriter carriage return.
2026-01-19 13:32:10 -06:00
vicrodh fa7cb51e91 Add pauses to ticker animation for smoother cycling
Animation now pauses at start and end positions before moving, eliminating jarring jumps when loop restarts.
2026-01-19 13:31:07 -06:00
vicrodh 29dfb78124 Reduce ticker animation speed to improve readability
Reduced speed from 80 to 40 pixels per second to make device name more readable and reduce stuttering.
2026-01-19 13:29:52 -06:00
vicrodh 0ee2891f44 Reduce badge tooltip width to 2/3 of original size 2026-01-19 13:28:52 -06:00
vicrodh de08d841b0 Fix ticker animation to trigger on tooltip open, not hover
Animation now starts automatically when tooltip appears if device name overflows, since tooltip has pointer-events: none and cannot be hovered.
2026-01-19 13:28:01 -06:00
vicrodh 5f3b4631e6 Add ticker animation for long device names in badge tooltip
Adds scrolling animation when device names overflow tooltip width, borrowed from AlbumCard component pattern. Also fixes accessibility warning by adding role and aria-label to badge container.
2026-01-19 13:26:56 -06:00
vicrodh 6166b7c206 Reduce console spam: change hardware status log from info to debug
The 1s polling of get_hardware_audio_status was logging every second:
"Hardware audio status: 192000Hz, format: Some("S32_LE")"

This is useful for debugging but too noisy for normal usage.

Change:
- log::info! → log::debug! (line 52)

Result:
- Console stays clean during playback
- Log still available with RUST_LOG=debug for debugging
- Polling continues working, just silently
2026-01-19 13:20:49 -06:00
vicrodh ea7614f639 Fix badge issues: restore lightweight 1s polling for hardwareStatus only
This reverts the event-driven approach (9242b95) and restores lightweight
polling, but ONLY for hardwareStatus.

Problems with event-driven approach:
1. False yellow warnings: hardwareStatus had stale data from previous song
   - Hardware: 88200 Hz (correct)
   - Cached hardwareStatus: 44100 Hz (from previous song)
   - Badge logic: 88.2 !== 44.1 → WARNING (false positive)

2. Lost device name: outputStatus never updated after mount
   - loadStatus() only called once on mount
   - outputStatus.device_name became stale
   - Badge tooltip showed "Default" instead of "hw:4,0"

Solution - Lightweight polling (best of both worlds):
- Call loadStatus() once on mount (loads everything)
- Poll ONLY hardwareStatus every 1s (no device enumeration)
- get_hardware_audio_status just reads /proc/asound (very cheap)
- No CPAL device enumeration (no console spam)
- No get_pipewire_sinks calls (no ALSA errors)

Benefits:
- Badge always shows current hardware status (accurate resampling detection)
- Device name preserved (loaded once, doesn't change)
- Zero console spam (no device enumeration)
- Very lightweight (just read /proc/asound file)
- ~1000x cheaper than full loadStatus() polling

This gives us accurate bit-perfect validation without the overhead.
2026-01-19 13:11:28 -06:00
vicrodh 0701892ed5 fix(local): clear context and seed queue
cx
2026-01-19 13:10:42 -06:00
vicrodh 1fae9b7d9f fix(ui): wire active state in lists
cx
2026-01-19 13:02:43 -06:00
vicrodh c59ab226b9 fix(playback): honor autoplay and seed queues
cx
2026-01-19 12:46:28 -06:00
vicrodh 7c4fb6d483 fix(favorites): show active track and icon
cx
2026-01-19 12:42:27 -06:00
vicrodh c97d4680e4 feat(theme): add additional palettes
cx
2026-01-19 12:41:43 -06:00
vicrodh 9242b95939 Replace 1s polling with event-driven updates on sample rate change
Changed hardware status polling from continuous (every 1s) to event-driven
(only when sample rate changes).

Rationale:
- Hardware sample rate ONLY changes when playing new song with different rate
- Continuous polling was overkill - 3600 unnecessary calls per hour
- If system is properly configured, status doesn't change mid-song
- Polling was originally added for "instant feedback" but wastes resources

Changes:
- Removed setInterval polling (lines 162-171)
- Added $effect that watches samplingRate prop changes
- Only calls get_hardware_audio_status when:
  * samplingRate changes (new song or format change)
  * Using DAC Passthrough or ALSA Direct (bit-perfect modes)
- Tracks previousSamplingRate to detect actual changes

Benefits:
- Zero backend calls during playback (unless rate changes)
- Still validates bit-perfect when it matters (new sample rate)
- Massive reduction in /proc/asound reads
- Better battery life, lower CPU usage
- Same UX - badge updates when song changes

Testing plan:
- Play songs with same sample rate → zero backend calls
- Play songs with different rates → update on each rate change
- Verify badge still shows correct status
- If issues found, can revert to 1s polling
2026-01-19 12:13:14 -06:00
vicrodh 19a571dddc Remove that was spamming backend calls on playback
The (() => { if (outputStatus?.is_playing) loadStatus(); }) was
causing massive console spam ("spam masivo") that continued even after
removing mouse from badge.

Root causes:
1.  was cherry-picked from feature/ui-fixes for badge auto-update
2. But now we have 1s polling that already keeps data fresh
3. outputStatus object was being mutated/recreated frequently
4. This triggered  repeatedly, calling loadStatus()
5. Each loadStatus() enumerated 12 CPAL devices + PipeWire sinks
6. CPAL enumeration causes ALSA errors: "Cannot get card index for 0"

Previous commit (0c3ca16) removed loadStatus() from onmouseenter, but
spam continued because  kept triggering during playback.

Solution:
- Removed  completely (lines 150-156)
- loadStatus() now only called once on mount
- Polling interval (1s) only calls get_hardware_audio_status
- get_hardware_audio_status just reads /proc/asound (no device enumeration)

Result:
- Console spam eliminated completely
- Badge still updates every 1s via polling
- Zero CPAL/ALSA enumeration during playback
- Massive reduction in CPU/battery usage
2026-01-19 12:07:30 -06:00
vicrodh 0c3ca16550 Fix badge hover spam - remove loadStatus() on mouseenter
Root cause:
- onmouseenter was calling loadStatus() which enumerates ALL devices
- loadStatus() calls: get_audio_output_devices (12 devices), get_pipewire_sinks, get_hardware_audio_status
- Each hover triggered 3 expensive backend calls + CPAL/ALSA enumeration
- User reported "spam masivo en la consola" when hovering badge

Solution:
- Removed loadStatus() call from onmouseenter (line 180)
- Only set isHovering = true to show tooltip
- Polling interval (1s) already keeps hardware status fresh
- Tooltip now shows cached data instead of triggering new enumeration

Impact:
- Hover now instant with zero backend calls
- Console spam eliminated
- Battery/CPU usage reduced significantly
- Tooltip still shows current data via 1s polling
2026-01-19 12:06:21 -06:00
vicrodh 282edfb206 Add Known Issues section to README
Documents known limitations discovered during ALSA Direct testing:

1. Seekbar Performance with Hi-Res Audio
   - 10-20s delay when seeking with >96kHz sample rates
   - Root cause: decoder must decode all samples from start to seek position
   - Workaround: Use prev/next track buttons (instant)
   - Future: Byte-level seeking planned for next release

2. First Sample Rate Change
   - Brief delay on first large rate change (e.g., 88.2→44.1 kHz)
   - Hardware stabilization time - normal behavior
   - Subsequent changes are smooth

3. ALSA Direct Mode
   - Bit-perfect but exclusive access (blocks other apps)
   - Hardware volume control experimental
   - Some DACs don't support hardware mixer

4. PipeWire DAC Passthrough
   - Requires PipeWire configuration for rate switching
   - Link to documentation

This section helps users understand limitations and workarounds, setting
proper expectations for bit-perfect audio modes.
2026-01-19 11:47:35 -06:00
vicrodh 05780f2b13 refactor(theme): centralize global theme styles
cx
2026-01-19 11:43:14 -06:00
vicrodh 8947bcf9c3 Skip drain on track skip for instant track changes
This fixes the 2-5s delay when rapidly changing tracks. The drain() was
blocking for hundreds of milliseconds waiting for the PCM buffer to empty,
even when the user was skipping tracks.

Root cause (playback_engine.rs:136):
- drain() was called ALWAYS after playback loop ended
- drain() blocks until PCM buffer is completely empty (~125-500ms)
- When user skips tracks, we don't need elegant buffer drain
- This caused 'need to wait 2-5s' or 'double click next' behavior

Solution:
- Added 'natural_end' flag to track WHY playback stopped
- natural_end=true: Song finished normally → DO drain (elegant end)
- natural_end=false: User skipped/paused → SKIP drain (instant response)

Benefits:
- Track changes now instant (no 2-5s wait)
- Songs that finish naturally still drain properly (no clicks/pops)
- Maintains audio quality while improving responsiveness

Testing:
- Rapid track skipping should be instant
- Songs that play to end should have smooth transition
- No audio artifacts (clicks/pops) in either case
2026-01-19 11:40:19 -06:00
vicrodh 0a361712ce Increase stream initialization delay from 50ms to 150ms
This addresses the 'slow playback' issue on first large sample rate transition
(e.g., 88.2kHz → 44.1kHz). The hardware needs extra time to stabilize when
changing sample rates significantly, especially on cold start.

Root cause:
- First transition 88.2→44.1 kHz: song started slowly
- Subsequent identical transitions: clean
- Affects both ALSA Direct and PipeWire DAC Passthrough
- Hardware 'warm-up' time needed for large rate changes

Fix:
- Increased delay from 50ms to 150ms (still imperceptible to user)
- Gives DAC hardware more time to stabilize clock after rate change
- Extra time especially critical for downward transitions (88.2→44.1)

Testing needed:
- Verify first 88.2→44.1 transition is now clean
- Ensure 150ms delay doesn't create noticeable gap
- Check all other transitions still work
2026-01-19 11:39:01 -06:00
vicrodh 97c9473790 Fix DAC badge showing 'Default' instead of actual device
The badge was always showing 'Default' regardless of the selected device because
thread_state.set_current_device() was only being called in the legacy CPAL path,
not in the backend system path (PipeWire DAC, ALSA Direct).

Root cause:
- Lines 801-805: Backend system creates stream but never sets current_device
- Lines 847, 883: Only legacy CPAL path was setting device name from CPAL device.name()
- UI badge calls get_audio_output_status() which returns player.state.current_device()
- current_device was None/outdated when using backend system

Fix:
- After successful stream creation (line 897), read output_device from settings
- Set thread_state.current_device with the device name from settings
- Fallback to 'Default' string if output_device is None
- Now badge shows: 'hw:4,0', 'DacMagic Plus Analog Stereo', etc.

Testing:
- ALSA Direct: Should show 'hw:4,0' or configured device
- PipeWire DAC: Should show 'DacMagic Plus Analog Stereo' or selected sink
- System Default: Should show 'Default'
2026-01-19 11:29:11 -06:00
vicrodh 395fd165d4 feat(player): add volume sliders to FocusMode and MiniPlayer
cx
2026-01-19 11:26:08 -06:00
vicrodh 318e3d795a feat(context): scroll to active track on context navigation
cx
2026-01-19 11:19:52 -06:00
vicrodh 78c4898edf fix(favorites): persist custom icon and sync modal state
cx
2026-01-19 11:11:17 -06:00
vicrodh 7831b07c30 feat(favorites): make tabs history-aware views and normalize order
cx
2026-01-19 11:11:03 -06:00
vicrodh f88cee7674 Fix sample rate change sync gap (all backends)
This is an integral fix that resolves the multi-second gap when changing
sample rates, without breaking bit-perfect modes (DAC Passthrough, ALSA Direct).

Root causes identified:
1. Missing ALSA Direct format change detection - stream wasn't recreated
2. Unnecessary CPAL device enumeration before backend system - added latency
3. Decoder started before stream fully initialized - seekbar advanced without audio

Changes made:
1. Added ALSA Direct to format change detection (line 773-775)
   - Stream now recreates on sample rate change for ALSA Direct
   - Maintains bit-perfect playback like DAC Passthrough

2. Restructured device initialization to skip CPAL enumeration (lines 798-893)
   - Backend system (PipeWire DAC, ALSA Direct) checked FIRST
   - CPAL enumeration only used as fallback for legacy path
   - Eliminates "Device 'hw:4,0' not found" warning for ALSA Direct

3. Added 50ms delay after stream creation (line 904-906)
   - Ensures stream is fully initialized before decoder starts
   - Prevents seekbar advancing without audio output
   - Small enough not to be noticeable, large enough to prevent gap

Testing needed:
- ALSA Direct: 192→96→192→44.1→48→88.2 kHz transitions
- PipeWire + DAC Passthrough: Same sample rate transitions
- System Default: Verify gapless still works
- Verify bit-perfect modes still work (no resampling)
2026-01-19 09:10:08 -06:00
vicrodh 311a2a7be1 Update badge status immediately when playback starts
Add effect that reloads audio settings and status when playback begins, ensuring DAC/EXC badges show correct state without requiring hover interaction.
2026-01-19 08:39:14 -06:00
vicrodh ff64e9e56a Fix track not showing as active after session restore
The current track is now marked as active even when paused, matching standard player behavior. This fixes the issue where after app restoration, the loaded track doesn't appear active until user interaction.

Changed: Remove isPlaybackActive condition from track active state logic in AlbumDetailView and PlaylistDetailView.
2026-01-19 08:39:14 -06:00
vicrodh 8b825856d2 UX improvements for ALSA Direct settings
1. Change hardware volume to visible help text (like Offline settings)
   - More critical info should be always visible
   - Clearer explanation of experimental nature

2. Add blue HW badge for ALSA Direct mode
   - Replaces DAC badge (mutually exclusive)
   - Blue color simulates audio equipment LED
   - Shows 'Hardware Direct: Bit-perfect ALSA' in tooltip
   - Displays device name and sample rate
   - Only visible when: ALSA Direct + hw plugin

3. Gapless logic already correct
   - Only restricts gapless with DAC Passthrough (PipeWire)
   - ALSA Direct can do gapless (same sample rate)
   - Note: Different sample rates need investigation
2026-01-19 08:35:15 -06:00
vicrodh 334a7a7e80 Fix hardware volume checkbox not appearing (case mismatch)
Backend returns 'hw (Direct Hardware)' (lowercase) but UI was comparing with 'Hw (Direct Hardware)' (uppercase). Fixed all occurrences to use lowercase.
2026-01-19 08:21:40 -06:00
vicrodh 45e6df49d5 Add UI for ALSA hardware volume control
- Add alsa_hardware_volume to AudioSettings interface
- Add Tauri command set_audio_alsa_hardware_volume
- Add checkbox in Settings (visible only for ALSA Direct + Hw plugin)
- Checkbox disabled by default for maximum compatibility
- Clear tooltip explaining experimental nature and risks
2026-01-19 04:08:44 -06:00
vicrodh ce72addd90 Fix database migration: remove alsa_hardware_volume from INSERT
User's existing database doesn't have the column yet, so INSERT fails.
Migration adds column after INSERT runs. Solution: only insert old columns.
2026-01-19 04:01:29 -06:00
vicrodh 61688bd1ea Integrate hardware volume control in PlaybackEngine
- Add hardware_volume parameter to PlaybackEngine::new_alsa_direct()
- Update all three call sites in player.rs to pass alsa_hardware_volume setting
- Implement conditional volume control: hardware mixer or DAC/amplifier
- Add device_id() getter to AlsaDirectStream for mixer access
- Hardware volume disabled by default for maximum compatibility
2026-01-19 03:59:28 -06:00
vicrodh c87b41894d Implement ALSA hardware mixer volume control
Added set_hardware_volume() to AlsaDirectStream:
- Tries common mixer control names (Master, PCM, Speaker, Headphone, Digital)
- Returns error if DAC doesn't support mixer (doesn't break playback)
- Stores device_id in struct for mixer access

This enables bit-perfect volume control via DAC hardware when supported.
Falls back gracefully if not supported.
2026-01-19 03:53:41 -06:00
vicrodh 31798432cb Fix database migration for alsa_hardware_volume column
PROBLEM: App crashed on startup with existing databases:
'table audio_settings has no column named alsa_hardware_volume'

CAUSE: ALTER TABLE with 'NOT NULL' constraint fails on SQLite migrations.

FIX:
- Removed NOT NULL from ALTER TABLE statement
- Handle NULL values with unwrap_or(0) in get_settings()
- Defaults to false (disabled) for old databases

Now works with both new and existing databases.
2026-01-19 03:52:01 -06:00
vicrodh 7177f248c9 Add alsa_hardware_volume setting (disabled by default)
Preparation for hybrid volume control (B+C option):
- New field: alsa_hardware_volume: bool (default: false)
- Database schema updated with migration support
- Setter/getter methods added

When enabled, will attempt to control DAC volume via ALSA mixer.
When disabled (default), in-app volume control is disabled for maximum
compatibility (user controls volume on DAC/amplifier).
2026-01-19 03:50:02 -06:00
vicrodh c7a3737fb5 Implement automatic format detection for ALSA Direct
PROBLEM: Hardcoding S32_LE only worked for Cambridge Audio DAC, not generic.

SOLUTION: Auto-detect best format at runtime:
- Try formats in priority order: FloatLE > S32LE > S24LE > S16LE
- Store detected format in AlsaDirectStream struct
- write() auto-converts from i16 based on detected format:
  * FloatLE: i16 -> f32 (normalize to -1.0..1.0)
  * S32LE: i16 -> i32 (bit-perfect: shift left 16 bits)
  * S16LE: i16 -> i16 (no conversion)

Now works with any DAC regardless of supported formats.
2026-01-19 03:38:28 -06:00
vicrodh dc9c7d0424 Fix format compatibility: use S32_LE instead of FloatLE
PROBLEM: Cambridge Audio DAC only supports S32_LE format, not FloatLE.
Previous code failed with 'Invalid argument (22)' when trying to set FloatLE.

SOLUTION:
- alsa_direct.rs: Changed format from FloatLE to S32_LE
- alsa_direct.rs: Changed write() to accept i32 samples instead of f32
- playback_engine.rs: Convert i16 to i32 using bit-perfect left shift:
  i32 = (i16 as i32) << 16

This maintains full bit-perfect precision while using hardware-supported format.
2026-01-19 03:35:43 -06:00
vicrodh dd03bcd09e Fix ALSA Direct streaming: process chunks instead of buffering entire file
PROBLEM: Original code tried to collect() entire audio source into memory
before playback, causing 600+ MB allocations for 192kHz tracks and silent
failures.

SOLUTION: Stream samples in 8192-frame chunks:
- Read chunk from source iterator
- Convert i16 to f32
- Write to ALSA immediately
- Repeat until end of stream

This reduces memory usage from 600+ MB to ~300 KB per chunk and fixes
the no-audio issue.
2026-01-19 03:28:42 -06:00
vicrodh 192b7e75e2 Complete PlaybackEngine integration with hybrid Rodio/ALSA Direct support
- Replace Sink with PlaybackEngine abstraction throughout player
- Update StreamType to use Arc<AlsaDirectStream> for sharing
- Adapt all player commands (Play, Pause, Resume, Seek, Stop, SetVolume, ReinitDevice)
- Add as_any() trait method for backend downcasting
- Fix all type mismatches and compilation errors
- Compilation successful with 0 errors, 30 warnings
2026-01-19 03:14:27 -06:00
vicrodh 63d3e8c043 WIP: Add PlaybackEngine abstraction and StreamType enum
- Create playback_engine.rs module wrapping Sink and AlsaDirectStream
- Add StreamType enum (Rodio or AlsaDirect)
- Modify try_init_stream_with_backend() to detect hw: devices
- Update player thread types (stream_opt, current_engine)

Next: Complete player.rs integration (extensive changes needed)
Status: Does not compile yet - work in progress
2026-01-19 02:51:48 -06:00
vicrodh f88de797ad Implement direct ALSA access with alsa-rs for hw: devices
- Create AlsaDirectStream module for bit-perfect PCM access
- Bypasses CPAL/rodio for hw:X,Y and plughw:X,Y devices
- Add try_create_direct_stream() method to AlsaBackend
- Configures optimal buffer sizes for high-res audio (500ms for 192kHz)
- Handles PCM errors with automatic recovery

Next: Integrate with player audio thread
2026-01-19 02:44:31 -06:00
vicrodh b82abb145b fix: resolve Favorites tab navigation circular bug and prevent user clicks from triggering nav effect
cx
2026-01-18 16:32:13 -06:00
vicrodh 9c45a82fd8 fix(favorites): add debug logging for preferences loading
cp
2026-01-18 16:21:36 -06:00
vicrodh e752791d3a fix: correct async loading of favorites preferences and tab order
- Remove await from onMount (not async)
- Use .then() chain for proper async handling
- Initialize activeTab from preferences on mount
- Fixes tab order not persisting
- Fixes custom icon not displaying

cx
2026-01-18 16:17:30 -06:00
vicrodh 5e60de9970 fix(phase4): await favorites preferences load to preserve tab order
cp
2026-01-18 16:07:56 -06:00
vicrodh 4a6f09d5b9 fix(favorites): restore tab navigation functionality
Removed continuous  sync that was overriding user tab clicks.
Now only syncs activeTab with currentTab on initial mount to respect
configured first tab, then allows normal tab navigation.

cp
2026-01-18 16:02:10 -06:00
vicrodh ffb16656e7 feat(phase4.7): implement history-aware favorites tab navigation
- Extended navigationStore with FavoritesTab state tracking
- Added setFavoritesTab() to push tab changes to history
- Modified navigateTo() to support favorites sub-navigation
- Wired handleTabChange() to call setFavoritesTab()
- Synced activeTab with navigation store via currentTab prop
- Back button now returns to correct Favorites tab

cp
2026-01-18 15:52:31 -06:00
vicrodh 902705f47f fix(phase4): add icon_background column migration for existing databases
- Detect missing icon_background column in favorites_preferences table
- Add ALTER TABLE migration to preserve existing user data
- Apply migration in both FavoritesPreferencesStore::new() and create_table()

cx
2026-01-18 15:42:11 -06:00
vicrodh ad73b5d879 fix(phase4): adjust sticky nav top position to reach window edge
- Change top from 0 to -24px to account for container padding
- Ensures nav bar reaches top edge when scrolling
- clearCurrentSearch already collapses search correctly

cp
2026-01-18 15:31:44 -06:00
vicrodh 92486c3943 fix(phase4): sticky nav reaches top edge and search collapses on clear
- Remove negative top margin from .favorites-nav (was -24px, now 0)
- Update clearCurrentSearch() to collapse search when cleared
- Add hover state to clear button for better UX

cp
2026-01-18 15:28:07 -06:00
vicrodh a45806e4c4 fix(phase4): sticky nav now reaches top edge when scrolling
- Adjusted negative margins to cancel parent padding
- Matches Artist page sticky behavior
- Nav bar now fully sticks to window top

cp
2026-01-18 15:20:40 -06:00
vicrodh 88e0ef8e01 feat(phase4.5): implement Artist-style navigation bar
- Replaced button-style tabs with underlined navigation links
- Sticky navigation bar on scroll (top: 0, z-index: 4)
- Integrated searchbar in nav-right (icon → expandable input)
- Tab order respects user preferences (favoritesPreferences.tab_order)
- Active tab shows accent-colored bottom border (2px)
- Removed redundant search container section
- Matches Artist page and Settings page nav styles

cp
2026-01-18 15:12:58 -06:00
vicrodh 9269458d77 feat(phase4): add helper functions for tab navigation and search
- Added getCurrentSearchValue(), setCurrentSearchValue(), clearCurrentSearch()
- Added getTabIcon() and getTabLabel() helpers
- Added tabLabels constant
- Added searchExpanded state for collapsible search
- Preparation for Artist-style navigation bar (Phase 4.5)

cp
2026-01-18 15:11:42 -06:00
vicrodh 64bd4d729e feat(phase4.4): wire custom icon and background display
- Dynamic icon rendering (preset + custom upload)
- Background color/gradient applied to header icon
- Support for all preset icons (heart, star, music, folder, disc, library)
- Custom uploaded image display via asset protocol

cp
2026-01-18 15:08:44 -06:00
vicrodh 76c9a9653e feat(phase4.3): add custom gradient picker with 2-3 color support
- Expanded preset gradients (sunset, ocean, fire, mint, candy, forest)
- Added custom gradient builder (2-3 colors)
- Interactive color picker with add/remove controls
- Apply/Cancel actions for custom gradients

cp
2026-01-18 15:07:21 -06:00
vicrodh 3039cb5d37 fix(phase4.3): expand color grid to 12 columns with additional colors
- Add 3 more solid colors (cyan, rose, slate) for total of 11 solids
- Keep only sunset gradient (1 gradient)
- Change grid from 8 to 12 columns
- Ensures all colors fit in single row

cp
2026-01-18 15:02:28 -06:00
vicrodh df50eb1c8f fix(ui): reduce color grid gap to 2px
cp
2026-01-18 14:46:11 -06:00
vicrodh 2f163f36f5 fix(phase4.3): adjust modal centering and color swatch sizes
- Reduce modal width from 920px to 736px (80% of original)
- Center modal with 140px left offset (half sidebar width)
- Reduce color swatches from 40px to 30px
- Reduce color-grid gap from 8px to 4px
- Fix icon-preset button justify-content typo
- Swatches now properly fill single row

cp
2026-01-18 14:44:29 -06:00
vicrodh cdc4435306 fix(phase4.3): adjust modal width to 920px and limit color swatches to 40x40
- Reduce modal width by 20% (1150px → 920px)
- Add max-width/max-height constraints to color buttons (40px)
- Maintain aspect ratio and grid layout

cp
2026-01-18 14:37:56 -06:00
vicrodh 8607729013 fix(ui): adjust modal layout - 65/35 column split, smaller color swatches
- Changed modal columns from 50/50 to 65/35 split
- Reduced color picker grid gaps and increased density (8 columns)
- Adjusted color swatch border radius for consistency

cp
2026-01-18 14:19:51 -06:00
vicrodh 4009ae9b26 feat(phase4.3): add background color picker to favorites modal
- Add icon_background field to backend (Rust + TS types)
- Update modal to 60% wider (1150px)
- Implement two-column layout (icon left, tabs right)
- Add solid color picker (8 colors + none)
- Add gradient picker (6 gradients)
- Remove background from edit button to match PlaylistView style
- Update database migration for icon_background field

cp
2026-01-18 14:13:50 -06:00
vicrodh dddae17d63 Re-enable ALSA Direct backend for testing
- Remove filter from backend selector dropdown
- Remove auto-switch logic from ALSA Direct to Auto
- Allow user to test if CPAL can actually open hw: devices
- If this works, we can skip alsa-rs implementation
- If it fails, we'll need to implement direct alsa-rs approach
2026-01-18 14:06:32 -06:00
vicrodh 9c76792741 Add alsa crate for direct ALSA hardware access
- Add alsa 0.9 as Linux-only dependency
- Will replace CPAL-based ALSA backend with direct alsa-rs implementation
- Required to properly access hw:X,Y devices for bit-perfect playback
2026-01-18 14:02:43 -06:00
vicrodh 5bd52cc89b feat(phase4.3): add favorites edit modal component
- Create FavoritesEditModal with preset icon grid
- Add custom image upload button
- Add tab reorder UI with up/down buttons
- Integrate edit button in Favorites page header (top-right)
- Add i18n keys for EN and ES
- Wire modal save handler to backend

cc
2026-01-18 14:02:37 -06:00
vicrodh a6aa6aa936 feat(phase4.2): add favorites preferences backend
- Create favorites_preferences.rs with FavoritesPreferences struct
- Add database table (custom_icon_path, custom_icon_preset, tab_order)
- Implement State wrapper and Tauri commands
- Register state and commands in lib.rs
- Default preset: heart, default order: tracks/albums/artists/playlists

cc
2026-01-18 13:57:17 -06:00
vicrodh d39180bd6c feat(ui): show playing status in search and artist tracks
cx
2026-01-18 05:46:57 -06:00
vicrodh c6f86a9bcc feat(ui): pause from track row playing icon
cx
2026-01-18 05:46:43 -06:00
vicrodh 407fab44db fix(ui): slow album card ticker speed
cx
2026-01-18 05:38:41 -06:00
vicrodh ed45fa4156 feat(ui): show volume value while dragging
cx
2026-01-18 05:38:32 -06:00
vicrodh 5a42df35a4 fix(ui): lock playlist import button after success
cx
2026-01-18 05:38:22 -06:00
vicrodh c67c479bac fix(ui): wire stack icon click and tooltip
cx
2026-01-18 05:33:00 -06:00
vicrodh c2628b0076 fix(config): align autoplay mode serialization
cx
2026-01-18 05:32:49 -06:00
vicrodh d96233730b fix(phase3): custom tooltip for context icon
- Replace native title with custom tooltip similar to DAC/EXC badges
- Add hover state and styled tooltip with context info
- Add debug logs to investigate onClick callback issue

cp
2026-01-18 04:58:35 -06:00
vicrodh 12067d7a61 fix(phase3): context navigation and autoplay persistence
- Fixed context navigation using correct property names (.type, .id)
- Simplified autoplay setting from radio buttons to toggle switch
- Fixed tooltip using native title attribute (like QualityBadge)
- Removed custom tooltip CSS and hover state
- Updated translations (en/es) for clearer autoplay behavior description

cp
2026-01-18 04:53:43 -06:00
vicrodh 315bdce79c fix(settings): reload playback preferences when view renders
- Added $effect to reload preferences each time SettingsView is visible
- Fixes autoplay mode not persisting when navigating away and back
- Settings view doesn't unmount, so onMount only runs once per session

cp
2026-01-18 04:38:15 -06:00
vicrodh b666722b98 debug: add detailed logging to loadPlaybackPreferences
cp
2026-01-18 04:34:54 -06:00
vicrodh 92f1644601 fix(context): add custom tooltip and pass onClick callback
- Implemented custom tooltip for StackIcon (similar to AudioOutputBadges)
- Shows 'Playing from', context name, and 'Click to navigate' hint
- Added onContextClick={handleContextNavigation} to ExpandedPlayer
- Fixed onClick prop not being passed, enabling navigation

cp
2026-01-18 04:34:42 -06:00
vicrodh 0feb1e1b4a debug: add detailed logging to StackIcon click handler
cp
2026-01-18 04:09:31 -06:00
vicrodh ae3a90d378 fix(i18n): add translations for playback preferences
Added translations for:
- Autoplay behavior setting
- Continue within source / Play only selected track options
- Show context icon setting and tooltip

Both English and Spanish translations added.

Changed StackIcon tooltip to use native browser title (matches QualityBadge style).
Removed arrow indicator from context icon (cursor change is sufficient).

cp
2026-01-18 04:09:20 -06:00
vicrodh 2a4f58cb08 fix(css): remove extra closing brace in ExpandedPlayer styles
Syntax error on line 568 - duplicate closing brace after .album rule

cp
2026-01-18 04:00:25 -06:00
vicrodh fdf288b01e fix(migration): robust database migration for show_context_icon
Problem:
- Users updating from previous versions would crash on startup
- Table created with new column caused "no column named show_context_icon" error
- Existing users had old schema without the column

Solution:
- Step 1: Create table with old schema (backwards compatible)
- Step 2: Check if show_context_icon column exists using pragma_table_info
- Step 3: Add column ONLY if it doesn't exist (safe migration)
- Step 4: Insert default row

This ensures:
✅ New installs work (table created fresh)
✅ Existing users migrate seamlessly (column added, settings preserved)
✅ No data loss
✅ Idempotent (can run multiple times safely)

Tested scenarios:
- Fresh install (no DB) → creates table, adds column, inserts defaults
  Result: id=1, autoplay_mode='continue', show_context_icon=1
- Existing DB without column → adds column, preserves user settings
  Result: id=1, autoplay_mode='track_only' (preserved), show_context_icon=1
- Existing DB with column → no changes (idempotent)

Migration logs added for debugging.

cp
2026-01-18 03:57:28 -06:00
vicrodh 584650fee1 feat(phase37): implement clickable context tooltip navigation
StackIcon Component:
- Now accepts onClick prop
- Changed from div to button element
- Added arrow (→) that appears on hover
- Tooltip text changed to "Click to go to: {source}"
- Visual feedback: hover background + active scale

Navigation Logic (+page.svelte):
- Added handleContextNavigation function
- Switch based on context_type:
  - album → handleAlbumClick
  - playlist → navigate + set selectedPlaylistId
  - artist_top → handleArtistClick
  - favorites → navigate to favorites
  - home_list → navigate to home
  - search → navigate to search
- Import getCurrentContext from playbackContextStore

UI Integration:
- ExpandedPlayer: Added onContextClick prop, passed to StackIcon
- FocusMode: Added onContextClick prop, passed to StackIcon
- Both receive handleContextNavigation callback

Phase 3.7 COMPLETE ✅

cp
2026-01-18 03:47:11 -06:00
vicrodh b070884ee8 feat(phase36): implement context icon visibility toggle (frontend + UI)
Frontend:
- Add show_context_icon to PlaybackPreferences interface
- Add setShowContextIcon function to store
- StackIcon now subscribes to preferences and checks show_context_icon
- Icon hidden when setting is false (context still tracked)

UI (Settings → Playback):
- Add toggle: "Show track playing context in player"
- Tooltip with bilingual explanation (EN/ES)
- Default: enabled (true)
- Persists across restarts

Context tracking ALWAYS active regardless of icon visibility.

Phase 3.6 COMPLETE ✅

cp
2026-01-18 03:40:19 -06:00
vicrodh dfd1eb588d feat(phase36): add show_context_icon setting (backend)
Database:
- Add show_context_icon column (INTEGER, default 1)
- Migration for existing databases

Backend:
- Add show_context_icon to PlaybackPreferences struct
- Default value: true (icon visible)
- Add set_show_context_icon method to store/state
- Add Tauri command: set_show_context_icon

Context tracking remains ALWAYS active regardless of icon visibility.

cp
2026-01-18 03:38:14 -06:00
vicrodh 640cf5db41 feat(phase35): implement context in HomeView
Context creation:
- Creates 'home_list' context for Continue Listening section
- Uses 'continue_listening' as ID and 'Continue Listening' as label
- Tracks user's listening history in a context
- Stack icon will show "Playing from: Continue Listening"

Home view now fully integrated with context system.

cp
2026-01-18 03:34:50 -06:00
vicrodh a473c969d9 feat(phase35): implement context in SearchView
Context creation:
- Creates 'search' context when playing track from results
- Uses search query as ID and 'Search: {query}' as label
- Applies to both All tab (first 6) and Tracks tab (full list)
- Stack icon will show "Playing from: Search · {query}"

Search view now fully integrated with context system.

cp
2026-01-18 03:33:23 -06:00
vicrodh e3ce6a3760 feat(phase35): implement context in FavoritesView
Context creation:
- Creates 'favorites' context when playing track
- Uses 'favorites' as ID and 'Favorites' as label
- Uses filteredTracks for context (respects search/filter)
- Stack icon will show "Playing from: Favorites"

Favorites view now fully integrated with context system.

cp
2026-01-18 03:31:25 -06:00
vicrodh 0bd60bbc8f feat(phase35): implement context in ArtistDetailView
Context creation:
- Creates 'artist_top' context when playing from Top Tracks
- Uses artist ID and name
- Passes track index from UI loop
- Stack icon will show "Playing from: Artist · {name}"

Artist view now fully integrated with context system.

cp
2026-01-18 03:30:47 -06:00