This commit is contained in:
Benjamin Schaaf
2021-02-06 23:51:54 +11:00
parent d7d774c579
commit 56ae24b479
5 changed files with 329 additions and 89 deletions

View File

@@ -15,7 +15,7 @@ from ..adapters import (
)
from ..config import AppConfiguration
from ..ui import util
from ..ui.common import AlbumWithSongs, IconButton, LoadError, SpinnerImage
from ..ui.common import AlbumWithSongs, IconButton, LoadError, SpinnerImage, Sizer
def _to_type(query_type: AlbumSearchQuery.Type) -> str:
@@ -46,7 +46,7 @@ def _from_str(type_str: str) -> AlbumSearchQuery.Type:
}[type_str]
class AlbumsPanel(Gtk.Box):
class AlbumsPanel(Handy.Leaflet):
__gsignals__ = {
"song-clicked": (
GObject.SignalFlags.RUN_FIRST,
@@ -60,18 +60,25 @@ class AlbumsPanel(Gtk.Box):
),
}
current_query: AlbumSearchQuery = AlbumSearchQuery(AlbumSearchQuery.Type.RANDOM)
offline_mode = False
provider_id: Optional[str] = None
populating_genre_combo = False
grid_order_token: int = 0
album_sort_direction: str = "ascending"
album_page_size: int = 30
# album_page_size: int = 30
album_page: int = 0
grid_pages_count: int = 0
def __init__(self):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
current_albums_result: Result = None
leaflet = Handy.Leaflet(transition_type=Handy.LeafletTransitionType.SLIDE, can_swipe_forward=False)
albums = []
albums_by_id = {}
def __init__(self):
super().__init__(transition_type=Handy.LeafletTransitionType.SLIDE, can_swipe_forward=False, interpolate_size=False)
self.grid_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
actionbar = Gtk.ActionBar()
@@ -123,6 +130,57 @@ class AlbumsPanel(Gtk.Box):
self.sort_toggle.connect("clicked", self.on_sort_toggle_clicked)
actionbar.pack_start(self.sort_toggle)
self.refresh_button = IconButton(
"view-refresh-symbolic", "Refresh list of albums", relief=True
)
self.refresh_button.connect("clicked", self.on_refresh_clicked)
actionbar.pack_end(self.refresh_button)
# actionbar.pack_end(Gtk.Label(label="albums per page"))
# self.show_count_dropdown, _ = self.make_combobox(
# ((x, x, True) for x in ("20", "30", "40", "50")),
# self.on_show_count_dropdown_change,
# )
# actionbar.pack_end(self.show_count_dropdown)
# actionbar.pack_end(Gtk.Label(label="Show"))
self.grid_box.pack_start(actionbar, False, False, 0)
# 700 shows ~3 albums
grid_sizer = Sizer(natural_width=700)
scrolled_window = Gtk.ScrolledWindow(
hscrollbar_policy=Gtk.PolicyType.NEVER)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.grid = Gtk.FlowBox(
hexpand=True,
margin_top=5,
row_spacing=5,
column_spacing=5,
homogeneous=True,
max_children_per_line=999,
valign=Gtk.Align.START,
halign=Gtk.Align.CENTER,
selection_mode=Gtk.SelectionMode.SINGLE)
self.grid.connect("child-activated", self.on_album_clicked)
# self.grid.connect(
# "song-clicked",
# lambda _, *args: self.emit("song-clicked", *args),
# )
# self.grid.connect(
# "refresh-window",
# lambda _, *args: self.emit("refresh-window", *args),
# )
# self.grid.connect("cover-clicked", self.on_album_clicked)
# self.grid.connect("num-pages-changed", self.on_grid_num_pages_changed)
box.add(self.grid)
bottom_actionbar = Gtk.ActionBar()
# Add the page widget.
page_widget = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
self.prev_page = IconButton(
@@ -145,39 +203,46 @@ class AlbumsPanel(Gtk.Box):
)
self.next_page.connect("clicked", self.on_next_page_clicked)
page_widget.add(self.next_page)
actionbar.set_center_widget(page_widget)
bottom_actionbar.set_center_widget(page_widget)
self.refresh_button = IconButton(
"view-refresh-symbolic", "Refresh list of albums", relief=True
)
self.refresh_button.connect("clicked", self.on_refresh_clicked)
actionbar.pack_end(self.refresh_button)
box.add(bottom_actionbar)
actionbar.pack_end(Gtk.Label(label="albums per page"))
self.show_count_dropdown, _ = self.make_combobox(
((x, x, True) for x in ("20", "30", "40", "50")),
self.on_show_count_dropdown_change,
)
actionbar.pack_end(self.show_count_dropdown)
actionbar.pack_end(Gtk.Label(label="Show"))
scrolled_window.add(box)
grid_sizer.add(scrolled_window)
self.grid_box.pack_start(grid_sizer, True, True, 0)
# self.add(actionbar)
leaflet.add(actionbar)
self.add(self.grid_box)
self.details_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.details_box.get_style_context().add_class("details-panel")
details_top_bar_revealer = Gtk.Revealer(reveal_child=False)
details_top_bar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
back_button = IconButton("go-previous-symbolic")
def back_clicked(*_):
self.set_visible_child(self.grid_box)
back_button.connect("clicked", back_clicked)
details_top_bar.pack_start(back_button, False, False, 0)
details_top_bar_revealer.add(details_top_bar)
self.details_box.pack_start(details_top_bar_revealer, False, False, 0)
self.album_with_songs = AlbumWithSongs(cover_art_size=100)
self.details_box.pack_start(self.album_with_songs, True, True, 0)
self.add(self.details_box)
def folded_changed(*_):
if not self.get_folded():
self.set_visible_child(self.grid_box)
details_top_bar_revealer.set_reveal_child(self.get_folded())
self.connect("notify::folded", folded_changed)
scrolled_window = Gtk.ScrolledWindow()
self.grid = AlbumsGrid()
self.grid.connect(
"song-clicked",
lambda _, *args: self.emit("song-clicked", *args),
)
self.grid.connect(
"refresh-window",
lambda _, *args: self.emit("refresh-window", *args),
)
self.grid.connect("cover-clicked", self.on_grid_cover_clicked)
self.grid.connect("num-pages-changed", self.on_grid_num_pages_changed)
scrolled_window.add(self.grid)
self.add(scrolled_window)
def make_combobox(
self,
@@ -234,7 +299,7 @@ class AlbumsPanel(Gtk.Box):
except Exception:
self.updating_query = False
def update(self, app_config: AppConfiguration = None, force: bool = False):
def update(self, app_config: AppConfiguration, force: bool = False):
self.updating_query = True
supported_type_strings = {
@@ -246,9 +311,38 @@ class AlbumsPanel(Gtk.Box):
# (En|Dis)able getting genres.
self.sort_type_combo_store[1][2] = AdapterManager.can_get_genres()
if app_config:
if (self.current_query != app_config.state.current_album_search_query
or self.offline_mode != app_config.offline_mode
or self.provider_id != app_config.current_provider_id):
self.current_query = app_config.state.current_album_search_query
self.offline_mode = app_config.offline_mode
self.provider_id = app_config.current_provider_id
if self.current_albums_result is not None:
self.current_albums_result.cancel()
self.current_albums_result = AdapterManager.get_albums(
self.current_query, use_ground_truth_adapter=force)
if self.current_albums_result.data_is_available:
# Don't idle add if the data is already available.
self.current_albums_result.add_done_callback(self._albums_loaded)
else:
# self.spinner.show()
self.current_albums_result.add_done_callback(
lambda f: GLib.idle_add(self._albums_received, f)
)
if (self.album_sort_direction != app_config.state.album_sort_direction
or self.album_page != app_config.state.album_page):
self.album_sort_direction = app_config.state.album_sort_direction
self.album_page = app_config.state.album_page
self._update_albums()
# self.current_query = app_config.state.current_album_search_query
# self.offline_mode = app_config.offline_mode
self.alphabetical_type_combo.set_active_id(
{
@@ -266,7 +360,6 @@ class AlbumsPanel(Gtk.Box):
# Update the page display
if app_config:
self.album_page = app_config.state.album_page
self.album_page_size = app_config.state.album_page_size
self.refresh_button.set_sensitive(not app_config.offline_mode)
self.prev_page.set_sensitive(self.album_page > 0)
@@ -309,16 +402,93 @@ class AlbumsPanel(Gtk.Box):
+ self._get_opposite_sort_dir(self.album_sort_direction)
)
self.show_count_dropdown.set_active_id(
str(app_config.state.album_page_size)
)
# Has to be last because it resets self.updating_query
self.populate_genre_combo(app_config, force=force)
# At this point, the current query should be totally updated.
self.grid_order_token = self.grid.update_params(app_config)
self.grid.update(self.grid_order_token, app_config, force=force)
selected_album = self.albums_by_id.get(app_config.state.selected_album_id, None)
self.album_with_songs.update(selected_album, app_config, force=force)
def _albums_loaded(self, result: Result[Iterable[API.Album]]):
self.current_albums_result = None
# TODO: Error handling
self.albums = []
try:
self.albums = list(result.result())
except CacheMissError as e:
print(e)
except Exception as e:
print(e)
self.albums_by_id = {album.id: album for album in self.albums}
self._update_albums()
def _update_albums(self):
# Update ordering
if self.album_sort_direction == "descending":
self.albums.reverse()
# TODO: Update instead of re-create
for child in self.grid.get_children():
self.grid.remove(child)
for album in self.albums:
self.grid.add(self._create_cover_art_widget(album))
def _make_label(self, text: str, name: str) -> Gtk.Label:
return Gtk.Label(
name=name,
label=text,
tooltip_text=text,
ellipsize=Pango.EllipsizeMode.END,
max_width_chars=22,
halign=Gtk.Align.START,
)
def _create_cover_art_widget(self, album) -> Gtk.Box:
widget_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
# Cover art image
artwork = SpinnerImage(
loading=False,
image_name="grid-artwork",
spinner_name="grid-artwork-spinner",
image_size=200,
)
widget_box.pack_start(artwork, False, False, 0)
# Header for the widget
header_label = self._make_label(album.name, "grid-header-label")
widget_box.pack_start(header_label, False, False, 0)
# Extra info for the widget
info_text = util.dot_join(
album.artist.name if album.artist else "-", album.year
)
if info_text:
info_label = self._make_label(info_text, "grid-info-label")
widget_box.pack_start(info_label, False, False, 0)
# Download the cover art.
def on_artwork_downloaded(filename: Result[str]):
artwork.set_from_file(filename.result())
artwork.set_loading(False)
cover_art_filename_future = AdapterManager.get_cover_art_uri(
album.cover_art, "file"
)
if cover_art_filename_future.data_is_available:
on_artwork_downloaded(cover_art_filename_future)
else:
artwork.set_loading(True)
cover_art_filename_future.add_done_callback(
lambda f: GLib.idle_add(on_artwork_downloaded, f)
)
widget_box.show_all()
return widget_box
def _get_opposite_sort_dir(self, sort_dir: str) -> str:
return ("ascending", "descending")[0 if sort_dir == "descending" else 1]
@@ -469,10 +639,15 @@ class AlbumsPanel(Gtk.Box):
False,
)
def on_grid_cover_clicked(self, grid: Any, id: str):
def on_album_clicked(self, _:Any, child: Gtk.FlowBoxChild):
album = self.albums[child.get_index()]
if self.get_folded() and self.get_visible_child() == self.grid_box:
self.set_visible_child(self.details_box)
self.emit(
"refresh-window",
{"selected_album_id": id},
{"selected_album_id": album.id},
False,
)