[gnome-music/wip/mschraal/albumview-covers-on-demand: 12/14] albumsview: Load covers on demand
- From: Jean Felder <jfelder src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/mschraal/albumview-covers-on-demand: 12/14] albumsview: Load covers on demand
- Date: Mon, 4 Nov 2019 13:44:33 +0000 (UTC)
commit a6ba6068b1949f09455f78b84245e5b379f2aff6
Author: Marinus Schraal <mschraal gnome org>
Date: Fri Oct 18 17:03:01 2019 +0200
albumsview: Load covers on demand
Loading all covers on startup is a very demanding task, especially on a
fresh install. Previously Music was using a delayed loading hack, but it
was still resource intensive and suboptimal.
Instead load covers on demand. GTK does not currently provide a proper
way of doing this, so the implementation is hackish.
gnomemusic/views/albumsview.py | 57 +++++++++++++++++++++++++++++++++++++++-
gnomemusic/views/searchview.py | 1 +
gnomemusic/widgets/albumcover.py | 23 +++++++++-------
3 files changed, 71 insertions(+), 10 deletions(-)
---
diff --git a/gnomemusic/views/albumsview.py b/gnomemusic/views/albumsview.py
index c0f70a91..9d32b197 100644
--- a/gnomemusic/views/albumsview.py
+++ b/gnomemusic/views/albumsview.py
@@ -22,8 +22,10 @@
# code, but you are not obligated to do so. If you do not wish to do so,
# delete this exception statement from your version.
+import math
+
from gettext import gettext as _
-from gi.repository import GObject, Gtk
+from gi.repository import GLib, GObject, Gtk
from gnomemusic.widgets.headerbar import HeaderBar
from gnomemusic.widgets.albumcover import AlbumCover
@@ -62,6 +64,8 @@ class AlbumsView(Gtk.Stack):
self._window = application.props.window
self._headerbar = self._window._headerbar
+ self._timeout_id = None
+ self._viewport = self._all_albums.get_child()
model = self._window._app.props.coremodel.props.albums_sort
self._flowbox.bind_model(model, self._create_widget)
@@ -83,8 +87,59 @@ class AlbumsView(Gtk.Stack):
self.connect(
"notify::search-mode-active", self._on_search_mode_changed)
+ self._all_albums.props.vadjustment.connect(
+ "value-changed", self._on_vadjustment_changed)
+ self._all_albums.props.vadjustment.connect(
+ "changed", self._on_vadjustment_changed)
+
self.show_all()
+ def _on_vadjustment_changed(self, adjustment):
+ if self._timeout_id is not None:
+ GLib.source_remove(self._timeout_id)
+ self._timeout_id = None
+
+ self._timeout_id = GLib.timeout_add(
+ 200, self._retrieve_covers, adjustment.props.value,
+ priority=GLib.PRIORITY_LOW)
+
+ def _retrieve_covers(self, old_adjustment):
+ adjustment = self._all_albums.props.vadjustment.props.value
+
+ if old_adjustment != adjustment:
+ return GLib.SOURCE_CONTINUE
+
+ # This is blatant hack to get the top left AlbumCover. It polls
+ # the flowbox twice if needed to handle possible margins
+ # between AlbumCovers.
+ top_left_cover = self._flowbox.get_child_at_pos(100, adjustment + 100)
+ if not top_left_cover:
+ top_left_cover = self._flowbox.get_child_at_pos(
+ 50, adjustment + 50)
+ if not top_left_cover:
+ return GLib.SOURCE_CONTINUE
+
+ cover_size, _ = top_left_cover.get_allocated_size()
+ viewport_size, _ = self._viewport.get_allocated_size()
+
+ covers_row = math.ceil(viewport_size.width / cover_size.width)
+ covers_col = math.ceil(viewport_size.height / cover_size.height)
+
+ children = self._flowbox.get_children()
+ retrieve_list = []
+ for i, albumcover in enumerate(children):
+ if top_left_cover == albumcover:
+ retrieve_covers = covers_row * covers_col
+ retrieve_list = children[i:i + retrieve_covers]
+ break
+
+ for albumcover in retrieve_list:
+ albumcover.retrieve()
+
+ self._timeout_id = None
+
+ return GLib.SOURCE_REMOVE
+
def _on_selection_mode_changed(self, widget, data=None):
if not self.props.selection_mode:
self.unselect_all()
diff --git a/gnomemusic/views/searchview.py b/gnomemusic/views/searchview.py
index 0cc31c56..40ed115b 100644
--- a/gnomemusic/views/searchview.py
+++ b/gnomemusic/views/searchview.py
@@ -160,6 +160,7 @@ class SearchView(Gtk.Stack):
def _create_album_widget(self, corealbum):
album_widget = AlbumCover(corealbum)
+ album_widget.retrieve()
self.bind_property(
"selection-mode", album_widget, "selection-mode",
diff --git a/gnomemusic/widgets/albumcover.py b/gnomemusic/widgets/albumcover.py
index ae6b82f8..7b9cfaa7 100644
--- a/gnomemusic/widgets/albumcover.py
+++ b/gnomemusic/widgets/albumcover.py
@@ -24,7 +24,7 @@
import gi
gi.require_version('Grl', '0.3')
-from gi.repository import Gdk, GLib, GObject, Gtk
+from gi.repository import Gdk, GObject, Gtk
from gnomemusic import log
from gnomemusic.albumartcache import Art
@@ -68,6 +68,7 @@ class AlbumCover(Gtk.FlowBoxChild):
AlbumCover._nr_albums += 1
self._corealbum = corealbum
+ self._retrieved = False
self._tooltip = TwoLineTip()
@@ -96,16 +97,20 @@ class AlbumCover(Gtk.FlowBoxChild):
self.show()
- # FIXME: To work around slow updating of the albumsview,
- # load album covers with a fixed delay. This results in a
- # quick first show with a placeholder cover and then a
- # reasonably responsive view while loading the actual
- # covers.
self._update_cover_id = self._cover_stack.connect(
"updated", self._on_cover_stack_updated)
- GLib.timeout_add(
- 50 * self._nr_albums, self._cover_stack.update, self._corealbum,
- priority=GLib.PRIORITY_LOW)
+
+ def retrieve(self):
+ """Start retrieving the actual album cover
+
+ Cover retrieval is an expensive operation, so use this call to
+ start the retrieval process when needed.
+ """
+ if self._retrieved:
+ return
+
+ self._retrieved = True
+ self._cover_stack.update(self._corealbum)
@GObject.Property(type=CoreAlbum, flags=GObject.ParamFlags.READABLE)
def corealbum(self):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]