feat(slint): per-row offline affordance + the unlock padlock (Slice 2 UI)
TrackRow now renders the offline state the controller maintains: - The offline button is stateful: cloud-download (none, click -> cache) -> loader-circle accent (queued/downloading) -> circle-check accent (ready, click -> uncache) -> triangle-alert red (failed, click -> retry). Shown on surfaces that enable it AND on any row with active cache state. - The unlock PADLOCK (user-requested, back from Tauri): a pulsing lock glyph overlays the play cell while the track's CMAF bundle decrypts, driven by the `unlocking` flag the row_sink toggles on UnlockStart/UnlockEnd. New lucide lock.svg / lock-open.svg assets. The context menu's "Make available offline" already routes to caching. Testable loop: cache a track (album button or context menu) -> watch it download -> play it offline -> padlock pulses during decrypt. qbz-slint compiles clean. cc
This commit is contained in:
3 files changed
+61
-5
No files matched your search
@@ -220,6 +220,34 @@ export component TrackRow inherits Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Offline-decrypt padlock — overlays the play cell while the
|
||||
// track's CMAF bundle is being decrypted for playback. Pulses
|
||||
// to read as "unlocking" (mirrors Tauri's unlock glyph).
|
||||
if root.track.unlocking: lock-overlay := Rectangle {
|
||||
property <bool> pulse;
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
border-radius: 6px;
|
||||
background: #000000aa;
|
||||
QbzIcon {
|
||||
source: @image-url("../assets/icons/lock.svg");
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
x: (parent.width - self.width) / 2;
|
||||
y: (parent.height - self.height) / 2;
|
||||
tint: Theme.accent;
|
||||
opacity: lock-overlay.pulse ? 1.0 : 0.4;
|
||||
animate opacity { duration: 450ms; }
|
||||
}
|
||||
Timer {
|
||||
interval: 450ms;
|
||||
running: true;
|
||||
triggered => {
|
||||
lock-overlay.pulse = !lock-overlay.pulse;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,8 +393,15 @@ export component TrackRow inherits Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Offline cache.
|
||||
if root.show-download: VerticalLayout {
|
||||
// Offline cache — a stateful affordance reflecting cache-status:
|
||||
// 0 none cloud-download (click -> cache)
|
||||
// 1/2 q'd/dl'ing loader (accent) (click -> cache; re-queues)
|
||||
// 3 ready circle-check (click -> uncache)
|
||||
// 4 failed triangle-alert (click -> cache; retries)
|
||||
// Shown when the surface enables it OR the track has active state, so
|
||||
// a downloading/ready copy surfaces its status even where the button
|
||||
// isn't enabled by default.
|
||||
if root.show-download || root.track.cache-status > 0: VerticalLayout {
|
||||
alignment: center;
|
||||
Rectangle {
|
||||
width: 28px;
|
||||
@@ -374,17 +409,30 @@ export component TrackRow inherits Rectangle {
|
||||
border-radius: Radius.sm;
|
||||
background: dl-ta.has-hover ? Theme.surface-elevated : transparent;
|
||||
QbzIcon {
|
||||
source: @image-url("../assets/icons/cloud-download.svg");
|
||||
source: root.track.cache-status == 3
|
||||
? @image-url("../assets/icons/circle-check-big.svg")
|
||||
: (root.track.cache-status == 4
|
||||
? @image-url("../assets/icons/triangle-alert.svg")
|
||||
: ((root.track.cache-status == 1 || root.track.cache-status == 2)
|
||||
? @image-url("../assets/icons/loader-circle.svg")
|
||||
: @image-url("../assets/icons/cloud-download.svg")));
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
x: (parent.width - self.width) / 2;
|
||||
y: (parent.height - self.height) / 2;
|
||||
tint: dl-ta.has-hover ? Theme.text-primary : Theme.text-muted;
|
||||
tint: root.track.cache-status == 3
|
||||
? Theme.accent
|
||||
: (root.track.cache-status == 4
|
||||
? #e0564f
|
||||
: ((root.track.cache-status == 1 || root.track.cache-status == 2)
|
||||
? Theme.accent
|
||||
: (dl-ta.has-hover ? Theme.text-primary : Theme.text-muted)));
|
||||
}
|
||||
dl-ta := TouchArea {
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
root.media-action("track", root.track.id, "download");
|
||||
root.media-action("track", root.track.id,
|
||||
root.track.cache-status == 3 ? "uncache" : "cache");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user