Local-surface track menus gain Go to Album / Go to Artist (owner improvement - Tauri omits them on local rows), routed by source: local rows navigate via their album_group_key and artist name to the local album view and LocalLibrary Artists; plex rows resolve the content-hash plex album key (local_queue_track parity); qobuz_download rows recover their real Qobuz album/artist ids through get_track and open the Qobuz pages, falling back to the local destinations when the resolve fails so the click always lands. Entries hide when keys are absent (ephemeral, file:/broken:/unresolved rows). Playlist-detail sidecar rows opt in with the same routing, and the global go-to arms divert snapshot local/plex rows before the catalog parse (a local row id would have been mis-typed as a Qobuz catalog id). Playlist header drops its local CircleAction copy (transparent + 1px border ring) for the shared user-verified primitive (solid primary disc, translucent fills, dim-on-disabled) - all seven actions restyled, callbacks untouched. cc
186 lines
8.1 KiB
Plaintext
186 lines
8.1 KiB
Plaintext
// Track-row "more" context menu — flat, ported 1:1 from the Tauri
|
|
// TrackMenu component. Items that have no Slint wiring yet emit a
|
|
// media-action with an action string the runtime currently ignores
|
|
// (no-op until backend wiring lands).
|
|
|
|
import { ContextMenu } from "ContextMenu.slint";
|
|
import { ContextMenuItem } from "ContextMenuItem.slint";
|
|
|
|
export component TrackContextMenu inherits PopupWindow {
|
|
in property <string> track-id;
|
|
// Per-source applicability (the surrounding row sets these from the track's
|
|
// source). `qobuz-actions` = the Qobuz-backed block (radio, share,
|
|
// make-offline, go-to album/artist, track info) — on for Qobuz + offline,
|
|
// off for local / Plex / ephemeral. `favorite-action` / `mixtape-action`
|
|
// gate the favorite and Add-to-Mixtape entries independently of the block
|
|
// (library surfaces show them on rows the Qobuz block is dead for — spec
|
|
// §3.1/§3.2); they default to the block so Qobuz surfaces are unchanged.
|
|
// `playlist-action` = Add to playlist — on for Qobuz + offline + local +
|
|
// Plex (local playlists store each source's own ref), off for ephemeral.
|
|
// `remove-from-playlist-action` = the playlist-detail per-row removal
|
|
// (every row source — the arm splits by id namespace); the surface
|
|
// gates it on ownership (spec §3.1).
|
|
// `track-info-action` lets a surface HIDE the Track Info entry while
|
|
// its target feature is missing there (spec §3.3) — defaults on so
|
|
// other surfaces are untouched.
|
|
// `go-album-action` / `go-artist-action` — the Go to album / Go to
|
|
// artist pair, gated independently of the block so library surfaces
|
|
// can show them on local/plex/qobuz_download rows too (owner
|
|
// improvement over Tauri, which omits both on local rows; the Rust
|
|
// arms route by row source). Default to the block so Qobuz surfaces
|
|
// are unchanged.
|
|
// The transient actions (play / next / queue) always show.
|
|
in property <bool> qobuz-actions: true;
|
|
in property <bool> favorite-action: root.qobuz-actions;
|
|
in property <bool> mixtape-action: root.qobuz-actions;
|
|
in property <bool> playlist-action: true;
|
|
in property <bool> remove-from-playlist-action: false;
|
|
in property <bool> track-info-action: true;
|
|
in property <bool> go-album-action: root.qobuz-actions;
|
|
in property <bool> go-artist-action: root.qobuz-actions;
|
|
// The row's offline-cache status (TrackItem.cache-status): when cached
|
|
// (3) the single "Make available offline" entry swaps for the
|
|
// Refresh / Remove pair — Tauri's ready-state submenu, rendered flat
|
|
// (cosmetic-flat per spec §3.5).
|
|
in property <int> cache-status: 0;
|
|
callback media-action(string, string, string);
|
|
|
|
width: 224px;
|
|
// 3 transient + optional favorite/mixtape/add-to-playlist/remove +
|
|
// optional go-to pair + the Qobuz block (3 fixed + 1-or-2 offline
|
|
// entries + optional track info).
|
|
height: (3
|
|
+ (root.favorite-action ? 1 : 0)
|
|
+ (root.mixtape-action ? 1 : 0)
|
|
+ (root.playlist-action ? 1 : 0)
|
|
+ (root.remove-from-playlist-action ? 1 : 0)
|
|
+ (root.go-album-action ? 1 : 0)
|
|
+ (root.go-artist-action ? 1 : 0)
|
|
+ (root.qobuz-actions
|
|
? 3 + (root.cache-status == 3 ? 2 : 1) + (root.track-info-action ? 1 : 0)
|
|
: 0)) * 30px;
|
|
|
|
ContextMenu {
|
|
ContextMenuItem {
|
|
icon: @image-url("../assets/icons/play.svg");
|
|
label: @tr("Play now");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "play");
|
|
}
|
|
}
|
|
ContextMenuItem {
|
|
icon: @image-url("../assets/icons/list-plus.svg");
|
|
label: @tr("Play next");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "play-next");
|
|
}
|
|
}
|
|
ContextMenuItem {
|
|
icon: @image-url("../assets/icons/list-end.svg");
|
|
label: @tr("Add to queue");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "queue");
|
|
}
|
|
}
|
|
if root.qobuz-actions: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/radio.svg");
|
|
label: @tr("Create radio");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "create-radio");
|
|
}
|
|
}
|
|
if root.favorite-action: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/heart.svg");
|
|
label: @tr("Add to library");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "favorite");
|
|
}
|
|
}
|
|
if root.mixtape-action: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/cassette-tape.svg");
|
|
label: @tr("Add to mixtape");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "add-to-mixtape");
|
|
}
|
|
}
|
|
if root.playlist-action: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/list-music.svg");
|
|
label: @tr("Add to playlist");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "add-to-playlist");
|
|
}
|
|
}
|
|
// Remove from playlist (danger) — playlist detail only, after Add
|
|
// to playlist (Tauri group order, spec §1.3 #8).
|
|
if root.remove-from-playlist-action: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/trash-2.svg");
|
|
label: @tr("Remove from playlist");
|
|
danger: true;
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "remove-from-playlist");
|
|
}
|
|
}
|
|
if root.qobuz-actions: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/link.svg");
|
|
label: @tr("Share Qobuz link");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "share-qobuz");
|
|
}
|
|
}
|
|
if root.qobuz-actions: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/link.svg");
|
|
label: @tr("Share Song.link");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "share-songlink");
|
|
}
|
|
}
|
|
// Offline-cache block — cached-state-aware (Tauri's ready-state
|
|
// submenu, flat per spec §3.5): not cached -> Make available
|
|
// offline; cached -> Refresh + Remove (icons 1:1 with Tauri's
|
|
// RefreshCw / Trash2).
|
|
if root.qobuz-actions && root.cache-status != 3: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/cloud-download.svg");
|
|
label: @tr("Make available offline");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "download");
|
|
}
|
|
}
|
|
if root.qobuz-actions && root.cache-status == 3: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/refresh-cw.svg");
|
|
label: @tr("Refresh offline copy");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "recache");
|
|
}
|
|
}
|
|
if root.qobuz-actions && root.cache-status == 3: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/trash-2.svg");
|
|
label: @tr("Remove offline copy");
|
|
danger: true;
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "uncache");
|
|
}
|
|
}
|
|
if root.go-album-action: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/disc-3.svg");
|
|
label: @tr("Go to album");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "go-to-album");
|
|
}
|
|
}
|
|
if root.go-artist-action: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/user.svg");
|
|
label: @tr("Go to artist");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "go-to-artist");
|
|
}
|
|
}
|
|
if root.qobuz-actions && root.track-info-action: ContextMenuItem {
|
|
icon: @image-url("../assets/icons/info.svg");
|
|
label: @tr("Track info");
|
|
clicked => {
|
|
root.media-action("track", root.track-id, "track-info");
|
|
}
|
|
}
|
|
}
|
|
}
|