Six-step modal (Welcome / Check / DACs / Configure / Test / Done) opened from Settings > Audio. It probes the audio stack and renders per-distro remediations, enumerates DACs with a manual node.name escape hatch, generates the PipeWire / WirePlumber snippets to copy, and plays four tracks spanning 16/44.1 to 24/192 with a live requested-vs-negotiated read-back. Read-only: it never writes a system file or runs a command. The logic was unreachable from Qt — every public function in qbz-dac-wizard takes a &AppWindow and writes straight into Slint globals. It is lifted into a new frontend-agnostic crate, qbz-dac-wizard-core, which returns plain data. qbz-dac-wizard itself is left untouched. Rust owns everything it computes plus `open`, so the reset and the probe are one act; QML owns the step navigation and the four progress checkboxes, which is how the reference splits them too. Two deliberate divergences from the reference: the row sits at the end of OUTPUT rather than BIT-PERFECT, and it is offered on every backend instead of PipeWire only — someone on ALSA direct is exactly who needs the walkthrough. The green glyphs use the accent tint, not success: success has no qrc bake directory, so a degraded tint set would render nothing at all. Every success-toned text keeps theme.success (#3fae6a verbatim). Verified by 309 tests, both QML audits and the offscreen smoke, plus a forced-route probe that mounts Settings and walks the wizard's steps — the standard smoke only mounts Home, so it is no evidence for a modal. The modal was also driven and screenshotted over VNC. cc
168 lines
6.5 KiB
TOML
168 lines
6.5 KiB
TOML
[workspace]
|
|
resolver = "2"
|
|
|
|
members = [
|
|
"qbz-app",
|
|
"qbz-theme",
|
|
"qbz-models",
|
|
"qbz-audio",
|
|
"qbz-player",
|
|
"qbz-qobuz",
|
|
"qbz-radio",
|
|
"qbz-core",
|
|
"qbz-integrations",
|
|
"qbz-cache",
|
|
"qbz-library",
|
|
"qbz-cast",
|
|
"qbz-cmaf",
|
|
"qbz-dsd",
|
|
"qbz-secrets",
|
|
"qbz-offline-cache",
|
|
"qbz-plex",
|
|
"qconnect-core",
|
|
"qconnect-protocol",
|
|
"qconnect-transport-ws",
|
|
"qconnect-app",
|
|
"qbz-ui",
|
|
# The HiFi Wizard's frontend-agnostic core (ADR-006), extracted for the Qt
|
|
# port. `qbz-dac-wizard` is the SLINT one and is deliberately NOT wired to
|
|
# this crate: the Slint tree is frozen (owner, 2026-08-11 — "ya no hacemos
|
|
# cambios para Slint"), and rewiring it would have been a change to a tree
|
|
# nobody compiles or tests any more. The two therefore hold the same logic
|
|
# twice; that is safe only BECAUSE the Slint side is frozen, and it is the
|
|
# reason a fix here never needs porting back.
|
|
"qbz-dac-wizard-core",
|
|
"qbz-dac-wizard",
|
|
"qbz-text-utils",
|
|
"qbz-slint-common",
|
|
"qbz",
|
|
"qbz-credentials",
|
|
"qbz-media-controls",
|
|
"qbz-mixtape",
|
|
"qbz-playlist-import",
|
|
"qbz-lyrics",
|
|
"qbz-i18n",
|
|
"qbz-music-link",
|
|
"qbz-reco",
|
|
"qbz-external-reco",
|
|
"qbz-log",
|
|
"qbzd",
|
|
"qbz-qt",
|
|
# The source-agnostic seam (one trait + one registry over Qobuz / local /
|
|
# Plex). Purely additive: nothing in `qbz` or `qbz-mixtape` changes, and it
|
|
# deliberately does NOT depend on qbz-audio / qbz-player.
|
|
"qbz-source",
|
|
]
|
|
|
|
# Qt-frontend POC worktree: plain `cargo build`/`cargo check` in this workspace
|
|
# produces ONLY the Qt binary (plus its Slint-free dependency closure). The
|
|
# Slint crates remain members but are never built by default here.
|
|
default-members = ["qbz-qt"]
|
|
|
|
[workspace.package]
|
|
version = "2.0.2"
|
|
edition = "2021"
|
|
license = "MIT"
|
|
repository = "https://github.com/vicrodh/qbz"
|
|
|
|
[workspace.dependencies]
|
|
# Async runtime
|
|
tokio = { version = "1", features = ["full"] }
|
|
async-trait = "0.1"
|
|
futures-util = "0.3"
|
|
tokio-stream = { version = "0.1", features = ["sync"] }
|
|
|
|
# Serialization
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
|
|
# HTTP
|
|
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls-webpki-roots-no-provider", "cookies", "stream"] }
|
|
|
|
# Logging
|
|
log = "0.4"
|
|
tracing = "0.1"
|
|
|
|
# Error handling
|
|
thiserror = "2"
|
|
anyhow = "1"
|
|
|
|
# Crypto (Qobuz auth)
|
|
md-5 = "0.10"
|
|
base64 = "0.22"
|
|
|
|
# Time
|
|
chrono = "0.4"
|
|
|
|
# Regex
|
|
regex = "1"
|
|
|
|
# Audio
|
|
symphonia = { version = "0.5", features = ["all"] }
|
|
|
|
# Random number generation (shuffle / DJ-mix) — mirrors src-tauri pin
|
|
rand = "0.10"
|
|
|
|
# Fuzzy string similarity (track-mix dedup) — mirrors src-tauri pin
|
|
strsim = "0.11"
|
|
|
|
# Note: Linux-specific dependencies (alsa) go in individual crate Cargo.toml files
|
|
# because workspace manifests cannot have [target] sections
|
|
|
|
[profile.release]
|
|
# Strip symbol tables from release binaries. Measured on 2026-07-02:
|
|
# 400 MB -> 218 MB (-45%). There are no .debug_* sections in a default
|
|
# release build — the weight is .strtab (151 MB) + .symtab (22 MB), inflated
|
|
# by Slint's generated generic symbol names. Trade-off: panic backtraces show
|
|
# addresses instead of names; the release workflow archives the UNSTRIPPED
|
|
# binary as an Actions artifact per tag for offline symbolication.
|
|
# Codegen knobs (opt-level / codegen-units / jobs) intentionally stay in the
|
|
# workflows' env (CARGO_PROFILE_RELEASE_*) — they are CI-memory tuning, not
|
|
# a property of the package.
|
|
strip = "symbols"
|
|
|
|
[patch.crates-io]
|
|
# Slint 1.16's femtovg-wgpu renderer leaves the wgpu surface alpha mode at
|
|
# `Auto`, which resolves as an opaque compositor surface on KWin/Wayland and
|
|
# makes borderless transparent windows show a black rectangular backing. The
|
|
# patch keeps Slint pinned but chooses a supported non-opaque composite alpha
|
|
# mode when the surface advertises one, so the miniplayer card can have real
|
|
# transparent rounded corners. The non-opaque mode is PER-WINDOW opt-in
|
|
# (`wgpu::set_surface_prefers_transparent`, flipped from qbz's winit
|
|
# window-attributes hook): only the miniplayer pays the compositor-blend cost,
|
|
# the main window keeps an Opaque swapchain.
|
|
i-slint-renderer-femtovg = { path = "vendor/i-slint-renderer-femtovg-1.16.1" }
|
|
# On modern macOS, fontique's CoreText per-script fallback can fail to resolve
|
|
# a Han-script family (the suggested PingFang is not always in the scanned
|
|
# family map), so Japanese kanji rendered blank while kana worked. The patch
|
|
# pre-registers the known system CJK families (Hiragino/PingFang/Apple SD
|
|
# Gothic Neo/Arial Unicode MS, Japanese-biased default) in the fallback map at
|
|
# collection creation, which takes priority over the CoreText query. macOS-only
|
|
# (#[cfg]); Linux keeps its working fontconfig fallback.
|
|
i-slint-common = { path = "vendor/i-slint-common-1.16.1" }
|
|
# With `overflow: elide`, sharedparley culled EVERY line whose bottom edge
|
|
# exceeded max_height — including the FIRST one, eliding the text to nothing.
|
|
# CJK fallback fonts (Hiragino on macOS) report line metrics taller than
|
|
# snug fixed-height boxes (TrackRow's 20px title line at 14px), so every
|
|
# CJK track title rendered blank on macOS while Latin fit (#543; verified
|
|
# with a headless repro matrix on the Mac Mini). The patch always draws the
|
|
# first line — it still gets the ellipsis treatment as the last visible one.
|
|
i-slint-core = { path = "vendor/i-slint-core-1.16.1" }
|
|
# Slint compiles femtovg with the swash raster path. Swash fails to scale
|
|
# some variable fonts at a non-default variation instance (the CFF2-based
|
|
# CJK system fonts on modern macOS), and femtovg cached those glyphs as
|
|
# permanently missing — so CJK text at any non-regular weight rendered
|
|
# blank (#543; regular weight = empty coords = renders fine). The patch
|
|
# retries the glyph at the font's DEFAULT instance before giving up: worst
|
|
# case the glyph draws at regular weight instead of not at all. No effect
|
|
# on fonts/instances that already render.
|
|
femtovg = { path = "vendor/femtovg-0.23.2" }
|
|
# macOS Skia renderer: skia bug 310510989 makes new_from_data fail for TTC
|
|
# faces at index > 0, and for some system collections (AppleSDGothicNeo.ttc,
|
|
# where EVERY weight sits at index > 0) the upstream read/write-fonts rebuild
|
|
# workaround ALSO fails — every Korean glyph run at non-regular weights drew
|
|
# nothing. The patch adds a second-chance workaround: resolve the same face
|
|
# through CoreText by family name + OS/2 weight, guarded by cmap glyph-id
|
|
# spot checks so a wrong match is rejected instead of drawing wrong glyphs.
|
|
i-slint-renderer-skia = { path = "vendor/i-slint-renderer-skia-1.16.1" }
|