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:
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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>;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user