diff --git a/share/gpodder/ui/gtk/gpodder.ui b/share/gpodder/ui/gtk/gpodder.ui
index a14b8331..abb3df6d 100644
--- a/share/gpodder/ui/gtk/gpodder.ui
+++ b/share/gpodder/ui/gtk/gpodder.ui
@@ -175,7 +175,9 @@
True
GTK_POLICY_AUTOMATIC
GTK_POLICY_AUTOMATIC
- True
+ True
+ True
+
GTK_SHADOW_IN
GTK_CORNER_TOP_LEFT
@@ -214,56 +216,6 @@
-
-
-
False
diff --git a/share/gpodder/ui/gtk/menus.ui b/share/gpodder/ui/gtk/menus.ui
index c2c30093..4d891347 100644
--- a/share/gpodder/ui/gtk/menus.ui
+++ b/share/gpodder/ui/gtk/menus.ui
@@ -43,6 +43,10 @@
Check for new episodes
<Primary>r
+ -
+ win.cancelFeedUpdate
+ Cancel check for new episodes
+
-
win.downloadAllNew
Download new episodes
diff --git a/src/gpodder/gtkui/app.py b/src/gpodder/gtkui/app.py
index cc525b28..710a9f37 100644
--- a/src/gpodder/gtkui/app.py
+++ b/src/gpodder/gtkui/app.py
@@ -145,7 +145,25 @@ class gPodderApplication(Gtk.Application):
self.want_headerbar = ('GNOME' in xdg_current_desktops) and not gpodder.ui.osx and not csd_disabled
+ self.header_bar_refresh_button = Gtk.Button.new_from_icon_name('view-refresh-symbolic', Gtk.IconSize.SMALL_TOOLBAR)
+
+ # TODO: In Gtk 4, Gtk.Button.set_icon_name() is a thing, so this can probably be removed once we migrate
+ def _set_icon_name_patch(icon_name):
+ self.header_bar_refresh_button.set_image(Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.SMALL_TOOLBAR))
+
+ self.header_bar_refresh_button.set_icon_name = _set_icon_name_patch
+ self.header_bar_refresh_button.set_action_name('win.update')
+
+ self.header_bar_refresh_ui = Gtk.Grid()
+
+ self.header_bar_menu_button = Gtk.Button.new_from_icon_name('open-menu-symbolic', Gtk.IconSize.SMALL_TOOLBAR)
+ self.header_bar_menu_button.set_action_name('app.menu')
+
self.app_menu = builder.get_object('app-menu')
+
+ self.menu_popover = Gtk.Popover.new_from_model(self.header_bar_menu_button, self.app_menu)
+ self.menu_popover.set_position(Gtk.PositionType.BOTTOM)
+
if self.want_headerbar:
# This is a dirty hack to remove the "Quit" item in the menu
it = self.app_menu.iterate_item_links(2)
@@ -153,14 +171,6 @@ class gPodderApplication(Gtk.Application):
it.get_value().remove(2)
# Use GtkHeaderBar for client-side decorations on recent GNOME 3 versions
- self.header_bar_menu_button = Gtk.Button.new_from_icon_name('open-menu-symbolic', Gtk.IconSize.SMALL_TOOLBAR)
- self.header_bar_menu_button.set_action_name('app.menu')
-
- self.header_bar_refresh_button = Gtk.Button.new_from_icon_name('view-refresh-symbolic', Gtk.IconSize.SMALL_TOOLBAR)
- self.header_bar_refresh_button.set_action_name('win.updateChannel')
-
- self.menu_popover = Gtk.Popover.new_from_model(self.header_bar_menu_button, self.app_menu)
- self.menu_popover.set_position(Gtk.PositionType.BOTTOM)
for (accel, action) in parse_app_menu_for_accels(menu_filename):
self.add_accelerator(accel, action, None)
@@ -168,7 +178,6 @@ class gPodderApplication(Gtk.Application):
# TODO: Move the menubar
self.set_menubar(self.menubar)
else:
- self.menubar.insert_submenu(0, 'gPodder', self.app_menu)
self.set_menubar(self.menubar)
Gtk.Window.set_default_icon_name('gpodder')
diff --git a/src/gpodder/gtkui/main.py b/src/gpodder/gtkui/main.py
index 6ae19590..7974fff0 100644
--- a/src/gpodder/gtkui/main.py
+++ b/src/gpodder/gtkui/main.py
@@ -98,10 +98,22 @@ class gPodder(BuilderWidget, dbus.service.Object):
self.stack_switcher = Gtk.StackSwitcher()
self.stack_switcher.set_stack(self.wNotebook)
+ self.pbFeedUpdate = Gtk.ProgressBar()
+ self.pbFeedUpdate.set_show_text(True)
+ self.pbFeedUpdate.set_property('ellipsize', Pango.EllipsizeMode.END)
+ self.pbFeedUpdate.set_property('valign', Gtk.Align.CENTER)
+ self.pbFeedUpdate.set_property('vexpand', True)
+
+ self.header_bar_refresh_ui_revealer = Gtk.Revealer()
+ self.header_bar_refresh_ui_revealer.set_transition_type(Gtk.RevealerTransitionType.CROSSFADE)
+ self.header_bar_refresh_ui_revealer.add(self.pbFeedUpdate)
+ self.application.header_bar_refresh_ui.attach(self.header_bar_refresh_ui_revealer, 0, 0, 1, 1)
+
if self.application.want_headerbar:
self.header_bar = Gtk.HeaderBar()
self.header_bar.pack_end(self.application.header_bar_menu_button)
self.header_bar.pack_start(self.application.header_bar_refresh_button)
+ self.header_bar.pack_start(self.application.header_bar_refresh_ui)
self.header_bar.set_custom_title(self.stack_switcher)
self.header_bar.set_show_close_button(True)
self.header_bar.show_all()
@@ -111,10 +123,28 @@ class gPodder(BuilderWidget, dbus.service.Object):
self.main_window.set_titlebar(self.header_bar)
else:
- self.vMain.pack_start(self.stack_switcher, False, True, 6)
+ hb = Gtk.HBox()
+ hb.set_border_width(6)
+ self.vMain.pack_start(hb, False, True, 0)
+ self.vMain.reorder_child(hb, 1)
+
+ self.pbFeedUpdate.set_property('vexpand', False)
+ self.vMain.pack_start(self.application.header_bar_refresh_ui, False, False, 0)
+
+ def _on_child_revealed(widget, prop=None):
+ widget.set_visible(widget.get_child_revealed())
+
+ self.header_bar_refresh_ui_revealer.connect('notify::child-revealed', _on_child_revealed)
+ self.application.header_bar_refresh_ui.show_all()
+ _on_child_revealed(self.header_bar_refresh_ui_revealer)
+
+ self.vMain.reorder_child(self.application.header_bar_refresh_ui, 2)
+
+ hb.pack_start(self.application.header_bar_refresh_button, False, False, 0)
+ hb.pack_start(self.stack_switcher, True, True, 6)
+ hb.pack_start(self.application.header_bar_menu_button, False, False, 0)
self.stack_switcher.set_property('halign', Gtk.Align.CENTER)
- self.vMain.reorder_child(self.stack_switcher, 1)
- self.stack_switcher.show_all()
+ hb.show_all()
gpodder.user_extensions.on_ui_object_available('gpodder-gtk', self)
self.toolbar.set_property('visible', self.config.show_toolbar)
@@ -225,8 +255,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
util.run_in_background(self.user_apps_reader.read)
# Now, update the feed cache, when everything's in place
- if not self.application.want_headerbar:
- self.btnUpdateFeeds.show()
self.feed_cache_update_cancelled = False
self.update_podcast_list_model()
@@ -240,6 +268,8 @@ class gPodder(BuilderWidget, dbus.service.Object):
if self.config.auto_update_feeds:
self.restart_auto_update_timer()
+ self._hide_refresh_ui_source_id = None
+
# Find expired (old) episodes and delete them
old_episodes = list(common.get_expired_episodes(self.channels, self.config))
if len(old_episodes) > 0:
@@ -307,6 +337,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
action_defs = [
('update', self.on_itemUpdate_activate),
+ ('cancelFeedUpdate', self.on_btnCancelFeedUpdate_clicked),
('downloadAllNew', self.on_itemDownloadAllNew_activate),
('removeOldEpisodes', self.on_itemRemoveOldEpisodes_activate),
('discover', self.on_itemImportChannels_activate),
@@ -336,6 +367,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
self.update_action = g.lookup_action('update')
self.update_channel_action = g.lookup_action('updateChannel')
+ self.cancel_feed_update_action = g.lookup_action('cancelFeedUpdate')
self.edit_channel_action = g.lookup_action('editChannel')
self.play_action = g.lookup_action('play')
self.open_action = g.lookup_action('open')
@@ -345,6 +377,8 @@ class gPodder(BuilderWidget, dbus.service.Object):
self.toggle_episode_new_action = g.lookup_action('toggleEpisodeNew')
self.toggle_episode_lock_action = g.lookup_action('toggleEpisodeLock')
+ self.cancel_feed_update_action.set_enabled(False)
+
action = Gio.SimpleAction.new_stateful(
'showToolbar', None, GLib.Variant.new_boolean(self.config.show_toolbar))
action.connect('activate', self.on_itemShowToolbar_activate)
@@ -2627,20 +2661,35 @@ class gPodder(BuilderWidget, dbus.service.Object):
def show_update_feeds_buttons(self):
# Make sure that the buttons for updating feeds
# appear - this should happen after a feed update
- self.hboxUpdateFeeds.hide()
- if not self.application.want_headerbar:
- self.btnUpdateFeeds.show()
+ self.header_bar_refresh_ui_revealer.set_reveal_child(False)
+ self._make_update_button_update()
+
+ def _make_update_button_update(self):
+ self.cancel_feed_update_action.set_enabled(False)
+ self.application.header_bar_refresh_button.set_icon_name('view-refresh-symbolic')
+ self.application.header_bar_refresh_button.set_action_name('win.update')
self.update_action.set_enabled(True)
self.update_channel_action.set_enabled(True)
- def on_btnCancelFeedUpdate_clicked(self, widget):
+ def _make_update_button_cancel(self):
+ self.update_action.set_enabled(False)
+ self.update_channel_action.set_enabled(False)
+ self.application.header_bar_refresh_button.set_icon_name('edit-undo-symbolic')
+ self.application.header_bar_refresh_button.set_action_name('win.cancelFeedUpdate')
+ self.cancel_feed_update_action.set_enabled(True)
+
+ def on_btnCancelFeedUpdate_clicked(self, *args):
if not self.feed_cache_update_cancelled:
self.pbFeedUpdate.set_text(_('Cancelling...'))
self.feed_cache_update_cancelled = True
- self.btnCancelFeedUpdate.set_sensitive(False)
else:
self.show_update_feeds_buttons()
+ def _hide_header_bar_refresh_ui(self):
+ self.header_bar_refresh_ui_revealer.set_reveal_child(False)
+ self._hide_refresh_ui_source_id = None
+ return False
+
def update_feed_cache(self, channels=None,
show_new_episodes_dialog=True):
if self.config.check_connection and not util.connection_available():
@@ -2655,15 +2704,15 @@ class gPodder(BuilderWidget, dbus.service.Object):
# Only update podcasts for which updates are enabled
channels = [c for c in self.channels if not c.pause_subscription]
- self.update_action.set_enabled(False)
- self.update_channel_action.set_enabled(False)
+ self._make_update_button_cancel()
self.feed_cache_update_cancelled = False
- self.btnCancelFeedUpdate.show()
- self.btnCancelFeedUpdate.set_sensitive(True)
- self.btnCancelFeedUpdate.set_image(Gtk.Image.new_from_icon_name('process-stop', Gtk.IconSize.BUTTON))
- self.hboxUpdateFeeds.show_all()
- self.btnUpdateFeeds.hide()
+
+ if self._hide_refresh_ui_source_id is not None:
+ GObject.source_remove(self._hide_refresh_ui_source_id)
+ self._hide_refresh_ui_source_id = None
+
+ self.header_bar_refresh_ui_revealer.set_reveal_child(True)
count = len(channels)
text = N_('Updating %(count)d feed...', 'Updating %(count)d feeds...',
@@ -2759,10 +2808,8 @@ class gPodder(BuilderWidget, dbus.service.Object):
self.pbFeedUpdate.set_fraction(1.0)
self.pbFeedUpdate.set_text(_('No new episodes'))
self.feed_cache_update_cancelled = True
- self.btnCancelFeedUpdate.show()
- self.btnCancelFeedUpdate.set_sensitive(True)
- self.update_action.set_enabled(True)
- self.btnCancelFeedUpdate.set_image(Gtk.Image.new_from_icon_name('edit-clear', Gtk.IconSize.BUTTON))
+ self._hide_refresh_ui_source_id = GObject.timeout_add(3000, self._hide_header_bar_refresh_ui)
+ self._make_update_button_update()
else:
count = len(episodes)
# New episodes are available