[gnome-software/1364-implement-other-apps-by-author-section-in-app-details-page: 10/14] gs-details-page: Add "Other Apps by $author" section




commit 6dadef76932b5e27b3932bcb40798588d4b8285d
Author: Milan Crha <mcrha redhat com>
Date:   Tue Mar 15 18:19:57 2022 +0100

    gs-details-page: Add "Other Apps by $author" section
    
    Add the "Other Apps by $author" section at the end of the page,
    thus the users can check what other apps the developer or a project
    group offers.
    
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1364

 src/gs-details-page.c  | 99 +++++++++++++++++++++++++++++++++++++++++++++++++-
 src/gs-details-page.ui | 42 +++++++++++++++++++++
 2 files changed, 140 insertions(+), 1 deletion(-)
---
diff --git a/src/gs-details-page.c b/src/gs-details-page.c
index dd1591087..d23229492 100644
--- a/src/gs-details-page.c
+++ b/src/gs-details-page.c
@@ -32,6 +32,7 @@
 #include "gs-progress-button.h"
 #include "gs-screenshot-carousel.h"
 #include "gs-star-widget.h"
+#include "gs-summary-tile.h"
 #include "gs-review-histogram.h"
 #include "gs-review-dialog.h"
 #include "gs-review-row.h"
@@ -147,6 +148,9 @@ struct _GsDetailsPage
        GsLicenseTile           *license_tile;
        GtkInfoBar              *translation_infobar;
        GtkButton               *translation_infobar_button;
+       GtkWidget               *other_apps_heading;
+       GtkWidget               *box_other_apps;
+       gchar                   *last_developer_name;
 };
 
 G_DEFINE_TYPE (GsDetailsPage, gs_details_page, GS_TYPE_PAGE)
@@ -947,6 +951,55 @@ update_action_row_from_link (AdwActionRow *row,
        return (url != NULL);
 }
 
+static void
+gs_details_page_app_tile_clicked (GsAppTile *tile,
+                                 gpointer user_data)
+{
+       GsDetailsPage *self = GS_DETAILS_PAGE (user_data);
+       GsApp *app;
+
+       app = gs_app_tile_get_app (tile);
+       gs_details_page_set_app (self, app);
+}
+
+static void
+gs_details_page_search_other_apps_cb (GObject *source_object,
+                                     GAsyncResult *result,
+                                     gpointer user_data)
+{
+       GsDetailsPage *self = GS_DETAILS_PAGE (user_data);
+       g_autoptr(GsAppList) list = NULL;
+       g_autoptr(GError) local_error = NULL;
+       gboolean any_added = FALSE;
+
+       list = gs_plugin_loader_job_process_finish (GS_PLUGIN_LOADER (source_object), result, &local_error);
+       if (list == NULL) {
+               if (g_error_matches (local_error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED) ||
+                   g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+                       g_debug ("search cancelled");
+                       return;
+               }
+               g_warning ("failed to get other apps: %s", local_error->message);
+               return;
+       }
+
+       if (!self->app || !gs_page_is_active (GS_PAGE (self)))
+               return;
+
+       for (guint i = 0; i < gs_app_list_length (list); i++) {
+               GsApp *app = gs_app_list_index (list, i);
+               if (g_strcmp0 (gs_app_get_id (app), gs_app_get_id (self->app)) != 0) {
+                       GtkWidget *tile = gs_summary_tile_new (app);
+                       g_signal_connect (tile, "clicked", G_CALLBACK (gs_details_page_app_tile_clicked), 
self);
+                       gtk_flow_box_insert (GTK_FLOW_BOX (self->box_other_apps), tile, -1);
+
+                       any_added = TRUE;
+               }
+       }
+
+       gtk_widget_set_visible (self->box_other_apps, any_added);
+}
+
 static void
 gs_details_page_refresh_all (GsDetailsPage *self)
 {
@@ -1027,8 +1080,49 @@ gs_details_page_refresh_all (GsDetailsPage *self)
        tmp = gs_app_get_developer_name (self->app);
        if (tmp == NULL)
                tmp = gs_app_get_project_group (self->app);
-       if (tmp != NULL)
+       if (tmp != NULL) {
                gtk_label_set_label (GTK_LABEL (self->developer_name_label), tmp);
+
+               if (g_strcmp0 (tmp, self->last_developer_name) != 0) {
+                       g_autoptr(GsPluginJob) plugin_job = NULL;
+                       g_autofree gchar *heading = NULL;
+
+                       /* Hide the section, it will be shown only if any other app had been found */
+                       gtk_widget_set_visible (self->box_other_apps, FALSE);
+
+                       g_clear_pointer (&self->last_developer_name, g_free);
+                       self->last_developer_name = g_strdup (tmp);
+
+                       /* Translators: the '%s' is replaced with a developer name or a project group */
+                       heading = g_strdup_printf (_("Other Apps by %s"), self->last_developer_name);
+                       gtk_label_set_label (GTK_LABEL (self->other_apps_heading), heading);
+                       gs_widget_remove_all (self->box_other_apps, (GsRemoveFunc) gtk_flow_box_remove);
+
+                       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_SEARCH_OTHER_APPS,
+                                                        "search", self->last_developer_name,
+                                                        "max-results", 18,
+                                                        "refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
+                                                                        
GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
+                                                                        
GS_PLUGIN_REFINE_FLAGS_REQUIRE_HISTORY |
+                                                                        
GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION |
+                                                                        
GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEW_RATINGS |
+                                                                        
GS_PLUGIN_REFINE_FLAGS_REQUIRE_DESCRIPTION |
+                                                                        
GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE |
+                                                                        
GS_PLUGIN_REFINE_FLAGS_REQUIRE_PERMISSIONS |
+                                                                        
GS_PLUGIN_REFINE_FLAGS_REQUIRE_RATING,
+                                                        "dedupe-flags", 
GS_APP_LIST_FILTER_FLAG_KEY_ID_PROVIDES,
+                                                        NULL);
+                       gs_plugin_loader_job_process_async (self->plugin_loader, plugin_job,
+                                                           self->cancellable,
+                                                           gs_details_page_search_other_apps_cb,
+                                                           self);
+               }
+       } else if (tmp == NULL) {
+               g_clear_pointer (&self->last_developer_name, g_free);
+               gs_widget_remove_all (self->box_other_apps, (GsRemoveFunc) gtk_flow_box_remove);
+               gtk_widget_set_visible (self->box_other_apps, FALSE);
+       }
+
        gtk_widget_set_visible (GTK_WIDGET (self->developer_name_label), tmp != NULL);
        gtk_widget_set_visible (GTK_WIDGET (self->developer_verified_image), gs_app_has_quirk (self->app, 
GS_APP_QUIRK_DEVELOPER_VERIFIED));
 
