feat(quick-7): wire frontend pin-default-playlist feature end-to-end

- Add pinDefault state, getter, setter to favorites-store
- Add pinDefault getter and setPinDefault to favorites-controller
- Update sortedEntries in playlist-view to pin default playlist to top
- Add Pin to Top toggle in config page Favorites section
- Add Wails bindings for GetPinDefaultPlaylist/SetPinDefaultPlaylist
- React to PinDefault in FavoritesConfigChanged event payload
This commit is contained in:
2026-03-01 10:06:56 -05:00
parent 6e123bd47f
commit e6378e1f0d
6 changed files with 90 additions and 4 deletions
@@ -819,6 +819,21 @@ export class ConfigPage extends LitElement {
}); });
}; };
private handlePinDefaultChange = (
e: CustomEvent<ConfigFieldChangeEvent>,
): void => {
const pin = Boolean(e.detail.value);
this.favCtrl
.setPinDefault(pin)
.catch((err: unknown) => {
console.error(
'Failed to set pin default:',
err,
);
});
};
// =================================================================== // ===================================================================
// TRACK LIST COLUMN HANDLERS // TRACK LIST COLUMN HANDLERS
// =================================================================== // ===================================================================
@@ -1082,6 +1097,18 @@ export class ConfigPage extends LitElement {
.iconStyle} .iconStyle}
@config-change=${this.handleFavIconStyleChange} @config-change=${this.handleFavIconStyleChange}
></config-field> ></config-field>
<config-field
.schema=${{
key: 'pinDefaultPlaylist',
label: 'Pin to Top',
description:
'Always show the default playlist first, regardless of sort order.',
type: 'toggle' as const,
}}
.value=${this.favCtrl.pinDefault}
@config-change=${this.handlePinDefaultChange}
></config-field>
</config-section> </config-section>
`; `;
} }
@@ -1042,6 +1042,22 @@ export class PlaylistView
this.sortDirection === 'asc' ? 1 : -1; this.sortDirection === 'asc' ? 1 : -1;
return [...entries].sort((a, b) => { return [...entries].sort((a, b) => {
// Pin default playlist to top when enabled.
if (this.favCtrl.pinDefault) {
const aIsDefault =
a.summary.ID ===
this.favCtrl.playlistId;
const bIsDefault =
b.summary.ID ===
this.favCtrl.playlistId;
if (aIsDefault && !bIsDefault)
return -1;
if (!aIsDefault && bIsDefault)
return 1;
}
let cmp = 0; let cmp = 0;
switch (this.sortField) { switch (this.sortField) {
@@ -69,6 +69,10 @@ export class FavoritesController
return favoritesStore.getPlaylistId(); return favoritesStore.getPlaylistId();
} }
get pinDefault(): boolean {
return favoritesStore.getPinDefault();
}
/** /**
* Returns the icon name for the current icon style. * Returns the icon name for the current icon style.
*/ */
@@ -113,4 +117,10 @@ export class FavoritesController
): Promise<void> { ): Promise<void> {
await favoritesStore.setDefaultPlaylist(id); await favoritesStore.setDefaultPlaylist(id);
} }
async setPinDefault(
pin: boolean,
): Promise<void> {
await favoritesStore.setPinDefault(pin);
}
} }
+25 -4
View File
@@ -9,8 +9,10 @@ import {
import { import {
GetFavoritesIconStyle, GetFavoritesIconStyle,
GetFavoritesPlaylistID, GetFavoritesPlaylistID,
GetPinDefaultPlaylist,
SetFavoritesIconStyle, SetFavoritesIconStyle,
SetFavoritesPlaylistID, SetFavoritesPlaylistID,
SetPinDefaultPlaylist,
} from '@go/config/Config'; } from '@go/config/Config';
import { Events } from '../events'; import { Events } from '../events';
@@ -29,6 +31,7 @@ class FavoritesStore {
private playlistId = 0; private playlistId = 0;
private playlistName = 'Favorites'; private playlistName = 'Favorites';
private iconStyle: IconStyle = 'heart'; private iconStyle: IconStyle = 'heart';
private pinDefault = true;
private favoritedPaths = new Set<string>(); private favoritedPaths = new Set<string>();
private subscribers = new Set<Subscriber>(); private subscribers = new Set<Subscriber>();
private loading = false; private loading = false;
@@ -44,10 +47,13 @@ class FavoritesStore {
(data: { (data: {
PlaylistID: number; PlaylistID: number;
IconStyle: string; IconStyle: string;
PinDefault: boolean;
}) => { }) => {
this.playlistId = data.PlaylistID; this.playlistId = data.PlaylistID;
this.iconStyle = this.iconStyle =
data.IconStyle as IconStyle; data.IconStyle as IconStyle;
this.pinDefault = data.PinDefault;
this.notify();
void this.loadPlaylistName(); void this.loadPlaylistName();
void this.loadPaths(); void this.loadPaths();
}, },
@@ -119,6 +125,10 @@ class FavoritesStore {
return this.playlistId; return this.playlistId;
} }
getPinDefault(): boolean {
return this.pinDefault;
}
isLoading(): boolean { isLoading(): boolean {
return this.loading; return this.loading;
} }
@@ -203,6 +213,14 @@ class FavoritesStore {
await this.loadPaths(); await this.loadPaths();
} }
async setPinDefault(
pin: boolean,
): Promise<void> {
this.pinDefault = pin;
this.notify();
await SetPinDefaultPlaylist(pin);
}
// =============================================================== // ===============================================================
// SUBSCRIPTION SYSTEM // SUBSCRIPTION SYSTEM
// =============================================================== // ===============================================================
@@ -223,13 +241,16 @@ class FavoritesStore {
private async loadConfig(): Promise<void> { private async loadConfig(): Promise<void> {
try { try {
const [id, style] = await Promise.all([ const [id, style, pin] =
GetFavoritesPlaylistID(), await Promise.all([
GetFavoritesIconStyle(), GetFavoritesPlaylistID(),
]); GetFavoritesIconStyle(),
GetPinDefaultPlaylist(),
]);
this.playlistId = id; this.playlistId = id;
this.iconStyle = style as IconStyle; this.iconStyle = style as IconStyle;
this.pinDefault = pin;
await this.loadPlaylistName(); await this.loadPlaylistName();
this.notify(); this.notify();
} catch { } catch {
+4
View File
@@ -9,6 +9,8 @@ export function GetFavoritesPlaylistID():Promise<number>;
export function GetLibraryDirectory():Promise<string>; export function GetLibraryDirectory():Promise<string>;
export function GetPinDefaultPlaylist():Promise<boolean>;
export function GetScanConcurrency():Promise<string>; export function GetScanConcurrency():Promise<string>;
export function GetThemeAccentColor():Promise<string>; export function GetThemeAccentColor():Promise<string>;
@@ -29,6 +31,8 @@ export function SetFavoritesPlaylistID(arg1:number):Promise<void>;
export function SetLibraryDirectory(arg1:string):Promise<void>; export function SetLibraryDirectory(arg1:string):Promise<void>;
export function SetPinDefaultPlaylist(arg1:boolean):Promise<void>;
export function SetScanConcurrency(arg1:string):Promise<void>; export function SetScanConcurrency(arg1:string):Promise<void>;
export function SetThemeAccentColor(arg1:string):Promise<void>; export function SetThemeAccentColor(arg1:string):Promise<void>;
+8
View File
@@ -14,6 +14,10 @@ export function GetLibraryDirectory() {
return window['go']['config']['Config']['GetLibraryDirectory'](); return window['go']['config']['Config']['GetLibraryDirectory']();
} }
export function GetPinDefaultPlaylist() {
return window['go']['config']['Config']['GetPinDefaultPlaylist']();
}
export function GetScanConcurrency() { export function GetScanConcurrency() {
return window['go']['config']['Config']['GetScanConcurrency'](); return window['go']['config']['Config']['GetScanConcurrency']();
} }
@@ -54,6 +58,10 @@ export function SetLibraryDirectory(arg1) {
return window['go']['config']['Config']['SetLibraryDirectory'](arg1); return window['go']['config']['Config']['SetLibraryDirectory'](arg1);
} }
export function SetPinDefaultPlaylist(arg1) {
return window['go']['config']['Config']['SetPinDefaultPlaylist'](arg1);
}
export function SetScanConcurrency(arg1) { export function SetScanConcurrency(arg1) {
return window['go']['config']['Config']['SetScanConcurrency'](arg1); return window['go']['config']['Config']['SetScanConcurrency'](arg1);
} }