feat(qbz-slint): Queue+Lyrics stacking, NowPlayingBar polish, shell fill fix

NowPlayingBar / SongCard:
- Audio stamp homologated New<->Classic + vertically centred (alignment:center
  on the stamp column; New had a binding-loop card height, now explicit).
- Dot-LED output indicators (circle-dot/circle) in both modes; render-target
  badge moved into the LED row when a peer/cast device owns playback.
- Right-cluster buttons made square (32x32); context glyph -> disc-album,
  flush-left; classic stamp right margin; quality tooltip = the quality text;
  heart tooltip = Add to library; Qobuz Connect tooltip always shows On/Off.

Qobuz Connect:
- Clear the session topology on disconnect so a late event cannot resurrect
  the golden render badge (badge-persists-after-disconnect fix).

Queue / Lyrics right panel:
- Queue and Lyrics can both be open at once, stacked vertically in one column
  (independent queue-open/lyrics-open flags replace the exclusive right-panel
  int); each closable from its bar button and its own X.
- Panel width 280; compact rows (zebra), now-playing card homologated with a
  row, flexible footer search, Lyrics title sized like the Queue tabs.

Shell layout:
- Pin AppShell to the window and size the content area arithmetically
  (window - header - player-bar - padding). A Slint VerticalLayout ignores an
  explicit height and does not auto-fill its parent Rectangle, so the content
  row collapsed once the right panels became conditionally mounted; a Rectangle
  takes the explicit height and it cascades up. Bar height references the single
  Layout.player-bar-height source (note left for the future Small/Large bars).

cc
This commit is contained in:
vicrodh committed 2026-06-04 11:49:24 -06:00
1 parent 8e1bf18f2f
commit 14e3e3689c
12 files changed
+300 -151

No files matched your search

+8
View File
@@ -448,6 +448,14 @@ impl SlintQconnectService {
{
let mut state = runtime.sync_state.lock().await;
state.watchdog_generation = state.watchdog_generation.wrapping_add(1);
// Clear the session topology + per-renderer cache so that any
// event still in flight when the loop aborts cannot recompute
// `is_peer_renderer_active() == true` and resurrect the golden
// render badge AFTER we clear is-remote/cast-target below
// (tokio `abort()` is not instantaneous; the sink can run one
// more `refresh_now_playing_remote_state` from a stale session).
state.session = QconnectSessionState::default();
state.session_renderer_states.clear();
}
if let Err(err) = runtime.app.disconnect().await {
let mut guard = self.inner.lock().await;