[gnome-software] Implement the sorting of apps in the category view



commit 65f03f6045524236d2eebbc2d52298e9189dc97c
Author: Joaquim Rocha <jrocha endlessm com>
Date:   Thu Aug 10 22:42:18 2017 +0100

    Implement the sorting of apps in the category view
    
    This implementation follows the new designs and uses a popover
    to select between sorting by rating or by name.

 src/gs-category-page.c  |   99 +++++++++++++++++++++++++++++++++++++++++++++++
 src/gs-category-page.ui |   89 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 188 insertions(+), 0 deletions(-)
---
diff --git a/src/gs-category-page.c b/src/gs-category-page.c
index fb3432d..3959027 100644
--- a/src/gs-category-page.c
+++ b/src/gs-category-page.c
@@ -23,11 +23,17 @@
 #include "config.h"
 
 #include <string.h>
+#include <glib/gi18n.h>
 
 #include "gs-common.h"
 #include "gs-summary-tile.h"
 #include "gs-category-page.h"
 
+typedef enum {
+       SUBCATEGORY_SORT_TYPE_RATING,
+       SUBCATEGORY_SORT_TYPE_NAME
+} SubcategorySortType;
+
 struct _GsCategoryPage
 {
        GsPage           parent_instance;
@@ -38,6 +44,9 @@ struct _GsCategoryPage
        GsShell         *shell;
        GsCategory      *category;
        GsCategory      *subcategory;
+       guint           sort_rating_handler_id;
+       guint           sort_name_handler_id;
+       SubcategorySortType sort_type;
 
        GtkWidget       *infobar_category_shell_extensions;
        GtkWidget       *button_category_shell_extensions;
@@ -46,6 +55,9 @@ struct _GsCategoryPage
        GtkWidget       *subcats_filter_button_label;
        GtkWidget       *subcats_filter_button;
        GtkWidget       *popover_filter_box;
+       GtkWidget       *subcats_sort_button_label;
+       GtkWidget       *sort_rating_button;
+       GtkWidget       *sort_name_button;
 };
 
 G_DEFINE_TYPE (GsCategoryPage, gs_category_page, GS_TYPE_PAGE)
@@ -72,6 +84,40 @@ app_tile_clicked (GsAppTile *tile, gpointer data)
 }
 
 static void
+gs_category_page_sort_by_type (GsCategoryPage *self,
+                              SubcategorySortType sort_type)
+{
+       const gchar *button_label;
+
+       if (sort_type == SUBCATEGORY_SORT_TYPE_NAME)
+               /* TRANSLATORS: button text when apps have been sorted alphabetically */
+               button_label = _("Sorted by Name");
+       else
+               /* TRANSLATORS: button text when apps have been sorted by their rating */
+               button_label = _("Sorted by Rating");
+
+       gtk_label_set_text (GTK_LABEL (self->subcats_sort_button_label), button_label);
+
+       /* only sort again if the sort type is different */
+       if (self->sort_type == sort_type)
+               return;
+
+       self->sort_type = sort_type;
+       gtk_flow_box_invalidate_sort (GTK_FLOW_BOX (self->category_detail_box));
+}
+
+static void
+sort_button_clicked (GtkButton *button, gpointer data)
+{
+       GsCategoryPage *self = GS_CATEGORY_PAGE (data);
+
+       if (button == GTK_BUTTON (self->sort_rating_button))
+               gs_category_page_sort_by_type (self, SUBCATEGORY_SORT_TYPE_RATING);
+       else
+               gs_category_page_sort_by_type (self, SUBCATEGORY_SORT_TYPE_NAME);
+}
+
+static void
 gs_category_page_get_apps_cb (GObject *source_object,
                               GAsyncResult *res,
                               gpointer user_data)
@@ -105,6 +151,15 @@ gs_category_page_get_apps_cb (GObject *source_object,
                gtk_widget_set_can_focus (gtk_widget_get_parent (tile), FALSE);
        }
 
+       self->sort_rating_handler_id = g_signal_connect (self->sort_rating_button,
+                                                        "clicked",
+                                                        G_CALLBACK (sort_button_clicked),
+                                                        self);
+       self->sort_name_handler_id = g_signal_connect (self->sort_name_button,
+                                                      "clicked",
+                                                      G_CALLBACK (sort_button_clicked),
+                                                      self);
+
        /* seems a good place */
        gs_shell_profile_dump (self->shell);
 }
@@ -115,6 +170,31 @@ _max_results_sort_cb (GsApp *app1, GsApp *app2, gpointer user_data)
        return gs_app_get_rating (app1) < gs_app_get_rating (app2);
 }
 
