From c94140e69afa8a12a7448baf19127b9f4a7e46bd Mon Sep 17 00:00:00 2001 From: Marius Meisenzahl Date: Thu, 6 Jan 2022 23:20:43 +0000 Subject: [PATCH] Automatically install curated Flatpak updates (#1793) * Client: Automatically install Flatpak updates if cache is old * Add setting to automatically install Flatpak updates * MainWindow: Add menu with setting to toggle if Flatpak updates should be automatically installed * Client: Fix automatic installtion of Flatpak packages * Settings: Disable automatically-install-flatpak-updates by default * Client: Only automatically install native Flatpak apps * Update wording Co-authored-by: Cassidy James Blaede * MainWindow: Use even margins Co-authored-by: Cassidy James Blaede * MainWindow: Use LARGE_TOOLBAR * CSS: Use 3px as rem * CSS: Add comment about calculation * UpdateManager: Filter automatically installed Flatpak apps * UpdateManager: Don't count automatic updates * MainWindow: Update cache and install updates when setting is turned on * MainWindow: Cancel updates when setting is turned off * Apply suggestions from code review Co-authored-by: Cassidy James Blaede * Update io.elementary.appcenter.appdata.xml.in * MainWindow: Update auto update description * Client: Exclude `should_pay` apps Co-authored-by: Cassidy James Blaede --- data/io.elementary.appcenter.appdata.xml.in | 6 ++- data/io.elementary.appcenter.gschema.xml | 5 +++ data/styles/application.css | 4 +- src/Core/Client.vala | 27 ++++++++++--- src/Core/UpdateManager.vala | 12 +++++- src/MainWindow.vala | 43 +++++++++++++++++++++ 6 files changed, 87 insertions(+), 10 deletions(-) diff --git a/data/io.elementary.appcenter.appdata.xml.in b/data/io.elementary.appcenter.appdata.xml.in index c193446b8..f5e027619 100644 --- a/data/io.elementary.appcenter.appdata.xml.in +++ b/data/io.elementary.appcenter.appdata.xml.in @@ -11,8 +11,12 @@

The open source, pay-what-you-want app store from elementary. Reviewed and curated by elementary to ensure a native, privacy-respecting, and secure experience. Browse by categories or search and discover new apps. AppCenter is also used for updating your system to the latest and greatest version for new features and fixes.

- + +

New features:

+
    +
  • Added an option to automatically update curated apps
  • +

Fixes:

  • Prevent back button from disappearing or requiring multiple clicks
  • diff --git a/data/io.elementary.appcenter.gschema.xml b/data/io.elementary.appcenter.gschema.xml index 355c10648..3cdcfd417 100644 --- a/data/io.elementary.appcenter.gschema.xml +++ b/data/io.elementary.appcenter.gschema.xml @@ -41,5 +41,10 @@ Unix UTC time of last cache refresh Used to determine when AppCenter last refreshed its caches and checked for package updates + + false + Automatic updates + Whether to automatically install updates to curated Flatpak apps + diff --git a/data/styles/application.css b/data/styles/application.css index 09385d0ad..aa8b1f5cc 100644 --- a/data/styles/application.css +++ b/data/styles/application.css @@ -16,6 +16,6 @@ */ .titlebar { - padding-bottom: 0; - padding-top: 0; + padding-bottom: 0.333rem; /* 3px at 9pt font */ + padding-top: 0.333rem; /* 3px at 9pt font */ } diff --git a/src/Core/Client.vala b/src/Core/Client.vala index d141819eb..343083cb0 100644 --- a/src/Core/Client.vala +++ b/src/Core/Client.vala @@ -130,7 +130,8 @@ public class AppCenterCore.Client : Object { /* One cache update a day, keeps the doctor away! */ var seconds_since_last_refresh = new DateTime.now_utc ().difference (last_cache_update) / GLib.TimeSpan.SECOND; - if (force || seconds_since_last_refresh >= SECONDS_BETWEEN_REFRESHES) { + bool last_cache_update_is_old = seconds_since_last_refresh >= SECONDS_BETWEEN_REFRESHES; + if (force || last_cache_update_is_old) { if (nm.get_network_available ()) { debug ("New refresh task"); @@ -156,10 +157,6 @@ public class AppCenterCore.Client : Object { debug ("Too soon to refresh and not forced"); } - if (nm.get_network_available ()) { - refresh_updates.begin (); - } - var next_refresh = SECONDS_BETWEEN_REFRESHES - (uint)seconds_since_last_refresh; debug ("Setting a timeout for a refresh in %f minutes", next_refresh / 60.0f); update_cache_timeout_id = GLib.Timeout.add_seconds (next_refresh, () => { @@ -168,6 +165,26 @@ public class AppCenterCore.Client : Object { return GLib.Source.REMOVE; }); + + if (nm.get_network_available ()) { + if (last_cache_update_is_old && AppCenter.App.settings.get_boolean ("automatic-updates")) { + yield refresh_updates (); + debug ("Update Flatpaks"); + var installed_apps = yield FlatpakBackend.get_default ().get_installed_applications (cancellable); + foreach (var app in installed_apps) { + if (app.is_native && app.update_available && !app.should_pay) { + debug ("Update: %s", app.get_name ()); + try { + yield app.update (false); + } catch (Error e) { + warning ("Updating %s failed: %s", app.get_name (), e.message); + } + } + } + } + + refresh_updates.begin (); + } } public Package? get_package_for_component_id (string id) { diff --git a/src/Core/UpdateManager.vala b/src/Core/UpdateManager.vala index 9deceaf50..d07c6c794 100644 --- a/src/Core/UpdateManager.vala +++ b/src/Core/UpdateManager.vala @@ -73,6 +73,7 @@ public class AppCenterCore.UpdateManager : Object { if (appcenter_package != null) { debug ("Added %s to app updates", pkg_name); apps_with_updates.add (appcenter_package); + count++; appcenter_package.latest_version = pk_package.get_version (); } else { debug ("Added %s to OS updates", pkg_name); @@ -100,6 +101,11 @@ public class AppCenterCore.UpdateManager : Object { if (appcenter_package != null) { debug ("Added %s to app updates", flatpak_update); apps_with_updates.add (appcenter_package); + + if (!(AppCenter.App.settings.get_boolean ("automatic-updates") && appcenter_package.is_native)) { + count++; + } + appcenter_package.change_information.updatable_packages.@set (fp_client, flatpak_update); appcenter_package.update_state (); try { @@ -122,7 +128,10 @@ public class AppCenterCore.UpdateManager : Object { continue; } - os_count++; + if (!AppCenter.App.settings.get_boolean ("automatic-updates")) { + os_count++; + } + os_desc += Markup.printf_escaped ( " • %s\n\t%s\n", @ref.get_name (), @@ -153,7 +162,6 @@ public class AppCenterCore.UpdateManager : Object { os_updates.description = "%s\n%s\n".printf (GLib.Markup.printf_escaped (_("%s:"), latest_version), os_desc); } - count = apps_with_updates.size; debug ("%u app updates found", count); if (os_count > 0) { count += 1; diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 80337a598..e3c5e7053 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -215,11 +215,48 @@ public class AppCenter.MainWindow : Hdy.ApplicationWindow { spinner = new Gtk.Spinner (); + var automatic_updates_button = new Granite.SwitchModelButton (_("Automatic Updates")) { + description = _("Automatically update free and paid-for curated apps") + }; + + automatic_updates_button.notify["active"].connect (() => { + if (automatic_updates_button.active) { + AppCenterCore.Client.get_default ().update_cache.begin (true); + } else { + AppCenterCore.Client.get_default ().cancel_updates (true); + } + }); + + var menu_popover_grid = new Gtk.Grid () { + column_spacing = 6, + margin_bottom = 6, + margin_top = 6, + orientation = Gtk.Orientation.VERTICAL, + row_spacing = 6 + }; + + menu_popover_grid.add (automatic_updates_button); + + menu_popover_grid.show_all (); + + var menu_popover = new Gtk.Popover (null); + menu_popover.add (menu_popover_grid); + + var menu_button = new Gtk.MenuButton () { + can_focus = false, + image = new Gtk.Image.from_icon_name ("open-menu", Gtk.IconSize.LARGE_TOOLBAR), + popover = menu_popover, + tooltip_text = _("Settings"), + valign = Gtk.Align.CENTER + }; + + var headerbar = new Hdy.HeaderBar () { show_close_button = true }; headerbar.set_custom_title (custom_title_stack); headerbar.pack_start (return_button); + headerbar.pack_end (menu_button); headerbar.pack_end (search_entry); headerbar.pack_end (spinner); @@ -253,6 +290,12 @@ public class AppCenter.MainWindow : Hdy.ApplicationWindow { int window_width, window_height; App.settings.get ("window-position", "(ii)", out window_x, out window_y); App.settings.get ("window-size", "(ii)", out window_width, out window_height); + App.settings.bind ( + "automatic-updates", + automatic_updates_button, + "active", + SettingsBindFlags.DEFAULT + ); if (window_x != -1 || window_y != -1) { move (window_x, window_y);