From 16d45831c749ee502bcebcee6eb9787a5bfb3f35 Mon Sep 17 00:00:00 2001 From: sid Date: Mon, 31 Jul 2023 21:11:49 +0000 Subject: [PATCH 1/9] gs-category-page: Fix issues with displaying apps in category page This commit fixes the below rendering / display issues in Category page, by delaying the population of GtkFlowBox to the very end. 1. Recently updated apps in random location in "Other Software". 2. Web apps at the end of "Other Software". 3. Featured apps at the end of "Other Software". 4. Fix issues in [2] and [3] where the app is not displayed within the tile. 5. Rejected recently updated apps in the top of "Other Software". See merge request GNOME/gnome-software!1748 Closes #2268 Closes #2282 --- src/gs-category-page.c | 361 +++++++++++++++++++++++++++++------------ 1 file changed, 257 insertions(+), 104 deletions(-) diff --git a/src/gs-category-page.c b/src/gs-category-page.c index 8219c79b8..89b9a6425 100644 --- a/src/gs-category-page.c +++ b/src/gs-category-page.c @@ -283,35 +283,171 @@ choose_top_carousel_apps (LoadCategoryData *data, } static gint -compare_release_date_cb (gconstpointer aa, - gconstpointer bb) +app_name_flowbox_sort_func (GtkFlowBoxChild *child1, + GtkFlowBoxChild *child2, + gpointer user_data) { - GsApp *app_a = gs_app_tile_get_app ((GsAppTile *) aa); - GsApp *app_b = gs_app_tile_get_app ((GsAppTile *) bb); - guint64 release_date_a = gs_app_get_release_date (app_a); - guint64 release_date_b = gs_app_get_release_date (app_b); + GsAppTile *tile1 = GS_APP_TILE (child1); + GsAppTile *tile2 = GS_APP_TILE (child2); + GsApp *app1 = gs_app_tile_get_app (tile1); + GsApp *app2 = gs_app_tile_get_app (tile2); - if (release_date_a == release_date_b) - return g_utf8_collate (gs_app_get_name (app_a), gs_app_get_name (app_b)); + /* Placeholder tiles have no app. */ + if (app1 == NULL && app2 == NULL) + return 0; + if (app1 == NULL) + return 1; + if (app2 == NULL) + return -1; + + return gs_utils_sort_strcmp (gs_app_get_name (app1), gs_app_get_name (app2)); +} + +static gint +release_date_sort_func (GsAppTile *tile1, + GsAppTile *tile2) +{ + GsApp *app1 = gs_app_tile_get_app (tile1); + GsApp *app2 = gs_app_tile_get_app (tile2); + guint64 release_date1, release_date2; + + /* Placeholder tiles have no app. */ + if (app1 == NULL && app2 == NULL) + return 0; + if (app1 == NULL) + return 1; + if (app2 == NULL) + return -1; + + release_date1 = gs_app_get_release_date (app1); + release_date2 = gs_app_get_release_date (app2); + + if (release_date1 == release_date2) + return g_utf8_collate (gs_app_get_name (app1), gs_app_get_name (app2)); + + return release_date1 < release_date2 ? 1 : -1; +} + +static gint +release_date_gptrarray_sort_func (gconstpointer tile1, + gconstpointer tile2) +{ + GsAppTile *tile_a = (*(GsAppTile **) tile1); + GsAppTile *tile_b = (*(GsAppTile **) tile2); + + return release_date_sort_func (tile_a, tile_b); +} + +static gint +release_date_flowbox_sort_func (GtkFlowBoxChild *child1, + GtkFlowBoxChild *child2, + gpointer user_data) +{ + GsAppTile *tile1 = GS_APP_TILE (child1); + GsAppTile *tile2 = GS_APP_TILE (child2); - return release_date_a < release_date_b ? -1 : 1; + return release_date_sort_func (tile1, tile2); } + +/* Sort all flow boxes in this page, if 'enable' is TRUE, else disable + sorting on all flow boxes. Sorting should always be enabled, except + for cases when doing bulk additions, where sorting once after the + bulk addition will offer better performance. */ static void -move_to_flow_box (GsCategoryPage *self, - GtkFlowBox *source, - GtkFlowBox *destination) +gs_category_page_set_sort (GsCategoryPage *self, gboolean enable) { - for (GtkFlowBoxChild *child = gtk_flow_box_get_child_at_index (source, 0); - child != NULL; - child = gtk_flow_box_get_child_at_index (source, 0)) { - GtkWidget *tile = gtk_flow_box_child_get_child (child); - g_object_ref (tile); - gtk_flow_box_remove (source, tile); - gtk_flow_box_insert (destination, tile, -1); - gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); - g_object_unref (tile); + GtkFlowBoxSortFunc name_sort_func = NULL; + GtkFlowBoxSortFunc recent_sort_func = NULL; + + if (enable) { + name_sort_func = app_name_flowbox_sort_func; + recent_sort_func = release_date_flowbox_sort_func; } + + /* Sort the featured apps flowbox by app name, when sorting is + enabled. */ + gtk_flow_box_set_sort_func (GTK_FLOW_BOX (self->featured_flow_box), + name_sort_func, + NULL, + NULL); + + /* Sort the recent apps flowbox by release date, when sorting + is enabled. Note that recent apps flowbox is already + sorted. This call is there to account for the case + (possibly in future), where app tiles are added to the + flowbox after the initial population in 'populate_flow_boxes ()'. */ + gtk_flow_box_set_sort_func (GTK_FLOW_BOX (self->recently_updated_flow_box), + recent_sort_func, + NULL, + NULL); + + /* Sort the web apps flowbox by app name, when sorting is enabled. */ + gtk_flow_box_set_sort_func (GTK_FLOW_BOX (self->web_apps_flow_box), + name_sort_func, + NULL, + NULL); + + /* Sort the other apps flowbox by app name, when sorting is enabled. */ + gtk_flow_box_set_sort_func (GTK_FLOW_BOX (self->category_detail_box), + name_sort_func, + NULL, + NULL); +} + +static void +populate_flow_boxes (GsCategoryPage *self, + GPtrArray *featured_app_tiles, + GPtrArray *recently_updated_app_tiles, + GPtrArray *web_app_tiles, + GPtrArray *other_app_tiles) +{ + guint i; + GtkWidget *tile; + + /* Disable sorting on all flowboxes so we don't sort on each + flowbox insertion which is not good for performance. */ + gs_category_page_set_sort (self, FALSE); + + /* Populate featured flowbox */ + if (featured_app_tiles) { + for (i = 0; i < featured_app_tiles->len; i++) { + tile = g_ptr_array_index (featured_app_tiles, i); + gtk_flow_box_insert (GTK_FLOW_BOX (self->featured_flow_box), tile, -1); + gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); + } + } + + /* Populate recently updated flowbox */ + if (recently_updated_app_tiles) { + for (i = 0; i < recently_updated_app_tiles->len; i++) { + tile = g_ptr_array_index (recently_updated_app_tiles, i); + gtk_flow_box_insert (GTK_FLOW_BOX (self->recently_updated_flow_box), tile, -1); + gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); + } + } + + /* Populate web apps flowbox */ + if (web_app_tiles) { + for (i = 0; i < web_app_tiles->len; i++) { + tile = g_ptr_array_index (web_app_tiles, i); + gtk_flow_box_insert (GTK_FLOW_BOX (self->web_apps_flow_box), tile, -1); + gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); + } + } + + /* Populate other apps flowbox */ + if (other_app_tiles) { + for (i = 0; i < other_app_tiles->len; i++) { + tile = g_ptr_array_index (other_app_tiles, i); + gtk_flow_box_insert (GTK_FLOW_BOX (self->category_detail_box), tile, -1); + gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); + } + } + + /* Re-enable sorting on all flowboxes now that they are fully + populated */ + gs_category_page_set_sort (self, TRUE); } static void @@ -320,12 +456,18 @@ load_category_finish (LoadCategoryData *data) GsCategoryPage *self = data->page; guint64 recently_updated_cutoff_secs; guint64 n_recently_updated = 0; - guint64 n_featured = 0; + guint64 n_featured_apps = 0; guint64 n_web_apps = 0; - guint64 picked_recently_updated = 0; - guint64 min_release_date = G_MAXUINT64; - GSList *recently_updated = NULL, *link; + guint64 n_carousel_apps = 0; + guint64 n_other_apps = 0; + guint64 n_category_apps = 0; + guint64 n_total_apps; + g_autoptr(GPtrArray) featured_app_tiles = g_ptr_array_new (); + g_autoptr(GPtrArray) recently_updated_app_tiles = g_ptr_array_new (); + g_autoptr(GPtrArray) web_app_tiles = g_ptr_array_new (); + g_autoptr(GPtrArray) other_app_tiles = NULL; g_autoptr(GsAppList) top_carousel_apps = NULL; + GtkWidget *tile; if (!data->get_featured_apps_finished || !data->get_main_apps_finished) @@ -345,6 +487,12 @@ load_category_finish (LoadCategoryData *data) /* Last 30 days */ recently_updated_cutoff_secs = g_get_real_time () / G_USEC_PER_SEC - 30 * 24 * 60 * 60; + if (data->apps) + n_category_apps = gs_app_list_length (data->apps); + + /* High probability that all apps could land here */ + other_app_tiles = g_ptr_array_sized_new (n_category_apps); + /* Apps to go in the top carousel */ top_carousel_apps = choose_top_carousel_apps (data, recently_updated_cutoff_secs); @@ -352,12 +500,12 @@ load_category_finish (LoadCategoryData *data) GsApp *app = gs_app_list_index (data->apps, i); gboolean is_featured, is_recently_updated; guint64 release_date; - GtkWidget *flow_box = self->category_detail_box; - GtkWidget *tile; /* To be listed in the top carousel? */ - if (gs_app_list_lookup (top_carousel_apps, gs_app_get_unique_id (app)) != NULL) + if (gs_app_list_lookup (top_carousel_apps, gs_app_get_unique_id (app)) != NULL) { + n_carousel_apps++; continue; + } release_date = gs_app_get_release_date (app); is_featured = (data->featured_app_ids != NULL && @@ -367,69 +515,104 @@ load_category_finish (LoadCategoryData *data) tile = gs_summary_tile_new (app); if (is_featured) { - n_featured++; - flow_box = self->featured_flow_box; + n_featured_apps++; + g_ptr_array_add (featured_app_tiles, tile); } else if (is_recently_updated) { n_recently_updated++; - if (picked_recently_updated < MAX_RECENTLY_UPDATED_APPS) { - recently_updated = g_slist_insert_sorted (recently_updated, tile, compare_release_date_cb); - picked_recently_updated++; - if (min_release_date > release_date) - min_release_date = release_date; - flow_box = NULL; - } else if (release_date >= min_release_date) { - recently_updated = g_slist_insert_sorted (recently_updated, tile, compare_release_date_cb); - tile = recently_updated->data; - recently_updated = g_slist_remove (recently_updated, tile); - min_release_date = gs_app_get_release_date (gs_app_tile_get_app (GS_APP_TILE (recently_updated->data))); - } + g_ptr_array_add (recently_updated_app_tiles, tile); } else if (gs_app_get_kind (app) == AS_COMPONENT_KIND_WEB_APP) { n_web_apps++; - flow_box = self->web_apps_flow_box; - } - - if (flow_box != NULL) { - gtk_flow_box_insert (GTK_FLOW_BOX (flow_box), tile, -1); - gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); + g_ptr_array_add (web_app_tiles, tile); + } else { + n_other_apps++; + g_ptr_array_add (other_app_tiles, tile); } } + n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated + n_web_apps + n_other_apps; + + g_assert (n_total_apps == n_category_apps); + g_assert (n_featured_apps == 0 || n_featured_apps == featured_app_tiles->len); + g_assert (n_recently_updated == 0 || n_recently_updated == recently_updated_app_tiles->len); + g_assert (n_web_apps == 0 || n_web_apps == web_app_tiles->len); + g_assert (n_other_apps == 0 || n_other_apps == other_app_tiles->len); + /* If these sections end up being too empty (which looks odd), merge them into the main section. * See https://gitlab.gnome.org/GNOME/gnome-software/-/issues/2053 */ - if (n_featured < MIN_SECTION_APPS) - move_to_flow_box (self, GTK_FLOW_BOX (self->featured_flow_box), GTK_FLOW_BOX (self->category_detail_box)); + if (n_featured_apps > 0 && n_featured_apps < MIN_SECTION_APPS) { + g_debug ("\tOnly %" G_GUINT64_FORMAT " featured apps, needed at least %d; moving apps to others", + n_featured_apps, MIN_SECTION_APPS); + g_ptr_array_extend_and_steal (other_app_tiles, g_steal_pointer (&featured_app_tiles)); + n_other_apps += n_featured_apps; + n_featured_apps = 0; + } + - if (n_web_apps < MIN_SECTION_APPS) - move_to_flow_box (self, GTK_FLOW_BOX (self->web_apps_flow_box), GTK_FLOW_BOX (self->category_detail_box)); + if (n_web_apps > 0 && n_web_apps < MIN_SECTION_APPS) { + g_debug ("\tOnly %" G_GUINT64_FORMAT " web apps, needed at least %d; moving apps to others", + n_web_apps, MIN_SECTION_APPS); + g_ptr_array_extend_and_steal (other_app_tiles, g_steal_pointer (&web_app_tiles)); + n_other_apps += n_web_apps; + n_web_apps = 0; + } - /* Show 'Recently Updated' section only if there had been enough of them recognized. + /* Show 'New & Updated' section only if there had been enough of them recognized. * See https://gitlab.gnome.org/GNOME/gnome-software/-/issues/2053 */ - if (n_recently_updated >= MIN_RECENTLY_UPDATED_APPS && picked_recently_updated >= MIN_SECTION_APPS) { - for (link = recently_updated; link != NULL; link = g_slist_next (link)) { - GtkWidget *tile = link->data; - gtk_flow_box_insert (GTK_FLOW_BOX (self->recently_updated_flow_box), tile, -1); - gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); - } - } else { - /* put them at the top */ - recently_updated = g_slist_reverse (recently_updated); - for (link = recently_updated; link != NULL; link = g_slist_next (link)) { - GtkWidget *tile = link->data; - gtk_flow_box_insert (GTK_FLOW_BOX (self->category_detail_box), tile, 0); - gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); + if (n_recently_updated > 0) { + if (n_recently_updated < MIN_RECENTLY_UPDATED_APPS) { + g_debug ("\tOnly %" G_GUINT64_FORMAT " recent apps, needed at least %d; moving apps to others", + n_recently_updated, MIN_RECENTLY_UPDATED_APPS); + g_ptr_array_extend_and_steal (other_app_tiles, g_steal_pointer (&recently_updated_app_tiles)); + n_other_apps += n_recently_updated; + n_recently_updated = 0; + } else { + guint n_apps_to_move; + + /* Defer sorting till we're sure that sorted + data will be actually useful */ + g_ptr_array_sort (recently_updated_app_tiles, release_date_gptrarray_sort_func); + + g_assert (n_recently_updated >= MAX_RECENTLY_UPDATED_APPS); + n_apps_to_move = n_recently_updated - MAX_RECENTLY_UPDATED_APPS; + + if (n_apps_to_move > 0) { + g_debug ("\tAlready %" G_GUINT64_FORMAT " recent apps, needed at most %d; moving %u apps to others", + n_recently_updated, MAX_RECENTLY_UPDATED_APPS, n_apps_to_move); + + for (guint j = 0; j < n_apps_to_move; j++) { + /* keep removing at the same index */ + tile = g_ptr_array_steal_index_fast (recently_updated_app_tiles, MAX_RECENTLY_UPDATED_APPS); + g_ptr_array_add (other_app_tiles, tile); + } + + n_recently_updated -= n_apps_to_move; + n_other_apps += n_apps_to_move; + } } } - g_slist_free (recently_updated); + n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated + n_web_apps + n_other_apps; + + g_assert (n_total_apps == n_category_apps); + g_assert (n_featured_apps == 0 || n_featured_apps == featured_app_tiles->len); + g_assert (n_recently_updated == 0 || n_recently_updated == recently_updated_app_tiles->len); + g_assert (n_web_apps == 0 || n_web_apps == web_app_tiles->len); + g_assert (n_other_apps == 0 || n_other_apps == other_app_tiles->len); + /* Populate all flowboxes. */ + populate_flow_boxes (self, featured_app_tiles, recently_updated_app_tiles, web_app_tiles, other_app_tiles); + + /* Show carousel only if it has apps */ gtk_widget_set_visible (self->top_carousel, gs_app_list_length (top_carousel_apps) > 0); gs_featured_carousel_set_apps (GS_FEATURED_CAROUSEL (self->top_carousel), top_carousel_apps); - /* Show each of the flow boxes if they have any children. */ - gtk_widget_set_visible (self->featured_flow_box, gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (self->featured_flow_box), 0) != NULL); - gtk_widget_set_visible (self->recently_updated_flow_box, gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (self->recently_updated_flow_box), 0) != NULL); - gtk_widget_set_visible (self->web_apps_flow_box, gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (self->web_apps_flow_box), 0) != NULL); - gtk_widget_set_visible (self->category_detail_box, gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (self->category_detail_box), 0) != NULL); + /* Show each of the flow boxes only if they have apps. */ + gtk_widget_set_visible (self->featured_flow_box, n_featured_apps > 0); + gtk_widget_set_visible (self->recently_updated_flow_box, n_recently_updated > 0); + gtk_widget_set_visible (self->web_apps_flow_box, n_web_apps > 0); + gtk_widget_set_visible (self->category_detail_box, n_other_apps > 0); + + /* Don't show "Other Software" heading if it's the only heading */ gtk_widget_set_visible (self->other_heading, gtk_widget_get_visible (self->category_detail_box) && ( gtk_widget_get_visible (self->featured_flow_box) || gtk_widget_get_visible (self->recently_updated_flow_box) || @@ -602,33 +785,6 @@ gs_category_page_get_category (GsCategoryPage *self) return self->category; } -static gint -recently_updated_sort_cb (GtkFlowBoxChild *child1, - GtkFlowBoxChild *child2, - gpointer user_data) -{ - GsSummaryTile *tile1 = GS_SUMMARY_TILE (child1); - GsSummaryTile *tile2 = GS_SUMMARY_TILE (child2); - GsApp *app1 = gs_app_tile_get_app (GS_APP_TILE (tile1)); - GsApp *app2 = gs_app_tile_get_app (GS_APP_TILE (tile2)); - guint64 release_date1 = 0, release_date2 = 0; - - /* Placeholder tiles have no app. */ - if (app1 != NULL) - release_date1 = gs_app_get_release_date (app1); - if (app2 != NULL) - release_date2 = gs_app_get_release_date (app2); - - /* Don’t use the normal subtraction trick, as there’s the possibility - * for overflow in the conversion from guint64 to gint. */ - if (release_date1 > release_date2) - return -1; - else if (release_date2 > release_date1) - return 1; - else - return 0; -} - static void gs_category_page_init (GsCategoryPage *self) { @@ -636,11 +792,8 @@ gs_category_page_init (GsCategoryPage *self) gtk_widget_init_template (GTK_WIDGET (self)); - /* Sort the recently updated apps by update date. */ - gtk_flow_box_set_sort_func (GTK_FLOW_BOX (self->recently_updated_flow_box), - recently_updated_sort_cb, - NULL, - NULL); + /* Enable sorting on all flowboxes by default. */ + gs_category_page_set_sort (self, TRUE); gs_featured_carousel_set_apps (GS_FEATURED_CAROUSEL (self->top_carousel), NULL); } -- GitLab From c1606ce0606e836592616bcd666fd8601d0fb4dd Mon Sep 17 00:00:00 2001 From: sid Date: Sat, 2 Sep 2023 22:08:54 +0000 Subject: [PATCH 2/9] gs-category-page: Add function 'print_app_bucket_stats()' to print bucket stats See merge request GNOME/gnome-software!1748 --- src/gs-category-page.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/gs-category-page.c b/src/gs-category-page.c index 89b9a6425..0284f7355 100644 --- a/src/gs-category-page.c +++ b/src/gs-category-page.c @@ -450,6 +450,22 @@ populate_flow_boxes (GsCategoryPage *self, gs_category_page_set_sort (self, TRUE); } +static void +print_app_bucket_stats (GsCategoryPage *self, + guint64 n_carousel_apps, + guint64 n_featured_apps, + guint64 n_recently_updated, + guint64 n_web_apps, + guint64 n_other_apps, + guint64 n_total_apps) +{ + g_debug ("[%s] Carousel apps: %" G_GUINT64_FORMAT ", Featured apps: %" G_GUINT64_FORMAT ", Recent apps: %" G_GUINT64_FORMAT ", " + "Web apps: %" G_GUINT64_FORMAT ", Other apps: %" G_GUINT64_FORMAT ", Total apps: %" G_GUINT64_FORMAT, + gs_category_get_name (self->category), + n_carousel_apps, n_featured_apps, n_recently_updated, + n_web_apps, n_other_apps, n_total_apps); +} + static void load_category_finish (LoadCategoryData *data) { @@ -530,6 +546,7 @@ load_category_finish (LoadCategoryData *data) } n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated + n_web_apps + n_other_apps; + print_app_bucket_stats (self, n_carousel_apps, n_featured_apps, n_recently_updated, n_web_apps, n_other_apps, n_category_apps); g_assert (n_total_apps == n_category_apps); g_assert (n_featured_apps == 0 || n_featured_apps == featured_app_tiles->len); @@ -592,6 +609,7 @@ load_category_finish (LoadCategoryData *data) } n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated + n_web_apps + n_other_apps; + print_app_bucket_stats (self, n_carousel_apps, n_featured_apps, n_recently_updated, n_web_apps, n_other_apps, n_category_apps); g_assert (n_total_apps == n_category_apps); g_assert (n_featured_apps == 0 || n_featured_apps == featured_app_tiles->len); -- GitLab From e7fa2239803733debd669db07bc9dae946f37af6 Mon Sep 17 00:00:00 2001 From: sid Date: Sat, 2 Sep 2023 21:31:09 +0000 Subject: [PATCH 3/9] gs-category-page: Refactor bucket assert and print code to macros See merge request GNOME/gnome-software!1748 --- src/gs-category-page.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/gs-category-page.c b/src/gs-category-page.c index 0284f7355..6f4bf010d 100644 --- a/src/gs-category-page.c +++ b/src/gs-category-page.c @@ -47,6 +47,16 @@ G_DEFINE_TYPE (GsCategoryPage, gs_category_page, GS_TYPE_PAGE) #define MIN_RECENTLY_UPDATED_APPS 50 #define MIN_SECTION_APPS 3 +#define validate_app_buckets() \ + n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated + n_web_apps + n_other_apps; \ + print_app_bucket_stats (self, n_carousel_apps, n_featured_apps, n_recently_updated, n_web_apps, n_other_apps, n_category_apps); \ + \ + g_assert (n_total_apps == n_category_apps); \ + g_assert (n_featured_apps == 0 || n_featured_apps == featured_app_tiles->len); \ + g_assert (n_recently_updated == 0 || n_recently_updated == recently_updated_app_tiles->len); \ + g_assert (n_web_apps == 0 || n_web_apps == web_app_tiles->len); \ + g_assert (n_other_apps == 0 || n_other_apps == other_app_tiles->len); \ + typedef enum { PROP_CATEGORY = 1, /* Override properties: */ @@ -545,14 +555,7 @@ load_category_finish (LoadCategoryData *data) } } - n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated + n_web_apps + n_other_apps; - print_app_bucket_stats (self, n_carousel_apps, n_featured_apps, n_recently_updated, n_web_apps, n_other_apps, n_category_apps); - - g_assert (n_total_apps == n_category_apps); - g_assert (n_featured_apps == 0 || n_featured_apps == featured_app_tiles->len); - g_assert (n_recently_updated == 0 || n_recently_updated == recently_updated_app_tiles->len); - g_assert (n_web_apps == 0 || n_web_apps == web_app_tiles->len); - g_assert (n_other_apps == 0 || n_other_apps == other_app_tiles->len); + validate_app_buckets (); /* If these sections end up being too empty (which looks odd), merge them into the main section. * See https://gitlab.gnome.org/GNOME/gnome-software/-/issues/2053 */ @@ -608,14 +611,7 @@ load_category_finish (LoadCategoryData *data) } } - n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated + n_web_apps + n_other_apps; - print_app_bucket_stats (self, n_carousel_apps, n_featured_apps, n_recently_updated, n_web_apps, n_other_apps, n_category_apps); - - g_assert (n_total_apps == n_category_apps); - g_assert (n_featured_apps == 0 || n_featured_apps == featured_app_tiles->len); - g_assert (n_recently_updated == 0 || n_recently_updated == recently_updated_app_tiles->len); - g_assert (n_web_apps == 0 || n_web_apps == web_app_tiles->len); - g_assert (n_other_apps == 0 || n_other_apps == other_app_tiles->len); + validate_app_buckets (); /* Populate all flowboxes. */ populate_flow_boxes (self, featured_app_tiles, recently_updated_app_tiles, web_app_tiles, other_app_tiles); -- GitLab From 6bcdf8b883688dd7611e77272433ea87811ee7bc Mon Sep 17 00:00:00 2001 From: sid Date: Fri, 1 Sep 2023 23:55:38 +0000 Subject: [PATCH 4/9] gs-category-page: Rename 'n_recently_updated' to 'n_recently_updated_apps' See merge request GNOME/gnome-software!1748 --- src/gs-category-page.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/gs-category-page.c b/src/gs-category-page.c index 6f4bf010d..40a49b2d8 100644 --- a/src/gs-category-page.c +++ b/src/gs-category-page.c @@ -48,12 +48,12 @@ G_DEFINE_TYPE (GsCategoryPage, gs_category_page, GS_TYPE_PAGE) #define MIN_SECTION_APPS 3 #define validate_app_buckets() \ - n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated + n_web_apps + n_other_apps; \ - print_app_bucket_stats (self, n_carousel_apps, n_featured_apps, n_recently_updated, n_web_apps, n_other_apps, n_category_apps); \ + n_total_apps = n_carousel_apps + n_featured_apps + n_recently_updated_apps + n_web_apps + n_other_apps; \ + print_app_bucket_stats (self, n_carousel_apps, n_featured_apps, n_recently_updated_apps, n_web_apps, n_other_apps, n_category_apps); \ \ g_assert (n_total_apps == n_category_apps); \ g_assert (n_featured_apps == 0 || n_featured_apps == featured_app_tiles->len); \ - g_assert (n_recently_updated == 0 || n_recently_updated == recently_updated_app_tiles->len); \ + g_assert (n_recently_updated_apps == 0 || n_recently_updated_apps == recently_updated_app_tiles->len); \ g_assert (n_web_apps == 0 || n_web_apps == web_app_tiles->len); \ g_assert (n_other_apps == 0 || n_other_apps == other_app_tiles->len); \ @@ -464,7 +464,7 @@ static void print_app_bucket_stats (GsCategoryPage *self, guint64 n_carousel_apps, guint64 n_featured_apps, - guint64 n_recently_updated, + guint64 n_recently_updated_apps, guint64 n_web_apps, guint64 n_other_apps, guint64 n_total_apps) @@ -472,7 +472,7 @@ print_app_bucket_stats (GsCategoryPage *self, g_debug ("[%s] Carousel apps: %" G_GUINT64_FORMAT ", Featured apps: %" G_GUINT64_FORMAT ", Recent apps: %" G_GUINT64_FORMAT ", " "Web apps: %" G_GUINT64_FORMAT ", Other apps: %" G_GUINT64_FORMAT ", Total apps: %" G_GUINT64_FORMAT, gs_category_get_name (self->category), - n_carousel_apps, n_featured_apps, n_recently_updated, + n_carousel_apps, n_featured_apps, n_recently_updated_apps, n_web_apps, n_other_apps, n_total_apps); } @@ -481,7 +481,7 @@ load_category_finish (LoadCategoryData *data) { GsCategoryPage *self = data->page; guint64 recently_updated_cutoff_secs; - guint64 n_recently_updated = 0; + guint64 n_recently_updated_apps = 0; guint64 n_featured_apps = 0; guint64 n_web_apps = 0; guint64 n_carousel_apps = 0; @@ -544,7 +544,7 @@ load_category_finish (LoadCategoryData *data) n_featured_apps++; g_ptr_array_add (featured_app_tiles, tile); } else if (is_recently_updated) { - n_recently_updated++; + n_recently_updated_apps++; g_ptr_array_add (recently_updated_app_tiles, tile); } else if (gs_app_get_kind (app) == AS_COMPONENT_KIND_WEB_APP) { n_web_apps++; @@ -578,13 +578,13 @@ load_category_finish (LoadCategoryData *data) /* Show 'New & Updated' section only if there had been enough of them recognized. * See https://gitlab.gnome.org/GNOME/gnome-software/-/issues/2053 */ - if (n_recently_updated > 0) { - if (n_recently_updated < MIN_RECENTLY_UPDATED_APPS) { + if (n_recently_updated_apps > 0) { + if (n_recently_updated_apps < MIN_RECENTLY_UPDATED_APPS) { g_debug ("\tOnly %" G_GUINT64_FORMAT " recent apps, needed at least %d; moving apps to others", - n_recently_updated, MIN_RECENTLY_UPDATED_APPS); + n_recently_updated_apps, MIN_RECENTLY_UPDATED_APPS); g_ptr_array_extend_and_steal (other_app_tiles, g_steal_pointer (&recently_updated_app_tiles)); - n_other_apps += n_recently_updated; - n_recently_updated = 0; + n_other_apps += n_recently_updated_apps; + n_recently_updated_apps = 0; } else { guint n_apps_to_move; @@ -592,12 +592,12 @@ load_category_finish (LoadCategoryData *data) data will be actually useful */ g_ptr_array_sort (recently_updated_app_tiles, release_date_gptrarray_sort_func); - g_assert (n_recently_updated >= MAX_RECENTLY_UPDATED_APPS); - n_apps_to_move = n_recently_updated - MAX_RECENTLY_UPDATED_APPS; + g_assert (n_recently_updated_apps >= MAX_RECENTLY_UPDATED_APPS); + n_apps_to_move = n_recently_updated_apps - MAX_RECENTLY_UPDATED_APPS; if (n_apps_to_move > 0) { g_debug ("\tAlready %" G_GUINT64_FORMAT " recent apps, needed at most %d; moving %u apps to others", - n_recently_updated, MAX_RECENTLY_UPDATED_APPS, n_apps_to_move); + n_recently_updated_apps, MAX_RECENTLY_UPDATED_APPS, n_apps_to_move); for (guint j = 0; j < n_apps_to_move; j++) { /* keep removing at the same index */ @@ -605,7 +605,7 @@ load_category_finish (LoadCategoryData *data) g_ptr_array_add (other_app_tiles, tile); } - n_recently_updated -= n_apps_to_move; + n_recently_updated_apps -= n_apps_to_move; n_other_apps += n_apps_to_move; } } @@ -622,7 +622,7 @@ load_category_finish (LoadCategoryData *data) /* Show each of the flow boxes only if they have apps. */ gtk_widget_set_visible (self->featured_flow_box, n_featured_apps > 0); - gtk_widget_set_visible (self->recently_updated_flow_box, n_recently_updated > 0); + gtk_widget_set_visible (self->recently_updated_flow_box, n_recently_updated_apps > 0); gtk_widget_set_visible (self->web_apps_flow_box, n_web_apps > 0); gtk_widget_set_visible (self->category_detail_box, n_other_apps > 0); -- GitLab From 2d7d0d4f0478b9d7818edddd34366b2eb55a4c99 Mon Sep 17 00:00:00 2001 From: sid Date: Sat, 2 Sep 2023 00:48:11 +0000 Subject: [PATCH 5/9] gs-category-page: Rename 'MIN_RECENTLY_UPDATED_APPS' / 'MAX_RECENTLY_UPDATED_APPS' Rename 'MIN_RECENTLY_UPDATED_APPS' to 'MIN_RECENT_APPS_REQUIRED' Rename 'MAX_RECENTLY_UPDATED_APPS' to 'MAX_RECENT_APPS_TO_DISPLAY' See merge request GNOME/gnome-software!1748 --- src/gs-category-page.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/gs-category-page.c b/src/gs-category-page.c index 40a49b2d8..33f0bd450 100644 --- a/src/gs-category-page.c +++ b/src/gs-category-page.c @@ -43,8 +43,8 @@ G_DEFINE_TYPE (GsCategoryPage, gs_category_page, GS_TYPE_PAGE) /* See https://gitlab.gnome.org/GNOME/gnome-software/-/issues/2053 * for the rationale behind the numbers */ -#define MAX_RECENTLY_UPDATED_APPS 12 -#define MIN_RECENTLY_UPDATED_APPS 50 +#define MAX_RECENT_APPS_TO_DISPLAY 12 +#define MIN_RECENT_APPS_REQUIRED 50 #define MIN_SECTION_APPS 3 #define validate_app_buckets() \ @@ -579,9 +579,9 @@ load_category_finish (LoadCategoryData *data) /* Show 'New & Updated' section only if there had been enough of them recognized. * See https://gitlab.gnome.org/GNOME/gnome-software/-/issues/2053 */ if (n_recently_updated_apps > 0) { - if (n_recently_updated_apps < MIN_RECENTLY_UPDATED_APPS) { + if (n_recently_updated_apps < MIN_RECENT_APPS_REQUIRED) { g_debug ("\tOnly %" G_GUINT64_FORMAT " recent apps, needed at least %d; moving apps to others", - n_recently_updated_apps, MIN_RECENTLY_UPDATED_APPS); + n_recently_updated_apps, MIN_RECENT_APPS_REQUIRED); g_ptr_array_extend_and_steal (other_app_tiles, g_steal_pointer (&recently_updated_app_tiles)); n_other_apps += n_recently_updated_apps; n_recently_updated_apps = 0; @@ -592,16 +592,16 @@ load_category_finish (LoadCategoryData *data) data will be actually useful */ g_ptr_array_sort (recently_updated_app_tiles, release_date_gptrarray_sort_func); - g_assert (n_recently_updated_apps >= MAX_RECENTLY_UPDATED_APPS); - n_apps_to_move = n_recently_updated_apps - MAX_RECENTLY_UPDATED_APPS; + g_assert (n_recently_updated_apps >= MAX_RECENT_APPS_TO_DISPLAY); + n_apps_to_move = n_recently_updated_apps - MAX_RECENT_APPS_TO_DISPLAY; if (n_apps_to_move > 0) { g_debug ("\tAlready %" G_GUINT64_FORMAT " recent apps, needed at most %d; moving %u apps to others", - n_recently_updated_apps, MAX_RECENTLY_UPDATED_APPS, n_apps_to_move); + n_recently_updated_apps, MAX_RECENT_APPS_TO_DISPLAY, n_apps_to_move); for (guint j = 0; j < n_apps_to_move; j++) { /* keep removing at the same index */ - tile = g_ptr_array_steal_index_fast (recently_updated_app_tiles, MAX_RECENTLY_UPDATED_APPS); + tile = g_ptr_array_steal_index_fast (recently_updated_app_tiles, MAX_RECENT_APPS_TO_DISPLAY); g_ptr_array_add (other_app_tiles, tile); } @@ -666,7 +666,7 @@ gs_category_page_load_category (GsCategoryPage *self) gs_featured_carousel_set_apps (GS_FEATURED_CAROUSEL (self->top_carousel), NULL); gs_category_page_add_placeholders (self, GTK_FLOW_BOX (self->category_detail_box), MIN (30, gs_category_get_size (self->subcategory))); - gs_category_page_add_placeholders (self, GTK_FLOW_BOX (self->recently_updated_flow_box), MAX_RECENTLY_UPDATED_APPS); + gs_category_page_add_placeholders (self, GTK_FLOW_BOX (self->recently_updated_flow_box), MAX_RECENT_APPS_TO_DISPLAY); gtk_widget_set_visible (self->top_carousel, TRUE); gtk_widget_set_visible (self->category_detail_box, TRUE); gtk_widget_set_visible (self->recently_updated_flow_box, TRUE); -- GitLab From 09175c518f6986457677ca9ee49e59a46f0a47d8 Mon Sep 17 00:00:00 2001 From: sid Date: Sat, 2 Sep 2023 00:39:26 +0000 Subject: [PATCH 6/9] gs-category-page: Show latest release date for recently updated apps on hover See merge request GNOME/gnome-software!1748 --- src/gs-category-page.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/gs-category-page.c b/src/gs-category-page.c index 33f0bd450..e54cfa22d 100644 --- a/src/gs-category-page.c +++ b/src/gs-category-page.c @@ -431,7 +431,16 @@ populate_flow_boxes (GsCategoryPage *self, /* Populate recently updated flowbox */ if (recently_updated_app_tiles) { for (i = 0; i < recently_updated_app_tiles->len; i++) { + guint64 release_date; + g_autofree gchar *release_date_tooltip = NULL; tile = g_ptr_array_index (recently_updated_app_tiles, i); + + /* Shows the latest release date of the app in + relative format (e.g. "10 days ago") on hover. */ + release_date = gs_app_get_release_date (gs_app_tile_get_app (GS_APP_TILE (tile))); + release_date_tooltip = gs_utils_time_to_string (release_date); + gtk_widget_set_tooltip_text (tile, release_date_tooltip); + gtk_flow_box_insert (GTK_FLOW_BOX (self->recently_updated_flow_box), tile, -1); gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE); } -- GitLab From 4e1ef48f4cb605d94b87bca49cc7f83181a9f1a1 Mon Sep 17 00:00:00 2001 From: sid Date: Thu, 7 Sep 2023 18:08:08 +0000 Subject: [PATCH 7/9] gs-overview-page: Show latest release date for recently updated apps on hover See merge request GNOME/gnome-software!1748 --- src/gs-overview-page.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/gs-overview-page.c b/src/gs-overview-page.c index 26d32e1d4..ad8d31897 100644 --- a/src/gs-overview-page.c +++ b/src/gs-overview-page.c @@ -250,8 +250,18 @@ gs_overview_page_get_recent_cb (GObject *source_object, GAsyncResult *res, gpoin gs_widget_remove_all (self->box_recent, (GsRemoveFunc) gtk_flow_box_remove); for (i = 0; i < gs_app_list_length (list); i++) { + guint64 release_date; + g_autofree gchar *release_date_tooltip = NULL; + app = gs_app_list_index (list, i); tile = gs_summary_tile_new (app); + + /* Shows the latest release date of the app in + relative format (e.g. "10 days ago") on hover. */ + release_date = gs_app_get_release_date (app); + release_date_tooltip = gs_utils_time_to_string (release_date); + gtk_widget_set_tooltip_text (tile, release_date_tooltip); + gtk_flow_box_insert (GTK_FLOW_BOX (self->box_recent), tile, -1); } gtk_widget_set_visible (self->box_recent, TRUE); -- GitLab From ed2aa3f15990c732e3264aa859db1c50b9a5b97a Mon Sep 17 00:00:00 2001 From: sid Date: Tue, 12 Sep 2023 19:40:47 +0000 Subject: [PATCH 8/9] gs-category-page: Use 'gs_utils_app_sort_name()' when sorting apps by name See merge request GNOME/gnome-software!1748 --- src/gs-category-page.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gs-category-page.c b/src/gs-category-page.c index e54cfa22d..53c5fae74 100644 --- a/src/gs-category-page.c +++ b/src/gs-category-page.c @@ -310,7 +310,7 @@ app_name_flowbox_sort_func (GtkFlowBoxChild *child1, if (app2 == NULL) return -1; - return gs_utils_sort_strcmp (gs_app_get_name (app1), gs_app_get_name (app2)); + return gs_utils_app_sort_name (app1, app2, NULL); } static gint @@ -333,7 +333,7 @@ release_date_sort_func (GsAppTile *tile1, release_date2 = gs_app_get_release_date (app2); if (release_date1 == release_date2) - return g_utf8_collate (gs_app_get_name (app1), gs_app_get_name (app2)); + return gs_utils_app_sort_name (app1, app2, NULL); return release_date1 < release_date2 ? 1 : -1; } -- GitLab From b53d82c12d9240a25558e06fd62cb14366848d06 Mon Sep 17 00:00:00 2001 From: sid Date: Tue, 12 Sep 2023 19:46:51 +0000 Subject: [PATCH 9/9] gs-category-page: Don't sort query results as we sort apps later anyway Since the only usage of the '_max_results_sort_cb()' sort function is now removed, it was decided to remove the function to avoid compiler warnings. See merge request GNOME/gnome-software!1748 --- src/gs-category-page.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/gs-category-page.c b/src/gs-category-page.c index 53c5fae74..34e7edca8 100644 --- a/src/gs-category-page.c +++ b/src/gs-category-page.c @@ -94,17 +94,6 @@ top_carousel_app_clicked_cb (GsFeaturedCarousel *carousel, g_signal_emit (self, obj_signals[SIGNAL_APP_CLICKED], 0, app); } -static gint -_max_results_sort_cb (GsApp *app1, GsApp *app2, gpointer user_data) -{ - gint name_sort = gs_utils_sort_strcmp (gs_app_get_name (app1), gs_app_get_name (app2)); - - if (name_sort != 0) - return name_sort; - - return gs_app_get_rating (app1) - gs_app_get_rating (app2); -} - static void gs_category_page_add_placeholders (GsCategoryPage *self, GtkFlowBox *flow_box, @@ -724,7 +713,6 @@ gs_category_page_load_category (GsCategoryPage *self) featured_query = gs_app_query_new ("category", featured_subcat, "refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_KUDOS, - "sort-func", gs_utils_app_sort_name, "license-type", gs_page_get_query_license_type (GS_PAGE (self)), NULL); featured_plugin_job = gs_plugin_job_list_apps_new (featured_query, @@ -745,7 +733,6 @@ gs_category_page_load_category (GsCategoryPage *self) GS_PLUGIN_REFINE_FLAGS_REQUIRE_KUDOS, "dedupe-flags", GS_APP_LIST_FILTER_FLAG_PREFER_INSTALLED | GS_APP_LIST_FILTER_FLAG_KEY_ID_PROVIDES, - "sort-func", _max_results_sort_cb, "license-type", gs_page_get_query_license_type (GS_PAGE (self)), NULL); main_plugin_job = gs_plugin_job_list_apps_new (main_query, -- GitLab