From 7005ca5fcecfa07551f65792d53cce71da6972f5 Mon Sep 17 00:00:00 2001 From: Danielle Fore Date: Mon, 22 Jan 2024 14:22:18 -0800 Subject: [PATCH 1/3] Redesign --- src/DBus/SystemUpdate.vala | 27 ++++ src/Plug.vala | 3 - src/Views/OperatingSystemView.vala | 188 ++++++++++++++++++++++---- src/Views/UpdatesView.vala | 205 ----------------------------- src/meson.build | 2 +- 5 files changed, 192 insertions(+), 233 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..e1fc32d6 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,90 @@ 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, + 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 +194,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 +203,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 +210,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 +241,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 +297,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 = _("Restart 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 bb363bae..00000000 --- a/src/Views/UpdatesView.vala +++ /dev/null @@ -1,205 +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 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; - private Gtk.InfoBar reboot_infobar; - - public UpdatesView () { - Object ( - icon_name: "system-software-update", - title: _("Updates"), - description: _("System updates.") - ); - } - - 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 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"); - } - }); - - 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); - } - }); - } - }); - - check_button.clicked.connect (() => { - if (update_proxy != null) { - 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); - } - }); - } - }); - } - - 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 = "blank"; - 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 0a75ed309bce7a0f0958770f3955c707e4efc045 Mon Sep 17 00:00:00 2001 From: Danielle Fore Date: Mon, 22 Jan 2024 14:26:30 -0800 Subject: [PATCH 2/3] Fix restart label --- 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 e1fc32d6..8e1e6786 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -360,7 +360,7 @@ public class About.OperatingSystemView : Gtk.Box { case RESTART_REQUIRED: updates_image.icon_name = "system-reboot"; updates_title.label = _("Restart Required"); - updates_description.label = _("Restart to finish installing updates"); + updates_description.label = _("A restart is required to finish installing updates"); check_button.sensitive = false; break; } From 7b803609dee84e2de9994b71e87346a289fb13d1 Mon Sep 17 00:00:00 2001 From: Danielle Fore Date: Mon, 22 Jan 2024 14:42:33 -0800 Subject: [PATCH 3/3] Fix clipped focus style --- src/Views/OperatingSystemView.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Views/OperatingSystemView.vala b/src/Views/OperatingSystemView.vala index 8e1e6786..90e1bdf1 100644 --- a/src/Views/OperatingSystemView.vala +++ b/src/Views/OperatingSystemView.vala @@ -162,6 +162,7 @@ public class About.OperatingSystemView : Gtk.Box { update_button_revealer = new Gtk.Revealer () { child = update_button, + overflow = VISIBLE, transition_type = SLIDE_LEFT };