feat(qbz-slint): per-device-type icons in the QConnect device picker

Mirror Qobuz Connect's device icons in the connect flyout: map each renderer's
device_type to an icon (6 -> smartphone, 5 -> monitor or globe when the name is a
web player/browser, else -> speaker), matching the Tauri QconnectBadge
resolveDeviceType. Adds lucide monitor/smartphone/speaker/globe svgs, an icon key
on the QconnectDevice model computed in the event sink, and a per-row icon in the
PlayerBar device list.

cc
This commit is contained in:
vicrodh committed 2026-06-03 11:19:14 -06:00
1 parent 9bb5e6db26
commit e845c59fea
7 files changed
+52 -1

No files matched your search

@@ -158,6 +158,8 @@ impl SlintQconnectEventSink {
.into(),
is_local: Some(r.renderer_id) == session.local_renderer_id,
is_active: Some(r.renderer_id) == session.active_renderer_id,
icon: device_icon_key(r.device_type, r.friendly_name.as_deref().unwrap_or(""))
.into(),
})
.collect();
(devices, session.active_renderer_id.unwrap_or(-1))
@@ -495,6 +497,25 @@ impl QconnectEventSink for SlintQconnectEventSink {
}
}
/// Map a renderer's `device_type` (+ a name heuristic for web players) to a
/// device-icon key, mirroring the Tauri `QconnectBadge.resolveDeviceType`:
/// 6 = mobile, 5 = computer (or "web" when the name says web player/browser),
/// anything else (3/4/…) = speaker/receiver.
fn device_icon_key(device_type: Option<i32>, friendly_name: &str) -> &'static str {
match device_type.unwrap_or(5) {
6 => "mobile",
5 => {
let name = friendly_name.to_ascii_lowercase();
if name.contains("web player") || name.contains("browser") {
"web"
} else {
"computer"
}
}
_ => "speaker",
}
}
/// Format a QConnect event into a one-line DEV-log entry. Big payloads
/// (QueueUpdated / SessionManagement) are summarized; the rest use Debug.
fn dev_event_line(event: &QconnectAppEvent) -> String {
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10" />
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
<path d="M2 12h20" />
</svg>

After

Width:  |  Height:  |  Size: 307 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="20" height="14" x="2" y="3" rx="2" />
<line x1="8" x2="16" y1="21" y2="21" />
<line x1="12" x2="12" y1="17" y2="21" />
</svg>

After

Width:  |  Height:  |  Size: 322 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="14" height="20" x="5" y="2" rx="2" ry="2" />
<path d="M12 18h.01" />
</svg>

After

Width:  |  Height:  |  Size: 270 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="16" height="20" x="4" y="2" rx="2" />
<circle cx="12" cy="14" r="4" />
<path d="M12 6h.01" />
</svg>

After

Width:  |  Height:  |  Size: 297 B

+10 -1
View File
@@ -431,7 +431,16 @@ export component PlayerBar inherits Rectangle {
VerticalLayout {
alignment: center;
QbzIcon {
source: @image-url("../assets/icons/monitor-speaker.svg");
// Device-type icon, mirroring Qobuz Connect (computer /
// web / mobile / speaker). @image-url needs a literal, so
// pick among the four by the device's icon key.
source: d.icon == "mobile"
? @image-url("../assets/icons/smartphone.svg")
: d.icon == "speaker"
? @image-url("../assets/icons/speaker.svg")
: d.icon == "web"
? @image-url("../assets/icons/globe.svg")
: @image-url("../assets/icons/monitor.svg");
width: 14px;
height: 14px;
tint: d.is-active ? Theme.accent : Theme.text-secondary;
+2
View File
@@ -1984,6 +1984,8 @@ export struct QconnectDevice {
name: string,
is-local: bool, // this is QBZ itself ("Play here")
is-active: bool, // currently the active renderer
// Device-type icon key (mirrors Qobuz Connect): "computer" | "web" | "mobile" | "speaker".
icon: string,
}
// Qobuz Connect DEV diagnostics — live session topology + a rolling event log,