[gnome-software/wip/hughsie/moderate] Add a moderation view in gnome-software



commit 8f3ec3cf42abde40979760973adf85aed55e4540
Author: Richard Hughes <richard hughsie com>
Date:   Thu Feb 11 18:09:29 2016 +0000

    Add a moderation view in gnome-software
    
    This is work in progress, and would perhaps be done better server-side anyway...

 src/Makefile.am                         |    2 +
 src/gnome-software.gresource.xml        |    1 +
 src/gnome-software.ui                   |    8 +
 src/gs-application.c                    |    2 +
 src/gs-plugin-loader.c                  |   83 ++++++++
 src/gs-plugin-loader.h                  |    8 +
 src/gs-plugin.h                         |    4 +
 src/gs-shell-moderate.c                 |  328 +++++++++++++++++++++++++++++++
 src/gs-shell-moderate.h                 |   51 +++++
 src/gs-shell-moderate.ui                |   62 ++++++
 src/gs-shell.c                          |   12 ++
 src/gs-shell.h                          |    1 +
 src/plugins/gs-plugin-xdg-app-reviews.c |   33 +++
 13 files changed, 595 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 519143b..6e7d341 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -167,6 +167,8 @@ gnome_software_SOURCES =                            \
        gs-shell-extras.h                               \
        gs-shell-installed.c                            \
        gs-shell-installed.h                            \
+       gs-shell-moderate.c                             \
+       gs-shell-moderate.h                             \
        gs-shell-overview.c                             \
        gs-shell-overview.h                             \
        gs-shell-updates.c                              \
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 261562f..9c29e61 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -20,6 +20,7 @@
   <file preprocess="xml-stripblanks">gs-shell-extras.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-details.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-installed.ui</file>
+  <file preprocess="xml-stripblanks">gs-shell-moderate.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-overview.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-search.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-updates.ui</file>
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index 6392826..03d1ef2 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -407,6 +407,14 @@
               </packing>
             </child>
             <child>
+              <object class="GsShellModerate" id="shell_moderate">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="name">moderate</property>
+              </packing>
+            </child>
+            <child>
               <object class="GsShellSearch" id="shell_search">
                 <property name="visible">True</property>
               </object>
