@@ 5,6 5,7 @@ gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw, Gio, Gdk, GLib
from unidecode import unidecode
from gettext import gettext as _
+import threading
from melon.servers.utils import get_server_instance, get_servers_list
from melon.servers.utils import pixbuf_from_url
@@ 16,14 17,25 @@ from melon.models import get_app_settings
from melon.models import is_subscribed_to_channel, ensure_subscribed_to_channel, ensure_unsubscribed_from_channel
class BrowseChannelScreen(Adw.NavigationPage):
- def fetch_page(self, page=1):
- feed_id = self.current_feed
- cont = self.instance.get_channel_feed_content(self.channel_id, feed_id)
+ def display_page(self, cont):
+ """
+ Display the channel feed page
+ """
app_conf = get_app_settings()
+ self.results.set_header_suffix(None)
for res in cont:
self.results.add(AdaptiveFeedItem(res, show_preview=app_conf["show_images_in_browse"]))
-
+ def fetch_page(self, page=1):
+ """
+ Fetch feed information
+ """
+ feed_id = self.current_feed
+ cont = self.instance.get_channel_feed_content(self.channel.id, feed_id)
+ GLib.idle_add(self.display_page, cont)
def change_feed(self, feed_id):
+ """
+ change the feed and prepare layout
+ """
self.current_feed = feed_id
if not self.results is None:
self.box.remove(self.results)
@@ 34,9 46,17 @@ class BrowseChannelScreen(Adw.NavigationPage):
feed_name = feed.name
break
self.results.set_title(feed_name)
+ spinner = Gtk.Spinner()
+ spinner.set_size_request(20, 20)
+ spinner.start()
+ self.results.set_header_suffix(spinner)
self.results.set_vexpand(True)
self.box.add(self.results)
- self.fetch_page()
+ # fetch page on new thread
+ self.thread = threading.Thread(target=self.fetch_page)
+ self.thread.daemon = True
+ self.thread.start()
+
def change_feed_wrapper(self, feed_name):
for feed in self.feeds:
if feed.name == feed_name:
@@ 44,53 64,27 @@ class BrowseChannelScreen(Adw.NavigationPage):
break
def on_open_in_browser(self, arg):
Gtk.UriLauncher.new(uri=self.channel.url).launch()
- def __init__(self, server_id, channel_id, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.channel_id = channel_id
- # get instance handle
- server = get_servers_list()[server_id]
- self.instance = get_server_instance(server)
- # obtain channel information
- channel = self.instance.get_channel_info(channel_id)
- self.channel = channel
- self.set_title(unidecode(channel.name))
-
- self.header_bar = Adw.HeaderBar()
- self.external_btn = IconButton("","modem-symbolic")
- self.external_btn.connect("clicked", self.on_open_in_browser)
- self.header_bar.pack_end(self.external_btn)
- self.toolbar_view = Adw.ToolbarView()
- self.toolbar_view.add_top_bar(self.header_bar)
-
- self.wrapper = Adw.Clamp()
- self.scrollview = Gtk.ScrolledWindow()
+ def display_info(self, texture):
+ # base layout
self.box = Adw.PreferencesPage()
self.about = Adw.PreferencesGroup()
- self.about.set_title(unidecode(channel.name).replace("&", "&"))
- self.about.set_description(unidecode(channel.bio).replace("&", "&"))
-
self.results = None
-
- # we have to append all the neccessary elements here,
- # because if there are no channel feeds this function will exit early
- self.scrollview.set_child(self.box)
- self.wrapper.set_child(self.scrollview)
- self.toolbar_view.set_content(self.wrapper)
- self.set_child(self.toolbar_view)
self.box.add(self.about)
+ self.scrollview.set_child(self.box)
+
+ # update meta
+ self.set_title(unidecode(self.channel.name))
+ self.about.set_title(unidecode(self.channel.name).replace("&", "&"))
+ self.about.set_description(unidecode(self.channel.bio).replace("&", "&"))
# display channel info
- app_conf = get_app_settings()
av = Adw.Avatar()
av.set_size(64)
- if app_conf["show_images_in_browse"]:
- pixbuf = pixbuf_from_url(channel.avatar)
- if not pixbuf is None:
- texture = Gdk.Texture.new_for_pixbuf(pixbuf)
- av.set_custom_image(texture)
- else:
- av.set_text(channel.name)
+ if not texture is None:
+ av.set_custom_image(texture)
+ else:
+ av.set_text(self.channel.name)
self.about.set_header_suffix(av)
# add (un)subscribe button
@@ 100,42 94,96 @@ class BrowseChannelScreen(Adw.NavigationPage):
_("Add latest uploads to home feed"),
PreferenceType.TOGGLE,
False,
- is_subscribed_to_channel(self.channel.server, self.channel_id)
+ is_subscribed_to_channel(self.channel.server, self.channel.id)
)
sub_row = PreferenceRow(sub_pref)
sub_row.set_callback(self.update_sub)
self.about.add(sub_row.get_widget())
+ def display_feedselect(self):
+ pref = Preference(
+ "channel-feed",
+ _("Channel feed"),
+ _("This channel provides multiple feeds, choose which one to view"),
+ PreferenceType.DROPDOWN,
+ [ feed.name for feed in self.feeds ],
+ self.default_feed_name
+ )
+ # display preference
+ row = PreferenceRow(pref)
+ row.set_callback(self.change_feed_wrapper)
+ self.about.add(row.get_widget())
+
+ def background(self, channel_id):
+ # obtain channel information
+ self.channel = self.instance.get_channel_info(channel_id)
+ app_conf = get_app_settings()
+ pixbuf = None
+ if app_conf["show_images_in_browse"]:
+ pixbuf = pixbuf_from_url(self.channel.avatar)
+ texture = None
+ if not pixbuf is None:
+ texture = Gdk.Texture.new_for_pixbuf(pixbuf)
+ GLib.idle_add(self.display_info, texture)
+
# get channel feeds
- feeds = self.instance.get_channel_feeds(self.channel_id)
+ feeds = self.instance.get_channel_feeds(channel_id)
self.feeds = feeds
if len(feeds) == 0:
# if the channel doesn't have any feeds, we are done here
return
default_feed = feeds[0].id
- if len(feeds) > 1:
- default_feed = self.instance.get_default_channel_feed(self.channel_id)
- # ONLY DISPLAY FEED-SELECT IF FEEDCOUNT > 1
- # construct preference to select feed
- default_name = ""
- for feed in feeds:
- if feed.id == default_feed:
- default_name = feed.name
- break
- pref = Preference(
- "channel-feed",
- _("Channel feed"),
- _("This channel provides multiple feeds, choose which one to view"),
- PreferenceType.DROPDOWN,
- [ feed.name for feed in feeds ],
- default_name
- )
- # display preference
- row = PreferenceRow(pref)
- row.set_callback(self.change_feed_wrapper)
- self.about.add(row.get_widget())
-
- self.change_feed(default_feed)
+ default_feed = self.instance.get_default_channel_feed(channel_id)
+ # ONLY DISPLAY FEED-SELECT IF FEEDCOUNT > 1
+ # construct preference to select feed
+ default_name = ""
+ for feed in feeds:
+ if feed.id == default_feed:
+ default_name = feed.name
+ break
+ self.default_feed_name = default_name
+ GLib.idle_add(self.display_feedselect)
+
+ # run feed layout prep on main thread
+ # a new thread will be spawned there
+ GLib.idle_add(self.change_feed, default_feed)
+
+ def __init__(self, server_id, channel_id, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.channel_id = channel_id
+ # get instance handle
+ server = get_servers_list()[server_id]
+ self.instance = get_server_instance(server)
+
+ self.header_bar = Adw.HeaderBar()
+ self.external_btn = IconButton("","modem-symbolic")
+ self.external_btn.connect("clicked", self.on_open_in_browser)
+ self.header_bar.pack_end(self.external_btn)
+
+ self.toolbar_view = Adw.ToolbarView()
+ self.toolbar_view.add_top_bar(self.header_bar)
+
+ self.wrapper = Adw.Clamp()
+ self.scrollview = Gtk.ScrolledWindow()
+
+ # show spinner
+ # will be cleared by display_info
+ spinner = Gtk.Spinner()
+ spinner.set_size_request(50, 50)
+ spinner.start()
+ cb = Gtk.CenterBox()
+ cb.set_center_widget(spinner)
+ self.scrollview.set_child(cb)
+
+ self.wrapper.set_child(self.scrollview)
+ self.toolbar_view.set_content(self.wrapper)
+ self.set_child(self.toolbar_view)
+
+ # start background thread
+ self.thread = threading.Thread(target=self.background, args=[channel_id])
+ self.thread.daemon = True
+ self.thread.start()
+
def update_sub(self, subscribe):
if subscribe:
ensure_subscribed_to_channel(self.channel)
@@ 5,6 5,7 @@ gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw, Gio, Gdk, GLib
from unidecode import unidecode
from gettext import gettext as _
+import threading
from melon.servers.utils import get_server_instance, get_servers_list
from melon.servers.utils import pixbuf_from_url
@@ 16,10 17,69 @@ from melon.models import get_app_settings
from melon.models import has_bookmarked_external_playlist, ensure_bookmark_external_playlist, ensure_unbookmark_external_playlist
class BrowsePlaylistScreen(Adw.NavigationPage):
- def fetch_page(self, page=1):
+ def render_page(self, items):
+ app_conf = get_app_settings()
+ for res in items:
+ self.results.add(AdaptiveFeedItem(res, show_preview=app_conf["show_images_in_browse"]))
+ def fetch_page(self, page=0):
cont = self.instance.get_playlist_content(self.playlist_id)
- for res in cont:
- self.results.add(AdaptiveFeedItem(res))
+ GLib.idle_add(self.render_page, cont)
+ def do_fetch_page(self, page=0):
+ # start background thread
+ self.thread = threading.Thread(target=self.fetch_page, args=[page])
+ self.thread.daemon = True
+ self.thread.start()
+
+ def display_info(self, texture):
+ # base layout
+ self.box = Adw.PreferencesPage()
+ self.about = Adw.PreferencesGroup()
+ self.about.set_title(unidecode(self.playlist.title))
+ self.about.set_description(unidecode(self.playlist.description))
+ self.set_title(self.playlist.title)
+
+ self.results = None
+ self.scrollview.set_child(self.box)
+ self.box.add(self.about)
+
+ bookmark_pref = Preference(
+ "bookmark-playlist",
+ _("Bookmark"),
+ _("Add Playlist to your local playlist collection"),
+ PreferenceType.TOGGLE,
+ False,
+ has_bookmarked_external_playlist(self.playlist.server, self.playlist.id))
+ bookmark_row = PreferenceRow(bookmark_pref)
+ bookmark_row.set_callback(self.bookmark_playlist)
+ self.about.add(bookmark_row.get_widget())
+
+ # display channel info
+ av = Adw.Avatar()
+ av.set_size(64)
+ if not texture is None:
+ av.set_custom_image(texture)
+ else:
+ av.set_text(self.playlist.title)
+ self.about.set_header_suffix(av)
+
+ self.results = Adw.PreferencesGroup()
+ self.box.add(self.results)
+
+
+ def background(self, playlist_id):
+ # obtain playlist information
+ self.playlist = self.instance.get_playlist_info(playlist_id)
+ app_conf = get_app_settings()
+ pixbuf = None
+ if app_conf["show_images_in_browse"]:
+ pixbuf = pixbuf_from_url(self.playlist.thumbnail)
+ texture = None
+ if not pixbuf is None:
+ texture = Gdk.Texture.new_for_pixbuf(pixbuf)
+ GLib.idle_add(self.display_info, texture)
+
+ # load first page
+ GLib.idle_add(self.do_fetch_page)
def on_open_in_browser(self, arg):
Gtk.UriLauncher.new(uri=self.playlist.url).launch()
@@ 37,9 97,6 @@ class BrowsePlaylistScreen(Adw.NavigationPage):
# get instance handle
server = get_servers_list()[server_id]
self.instance = get_server_instance(server)
- # obtain channel information
- self.playlist = self.instance.get_playlist_info(playlist_id)
- self.set_title(self.playlist.title)
self.header_bar = Adw.HeaderBar()
self.external_btn = IconButton("","modem-symbolic")
@@ 51,45 108,21 @@ class BrowsePlaylistScreen(Adw.NavigationPage):
self.wrapper = Adw.Clamp()
self.scrollview = Gtk.ScrolledWindow()
- self.box = Adw.PreferencesPage()
- self.about = Adw.PreferencesGroup()
- self.about.set_title(unidecode(self.playlist.title))
- self.about.set_description(unidecode(self.playlist.description))
- bookmark_pref = Preference(
- "bookmark-playlist",
- _("Bookmark"),
- _("Add Playlist to your local playlist collection"),
- PreferenceType.TOGGLE,
- False,
- has_bookmarked_external_playlist(server_id, playlist_id))
- bookmark_row = PreferenceRow(bookmark_pref)
- bookmark_row.set_callback(self.bookmark_playlist)
- self.about.add(bookmark_row.get_widget())
-
- self.results = None
+ # show spinner
+ # will be cleared by display_info
+ spinner = Gtk.Spinner()
+ spinner.set_size_request(50, 50)
+ spinner.start()
+ cb = Gtk.CenterBox()
+ cb.set_center_widget(spinner)
+ self.scrollview.set_child(cb)
- # we have to append all the neccessary elements here,
- # because if there are no channel feeds this function will exit early
- self.scrollview.set_child(self.box)
self.wrapper.set_child(self.scrollview)
self.toolbar_view.set_content(self.wrapper)
self.set_child(self.toolbar_view)
- self.box.add(self.about)
-
- # display channel info
- app_conf = get_app_settings()
- av = Adw.Avatar()
- av.set_size(64)
- if app_conf["show_images_in_browse"]:
- pixbuf = pixbuf_from_url(self.playlist.thumbnail)
- if not pixbuf is None:
- texture = Gdk.Texture.new_for_pixbuf(pixbuf)
- av.set_custom_image(texture)
- else:
- av.set_text(self.playlist.title)
- self.about.set_header_suffix(av)
- self.results = Adw.PreferencesGroup()
- self.box.add(self.results)
- self.fetch_page()
+ # start background thread
+ self.thread = threading.Thread(target=self.background, args=[playlist_id])
+ self.thread.daemon = True
+ self.thread.start()