From 5977fceb4c594309a8bf559e0257065f7561c2ca Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 Jan 2024 19:31:31 +0100 Subject: [PATCH 01/26] Add basic system updates UI --- src/Plug.vala | 3 + src/Views/UpdatesView.vala | 177 +++++++++++++++++++++++++++++++++++++ src/meson.build | 1 + 3 files changed, 181 insertions(+) create mode 100644 src/Views/UpdatesView.vala diff --git a/src/Plug.vala b/src/Plug.vala index 4fd5bdb2..64bcb0e2 100644 --- a/src/Plug.vala +++ b/src/Plug.vala @@ -56,12 +56,15 @@ public class About.Plug : Switchboard.Plug { var firmware_view = new FirmwareView (); + var update_view = new UpdatesView (); + stack = new Gtk.Stack () { vexpand = true }; stack.add_titled (operating_system_view, OPERATING_SYSTEM, _("Operating System")); stack.add_titled (hardware_view, HARDWARE, _("Hardware")); stack.add_titled (firmware_view, FIRMWARE, _("Firmware")); + stack.add_titled (update_view, "updates", _("Updates")); var stack_switcher = new Gtk.StackSwitcher () { halign = Gtk.Align.CENTER, diff --git a/src/Views/UpdatesView.vala b/src/Views/UpdatesView.vala new file mode 100644 index 00000000..54efff66 --- /dev/null +++ b/src/Views/UpdatesView.vala @@ -0,0 +1,177 @@ +[DBus (name="io.elementary.settings_daemon.SystemUpdate")] +public interface SystemUpdate : Object { + public enum State { + UP_TO_DATE, + CHECKING, + AVAILABLE, + DOWNLOADING, + RESTART_REQUIRED + } + + public struct CurrentState { + State state; + string message; + } + + public struct UpdateDetails { + string[] packages; + int size; + } + + public signal void state_changed (); + + public abstract async CurrentState get_current_state () throws DBusError, IOError; + public abstract async UpdateDetails get_update_details () throws DBusError, IOError; + public abstract async void update () throws DBusError, IOError; + public abstract async void check_for_updates (bool force = false) throws DBusError, IOError; +} + +public class About.UpdatesView : Granite.SimpleSettingsPage { + private Gtk.StringList updates; + private SystemUpdate? update_proxy = null; + private Granite.Placeholder checking_alert_view; + private Granite.Placeholder up_to_date_alert_view; + private Gtk.ListBox update_list; + private Gtk.Stack button_stack; + private Granite.OverlayBar status_bar; + + public UpdatesView () { + Object ( + icon_name: "system-software-update", + title: _("Updates"), + description: _("System updates.") + ); + } + + construct { + updates = new Gtk.StringList (null); + + checking_alert_view = new Granite.Placeholder (_("Checking for Updates")) { + description = _("Connecting to the backend and searching for updates."), + icon = new ThemedIcon ("sync-synchronizing") + }; + + up_to_date_alert_view = new Granite.Placeholder (_("Up To Date")) { + description = _("No updates available."), + icon = new ThemedIcon ("emblem-default") + }; + + update_list = new Gtk.ListBox () { + vexpand = true, + selection_mode = Gtk.SelectionMode.SINGLE + }; + update_list.set_placeholder (up_to_date_alert_view); + update_list.bind_model (updates, (obj) => { + var str = ((Gtk.StringObject) obj).string; + return new Gtk.Label (str); + }); + + var update_scrolled = new Gtk.ScrolledWindow () { + child = update_list + }; + + var stack = new Gtk.Stack () { + transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }; + stack.add_child (update_scrolled); + + var overlay = new Gtk.Overlay () { + child = stack + }; + + status_bar = new Granite.OverlayBar (overlay) { + visible = false, + active = true + }; + + var frame = new Gtk.Frame (null) { + child = overlay + }; + + content_area.attach (frame, 0, 0); + + var check_button = new Gtk.Button.with_label (_("Check for updates")); + + var update_button = new Gtk.Button.with_label (_("Download")); + update_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); + + var blank = new Gtk.Grid (); + + button_stack = new Gtk.Stack () { + transition_type = CROSSFADE + }; + button_stack.add_named (check_button, "check"); + button_stack.add_named (update_button, "update"); + button_stack.add_named (blank, "blank"); + + action_area.append (button_stack); + + Bus.get_proxy.begin (SESSION, "io.elementary.settings-daemon", "/io/elementary/settings_daemon", 0, null, (obj, res) => { + try { + update_proxy = Bus.get_proxy.end (res); + + update_proxy.state_changed.connect (update_state); + update_state.begin (); + } catch (Error e) { + critical ("Failed to get updates proxy"); + } + }); + + check_button.clicked.connect (() => { + if (update_proxy != null) { + try { + update_proxy.check_for_updates.begin (); + } catch (Error e) { + warning ("Failed to check for updates: %s", e.message); + } + } + }); + } + + private async void update_state () { + if (update_proxy == null) { + return; + } + + SystemUpdate.CurrentState current_state; + try { + current_state = yield update_proxy.get_current_state (); + } catch (Error e) { + critical ("Failed to get current state from Updates Backend: %s", e.message); + return; + } + + switch (current_state.state) { + case UP_TO_DATE: + status_bar.visible = false; + update_list.set_placeholder (up_to_date_alert_view); + button_stack.visible_child_name = "check"; + break; + case CHECKING: + status_bar.visible = true; + status_bar.label = current_state.message; + update_list.set_placeholder (checking_alert_view); + button_stack.visible_child_name = "blank"; + break; + case AVAILABLE: + status_bar.visible = false; + try { + var details = yield update_proxy.get_update_details (); + updates.splice (0, 0, details.packages); + button_stack.visible_child_name = "update"; + } catch (Error e) { + warning ("Failed to get updates list from backend: %s", e.message); + } + break; + case DOWNLOADING: + status_bar.visible = true; + status_bar.label = current_state.message; + button_stack.visible_child_name = "blank"; + break; + case RESTART_REQUIRED: + status_bar.visible = false; + button_stack.visible_child_name = "blank"; + break; + } + } +} \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index 6babf8c9..b1f8031f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -7,6 +7,7 @@ plug_files = files( 'Views/FirmwareView.vala', 'Views/HardwareView.vala', 'Views/OperatingSystemView.vala', + 'Views/UpdatesView.vala', 'Widgets/FirmwareUpdateRow.vala' ) From beed70f92b8fecd27c1ce836e96ddfcaec17afd7 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 Jan 2024 22:41:01 +0100 Subject: [PATCH 02/26] Hook about download button and add reboot infobar --- src/Views/UpdatesView.vala | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Views/UpdatesView.vala b/src/Views/UpdatesView.vala index 54efff66..03fd3124 100644 --- a/src/Views/UpdatesView.vala +++ b/src/Views/UpdatesView.vala @@ -34,6 +34,7 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { private Gtk.ListBox update_list; private Gtk.Stack button_stack; private Granite.OverlayBar status_bar; + private Gtk.InfoBar reboot_infobar; public UpdatesView () { Object ( @@ -46,6 +47,12 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { construct { updates = new Gtk.StringList (null); + reboot_infobar = new Gtk.InfoBar () { + revealed = false, + message_type = WARNING + }; + reboot_infobar.add_child (new Gtk.Label (_("A restart is required to finish installing updates"))); + checking_alert_view = new Granite.Placeholder (_("Checking for Updates")) { description = _("Connecting to the backend and searching for updates."), icon = new ThemedIcon ("sync-synchronizing") @@ -89,6 +96,7 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { }; content_area.attach (frame, 0, 0); + content_area.attach (reboot_infobar, 0, 1); var check_button = new Gtk.Button.with_label (_("Check for updates")); @@ -117,6 +125,16 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { } }); + update_button.clicked.connect (() => { + if (update_proxy != null) { + try { + update_proxy.update.begin (); + } catch (Error e) { + warning ("Failed to updates: %s", e.message); + } + } + }); + check_button.clicked.connect (() => { if (update_proxy != null) { try { @@ -169,9 +187,10 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { button_stack.visible_child_name = "blank"; break; case RESTART_REQUIRED: + reboot_infobar.revealed = true; status_bar.visible = false; button_stack.visible_child_name = "blank"; break; } } -} \ No newline at end of file +} From 38bb5c2d1d0abf8af76ca9c3297fab512cdfa290 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 Jan 2024 22:44:23 +0100 Subject: [PATCH 03/26] More error handling --- src/Views/UpdatesView.vala | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Views/UpdatesView.vala b/src/Views/UpdatesView.vala index 03fd3124..ada962be 100644 --- a/src/Views/UpdatesView.vala +++ b/src/Views/UpdatesView.vala @@ -127,21 +127,25 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { update_button.clicked.connect (() => { if (update_proxy != null) { - try { - update_proxy.update.begin (); - } catch (Error e) { - warning ("Failed to updates: %s", e.message); - } + update_proxy.update.begin ((obj, res) => { + try { + update_proxy.update.end (res); + } catch (Error e) { + critical ("Failed to update: %s", e.message); + } + }); } }); check_button.clicked.connect (() => { if (update_proxy != null) { - try { - update_proxy.check_for_updates.begin (); - } catch (Error e) { - warning ("Failed to check for updates: %s", e.message); - } + update_proxy.check_for_updates.begin (false, (obj, res) => { + try { + update_proxy.update.end (res); + } catch (Error e) { + critical ("Failed to check for updates: %s", e.message); + } + }); } }); } From 36c39b6c74fdd8d237bbfad8ff5cf09a1bfe5096 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 Jan 2024 22:45:59 +0100 Subject: [PATCH 04/26] Improve label design --- src/Views/UpdatesView.vala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Views/UpdatesView.vala b/src/Views/UpdatesView.vala index ada962be..bb363bae 100644 --- a/src/Views/UpdatesView.vala +++ b/src/Views/UpdatesView.vala @@ -70,7 +70,12 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { update_list.set_placeholder (up_to_date_alert_view); update_list.bind_model (updates, (obj) => { var str = ((Gtk.StringObject) obj).string; - return new Gtk.Label (str); + return new Gtk.Label (str) { + halign = START, + valign = CENTER, + margin_start = 6, + margin_top = 3 + }; }); var update_scrolled = new Gtk.ScrolledWindow () { @@ -179,7 +184,7 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { status_bar.visible = false; try { var details = yield update_proxy.get_update_details (); - updates.splice (0, 0, details.packages); + updates.splice (0, updates.get_n_items (), details.packages); button_stack.visible_child_name = "update"; } catch (Error e) { warning ("Failed to get updates list from backend: %s", e.message); From cd2b91b0469a1b8d9c0f84023c2bced5e794c585 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Mon, 22 Jan 2024 23:33:21 +0100 Subject: [PATCH 05/26] Add cancel button --- src/Views/UpdatesView.vala | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Views/UpdatesView.vala b/src/Views/UpdatesView.vala index bb363bae..629a6149 100644 --- a/src/Views/UpdatesView.vala +++ b/src/Views/UpdatesView.vala @@ -22,8 +22,9 @@ public interface SystemUpdate : Object { public abstract async CurrentState get_current_state () throws DBusError, IOError; public abstract async UpdateDetails get_update_details () throws DBusError, IOError; - public abstract async void update () throws DBusError, IOError; + public abstract async void cancel () throws DBusError, IOError; public abstract async void check_for_updates (bool force = false) throws DBusError, IOError; + public abstract async void update () throws DBusError, IOError; } public class About.UpdatesView : Granite.SimpleSettingsPage { @@ -39,8 +40,8 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { public UpdatesView () { Object ( icon_name: "system-software-update", - title: _("Updates"), - description: _("System updates.") + title: _("Operating System Updates"), + description: _("Updates to system components") ); } @@ -108,14 +109,15 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { var update_button = new Gtk.Button.with_label (_("Download")); update_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - var blank = new Gtk.Grid (); + var cancel_button = new Gtk.Button.with_label (_("Cancel")); button_stack = new Gtk.Stack () { transition_type = CROSSFADE }; button_stack.add_named (check_button, "check"); button_stack.add_named (update_button, "update"); - button_stack.add_named (blank, "blank"); + button_stack.add_named (cancel_button, "cancel"); + button_stack.add_named (new Gtk.Grid (), "blank"); action_area.append (button_stack); @@ -130,6 +132,18 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { } }); + check_button.clicked.connect (() => { + if (update_proxy != null) { + update_proxy.check_for_updates.begin (false, (obj, res) => { + try { + update_proxy.check_for_updates.end (res); + } catch (Error e) { + critical ("Failed to check for updates: %s", e.message); + } + }); + } + }); + update_button.clicked.connect (() => { if (update_proxy != null) { update_proxy.update.begin ((obj, res) => { @@ -142,13 +156,13 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { } }); - check_button.clicked.connect (() => { + cancel_button.clicked.connect (() => { if (update_proxy != null) { - update_proxy.check_for_updates.begin (false, (obj, res) => { + update_proxy.cancel.begin ((obj, res) => { try { - update_proxy.update.end (res); + update_proxy.cancel.end (res); } catch (Error e) { - critical ("Failed to check for updates: %s", e.message); + critical ("Failed to cancel update: %s", e.message); } }); } @@ -193,7 +207,7 @@ public class About.UpdatesView : Granite.SimpleSettingsPage { case DOWNLOADING: status_bar.visible = true; status_bar.label = current_state.message; - button_stack.visible_child_name = "blank"; + button_stack.visible_child_name = "cancel"; break; case RESTART_REQUIRED: reboot_infobar.revealed = true; From ce2f0b547b6d09ecbb085233bee04d867a7e24e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 22 Jan 2024 14:44:48 -0800 Subject: [PATCH 06/26] Updates Redesign (#281) --- src/DBus/SystemUpdate.vala | 27 ++++ src/Plug.vala | 3 - src/Views/OperatingSystemView.vala | 189 +++++++++++++++++++++---- src/Views/UpdatesView.vala | 219 ----------------------------- src/meson.build | 2 +- 5 files changed, 193 insertions(+), 247 deletions(-) create mode 100644 src/DBus/SystemUpdate.vala delete mode 100644 src/Views/UpdatesView.vala diff --git a/src/DBus/SystemUpdate.vala b/src/DBus/SystemUpdate.vala new file mode 100644 index 00000000..2a993ad2 --- /dev/null +++ b/src/DBus/SystemUpdate.vala @@ -0,0 +1,27 @@ +[DBus (name="io.elementary.settings_daemon.SystemUpdate")] +public interface SystemUpdate : Object { + public enum State { + UP_TO_DATE, + CHECKING, + AVAILABLE, + DOWNLOADING, + RESTART_REQUIRED + } + + public struct CurrentState { + State state; + string message; + } + + public struct UpdateDetails { + string[] packages; + int size; + } + + public signal void state_changed (); + + public abstract async CurrentState get_current_state () throws DBusError, IOError; + public abstract async UpdateDetails get_update_details () throws DBusError, IOError; + public abstract async void update () throws DBusError, IOError; + public abstract async void check_for_updates (bool force = false) throws DBusError, IOError; +} diff --git a/src/Plug.vala b/src/Plug.vala index 64bcb0e2..4fd5bdb2 100644 --- a/src/Plug.vala +++ b/src/Plug.vala @@ -56,15 +56,12 @@ public class About.Plug : Switchboard.Plug { var firmware_view = new FirmwareView (); - var update_view = new UpdatesView (); - stack = new Gtk.Stack () { vexpand = true }; stack.add_titled (operating_system_view, OPERATING_SYSTEM, _("Operating System")); stack.add_titled (hardware_view, HARDWARE, _("Hardware")); stack.add_titled (firmware_view, FIRMWARE, _("Firmware")); - stack.add_titled (update_view, "updates", _("Updates")); var stack_switcher = new Gtk.StackSwitcher () { halign = Gtk.Align.CENTER, diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index a5767f0c..90e1bdf1 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -21,7 +21,14 @@ public class About.OperatingSystemView : Gtk.Box { private string support_url; + private Gtk.StringList updates; + private SystemUpdate? update_proxy = null; private Gtk.Grid software_grid; + private Gtk.Button check_button; + private Gtk.Image updates_image; + private Gtk.Label updates_title; + private Gtk.Label updates_description; + private Gtk.Revealer update_button_revealer; construct { var style_provider = new Gtk.CssProvider (); @@ -84,7 +91,6 @@ public class About.OperatingSystemView : Gtk.Box { var title = new Gtk.Label (pretty_name) { ellipsize = Pango.EllipsizeMode.END, - margin_bottom = 12, selectable = true, use_markup = true, xalign = 0 @@ -95,40 +101,91 @@ public class About.OperatingSystemView : Gtk.Box { selectable = true, xalign = 0 }; + kernel_version_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); + kernel_version_label.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); var website_url = Environment.get_os_info (GLib.OsInfoKey.HOME_URL); if (website_url == "" || website_url == null) { website_url = "https://elementary.io"; } - var website_label = new Gtk.LinkButton.with_label (website_url, _("Website")) { - margin_top = 12 - }; + var website_label = new Gtk.LinkButton.with_label (website_url, _("Website")); var help_button = new Gtk.LinkButton.with_label (support_url, _("Get Support")) { halign = Gtk.Align.CENTER, - hexpand = true, - margin_top = 12 + hexpand = true }; var translate_button = new Gtk.LinkButton.with_label ( "https://l10n.elementary.io/projects/", _("Suggest Translations") - ) { - margin_top = 12 - }; + ); var bug_button = new Gtk.Button.with_label (_("Send Feedback")); - Gtk.Button? update_button = null; - var appcenter_info = new GLib.DesktopAppInfo ("io.elementary.appcenter.desktop"); - if (appcenter_info != null) { - update_button = new Gtk.Button.with_label (_("Check for Updates")); - update_button.clicked.connect (() => { - appcenter_info.launch_action ("ShowUpdates", new GLib.AppLaunchContext ()); - }); - } + updates = new Gtk.StringList (null); + + var update_list = new Gtk.ListBox () { + vexpand = true, + selection_mode = Gtk.SelectionMode.SINGLE + }; + update_list.bind_model (updates, (obj) => { + var str = ((Gtk.StringObject) obj).string; + return new Gtk.Label (str); + }); + + var update_scrolled = new Gtk.ScrolledWindow () { + child = update_list + }; + + updates_image = new Gtk.Image () { + icon_size = LARGE + }; + + updates_title = new Gtk.Label (null) { + hexpand = true, + margin_end = 6, + xalign = 0 + }; + + updates_description = new Gtk.Label (null) { + xalign = 0 + }; + updates_description.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); + updates_description.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); + + var update_button = new Gtk.Button.with_label (_("Download")) { + margin_end = 6, + valign = CENTER + }; + + update_button_revealer = new Gtk.Revealer () { + child = update_button, + overflow = VISIBLE, + transition_type = SLIDE_LEFT + }; + + var updates_grid = new Gtk.Grid () { + column_spacing = 6, + margin_top = 6, + margin_bottom = 6, + margin_start = 6 + }; + updates_grid.attach (updates_image, 0, 0, 1, 2); + updates_grid.attach (updates_title, 1, 0); + updates_grid.attach (updates_description, 1, 1); + updates_grid.attach (update_button_revealer, 2, 0, 1, 2); + + var frame = new Gtk.Frame (null) { + child = updates_grid, + margin_bottom = 12, + margin_top = 12, + valign = CENTER + }; + frame.add_css_class (Granite.STYLE_CLASS_VIEW); + + check_button = new Gtk.Button.with_label (_("Check for Updates")); var settings_restore_button = new Gtk.Button.with_label (_("Restore Default Settings")); @@ -138,9 +195,7 @@ public class About.OperatingSystemView : Gtk.Box { homogeneous = true }; primary_button_box.append (bug_button); - if (update_button != null) { - primary_button_box.append (update_button); - } + primary_button_box.append (check_button); var button_grid = new Gtk.Box (HORIZONTAL, 6); button_grid.append (settings_restore_button); @@ -149,7 +204,6 @@ public class About.OperatingSystemView : Gtk.Box { software_grid = new Gtk.Grid () { column_spacing = 32, halign = Gtk.Align.CENTER, - row_spacing = 6, valign = Gtk.Align.CENTER, vexpand = true }; @@ -157,9 +211,10 @@ public class About.OperatingSystemView : Gtk.Box { software_grid.attach (title, 1, 0, 3); software_grid.attach (kernel_version_label, 1, 2, 3); - software_grid.attach (website_label, 1, 3); - software_grid.attach (help_button, 2, 3); - software_grid.attach (translate_button, 3, 3); + software_grid.attach (frame, 1, 3, 3); + software_grid.attach (website_label, 1, 4); + software_grid.attach (help_button, 2, 4); + software_grid.attach (translate_button, 3, 4); margin_top = 12; margin_end = 12; @@ -187,6 +242,27 @@ public class About.OperatingSystemView : Gtk.Box { }); get_upstream_release.begin (); + + Bus.get_proxy.begin (SESSION, "io.elementary.settings-daemon", "/io/elementary/settings_daemon", 0, null, (obj, res) => { + try { + update_proxy = Bus.get_proxy.end (res); + + update_proxy.state_changed.connect (update_state); + update_state.begin (); + } catch (Error e) { + critical ("Failed to get updates proxy"); + } + }); + + check_button.clicked.connect (() => { + if (update_proxy != null) { + try { + update_proxy.check_for_updates.begin (); + } catch (Error e) { + warning ("Failed to check for updates: %s", e.message); + } + } + }); } private async void get_upstream_release () { @@ -222,10 +298,75 @@ public class About.OperatingSystemView : Gtk.Box { selectable = true, xalign = 0 }; + based_off.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); + based_off.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); software_grid.attach (based_off, 1, 1, 3); } } + private async void update_state () { + if (update_proxy == null) { + return; + } + + SystemUpdate.CurrentState current_state; + try { + current_state = yield update_proxy.get_current_state (); + } catch (Error e) { + critical ("Failed to get current state from Updates Backend: %s", e.message); + return; + } + + update_button_revealer.reveal_child = false; + + switch (current_state.state) { + case UP_TO_DATE: + updates_image.icon_name = "process-completed"; + updates_title.label = _("Up To Date"); + updates_description.label = _("No updates available"); + check_button.sensitive = true; + break; + case CHECKING: + updates_image.icon_name = "emblem-synchronized"; + updates_title.label = _("Checking for Updates"); + updates_description.label = current_state.message; + check_button.sensitive = false; + break; + case AVAILABLE: + updates_image.icon_name = "software-update-available"; + updates_title.label = _("Updates Available"); + update_button_revealer.reveal_child = true; + check_button.sensitive = true; + + try { + var details = yield update_proxy.get_update_details (); + updates_description.label = ngettext ( + _("%i update available").printf (details.packages.length), + _("%i updates available").printf (details.packages.length), + details.packages.length + ); + + updates.splice (0, 0, details.packages); + } catch (Error e) { + updates_description.label = _("Unable to determine number of updates"); + warning ("Failed to get updates list from backend: %s", e.message); + } + break; + case DOWNLOADING: + updates_image.icon_name = "browser-download"; + updates_title.label = _("Downloading Updates"); + updates_description.label = current_state.message; + check_button.sensitive = false; + break; + case RESTART_REQUIRED: + updates_image.icon_name = "system-reboot"; + updates_title.label = _("Restart Required"); + updates_description.label = _("A restart is required to finish installing updates"); + check_button.sensitive = false; + break; + } + } + private void launch_support_url () { try { AppInfo.launch_default_for_uri (support_url, null); diff --git a/src/Views/UpdatesView.vala b/src/Views/UpdatesView.vala deleted file mode 100644 index 629a6149..00000000 --- a/src/Views/UpdatesView.vala +++ /dev/null @@ -1,219 +0,0 @@ -[DBus (name="io.elementary.settings_daemon.SystemUpdate")] -public interface SystemUpdate : Object { - public enum State { - UP_TO_DATE, - CHECKING, - AVAILABLE, - DOWNLOADING, - RESTART_REQUIRED - } - - public struct CurrentState { - State state; - string message; - } - - public struct UpdateDetails { - string[] packages; - int size; - } - - public signal void state_changed (); - - public abstract async CurrentState get_current_state () throws DBusError, IOError; - public abstract async UpdateDetails get_update_details () throws DBusError, IOError; - public abstract async void cancel () throws DBusError, IOError; - public abstract async void check_for_updates (bool force = false) throws DBusError, IOError; - public abstract async void update () throws DBusError, IOError; -} - -public class About.UpdatesView : Granite.SimpleSettingsPage { - private Gtk.StringList updates; - private SystemUpdate? update_proxy = null; - private Granite.Placeholder checking_alert_view; - private Granite.Placeholder up_to_date_alert_view; - private Gtk.ListBox update_list; - private Gtk.Stack button_stack; - private Granite.OverlayBar status_bar; - private Gtk.InfoBar reboot_infobar; - - public UpdatesView () { - Object ( - icon_name: "system-software-update", - title: _("Operating System Updates"), - description: _("Updates to system components") - ); - } - - construct { - updates = new Gtk.StringList (null); - - reboot_infobar = new Gtk.InfoBar () { - revealed = false, - message_type = WARNING - }; - reboot_infobar.add_child (new Gtk.Label (_("A restart is required to finish installing updates"))); - - checking_alert_view = new Granite.Placeholder (_("Checking for Updates")) { - description = _("Connecting to the backend and searching for updates."), - icon = new ThemedIcon ("sync-synchronizing") - }; - - up_to_date_alert_view = new Granite.Placeholder (_("Up To Date")) { - description = _("No updates available."), - icon = new ThemedIcon ("emblem-default") - }; - - update_list = new Gtk.ListBox () { - vexpand = true, - selection_mode = Gtk.SelectionMode.SINGLE - }; - update_list.set_placeholder (up_to_date_alert_view); - update_list.bind_model (updates, (obj) => { - var str = ((Gtk.StringObject) obj).string; - return new Gtk.Label (str) { - halign = START, - valign = CENTER, - margin_start = 6, - margin_top = 3 - }; - }); - - var update_scrolled = new Gtk.ScrolledWindow () { - child = update_list - }; - - var stack = new Gtk.Stack () { - transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT - }; - stack.add_child (update_scrolled); - - var overlay = new Gtk.Overlay () { - child = stack - }; - - status_bar = new Granite.OverlayBar (overlay) { - visible = false, - active = true - }; - - var frame = new Gtk.Frame (null) { - child = overlay - }; - - content_area.attach (frame, 0, 0); - content_area.attach (reboot_infobar, 0, 1); - - var check_button = new Gtk.Button.with_label (_("Check for updates")); - - var update_button = new Gtk.Button.with_label (_("Download")); - update_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - - var cancel_button = new Gtk.Button.with_label (_("Cancel")); - - button_stack = new Gtk.Stack () { - transition_type = CROSSFADE - }; - button_stack.add_named (check_button, "check"); - button_stack.add_named (update_button, "update"); - button_stack.add_named (cancel_button, "cancel"); - button_stack.add_named (new Gtk.Grid (), "blank"); - - action_area.append (button_stack); - - Bus.get_proxy.begin (SESSION, "io.elementary.settings-daemon", "/io/elementary/settings_daemon", 0, null, (obj, res) => { - try { - update_proxy = Bus.get_proxy.end (res); - - update_proxy.state_changed.connect (update_state); - update_state.begin (); - } catch (Error e) { - critical ("Failed to get updates proxy"); - } - }); - - check_button.clicked.connect (() => { - if (update_proxy != null) { - update_proxy.check_for_updates.begin (false, (obj, res) => { - try { - update_proxy.check_for_updates.end (res); - } catch (Error e) { - critical ("Failed to check for updates: %s", e.message); - } - }); - } - }); - - update_button.clicked.connect (() => { - if (update_proxy != null) { - update_proxy.update.begin ((obj, res) => { - try { - update_proxy.update.end (res); - } catch (Error e) { - critical ("Failed to update: %s", e.message); - } - }); - } - }); - - cancel_button.clicked.connect (() => { - if (update_proxy != null) { - update_proxy.cancel.begin ((obj, res) => { - try { - update_proxy.cancel.end (res); - } catch (Error e) { - critical ("Failed to cancel update: %s", e.message); - } - }); - } - }); - } - - private async void update_state () { - if (update_proxy == null) { - return; - } - - SystemUpdate.CurrentState current_state; - try { - current_state = yield update_proxy.get_current_state (); - } catch (Error e) { - critical ("Failed to get current state from Updates Backend: %s", e.message); - return; - } - - switch (current_state.state) { - case UP_TO_DATE: - status_bar.visible = false; - update_list.set_placeholder (up_to_date_alert_view); - button_stack.visible_child_name = "check"; - break; - case CHECKING: - status_bar.visible = true; - status_bar.label = current_state.message; - update_list.set_placeholder (checking_alert_view); - button_stack.visible_child_name = "blank"; - break; - case AVAILABLE: - status_bar.visible = false; - try { - var details = yield update_proxy.get_update_details (); - updates.splice (0, updates.get_n_items (), details.packages); - button_stack.visible_child_name = "update"; - } catch (Error e) { - warning ("Failed to get updates list from backend: %s", e.message); - } - break; - case DOWNLOADING: - status_bar.visible = true; - status_bar.label = current_state.message; - button_stack.visible_child_name = "cancel"; - break; - case RESTART_REQUIRED: - reboot_infobar.revealed = true; - status_bar.visible = false; - button_stack.visible_child_name = "blank"; - break; - } - } -} diff --git a/src/meson.build b/src/meson.build index b1f8031f..217deb51 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,5 +1,6 @@ plug_files = files( 'Plug.vala', + 'DBus' / 'SystemUpdate.vala', 'Interfaces/FirmwareClient.vala', 'Interfaces/LoginManager.vala', 'Utils/ARMPartDecoder.vala', @@ -7,7 +8,6 @@ plug_files = files( 'Views/FirmwareView.vala', 'Views/HardwareView.vala', 'Views/OperatingSystemView.vala', - 'Views/UpdatesView.vala', 'Widgets/FirmwareUpdateRow.vala' ) From 848767361d49070ea7e6aa6830d02296aa417d16 Mon Sep 17 00:00:00 2001 From: Danielle Fore Date: Mon, 22 Jan 2024 14:50:15 -0800 Subject: [PATCH 07/26] Add download button --- src/DBus/SystemUpdate.vala | 3 ++- src/Views/OperatingSystemView.vala | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/DBus/SystemUpdate.vala b/src/DBus/SystemUpdate.vala index 2a993ad2..0a0633f4 100644 --- a/src/DBus/SystemUpdate.vala +++ b/src/DBus/SystemUpdate.vala @@ -22,6 +22,7 @@ public interface SystemUpdate : Object { public abstract async CurrentState get_current_state () throws DBusError, IOError; public abstract async UpdateDetails get_update_details () throws DBusError, IOError; - public abstract async void update () throws DBusError, IOError; + public abstract async void cancel () throws DBusError, IOError; public abstract async void check_for_updates (bool force = false) throws DBusError, IOError; + public abstract async void update () throws DBusError, IOError; } diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 90e1bdf1..b11fa83f 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -29,6 +29,7 @@ public class About.OperatingSystemView : Gtk.Box { private Gtk.Label updates_title; private Gtk.Label updates_description; private Gtk.Revealer update_button_revealer; + private Gtk.Revealer cancel_button_revealer; construct { var style_provider = new Gtk.CssProvider (); @@ -166,6 +167,17 @@ public class About.OperatingSystemView : Gtk.Box { transition_type = SLIDE_LEFT }; + var cancel_button = new Gtk.Button.with_label (_("Cancel")) { + margin_end = 6, + valign = CENTER + }; + + cancel_button_revealer = new Gtk.Revealer () { + child = update_button, + overflow = VISIBLE, + transition_type = SLIDE_LEFT + }; + var updates_grid = new Gtk.Grid () { column_spacing = 6, margin_top = 6, @@ -176,6 +188,7 @@ public class About.OperatingSystemView : Gtk.Box { updates_grid.attach (updates_title, 1, 0); updates_grid.attach (updates_description, 1, 1); updates_grid.attach (update_button_revealer, 2, 0, 1, 2); + updates_grid.attach (cancel_button_revealer, 3, 0, 1, 2); var frame = new Gtk.Frame (null) { child = updates_grid, @@ -254,6 +267,16 @@ public class About.OperatingSystemView : Gtk.Box { } }); + cancel_button.clicked.connect (() => { + if (update_proxy != null) { + try { + update_proxy.cancel.begin (); + } catch (Error e) { + critical ("Failed to cancel update: %s", e.message); + } + } + }); + check_button.clicked.connect (() => { if (update_proxy != null) { try { @@ -356,6 +379,7 @@ public class About.OperatingSystemView : Gtk.Box { updates_image.icon_name = "browser-download"; updates_title.label = _("Downloading Updates"); updates_description.label = current_state.message; + cancel_button_revealer.reveal_child = true; check_button.sensitive = false; break; case RESTART_REQUIRED: From 7e2458d3900479275b1f78873f0df526b1225819 Mon Sep 17 00:00:00 2001 From: Danielle Fore Date: Mon, 22 Jan 2024 14:51:08 -0800 Subject: [PATCH 08/26] Avoid extra margin --- src/Views/OperatingSystemView.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index b11fa83f..d4ca5d0a 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -141,7 +141,8 @@ public class About.OperatingSystemView : Gtk.Box { }; updates_image = new Gtk.Image () { - icon_size = LARGE + icon_size = LARGE, + margin_end = 6 }; updates_title = new Gtk.Label (null) { @@ -179,7 +180,6 @@ public class About.OperatingSystemView : Gtk.Box { }; var updates_grid = new Gtk.Grid () { - column_spacing = 6, margin_top = 6, margin_bottom = 6, margin_start = 6 From d2595f6166120cf1bfc13377850adfc0c9983375 Mon Sep 17 00:00:00 2001 From: Danielle Fore Date: Mon, 22 Jan 2024 14:52:23 -0800 Subject: [PATCH 09/26] More straightforward revealer settings --- src/Views/OperatingSystemView.vala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index d4ca5d0a..2da4f0b7 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -340,7 +340,8 @@ public class About.OperatingSystemView : Gtk.Box { return; } - update_button_revealer.reveal_child = false; + update_button_revealer.reveal_child = current_state.state == AVAILABLE; + cancel_button_revealer.reveal_child = current_state.state == DOWNLOADING; switch (current_state.state) { case UP_TO_DATE: @@ -358,7 +359,6 @@ public class About.OperatingSystemView : Gtk.Box { case AVAILABLE: updates_image.icon_name = "software-update-available"; updates_title.label = _("Updates Available"); - update_button_revealer.reveal_child = true; check_button.sensitive = true; try { @@ -379,7 +379,6 @@ public class About.OperatingSystemView : Gtk.Box { updates_image.icon_name = "browser-download"; updates_title.label = _("Downloading Updates"); updates_description.label = current_state.message; - cancel_button_revealer.reveal_child = true; check_button.sensitive = false; break; case RESTART_REQUIRED: From ab213dae7d2840cbb37f863613aa2aa2fd39d65b Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:16:11 +0100 Subject: [PATCH 10/26] Hookup update button and handle the correct errors --- src/Views/OperatingSystemView.vala | 46 ++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 2da4f0b7..002c7739 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -267,23 +267,39 @@ public class About.OperatingSystemView : Gtk.Box { } }); - cancel_button.clicked.connect (() => { + check_button.clicked.connect (() => { if (update_proxy != null) { - try { - update_proxy.cancel.begin (); - } catch (Error e) { - critical ("Failed to cancel update: %s", e.message); - } + update_proxy.check_for_updates.begin (false, (obj, res) => { + try { + update_proxy.check_for_updates.end (res); + } catch (Error e) { + critical ("Failed to check for updates: %s", e.message); + } + }); } }); - check_button.clicked.connect (() => { + update_button.clicked.connect (() => { if (update_proxy != null) { - try { - update_proxy.check_for_updates.begin (); - } catch (Error e) { - warning ("Failed to check for updates: %s", e.message); - } + update_proxy.update.begin ((obj, res) => { + try { + update_proxy.update.end (res); + } catch (Error e) { + critical ("Failed to update: %s", e.message); + } + }); + } + }); + + cancel_button.clicked.connect (() => { + if (update_proxy != null) { + update_proxy.cancel.begin ((obj, res) => { + try { + update_proxy.cancel.end (res); + } catch (Error e) { + critical ("Failed to cancel update: %s", e.message); + } + }); } }); } @@ -387,6 +403,12 @@ public class About.OperatingSystemView : Gtk.Box { updates_description.label = _("A restart is required to finish installing updates"); check_button.sensitive = false; break; + case ERROR: + updates_image.icon_name = "dialog-error"; + updates_title.label = _("Error"); + updates_description.label = _("An error occured while trying to update the system"); + check_button.sensitive = false; + break; } } From 905c1db01a9c27ff65ae7a9df4870518c00d7c8c Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Tue, 23 Jan 2024 00:16:54 +0100 Subject: [PATCH 11/26] Update src/Views/OperatingSystemView.vala MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danielle Foré --- src/Views/OperatingSystemView.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 002c7739..e9437290 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -161,6 +161,7 @@ public class About.OperatingSystemView : Gtk.Box { margin_end = 6, valign = CENTER }; + update_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION) update_button_revealer = new Gtk.Revealer () { child = update_button, From 3006e87760801836b434a54aeb27ba8b9b371ed6 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:21:05 +0100 Subject: [PATCH 12/26] Add error handling --- src/DBus/SystemUpdate.vala | 3 ++- src/Views/OperatingSystemView.vala | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/DBus/SystemUpdate.vala b/src/DBus/SystemUpdate.vala index 0a0633f4..aff6fcb8 100644 --- a/src/DBus/SystemUpdate.vala +++ b/src/DBus/SystemUpdate.vala @@ -5,7 +5,8 @@ public interface SystemUpdate : Object { CHECKING, AVAILABLE, DOWNLOADING, - RESTART_REQUIRED + RESTART_REQUIRED, + ERROR } public struct CurrentState { diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index e9437290..3f01bcd5 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -30,6 +30,7 @@ public class About.OperatingSystemView : Gtk.Box { private Gtk.Label updates_description; private Gtk.Revealer update_button_revealer; private Gtk.Revealer cancel_button_revealer; + private Gtk.Revealer error_button_revealer; construct { var style_provider = new Gtk.CssProvider (); @@ -161,7 +162,7 @@ public class About.OperatingSystemView : Gtk.Box { margin_end = 6, valign = CENTER }; - update_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION) + update_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); update_button_revealer = new Gtk.Revealer () { child = update_button, @@ -175,7 +176,18 @@ public class About.OperatingSystemView : Gtk.Box { }; cancel_button_revealer = new Gtk.Revealer () { - child = update_button, + child = cancel_button, + overflow = VISIBLE, + transition_type = SLIDE_LEFT + }; + + var error_button = new Gtk.Button.with_label (_("Refresh")) { + margin_end = 6, + valign = CENTER + }; + + error_button_revealer = new Gtk.Revealer () { + child = error_button, overflow = VISIBLE, transition_type = SLIDE_LEFT }; @@ -190,6 +202,7 @@ public class About.OperatingSystemView : Gtk.Box { updates_grid.attach (updates_description, 1, 1); updates_grid.attach (update_button_revealer, 2, 0, 1, 2); updates_grid.attach (cancel_button_revealer, 3, 0, 1, 2); + updates_grid.attach (error_button_revealer, 2, 0, 1, 2); var frame = new Gtk.Frame (null) { child = updates_grid, @@ -359,6 +372,7 @@ public class About.OperatingSystemView : Gtk.Box { update_button_revealer.reveal_child = current_state.state == AVAILABLE; cancel_button_revealer.reveal_child = current_state.state == DOWNLOADING; + error_button_revealer.reveal_child = current_state.state == ERROR; switch (current_state.state) { case UP_TO_DATE: From 13740fea9ec6fe18dd4648139b2a4d201f3589d4 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:26:51 +0100 Subject: [PATCH 13/26] Update description and hook up refresh button --- src/Views/OperatingSystemView.vala | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 3f01bcd5..99ca5acf 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -316,6 +316,18 @@ public class About.OperatingSystemView : Gtk.Box { }); } }); + + error_button.clicked.connect (() => { + if (update_proxy != null) { + update_proxy.check_for_updates.begin (true, (obj, res) => { + try { + update_proxy.check_for_updates.end (res); + } catch (Error e) { + critical ("Failed to force refresh: %s", e.message); + } + }); + } + }); } private async void get_upstream_release () { @@ -420,8 +432,8 @@ public class About.OperatingSystemView : Gtk.Box { break; case ERROR: updates_image.icon_name = "dialog-error"; - updates_title.label = _("Error"); - updates_description.label = _("An error occured while trying to update the system"); + updates_title.label = _("Failed to download updates"); + updates_description.label = _("Manually refreshing updates may resolve the issue."); check_button.sensitive = false; break; } From 1935602b233ac39f800236bbd80dda2c1ddb786b Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:31:52 +0100 Subject: [PATCH 14/26] Fix overlapping --- src/Views/OperatingSystemView.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 99ca5acf..b3d9ccde 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -202,7 +202,7 @@ public class About.OperatingSystemView : Gtk.Box { updates_grid.attach (updates_description, 1, 1); updates_grid.attach (update_button_revealer, 2, 0, 1, 2); updates_grid.attach (cancel_button_revealer, 3, 0, 1, 2); - updates_grid.attach (error_button_revealer, 2, 0, 1, 2); + updates_grid.attach (error_button_revealer, 4, 0, 1, 2); var frame = new Gtk.Frame (null) { child = updates_grid, From c738efacf553f7fb759c25a86556e122b698f3f7 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:34:00 +0100 Subject: [PATCH 15/26] Add start margins to buttons so that it doesn't look too ugly on long line lengths --- src/Views/OperatingSystemView.vala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index b3d9ccde..29a6446f 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -159,6 +159,7 @@ public class About.OperatingSystemView : Gtk.Box { updates_description.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); var update_button = new Gtk.Button.with_label (_("Download")) { + margin_start = 6, margin_end = 6, valign = CENTER }; @@ -171,6 +172,7 @@ public class About.OperatingSystemView : Gtk.Box { }; var cancel_button = new Gtk.Button.with_label (_("Cancel")) { + margin_start = 6, margin_end = 6, valign = CENTER }; @@ -182,6 +184,7 @@ public class About.OperatingSystemView : Gtk.Box { }; var error_button = new Gtk.Button.with_label (_("Refresh")) { + margin_start = 6, margin_end = 6, valign = CENTER }; From 485c436fdbf1a2be168f41a0c6602473b11f8598 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:38:13 +0100 Subject: [PATCH 16/26] Use stack :) --- src/Views/OperatingSystemView.vala | 40 +++++++++++------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 29a6446f..86b073c1 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -28,9 +28,7 @@ public class About.OperatingSystemView : Gtk.Box { private Gtk.Image updates_image; private Gtk.Label updates_title; private Gtk.Label updates_description; - private Gtk.Revealer update_button_revealer; - private Gtk.Revealer cancel_button_revealer; - private Gtk.Revealer error_button_revealer; + private Gtk.Stack button_stack; construct { var style_provider = new Gtk.CssProvider (); @@ -165,35 +163,25 @@ public class About.OperatingSystemView : Gtk.Box { }; update_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - update_button_revealer = new Gtk.Revealer () { - child = update_button, - overflow = VISIBLE, - transition_type = SLIDE_LEFT - }; - var cancel_button = new Gtk.Button.with_label (_("Cancel")) { margin_start = 6, margin_end = 6, valign = CENTER }; - cancel_button_revealer = new Gtk.Revealer () { - child = cancel_button, - overflow = VISIBLE, - transition_type = SLIDE_LEFT - }; - var error_button = new Gtk.Button.with_label (_("Refresh")) { margin_start = 6, margin_end = 6, valign = CENTER }; - error_button_revealer = new Gtk.Revealer () { - child = error_button, - overflow = VISIBLE, - transition_type = SLIDE_LEFT + button_stack = new Gtk.Stack () { + transition_type = CROSSFADE }; + button_stack.add_named (update_button, "update"); + button_stack.add_named (cancel_button, "cancel"); + button_stack.add_named (error_button, "error"); + button_stack.add_named (new Gtk.Grid (), "blank"); var updates_grid = new Gtk.Grid () { margin_top = 6, @@ -203,9 +191,7 @@ public class About.OperatingSystemView : Gtk.Box { updates_grid.attach (updates_image, 0, 0, 1, 2); updates_grid.attach (updates_title, 1, 0); updates_grid.attach (updates_description, 1, 1); - updates_grid.attach (update_button_revealer, 2, 0, 1, 2); - updates_grid.attach (cancel_button_revealer, 3, 0, 1, 2); - updates_grid.attach (error_button_revealer, 4, 0, 1, 2); + updates_grid.attach (button_stack, 2, 0, 1, 2); var frame = new Gtk.Frame (null) { child = updates_grid, @@ -385,27 +371,26 @@ public class About.OperatingSystemView : Gtk.Box { return; } - update_button_revealer.reveal_child = current_state.state == AVAILABLE; - cancel_button_revealer.reveal_child = current_state.state == DOWNLOADING; - error_button_revealer.reveal_child = current_state.state == ERROR; - switch (current_state.state) { case UP_TO_DATE: updates_image.icon_name = "process-completed"; updates_title.label = _("Up To Date"); updates_description.label = _("No updates available"); check_button.sensitive = true; + button_stack.visible_child_name = "blank"; break; case CHECKING: updates_image.icon_name = "emblem-synchronized"; updates_title.label = _("Checking for Updates"); updates_description.label = current_state.message; check_button.sensitive = false; + button_stack.visible_child_name = "blank"; break; case AVAILABLE: updates_image.icon_name = "software-update-available"; updates_title.label = _("Updates Available"); check_button.sensitive = true; + button_stack.visible_child_name = "update"; try { var details = yield update_proxy.get_update_details (); @@ -426,18 +411,21 @@ public class About.OperatingSystemView : Gtk.Box { updates_title.label = _("Downloading Updates"); updates_description.label = current_state.message; check_button.sensitive = false; + button_stack.visible_child_name = "cancel"; break; case RESTART_REQUIRED: updates_image.icon_name = "system-reboot"; updates_title.label = _("Restart Required"); updates_description.label = _("A restart is required to finish installing updates"); check_button.sensitive = false; + button_stack.visible_child_name = "blank"; break; case ERROR: updates_image.icon_name = "dialog-error"; updates_title.label = _("Failed to download updates"); updates_description.label = _("Manually refreshing updates may resolve the issue."); check_button.sensitive = false; + button_stack.visible_child_name = "error"; break; } } From 93c535f437a963d857f535a13e0386e46faf8255 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:45:11 +0100 Subject: [PATCH 17/26] Add last checked --- src/Views/OperatingSystemView.vala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 86b073c1..29262e6e 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -19,6 +19,8 @@ */ public class About.OperatingSystemView : Gtk.Box { + private static Settings update_settings = new Settings ("io.elementary.settings-daemon.system-updates"); + private string support_url; private Gtk.StringList updates; @@ -375,7 +377,11 @@ public class About.OperatingSystemView : Gtk.Box { case UP_TO_DATE: updates_image.icon_name = "process-completed"; updates_title.label = _("Up To Date"); - updates_description.label = _("No updates available"); + updates_description.label = _("Last checked %s.").printf ( + Granite.DateTime.get_relative_datetime ( + new DateTime.from_unix_local (update_settings.get_int64 ("last-refresh-time")) + ) + ); check_button.sensitive = true; button_stack.visible_child_name = "blank"; break; From b79238868c10d6352f69a3536b2b1e652997d9eb Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:49:08 +0100 Subject: [PATCH 18/26] Minor refinement and dont notify on manual check --- src/DBus/SystemUpdate.vala | 2 +- src/Views/OperatingSystemView.vala | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DBus/SystemUpdate.vala b/src/DBus/SystemUpdate.vala index aff6fcb8..4929a5c2 100644 --- a/src/DBus/SystemUpdate.vala +++ b/src/DBus/SystemUpdate.vala @@ -24,6 +24,6 @@ public interface SystemUpdate : Object { public abstract async CurrentState get_current_state () throws DBusError, IOError; public abstract async UpdateDetails get_update_details () throws DBusError, IOError; public abstract async void cancel () throws DBusError, IOError; - public abstract async void check_for_updates (bool force = false) throws DBusError, IOError; + public abstract async void check_for_updates (bool force, bool notify) throws DBusError, IOError; public abstract async void update () throws DBusError, IOError; } diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 29262e6e..32bd6224 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -180,10 +180,10 @@ public class About.OperatingSystemView : Gtk.Box { button_stack = new Gtk.Stack () { transition_type = CROSSFADE }; + button_stack.add_named (new Gtk.Grid (), "blank"); button_stack.add_named (update_button, "update"); button_stack.add_named (cancel_button, "cancel"); button_stack.add_named (error_button, "error"); - button_stack.add_named (new Gtk.Grid (), "blank"); var updates_grid = new Gtk.Grid () { margin_top = 6, @@ -274,7 +274,7 @@ public class About.OperatingSystemView : Gtk.Box { check_button.clicked.connect (() => { if (update_proxy != null) { - update_proxy.check_for_updates.begin (false, (obj, res) => { + update_proxy.check_for_updates.begin (false, false, (obj, res) => { try { update_proxy.check_for_updates.end (res); } catch (Error e) { @@ -310,7 +310,7 @@ public class About.OperatingSystemView : Gtk.Box { error_button.clicked.connect (() => { if (update_proxy != null) { - update_proxy.check_for_updates.begin (true, (obj, res) => { + update_proxy.check_for_updates.begin (true, false, (obj, res) => { try { update_proxy.check_for_updates.end (res); } catch (Error e) { From bd8e1ef6b1b7427230d7b1e4dcdcc305dcc335b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 22 Jan 2024 15:57:00 -0800 Subject: [PATCH 19/26] Clean up buttons (#283) --- src/Views/OperatingSystemView.vala | 70 ++++++++---------------------- 1 file changed, 17 insertions(+), 53 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 32bd6224..a86d9fb4 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -26,7 +26,6 @@ public class About.OperatingSystemView : Gtk.Box { private Gtk.StringList updates; private SystemUpdate? update_proxy = null; private Gtk.Grid software_grid; - private Gtk.Button check_button; private Gtk.Image updates_image; private Gtk.Label updates_title; private Gtk.Label updates_description; @@ -124,7 +123,10 @@ public class About.OperatingSystemView : Gtk.Box { _("Suggest Translations") ); - var bug_button = new Gtk.Button.with_label (_("Send Feedback")); + var bug_button = new Gtk.Button.with_label (_("Send Feedback")) { + halign = END, + hexpand = true + }; updates = new Gtk.StringList (null); @@ -142,8 +144,7 @@ public class About.OperatingSystemView : Gtk.Box { }; updates_image = new Gtk.Image () { - icon_size = LARGE, - margin_end = 6 + icon_size = LARGE }; updates_title = new Gtk.Label (null) { @@ -158,35 +159,26 @@ public class About.OperatingSystemView : Gtk.Box { updates_description.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); updates_description.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); - var update_button = new Gtk.Button.with_label (_("Download")) { - margin_start = 6, - margin_end = 6, - valign = CENTER - }; + var update_button = new Gtk.Button.with_label (_("Download")); update_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); - var cancel_button = new Gtk.Button.with_label (_("Cancel")) { - margin_start = 6, - margin_end = 6, - valign = CENTER - }; + var cancel_button = new Gtk.Button.with_label (_("Cancel")); - var error_button = new Gtk.Button.with_label (_("Refresh")) { - margin_start = 6, - margin_end = 6, - valign = CENTER - }; + var refresh_button = new Gtk.Button.with_label (_("Refresh")); button_stack = new Gtk.Stack () { - transition_type = CROSSFADE + transition_type = CROSSFADE, + valign = CENTER }; button_stack.add_named (new Gtk.Grid (), "blank"); button_stack.add_named (update_button, "update"); button_stack.add_named (cancel_button, "cancel"); - button_stack.add_named (error_button, "error"); + button_stack.add_named (refresh_button, "refresh"); var updates_grid = new Gtk.Grid () { + column_spacing = 6, margin_top = 6, + margin_end = 6, margin_bottom = 6, margin_start = 6 }; @@ -203,21 +195,11 @@ public class About.OperatingSystemView : Gtk.Box { }; frame.add_css_class (Granite.STYLE_CLASS_VIEW); - check_button = new Gtk.Button.with_label (_("Check for Updates")); - var settings_restore_button = new Gtk.Button.with_label (_("Restore Default Settings")); - var primary_button_box = new Gtk.Box (HORIZONTAL, 6) { - hexpand = true, - halign = END, - homogeneous = true - }; - primary_button_box.append (bug_button); - primary_button_box.append (check_button); - var button_grid = new Gtk.Box (HORIZONTAL, 6); button_grid.append (settings_restore_button); - button_grid.append (primary_button_box); + button_grid.append (bug_button); software_grid = new Gtk.Grid () { column_spacing = 32, @@ -272,18 +254,6 @@ public class About.OperatingSystemView : Gtk.Box { } }); - check_button.clicked.connect (() => { - if (update_proxy != null) { - update_proxy.check_for_updates.begin (false, false, (obj, res) => { - try { - update_proxy.check_for_updates.end (res); - } catch (Error e) { - critical ("Failed to check for updates: %s", e.message); - } - }); - } - }); - update_button.clicked.connect (() => { if (update_proxy != null) { update_proxy.update.begin ((obj, res) => { @@ -308,7 +278,7 @@ public class About.OperatingSystemView : Gtk.Box { } }); - error_button.clicked.connect (() => { + refresh_button.clicked.connect (() => { if (update_proxy != null) { update_proxy.check_for_updates.begin (true, false, (obj, res) => { try { @@ -382,20 +352,17 @@ public class About.OperatingSystemView : Gtk.Box { new DateTime.from_unix_local (update_settings.get_int64 ("last-refresh-time")) ) ); - check_button.sensitive = true; - button_stack.visible_child_name = "blank"; + button_stack.visible_child_name = "refresh"; break; case CHECKING: updates_image.icon_name = "emblem-synchronized"; updates_title.label = _("Checking for Updates"); updates_description.label = current_state.message; - check_button.sensitive = false; button_stack.visible_child_name = "blank"; break; case AVAILABLE: updates_image.icon_name = "software-update-available"; updates_title.label = _("Updates Available"); - check_button.sensitive = true; button_stack.visible_child_name = "update"; try { @@ -416,22 +383,19 @@ public class About.OperatingSystemView : Gtk.Box { updates_image.icon_name = "browser-download"; updates_title.label = _("Downloading Updates"); updates_description.label = current_state.message; - check_button.sensitive = false; button_stack.visible_child_name = "cancel"; break; case RESTART_REQUIRED: updates_image.icon_name = "system-reboot"; updates_title.label = _("Restart Required"); updates_description.label = _("A restart is required to finish installing updates"); - check_button.sensitive = false; button_stack.visible_child_name = "blank"; break; case ERROR: updates_image.icon_name = "dialog-error"; updates_title.label = _("Failed to download updates"); updates_description.label = _("Manually refreshing updates may resolve the issue."); - check_button.sensitive = false; - button_stack.visible_child_name = "error"; + button_stack.visible_child_name = "refresh"; break; } } From a78c0db4889877b115435807fb79eac97810cd39 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 00:59:13 +0100 Subject: [PATCH 20/26] Only FORCE refresh on error --- src/Views/OperatingSystemView.vala | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index a86d9fb4..5a159e00 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -278,17 +278,7 @@ public class About.OperatingSystemView : Gtk.Box { } }); - refresh_button.clicked.connect (() => { - if (update_proxy != null) { - update_proxy.check_for_updates.begin (true, false, (obj, res) => { - try { - update_proxy.check_for_updates.end (res); - } catch (Error e) { - critical ("Failed to force refresh: %s", e.message); - } - }); - } - }); + refresh_button.clicked.connect (refresh_clicked); } private async void get_upstream_release () { @@ -400,6 +390,19 @@ public class About.OperatingSystemView : Gtk.Box { } } + private async void refresh_clicked () { + if (update_proxy == null) { + return; + } + + try { + var force = (yield update_proxy.get_current_state ()).state == ERROR; + yield update_proxy.check_for_updates (force, false); + } catch (Error e) { + critical ("Failed to check for updates: %s", e.message); + } + } + private void launch_support_url () { try { AppInfo.launch_default_for_uri (support_url, null); From 23110387a5bc899eaf8948260d654d6885602d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 23 Jan 2024 03:09:57 -0800 Subject: [PATCH 21/26] Add package details dialog (#284) --- po/POTFILES | 1 + src/Views/OperatingSystemView.vala | 53 +++++++++++++-------- src/Widgets/UpdateDetailsDialog.vala | 71 ++++++++++++++++++++++++++++ src/meson.build | 3 +- 4 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 src/Widgets/UpdateDetailsDialog.vala diff --git a/po/POTFILES b/po/POTFILES index 6a97cd11..c48ca987 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -4,3 +4,4 @@ src/Views/FirmwareView.vala src/Views/HardwareView.vala src/Views/OperatingSystemView.vala src/Widgets/FirmwareUpdateRow.vala +src/Widgets/UpdateDetailsDialog.vala diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 5a159e00..54fb708e 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -22,13 +22,13 @@ public class About.OperatingSystemView : Gtk.Box { private static Settings update_settings = new Settings ("io.elementary.settings-daemon.system-updates"); private string support_url; - - private Gtk.StringList updates; + private Gtk.StringList packages; private SystemUpdate? update_proxy = null; private Gtk.Grid software_grid; private Gtk.Image updates_image; private Gtk.Label updates_title; private Gtk.Label updates_description; + private Gtk.Revealer details_button_revealer; private Gtk.Stack button_stack; construct { @@ -51,7 +51,9 @@ public class About.OperatingSystemView : Gtk.Box { icon_name = logo_icon_name, }; - var logo_overlay = new Gtk.Overlay (); + var logo_overlay = new Gtk.Overlay () { + valign = START + }; if (Gtk.IconTheme.get_for_display (Gdk.Display.get_default ()).has_icon (logo_icon_name + "-symbolic")) { foreach (unowned var path in Environment.get_system_data_dirs ()) { @@ -128,20 +130,7 @@ public class About.OperatingSystemView : Gtk.Box { hexpand = true }; - updates = new Gtk.StringList (null); - - var update_list = new Gtk.ListBox () { - vexpand = true, - selection_mode = Gtk.SelectionMode.SINGLE - }; - update_list.bind_model (updates, (obj) => { - var str = ((Gtk.StringObject) obj).string; - return new Gtk.Label (str); - }); - - var update_scrolled = new Gtk.ScrolledWindow () { - child = update_list - }; + packages = new Gtk.StringList (null); updates_image = new Gtk.Image () { icon_size = LARGE @@ -175,6 +164,18 @@ public class About.OperatingSystemView : Gtk.Box { button_stack.add_named (cancel_button, "cancel"); button_stack.add_named (refresh_button, "refresh"); + var details_button = new Gtk.Button.with_label (_("Learn More…")) { + halign = START, + has_frame = false, + margin_top = 6 + }; + details_button.add_css_class ("link"); + details_button.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); + + details_button_revealer = new Gtk.Revealer () { + child = details_button + }; + var updates_grid = new Gtk.Grid () { column_spacing = 6, margin_top = 6, @@ -186,6 +187,7 @@ public class About.OperatingSystemView : Gtk.Box { updates_grid.attach (updates_title, 1, 0); updates_grid.attach (updates_description, 1, 1); updates_grid.attach (button_stack, 2, 0, 1, 2); + updates_grid.attach (details_button_revealer, 1, 2, 2); var frame = new Gtk.Frame (null) { child = updates_grid, @@ -279,6 +281,13 @@ public class About.OperatingSystemView : Gtk.Box { }); refresh_button.clicked.connect (refresh_clicked); + + details_button.clicked.connect (() => { + var details_dialog = new UpdateDetailsDialog (packages) { + transient_for = (Gtk.Window) get_root () + }; + details_dialog.present (); + }); } private async void get_upstream_release () { @@ -333,6 +342,8 @@ public class About.OperatingSystemView : Gtk.Box { return; } + details_button_revealer.reveal_child = current_state.state == AVAILABLE; + switch (current_state.state) { case UP_TO_DATE: updates_image.icon_name = "process-completed"; @@ -358,12 +369,12 @@ public class About.OperatingSystemView : Gtk.Box { try { var details = yield update_proxy.get_update_details (); updates_description.label = ngettext ( - _("%i update available").printf (details.packages.length), - _("%i updates available").printf (details.packages.length), + "%i update available", + "%i updates available", details.packages.length - ); + ).printf (details.packages.length); - updates.splice (0, 0, details.packages); + packages.splice (0, packages.get_n_items (), details.packages); } catch (Error e) { updates_description.label = _("Unable to determine number of updates"); warning ("Failed to get updates list from backend: %s", e.message); diff --git a/src/Widgets/UpdateDetailsDialog.vala b/src/Widgets/UpdateDetailsDialog.vala new file mode 100644 index 00000000..4cd67a8d --- /dev/null +++ b/src/Widgets/UpdateDetailsDialog.vala @@ -0,0 +1,71 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) + */ + +public class About.UpdateDetailsDialog : Granite.Dialog { + public Gtk.StringList packages { get; construct; } + + public UpdateDetailsDialog (Gtk.StringList packages ) { + Object (packages: packages); + } + + construct { + title = _("What's New"); + modal = true; + + var title_label = new Gtk.Label ( + ngettext ( + "%u package will be upgraded", + "%u packages will be upgraded", + packages.get_n_items () + ).printf (packages.get_n_items ()) + ) { + halign = START + }; + title_label.add_css_class (Granite.STYLE_CLASS_TITLE_LABEL); + + var packages_listbox = new Gtk.ListBox () { + vexpand = true, + selection_mode = NONE + }; + packages_listbox.add_css_class (Granite.STYLE_CLASS_RICH_LIST); + packages_listbox.bind_model (packages, (obj) => { + var str = ((Gtk.StringObject) obj).string; + + var image = new Gtk.Image.from_icon_name ("package-x-generic") { + icon_size = LARGE + }; + + var label = new Gtk.Label (str); + + var box = new Gtk.Box (HORIZONTAL, 6); + box.append (image); + box.append (label); + + return box; + }); + + var scrolled = new Gtk.ScrolledWindow () { + child = packages_listbox, + max_content_height = 400, + propagate_natural_height = true + }; + + var frame = new Gtk.Frame (null) { + child = scrolled + }; + + var box = new Gtk.Box (VERTICAL, 12); + box.append (title_label); + box.append (frame); + + get_content_area ().append (box); + + add_button (_("Close"), Gtk.ResponseType.CLOSE); + + response.connect (() => { + close (); + }); + } +} diff --git a/src/meson.build b/src/meson.build index 217deb51..5c4edf49 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,7 +8,8 @@ plug_files = files( 'Views/FirmwareView.vala', 'Views/HardwareView.vala', 'Views/OperatingSystemView.vala', - 'Widgets/FirmwareUpdateRow.vala' + 'Widgets/FirmwareUpdateRow.vala', + 'Widgets' / 'UpdateDetailsDialog.vala' ) switchboard_dep = dependency('switchboard-3') From 383d5ec3b953011c41a5e909ae04ebb9789ac102 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 12:19:39 +0100 Subject: [PATCH 22/26] Add error details --- src/Views/OperatingSystemView.vala | 42 +++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 54fb708e..d83885a0 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -24,6 +24,7 @@ public class About.OperatingSystemView : Gtk.Box { private string support_url; private Gtk.StringList packages; private SystemUpdate? update_proxy = null; + private SystemUpdate.CurrentState? current_state = null; private Gtk.Grid software_grid; private Gtk.Image updates_image; private Gtk.Label updates_title; @@ -282,12 +283,7 @@ public class About.OperatingSystemView : Gtk.Box { refresh_button.clicked.connect (refresh_clicked); - details_button.clicked.connect (() => { - var details_dialog = new UpdateDetailsDialog (packages) { - transient_for = (Gtk.Window) get_root () - }; - details_dialog.present (); - }); + details_button.clicked.connect (details_clicked); } private async void get_upstream_release () { @@ -334,7 +330,6 @@ public class About.OperatingSystemView : Gtk.Box { return; } - SystemUpdate.CurrentState current_state; try { current_state = yield update_proxy.get_current_state (); } catch (Error e) { @@ -342,7 +337,7 @@ public class About.OperatingSystemView : Gtk.Box { return; } - details_button_revealer.reveal_child = current_state.state == AVAILABLE; + details_button_revealer.reveal_child = current_state.state == AVAILABLE || current_state.state == ERROR; switch (current_state.state) { case UP_TO_DATE: @@ -401,14 +396,41 @@ public class About.OperatingSystemView : Gtk.Box { } } + private void details_clicked () { + if (current_state == null) { + return; + } + + if (current_state.state == ERROR) { + var message_dialog = new Granite.MessageDialog ( + _("Failed to download updates"), + _("This may have been caused by sideloaded or manually compiled software, a third-party software source, or a package manager error. Manually refreshing updates may resolve the issue."), + new ThemedIcon ("dialog-error") + ) { + transient_for = (Gtk.Window) get_root (), + modal = true + }; + + message_dialog.show_error_details (current_state.message); + + message_dialog.response.connect (message_dialog.destroy); + message_dialog.present (); + return; + } + + var details_dialog = new UpdateDetailsDialog (packages) { + transient_for = (Gtk.Window) get_root () + }; + details_dialog.present (); + } + private async void refresh_clicked () { if (update_proxy == null) { return; } try { - var force = (yield update_proxy.get_current_state ()).state == ERROR; - yield update_proxy.check_for_updates (force, false); + yield update_proxy.check_for_updates (current_state.state == ERROR, false); } catch (Error e) { critical ("Failed to check for updates: %s", e.message); } From cc2ba33c5f3258009e2b2a60092619d420d4e09d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 23 Jan 2024 08:39:11 -0800 Subject: [PATCH 23/26] Consistently avoid terminating punctuation in secondary labels --- src/Views/OperatingSystemView.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index d83885a0..013028f8 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -343,7 +343,7 @@ public class About.OperatingSystemView : Gtk.Box { case UP_TO_DATE: updates_image.icon_name = "process-completed"; updates_title.label = _("Up To Date"); - updates_description.label = _("Last checked %s.").printf ( + updates_description.label = _("Last checked %s").printf ( Granite.DateTime.get_relative_datetime ( new DateTime.from_unix_local (update_settings.get_int64 ("last-refresh-time")) ) @@ -390,7 +390,7 @@ public class About.OperatingSystemView : Gtk.Box { case ERROR: updates_image.icon_name = "dialog-error"; updates_title.label = _("Failed to download updates"); - updates_description.label = _("Manually refreshing updates may resolve the issue."); + updates_description.label = _("Manually refreshing updates may resolve the issue"); button_stack.visible_child_name = "refresh"; break; } From e3e679b483187d78aac2eb68d5d491b3ad027d31 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 23 Jan 2024 19:58:06 +0100 Subject: [PATCH 24/26] Always force check for update and update settings id --- src/Views/OperatingSystemView.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 013028f8..23a1b382 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -19,7 +19,7 @@ */ public class About.OperatingSystemView : Gtk.Box { - private static Settings update_settings = new Settings ("io.elementary.settings-daemon.system-updates"); + private static Settings update_settings = new Settings ("io.elementary.settings-daemon.system-update"); private string support_url; private Gtk.StringList packages; @@ -430,7 +430,7 @@ public class About.OperatingSystemView : Gtk.Box { } try { - yield update_proxy.check_for_updates (current_state.state == ERROR, false); + yield update_proxy.check_for_updates (true, false); } catch (Error e) { critical ("Failed to check for updates: %s", e.message); } From 088154bee7441b5f1523faa36643c106a02e68e2 Mon Sep 17 00:00:00 2001 From: Danielle Fore Date: Tue, 23 Jan 2024 13:03:49 -0800 Subject: [PATCH 25/26] Prevent blank stack preserving space, never hscroll --- src/Views/OperatingSystemView.vala | 1 + src/Widgets/UpdateDetailsDialog.vala | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index e7b41585..ece69121 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -157,6 +157,7 @@ public class About.OperatingSystemView : Gtk.Box { var refresh_button = new Gtk.Button.with_label (_("Refresh")); button_stack = new Gtk.Stack () { + hhomogeneous = false, transition_type = CROSSFADE, valign = CENTER }; diff --git a/src/Widgets/UpdateDetailsDialog.vala b/src/Widgets/UpdateDetailsDialog.vala index 4cd67a8d..606185fa 100644 --- a/src/Widgets/UpdateDetailsDialog.vala +++ b/src/Widgets/UpdateDetailsDialog.vala @@ -48,6 +48,7 @@ public class About.UpdateDetailsDialog : Granite.Dialog { var scrolled = new Gtk.ScrolledWindow () { child = packages_listbox, + hscrollbar_policy = NEVER, max_content_height = 400, propagate_natural_height = true }; From f2ea2ef51d6abb24514200ad81016d3dd862ba26 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Wed, 24 Jan 2024 19:52:21 +0100 Subject: [PATCH 26/26] local -> utc --- src/Views/OperatingSystemView.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index ece69121..a8951c6b 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -346,7 +346,7 @@ public class About.OperatingSystemView : Gtk.Box { updates_title.label = _("Up To Date"); updates_description.label = _("Last checked %s").printf ( Granite.DateTime.get_relative_datetime ( - new DateTime.from_unix_local (update_settings.get_int64 ("last-refresh-time")) + new DateTime.from_unix_utc (update_settings.get_int64 ("last-refresh-time")) ) ); button_stack.visible_child_name = "refresh";