feat(qt): port Qobuz Connect — service, flyout, routing and touchpoints

Full-parity port of the Slint QConnect integration per the contract at
qbz-nix-docs/qt-frontend/2026-08-01-qconnect-port/00-CONTRACT.md (three
adversarial review rounds on the spec, §12 trap sign-off PASS on both
halves, RFB-verified incl. a real cloud connect, live session
owner-tested). The shared crates are consumed verbatim — zero backend
changes.

- adapter quartet: qconnect_transport_qt (credentials, identity on the
  shared qconnect_settings.db), qconnect_engine_qt (start_track_stream
  fallback chain + feeder helpers + CMAF cursor sync),
  qconnect_event_sink_qt, qconnect_qt (the facade: connect/disconnect
  recipe, controller routing, echo guards, offline parking B12, startup
  auto-connect)
- QbzQConnect bridge singleton + on_session_entered wiring; one shared
  flyout for both bars (tooltip on the large bar only), Developer >
  Connect diagnostics modal, device-row glyphs, settings rows live
- poll loop: peer-reflection branch before cast, ~2 s renderer reports,
  sync-on-add on every Qobuz-castable add path
- routing: cast → QConnect → local (mute QConnect-first), play arms
  after the set_queue funnel, reorder cloud arm with no local fallback,
  volume/mute/seek remote-first
- touchpoints: lyrics remote anchor, scrobble guarded / Discord
  unguarded, cast suspend/resume, volume-lock lifted when remote

km
This commit is contained in:
vicrodh committed 2026-08-01 20:23:38 -06:00
1 parent 35508b5f87
commit c8559a68b3
55 files changed
+7007 -87

No files matched your search

+16 -2
View File
@@ -479,8 +479,8 @@ pub async fn remove_all_after(runtime: &Arc<AppRuntime<LoggingAdapter>>, page_in
/// queue index once the filter is resolved.
///
/// POC-NOTE: the Slint arm first offers the move to the QConnect cloud
/// (WS-authoritative when connected); there is no QConnect seam in this port,
/// so the local core path is the only one.
/// (WS-authoritative when connected) — that seam is now ported below, 1:1
/// with `queue.rs:686-697`.
pub async fn move_track(
runtime: &Arc<AppRuntime<LoggingAdapter>>,
from_page: usize,
@@ -502,6 +502,20 @@ pub async fn move_track(
if from_q == to_q {
return;
}
// Connected -> the cloud reorders and echoes a QueueUpdated that
// materialize_remote_queue applies; do NOT also reorder locally (would
// diverge). TRAP (§7): routed reorders never touch the local queue, and
// on ERROR there is NO local fallback (Slint queue.rs:688-697).
if let Some(svc) = crate::qconnect_qt::service() {
match svc.reorder_upcoming_if_remote(from_q, to_q).await {
Ok(true) => return,
Ok(false) => {} // not connected -> local path
Err(e) => {
log::warn!("[qbz-qt] queue: reorder handoff failed: {e}");
return; // connected but errored -> do NOT local-reorder
}
}
}
runtime.core().move_track(from_q, to_q).await;
publish(runtime).await;
}