beginnings of artist grid and artist details view

This commit is contained in:
2026-02-22 19:17:27 -05:00
parent 30bbdd7c53
commit 9dabfb81c5
15 changed files with 1186 additions and 10 deletions
@@ -51,6 +51,16 @@ export class LibraryController implements ReactiveController {
return libraryStore.getAlbums();
}
async getArtists(): Promise<library.Artist[]> {
return libraryStore.getArtists();
}
async getAlbumsByArtist(
artistID: number,
): Promise<library.Album[]> {
return libraryStore.getAlbumsByArtist(artistID);
}
get cachedTracks(): library.Track[] | null {
return libraryStore.getCachedTracks();
}
@@ -59,6 +69,10 @@ export class LibraryController implements ReactiveController {
return libraryStore.getCachedAlbums();
}
get cachedArtists(): library.Artist[] | null {
return libraryStore.getCachedArtists();
}
get tracksLoading(): boolean {
return libraryStore.isTracksLoading();
}
@@ -67,6 +81,10 @@ export class LibraryController implements ReactiveController {
return libraryStore.isAlbumsLoading();
}
get artistsLoading(): boolean {
return libraryStore.isArtistsLoading();
}
// ===================================================================
// SCROLL POSITION
// ===================================================================
+57 -1
View File
@@ -1,5 +1,10 @@
import { EventsOn } from '@runtime/runtime';
import { GetAllTracks, GetAllAlbums } from '@go/library/Library';
import {
GetAllTracks,
GetAllAlbums,
GetAllArtists,
GetAlbumsByArtist,
} from '@go/library/Library';
import type { library } from '@go/models';
import { Events } from '../events';
@@ -22,9 +27,11 @@ const COVER_SIZE_KEY = 'cover-grid-size';
class LibraryStore {
private tracks: library.Track[] | null = null;
private albums: library.Album[] | null = null;
private artists: library.Artist[] | null = null;
private tracksLoading = false;
private albumsLoading = false;
private artistsLoading = false;
private coverSizeValue: number = COVER_SIZE_DEFAULT;
@@ -94,6 +101,35 @@ class LibraryStore {
}
}
async getArtists(): Promise<library.Artist[]> {
if (this.artists !== null) {
return this.artists;
}
if (this.artistsLoading) {
return this.waitForArtists();
}
this.artistsLoading = true;
this.notify();
try {
const artists = await GetAllArtists();
this.artists = artists;
return artists;
} finally {
this.artistsLoading = false;
this.notify();
}
}
async getAlbumsByArtist(
artistID: number,
): Promise<library.Album[]> {
return GetAlbumsByArtist(artistID);
}
// ===================================================================
// STATE ACCESSORS
// Synchronous access for controllers that need current cached values.
@@ -115,6 +151,14 @@ class LibraryStore {
return this.albumsLoading;
}
getCachedArtists(): library.Artist[] | null {
return this.artists;
}
isArtistsLoading(): boolean {
return this.artistsLoading;
}
// ===================================================================
// SCROLL POSITION
// ===================================================================
@@ -184,6 +228,7 @@ class LibraryStore {
private invalidate(): void {
this.tracks = null;
this.albums = null;
this.artists = null;
this.scrollPositions = { tracks: 0, albums: 0 };
this.notify();
}
@@ -228,6 +273,17 @@ class LibraryStore {
});
});
}
private waitForArtists(): Promise<library.Artist[]> {
return new Promise((resolve) => {
const unsub = this.subscribe(() => {
if (!this.artistsLoading && this.artists !== null) {
unsub();
resolve(this.artists);
}
});
});
}
}
// Singleton instance.
+1 -1
View File
@@ -1,5 +1,5 @@
/** Searchable views that respond to the global search term. */
const SEARCHABLE_VIEWS = new Set(['tracks', 'albums', 'playlists']);
const SEARCHABLE_VIEWS = new Set(['tracks', 'albums', 'playlists', 'artists']);
type Subscriber = () => void;