diff --git a/src/gs-application.c b/src/gs-application.c
index 71f6f66..e811a15 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -513,6 +513,8 @@ set_mode_activated (GSimpleAction *action,
                gs_shell_set_mode (app->shell, GS_SHELL_MODE_UPDATES);
        } else if (g_strcmp0 (mode, "installed") == 0) {
                gs_shell_set_mode (app->shell, GS_SHELL_MODE_INSTALLED);
+       } else if (g_strcmp0 (mode, "moderate") == 0) {
+               gs_shell_set_mode (app->shell, GS_SHELL_MODE_MODERATE);
        } else if (g_strcmp0 (mode, "overview") == 0) {
                gs_shell_set_mode (app->shell, GS_SHELL_MODE_OVERVIEW);
        } else if (g_strcmp0 (mode, "updated") == 0) {
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index ccf3ebc..dd4a588 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -1003,6 +1003,89 @@ gs_plugin_loader_get_distro_upgrades_finish (GsPluginLoader *plugin_loader,
 /******************************************************************************/
 
 /**
+ * gs_plugin_loader_get_unvoted_reviews_thread_cb:
+ **/
+static void
+gs_plugin_loader_get_unvoted_reviews_thread_cb (GTask *task,
+                                               gpointer object,
+                                               gpointer task_data,
+                                               GCancellable *cancellable)
+{
+       GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) task_data;
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+       GError *error = NULL;
+
+       state->list = gs_plugin_loader_run_results (plugin_loader,
+                                                   "gs_plugin_add_unvoted_reviews",
+                                                   state->flags,
+                                                   cancellable,
+                                                   &error);
+       if (error != NULL) {
+               g_task_return_error (task, error);
+               return;
+       }
+
+       /* filter package list */
+       gs_plugin_list_filter_duplicates (&state->list);
+
+       /* dedupe applications we already know about */
+       gs_plugin_loader_list_dedupe (plugin_loader, state->list);
+
+       /* success */
+       g_task_return_pointer (task, gs_plugin_list_copy (state->list), (GDestroyNotify) gs_plugin_list_free);
+}
+
+/**
+ * gs_plugin_loader_get_unvoted_reviews_async:
+ *
+ * This method calls all plugins that implement the gs_plugin_add_unvoted_reviews()
+ * function.
+ **/
+void
+gs_plugin_loader_get_unvoted_reviews_async (GsPluginLoader *plugin_loader,
+                                           GsPluginRefineFlags flags,
+                                           GCancellable *cancellable,
+                                           GAsyncReadyCallback callback,
+                                           gpointer user_data)
+{
+       GsPluginLoaderAsyncState *state;
+       g_autoptr(GTask) task = NULL;
+
+       g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+       g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+       /* save state */
+       state = g_slice_new0 (GsPluginLoaderAsyncState);
+       state->flags = flags;
+
+       /* run in a thread */
+       task = g_task_new (plugin_loader, cancellable, callback, user_data);
+       g_task_set_task_data (task, state, (GDestroyNotify) gs_plugin_loader_free_async_state);
+       g_task_set_return_on_cancel (task, TRUE);
+       g_task_run_in_thread (task, gs_plugin_loader_get_unvoted_reviews_thread_cb);
+}
+
+/**
+ * gs_plugin_loader_get_unvoted_reviews_finish:
+ *
+ * Return value: (element-type GsApp) (transfer full): A list of applications
+ **/
+GList *
+gs_plugin_loader_get_unvoted_reviews_finish (GsPluginLoader *plugin_loader,
+                                            GAsyncResult *res,
+                                            GError **error)
+{
+       g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
+       g_return_val_if_fail (G_IS_TASK (res), NULL);
+       g_return_val_if_fail (g_task_is_valid (res, plugin_loader), NULL);
+       g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+       return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+/******************************************************************************/
+
+/**
  * gs_plugin_loader_get_sources_thread_cb:
  **/
 static void
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 3925dc9..2365cb0 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -95,6 +95,14 @@ void          gs_plugin_loader_get_distro_upgrades_async (GsPluginLoader     *plugin_loader
 GList          *gs_plugin_loader_get_distro_upgrades_finish (GsPluginLoader    *plugin_loader,
                                                         GAsyncResult   *res,
                                                         GError         **error);
+void            gs_plugin_loader_get_unvoted_reviews_async (GsPluginLoader     *plugin_loader,
+                                                        GsPluginRefineFlags flags,
+                                                        GCancellable   *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer        user_data);
+GList          *gs_plugin_loader_get_unvoted_reviews_finish (GsPluginLoader    *plugin_loader,
+                                                        GAsyncResult   *res,
+                                                        GError         **error);
 void            gs_plugin_loader_get_sources_async     (GsPluginLoader *plugin_loader,
                                                         GsPluginRefineFlags flags,
                                                         GCancellable   *cancellable,
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index cfbeef9..ac0bf39 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -249,6 +249,10 @@ gboolean    gs_plugin_add_featured                 (GsPlugin       *plugin,
                                                         GList          **list,
                                                         GCancellable   *cancellable,
                                                         GError         **error);
+gboolean        gs_plugin_add_unvoted_reviews          (GsPlugin       *plugin,
+                                                        GList          **list,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
 gboolean        gs_plugin_refine                       (GsPlugin       *plugin,
                                                         GList          **list,
                                                         GsPluginRefineFlags flags,
diff --git a/src/gs-shell-moderate.c b/src/gs-shell-moderate.c
new file mode 100644
index 0000000..4036458
--- /dev/null
+++ b/src/gs-shell-moderate.c
@@ -0,0 +1,328 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2013 Matthias Clasen <mclasen redhat com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+//#include <appstream-glib.h>
+
+#include "gs-shell.h"
+#include "gs-shell-moderate.h"
+#include "gs-app.h"
+#include "gs-utils.h"
+#include "gs-app-row.h"
+#include "gs-review-row.h"
+
+struct _GsShellModerate
+{
+       GsPage                   parent_instance;
+
+       GsPluginLoader          *plugin_loader;
+       GtkBuilder              *builder;
+       GCancellable            *cancellable;
+       GtkSizeGroup            *sizegroup_image;
+       GtkSizeGroup            *sizegroup_name;
+       gboolean                 waiting;
+       GsShell                 *shell;
+
+       GtkWidget               *list_box_install;
+       GtkWidget               *scrolledwindow_install;
+       GtkWidget               *spinner_install;
+       GtkWidget               *stack_install;
+};
+
+G_DEFINE_TYPE (GsShellModerate, gs_shell_moderate, GS_TYPE_PAGE)
+
+static void
+gs_shell_moderate_app_row_activated_cb (GtkListBox *list_box,
+                                        GtkListBoxRow *row,
+                                        GsShellModerate *self)
+{
+       g_warning ("APP ACTIVATED");
+//     GsApp *app;
+//     app = gs_app_row_get_app (GS_APP_ROW (row));
+//     gs_shell_show_app (self->shell, app);
+}
+
+/**
+ * gs_shell_moderate_app_remove_cb:
+ **/
+static void
+gs_shell_moderate_app_remove_cb (GsAppRow *app_row,
+                                 GsShellModerate *self)
+{
+       g_warning ("APP ACTION");
+}
+
+/**
+ * gs_shell_moderate_app_set_review_cb:
+ **/
+static void
+gs_shell_moderate_app_set_review_cb (GObject *source,
+                                    GAsyncResult *res,
+                                    gpointer user_data)
+{
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
+//     GsShellDetails *self = GS_SHELL_DETAILS (user_data);
+       g_autoptr(GError) error = NULL;
+
+       if (!gs_plugin_loader_app_action_finish (plugin_loader, res, &error)) {
+               g_warning ("failed to set review: %s", error->message);
+               return;
+       }
+}
+
+static void
+gs_shell_moderate_review_clicked_cb (GsReviewRow *row,
+                                    GsReviewAction action,
+                                    GsShellModerate *self)
+{
+       GsApp *app = g_object_get_data (G_OBJECT (row), "GsApp");
+       gs_plugin_loader_review_action_async (self->plugin_loader,
+                                             app,
+                                             gs_review_row_get_review (row),
+                                             action,
+                                             self->cancellable,
+                                             gs_shell_moderate_app_set_review_cb,
+                                             self);
+       gtk_widget_set_visible (GTK_WIDGET (row), FALSE);
+}
+
+static void
+gs_shell_moderate_add_app (GsShellModerate *self, GsApp *app)
+{
+       GPtrArray *reviews;
+       GtkWidget *app_row;
+       guint i;
+
+       /* add top level app */
+       app_row = gs_app_row_new (app);
+       gs_app_row_set_colorful (GS_APP_ROW (app_row), FALSE);
+       g_signal_connect (app_row, "button-clicked",
+                         G_CALLBACK (gs_shell_moderate_app_remove_cb), self);
+       gtk_container_add (GTK_CONTAINER (self->list_box_install), app_row);
+       gs_app_row_set_size_groups (GS_APP_ROW (app_row),
+                                   self->sizegroup_image,
+                                   self->sizegroup_name);
+
+       /* add reviews */
+       reviews = gs_app_get_reviews (app);
+       for (i = 0; i < reviews->len; i++) {
+               GsReview *review = g_ptr_array_index (reviews, i);
+               GtkWidget *row = gs_review_row_new (review);
+               gs_review_row_set_actions (GS_REVIEW_ROW (row),
+                                          1 << GS_REVIEW_ACTION_UPVOTE |
+                                          1 << GS_REVIEW_ACTION_DOWNVOTE |
+                                          1 << GS_REVIEW_ACTION_REPORT);
+               g_signal_connect (row, "button-clicked",
+                                 G_CALLBACK (gs_shell_moderate_review_clicked_cb), self);
+               g_object_set_data_full (G_OBJECT (row), "GsApp",
+                                       g_object_ref (app),
+                                       (GDestroyNotify) g_object_unref);
+               gtk_container_add (GTK_CONTAINER (self->list_box_install), row);
+       }
+       gtk_widget_show (app_row);
+}
+
+/**
+ * gs_shell_moderate_get_unvoted_reviews_cb:
+ **/
+static void
+gs_shell_moderate_get_unvoted_reviews_cb (GObject *source_object,
+                                         GAsyncResult *res,
+                                         gpointer user_data)
+{
+       GList *l;
+       GsApp *app;
+       GsShellModerate *self = GS_SHELL_MODERATE (user_data);
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
+       g_autoptr(GError) error = NULL;
+       g_autoptr(GsAppList) list = NULL;
+
+       gs_stop_spinner (GTK_SPINNER (self->spinner_install));
+       gtk_stack_set_visible_child_name (GTK_STACK (self->stack_install), "view");
+
+       self->waiting = FALSE;
+
+       list = gs_plugin_loader_get_unvoted_reviews_finish (plugin_loader,
+                                                           res,
+                                                           &error);
+       if (list == NULL) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                       g_warning ("failed to get moderate apps: %s", error->message);
+               return;
+       }
+       for (l = list; l != NULL; l = l->next) {
+               app = GS_APP (l->data);
+               gs_shell_moderate_add_app (self, app);
+       }
+}
+
+/**
+ * gs_shell_moderate_load:
+ */
+static void
+gs_shell_moderate_load (GsShellModerate *self)
+{
+       if (self->waiting)
+               return;
+       self->waiting = TRUE;
+
+       /* remove old entries */
+       gs_container_remove_all (GTK_CONTAINER (self->list_box_install));
+
+       /* get unvoted reviews as apps */
+       gs_plugin_loader_get_unvoted_reviews_async (self->plugin_loader,
+                                                   GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                                   GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION |
+                                                   GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
+                                                   GS_PLUGIN_REFINE_FLAGS_REQUIRE_PROVENANCE |
+                                                   GS_PLUGIN_REFINE_FLAGS_REQUIRE_DESCRIPTION |
+                                                   GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENCE |
+                                                   GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEWS,
+                                                   self->cancellable,
+                                                   gs_shell_moderate_get_unvoted_reviews_cb,
+                                                   self);
+       gs_start_spinner (GTK_SPINNER (self->spinner_install));
+       gtk_stack_set_visible_child_name (GTK_STACK (self->stack_install), "spinner");
+}
+
+/**
+ * gs_shell_moderate_reload:
+ */
+void
+gs_shell_moderate_reload (GsShellModerate *self)
+{
+       gs_shell_moderate_load (self);
+}
+
+/**
+ * gs_shell_moderate_switch_to:
+ **/
+void
+gs_shell_moderate_switch_to (GsShellModerate *self, gboolean scroll_up)
+{
+       if (gs_shell_get_mode (self->shell) != GS_SHELL_MODE_MODERATE) {
+               g_warning ("Called switch_to(moderate) when in mode %s",
+                          gs_shell_get_mode_string (self->shell));
+               return;
+       }
+       if (scroll_up) {
+               GtkAdjustment *adj;
+               adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW 
(self->scrolledwindow_install));
+               gtk_adjustment_set_value (adj, gtk_adjustment_get_lower (adj));
+       }
+       if (gs_shell_get_mode (self->shell) == GS_SHELL_MODE_MODERATE)
+               gs_grab_focus_when_mapped (self->scrolledwindow_install);
+       gs_shell_moderate_load (self);
+}
+
+/**
+ * gs_shell_moderate_setup:
+ */
+void
+gs_shell_moderate_setup (GsShellModerate *self,
+                         GsShell *shell,
+                         GsPluginLoader *plugin_loader,
+                         GtkBuilder *builder,
+                         GCancellable *cancellable)
+{
+       g_return_if_fail (GS_IS_SHELL_MODERATE (self));
+
+       self->shell = shell;
+       self->plugin_loader = g_object_ref (plugin_loader);
+       self->builder = g_object_ref (builder);
+       self->cancellable = g_object_ref (cancellable);
+
+       /* setup moderate */
+       g_signal_connect (self->list_box_install, "row-activated",
+                         G_CALLBACK (gs_shell_moderate_app_row_activated_cb), self);
+
+       /* chain up */
+       gs_page_setup (GS_PAGE (self),
+                      shell,
+                      plugin_loader,
+                      cancellable);
+}
+
+/**
+ * gs_shell_moderate_dispose:
+ **/
+static void
+gs_shell_moderate_dispose (GObject *object)
+{
+       GsShellModerate *self = GS_SHELL_MODERATE (object);
+
+       g_clear_object (&self->sizegroup_image);
+       g_clear_object (&self->sizegroup_name);
+
+       g_clear_object (&self->builder);
+       g_clear_object (&self->plugin_loader);
+       g_clear_object (&self->cancellable);
+
+       G_OBJECT_CLASS (gs_shell_moderate_parent_class)->dispose (object);
+}
+
+/**
+ * gs_shell_moderate_class_init:
+ **/
+static void
+gs_shell_moderate_class_init (GsShellModerateClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->dispose = gs_shell_moderate_dispose;
+
+       gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Software/gs-shell-moderate.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, GsShellModerate, list_box_install);
+       gtk_widget_class_bind_template_child (widget_class, GsShellModerate, scrolledwindow_install);
+       gtk_widget_class_bind_template_child (widget_class, GsShellModerate, spinner_install);
+       gtk_widget_class_bind_template_child (widget_class, GsShellModerate, stack_install);
+}
+
+/**
+ * gs_shell_moderate_init:
+ **/
+static void
+gs_shell_moderate_init (GsShellModerate *self)
+{
+       gtk_widget_init_template (GTK_WIDGET (self));
+
+       self->sizegroup_image = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+       self->sizegroup_name = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+}
+
+/**
+ * gs_shell_moderate_new:
+ **/
+GsShellModerate *
+gs_shell_moderate_new (void)
+{
+       GsShellModerate *self;
+       self = g_object_new (GS_TYPE_SHELL_MODERATE, NULL);
+       return GS_SHELL_MODERATE (self);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-shell-moderate.h b/src/gs-shell-moderate.h
new file mode 100644
index 0000000..4a74492
--- /dev/null
+++ b/src/gs-shell-moderate.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_SHELL_MODERATE_H
+#define __GS_SHELL_MODERATE_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gs-page.h"
+#include "gs-plugin-loader.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_SHELL_MODERATE (gs_shell_moderate_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsShellModerate, gs_shell_moderate, GS, SHELL_MODERATE, GsPage)
+
+GsShellModerate        *gs_shell_moderate_new          (void);
+void            gs_shell_moderate_switch_to    (GsShellModerate        *self,
+                                                gboolean               scroll_up);
+void            gs_shell_moderate_reload       (GsShellModerate        *self);
+void            gs_shell_moderate_setup        (GsShellModerate        *self,
+                                                GsShell                *shell,
+                                                GsPluginLoader         *plugin_loader,
+                                                GtkBuilder             *builder,
+                                                GCancellable           *cancellable);
+
+G_END_DECLS
+
+#endif /* __GS_SHELL_MODERATE_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-shell-moderate.ui b/src/gs-shell-moderate.ui
new file mode 100644
index 0000000..a781526
--- /dev/null
+++ b/src/gs-shell-moderate.ui
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="GsShellModerate" parent="GsPage">
+    <child internal-child="accessible">
+      <object class="AtkObject" id="moderate-accessible">
+        <property name="accessible-name" translatable="yes">Moderate page</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkStack" id="stack_install">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkSpinner" id="spinner_install">
+            <property name="visible">True</property>
+            <property name="width_request">32</property>
+            <property name="height_request">32</property>
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+          </object>
+          <packing>
+            <property name="name">spinner</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="box_install">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow_install">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <property name="vexpand">True</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GsFixedSizeBin" id="gs_fixed_bin">
+                    <property name="visible">True</property>
+                    <property name="preferred-width">860</property>
+                    <child>
+                      <object class="GtkListBox" id="list_box_install">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="selection_mode">none</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">view</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 62aff1b..37bcb14 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -29,6 +29,7 @@
 #include "gs-shell.h"
 #include "gs-shell-details.h"
 #include "gs-shell-installed.h"
+#include "gs-shell-moderate.h"
 #include "gs-shell-search.h"
 #include "gs-shell-overview.h"
 #include "gs-shell-updates.h"
@@ -46,6 +47,7 @@ static const gchar *page_name[] = {
        "details",
        "category",
        "extras",
+       "moderate",
 };
 
 typedef struct {
@@ -63,6 +65,7 @@ typedef struct
        GsShellMode              mode;
        GsShellOverview         *shell_overview;
        GsShellInstalled        *shell_installed;
+       GsShellModerate         *shell_moderate;
        GsShellSearch           *shell_search;
        GsShellUpdates          *shell_updates;
        GsShellDetails          *shell_details;
@@ -189,6 +192,9 @@ gs_shell_change_mode (GsShell *shell,
        case GS_SHELL_MODE_INSTALLED:
                gs_shell_installed_switch_to (priv->shell_installed, scroll_up);
                break;
+       case GS_SHELL_MODE_MODERATE:
+               gs_shell_moderate_switch_to (priv->shell_moderate, scroll_up);
+               break;
        case GS_SHELL_MODE_SEARCH:
                widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
                text = gtk_entry_get_text (GTK_ENTRY (widget));
@@ -647,6 +653,12 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
                                  priv->plugin_loader,
                                  priv->builder,
                                  priv->cancellable);
+       priv->shell_moderate = GS_SHELL_MODERATE (gtk_builder_get_object (priv->builder, "shell_moderate"));
+       gs_shell_moderate_setup (priv->shell_moderate,
+                                shell,
+                                priv->plugin_loader,
+                                priv->builder,
+                                priv->cancellable);
        priv->shell_search = GS_SHELL_SEARCH (gtk_builder_get_object (priv->builder, "shell_search"));
        gs_shell_search_setup (priv->shell_search,
                               shell,
diff --git a/src/gs-shell.h b/src/gs-shell.h
index 7f64277..ab41856 100644
--- a/src/gs-shell.h
+++ b/src/gs-shell.h
@@ -50,6 +50,7 @@ typedef enum {
        GS_SHELL_MODE_DETAILS,
        GS_SHELL_MODE_CATEGORY,
        GS_SHELL_MODE_EXTRAS,
+       GS_SHELL_MODE_MODERATE,
        GS_SHELL_MODE_LAST
 } GsShellMode;
 
diff --git a/src/plugins/gs-plugin-xdg-app-reviews.c b/src/plugins/gs-plugin-xdg-app-reviews.c
index 8ab9a5c..933cfda 100644
--- a/src/plugins/gs-plugin-xdg-app-reviews.c
+++ b/src/plugins/gs-plugin-xdg-app-reviews.c
@@ -985,3 +985,36 @@ gs_plugin_review_remove (GsPlugin *plugin,
        uri = g_strdup_printf ("%s/remove", plugin->priv->review_server);
        return gs_plugin_xdg_app_reviews_vote (plugin, review, uri, error);
 }
+
+/**
+ * gs_plugin_add_unvoted_reviews:
+ */
+gboolean
+gs_plugin_add_unvoted_reviews (GsPlugin *plugin,
+                              GList **list,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       g_autoptr(GsReview) review = NULL;
+       g_autoptr(GDateTime) dt = NULL;
+
+       g_autoptr(GsApp) app = gs_app_new ("org.gnome.Software.desktop");
+       gs_app_set_name (app, GS_APP_QUALITY_NORMAL, "Power Manager");
+       gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, "Power Management Program");
+       gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+       gs_app_set_kind (app, GS_APP_KIND_NORMAL);
+
+       /* set first review */
+       review = gs_review_new ();
+       gs_review_set_rating (review, 50);
+       gs_review_set_reviewer (review, "Angela Avery");
+       gs_review_set_summary (review, "Steep learning curve, but worth it");
+       gs_review_set_text (review, "Best overall 3D application I've ever used overall 3D application I've 
ever used. Best overall 3D application I've ever used overall 3D application I've ever used. Best overall 3D 
application I've ever used overall 3D application I've ever used. Best overall 3D application I've ever used 
overall 3D application I've ever used.");
+       gs_review_set_version (review, "3.16.4");
+       dt = g_date_time_new_now_utc ();
+       gs_review_set_date (review, dt);
+       gs_app_add_review (app, review);
+
+       gs_plugin_add_app (list, app);
+       return TRUE;
+}


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