Files
qbz/crates/Cargo.toml
T
vicrodh 8ba9483462 feat(qt): HiFi Wizard — guided DAC setup ported from Slint
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
2026-08-11 11:26:50 -06:00

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" }