Album Screen Redesign (#4)

Album screen redo

Reviewed-on: #4
This commit is contained in:
0x01FE committed 2025-11-03 14:07:50 -06:00
1 parent 9c462679c8
commit 4c6976b2df
6 files changed
+155 -84

No files matched your search

+105 -75
View File
@@ -561,11 +561,24 @@ class ArtistsGUI(Screen):
artist_panel.set_artist(filtered_artists[self.artists_displayed])
self.artists_displayed += 1
class Albums(Screen):
albums: list[SubSonic.Album]
BINDINGS = [
("a", "page_backward()", "Prev. Page"),
("d", "page_forward()", "Next Page")
]
modes: list[str] = ['All', 'Random', 'Recently Added']
# list[page number, albums]
albums: list[tuple[int, list[SubSonic.Album]]] = [(0, []) for n in range(len(modes))]
mode: int = 0
page: list[int] = [0 for n in range(len(modes))]
DATATABLE_SIZE: int
seed: float = random.random()
last_mode: int = 0
SPACE_NEEDED: int = 12
search_value: str = ''
def compose(self) -> ComposeResult:
yield Header(icon='')
@@ -575,21 +588,96 @@ class Albums(Screen):
yield Label(Text("* F3 ", style="bold orange").append_text(Text("Albums", style="white")), classes="headerb")
yield Label(Text("F4 ", style="bold orange").append_text(Text("Songs", style="white")), classes="headerb")
yield Label(Text("F5 ", style="bold orange").append_text(Text("Playlists", style="white")), classes="headerb")
with Vertical(id="albumContainer"):
yield Input(placeholder="Search", id="albumSearchBar")
yield DataTable(id="albumList")
with Horizontal(id='albumScreen'):
yield ListView(
*[ListItem(Label(mode_name)) for mode_name in self.modes],
id='albumModeSelectorList'
)
with Vertical(id="albumContainer"):
yield Input(placeholder="Search", id="albumSearchBar")
yield DataTable(id="albumList")
yield Label(id="pager")
yield Footer()
def on_mount(self) -> None:
app.sub_title = "Albums"
self.albums = conn.getAllAlbums()
albumTable = self.query_one(DataTable)
dt = self.query_one(DataTable)
albumTable.cursor_type = 'row'
albumTable.add_columns("Title", "Artist", "Songs", "Plays", "Year", "Time")
dt.cursor_type = 'row'
dt.add_columns("Title", "Artist", "Songs", "Plays", "Time")
for album in self.albums:
albumTable.add_row(album.title, album.artist, album.songCount, album.playCount, album.year, album.duration, key=album.id)
self.DATATABLE_SIZE = self.size.height - self.SPACE_NEEDED
self._update_datatable()
self._update_pager()
@on(events.Resize)
def on_resize(self) -> None:
self.DATATABLE_SIZE = self.size.height - self.SPACE_NEEDED
self._update_datatable()
def action_page_forward(self) -> None:
self.page[self.mode] += 1
self._update_datatable()
def action_page_backward(self) -> None:
if self.page[self.mode] - 1 < 0:
return
self.page[self.mode] -= 1
self._update_datatable()
def get_current_page(self) -> int:
return self.page[self.mode]
def _get_offset(self) -> int:
return (self.get_current_page()) * self.DATATABLE_SIZE
def _update_pager(self) -> None:
pager = self.query_one("#pager", Label)
pager.update(f'Page {self.page[self.mode] + 1}')
def _update_datatable(self, force_update: bool = False) -> None:
dt = self.query_one(DataTable)
space = self.DATATABLE_SIZE
offset = self._get_offset()
current_page: int = self.get_current_page()
page_n, albums = self.albums[self.mode]
if self.page[self.mode] == 0 and self.mode == 1 and self.last_mode != 1:
self.seed = random.random()
albums = []
if page_n != current_page or not albums or len(albums) < space or force_update or current_page == 1:
if self.mode == 0:
albums = app.navidrome.getAlbums(offset + space, offset, name=self.search_value)
elif self.mode == 1:
albums = app.navidrome.getAlbums(offset + space, offset, sort='random', seed=self.seed, name=self.search_value)
elif self.mode == 2:
albums = app.navidrome.getAlbums(offset + space, offset, order='DESC', sort='recently_added', name=self.search_value)
self.albums[self.mode] = (current_page, albums)
dt.clear()
for album in albums[:space]:
dt.add_row(album.title, album.artist, album.songCount, album.playCount, album.duration, key=album.id)
self.last_mode = self.mode
self._update_pager()
@on(ListView.Selected)
def mode_selected(self, e: ListView.Selected) -> None:
self.mode = e.index
self._update_datatable()
@on(events.ScreenResume)
def on_screen_resume(self, event: events.ScreenResume) -> None:
@@ -602,14 +690,13 @@ class Albums(Screen):
@on(Input.Submitted)
def search_submit(self, event: Input.Submitted) -> None:
search_value = event.value.lower()
self.search_value = event.value.lower()
album_table = self.query_one(DataTable)
if self.search_value:
self.page[self.mode] = 0
self._update_datatable(force_update=True)
album_table.clear()
for album in self.albums:
if search_value in album.title.lower() or search_value in album.artist.lower():
album_table.add_row(album.title, album.artist, album.songCount, album.playCount, album.year, album.duration, key=album.id)
class Playlists(Screen):
@@ -829,63 +916,6 @@ class SongsScreen(Screen):
for song in self.songs:
dt.add_row(song.title, song.album, song.artist, song.playCount, song.duration)
class Favourites(Screen):
BINDINGS = [
('p', 'play()', 'Play Song'),
('q', 'queue()', 'Queue Song'),
('m', 'shuffle_mix()', 'Shuffle Play')
]
songs: list[SubSonic.Song]
selected_song_id: str | None = None
def compose(self) -> ComposeResult:
yield Header(icon="")
with Horizontal(id="headerbs"):
yield Label(Text("F1 ", style="bold orange").append_text(Text("Player", style="white")), classes="headerb")
yield Label(Text("F2 ", style="bold orange").append_text(Text("Artists", style="white")), classes="headerb")
yield Label(Text("F3 ", style="bold orange").append_text(Text("Albums", style="white")), classes="headerb")
yield Label(Text("* F4 ", style="bold orange").append_text(Text("Songs", style="white")), classes="headerb")
yield Label(Text("F5 ", style="bold orange").append_text(Text("Playlists", style="white")), classes="headerb")
yield DataTable()
yield Footer()
def on_mount(self) -> None:
app.sub_title = "Favourites"
self.songs = conn.getStarredSongs()
songTable = self.query_one(DataTable)
songTable.cursor_type = "row"
songTable.add_columns("Title", "Album", "Artist", "Plays", "Duration", "Bitrate")
for song in self.songs:
songTable.add_row(song.title, song.album, song.artist, song.playCount, song.duration, song.bitRate, key=song.id)
@on(DataTable.RowHighlighted)
def row_highlighted(self, event: DataTable.RowHighlighted) -> None:
self.selected_song_id = event.row_key.value
def action_play(self) -> None:
song_index = self._find_selected_song()
app.play_song(self.songs[song_index])
app.song_queue = self.songs[song_index + 1:]
def action_queue(self) -> None:
song_index = self._find_selected_song()
app.queue_song(self.songs[song_index])
# Returns index of selected song
def _find_selected_song(self) -> int:
for i, song in enumerate(self.songs):
if song.id == self.selected_song_id:
return i
def action_shuffle_mix(self) -> None:
q = self.songs.copy()
random.shuffle(q)
app.play_song(q.pop(0))
app.song_queue = q
class CoverArtPixels(Container):
cover = reactive[Image.Image | None](None)