From dce9a58a2f2f45d5096adeeff5fa07dd86062cae Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Tue, 31 Dec 2024 07:54:28 -0500 Subject: [PATCH 01/16] Only add banner and recently updated apps when the cache is fully loaded. --- src/Core/FlatpakBackend.vala | 66 +++++++++++++++++++++++++----------- src/Views/Homepage.vala | 57 +++++++++++++++++++++---------- src/Widgets/Banner.vala | 16 ++++----- 3 files changed, 94 insertions(+), 45 deletions(-) diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index 293bc1f58..be0fc269a 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -51,6 +51,7 @@ public class AppCenterCore.FlatpakPackage : Package { public class AppCenterCore.FlatpakBackend : Object { public signal void operation_finished (Package package, Package.State operation, Error? error); public signal void cache_flush_needed (); + public signal void on_metadata_preprocessed (); // Based on https://github.com/flatpak/flatpak/blob/417e3949c0ecc314e69311e3ee8248320d3e3d52/common/flatpak-run-private.h private const string FLATPAK_METADATA_GROUP_APPLICATION = "Application"; @@ -963,8 +964,50 @@ public class AppCenterCore.FlatpakBackend : Object { return; } - GLib.GenericArray remotes = null; + preprocess_remotes_metadata (cancellable); + reload_appstream_pool (); + cache_flush_needed (); + job.result = Value (typeof (bool)); + job.result.set_boolean (true); + job.results_ready (); + } + public bool is_cache_refresh_needed () { + try { + if (user_installation != null && system_installation != null) { + var remotes = user_installation.list_remotes (); + remotes.extend_and_steal (system_installation.list_remotes ()); + for (int i = 0; i < remotes.length; i++) { + unowned Flatpak.Remote remote = remotes[i]; + if (remote_cache_refresh_needed (remote)) { + return true; + } + } + } + } catch (Error e) { + critical ("Error getting user flatpak remotes: %s", e.message); + } + + return false; + } + + private bool remote_cache_refresh_needed (Flatpak.Remote remote) { + var timestamp_file = remote.get_appstream_timestamp (null); + if (!timestamp_file.query_exists ()) { + return true; + } else { + var age = Utils.get_file_age (timestamp_file); + debug ("Appstream age: %u", age); + if (age > MAX_APPSTREAM_AGE) { + return true; + } + } + + return false; + } + + private void preprocess_remotes_metadata (GLib.Cancellable? cancellable) { + GLib.GenericArray remotes = null; if (user_installation != null) { try { user_installation.drop_caches (); @@ -985,12 +1028,7 @@ public class AppCenterCore.FlatpakBackend : Object { } } - reload_appstream_pool (); - cache_flush_needed (); - - job.result = Value (typeof (bool)); - job.result.set_boolean (true); - job.results_ready (); + on_metadata_preprocessed (); } private void preprocess_metadata (bool system, GLib.GenericArray remotes, Cancellable? cancellable) { @@ -1024,8 +1062,6 @@ public class AppCenterCore.FlatpakBackend : Object { for (int i = 0; i < remotes.length; i++) { unowned Flatpak.Remote remote = remotes[i]; - bool cache_refresh_needed = false; - unowned string origin_name = remote.get_name (); debug ("Found remote: %s", origin_name); @@ -1034,17 +1070,7 @@ public class AppCenterCore.FlatpakBackend : Object { continue; } - var timestamp_file = remote.get_appstream_timestamp (null); - if (!timestamp_file.query_exists ()) { - cache_refresh_needed = true; - } else { - var age = Utils.get_file_age (timestamp_file); - debug ("Appstream age: %u", age); - if (age > MAX_APPSTREAM_AGE) { - cache_refresh_needed = true; - } - } - + bool cache_refresh_needed = remote_cache_refresh_needed (remote); if (cache_refresh_needed) { debug ("Updating remote"); bool success = false; diff --git a/src/Views/Homepage.vala b/src/Views/Homepage.vala index a5dae8c42..12340e1d9 100644 --- a/src/Views/Homepage.vala +++ b/src/Views/Homepage.vala @@ -33,6 +33,9 @@ public class AppCenter.Homepage : Adw.NavigationPage { private Gtk.Revealer recently_updated_revealer; private Widgets.Banner appcenter_banner; + private Gtk.Revealer featured_apps_msg_revealer; + private Gtk.EventControllerMotion banner_motion_controller; + private Gtk.Button return_button; private Gtk.Label updates_badge; private Gtk.Revealer updates_badge_revealer; @@ -48,7 +51,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { hexpand = true; vexpand = true; - var banner_motion_controller = new Gtk.EventControllerMotion (); + banner_motion_controller = new Gtk.EventControllerMotion (); banner_carousel = new Adw.Carousel () { allow_long_swipes = true @@ -79,7 +82,8 @@ public class AppCenter.Homepage : Adw.NavigationPage { recently_updated_grid.attach (recently_updated_carousel, 0, 1); recently_updated_revealer = new Gtk.Revealer () { - child = recently_updated_grid + child = recently_updated_grid, + reveal_child = false }; var categories_label = new Granite.HeaderLabel (_("Categories")) { @@ -282,16 +286,33 @@ public class AppCenter.Homepage : Adw.NavigationPage { "#7239b3" ); banner_carousel.append (appcenter_banner); - - banner_carousel.page_changed.connect (page_changed_handler); + var spinner = new Gtk.Spinner () { + height_request = 24, + width_request = 24 + }; + spinner.start (); + var latest_featured_apps = new Gtk.Label (_("Getting Latest Apps")); + latest_featured_apps.add_css_class (Granite.STYLE_CLASS_H3_LABEL); + var featured_apps_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 8) { + halign = Gtk.Align.CENTER, + }; + featured_apps_box.append (spinner); + featured_apps_box.append (latest_featured_apps); + featured_apps_msg_revealer = new Gtk.Revealer () { + child = featured_apps_box, + reveal_child = true, + }; + appcenter_banner.main_box.append (featured_apps_msg_revealer); } - load_banners_and_carousels.begin ((obj, res) => { - load_banners_and_carousels.end (res); - banner_timeout_start (); - banner_motion_controller.enter.connect (banner_timeout_stop); - banner_motion_controller.leave.connect (banner_timeout_start); - }); + var backend = AppCenterCore.FlatpakBackend.get_default (); + if (backend.is_cache_refresh_needed ()) { + backend.on_metadata_preprocessed.connect (() => { + load_banners_and_carousels (backend); + }); + } else { + load_banners_and_carousels (backend); + } category_flow.child_activated.connect ((child) => { var card = (AbstractCategoryCard) child; @@ -314,14 +335,10 @@ public class AppCenter.Homepage : Adw.NavigationPage { }); } - private void page_changed_handler () { - banner_carousel.remove (appcenter_banner); - banner_carousel.page_changed.disconnect (page_changed_handler); - } + private void load_banners_and_carousels (AppCenterCore.FlatpakBackend backend) { + featured_apps_msg_revealer.reveal_child = false; - private async void load_banners_and_carousels () { - unowned var fp_client = AppCenterCore.FlatpakBackend.get_default (); - var packages_by_release_date = fp_client.get_featured_packages_by_release_date (); + var packages_by_release_date = backend.get_featured_packages_by_release_date (); var packages_in_banner = new Gee.LinkedList (); foreach (var package in packages_by_release_date) { @@ -382,7 +399,13 @@ public class AppCenter.Homepage : Adw.NavigationPage { } } + banner_carousel.remove (appcenter_banner); + banner_carousel.scroll_to (banner_carousel.get_nth_page (0), false); recently_updated_revealer.reveal_child = recently_updated_carousel.get_first_child () != null; + + banner_timeout_start (); + banner_motion_controller.enter.connect (banner_timeout_stop); + banner_motion_controller.leave.connect (banner_timeout_start); } private void banner_timeout_start () { diff --git a/src/Widgets/Banner.vala b/src/Widgets/Banner.vala index c7e012959..173765dc7 100644 --- a/src/Widgets/Banner.vala +++ b/src/Widgets/Banner.vala @@ -33,6 +33,8 @@ public class AppCenter.Widgets.Banner : Gtk.Button { public string app_name { get; construct; } public string summary { get; construct; } + public Gtk.Box main_box { get; construct; } + public Banner (string name, string summary, string description, Icon icon, string brand_color) { Object ( brand_color: brand_color, @@ -48,7 +50,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { var scale_factor = ((Gtk.Application) Application.get_default ()).active_window.get_scale_factor (); Object ( - name: package.get_name (), + app_name: package.get_name (), summary: package.get_summary (), description: package.get_description (), icon: package.get_icon (128, scale_factor), @@ -59,17 +61,13 @@ public class AppCenter.Widgets.Banner : Gtk.Button { construct { var name_label = new Gtk.Label (app_name) { - max_width_chars = 50, use_markup = true, - wrap = true, xalign = 0 }; name_label.add_css_class ("name"); var summary_label = new Gtk.Label (summary) { - max_width_chars = 50, use_markup = true, - wrap = true, xalign = 0 }; summary_label.add_css_class ("summary"); @@ -82,7 +80,6 @@ public class AppCenter.Widgets.Banner : Gtk.Button { var description_label = new Gtk.Label (description) { ellipsize = Pango.EllipsizeMode.END, lines = 2, - max_width_chars = 50, use_markup = true, wrap = true, xalign = 0 @@ -98,18 +95,21 @@ public class AppCenter.Widgets.Banner : Gtk.Button { inner_box.append (summary_label); inner_box.append (description_label); - var outer_box = new Gtk.Box (HORIZONTAL, 0) { + var outer_box = new Gtk.Box (HORIZONTAL, 24) { halign = CENTER }; outer_box.append (icon_image); outer_box.append (inner_box); + main_box = new Gtk.Box (VERTICAL, 0); + main_box.append (outer_box); + add_css_class ("banner"); add_css_class (Granite.STYLE_CLASS_CARD); add_css_class (Granite.STYLE_CLASS_ROUNDED); hexpand = true; - child = outer_box; + child = main_box; var provider = new Gtk.CssProvider (); try { From efcfb0a9137d114cd019ca808556ee97024386c1 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Tue, 31 Dec 2024 08:01:23 -0500 Subject: [PATCH 02/16] Ensure packge get_icon method gets a proper icon and does ot end up with a borken icon. This also attmepts to load all available icons, including flatpak emote icons via priority according to freedekstop specs. --- src/Core/Package.vala | 166 ++++++++++++++++++++++++++++-------------- 1 file changed, 111 insertions(+), 55 deletions(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 69b79e793..30ff7cb2e 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -649,79 +649,135 @@ public class AppCenterCore.Package : Object { } public GLib.Icon get_icon (uint size, uint scale_factor) { - GLib.Icon? icon = null; - uint current_size = 0; - uint current_scale = 0; uint pixel_size = size * scale_factor; - unowned var icons = component.get_icons (); - foreach (unowned var _icon in icons) { - switch (_icon.get_kind ()) { + uint remote_current_size = 0; + uint remote_current_scale = 0; + uint cached_current_size = 0; + uint cached_current_scale = 0; + + AppStream.Icon? stock_icon = null; + AppStream.Icon? cached_icon = null; + AppStream.Icon? local_icon = null; + AppStream.Icon? remote_icon = null; + + unowned var all_icons = component.get_icons (); + foreach (var icon in all_icons) { + switch (icon.get_kind ()) { case AppStream.IconKind.STOCK: - unowned string icon_name = _icon.get_name (); - if (Gtk.IconTheme.get_for_display (Gdk.Display.get_default ()).has_icon (icon_name)) { - return new ThemedIcon (icon_name); + if (Gtk.IconTheme.get_for_display (Gdk.Display.get_default ()) + .has_icon (icon.get_name ())) { + stock_icon = icon; } - break; - case AppStream.IconKind.CACHED: case AppStream.IconKind.LOCAL: - var icon_scale = _icon.get_scale (); - var icon_width = _icon.get_width () * icon_scale; - bool is_bigger = (icon_width > current_size && current_size < pixel_size); - bool has_better_dpi = (icon_width == current_size && current_scale < icon_scale && scale_factor <= icon_scale); + local_icon = icon; + break; + case AppStream.IconKind.CACHED: + var icon_scale = icon.get_scale (); + var icon_width = icon.get_width () * icon_scale; + + bool is_bigger = icon_width > cached_current_size + && cached_current_size < pixel_size; + bool has_better_dpi = icon_width == cached_current_size + && cached_current_scale < icon_scale + && scale_factor <= icon_scale; + if (is_bigger || has_better_dpi) { - var file = File.new_for_path (_icon.get_filename ()); - icon = new FileIcon (file); - current_size = icon_width; - current_scale = icon_scale; + cached_icon = icon; + cached_current_size = icon_width; + cached_current_scale = icon_scale; } - break; + case AppStream.IconKind.REMOTE: + var icon_scale = icon.get_scale (); + var icon_width = icon.get_width () * icon_scale; - case AppStream.IconKind.UNKNOWN: - warning ("'%s' is an unknown kind of AppStream icon", _icon.get_name ()); - break; + bool is_bigger = icon_width > remote_current_size + && remote_current_size < pixel_size; + bool has_better_dpi = icon_width == remote_current_size + && remote_current_scale < icon_scale + && scale_factor <= icon_scale; - case AppStream.IconKind.REMOTE: - warning ("'%s' is a remote AppStream icon", _icon.get_name ()); + if (is_bigger || has_better_dpi) { + remote_icon = icon; + remote_current_size = icon_width; + remote_current_scale = icon_scale; + } + break; + case AppStream.IconKind.UNKNOWN: + message ("'%s' is an unknown kind of AppStream icon", icon.get_name ()); break; } } - if (icon == null) { - switch (component.get_kind ()) { - case AppStream.ComponentKind.ADDON: - icon = new ThemedIcon ("extension"); - break; - case AppStream.ComponentKind.FONT: - icon = new ThemedIcon ("font-x-generic"); - break; - case AppStream.ComponentKind.ICON_THEME: - icon = new ThemedIcon ("preferences-desktop-theme"); - break; - case AppStream.ComponentKind.CODEC: - case AppStream.ComponentKind.CONSOLE_APP: - case AppStream.ComponentKind.DESKTOP_APP: - case AppStream.ComponentKind.DRIVER: - case AppStream.ComponentKind.FIRMWARE: - case AppStream.ComponentKind.GENERIC: - - case AppStream.ComponentKind.INPUT_METHOD: //ComponentKind.INPUTMETHOD is deprecated has same value so cannot be included - case AppStream.ComponentKind.LOCALIZATION: - case AppStream.ComponentKind.OPERATING_SYSTEM: - case AppStream.ComponentKind.REPOSITORY: - case AppStream.ComponentKind.RUNTIME: - case AppStream.ComponentKind.SERVICE: - case AppStream.ComponentKind.UNKNOWN: - case AppStream.ComponentKind.WEB_APP: - debug ("component kind not handled %s", component.get_kind ().to_string ()); - icon = new ThemedIcon ("application-default-icon"); - break; + // Respecting the recommended order by the AppStream API + // https://www.freedesktop.org/software/appstream/docs/chap-CatalogData.html#tag-ct-icon + // STOCK -> CACHED -> LOCAL -> REMOTE + GLib.File? file = null; + if (stock_icon != null) { + return new ThemedIcon (stock_icon.get_name ()); + } else if (cached_icon != null) { + file = File.new_for_path (cached_icon.get_filename ()); + } else if (local_icon != null) { + file = File.new_for_path (local_icon.get_filename ()); + } else if (remote_icon != null) { + // We need to check if URL is valid and an actual image before loading + var url = remote_icon.get_url (); + try { + var session = new Soup.Session (); + session.set_timeout (2); + var msg = new Soup.Message ("GET", url); + session.send_and_read (msg); + + var content_type = msg.response_headers.get_content_type (null); + if (msg.status_code == 200 && content_type != null && content_type.contains ("image")) { + file = File.new_for_uri (remote_icon.get_url ()); + } else { + warning ("Could not load remote_icon %s: Bad status, url or not an image", url); + } + session.abort (); + } catch (Error e) { + warning ("Could not load remote_icon %s: %s", url, e.message); } } - return icon; + try { + if (file != null) { + // We don't use FileIcon here because it crashes for some reason! + return new BytesIcon (file.load_bytes ()); + } + } catch (Error e) { + critical ("Could not load icon file: %s", e.message); + warning ("Could not load icon file: %s", e.message); + } + + switch (component.get_kind ()) { + case AppStream.ComponentKind.ADDON: + return new ThemedIcon ("extension"); + case AppStream.ComponentKind.FONT: + return new ThemedIcon ("font-x-generic"); + case AppStream.ComponentKind.ICON_THEME: + return new ThemedIcon ("preferences-desktop-theme"); + case AppStream.ComponentKind.CODEC: + case AppStream.ComponentKind.CONSOLE_APP: + case AppStream.ComponentKind.DESKTOP_APP: + case AppStream.ComponentKind.DRIVER: + case AppStream.ComponentKind.FIRMWARE: + case AppStream.ComponentKind.GENERIC: + + case AppStream.ComponentKind.INPUT_METHOD: //ComponentKind.INPUTMETHOD is deprecated has same value so cannot be included + case AppStream.ComponentKind.LOCALIZATION: + case AppStream.ComponentKind.OPERATING_SYSTEM: + case AppStream.ComponentKind.REPOSITORY: + case AppStream.ComponentKind.RUNTIME: + case AppStream.ComponentKind.SERVICE: + case AppStream.ComponentKind.UNKNOWN: + case AppStream.ComponentKind.WEB_APP: + default: + debug ("Component kind not handled %s", component.get_kind ().to_string ()); + return new ThemedIcon ("application-default-icon"); + } } public Package? get_plugin_host_package () { From 3b2e072cbb1dad1ea169d8ad72b40c8202fc7f4a Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Tue, 31 Dec 2024 10:32:30 -0500 Subject: [PATCH 03/16] Load with FileIcon instead of BytesIcon (should be ok since we now verify cache existence). Also removing a not needed critical message --- src/Core/Package.vala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 30ff7cb2e..6eb282c3a 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -744,11 +744,9 @@ public class AppCenterCore.Package : Object { try { if (file != null) { - // We don't use FileIcon here because it crashes for some reason! - return new BytesIcon (file.load_bytes ()); + return new FileIcon (file); } } catch (Error e) { - critical ("Could not load icon file: %s", e.message); warning ("Could not load icon file: %s", e.message); } From e912881f3162b3639c7acf04e79723e8e628c207 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Tue, 31 Dec 2024 10:36:15 -0500 Subject: [PATCH 04/16] Added css to latest_apps_message to have a slightly bigger font --- data/styles/HomePage.scss | 4 ++++ src/Views/Homepage.vala | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/data/styles/HomePage.scss b/data/styles/HomePage.scss index 18bf65205..fbfb22fad 100644 --- a/data/styles/HomePage.scss +++ b/data/styles/HomePage.scss @@ -73,5 +73,9 @@ homepage { font-size: 0.95rem; opacity: 0.85; } + + .latest_apps_message { + font-size: 1.5rem; + } } } diff --git a/src/Views/Homepage.vala b/src/Views/Homepage.vala index 12340e1d9..cae0e0121 100644 --- a/src/Views/Homepage.vala +++ b/src/Views/Homepage.vala @@ -285,14 +285,14 @@ public class AppCenter.Homepage : Adw.NavigationPage { new ThemedIcon ("io.elementary.appcenter"), "#7239b3" ); - banner_carousel.append (appcenter_banner); var spinner = new Gtk.Spinner () { - height_request = 24, - width_request = 24 + height_request = 28, + width_request = 28, }; spinner.start (); var latest_featured_apps = new Gtk.Label (_("Getting Latest Apps")); latest_featured_apps.add_css_class (Granite.STYLE_CLASS_H3_LABEL); + latest_featured_apps.add_css_class ("latest_apps_message"); var featured_apps_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 8) { halign = Gtk.Align.CENTER, }; @@ -301,8 +301,10 @@ public class AppCenter.Homepage : Adw.NavigationPage { featured_apps_msg_revealer = new Gtk.Revealer () { child = featured_apps_box, reveal_child = true, + vexpand = false, }; appcenter_banner.main_box.append (featured_apps_msg_revealer); + banner_carousel.append (appcenter_banner); } var backend = AppCenterCore.FlatpakBackend.get_default (); From aaeab44aababa80981c7a3762b7c35937e085765 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Tue, 31 Dec 2024 22:05:53 -0500 Subject: [PATCH 05/16] Instead of message dialogue in banner. Have a spinner in each unloaded icon. Then, change it to the correct icon when you are sure its correspondent cahce remote has been updated properly. This happens aof Banner icons, ListPackageRowGrid icons, and AppInfoView Icons --- data/styles/AppInfoView.scss | 6 +++ data/styles/HomePage.scss | 12 +++++ src/Core/FlatpakBackend.vala | 6 +-- src/Core/Package.vala | 11 ++-- src/Views/AppInfoView.vala | 25 ++++++++- src/Views/Homepage.vala | 54 ++++++++----------- .../AppContainers/ListPackageRowGrid.vala | 23 ++++++++ src/Widgets/Banner.vala | 49 ++++++++++++----- 8 files changed, 133 insertions(+), 53 deletions(-) diff --git a/data/styles/AppInfoView.scss b/data/styles/AppInfoView.scss index b0089515c..f87b96fc1 100644 --- a/data/styles/AppInfoView.scss +++ b/data/styles/AppInfoView.scss @@ -35,6 +35,12 @@ appinfoview { } } + .spinner { + background-color: rgba(black, 0.65); + border-radius: rem(10px); + padding: rem(12px); + } + .content-warning-box { margin: rem(12px) rem(12px) 0; } diff --git a/data/styles/HomePage.scss b/data/styles/HomePage.scss index fbfb22fad..162d6211a 100644 --- a/data/styles/HomePage.scss +++ b/data/styles/HomePage.scss @@ -78,4 +78,16 @@ homepage { font-size: 1.5rem; } } + + .spinner { + background-color: rgba(black, 0.65); + border-radius: rem(10px); + padding: rem(12px); + + &-small { + background-color: rgba(black, 0.65); + border-radius: rem(5px); + padding: rem(5px); + } + } } diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index be0fc269a..5c11b6dda 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -51,7 +51,7 @@ public class AppCenterCore.FlatpakPackage : Package { public class AppCenterCore.FlatpakBackend : Object { public signal void operation_finished (Package package, Package.State operation, Error? error); public signal void cache_flush_needed (); - public signal void on_metadata_preprocessed (); + public signal void on_metadata_remote_preprocessed (string remote_title); // Based on https://github.com/flatpak/flatpak/blob/417e3949c0ecc314e69311e3ee8248320d3e3d52/common/flatpak-run-private.h private const string FLATPAK_METADATA_GROUP_APPLICATION = "Application"; @@ -1027,8 +1027,6 @@ public class AppCenterCore.FlatpakBackend : Object { warning ("Error getting system flatpak remotes: %s", e.message); } } - - on_metadata_preprocessed (); } private void preprocess_metadata (bool system, GLib.GenericArray remotes, Cancellable? cancellable) { @@ -1138,6 +1136,8 @@ public class AppCenterCore.FlatpakBackend : Object { } else { continue; } + + on_metadata_remote_preprocessed (remote.get_title ()); } } diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 6eb282c3a..b3b91412d 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -107,6 +107,7 @@ public class AppCenterCore.Package : Object { public ChangeInformation change_information { public get; private set; } public GLib.Cancellable action_cancellable { public get; private set; } public State state { public get; private set; default = State.NOT_INSTALLED; } + public bool has_generic_icon { public get; private set; } public double progress { get { @@ -661,6 +662,7 @@ public class AppCenterCore.Package : Object { AppStream.Icon? local_icon = null; AppStream.Icon? remote_icon = null; + has_generic_icon = false; unowned var all_icons = component.get_icons (); foreach (var icon in all_icons) { switch (icon.get_kind ()) { @@ -742,14 +744,11 @@ public class AppCenterCore.Package : Object { } } - try { - if (file != null) { - return new FileIcon (file); - } - } catch (Error e) { - warning ("Could not load icon file: %s", e.message); + if (file != null && file.query_exists ()) { + return new FileIcon (file); } + has_generic_icon = true; switch (component.get_kind ()) { case AppStream.ComponentKind.ADDON: return new ThemedIcon ("extension"); diff --git a/src/Views/AppInfoView.vala b/src/Views/AppInfoView.vala index 5373dbebd..9901f77aa 100644 --- a/src/Views/AppInfoView.vala +++ b/src/Views/AppInfoView.vala @@ -67,7 +67,8 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { } construct { - AppCenterCore.FlatpakBackend.get_default ().cache_flush_needed.connect (() => { + unowned var backend = AppCenterCore.FlatpakBackend.get_default (); + backend.cache_flush_needed.connect (() => { to_recycle = true; }); @@ -183,6 +184,28 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { } } + var spinner = new Gtk.Spinner () { + margin_top = 6, + halign = Gtk.Align.CENTER, + valign = Gtk.Align.CENTER, + width_request = 104, + height_request = 104, + visible = package.has_generic_icon + }; + spinner.start (); + spinner.add_css_class ("spinner"); + app_icon_overlay.add_overlay (spinner); + + if (package.has_generic_icon) { + backend.on_metadata_remote_preprocessed.connect ((remote_title) => { + if (package.origin_description == remote_title) { + spinner.visible = false; + app_icon.clear (); + app_icon.set_from_gicon (package.get_icon (128, scale_factor)); + } + }); + } + var app_title = new Gtk.Label (package.get_name ()) { selectable = true, wrap = true, diff --git a/src/Views/Homepage.vala b/src/Views/Homepage.vala index cae0e0121..54d633067 100644 --- a/src/Views/Homepage.vala +++ b/src/Views/Homepage.vala @@ -285,36 +285,10 @@ public class AppCenter.Homepage : Adw.NavigationPage { new ThemedIcon ("io.elementary.appcenter"), "#7239b3" ); - var spinner = new Gtk.Spinner () { - height_request = 28, - width_request = 28, - }; - spinner.start (); - var latest_featured_apps = new Gtk.Label (_("Getting Latest Apps")); - latest_featured_apps.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - latest_featured_apps.add_css_class ("latest_apps_message"); - var featured_apps_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 8) { - halign = Gtk.Align.CENTER, - }; - featured_apps_box.append (spinner); - featured_apps_box.append (latest_featured_apps); - featured_apps_msg_revealer = new Gtk.Revealer () { - child = featured_apps_box, - reveal_child = true, - vexpand = false, - }; - appcenter_banner.main_box.append (featured_apps_msg_revealer); banner_carousel.append (appcenter_banner); } - var backend = AppCenterCore.FlatpakBackend.get_default (); - if (backend.is_cache_refresh_needed ()) { - backend.on_metadata_preprocessed.connect (() => { - load_banners_and_carousels (backend); - }); - } else { - load_banners_and_carousels (backend); - } + load_banners_and_carousels (); category_flow.child_activated.connect ((child) => { var card = (AbstractCategoryCard) child; @@ -337,7 +311,8 @@ public class AppCenter.Homepage : Adw.NavigationPage { }); } - private void load_banners_and_carousels (AppCenterCore.FlatpakBackend backend) { + private void load_banners_and_carousels () { + unowned var backend = AppCenterCore.FlatpakBackend.get_default (); featured_apps_msg_revealer.reveal_child = false; var packages_by_release_date = backend.get_featured_packages_by_release_date (); @@ -351,7 +326,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { var installed = false; foreach (var origin_package in package.origin_packages) { try { - if (AppCenterCore.FlatpakBackend.get_default ().is_package_installed (origin_package)) { + if (backend.is_package_installed (origin_package)) { installed = true; break; } @@ -368,6 +343,15 @@ public class AppCenter.Homepage : Adw.NavigationPage { show_package (package); }); + if (package.has_generic_icon) { + backend.on_metadata_remote_preprocessed.connect ((remote_title) => { + if (remote_title == package.origin_description) { + var scale_factor = ((Gtk.Application) Application.get_default ()).active_window.get_scale_factor (); + banner.update_icon (package.get_icon (128, scale_factor)); + } + }); + } + banner_carousel.append (banner); } } @@ -386,7 +370,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { var installed = false; foreach (var origin_package in package.origin_packages) { try { - if (AppCenterCore.FlatpakBackend.get_default ().is_package_installed (origin_package)) { + if (backend.is_package_installed (origin_package)) { installed = true; break; } @@ -397,6 +381,14 @@ public class AppCenter.Homepage : Adw.NavigationPage { if (!installed) { var package_row = new AppCenter.Widgets.ListPackageRowGrid (package); + if (package.has_generic_icon) { + backend.on_metadata_remote_preprocessed.connect ((remote_title) => { + if (remote_title == package.origin_description) { + var scale_factor = ((Gtk.Application) Application.get_default ()).active_window.get_scale_factor (); + package_row.update_icon (package.get_icon (128, scale_factor)); + } + }); + } recently_updated_carousel.append (package_row); } } @@ -404,7 +396,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { banner_carousel.remove (appcenter_banner); banner_carousel.scroll_to (banner_carousel.get_nth_page (0), false); recently_updated_revealer.reveal_child = recently_updated_carousel.get_first_child () != null; - + banner_timeout_start (); banner_motion_controller.enter.connect (banner_timeout_stop); banner_motion_controller.leave.connect (banner_timeout_start); diff --git a/src/Widgets/AppContainers/ListPackageRowGrid.vala b/src/Widgets/AppContainers/ListPackageRowGrid.vala index c7bbfa5e3..0902fa3bd 100644 --- a/src/Widgets/AppContainers/ListPackageRowGrid.vala +++ b/src/Widgets/AppContainers/ListPackageRowGrid.vala @@ -19,6 +19,7 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { private Gtk.Label package_summary; + private Gtk.Spinner spinner; public ListPackageRowGrid (AppCenterCore.Package package) { Object (package: package); @@ -55,6 +56,19 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { column_spacing = 12, row_spacing = 3 }; + + spinner = new Gtk.Spinner () { + margin_top = 1, + halign = Gtk.Align.CENTER, + valign = Gtk.Align.CENTER, + width_request = 40, + height_request = 40, + visible = package.has_generic_icon + }; + spinner.start (); + spinner.add_css_class ("spinner-small"); + app_icon_overlay.add_overlay (spinner); + grid.attach (app_icon_overlay, 0, 0, 1, 2); grid.attach (package_name, 1, 0); grid.attach (package_summary, 1, 1); @@ -62,4 +76,13 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { append (grid); } + + public void update_icon (Icon icon) { + spinner.visible = false; + Gtk.Image icon_image = app_icon_overlay.child as Gtk.Image; + if (icon_image != null) { + icon_image.clear (); + icon_image.set_from_gicon (icon); + } + } } diff --git a/src/Widgets/Banner.vala b/src/Widgets/Banner.vala index 173765dc7..9c9f0e7ad 100644 --- a/src/Widgets/Banner.vala +++ b/src/Widgets/Banner.vala @@ -32,29 +32,34 @@ public class AppCenter.Widgets.Banner : Gtk.Button { public string description { get; construct; } public string app_name { get; construct; } public string summary { get; construct; } + public bool has_generic_icon { get; construct set; } - public Gtk.Box main_box { get; construct; } + private Gtk.Spinner spinner; + private Gtk.Image icon_image; public Banner (string name, string summary, string description, Icon icon, string brand_color) { Object ( - brand_color: brand_color, + app_name: name, + summary: summary, description: description, icon: icon, - app_name: name, - summary: summary + brand_color: brand_color, + has_generic_icon: false ); } public Banner.from_package (AppCenterCore.Package package) { // Can't get widget scale factor before it's realized var scale_factor = ((Gtk.Application) Application.get_default ()).active_window.get_scale_factor (); + var pkg_icon = package.get_icon (128, scale_factor); Object ( app_name: package.get_name (), summary: package.get_summary (), description: package.get_description (), - icon: package.get_icon (128, scale_factor), - brand_color: package.get_color_primary () + icon: pkg_icon, + brand_color: package.get_color_primary (), + has_generic_icon: package.has_generic_icon ); } @@ -86,7 +91,23 @@ public class AppCenter.Widgets.Banner : Gtk.Button { }; description_label.add_css_class ("description"); - var icon_image = new Gtk.Image.from_gicon (icon); + spinner = new Gtk.Spinner () { + margin_top = 6, + halign = Gtk.Align.FILL, + valign = Gtk.Align.CENTER, + width_request = 80, + height_request = 104, + visible = has_generic_icon + }; + spinner.start (); + spinner.add_css_class ("spinner"); + + icon_image = new Gtk.Image.from_gicon (icon); + icon_image.add_css_class ("icon_image"); + var image_overlay = new Gtk.Overlay () { + child = icon_image, + }; + image_overlay.add_overlay (spinner); var inner_box = new Gtk.Box (VERTICAL, 0) { valign = CENTER @@ -98,18 +119,15 @@ public class AppCenter.Widgets.Banner : Gtk.Button { var outer_box = new Gtk.Box (HORIZONTAL, 24) { halign = CENTER }; - outer_box.append (icon_image); + outer_box.append (image_overlay); outer_box.append (inner_box); - main_box = new Gtk.Box (VERTICAL, 0); - main_box.append (outer_box); - add_css_class ("banner"); add_css_class (Granite.STYLE_CLASS_CARD); add_css_class (Granite.STYLE_CLASS_ROUNDED); hexpand = true; - child = main_box; + child = outer_box; var provider = new Gtk.CssProvider (); try { @@ -131,4 +149,11 @@ public class AppCenter.Widgets.Banner : Gtk.Button { critical ("Unable to set accent color: %s", e.message); } } + + public void update_icon (Icon icon) { + has_generic_icon = false; + spinner.visible = false; + icon_image.clear (); + icon_image.set_from_gicon (icon); + } } From 93e5cf9b41abd65610ffbc091a6add0e99428d33 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Tue, 31 Dec 2024 22:06:26 -0500 Subject: [PATCH 06/16] Make some flatpak backends unowned --- src/Application.vala | 2 +- src/Services/SearchProvider.vala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index 912f4d1cd..d0630649c 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -130,7 +130,7 @@ public class AppCenter.App : Gtk.Application { activate (); }); - var flatpak_backend = AppCenterCore.FlatpakBackend.get_default (); + unowned var flatpak_backend = AppCenterCore.FlatpakBackend.get_default (); flatpak_backend.operation_finished.connect (on_operation_finished); var update_manager = AppCenterCore.UpdateManager.get_default (); diff --git a/src/Services/SearchProvider.vala b/src/Services/SearchProvider.vala index 05149e855..69cb3aea9 100644 --- a/src/Services/SearchProvider.vala +++ b/src/Services/SearchProvider.vala @@ -41,7 +41,7 @@ public class SearchProvider : Object { public HashTable[] get_result_metas (string[] results) throws GLib.Error { var result = new GenericArray> (); - var flatpak_backend = AppCenterCore.FlatpakBackend.get_default (); + unowned var flatpak_backend = AppCenterCore.FlatpakBackend.get_default (); foreach (var str in results) { var package = flatpak_backend.get_package_for_component_id (str); if (package != null) { From 4564a8ec0cb55e2c2e08895aa016b72fb0921a1d Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Tue, 31 Dec 2024 22:18:14 -0500 Subject: [PATCH 07/16] Eliminate a bunch of critical assertions and unused variables. --- src/Views/Homepage.vala | 22 ++++++++++++++-------- src/Widgets/BackButton.vala | 4 +++- src/Widgets/Banner.vala | 9 ++++++++- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/Views/Homepage.vala b/src/Views/Homepage.vala index 54d633067..6cef93fec 100644 --- a/src/Views/Homepage.vala +++ b/src/Views/Homepage.vala @@ -33,10 +33,8 @@ public class AppCenter.Homepage : Adw.NavigationPage { private Gtk.Revealer recently_updated_revealer; private Widgets.Banner appcenter_banner; - private Gtk.Revealer featured_apps_msg_revealer; private Gtk.EventControllerMotion banner_motion_controller; - private Gtk.Button return_button; private Gtk.Label updates_badge; private Gtk.Revealer updates_badge_revealer; @@ -254,7 +252,6 @@ public class AppCenter.Homepage : Adw.NavigationPage { var headerbar = new Gtk.HeaderBar () { show_title_buttons = true }; - headerbar.pack_start (return_button); if (!Utils.is_running_in_guest_session ()) { headerbar.pack_end (updates_overlay); } @@ -313,7 +310,6 @@ public class AppCenter.Homepage : Adw.NavigationPage { private void load_banners_and_carousels () { unowned var backend = AppCenterCore.FlatpakBackend.get_default (); - featured_apps_msg_revealer.reveal_child = false; var packages_by_release_date = backend.get_featured_packages_by_release_date (); var packages_in_banner = new Gee.LinkedList (); @@ -346,8 +342,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { if (package.has_generic_icon) { backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (remote_title == package.origin_description) { - var scale_factor = ((Gtk.Application) Application.get_default ()).active_window.get_scale_factor (); - banner.update_icon (package.get_icon (128, scale_factor)); + banner.update_icon (package.get_icon (128, get_app_scale_factor ())); } }); } @@ -384,8 +379,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { if (package.has_generic_icon) { backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (remote_title == package.origin_description) { - var scale_factor = ((Gtk.Application) Application.get_default ()).active_window.get_scale_factor (); - package_row.update_icon (package.get_icon (128, scale_factor)); + package_row.update_icon (package.get_icon (128, get_app_scale_factor ())); } }); } @@ -445,6 +439,18 @@ public class AppCenter.Homepage : Adw.NavigationPage { }); } + private int get_app_scale_factor () { + var scale_factor = 1; + var app = ((Gtk.Application) Application.get_default ()); + if (app != null) { + if (app.active_window != null) { + scale_factor = app.active_window.get_scale_factor (); + } + } + + return scale_factor; + } + private abstract class AbstractCategoryCard : Gtk.FlowBoxChild { public AppStream.Category category { get; protected set; } diff --git a/src/Widgets/BackButton.vala b/src/Widgets/BackButton.vala index eab1ec7a1..c0c1d8343 100644 --- a/src/Widgets/BackButton.vala +++ b/src/Widgets/BackButton.vala @@ -24,7 +24,9 @@ public class AppCenter.BackButton : Gtk.Button { var current_page = (Adw.NavigationPage) get_ancestor (typeof (Adw.NavigationPage)); var navigation_view = (Adw.NavigationView) get_ancestor (typeof (Adw.NavigationView)); var previous_page = navigation_view.get_previous_page (current_page); - label_widget.label = previous_page.title; + if (previous_page != null) { + label_widget.label = previous_page.title; + } }); } } diff --git a/src/Widgets/Banner.vala b/src/Widgets/Banner.vala index 9c9f0e7ad..794fcc964 100644 --- a/src/Widgets/Banner.vala +++ b/src/Widgets/Banner.vala @@ -50,7 +50,14 @@ public class AppCenter.Widgets.Banner : Gtk.Button { public Banner.from_package (AppCenterCore.Package package) { // Can't get widget scale factor before it's realized - var scale_factor = ((Gtk.Application) Application.get_default ()).active_window.get_scale_factor (); + var scale_factor = 1; + var app = ((Gtk.Application) Application.get_default ()); + if (app != null) { + if (app.active_window != null) { + scale_factor = app.active_window.get_scale_factor (); + } + } + var pkg_icon = package.get_icon (128, scale_factor); Object ( From 337213533011897cd3092a5671eeed2f8eab507d Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Tue, 31 Dec 2024 22:22:18 -0500 Subject: [PATCH 08/16] Better warnign message for remote icon url fetch --- src/Core/Package.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index b3b91412d..49ecae212 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -736,7 +736,7 @@ public class AppCenterCore.Package : Object { if (msg.status_code == 200 && content_type != null && content_type.contains ("image")) { file = File.new_for_uri (remote_icon.get_url ()); } else { - warning ("Could not load remote_icon %s: Bad status, url or not an image", url); + warning ("Could not load remote_icon %s: Status error, bad url, or not an image", url); } session.abort (); } catch (Error e) { From a69dccb40d55326c8af76848174bfcde45041c95 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Wed, 1 Jan 2025 06:55:58 -0500 Subject: [PATCH 09/16] Remove unused CSS --- data/styles/HomePage.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/data/styles/HomePage.scss b/data/styles/HomePage.scss index 162d6211a..3e96726de 100644 --- a/data/styles/HomePage.scss +++ b/data/styles/HomePage.scss @@ -73,10 +73,6 @@ homepage { font-size: 0.95rem; opacity: 0.85; } - - .latest_apps_message { - font-size: 1.5rem; - } } .spinner { From ac670cbb626fbb4c255c39ff4d534897a5fe75b8 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Wed, 1 Jan 2025 06:59:42 -0500 Subject: [PATCH 10/16] Restoring some unused code back to original state --- src/Core/FlatpakBackend.vala | 65 ++++++++++++------------------------ 1 file changed, 21 insertions(+), 44 deletions(-) diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index 5c11b6dda..babd5ab79 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -964,50 +964,8 @@ public class AppCenterCore.FlatpakBackend : Object { return; } - preprocess_remotes_metadata (cancellable); - reload_appstream_pool (); - cache_flush_needed (); - job.result = Value (typeof (bool)); - job.result.set_boolean (true); - job.results_ready (); - } - - public bool is_cache_refresh_needed () { - try { - if (user_installation != null && system_installation != null) { - var remotes = user_installation.list_remotes (); - remotes.extend_and_steal (system_installation.list_remotes ()); - for (int i = 0; i < remotes.length; i++) { - unowned Flatpak.Remote remote = remotes[i]; - if (remote_cache_refresh_needed (remote)) { - return true; - } - } - } - } catch (Error e) { - critical ("Error getting user flatpak remotes: %s", e.message); - } - - return false; - } - - private bool remote_cache_refresh_needed (Flatpak.Remote remote) { - var timestamp_file = remote.get_appstream_timestamp (null); - if (!timestamp_file.query_exists ()) { - return true; - } else { - var age = Utils.get_file_age (timestamp_file); - debug ("Appstream age: %u", age); - if (age > MAX_APPSTREAM_AGE) { - return true; - } - } - - return false; - } - - private void preprocess_remotes_metadata (GLib.Cancellable? cancellable) { GLib.GenericArray remotes = null; + if (user_installation != null) { try { user_installation.drop_caches (); @@ -1027,6 +985,13 @@ public class AppCenterCore.FlatpakBackend : Object { warning ("Error getting system flatpak remotes: %s", e.message); } } + + reload_appstream_pool (); + cache_flush_needed (); + + job.result = Value (typeof (bool)); + job.result.set_boolean (true); + job.results_ready (); } private void preprocess_metadata (bool system, GLib.GenericArray remotes, Cancellable? cancellable) { @@ -1060,6 +1025,8 @@ public class AppCenterCore.FlatpakBackend : Object { for (int i = 0; i < remotes.length; i++) { unowned Flatpak.Remote remote = remotes[i]; + bool cache_refresh_needed = false; + unowned string origin_name = remote.get_name (); debug ("Found remote: %s", origin_name); @@ -1068,7 +1035,17 @@ public class AppCenterCore.FlatpakBackend : Object { continue; } - bool cache_refresh_needed = remote_cache_refresh_needed (remote); + var timestamp_file = remote.get_appstream_timestamp (null); + if (!timestamp_file.query_exists ()) { + cache_refresh_needed = true; + } else { + var age = Utils.get_file_age (timestamp_file); + debug ("Appstream age: %u", age); + if (age > MAX_APPSTREAM_AGE) { + cache_refresh_needed = true; + } + } + if (cache_refresh_needed) { debug ("Updating remote"); bool success = false; From dd81748f3f3315e1d419898d96ff597f5a109731 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Wed, 1 Jan 2025 08:44:03 -0500 Subject: [PATCH 11/16] Use a better name for generic icon in package --- src/Core/Package.vala | 6 +++--- src/Views/AppInfoView.vala | 4 ++-- src/Views/Homepage.vala | 4 ++-- src/Widgets/AppContainers/ListPackageRowGrid.vala | 2 +- src/Widgets/Banner.vala | 10 +++++----- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 49ecae212..47caedfea 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -107,7 +107,7 @@ public class AppCenterCore.Package : Object { public ChangeInformation change_information { public get; private set; } public GLib.Cancellable action_cancellable { public get; private set; } public State state { public get; private set; default = State.NOT_INSTALLED; } - public bool has_generic_icon { public get; private set; } + public bool uses_generic_icon { public get; private set; } public double progress { get { @@ -662,7 +662,7 @@ public class AppCenterCore.Package : Object { AppStream.Icon? local_icon = null; AppStream.Icon? remote_icon = null; - has_generic_icon = false; + uses_generic_icon = false; unowned var all_icons = component.get_icons (); foreach (var icon in all_icons) { switch (icon.get_kind ()) { @@ -748,7 +748,7 @@ public class AppCenterCore.Package : Object { return new FileIcon (file); } - has_generic_icon = true; + uses_generic_icon = true; switch (component.get_kind ()) { case AppStream.ComponentKind.ADDON: return new ThemedIcon ("extension"); diff --git a/src/Views/AppInfoView.vala b/src/Views/AppInfoView.vala index 9901f77aa..7d9f46c1e 100644 --- a/src/Views/AppInfoView.vala +++ b/src/Views/AppInfoView.vala @@ -190,13 +190,13 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { valign = Gtk.Align.CENTER, width_request = 104, height_request = 104, - visible = package.has_generic_icon + visible = package.uses_generic_icon }; spinner.start (); spinner.add_css_class ("spinner"); app_icon_overlay.add_overlay (spinner); - if (package.has_generic_icon) { + if (package.uses_generic_icon) { backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (package.origin_description == remote_title) { spinner.visible = false; diff --git a/src/Views/Homepage.vala b/src/Views/Homepage.vala index 6cef93fec..1fb21c835 100644 --- a/src/Views/Homepage.vala +++ b/src/Views/Homepage.vala @@ -339,7 +339,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { show_package (package); }); - if (package.has_generic_icon) { + if (package.uses_generic_icon) { backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (remote_title == package.origin_description) { banner.update_icon (package.get_icon (128, get_app_scale_factor ())); @@ -376,7 +376,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { if (!installed) { var package_row = new AppCenter.Widgets.ListPackageRowGrid (package); - if (package.has_generic_icon) { + if (package.uses_generic_icon) { backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (remote_title == package.origin_description) { package_row.update_icon (package.get_icon (128, get_app_scale_factor ())); diff --git a/src/Widgets/AppContainers/ListPackageRowGrid.vala b/src/Widgets/AppContainers/ListPackageRowGrid.vala index 0902fa3bd..e85314a63 100644 --- a/src/Widgets/AppContainers/ListPackageRowGrid.vala +++ b/src/Widgets/AppContainers/ListPackageRowGrid.vala @@ -63,7 +63,7 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { valign = Gtk.Align.CENTER, width_request = 40, height_request = 40, - visible = package.has_generic_icon + visible = package.uses_generic_icon }; spinner.start (); spinner.add_css_class ("spinner-small"); diff --git a/src/Widgets/Banner.vala b/src/Widgets/Banner.vala index 794fcc964..686d876b8 100644 --- a/src/Widgets/Banner.vala +++ b/src/Widgets/Banner.vala @@ -32,7 +32,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { public string description { get; construct; } public string app_name { get; construct; } public string summary { get; construct; } - public bool has_generic_icon { get; construct set; } + public bool uses_generic_icon { get; construct set; } private Gtk.Spinner spinner; private Gtk.Image icon_image; @@ -44,7 +44,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { description: description, icon: icon, brand_color: brand_color, - has_generic_icon: false + uses_generic_icon: false ); } @@ -66,7 +66,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { description: package.get_description (), icon: pkg_icon, brand_color: package.get_color_primary (), - has_generic_icon: package.has_generic_icon + uses_generic_icon: package.uses_generic_icon ); } @@ -104,7 +104,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { valign = Gtk.Align.CENTER, width_request = 80, height_request = 104, - visible = has_generic_icon + visible = uses_generic_icon }; spinner.start (); spinner.add_css_class ("spinner"); @@ -158,7 +158,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { } public void update_icon (Icon icon) { - has_generic_icon = false; + uses_generic_icon = false; spinner.visible = false; icon_image.clear (); icon_image.set_from_gicon (icon); From 4c0048ab747e7b0b5b039076559116235663a455 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Wed, 1 Jan 2025 10:08:16 -0500 Subject: [PATCH 12/16] Fix for a crash when using FileIcon to load certain remote icons. BytesIcon works! --- src/Core/Package.vala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 47caedfea..bd19136db 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -734,7 +734,7 @@ public class AppCenterCore.Package : Object { var content_type = msg.response_headers.get_content_type (null); if (msg.status_code == 200 && content_type != null && content_type.contains ("image")) { - file = File.new_for_uri (remote_icon.get_url ()); + file = File.new_for_uri (url); } else { warning ("Could not load remote_icon %s: Status error, bad url, or not an image", url); } @@ -744,8 +744,13 @@ public class AppCenterCore.Package : Object { } } - if (file != null && file.query_exists ()) { - return new FileIcon (file); + try { + if (file != null && file.query_exists ()) { + // Using FileIcon for some remote icons causes a crash, BytesIcon works though! + return new BytesIcon (file.load_bytes ()); + } + } catch (Error e) { + warning ("Failed to load icon %s: %s", get_name (), e.message); } uses_generic_icon = true; From aafd3ade92ffcadff1298561455247c657d1cc50 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Wed, 1 Jan 2025 10:43:02 -0500 Subject: [PATCH 13/16] Remove remote icons load as it makes get_icon a blocking method. Also, ensure no spinner shows when an icon is not available (instead of failing to load icon) --- src/Core/Package.vala | 55 ++++--------------- src/Views/AppInfoView.vala | 2 +- .../AppContainers/ListPackageRowGrid.vala | 2 +- src/Widgets/Banner.vala | 2 +- 4 files changed, 14 insertions(+), 47 deletions(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index bd19136db..12cdfb10f 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -108,6 +108,7 @@ public class AppCenterCore.Package : Object { public GLib.Cancellable action_cancellable { public get; private set; } public State state { public get; private set; default = State.NOT_INSTALLED; } public bool uses_generic_icon { public get; private set; } + public bool icon_available { public get; private set; } public double progress { get { @@ -652,17 +653,15 @@ public class AppCenterCore.Package : Object { public GLib.Icon get_icon (uint size, uint scale_factor) { uint pixel_size = size * scale_factor; - uint remote_current_size = 0; - uint remote_current_scale = 0; uint cached_current_size = 0; uint cached_current_scale = 0; AppStream.Icon? stock_icon = null; AppStream.Icon? cached_icon = null; AppStream.Icon? local_icon = null; - AppStream.Icon? remote_icon = null; uses_generic_icon = false; + icon_available = true; unowned var all_icons = component.get_icons (); foreach (var icon in all_icons) { switch (icon.get_kind ()) { @@ -692,23 +691,12 @@ public class AppCenterCore.Package : Object { } break; case AppStream.IconKind.REMOTE: - var icon_scale = icon.get_scale (); - var icon_width = icon.get_width () * icon_scale; - - bool is_bigger = icon_width > remote_current_size - && remote_current_size < pixel_size; - bool has_better_dpi = icon_width == remote_current_size - && remote_current_scale < icon_scale - && scale_factor <= icon_scale; - - if (is_bigger || has_better_dpi) { - remote_icon = icon; - remote_current_size = icon_width; - remote_current_scale = icon_scale; - } + debug ("'%s' is an unknown kind of AppStream icon", icon.get_name ()); + // We are not loading remote icons for now due to blocking events downloading the file + // TODO: Dynamically load remote icons without blocking get_icon method break; case AppStream.IconKind.UNKNOWN: - message ("'%s' is an unknown kind of AppStream icon", icon.get_name ()); + debug ("'%s' is an unknown kind of AppStream icon", icon.get_name ()); break; } } @@ -723,34 +711,13 @@ public class AppCenterCore.Package : Object { file = File.new_for_path (cached_icon.get_filename ()); } else if (local_icon != null) { file = File.new_for_path (local_icon.get_filename ()); - } else if (remote_icon != null) { - // We need to check if URL is valid and an actual image before loading - var url = remote_icon.get_url (); - try { - var session = new Soup.Session (); - session.set_timeout (2); - var msg = new Soup.Message ("GET", url); - session.send_and_read (msg); - - var content_type = msg.response_headers.get_content_type (null); - if (msg.status_code == 200 && content_type != null && content_type.contains ("image")) { - file = File.new_for_uri (url); - } else { - warning ("Could not load remote_icon %s: Status error, bad url, or not an image", url); - } - session.abort (); - } catch (Error e) { - warning ("Could not load remote_icon %s: %s", url, e.message); - } + } else { + // Either a remote or unkonw icon type + icon_available = false; } - try { - if (file != null && file.query_exists ()) { - // Using FileIcon for some remote icons causes a crash, BytesIcon works though! - return new BytesIcon (file.load_bytes ()); - } - } catch (Error e) { - warning ("Failed to load icon %s: %s", get_name (), e.message); + if (file != null && file.query_exists ()) { + return new FileIcon (file); } uses_generic_icon = true; diff --git a/src/Views/AppInfoView.vala b/src/Views/AppInfoView.vala index 7d9f46c1e..2a7460429 100644 --- a/src/Views/AppInfoView.vala +++ b/src/Views/AppInfoView.vala @@ -190,7 +190,7 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { valign = Gtk.Align.CENTER, width_request = 104, height_request = 104, - visible = package.uses_generic_icon + visible = package.uses_generic_icon && package.icon_available }; spinner.start (); spinner.add_css_class ("spinner"); diff --git a/src/Widgets/AppContainers/ListPackageRowGrid.vala b/src/Widgets/AppContainers/ListPackageRowGrid.vala index e85314a63..e36c32fc0 100644 --- a/src/Widgets/AppContainers/ListPackageRowGrid.vala +++ b/src/Widgets/AppContainers/ListPackageRowGrid.vala @@ -63,7 +63,7 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { valign = Gtk.Align.CENTER, width_request = 40, height_request = 40, - visible = package.uses_generic_icon + visible = package.uses_generic_icon && package.icon_available }; spinner.start (); spinner.add_css_class ("spinner-small"); diff --git a/src/Widgets/Banner.vala b/src/Widgets/Banner.vala index 686d876b8..414d9e371 100644 --- a/src/Widgets/Banner.vala +++ b/src/Widgets/Banner.vala @@ -66,7 +66,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { description: package.get_description (), icon: pkg_icon, brand_color: package.get_color_primary (), - uses_generic_icon: package.uses_generic_icon + uses_generic_icon: package.uses_generic_icon && package.icon_available ); } From 687cea910c863cd588a3716727412f80feca11ed Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Wed, 1 Jan 2025 20:17:08 -0500 Subject: [PATCH 14/16] Fixing bad linter errros --- src/Core/Package.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 12cdfb10f..07aaa934d 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -683,7 +683,7 @@ public class AppCenterCore.Package : Object { bool has_better_dpi = icon_width == cached_current_size && cached_current_scale < icon_scale && scale_factor <= icon_scale; - + if (is_bigger || has_better_dpi) { cached_icon = icon; cached_current_size = icon_width; From 17f4940d10ace36e2f1927a88f2044585e521d99 Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Fri, 3 Jan 2025 18:16:00 -0500 Subject: [PATCH 15/16] Implemented a dimmed icon update via Gtk.Stack instead of Gtk.Spinner --- data/styles/AppInfoView.scss | 6 ---- data/styles/HomePage.scss | 14 ++------ src/Views/AppInfoView.vala | 31 ++++++++-------- src/Views/Homepage.vala | 4 +-- .../AppContainers/AbstractPackageRowGrid.vala | 32 ++++++++++++++--- .../AppContainers/ListPackageRowGrid.vala | 22 ------------ src/Widgets/Banner.vala | 36 ++++++++----------- 7 files changed, 61 insertions(+), 84 deletions(-) diff --git a/data/styles/AppInfoView.scss b/data/styles/AppInfoView.scss index f87b96fc1..b0089515c 100644 --- a/data/styles/AppInfoView.scss +++ b/data/styles/AppInfoView.scss @@ -35,12 +35,6 @@ appinfoview { } } - .spinner { - background-color: rgba(black, 0.65); - border-radius: rem(10px); - padding: rem(12px); - } - .content-warning-box { margin: rem(12px) rem(12px) 0; } diff --git a/data/styles/HomePage.scss b/data/styles/HomePage.scss index 3e96726de..d0ffcbafb 100644 --- a/data/styles/HomePage.scss +++ b/data/styles/HomePage.scss @@ -74,16 +74,8 @@ homepage { opacity: 0.85; } } +} - .spinner { - background-color: rgba(black, 0.65); - border-radius: rem(10px); - padding: rem(12px); - - &-small { - background-color: rgba(black, 0.65); - border-radius: rem(5px); - padding: rem(5px); - } - } +.icon-dim { + filter: blur(0.75px) saturate(10%); } diff --git a/src/Views/AppInfoView.vala b/src/Views/AppInfoView.vala index 2a7460429..ef18de1fb 100644 --- a/src/Views/AppInfoView.vala +++ b/src/Views/AppInfoView.vala @@ -155,6 +155,9 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { var app_icon = new Gtk.Image () { pixel_size = 128 }; + var app_icon_updated = new Gtk.Image () { + pixel_size = 128 + }; var badge_image = new Gtk.Image () { halign = Gtk.Align.END, @@ -162,8 +165,14 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { pixel_size = 64 }; + var app_icon_stack = new Gtk.Stack () { + transition_type = Gtk.StackTransitionType.CROSSFADE + }; + app_icon_stack.add_named (app_icon, "base_icon"); + app_icon_stack.add_named (app_icon_updated, "updated_icon"); + var app_icon_overlay = new Gtk.Overlay () { - child = app_icon, + child = app_icon_stack, valign = Gtk.Align.START }; @@ -184,24 +193,12 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { } } - var spinner = new Gtk.Spinner () { - margin_top = 6, - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER, - width_request = 104, - height_request = 104, - visible = package.uses_generic_icon && package.icon_available - }; - spinner.start (); - spinner.add_css_class ("spinner"); - app_icon_overlay.add_overlay (spinner); - - if (package.uses_generic_icon) { + if (package.uses_generic_icon && package.icon_available) { + app_icon.add_css_class ("icon-dim"); backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (package.origin_description == remote_title) { - spinner.visible = false; - app_icon.clear (); - app_icon.set_from_gicon (package.get_icon (128, scale_factor)); + app_icon_updated.set_from_gicon (package.get_icon (128, scale_factor)); + app_icon_stack.visible_child_name = "updated_icon"; } }); } diff --git a/src/Views/Homepage.vala b/src/Views/Homepage.vala index 1fb21c835..1443ac309 100644 --- a/src/Views/Homepage.vala +++ b/src/Views/Homepage.vala @@ -339,7 +339,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { show_package (package); }); - if (package.uses_generic_icon) { + if (package.uses_generic_icon && package.icon_available) { backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (remote_title == package.origin_description) { banner.update_icon (package.get_icon (128, get_app_scale_factor ())); @@ -376,7 +376,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { if (!installed) { var package_row = new AppCenter.Widgets.ListPackageRowGrid (package); - if (package.uses_generic_icon) { + if (package.uses_generic_icon && package.icon_available) { backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (remote_title == package.origin_description) { package_row.update_icon (package.get_icon (128, get_app_scale_factor ())); diff --git a/src/Widgets/AppContainers/AbstractPackageRowGrid.vala b/src/Widgets/AppContainers/AbstractPackageRowGrid.vala index dd1ed2cab..aab5052c7 100644 --- a/src/Widgets/AppContainers/AbstractPackageRowGrid.vala +++ b/src/Widgets/AppContainers/AbstractPackageRowGrid.vala @@ -30,16 +30,28 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { protected ActionStack action_stack; protected Gtk.Label package_name; protected Gtk.Overlay app_icon_overlay; + protected Gtk.Stack image_stack; + protected Gtk.Image updated_icon_image; protected AbstractPackageRowGrid (AppCenterCore.Package package) { Object (package: package); } construct { - var app_icon = new Gtk.Image () { + var icon_image = new Gtk.Image () { pixel_size = 48 }; + updated_icon_image = new Gtk.Image () { + pixel_size = 48 + }; + + image_stack = new Gtk.Stack () { + transition_type = Gtk.StackTransitionType.CROSSFADE + }; + image_stack.add_named (icon_image, "base_icon"); + image_stack.add_named (updated_icon_image, "updated_icon"); + var badge_image = new Gtk.Image () { halign = Gtk.Align.END, valign = Gtk.Align.END, @@ -47,7 +59,7 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { }; app_icon_overlay = new Gtk.Overlay () { - child = app_icon + child = image_stack }; action_stack = new ActionStack (package) { @@ -58,12 +70,14 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { var plugin_host_package = package.get_plugin_host_package (); if (package.kind == AppStream.ComponentKind.ADDON && plugin_host_package != null) { - app_icon.gicon = plugin_host_package.get_icon (app_icon.pixel_size, scale_factor); + icon_image.gicon = plugin_host_package.get_icon (icon_image.pixel_size, scale_factor); + updated_icon_image.gicon = plugin_host_package.get_icon (updated_icon_image.pixel_size, scale_factor); badge_image.gicon = package.get_icon (badge_image.pixel_size / 2, scale_factor); app_icon_overlay.add_overlay (badge_image); } else { - app_icon.gicon = package.get_icon (app_icon.pixel_size, scale_factor); + icon_image.gicon = package.get_icon (icon_image.pixel_size, scale_factor); + updated_icon_image.gicon = package.get_icon (updated_icon_image.pixel_size, scale_factor); if (package.is_runtime_updates) { badge_image.icon_name = "system-software-update"; @@ -71,9 +85,19 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { } } + if (package.uses_generic_icon && package.icon_available) { + icon_image.add_css_class ("icon-dim"); + } + margin_top = 6; margin_start = 12; margin_bottom = 6; margin_end = 12; } + + public void update_icon (Icon icon) { + updated_icon_image.clear (); + updated_icon_image.set_from_gicon (icon); + image_stack.visible_child_name = "updated_icon"; + } } diff --git a/src/Widgets/AppContainers/ListPackageRowGrid.vala b/src/Widgets/AppContainers/ListPackageRowGrid.vala index e36c32fc0..9825e7842 100644 --- a/src/Widgets/AppContainers/ListPackageRowGrid.vala +++ b/src/Widgets/AppContainers/ListPackageRowGrid.vala @@ -19,7 +19,6 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { private Gtk.Label package_summary; - private Gtk.Spinner spinner; public ListPackageRowGrid (AppCenterCore.Package package) { Object (package: package); @@ -57,18 +56,6 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { row_spacing = 3 }; - spinner = new Gtk.Spinner () { - margin_top = 1, - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER, - width_request = 40, - height_request = 40, - visible = package.uses_generic_icon && package.icon_available - }; - spinner.start (); - spinner.add_css_class ("spinner-small"); - app_icon_overlay.add_overlay (spinner); - grid.attach (app_icon_overlay, 0, 0, 1, 2); grid.attach (package_name, 1, 0); grid.attach (package_summary, 1, 1); @@ -76,13 +63,4 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { append (grid); } - - public void update_icon (Icon icon) { - spinner.visible = false; - Gtk.Image icon_image = app_icon_overlay.child as Gtk.Image; - if (icon_image != null) { - icon_image.clear (); - icon_image.set_from_gicon (icon); - } - } } diff --git a/src/Widgets/Banner.vala b/src/Widgets/Banner.vala index 414d9e371..8b3c4ca4e 100644 --- a/src/Widgets/Banner.vala +++ b/src/Widgets/Banner.vala @@ -34,8 +34,8 @@ public class AppCenter.Widgets.Banner : Gtk.Button { public string summary { get; construct; } public bool uses_generic_icon { get; construct set; } - private Gtk.Spinner spinner; - private Gtk.Image icon_image; + private Gtk.Stack image_stack; + private Gtk.Image updated_icon_image; public Banner (string name, string summary, string description, Icon icon, string brand_color) { Object ( @@ -98,23 +98,16 @@ public class AppCenter.Widgets.Banner : Gtk.Button { }; description_label.add_css_class ("description"); - spinner = new Gtk.Spinner () { - margin_top = 6, - halign = Gtk.Align.FILL, - valign = Gtk.Align.CENTER, - width_request = 80, - height_request = 104, - visible = uses_generic_icon - }; - spinner.start (); - spinner.add_css_class ("spinner"); - - icon_image = new Gtk.Image.from_gicon (icon); - icon_image.add_css_class ("icon_image"); - var image_overlay = new Gtk.Overlay () { - child = icon_image, + var icon_image = new Gtk.Image.from_gicon (icon); + if (uses_generic_icon) { + icon_image.add_css_class ("icon-dim"); + } + updated_icon_image = new Gtk.Image.from_gicon (icon); + image_stack = new Gtk.Stack () { + transition_type = Gtk.StackTransitionType.CROSSFADE, }; - image_overlay.add_overlay (spinner); + image_stack.add_named (icon_image, "base_icon"); + image_stack.add_named (updated_icon_image, "updated_icon"); var inner_box = new Gtk.Box (VERTICAL, 0) { valign = CENTER @@ -126,7 +119,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { var outer_box = new Gtk.Box (HORIZONTAL, 24) { halign = CENTER }; - outer_box.append (image_overlay); + outer_box.append (image_stack); outer_box.append (inner_box); add_css_class ("banner"); @@ -159,8 +152,7 @@ public class AppCenter.Widgets.Banner : Gtk.Button { public void update_icon (Icon icon) { uses_generic_icon = false; - spinner.visible = false; - icon_image.clear (); - icon_image.set_from_gicon (icon); + updated_icon_image.set_from_gicon (icon); + image_stack.visible_child_name = "updated_icon"; } } From 7b27f52c20579cb63c6e2ab9bed171aa300edc1f Mon Sep 17 00:00:00 2001 From: italo-capasso Date: Fri, 3 Jan 2025 19:07:12 -0500 Subject: [PATCH 16/16] Changed named Gtk.Stack named icons to ref widget icons for performance reasons --- src/Views/AppInfoView.vala | 6 +++--- src/Widgets/AppContainers/AbstractPackageRowGrid.vala | 6 +++--- src/Widgets/Banner.vala | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Views/AppInfoView.vala b/src/Views/AppInfoView.vala index ef18de1fb..7b816b78c 100644 --- a/src/Views/AppInfoView.vala +++ b/src/Views/AppInfoView.vala @@ -168,8 +168,8 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { var app_icon_stack = new Gtk.Stack () { transition_type = Gtk.StackTransitionType.CROSSFADE }; - app_icon_stack.add_named (app_icon, "base_icon"); - app_icon_stack.add_named (app_icon_updated, "updated_icon"); + app_icon_stack.add_child (app_icon); + app_icon_stack.add_child (app_icon_updated); var app_icon_overlay = new Gtk.Overlay () { child = app_icon_stack, @@ -198,7 +198,7 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { backend.on_metadata_remote_preprocessed.connect ((remote_title) => { if (package.origin_description == remote_title) { app_icon_updated.set_from_gicon (package.get_icon (128, scale_factor)); - app_icon_stack.visible_child_name = "updated_icon"; + app_icon_stack.visible_child = app_icon_updated; } }); } diff --git a/src/Widgets/AppContainers/AbstractPackageRowGrid.vala b/src/Widgets/AppContainers/AbstractPackageRowGrid.vala index aab5052c7..e640c82d6 100644 --- a/src/Widgets/AppContainers/AbstractPackageRowGrid.vala +++ b/src/Widgets/AppContainers/AbstractPackageRowGrid.vala @@ -49,8 +49,8 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { image_stack = new Gtk.Stack () { transition_type = Gtk.StackTransitionType.CROSSFADE }; - image_stack.add_named (icon_image, "base_icon"); - image_stack.add_named (updated_icon_image, "updated_icon"); + image_stack.add_child (icon_image); + image_stack.add_child (updated_icon_image); var badge_image = new Gtk.Image () { halign = Gtk.Align.END, @@ -98,6 +98,6 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { public void update_icon (Icon icon) { updated_icon_image.clear (); updated_icon_image.set_from_gicon (icon); - image_stack.visible_child_name = "updated_icon"; + image_stack.visible_child = updated_icon_image; } } diff --git a/src/Widgets/Banner.vala b/src/Widgets/Banner.vala index 8b3c4ca4e..a2ef8c2d7 100644 --- a/src/Widgets/Banner.vala +++ b/src/Widgets/Banner.vala @@ -106,8 +106,8 @@ public class AppCenter.Widgets.Banner : Gtk.Button { image_stack = new Gtk.Stack () { transition_type = Gtk.StackTransitionType.CROSSFADE, }; - image_stack.add_named (icon_image, "base_icon"); - image_stack.add_named (updated_icon_image, "updated_icon"); + image_stack.add_child (icon_image); + image_stack.add_child (updated_icon_image); var inner_box = new Gtk.Box (VERTICAL, 0) { valign = CENTER @@ -153,6 +153,6 @@ public class AppCenter.Widgets.Banner : Gtk.Button { public void update_icon (Icon icon) { uses_generic_icon = false; updated_icon_image.set_from_gicon (icon); - image_stack.visible_child_name = "updated_icon"; + image_stack.visible_child = updated_icon_image; } }