Replace binary blur toggle with a 3-option dropdown. Full mode uses
the existing WebGL2 shader, Lite mode renders a pre-blurred static
image animated with CSS transforms (compositor-driven, immune to
Wayland frame callback stutter), and Off mode shows a solid color.
Includes config migration from disableBlurBackground to backgroundMode,
updated composition profiles, and i18n for all 4 locales.
Closes#127
Detect when QBZ runs inside a Snap sandbox (via SNAP env var) and show
a one-time welcome modal with required plug connection commands. Adds a
Snap Sandbox section in Settings with copyable commands, mirroring the
existing Flatpak pattern.
Backend: snap.rs module, DB table snap_welcome_shown, V2 commands.
Frontend: updatesService, +page.svelte modal queue, SettingsView section.
The packaging/snap/ copy already had the mpris plug but the root
snapcraft.yaml was missing it, preventing MPRIS media controls
from working in the Snap package.
When typing in the search bar, new results cause the virtual scroll
container to remount. The ResizeObserver was stale (watching the old
destroyed element) and containerWidth reset to 0, causing gridCols
to default to 1. Two fixes: cache the last known column count so
width=0 uses the previous layout, and reconnect the ResizeObserver
whenever the container element changes.
First Escape clears the search text, second Escape when input is
already empty removes focus from the input. Applied to both the
sidebar and titlebar search inputs for keyboard-driven navigation.
The CheckSquare button was next to the search bar instead of in the
header actions alongside Play/Shuffle/Save, inconsistent with DailyQ,
FavQ and TopQ views. Moved it to the header and removed orphaned CSS.
The broken views called onTrackAddToPlaylist in a loop (once per
selected track), causing each call to overwrite the previous track
IDs in the playlist modal. Only the last track survived. Now all 6
views collect IDs first and call onBulkAddToPlaylist once with the
full array.
Views fixed: ArtistDetailView, AlbumDetailView, LabelView,
FavoritesView, WeeklySuggestView, PlaylistDetailView.
v2_purchases_get_all and v2_purchases_get_by_type only set the
downloaded boolean but never populated downloaded_format_ids, so
check marks disappeared after app restart. Now both use
get_downloaded_purchase_formats() and build the format map, matching
the behavior already present in v2_purchases_get_album.
Fixes#119
When downloading a purchased album to ~/Music, the "Add to Local
Library" button was adding ~/Music (the entire music directory) instead
of the specific album folder like ~/Music/Artist/Album/.
After the first track downloads, extract the album-level folder from
the returned file path and update the stored destination. This ensures
only the downloaded album gets added to the library. Fixes#117.
The library scanner's album_root_dir() only knew to skip disc folders
(Disc 1, CD2, etc.) when resolving the album directory. Files stored
in quality subfolders like artist/album/FLAC 24-bit - 96 kHz/track.flac
caused each encoding variant to appear as a separate album card.
Add is_encoding_folder() to detect common audio format directory names
(FLAC, MP3, AAC, WAV, etc.) and make album_root_dir() skip past both
encoding and disc subdirectories, handling chained nesting too.
Fixes the workaround from #116.
Allow users to cancel an in-progress album download. The current track
finishes but no further tracks are started. A cancel button appears in
the progress bar during download, and a cancelled state shows how many
tracks completed. Closes#133.
Switch from CSS grid to CSS multi-column layout so categories pack
tightly top-to-bottom instead of creating large empty rows when
columns have uneven heights.
Add Shift+M toggle shortcut for mini player mode (main and mini window).
Add 1-5 number keys for surface switching (micro/compact/artwork/queue/lyrics)
in mini player context. Add playback shortcuts (Space, Ctrl+Arrow) to mini
player window. Fix X button to close app (or hide to tray) instead of
duplicating the Expand button behavior. Closes#134.
Previous shader was too subtle — drift, rotation, and breathing were
imperceptible with the smooth 8x8 texture. Now with much larger values:
- Drift: 0.05 -> 0.20 max (Lissajous with two frequencies)
- Scale breathing: 2% -> 12% range
- Rotation: 0.86deg -> 5deg range
- Added warm/cool color shifting over time
- Stronger vignette pulsing and brightness breathing
Safe because the 8x8-sourced texture has zero structure to reveal.
CSS filter:blur() may not work reliably in all WebView environments,
leaving artwork structure visible as rectangular artifacts. New
approach: draw the full artwork at 8x8 resolution (64 pixels) where
no structure can physically survive, then scale up to 128x128 with
high-quality bilinear smoothing. One optional blur pass for polish.
The 3-layer parallax shader created visible rectangular artifacts on
dark/uniform artwork. Each layer sampled at different scale/offset,
and the spatial weighting transitions between layers showed as
geometric seams regardless of offset magnitude.
New shader uses a single texture sample with organic Lissajous drift,
gentle rotation, scale breathing, pulsing vignette, and vertical tint.
The pre-blurred texture handles the visual complexity — the shader
just adds subtle life without geometric artifacts.
Two issues caused visible dark rectangles on simple/dark artwork:
1. Texture normalization always mapped to [30-240] regardless of source
brightness. For dark artwork (Metallica), this amplified noise 5x and
turned a dark album into a light gray background. Now uses
brightness-aware blending: dark artwork gets gentle lift (preserves
mood), colorful artwork gets full normalization.
2. Shader layer offsets were too large (up to 20% of texture), causing
visible layer boundaries where each sampling layer showed different
parts of the amplified texture. Reduced offsets by ~60% and tightened
scale ranges for smoother parallax.
CLAMP_TO_EDGE stretched edge pixels when ambient shader UVs exceeded
[0,1] range, creating visible dark rectangles on simple/dark artwork
(e.g. Metallica's black album). MIRRORED_REPEAT seamlessly mirrors
the texture instead. Also removed the hard clamp() in the fragment
shader so the mirrored wrapping actually takes effect.
Group immersive-related settings under a new "Immersive" subsection
at the bottom of Settings > Appearance, in order:
1. Immersive Default View
2. Composition (collapsible)
3. Disable Blur Background
4. Animation Frame Rate (collapsible)
Also fix chevron alignment in collapsible sections to be right-aligned
(justify-content: space-between) and clean up unused CSS classes.
- Replace native <select> with Dropdown component for GSK renderer
- Fix collapsible section layout: title+chevron on one row, description below
- Apply section-title-row wrapper to both Animation Frame Rate and Composition
- Add divider between Animation Frame Rate and Mini Player Default View
- Remove unused .composition-select CSS
- Replace raw checkbox with Toggle component for blur background
- Use composition-subsection class for FPS section (adds top border)
- Use composition-title class for consistent 14px font size
- Move desc to section-note inside expanded content
- Add summary key for inline collapsed text
- Shorten title from "Immersive Animation Frame Rate" to
"Animation Frame Rate"
Replace raw text caret and h4 with the standard section-title +
section-summary + ChevronDown/Up icon pattern used by the composition
section. Remove duplicate description that now shows as summary.
Add gskRenderer and disableBlurBackground fields to CompositionProfile.
Update existing profiles: Xwayland Performance now disables blur.
Add new Max Performance profile (Cairo software renderer + blur off)
for maximum compatibility on stutter-affected systems.
Profile matching and apply logic now includes all new fields.
Part of #127.
Detects GPU (NVIDIA/AMD/Intel), display server (Wayland/X11), desktop
environment, and VM status. Computes optimal configuration based on a
decision matrix and writes it to the graphics settings DB.
Usage: qbz --autoconfig-graphics
Part of #127.
When enabled, replaces the expensive blurred album artwork background
with a solid dark color extracted from the artwork at tiny resolution.
Significantly reduces GPU load and fixes stutter on affected systems.
Setting is stored in localStorage (same as FPS settings) and applies
on next immersive mode entry.
Part of #127.
Add gsk_renderer field to graphics settings DB with UI dropdown
(Auto/GL/NGL/Vulkan/Cairo). Value is read at startup and set as
GSK_RENDERER env var. Env var override takes precedence. Also
included in --reset-graphics and reset now restores hw_accel to true.
Part of #127.
Add is_amd_gpu() and is_intel_gpu() detection functions alongside
existing is_nvidia_gpu(). Update GraphicsStartupStatus to expose
has_amd and has_intel to frontend. Log detected GPUs at startup.
Part of #127.
The hardware_acceleration toggle in settings was dead code — stored in
DB but ignored at startup (main.rs only checked QBZ_HARDWARE_ACCEL env
var). Now the DB value is read as the default, with env var override.
Fixes part of #127.