Files
yellowjacket/frontend/src/store/controllers/library-controller.ts
T
yonlu 42b8cf9f52 feat(13-02): add library filter dropdown and wire all views to respect active filter
- Add selectedLibraryId state + ByLibrary conditional calls to library-store
- Add library filter pass-through methods to library-controller
- Create library-filter dropdown component in top bar
- Wire genre-details, cover-grid, artists-view, genres-view to use ByLibrary queries
- Update album-selection helper to respect library filter
- Regenerate Wails bindings for new ByLibrary methods
- Search remains client-side (automatically filtered by loaded data)
- Playlists remain unfiltered (use separate playlist store)
2026-03-16 09:41:27 -04:00

160 lines
4.5 KiB
TypeScript

import type { ReactiveController, ReactiveControllerHost } from 'lit';
import type { library } from '@go/models';
import { libraryStore } from '../library-store';
type ViewName = 'tracks' | 'albums' | 'artists' | 'genres';
/**
* LibraryController connects a Lit component to the LibraryStore.
*
* Usage in a component:
*
* private library = new LibraryController(this);
*
* async connectedCallback() {
* super.connectedCallback();
* this.tracks = await this.library.getTracks();
* }
*/
export class LibraryController implements ReactiveController {
private host: ReactiveControllerHost;
private unsubscribe?: () => void;
constructor(host: ReactiveControllerHost) {
this.host = host;
host.addController(this);
}
// ===================================================================
// LIFECYCLE HOOKS
// ===================================================================
/** Last observed changeGeneration from the store. */
private lastChangeGen = libraryStore.changeGeneration;
hostConnected(): void {
this.lastChangeGen = libraryStore.changeGeneration;
this.unsubscribe = libraryStore.subscribe(() => {
const gen = libraryStore.changeGeneration;
// Skip requestUpdate when only loading flags toggled
// (changeGeneration unchanged means no actual data changed).
if (gen !== this.lastChangeGen) {
this.lastChangeGen = gen;
this.host.requestUpdate();
}
});
}
hostDisconnected(): void {
this.unsubscribe?.();
}
// ===================================================================
// DATA ACCESS
// ===================================================================
async getTracks(): Promise<library.Track[]> {
return libraryStore.getTracks();
}
async getAlbums(): Promise<library.Album[]> {
return libraryStore.getAlbums();
}
async getArtists(): Promise<library.Artist[]> {
return libraryStore.getArtists();
}
async getGenres(): Promise<library.GenreWithCount[]> {
return libraryStore.getGenres();
}
async getAlbumsByArtist(
artistID: number,
): Promise<library.Album[]> {
return libraryStore.getAlbumsByArtist(artistID);
}
getAlbumsByArtistNameCached(
artistName: string,
): library.Album[] | null {
return libraryStore.getAlbumsByArtistNameCached(
artistName,
);
}
get cachedTracks(): library.Track[] | null {
return libraryStore.getCachedTracks();
}
get cachedAlbums(): library.Album[] | null {
return libraryStore.getCachedAlbums();
}
get cachedArtists(): library.Artist[] | null {
return libraryStore.getCachedArtists();
}
get cachedGenres(): library.GenreWithCount[] | null {
return libraryStore.getCachedGenres();
}
get tracksLoading(): boolean {
return libraryStore.isTracksLoading();
}
get albumsLoading(): boolean {
return libraryStore.isAlbumsLoading();
}
get artistsLoading(): boolean {
return libraryStore.isArtistsLoading();
}
get genresLoading(): boolean {
return libraryStore.isGenresLoading();
}
// ===================================================================
// SCROLL POSITION
// ===================================================================
getScrollPosition(view: ViewName): number {
return libraryStore.getScrollPosition(view);
}
setScrollPosition(view: ViewName, offset: number): void {
libraryStore.setScrollPosition(view, offset);
}
// ===================================================================
// LIBRARY FILTER
// ===================================================================
get selectedLibraryId(): number | null {
return libraryStore.getSelectedLibraryId();
}
setSelectedLibrary(id: number | null): void {
libraryStore.setSelectedLibrary(id);
}
async getLibraries(): Promise<library.Info[]> {
return libraryStore.getLibraries();
}
// ===================================================================
// COVER SIZE
// ===================================================================
get coverSize(): number {
return libraryStore.getCoverSize();
}
set coverSize(size: number) {
libraryStore.setCoverSize(size);
}
}