+static gint
+gs_category_page_sort_flow_box_sort_func (GtkFlowBoxChild *child1,
+                                         GtkFlowBoxChild *child2,
+                                         gpointer data)
+{
+       GsApp *app1 = gs_app_tile_get_app (GS_APP_TILE (gtk_bin_get_child (GTK_BIN (child1))));
+       GsApp *app2 = gs_app_tile_get_app (GS_APP_TILE (gtk_bin_get_child (GTK_BIN (child2))));
+       SubcategorySortType sort_type;
+
+       if (!GS_IS_APP (app1) || !GS_IS_APP (app2))
+               return 0;
+
+       sort_type = GS_CATEGORY_PAGE (data)->sort_type;
+
+       if (sort_type == SUBCATEGORY_SORT_TYPE_RATING) {
+               gint rating_app1 = gs_app_get_rating (app1);
+               gint rating_app2 = gs_app_get_rating (app2);
+               if (rating_app1 > rating_app2)
+                       return -1;
+               if (rating_app1 < rating_app2)
+                       return 1;
+       }
+       return g_strcmp0 (gs_app_get_name (app1), gs_app_get_name (app2));
+}
+
 static void
 gs_category_page_reload (GsPage *page)
 {
@@ -144,7 +224,19 @@ gs_category_page_reload (GsPage *page)
                gtk_widget_set_visible (self->infobar_category_shell_extensions, FALSE);
        }
 
+       if (self->sort_rating_handler_id > 0)
+               g_signal_handler_disconnect (self->sort_rating_button,
+                                            self->sort_rating_handler_id);
+
+       if (self->sort_name_handler_id > 0)
+               g_signal_handler_disconnect (self->sort_name_button,
+                                            self->sort_name_handler_id);
+
        gs_container_remove_all (GTK_CONTAINER (self->category_detail_box));
+
+       /* just ensure the sort button has the correct label */
+       gs_category_page_sort_by_type (self, self->sort_type);
+
        count = MIN(30, gs_category_get_size (self->subcategory));
        for (i = 0; i < count; i++) {
                tile = gs_summary_tile_new (NULL);
@@ -300,6 +392,10 @@ gs_category_page_setup (GsPage *page,
        self->plugin_loader = g_object_ref (plugin_loader);
        self->builder = g_object_ref (builder);
        self->shell = shell;
+       self->sort_type = SUBCATEGORY_SORT_TYPE_RATING;
+       gtk_flow_box_set_sort_func (GTK_FLOW_BOX (self->category_detail_box),
+                                   gs_category_page_sort_flow_box_sort_func,
+                                   self, NULL);
 
        adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (self->scrolledwindow_category));
        gtk_container_set_focus_vadjustment (GTK_CONTAINER (self->category_detail_box), adj);
@@ -330,6 +426,9 @@ gs_category_page_class_init (GsCategoryPageClass *klass)
        gtk_widget_class_bind_template_child (widget_class, GsCategoryPage, subcats_filter_button_label);
        gtk_widget_class_bind_template_child (widget_class, GsCategoryPage, subcats_filter_button);
        gtk_widget_class_bind_template_child (widget_class, GsCategoryPage, popover_filter_box);
+       gtk_widget_class_bind_template_child (widget_class, GsCategoryPage, subcats_sort_button_label);
+       gtk_widget_class_bind_template_child (widget_class, GsCategoryPage, sort_rating_button);
+       gtk_widget_class_bind_template_child (widget_class, GsCategoryPage, sort_name_button);
 }
 
 GsCategoryPage *
diff --git a/src/gs-category-page.ui b/src/gs-category-page.ui
index a45177f..59ff7a5 100644
--- a/src/gs-category-page.ui
+++ b/src/gs-category-page.ui
@@ -11,6 +11,28 @@
       </object>
     </child>
   </object>
+  <object class="GtkPopover" id="sorting_popover">
+    <property name="position">bottom</property>
+    <child>
+      <object class="GtkBox" id="sorting_popover_box">
+        <property name="visible">True</property>
+        <property name="margin">10</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkModelButton" id="sort_rating_button">
+            <property name="visible">True</property>
+            <property name="text" translatable="yes" comments="Translators: A label for a button to sort 
apps by their rating.">Top Rated</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="sort_name_button">
+            <property name="visible">True</property>
+            <property name="text" translatable="yes" comments="Translators: A label for a button to sort 
apps alphabetically.">Name</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
   <template class="GsCategoryPage" parent="GsPage">
     <child>
       <object class="GtkBox" id="box_category">
@@ -165,6 +187,65 @@
                                       <class name="text-button"/>
                                     </style>
                                   </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="pack-type">start</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkMenuButton" id="subcats_sort_button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="relief">normal</property>
+                                    <property name="popover">sorting_popover</property>
+                                    <child internal-child="accessible">
+                                      <object class="AtkObject">
+                                        <property name="accessible-name" translatable="yes">Subcategories 
sorting menu</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkBox" id="grid2">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="valign">center</property>
+                                        <property name="spacing">6</property>
+                                        <property name="orientation">horizontal</property>
+                                        <child>
+                                          <object class="GtkLabel" id="subcats_sort_button_label">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="xalign">0.0</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">True</property>
+                                            <property name="fill">False</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkArrow" id="arrow2">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="arrow_type">down</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="pack-type">end</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+                                    <style>
+                                      <class name="text-button"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="pack-type">end</property>
+                                  </packing>
                                 </child>
                               </object>
                             </child>
@@ -210,4 +291,12 @@
       <widget name="popover_filter_box"/>
     </widgets>
   </object>
+  <object class="GtkSizeGroup">
+    <property name="ignore-hidden">False</property>
+    <property name="mode">horizontal</property>
+    <widgets>
+      <widget name="subcats_sort_button_label"/>
+      <widget name="sorting_popover_box"/>
+    </widgets>
+  </object>
 </interface>


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