Fixed going to album in offline mode
This commit is contained in:
@@ -31,34 +31,41 @@ Features
|
||||
@samsartor for contributing the SVGs!
|
||||
* A new icon for indicating the connection state to the Subsonic server.
|
||||
Contributed by @samsartor.
|
||||
* A new icon for that data wasn't able to be loaded due to being offline.
|
||||
Contributed by @samsartor.
|
||||
|
||||
**Settings**
|
||||
**Application Menus**
|
||||
|
||||
* Settings are now in the popup under the gear icon rather than in a separate
|
||||
popup window.
|
||||
* The music provider configuration has gotten a major revamp.
|
||||
* You can now clear the cache via an option in the Downloads popup. There are
|
||||
options for removing the entire cache and removing just the song file cache.
|
||||
|
||||
.. * The music provider configuration has gotten a major revamp.
|
||||
.. * The Downloads popup shows the songs that are currently being downloaded.
|
||||
.. *
|
||||
|
||||
**Offline Mode**
|
||||
|
||||
* You can enable *Offline Mode* from the server menu.
|
||||
* Features that require network access are disabled in offline mode.
|
||||
* You can still browse anything that is already cached offline.
|
||||
|
||||
.. MENTION man page
|
||||
**Other Features**
|
||||
|
||||
.. * A man page has been added. Contributed by @baldurmen.
|
||||
|
||||
Under The Hood
|
||||
--------------
|
||||
|
||||
This release has a ton of under-the-hood changes to make things more robust
|
||||
and performant.
|
||||
This release has a ton of under-the-hood changes to make things more robust
|
||||
and performant.
|
||||
|
||||
* The cache is now stored in a SQLite database.
|
||||
* The cache no longer gets corrupted when Sublime Music fails to write to
|
||||
disk.
|
||||
* A generic `Adapter API`_ has been created which means that Sublime Music is
|
||||
no longer reliant on Subsonic and in the future, more backends can be added.
|
||||
* The cache is now stored in a SQLite database.
|
||||
* The cache no longer gets corrupted when Sublime Music fails to write to disk.
|
||||
* A generic `Adapter API`_ has been created which means that Sublime Music is no
|
||||
longer reliant on Subsonic. This means that in the future, more backends can
|
||||
be added.
|
||||
|
||||
.. _Adapter API: https://sumner.gitlab.io/sublime-music/adapter-api.html
|
||||
|
||||
|
@@ -114,15 +114,15 @@ class AlbumSearchQuery:
|
||||
... AlbumSearchQuery.Type.YEAR_RANGE, year_range=(2018, 2019)
|
||||
... )
|
||||
>>> query.strhash()
|
||||
'a6571bb7be65984c6627f545cab9fc767fce6d07'
|
||||
'5b0724ae23acd58bc2f9187617712775670e0b98'
|
||||
"""
|
||||
if not self._strhash:
|
||||
self._strhash = hashlib.sha1(
|
||||
bytes(
|
||||
json.dumps((self.type.value, self.year_range, self.genre.name)),
|
||||
"utf8",
|
||||
)
|
||||
).hexdigest()
|
||||
hash_tuple: Tuple[Any, ...] = (self.type.value,)
|
||||
if self.type.value == AlbumSearchQuery.Type.YEAR_RANGE:
|
||||
hash_tuple += (self.year_range,)
|
||||
elif self.type.value == AlbumSearchQuery.Type.GENRE:
|
||||
hash_tuple += (self.genre.name,)
|
||||
self._strhash = hashlib.sha1(bytes(str(hash_tuple), "utf8")).hexdigest()
|
||||
return self._strhash
|
||||
|
||||
|
||||
|
@@ -653,7 +653,7 @@ class SublimeMusicApp(Gtk.Application):
|
||||
|
||||
self.app_config.state.current_tab = "albums"
|
||||
self.app_config.state.selected_album_id = album_id.get_string()
|
||||
self.update_window(force=True)
|
||||
self.update_window()
|
||||
|
||||
def on_go_to_artist(self, action: Any, artist_id: GLib.Variant):
|
||||
self.app_config.state.current_tab = "artists"
|
||||
|
@@ -554,7 +554,7 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
halign=Gtk.Align.CENTER,
|
||||
selection_mode=Gtk.SelectionMode.SINGLE,
|
||||
)
|
||||
flowbox.set_max_children_per_line(10)
|
||||
flowbox.set_max_children_per_line(7)
|
||||
return flowbox
|
||||
|
||||
self.grid_top = create_flowbox()
|
||||
@@ -658,11 +658,9 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
if self.sort_dir == "descending" and selected_index:
|
||||
selected_index = len(self.current_models) - selected_index - 1
|
||||
|
||||
selection_changed = selected_index != self.currently_selected_index
|
||||
self.currently_selected_index = selected_index
|
||||
self.reflow_grids(
|
||||
force_reload_from_master=force_grid_reload_from_master,
|
||||
selection_changed=selection_changed,
|
||||
selected_index=selected_index,
|
||||
models=self.current_models,
|
||||
)
|
||||
self.spinner.hide()
|
||||
@@ -703,7 +701,10 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
|
||||
for c in self.error_container.get_children():
|
||||
self.error_container.remove(c)
|
||||
if is_partial and self.current_query.type != AlbumSearchQuery.Type.RANDOM:
|
||||
if is_partial and (
|
||||
len(albums) == 0
|
||||
or self.current_query.type != AlbumSearchQuery.Type.RANDOM
|
||||
):
|
||||
load_error = LoadError(
|
||||
"Album list",
|
||||
"load albums",
|
||||
@@ -779,14 +780,17 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
# add extra padding.
|
||||
# 200 + (10 * 2) + (5 * 2) = 230
|
||||
# picture + (padding * 2) + (margin * 2)
|
||||
new_items_per_row = min((rect.width // 230), 10)
|
||||
new_items_per_row = min((rect.width // 230), 7)
|
||||
if new_items_per_row != self.items_per_row:
|
||||
self.items_per_row = new_items_per_row
|
||||
self.detail_box_inner.set_size_request(
|
||||
self.items_per_row * 230 - 10, -1,
|
||||
)
|
||||
|
||||
self.reflow_grids(force_reload_from_master=True)
|
||||
self.reflow_grids(
|
||||
force_reload_from_master=True,
|
||||
selected_index=self.currently_selected_index,
|
||||
)
|
||||
|
||||
# Helper Methods
|
||||
# =========================================================================
|
||||
@@ -846,17 +850,18 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
def reflow_grids(
|
||||
self,
|
||||
force_reload_from_master: bool = False,
|
||||
selection_changed: bool = False,
|
||||
selected_index: int = None,
|
||||
models: List[_AlbumModel] = None,
|
||||
):
|
||||
# Calculate the page that the currently_selected_index is in. If it's a
|
||||
# different page, then update the window.
|
||||
page_changed = False
|
||||
if self.currently_selected_index is not None:
|
||||
page_of_selected_index = self.currently_selected_index // self.page_size
|
||||
if selected_index is not None:
|
||||
page_of_selected_index = selected_index // self.page_size
|
||||
if page_of_selected_index != self.page:
|
||||
page_changed = True
|
||||
self.page = page_of_selected_index
|
||||
self.emit(
|
||||
"refresh-window", {"album_page": page_of_selected_index}, False
|
||||
)
|
||||
return
|
||||
page_offset = self.page_size * self.page
|
||||
|
||||
# Calculate the look-at window.
|
||||
@@ -874,14 +879,14 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
|
||||
# Determine where the cuttoff is between the top and bottom grids.
|
||||
entries_before_fold = self.page_size
|
||||
if self.currently_selected_index is not None and self.items_per_row:
|
||||
relative_selected_index = self.currently_selected_index - page_offset
|
||||
if selected_index is not None and self.items_per_row:
|
||||
relative_selected_index = selected_index - page_offset
|
||||
entries_before_fold = (
|
||||
(relative_selected_index // self.items_per_row) + 1
|
||||
) * self.items_per_row
|
||||
|
||||
# Unreveal the current album details first
|
||||
if self.currently_selected_index is None:
|
||||
if selected_index is None:
|
||||
self.detail_box_revealer.set_reveal_child(False)
|
||||
|
||||
if force_reload_from_master:
|
||||
@@ -893,7 +898,7 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
self.list_store_bottom.splice(
|
||||
0, len(self.list_store_bottom), window[entries_before_fold:],
|
||||
)
|
||||
elif self.currently_selected_index or entries_before_fold != self.page_size:
|
||||
elif selected_index or entries_before_fold != self.page_size:
|
||||
# This case handles when the selection changes and the entries need to be
|
||||
# re-allocated to the top and bottom grids
|
||||
# Move entries between the two stores.
|
||||
@@ -913,14 +918,14 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
self.list_store_bottom.splice(0, 0, self.list_store_top[-diff:])
|
||||
self.list_store_top.splice(top_store_len - diff, diff, [])
|
||||
|
||||
if self.currently_selected_index is not None:
|
||||
relative_selected_index = self.currently_selected_index - page_offset
|
||||
if selected_index is not None:
|
||||
relative_selected_index = selected_index - page_offset
|
||||
to_select = self.grid_top.get_child_at_index(relative_selected_index)
|
||||
if not to_select:
|
||||
return
|
||||
self.grid_top.select_child(to_select)
|
||||
|
||||
if not selection_changed:
|
||||
if self.currently_selected_index == selected_index:
|
||||
return
|
||||
|
||||
for c in self.detail_box_inner.get_children():
|
||||
@@ -944,9 +949,4 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
self.grid_top.unselect_all()
|
||||
self.grid_bottom.unselect_all()
|
||||
|
||||
# If we had to change the page to select the index, then update the window. It
|
||||
# should basically be a no-op.
|
||||
if page_changed:
|
||||
self.emit(
|
||||
"refresh-window", {"album_page": self.page}, False,
|
||||
)
|
||||
self.currently_selected_index = selected_index
|
||||
|
@@ -556,6 +556,9 @@ class PlaylistDetailPanel(Gtk.Overlay):
|
||||
# and the expensive parts of the second loop are avoided if the IDs haven't
|
||||
# changed.
|
||||
song_ids, songs = [], []
|
||||
if len(self._current_song_ids) != len(playlist.songs):
|
||||
force = True
|
||||
|
||||
for i, c in enumerate(playlist.songs):
|
||||
if i >= len(self._current_song_ids) or c.id != self._current_song_ids[i]:
|
||||
force = True
|
||||
|
Reference in New Issue
Block a user