feat(slint): library/sidebar UX overhaul + theme switching + fixes
Shell & navigation: - Three-state sidebar (open/mini/closed); collapse cycles via header button. - Section nav as right-flyouts (sidebar) + compact header nav (closed) + full header tabs (nav-in-sidebar off), via a shared HeaderMenuOverlay. - Collapsed-folder right-flyout popup (max 4 + scrollbar), Rust-populated. - Thin auto-hiding sidebar scrollbar pinned to the edge (Flickable, drag-safe). - Slack-style bezel: rounded inset content panel over surface-card chrome. - Header restructure: nav buttons, window-centered search, app menu. Themes & components: - Live theme switching: Dark / OLED Black / Tokyo Night / System (std-widgets). - SegmentedTabBar (Discovery-style) with count badges for Library + Local Library. - MP3 quality-badge tier (format-first classification) across badges. - QbzSelect (Group/Sort) trimmed 20px. Behavior fixes: - Artist + Local Library Folder cover art now reach the rendered (visible/ grouped) models, not just the source set. - Favorites Playlists/Labels random buttons. - Playlist track click plays from the clicked track in visible order. - Dropdown idle-close pauses while the cursor rests on the menu. cc
This commit is contained in:
27 files changed
+1495
-619
No files matched your search
@@ -29,95 +29,23 @@ import { ListScrollbar } from "../primitives/ListScrollbar.slint";
|
||||
import { TrackRow } from "../primitives/TrackRow.slint";
|
||||
import { ToggleButton } from "../primitives/ToggleButton.slint";
|
||||
import { MultiSelectBar } from "../primitives/MultiSelectBar.slint";
|
||||
import { SegmentedTabBar, SegTab } from "../primitives/SegmentedTabBar.slint";
|
||||
import { ListView } from "std-widgets.slint";
|
||||
|
||||
// One tab in the Local Library tab menu — underline style (ADR-008: NO
|
||||
// pills). 1:1 with Favorites' FavTab so the chrome reads identically.
|
||||
component LibTab inherits Rectangle {
|
||||
in property <string> label;
|
||||
in property <string> id;
|
||||
in property <int> count;
|
||||
callback selected(string);
|
||||
|
||||
property <bool> active: LocalLibraryState.active-tab == root.id;
|
||||
height: 34px;
|
||||
width: tab-row.preferred-width;
|
||||
|
||||
tab-row := HorizontalLayout {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
spacing: 6px;
|
||||
Text {
|
||||
text: root.label;
|
||||
color: root.active ? Theme.text-primary : Theme.text-muted;
|
||||
font-size: Typography.body;
|
||||
font-weight: root.active ? Typography.semibold : Typography.regular;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
if root.count > 0: Text {
|
||||
text: root.count;
|
||||
color: Theme.text-muted;
|
||||
font-size: Typography.legal;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
// Active underline (NOT a pill background).
|
||||
Rectangle {
|
||||
y: parent.height - 2px;
|
||||
height: 2px;
|
||||
width: parent.width;
|
||||
background: root.active ? Theme.accent : transparent;
|
||||
border-radius: 1px;
|
||||
}
|
||||
ta := TouchArea {
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
root.selected(root.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The Local Library tabs as one floating group (row 1, right side). Order
|
||||
// mirrors the existing HeaderBar "Local Library" menu (Albums / Artists /
|
||||
// Folders / Tracks). Counts come from LocalLibraryState (0 until seeded).
|
||||
component LibTabMenu inherits HorizontalLayout {
|
||||
spacing: 18px;
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
LibTab {
|
||||
label: @tr("Albums");
|
||||
id: "albums";
|
||||
count: LocalLibraryState.album-count;
|
||||
selected(id) => { LocalLibraryActions.select-tab(id); }
|
||||
}
|
||||
}
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
LibTab {
|
||||
label: @tr("Artists");
|
||||
id: "artists";
|
||||
count: LocalLibraryState.artist-count;
|
||||
selected(id) => { LocalLibraryActions.select-tab(id); }
|
||||
}
|
||||
}
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
LibTab {
|
||||
label: @tr("Folders");
|
||||
id: "folders";
|
||||
count: LocalLibraryState.folder-count;
|
||||
selected(id) => { LocalLibraryActions.select-tab(id); }
|
||||
}
|
||||
}
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
LibTab {
|
||||
label: @tr("Tracks");
|
||||
id: "tracks";
|
||||
count: LocalLibraryState.track-count;
|
||||
selected(id) => { LocalLibraryActions.select-tab(id); }
|
||||
}
|
||||
}
|
||||
// The Local Library tabs as one floating group (row 1, right side) — now
|
||||
// the shared Discovery-style SegmentedTabBar, counts rendered as badges.
|
||||
// Order mirrors the existing HeaderBar "Local Library" menu (Albums /
|
||||
// Artists / Folders / Tracks). Counts come from LocalLibraryState (seeded
|
||||
// up front so the badges show without visiting each tab).
|
||||
component LibTabMenu inherits SegmentedTabBar {
|
||||
active-id: LocalLibraryState.active-tab;
|
||||
tabs: [
|
||||
{ id: "albums", label: @tr("Albums"), count: LocalLibraryState.album-count },
|
||||
{ id: "artists", label: @tr("Artists"), count: LocalLibraryState.artist-count },
|
||||
{ id: "folders", label: @tr("Folders"), count: LocalLibraryState.folder-count },
|
||||
{ id: "tracks", label: @tr("Tracks"), count: LocalLibraryState.track-count },
|
||||
];
|
||||
selected(id) => { LocalLibraryActions.select-tab(id); }
|
||||
}
|
||||
|
||||
// Standalone icon-only circle (ADR-008 permits a full circle for an
|
||||
@@ -445,10 +373,6 @@ export component LocalLibraryView inherits Rectangle {
|
||||
padding-right: 32px;
|
||||
padding-top: 11px;
|
||||
spacing: 16px;
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
NavButtons { }
|
||||
}
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
Text {
|
||||
@@ -458,11 +382,7 @@ export component LocalLibraryView inherits Rectangle {
|
||||
font-weight: Typography.bold;
|
||||
}
|
||||
}
|
||||
Rectangle { horizontal-stretch: 1; }
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
LibTabMenu { }
|
||||
}
|
||||
// Settings gear — inline, to the right of the title.
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
CircleIconBtn {
|
||||
@@ -472,6 +392,7 @@ export component LocalLibraryView inherits Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle { horizontal-stretch: 1; }
|
||||
}
|
||||
|
||||
Rectangle { height: 12px; }
|
||||
@@ -486,6 +407,12 @@ export component LocalLibraryView inherits Rectangle {
|
||||
padding-right: 32px;
|
||||
spacing: 8px;
|
||||
|
||||
// The section tab menu sits under the title (left of row 2).
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
LibTabMenu { }
|
||||
}
|
||||
|
||||
Rectangle { horizontal-stretch: 1; }
|
||||
|
||||
// Albums toolbar — search + sort (both server-side). The
|
||||
|
||||
Reference in new issue
Block a user