@@ -2153,6 +2247,7 @@ gs_details_page_dispose (GObject *object)
        g_clear_object (&self->size_group_origin_popover);
        g_clear_object (&self->odrs_provider);
        g_clear_object (&self->app_info_monitor);
+       g_clear_pointer (&self->last_developer_name, g_free);
 
        G_OBJECT_CLASS (gs_details_page_parent_class)->dispose (object);
 }
@@ -2281,6 +2376,8 @@ gs_details_page_class_init (GsDetailsPageClass *klass)
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, license_tile);
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, translation_infobar);
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, translation_infobar_button);
+       gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, other_apps_heading);
+       gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, box_other_apps);
 
        gtk_widget_class_bind_template_callback (widget_class, gs_details_page_link_row_activated_cb);
        gtk_widget_class_bind_template_callback (widget_class, 
gs_details_page_license_tile_get_involved_activated_cb);
diff --git a/src/gs-details-page.ui b/src/gs-details-page.ui
index cda8392a1..5fb88fd0e 100644
--- a/src/gs-details-page.ui
+++ b/src/gs-details-page.ui
@@ -899,6 +899,48 @@
                                 </child>
                               </object>
                             </child>
+                            <child>
+                              <object class="AdwClamp">
+                                <property name="visible" bind-source="box_other_apps" 
bind-property="visible" bind-flags="sync-create"/>
+                                <property name="maximum-size">860</property>
+                                <!-- ~⅔ of the maximum size. -->
+                                <property name="tightening-threshold">576</property>
+                                <property name="margin-start">12</property>
+                                <property name="margin-end">12</property>
+                                <child>
+                                  <object class="GtkBox">
+                                    <property name="halign">center</property>
+                                    <property name="hexpand">False</property>
+                                    <property name="orientation">vertical</property>
+                                    <property name="valign">start</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <object class="GtkLabel" id="other_apps_heading">
+                                        <property name="xalign">0</property>
+                                        <!-- the label is set in the code -->
+                                        <property name="label">Other Apps by ...</property>
+                                        <property name="margin-top">21</property>
+                                        <property name="margin-bottom">6</property>
+                                        <style>
+                                          <class name="heading"/>
+                                        </style>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFlowBox" id="box_other_apps">
+                                        <property name="homogeneous">True</property>
+                                        <property name="column-spacing">14</property>
+                                        <property name="row-spacing">14</property>
+                                        <property name="valign">start</property>
+                                        <accessibility>
+                                          <relation name="labelled-by">other_apps_heading</relation>
+                                        </accessibility>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
                           </object>
                         </child>
                       </object>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]