From 2a8107c7a2bc1b7706f8aa3106fc6c442ee8d42c Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 15:00:14 +0200 Subject: [PATCH 01/15] Prototype fast search --- src/Core/FlatpakBackend.vala | 24 +++++ src/Core/Package.vala | 27 ++++++ src/Core/SearchManager.vala | 32 +++++++ src/Views/SearchView.vala | 93 +++++++++++-------- .../AppContainers/ListPackageRowGrid.vala | 9 +- src/meson.build | 1 + 6 files changed, 144 insertions(+), 42 deletions(-) create mode 100644 src/Core/SearchManager.vala diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index 14e3cc839..4e593ca3f 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -440,7 +440,31 @@ public class AppCenterCore.FlatpakBackend : Object { return apps.values; } + public SearchManager get_search_manager () { + return new SearchManager (package_list.values.to_array ()); + } + + public Gee.Collection search_applications_fast (string query, AppStream.Category? category) { + warning ("SEARCHING FAST"); + var tokens = user_appstream_pool.build_search_tokens (query); + var packages = new ListStore (typeof (Package)); + var arr = package_list.values.to_array (); + packages.splice (0, 0, arr); + var filter = new Gtk.FilterListModel (packages, new Gtk.CustomFilter ((obj) => { + return ((Package) obj).matches_search (query) > 0; + })) { + incremental = true + }; + var result = new Gee.TreeSet (); + for (int i = 0; i < filter.n_items; i++) { + result.add ((Package) filter.get_item (i)); + } + warning ("SEARCHED FAST"); + return result; + } + public Gee.Collection search_applications (string query, AppStream.Category? category) { + return search_applications_fast (query, category); var results = new Gee.TreeSet (); var comps = user_appstream_pool.search (query); if (category == null) { diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 3f9fb8751..30f16c997 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -766,6 +766,33 @@ public class AppCenterCore.Package : Object { } } + public uint matches_search (string search_term) { + return component.search_matches (search_term); + // if (search_term == "") { + // return true; + // } + + // var _search_term = search_term.down (); + + // if (_search_term in get_name ().down ()) { + // return true; + // } + + // if (_search_term in get_summary ().down ()) { + // return true; + // } + + // if (_search_term in get_description ().down ()) { + // return true; + // } + + // if (_search_term in component.get_keywords_table ()) { + // return true; + // } + + // return false; + } + private string convert_version (string version) { if (is_runtime_updates) { return version; diff --git a/src/Core/SearchManager.vala b/src/Core/SearchManager.vala new file mode 100644 index 000000000..96dd150eb --- /dev/null +++ b/src/Core/SearchManager.vala @@ -0,0 +1,32 @@ +public class AppCenterCore.SearchManager : Object { + private ListStore packages; + + public ListModel results { get; construct; } + + public string query { get; set; } + + public SearchManager (Package[] packages) { + this.packages.splice (0, 0, packages); + } + + construct { + packages = new ListStore (typeof (Package)); + + var filter_model = new Gtk.FilterListModel (packages, new Gtk.CustomFilter ((obj) => { + return ((Package) obj).matches_search (query) > 0; + })); + + var sort_model = new Gtk.SortListModel (filter_model, new Gtk.CustomSorter ((obj1, obj2) => { + var package1 = (Package) obj1; + var package2 = (Package) obj2; + return (int) (package2.matches_search (query) - package1.matches_search (query)); + })); + + results = sort_model; + } + + public void search (string query) { + this.query = query; + packages.items_changed (0, packages.n_items, packages.n_items); + } +} diff --git a/src/Views/SearchView.vala b/src/Views/SearchView.vala index 8a3274888..4c70ef361 100644 --- a/src/Views/SearchView.vala +++ b/src/Views/SearchView.vala @@ -27,7 +27,8 @@ public class AppCenter.SearchView : Adw.NavigationPage { public string search_term { get; construct; } public bool mimetype { get; set; default = false; } - private GLib.ListStore list_store; + private AppCenterCore.SearchManager search_manager; + private GLib.ListModel list_store; private Gtk.SearchEntry search_entry; private Granite.Placeholder alert_view; @@ -63,16 +64,29 @@ public class AppCenter.SearchView : Adw.NavigationPage { list_store = new GLib.ListStore (typeof (AppCenterCore.Package)); - var list_box = new Gtk.ListBox () { - activate_on_single_click = true, + search_manager = AppCenterCore.FlatpakBackend.get_default ().get_search_manager (); + + var selection_model = new Gtk.NoSelection (search_manager.results); + + var factory = new Gtk.SignalListItemFactory (); + factory.setup.connect ((obj) => { + var list_item = (Gtk.ListItem) obj; + list_item.child = new Widgets.ListPackageRowGrid (null); + }); + factory.bind.connect ((obj) => { + var list_item = (Gtk.ListItem) obj; + ((Widgets.ListPackageRowGrid) list_item.child).bind ((AppCenterCore.Package) list_item.item); + }); + + var list_view = new Gtk.ListView (selection_model, factory) { hexpand = true, vexpand = true }; - list_box.bind_model (list_store, create_row_from_package); - list_box.set_placeholder (alert_view); + // list_box.bind_model (list_store, create_row_from_package); + // list_box.set_placeholder (alert_view); var scrolled = new Gtk.ScrolledWindow () { - child = list_box, + child = list_view, hscrollbar_policy = Gtk.PolicyType.NEVER }; @@ -91,10 +105,8 @@ public class AppCenter.SearchView : Adw.NavigationPage { search_entry.grab_focus (); }); - list_box.row_activated.connect ((row) => { - if (row is Widgets.PackageRow) { - show_app (((Widgets.PackageRow) row).get_package ()); - } + list_view.activate.connect ((index) => { + show_app ((AppCenterCore.Package) list_store.get_item (index)); }); search_entry.search_changed.connect (search); @@ -114,33 +126,34 @@ public class AppCenter.SearchView : Adw.NavigationPage { } private void search () { - list_store.remove_all (); + search_manager.search (search_entry.text); + // list_store.remove_all (); - if (search_entry.text.length >= VALID_QUERY_LENGTH) { - var dyn_flathub_link = "%s".printf (search_entry.text, _("Flathub")); - alert_view.description = _("Try changing search terms. You can also sideload Flatpak apps e.g. from %s").printf (dyn_flathub_link); + // if (search_entry.text.length >= VALID_QUERY_LENGTH) { + // var dyn_flathub_link = "%s".printf (search_entry.text, _("Flathub")); + // alert_view.description = _("Try changing search terms. You can also sideload Flatpak apps e.g. from %s").printf (dyn_flathub_link); - unowned var flatpak_backend = AppCenterCore.FlatpakBackend.get_default (); + // unowned var flatpak_backend = AppCenterCore.FlatpakBackend.get_default (); - Gee.Collection found_apps; + // Gee.Collection found_apps; - if (mimetype) { - found_apps = flatpak_backend.search_applications_mime (search_entry.text); - add_packages (found_apps); - } else { - var category = update_category (); + // if (mimetype) { + // found_apps = flatpak_backend.search_applications_mime (search_entry.text); + // add_packages (found_apps); + // } else { + // var category = update_category (); - found_apps = flatpak_backend.search_applications (search_entry.text, category); - add_packages (found_apps); - } + // found_apps = flatpak_backend.search_applications (search_entry.text, category); + // add_packages (found_apps); + // } - } else { - alert_view.description = _("The search term must be at least 3 characters long."); - } + // } else { + // alert_view.description = _("The search term must be at least 3 characters long."); + // } - if (mimetype) { - mimetype = false; - } + // if (mimetype) { + // mimetype = false; + // } } private AppStream.Category? update_category () { @@ -158,16 +171,16 @@ public class AppCenter.SearchView : Adw.NavigationPage { } public void add_packages (Gee.Collection packages) { - foreach (var package in packages) { - // Don't show plugins or fonts in search and category views - if (package.kind != AppStream.ComponentKind.ADDON && package.kind != AppStream.ComponentKind.FONT) { - GLib.CompareDataFunc sort_fn = (a, b) => { - return compare_packages (a, b); - }; - - list_store.insert_sorted (package, sort_fn); - } - } + // foreach (var package in packages) { + // // Don't show plugins or fonts in search and category views + // if (package.kind != AppStream.ComponentKind.ADDON && package.kind != AppStream.ComponentKind.FONT) { + // GLib.CompareDataFunc sort_fn = (a, b) => { + // return compare_packages (a, b); + // }; + + // list_store.insert_sorted (package, sort_fn); + // } + // } } private Gtk.Widget create_row_from_package (Object object) { diff --git a/src/Widgets/AppContainers/ListPackageRowGrid.vala b/src/Widgets/AppContainers/ListPackageRowGrid.vala index c7bbfa5e3..51d269ccd 100644 --- a/src/Widgets/AppContainers/ListPackageRowGrid.vala +++ b/src/Widgets/AppContainers/ListPackageRowGrid.vala @@ -20,12 +20,12 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { private Gtk.Label package_summary; - public ListPackageRowGrid (AppCenterCore.Package package) { + public ListPackageRowGrid (AppCenterCore.Package? package) { Object (package: package); } construct { - var package_name = new Gtk.Label (package.get_name ()) { + package_name = new Gtk.Label (package.get_name ()) { ellipsize = Pango.EllipsizeMode.END, lines = 2, max_width_chars = 1, @@ -62,4 +62,9 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { append (grid); } + + public void bind (AppCenterCore.Package package) { + package_name.label = package.get_name (); + package_summary.label = package.get_summary (); + } } diff --git a/src/meson.build b/src/meson.build index 28d93cdce..faf79f764 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,6 +12,7 @@ appcenter_files = files( 'Core/Houston.vala', 'Core/Package.vala', 'Core/ScreenshotCache.vala', + 'Core/SearchManager.vala', 'Core/SoupClient.vala', 'Core/Stripe.vala', 'Core/UpdateManager.vala', From e3337aa41010c179108a88ed463aaf6df85abd42 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 15:12:25 +0200 Subject: [PATCH 02/15] Some improvements --- src/Core/Package.vala | 4 +++- src/Core/SearchManager.vala | 2 +- src/Views/SearchView.vala | 5 ++--- .../AppContainers/AbstractPackageRowGrid.vala | 19 ++++++++++++------- .../AppContainers/ListPackageRowGrid.vala | 2 ++ 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 30f16c997..06984b635 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -766,8 +766,10 @@ public class AppCenterCore.Package : Object { } } + public uint cached_search_prio = 0; public uint matches_search (string search_term) { - return component.search_matches (search_term); + cached_search_prio = component.search_matches (search_term); + return cached_search_prio; // if (search_term == "") { // return true; // } diff --git a/src/Core/SearchManager.vala b/src/Core/SearchManager.vala index 96dd150eb..b628a719e 100644 --- a/src/Core/SearchManager.vala +++ b/src/Core/SearchManager.vala @@ -19,7 +19,7 @@ public class AppCenterCore.SearchManager : Object { var sort_model = new Gtk.SortListModel (filter_model, new Gtk.CustomSorter ((obj1, obj2) => { var package1 = (Package) obj1; var package2 = (Package) obj2; - return (int) (package2.matches_search (query) - package1.matches_search (query)); + return (int) (package2.cached_search_prio - package1.cached_search_prio); })); results = sort_model; diff --git a/src/Views/SearchView.vala b/src/Views/SearchView.vala index 4c70ef361..b3d6afeb5 100644 --- a/src/Views/SearchView.vala +++ b/src/Views/SearchView.vala @@ -79,11 +79,10 @@ public class AppCenter.SearchView : Adw.NavigationPage { }); var list_view = new Gtk.ListView (selection_model, factory) { + single_click_activate = true, hexpand = true, vexpand = true }; - // list_box.bind_model (list_store, create_row_from_package); - // list_box.set_placeholder (alert_view); var scrolled = new Gtk.ScrolledWindow () { child = list_view, @@ -106,7 +105,7 @@ public class AppCenter.SearchView : Adw.NavigationPage { }); list_view.activate.connect ((index) => { - show_app ((AppCenterCore.Package) list_store.get_item (index)); + show_app ((AppCenterCore.Package) search_manager.results.get_item (index)); }); search_entry.search_changed.connect (search); diff --git a/src/Widgets/AppContainers/AbstractPackageRowGrid.vala b/src/Widgets/AppContainers/AbstractPackageRowGrid.vala index dd1ed2cab..c6b365056 100644 --- a/src/Widgets/AppContainers/AbstractPackageRowGrid.vala +++ b/src/Widgets/AppContainers/AbstractPackageRowGrid.vala @@ -31,16 +31,19 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { protected Gtk.Label package_name; protected Gtk.Overlay app_icon_overlay; + private Gtk.Image app_icon; + private Gtk.Image badge_image; + protected AbstractPackageRowGrid (AppCenterCore.Package package) { Object (package: package); } construct { - var app_icon = new Gtk.Image () { + app_icon = new Gtk.Image () { pixel_size = 48 }; - var badge_image = new Gtk.Image () { + badge_image = new Gtk.Image () { halign = Gtk.Align.END, valign = Gtk.Align.END, pixel_size = 24 @@ -54,6 +57,13 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { show_open = false }; + margin_top = 6; + margin_start = 12; + margin_bottom = 6; + margin_end = 12; + } + + protected void update_package (AppCenterCore.Package package) { var scale_factor = get_scale_factor (); var plugin_host_package = package.get_plugin_host_package (); @@ -70,10 +80,5 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { app_icon_overlay.add_overlay (badge_image); } } - - margin_top = 6; - margin_start = 12; - margin_bottom = 6; - margin_end = 12; } } diff --git a/src/Widgets/AppContainers/ListPackageRowGrid.vala b/src/Widgets/AppContainers/ListPackageRowGrid.vala index 51d269ccd..96354429e 100644 --- a/src/Widgets/AppContainers/ListPackageRowGrid.vala +++ b/src/Widgets/AppContainers/ListPackageRowGrid.vala @@ -66,5 +66,7 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { public void bind (AppCenterCore.Package package) { package_name.label = package.get_name (); package_summary.label = package.get_summary (); + + update_package (package); } } From 526a3795b98656a8f410def6edaf96c6851d5e19 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 19:33:00 +0200 Subject: [PATCH 03/15] Only show unique packages --- src/Core/SearchManager.vala | 19 ++++++- src/Views/SearchView.vala | 109 ++++++++++-------------------------- 2 files changed, 46 insertions(+), 82 deletions(-) diff --git a/src/Core/SearchManager.vala b/src/Core/SearchManager.vala index b628a719e..15e376bbf 100644 --- a/src/Core/SearchManager.vala +++ b/src/Core/SearchManager.vala @@ -3,10 +3,22 @@ public class AppCenterCore.SearchManager : Object { public ListModel results { get; construct; } - public string query { get; set; } + public string query { get; private set; } + public AppStream.Category? category { get; private set; } public SearchManager (Package[] packages) { - this.packages.splice (0, 0, packages); + var unique_packages = new Gee.HashMap (); + foreach (var package in packages) { + var package_component_id = package.normalized_component_id; + if (unique_packages.has_key (package_component_id)) { + if (package.origin_score > unique_packages[package_component_id].origin_score) { + unique_packages[package_component_id] = package; + } + } else { + unique_packages[package_component_id] = package; + } + } + this.packages.splice (0, 0, unique_packages.values.to_array ()); } construct { @@ -25,8 +37,9 @@ public class AppCenterCore.SearchManager : Object { results = sort_model; } - public void search (string query) { + public void search (string query, AppStream.Category? category) { this.query = query; + this.category = category; // TODO packages.items_changed (0, packages.n_items, packages.n_items); } } diff --git a/src/Views/SearchView.vala b/src/Views/SearchView.vala index b3d6afeb5..07f0d6473 100644 --- a/src/Views/SearchView.vala +++ b/src/Views/SearchView.vala @@ -89,8 +89,12 @@ public class AppCenter.SearchView : Adw.NavigationPage { hscrollbar_policy = Gtk.PolicyType.NEVER }; + var stack = new Gtk.Stack (); + stack.add_child (alert_view); + stack.add_child (scrolled); + var toolbarview = new Adw.ToolbarView () { - content = scrolled + content = stack }; toolbarview.add_top_bar (headerbar); @@ -104,6 +108,16 @@ public class AppCenter.SearchView : Adw.NavigationPage { search_entry.grab_focus (); }); + selection_model.items_changed.connect (() => { + list_view.scroll_to (0, NONE, null); + + if (selection_model.n_items > 0) { + stack.visible_child = scrolled; + } else { + stack.visible_child = alert_view; + } + }); + list_view.activate.connect ((index) => { show_app ((AppCenterCore.Package) search_manager.results.get_item (index)); }); @@ -125,34 +139,23 @@ public class AppCenter.SearchView : Adw.NavigationPage { } private void search () { - search_manager.search (search_entry.text); - // list_store.remove_all (); - - // if (search_entry.text.length >= VALID_QUERY_LENGTH) { - // var dyn_flathub_link = "%s".printf (search_entry.text, _("Flathub")); - // alert_view.description = _("Try changing search terms. You can also sideload Flatpak apps e.g. from %s").printf (dyn_flathub_link); - - // unowned var flatpak_backend = AppCenterCore.FlatpakBackend.get_default (); - - // Gee.Collection found_apps; - - // if (mimetype) { - // found_apps = flatpak_backend.search_applications_mime (search_entry.text); - // add_packages (found_apps); - // } else { - // var category = update_category (); - - // found_apps = flatpak_backend.search_applications (search_entry.text, category); - // add_packages (found_apps); - // } + if (search_entry.text.length >= VALID_QUERY_LENGTH) { + var dyn_flathub_link = "%s".printf (search_entry.text, _("Flathub")); + alert_view.description = _("Try changing search terms. You can also sideload Flatpak apps e.g. from %s").printf (dyn_flathub_link); + + if (mimetype) { + // This didn't do anything + } else { + search_manager.search (search_entry.text, update_category ()); + } - // } else { - // alert_view.description = _("The search term must be at least 3 characters long."); - // } + } else { + alert_view.description = _("The search term must be at least 3 characters long."); + } - // if (mimetype) { - // mimetype = false; - // } + if (mimetype) { + mimetype = false; + } } private AppStream.Category? update_category () { @@ -168,56 +171,4 @@ public class AppCenter.SearchView : Adw.NavigationPage { search_entry.placeholder_text = _("Search Apps"); return null; } - - public void add_packages (Gee.Collection packages) { - // foreach (var package in packages) { - // // Don't show plugins or fonts in search and category views - // if (package.kind != AppStream.ComponentKind.ADDON && package.kind != AppStream.ComponentKind.FONT) { - // GLib.CompareDataFunc sort_fn = (a, b) => { - // return compare_packages (a, b); - // }; - - // list_store.insert_sorted (package, sort_fn); - // } - // } - } - - private Gtk.Widget create_row_from_package (Object object) { - unowned var package = (AppCenterCore.Package) object; - return new Widgets.PackageRow.list (package); - } - - private int search_priority (string name) { - if (name != null && search_entry.text != "") { - var name_lower = name.down (); - var term_lower = search_entry.text.down (); - - var term_position = name_lower.index_of (term_lower); - - // App name starts with our search term, highest priority - if (term_position == 0) { - return 2; - // App name contains our search term, high priority - } else if (term_position != -1) { - return 1; - } - } - - // Otherwise, normal appstream search ranking order - return 0; - } - - private int compare_packages (AppCenterCore.Package p1, AppCenterCore.Package p2) { - if ((p1.kind == AppStream.ComponentKind.ADDON) != (p2.kind == AppStream.ComponentKind.ADDON)) { - return p1.kind == AppStream.ComponentKind.ADDON ? 1 : -1; - } - - int sp1 = search_priority (p1.get_name ()); - int sp2 = search_priority (p2.get_name ()); - if (sp1 != sp2) { - return sp2 - sp1; - } - - return p1.get_name ().collate (p2.get_name ()); - } } From 619cf8f86e3805b2a88806d1740efd9683e2ffa0 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 19:39:25 +0200 Subject: [PATCH 04/15] Add category filtering --- src/Core/SearchManager.vala | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Core/SearchManager.vala b/src/Core/SearchManager.vala index 15e376bbf..b85546f80 100644 --- a/src/Core/SearchManager.vala +++ b/src/Core/SearchManager.vala @@ -18,6 +18,7 @@ public class AppCenterCore.SearchManager : Object { unique_packages[package_component_id] = package; } } + this.packages.splice (0, 0, unique_packages.values.to_array ()); } @@ -25,8 +26,16 @@ public class AppCenterCore.SearchManager : Object { packages = new ListStore (typeof (Package)); var filter_model = new Gtk.FilterListModel (packages, new Gtk.CustomFilter ((obj) => { + var package = (Package) obj; + + if (category != null && !package.component.is_member_of_category (category)) { + return false; + } + return ((Package) obj).matches_search (query) > 0; - })); + })) { + incremental = true + }; var sort_model = new Gtk.SortListModel (filter_model, new Gtk.CustomSorter ((obj1, obj2) => { var package1 = (Package) obj1; From 3f9f18ecc9e8e9eef83873b0f0c3fd50b04a8065 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 20:20:24 +0200 Subject: [PATCH 05/15] Search for multiple queries --- src/Core/FlatpakBackend.vala | 22 +------------------ src/Core/Package.vala | 42 ++++++++++++++++-------------------- src/Core/SearchManager.vala | 19 +++++++++------- 3 files changed, 31 insertions(+), 52 deletions(-) diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index 4e593ca3f..c15401f8a 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -441,30 +441,10 @@ public class AppCenterCore.FlatpakBackend : Object { } public SearchManager get_search_manager () { - return new SearchManager (package_list.values.to_array ()); - } - - public Gee.Collection search_applications_fast (string query, AppStream.Category? category) { - warning ("SEARCHING FAST"); - var tokens = user_appstream_pool.build_search_tokens (query); - var packages = new ListStore (typeof (Package)); - var arr = package_list.values.to_array (); - packages.splice (0, 0, arr); - var filter = new Gtk.FilterListModel (packages, new Gtk.CustomFilter ((obj) => { - return ((Package) obj).matches_search (query) > 0; - })) { - incremental = true - }; - var result = new Gee.TreeSet (); - for (int i = 0; i < filter.n_items; i++) { - result.add ((Package) filter.get_item (i)); - } - warning ("SEARCHED FAST"); - return result; + return new SearchManager (package_list.values.to_array (), user_appstream_pool); } public Gee.Collection search_applications (string query, AppStream.Category? category) { - return search_applications_fast (query, category); var results = new Gee.TreeSet (); var comps = user_appstream_pool.search (query); if (category == null) { diff --git a/src/Core/Package.vala b/src/Core/Package.vala index 06984b635..bb90bdbc5 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -766,33 +766,29 @@ public class AppCenterCore.Package : Object { } } - public uint cached_search_prio = 0; - public uint matches_search (string search_term) { - cached_search_prio = component.search_matches (search_term); - return cached_search_prio; - // if (search_term == "") { - // return true; - // } + public uint cached_search_score = 0; + public uint matches_search (string[] queries) { + // TODO: We don't use AppStream.Component.search_matches_all because it has some broken vapi + // (or at least I think so: the c code takes gchar** but vapi says string) - // var _search_term = search_term.down (); - - // if (_search_term in get_name ().down ()) { - // return true; - // } - - // if (_search_term in get_summary ().down ()) { - // return true; - // } + if (queries.length == 0) { + cached_search_score = 0; + return 0; + } - // if (_search_term in get_description ().down ()) { - // return true; - // } + uint score = 0; + foreach (var query in queries) { + var query_score = component.search_matches (query); - // if (_search_term in component.get_keywords_table ()) { - // return true; - // } + if (query_score == 0) { + score = 0; + break; + } - // return false; + score += query_score; + } + cached_search_score = score / queries.length; + return cached_search_score; } private string convert_version (string version) { diff --git a/src/Core/SearchManager.vala b/src/Core/SearchManager.vala index b85546f80..2f2549a11 100644 --- a/src/Core/SearchManager.vala +++ b/src/Core/SearchManager.vala @@ -1,12 +1,14 @@ -public class AppCenterCore.SearchManager : Object { - private ListStore packages; +public class AppCenterCore.SearchManager : Object { public ListModel results { get; construct; } - public string query { get; private set; } - public AppStream.Category? category { get; private set; } + private ListStore packages; + private AppStream.Pool pool; + + private string[] query; + private AppStream.Category? category; - public SearchManager (Package[] packages) { + public SearchManager (Package[] packages, AppStream.Pool pool) { var unique_packages = new Gee.HashMap (); foreach (var package in packages) { var package_component_id = package.normalized_component_id; @@ -20,6 +22,7 @@ public class AppCenterCore.SearchManager : Object { } this.packages.splice (0, 0, unique_packages.values.to_array ()); + this.pool = pool; } construct { @@ -40,15 +43,15 @@ public class AppCenterCore.SearchManager : Object { var sort_model = new Gtk.SortListModel (filter_model, new Gtk.CustomSorter ((obj1, obj2) => { var package1 = (Package) obj1; var package2 = (Package) obj2; - return (int) (package2.cached_search_prio - package1.cached_search_prio); + return (int) (package2.cached_search_score - package1.cached_search_score); })); results = sort_model; } public void search (string query, AppStream.Category? category) { - this.query = query; - this.category = category; // TODO + this.query = pool.build_search_tokens (query); + this.category = category; packages.items_changed (0, packages.n_items, packages.n_items); } } From 0f556c59eef0627dcc9a3c8eda88b7ad56f158d9 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 20:21:47 +0200 Subject: [PATCH 06/15] Cleanup --- src/Core/Package.vala | 50 +++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Core/Package.vala b/src/Core/Package.vala index bb90bdbc5..d4c4b3eaa 100644 --- a/src/Core/Package.vala +++ b/src/Core/Package.vala @@ -569,6 +569,31 @@ public class AppCenterCore.Package : Object { } } + public uint cached_search_score = 0; + public uint matches_search (string[] queries) { + // TODO: We don't use AppStream.Component.search_matches_all because it has some broken vapi + // (or at least I think so: the c code takes gchar** but vapi says string) + + if (queries.length == 0) { + cached_search_score = 0; + return 0; + } + + uint score = 0; + foreach (var query in queries) { + var query_score = component.search_matches (query); + + if (query_score == 0) { + score = 0; + break; + } + + score += query_score; + } + cached_search_score = score / queries.length; + return cached_search_score; + } + private string? name = null; public string? get_name () { if (name != null) { @@ -766,31 +791,6 @@ public class AppCenterCore.Package : Object { } } - public uint cached_search_score = 0; - public uint matches_search (string[] queries) { - // TODO: We don't use AppStream.Component.search_matches_all because it has some broken vapi - // (or at least I think so: the c code takes gchar** but vapi says string) - - if (queries.length == 0) { - cached_search_score = 0; - return 0; - } - - uint score = 0; - foreach (var query in queries) { - var query_score = component.search_matches (query); - - if (query_score == 0) { - score = 0; - break; - } - - score += query_score; - } - cached_search_score = score / queries.length; - return cached_search_score; - } - private string convert_version (string version) { if (is_runtime_updates) { return version; From dfd0e73f933f6fa1f0b6a359a86e3b31c433265a Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 20:25:38 +0200 Subject: [PATCH 07/15] Rename to search engine --- src/Core/FlatpakBackend.vala | 8 ++------ src/Core/{SearchManager.vala => SearchEngine.vala} | 4 ++-- src/Views/SearchView.vala | 12 ++++++------ src/meson.build | 2 +- 4 files changed, 11 insertions(+), 15 deletions(-) rename src/Core/{SearchManager.vala => SearchEngine.vala} (93%) diff --git a/src/Core/FlatpakBackend.vala b/src/Core/FlatpakBackend.vala index c15401f8a..20e546530 100644 --- a/src/Core/FlatpakBackend.vala +++ b/src/Core/FlatpakBackend.vala @@ -440,8 +440,8 @@ public class AppCenterCore.FlatpakBackend : Object { return apps.values; } - public SearchManager get_search_manager () { - return new SearchManager (package_list.values.to_array (), user_appstream_pool); + public SearchEngine get_search_engine () { + return new SearchEngine (package_list.values.to_array (), user_appstream_pool); } public Gee.Collection search_applications (string query, AppStream.Category? category) { @@ -497,10 +497,6 @@ public class AppCenterCore.FlatpakBackend : Object { return apps.values; } - public Gee.Collection search_applications_mime (string query) { - return new Gee.ArrayList (); - } - public Package? get_package_for_component_id (string id) { var suffixed_id = id + ".desktop"; foreach (var package in package_list.values) { diff --git a/src/Core/SearchManager.vala b/src/Core/SearchEngine.vala similarity index 93% rename from src/Core/SearchManager.vala rename to src/Core/SearchEngine.vala index 2f2549a11..8a8baa01c 100644 --- a/src/Core/SearchManager.vala +++ b/src/Core/SearchEngine.vala @@ -1,5 +1,5 @@ -public class AppCenterCore.SearchManager : Object { +public class AppCenterCore.SearchEngine : Object { public ListModel results { get; construct; } private ListStore packages; @@ -8,7 +8,7 @@ public class AppCenterCore.SearchManager : Object { private string[] query; private AppStream.Category? category; - public SearchManager (Package[] packages, AppStream.Pool pool) { + public SearchEngine (Package[] packages, AppStream.Pool pool) { var unique_packages = new Gee.HashMap (); foreach (var package in packages) { var package_component_id = package.normalized_component_id; diff --git a/src/Views/SearchView.vala b/src/Views/SearchView.vala index 07f0d6473..18bbdb8f6 100644 --- a/src/Views/SearchView.vala +++ b/src/Views/SearchView.vala @@ -27,7 +27,7 @@ public class AppCenter.SearchView : Adw.NavigationPage { public string search_term { get; construct; } public bool mimetype { get; set; default = false; } - private AppCenterCore.SearchManager search_manager; + private AppCenterCore.SearchEngine search_engine; private GLib.ListModel list_store; private Gtk.SearchEntry search_entry; private Granite.Placeholder alert_view; @@ -64,9 +64,9 @@ public class AppCenter.SearchView : Adw.NavigationPage { list_store = new GLib.ListStore (typeof (AppCenterCore.Package)); - search_manager = AppCenterCore.FlatpakBackend.get_default ().get_search_manager (); + search_engine = AppCenterCore.FlatpakBackend.get_default ().get_search_engine (); - var selection_model = new Gtk.NoSelection (search_manager.results); + var selection_model = new Gtk.NoSelection (search_engine.results); var factory = new Gtk.SignalListItemFactory (); factory.setup.connect ((obj) => { @@ -119,7 +119,7 @@ public class AppCenter.SearchView : Adw.NavigationPage { }); list_view.activate.connect ((index) => { - show_app ((AppCenterCore.Package) search_manager.results.get_item (index)); + show_app ((AppCenterCore.Package) search_engine.results.get_item (index)); }); search_entry.search_changed.connect (search); @@ -144,9 +144,9 @@ public class AppCenter.SearchView : Adw.NavigationPage { alert_view.description = _("Try changing search terms. You can also sideload Flatpak apps e.g. from %s").printf (dyn_flathub_link); if (mimetype) { - // This didn't do anything + // This didn't do anything so TODO } else { - search_manager.search (search_entry.text, update_category ()); + search_engine.search (search_entry.text, update_category ()); } } else { diff --git a/src/meson.build b/src/meson.build index faf79f764..fe73b1247 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,7 +12,7 @@ appcenter_files = files( 'Core/Houston.vala', 'Core/Package.vala', 'Core/ScreenshotCache.vala', - 'Core/SearchManager.vala', + 'Core/SearchEngine.vala', 'Core/SoupClient.vala', 'Core/Stripe.vala', 'Core/UpdateManager.vala', From 031edd2271d019e0e34dd3065a3217e4844ff501 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 20:54:09 +0200 Subject: [PATCH 08/15] Proper recycling --- src/Views/AppInfoView.vala | 3 +- src/Widgets/ActionStack.vala | 33 ++++++++---- .../AppContainers/AbstractPackageRowGrid.vala | 54 ++++++++++--------- .../InstalledPackageRowGrid.vala | 18 +++---- .../AppContainers/ListPackageRowGrid.vala | 6 ++- src/Widgets/HumbleButton.vala | 6 +-- src/Widgets/ProgressButton.vala | 28 ++++++---- 7 files changed, 85 insertions(+), 63 deletions(-) diff --git a/src/Views/AppInfoView.vala b/src/Views/AppInfoView.vala index d09b73e8d..b594d33f1 100644 --- a/src/Views/AppInfoView.vala +++ b/src/Views/AppInfoView.vala @@ -193,7 +193,8 @@ public class AppCenter.Views.AppInfoView : Adw.NavigationPage { overflow = VISIBLE }; - action_stack = new ActionStack (package); + action_stack = new ActionStack (); + action_stack.package = package; var button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { halign = Gtk.Align.END, diff --git a/src/Widgets/ActionStack.vala b/src/Widgets/ActionStack.vala index d1e5cf76b..7a7107c5b 100644 --- a/src/Widgets/ActionStack.vala +++ b/src/Widgets/ActionStack.vala @@ -4,7 +4,27 @@ */ public class AppCenter.ActionStack : Gtk.Box { - public AppCenterCore.Package package { get; construct set; } + private AppCenterCore.Package _package; + public AppCenterCore.Package package { + get { + return _package; + } + set { + if (package != null) { + package.notify["state"].disconnect (on_package_state_changed); + } + + _package = value; + + package.notify["state"].connect (on_package_state_changed); + + action_button.package = package; + cancel_button.package = package; + + update_action (); + } + } + public bool show_open { get; set; default = true; } public bool updates_view = false; @@ -23,12 +43,8 @@ public class AppCenter.ActionStack : Gtk.Box { private Gtk.Revealer action_button_revealer; private Gtk.Revealer open_button_revealer; - public ActionStack (AppCenterCore.Package package) { - Object (package: package); - } - construct { - action_button = new Widgets.HumbleButton (package); + action_button = new Widgets.HumbleButton (); action_button_revealer = new Gtk.Revealer () { child = action_button, @@ -53,7 +69,7 @@ public class AppCenter.ActionStack : Gtk.Box { button_box.append (action_button_revealer); button_box.append (open_button_revealer); - cancel_button = new ProgressButton (package); + cancel_button = new ProgressButton (); cancel_button.clicked.connect (() => action_cancelled ()); var action_button_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.BOTH); @@ -72,9 +88,6 @@ public class AppCenter.ActionStack : Gtk.Box { append (stack); - package.notify["state"].connect (on_package_state_changed); - update_action (); - destroy.connect (() => { if (state_source > 0) { GLib.Source.remove (state_source); diff --git a/src/Widgets/AppContainers/AbstractPackageRowGrid.vala b/src/Widgets/AppContainers/AbstractPackageRowGrid.vala index c6b365056..ff979fbbe 100644 --- a/src/Widgets/AppContainers/AbstractPackageRowGrid.vala +++ b/src/Widgets/AppContainers/AbstractPackageRowGrid.vala @@ -19,7 +19,34 @@ */ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { - public AppCenterCore.Package package { get; construct set; } + private AppCenterCore.Package _package; + public AppCenterCore.Package package { + get { + return _package; + } + set { + _package = value; + + action_stack.package = package; + + var scale_factor = get_scale_factor (); + + 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); + 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); + + if (package.is_runtime_updates) { + badge_image.icon_name = "system-software-update"; + app_icon_overlay.add_overlay (badge_image); + } + } + } + } public bool action_sensitive { set { @@ -34,10 +61,6 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { private Gtk.Image app_icon; private Gtk.Image badge_image; - protected AbstractPackageRowGrid (AppCenterCore.Package package) { - Object (package: package); - } - construct { app_icon = new Gtk.Image () { pixel_size = 48 @@ -53,7 +76,7 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { child = app_icon }; - action_stack = new ActionStack (package) { + action_stack = new ActionStack () { show_open = false }; @@ -62,23 +85,4 @@ public abstract class AppCenter.Widgets.AbstractPackageRowGrid : Gtk.Box { margin_bottom = 6; margin_end = 12; } - - protected void update_package (AppCenterCore.Package package) { - var scale_factor = get_scale_factor (); - - 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); - 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); - - if (package.is_runtime_updates) { - badge_image.icon_name = "system-software-update"; - app_icon_overlay.add_overlay (badge_image); - } - } - } } diff --git a/src/Widgets/AppContainers/InstalledPackageRowGrid.vala b/src/Widgets/AppContainers/InstalledPackageRowGrid.vala index 2b44c3c8b..5baff2c95 100644 --- a/src/Widgets/AppContainers/InstalledPackageRowGrid.vala +++ b/src/Widgets/AppContainers/InstalledPackageRowGrid.vala @@ -25,17 +25,8 @@ public class AppCenter.Widgets.InstalledPackageRowGrid : AbstractPackageRowGrid private Gtk.Revealer release_button_revealer; public InstalledPackageRowGrid (AppCenterCore.Package package, Gtk.SizeGroup? action_size_group) { - Object (package: package); + this.package = package; - if (action_size_group != null) { - action_size_group.add_widget (action_stack.action_button); - action_size_group.add_widget (action_stack.cancel_button); - } - - set_up_package (); - } - - construct { app_icon_overlay.margin_end = 12; action_stack.updates_view = true; @@ -89,6 +80,13 @@ public class AppCenter.Widgets.InstalledPackageRowGrid : AbstractPackageRowGrid }; releases_dialog.present (); }); + + if (action_size_group != null) { + action_size_group.add_widget (action_stack.action_button); + action_size_group.add_widget (action_stack.cancel_button); + } + + set_up_package (); } private void set_up_package () { diff --git a/src/Widgets/AppContainers/ListPackageRowGrid.vala b/src/Widgets/AppContainers/ListPackageRowGrid.vala index 96354429e..ae28f342e 100644 --- a/src/Widgets/AppContainers/ListPackageRowGrid.vala +++ b/src/Widgets/AppContainers/ListPackageRowGrid.vala @@ -21,7 +21,9 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { private Gtk.Label package_summary; public ListPackageRowGrid (AppCenterCore.Package? package) { - Object (package: package); + if (package != null) { + bind (package); + } } construct { @@ -67,6 +69,6 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { package_name.label = package.get_name (); package_summary.label = package.get_summary (); - update_package (package); + this.package = package; } } diff --git a/src/Widgets/HumbleButton.vala b/src/Widgets/HumbleButton.vala index 81603db9b..301b319e1 100644 --- a/src/Widgets/HumbleButton.vala +++ b/src/Widgets/HumbleButton.vala @@ -20,7 +20,7 @@ public class AppCenter.Widgets.HumbleButton : Gtk.Button { public signal void download_requested (); - public AppCenterCore.Package package { get; construct; } + public AppCenterCore.Package package { get; set; } private int _amount = 1; public int amount { @@ -69,10 +69,6 @@ public class AppCenter.Widgets.HumbleButton : Gtk.Button { } } - public HumbleButton (AppCenterCore.Package package) { - Object (package: package); - } - construct { hexpand = true; diff --git a/src/Widgets/ProgressButton.vala b/src/Widgets/ProgressButton.vala index a3036f0eb..cea58fd5e 100644 --- a/src/Widgets/ProgressButton.vala +++ b/src/Widgets/ProgressButton.vala @@ -4,24 +4,32 @@ */ public class AppCenter.ProgressButton : Gtk.Button { - public AppCenterCore.Package package { get; construct; } + private AppCenterCore.Package? _package; + public AppCenterCore.Package package { + get { + return _package; + } set { + if (package != null) { + package.change_information.progress_changed.disconnect (update_progress); + package.change_information.status_changed.disconnect (update_progress_status); + } - private Gtk.ProgressBar progressbar; + _package = value; - public ProgressButton (AppCenterCore.Package package) { - Object (package: package); + package.change_information.progress_changed.connect (update_progress); + package.change_information.status_changed.connect (update_progress_status); + + update_progress_status (); + update_progress (); + } } + private Gtk.ProgressBar progressbar; + construct { add_css_class ("progress"); add_css_class ("text-button"); - package.change_information.progress_changed.connect (update_progress); - package.change_information.status_changed.connect (update_progress_status); - - update_progress_status (); - update_progress (); - var cancel_label = new Gtk.Label (_("Cancel")) { mnemonic_widget = this }; From 15e2df3769a560dcb588aee3096664915a8b081f Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 21:05:24 +0200 Subject: [PATCH 09/15] Fix alert view not showing --- src/Views/SearchView.vala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Views/SearchView.vala b/src/Views/SearchView.vala index 18bbdb8f6..b66759311 100644 --- a/src/Views/SearchView.vala +++ b/src/Views/SearchView.vala @@ -28,8 +28,8 @@ public class AppCenter.SearchView : Adw.NavigationPage { public bool mimetype { get; set; default = false; } private AppCenterCore.SearchEngine search_engine; - private GLib.ListModel list_store; private Gtk.SearchEntry search_entry; + private Gtk.Stack stack; private Granite.Placeholder alert_view; public SearchView (string search_term) { @@ -62,8 +62,6 @@ public class AppCenter.SearchView : Adw.NavigationPage { }; headerbar.pack_start (new BackButton ()); - list_store = new GLib.ListStore (typeof (AppCenterCore.Package)); - search_engine = AppCenterCore.FlatpakBackend.get_default ().get_search_engine (); var selection_model = new Gtk.NoSelection (search_engine.results); @@ -89,7 +87,7 @@ public class AppCenter.SearchView : Adw.NavigationPage { hscrollbar_policy = Gtk.PolicyType.NEVER }; - var stack = new Gtk.Stack (); + stack = new Gtk.Stack (); stack.add_child (alert_view); stack.add_child (scrolled); @@ -151,6 +149,7 @@ public class AppCenter.SearchView : Adw.NavigationPage { } else { alert_view.description = _("The search term must be at least 3 characters long."); + stack.visible_child = alert_view; } if (mimetype) { From 9509b50a9c533b74601403d525de57e9c79c8738 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Thu, 20 Jun 2024 21:29:21 +0200 Subject: [PATCH 10/15] Add license header --- src/Core/SearchEngine.vala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Core/SearchEngine.vala b/src/Core/SearchEngine.vala index 8a8baa01c..5b104150a 100644 --- a/src/Core/SearchEngine.vala +++ b/src/Core/SearchEngine.vala @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Authored by: Leonhard Kargl + */ public class AppCenterCore.SearchEngine : Object { public ListModel results { get; construct; } From bd1900b19379eaac7af9095f4b2f58b437428a90 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 21 Jun 2024 13:28:52 +0200 Subject: [PATCH 11/15] Some null checking --- src/Widgets/ActionStack.vala | 10 +++++----- src/Widgets/HumbleButton.vala | 7 ++++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Widgets/ActionStack.vala b/src/Widgets/ActionStack.vala index 7a7107c5b..6d77364d9 100644 --- a/src/Widgets/ActionStack.vala +++ b/src/Widgets/ActionStack.vala @@ -4,8 +4,8 @@ */ public class AppCenter.ActionStack : Gtk.Box { - private AppCenterCore.Package _package; - public AppCenterCore.Package package { + private AppCenterCore.Package? _package; + public AppCenterCore.Package? package { get { return _package; } @@ -170,12 +170,12 @@ public class AppCenter.ActionStack : Gtk.Box { } } - private void action_cancelled () { + private void action_cancelled () requires (package != null) { update_action (); package.action_cancellable.cancel (); } - private void launch_package_app () { + private void launch_package_app () requires (package != null) { try { package.launch (); } catch (Error e) { @@ -183,7 +183,7 @@ public class AppCenter.ActionStack : Gtk.Box { } } - private async void action_clicked () { + private async void action_clicked () requires (package != null) { if (package.installed && !package.update_available) { action_button_revealer.reveal_child = false; } else if (package.update_available) { diff --git a/src/Widgets/HumbleButton.vala b/src/Widgets/HumbleButton.vala index 301b319e1..1bb290239 100644 --- a/src/Widgets/HumbleButton.vala +++ b/src/Widgets/HumbleButton.vala @@ -20,7 +20,7 @@ public class AppCenter.Widgets.HumbleButton : Gtk.Button { public signal void download_requested (); - public AppCenterCore.Package package { get; set; } + public AppCenterCore.Package? package { get; set; } private int _amount = 1; public int amount { @@ -79,6 +79,11 @@ public class AppCenter.Widgets.HumbleButton : Gtk.Button { #endif clicked.connect (() => { + if (package == null) { + warning ("Humble button with no associated package clicked."); + return; + } + if (amount != 0) { show_stripe_dialog (); } else { From 3e62db0259a6fdc3401a29981cea689908a8e428 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 21 Jun 2024 13:35:51 +0200 Subject: [PATCH 12/15] Fix warnings --- src/Widgets/AppContainers/ListPackageRowGrid.vala | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Widgets/AppContainers/ListPackageRowGrid.vala b/src/Widgets/AppContainers/ListPackageRowGrid.vala index ae28f342e..0001e21ee 100644 --- a/src/Widgets/AppContainers/ListPackageRowGrid.vala +++ b/src/Widgets/AppContainers/ListPackageRowGrid.vala @@ -27,7 +27,7 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { } construct { - package_name = new Gtk.Label (package.get_name ()) { + package_name = new Gtk.Label (null) { ellipsize = Pango.EllipsizeMode.END, lines = 2, max_width_chars = 1, @@ -37,7 +37,7 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { }; package_name.add_css_class (Granite.STYLE_CLASS_H3_LABEL); - package_summary = new Gtk.Label (package.get_summary ()) { + package_summary = new Gtk.Label (null) { ellipsize = Pango.EllipsizeMode.END, hexpand = true, lines = 2, @@ -49,10 +49,6 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { }; package_summary.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); - if (package.is_local) { - action_stack.visible = false; - } - var grid = new Gtk.Grid () { column_spacing = 12, row_spacing = 3 @@ -69,6 +65,8 @@ public class AppCenter.Widgets.ListPackageRowGrid : AbstractPackageRowGrid { package_name.label = package.get_name (); package_summary.label = package.get_summary (); + action_stack.visible = !package.is_local; + this.package = package; } } From 6fee2e1b0fa01cd0fe1de7f7da5d73c10b79976d Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 21 Jun 2024 15:20:18 +0200 Subject: [PATCH 13/15] Less lambdas --- src/Views/SearchView.vala | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/Views/SearchView.vala b/src/Views/SearchView.vala index b66759311..4ba7ca7d0 100644 --- a/src/Views/SearchView.vala +++ b/src/Views/SearchView.vala @@ -29,6 +29,9 @@ public class AppCenter.SearchView : Adw.NavigationPage { private AppCenterCore.SearchEngine search_engine; private Gtk.SearchEntry search_entry; + private Gtk.NoSelection selection_model; + private Gtk.ListView list_view; + private Gtk.ScrolledWindow scrolled; private Gtk.Stack stack; private Granite.Placeholder alert_view; @@ -64,7 +67,7 @@ public class AppCenter.SearchView : Adw.NavigationPage { search_engine = AppCenterCore.FlatpakBackend.get_default ().get_search_engine (); - var selection_model = new Gtk.NoSelection (search_engine.results); + selection_model = new Gtk.NoSelection (search_engine.results); var factory = new Gtk.SignalListItemFactory (); factory.setup.connect ((obj) => { @@ -76,13 +79,13 @@ public class AppCenter.SearchView : Adw.NavigationPage { ((Widgets.ListPackageRowGrid) list_item.child).bind ((AppCenterCore.Package) list_item.item); }); - var list_view = new Gtk.ListView (selection_model, factory) { + list_view = new Gtk.ListView (selection_model, factory) { single_click_activate = true, hexpand = true, vexpand = true }; - var scrolled = new Gtk.ScrolledWindow () { + scrolled = new Gtk.ScrolledWindow () { child = list_view, hscrollbar_policy = Gtk.PolicyType.NEVER }; @@ -106,15 +109,7 @@ public class AppCenter.SearchView : Adw.NavigationPage { search_entry.grab_focus (); }); - selection_model.items_changed.connect (() => { - list_view.scroll_to (0, NONE, null); - - if (selection_model.n_items > 0) { - stack.visible_child = scrolled; - } else { - stack.visible_child = alert_view; - } - }); + selection_model.items_changed.connect (on_items_changed); list_view.activate.connect ((index) => { show_app ((AppCenterCore.Package) search_engine.results.get_item (index)); @@ -136,6 +131,16 @@ public class AppCenter.SearchView : Adw.NavigationPage { }); } + private void on_items_changed () { + list_view.scroll_to (0, NONE, null); + + if (selection_model.n_items > 0) { + stack.visible_child = scrolled; + } else { + stack.visible_child = alert_view; + } + } + private void search () { if (search_entry.text.length >= VALID_QUERY_LENGTH) { var dyn_flathub_link = "%s".printf (search_entry.text, _("Flathub")); From 667045fc44e098197d15c113422f8fa44b69a9d6 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 21 Jun 2024 18:58:50 +0200 Subject: [PATCH 14/15] Fix memory leak --- src/Core/SearchEngine.vala | 12 +++++++++++- src/Views/SearchView.vala | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Core/SearchEngine.vala b/src/Core/SearchEngine.vala index 5b104150a..5a689baab 100644 --- a/src/Core/SearchEngine.vala +++ b/src/Core/SearchEngine.vala @@ -6,7 +6,7 @@ */ public class AppCenterCore.SearchEngine : Object { - public ListModel results { get; construct; } + public ListModel results { get; private set; } private ListStore packages; private AppStream.Pool pool; @@ -60,4 +60,14 @@ public class AppCenterCore.SearchEngine : Object { this.category = category; packages.items_changed (0, packages.n_items, packages.n_items); } + + /** + * This should be called if the engine is no longer needed. + * We need this because thanks to the delegates we get a reference cycle, + * where the filter and sorter keep a reference on us and we on them. + * Setting results to null will free them and they will in turn free us. + */ + public void cleanup () { + results = null; + } } diff --git a/src/Views/SearchView.vala b/src/Views/SearchView.vala index 4ba7ca7d0..686e03965 100644 --- a/src/Views/SearchView.vala +++ b/src/Views/SearchView.vala @@ -131,6 +131,10 @@ public class AppCenter.SearchView : Adw.NavigationPage { }); } + ~SearchView () { + search_engine.cleanup (); + } + private void on_items_changed () { list_view.scroll_to (0, NONE, null); From 11adc7d1a5de784a74d27e346fa8810908c50312 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Fri, 21 Jun 2024 18:59:22 +0200 Subject: [PATCH 15/15] Better comment --- src/Core/SearchEngine.vala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Core/SearchEngine.vala b/src/Core/SearchEngine.vala index 5a689baab..0d22c3eda 100644 --- a/src/Core/SearchEngine.vala +++ b/src/Core/SearchEngine.vala @@ -63,9 +63,10 @@ public class AppCenterCore.SearchEngine : Object { /** * This should be called if the engine is no longer needed. - * We need this because thanks to the delegates we get a reference cycle, + * We need this because thanks to how vala sets delegates we get a reference cycle, * where the filter and sorter keep a reference on us and we on them. * Setting results to null will free them and they will in turn free us. + * https://gitlab.gnome.org/GNOME/vala/-/issues/957 */ public void cleanup () { results = null;