[gnome-software] Add the ability to add and show user-submitted application reviews
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Add the ability to add and show user-submitted application reviews
- Date: Tue, 9 Feb 2016 17:22:26 +0000 (UTC)
commit 5b304d259d24ad719f16b7d6d2a991f3cc4216a3
Author: Robert Ancell <robert ancell canonical com>
Date: Tue Feb 9 12:19:07 2016 +0000
Add the ability to add and show user-submitted application reviews
Signed-off-by: Richard Hughes <richard hughsie com>
po/POTFILES.in | 3 +
src/Makefile.am | 8 +
src/gnome-software.gresource.xml | 2 +
src/gs-review-bar.c | 107 +++++++++++++
src/gs-review-bar.h | 42 +++++
src/gs-review-dialog.c | 98 ++++++++++++
src/gs-review-dialog.h | 44 +++++
src/gs-review-dialog.ui | 246 +++++++++++++++++++++++++++++
src/gs-review-histogram.c | 129 +++++++++++++++
src/gs-review-histogram.h | 47 ++++++
src/gs-review-histogram.ui | 323 ++++++++++++++++++++++++++++++++++++++
src/gs-shell-details.c | 133 +++++++++++++++-
src/gs-shell-details.ui | 94 +++++++++++-
src/gtk-style-hc.css | 9 +
src/gtk-style.css | 19 +++
15 files changed, 1296 insertions(+), 8 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index aba0a13..fdf8ea3 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -22,7 +22,10 @@ src/gs-main.c
src/gs-page.c
src/gs-plugin-loader.c
src/gs-popular-tile.c
+src/gs-review-dialog.c
+[type: gettext/glade]src/gs-review-dialog.ui
src/gs-review-row.c
+[type: gettext/glade]src/gs-review-histogram.ui
[type: gettext/glade]src/gs-review-row.ui
src/gs-screenshot-image.c
src/gs-shell.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 74c3130..519143b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,6 +37,8 @@ UI_FILES = \
gs-app-row.ui \
gs-first-run-dialog.ui \
gs-history-dialog.ui \
+ gs-review-dialog.ui \
+ gs-review-histogram.ui \
gs-review-row.ui \
gs-shell-category.ui \
gs-shell-extras.ui \
@@ -143,6 +145,12 @@ gnome_software_SOURCES = \
gs-progress-button.h \
gs-review.c \
gs-review.h \
+ gs-review-bar.c \
+ gs-review-bar.h \
+ gs-review-dialog.c \
+ gs-review-dialog.h \
+ gs-review-histogram.c \
+ gs-review-histogram.h \
gs-review-row.c \
gs-review-row.h \
gs-screenshot-image.c \
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 746492d..261562f 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -13,6 +13,8 @@
<file preprocess="xml-stripblanks">gs-app-row.ui</file>
<file preprocess="xml-stripblanks">gs-first-run-dialog.ui</file>
<file preprocess="xml-stripblanks">gs-history-dialog.ui</file>
+ <file preprocess="xml-stripblanks">gs-review-dialog.ui</file>
+ <file preprocess="xml-stripblanks">gs-review-histogram.ui</file>
<file preprocess="xml-stripblanks">gs-review-row.ui</file>
<file preprocess="xml-stripblanks">gs-shell-category.ui</file>
<file preprocess="xml-stripblanks">gs-shell-extras.ui</file>
diff --git a/src/gs-review-bar.c b/src/gs-review-bar.c
new file mode 100644
index 0000000..b556789
--- /dev/null
+++ b/src/gs-review-bar.c
@@ -0,0 +1,107 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * 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 <math.h>
+
+#include "gs-review-bar.h"
+
+struct _GsReviewBar
+{
+ GtkBin parent_instance;
+ gdouble fraction;
+};
+
+G_DEFINE_TYPE (GsReviewBar, gs_review_bar, GTK_TYPE_BIN)
+
+/**
+ * gs_review_bar_set_fraction:
+ **/
+void
+gs_review_bar_set_fraction (GsReviewBar *bar, gdouble fraction)
+{
+ g_return_if_fail (GS_IS_REVIEW_BAR (bar));
+ bar->fraction = fraction;
+}
+
+/**
+ * gs_review_bar_init:
+ **/
+static void
+gs_review_bar_init (GsReviewBar *bar)
+{
+}
+
+/**
+ * gs_review_bar_draw:
+ **/
+static gboolean
+gs_review_bar_draw (GtkWidget *widget, cairo_t *cr)
+{
+ GtkStyleContext *context;
+ gdouble y_offset, bar_height;
+ GdkRGBA color;
+
+ context = gtk_widget_get_style_context (widget);
+
+ /* don't fill the complete height (too heavy beside GtkLabel of that height) */
+ y_offset = floor (0.15 * gtk_widget_get_allocated_height (widget));
+ bar_height = gtk_widget_get_allocated_height (widget) - (y_offset * 2);
+
+ gtk_render_background (context, cr,
+ 0, y_offset,
+ gtk_widget_get_allocated_width (widget),
+ bar_height);
+
+ cairo_rectangle (cr,
+ 0, y_offset,
+ round (GS_REVIEW_BAR (widget)->fraction * gtk_widget_get_allocated_width (widget)),
+ bar_height);
+ gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget), &color);
+ cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha);
+ cairo_fill (cr);
+
+ return GTK_WIDGET_CLASS (gs_review_bar_parent_class)->draw (widget, cr);
+}
+
+/**
+ * gs_review_bar_class_init:
+ **/
+static void
+gs_review_bar_class_init (GsReviewBarClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ widget_class->draw = gs_review_bar_draw;
+}
+
+/**
+ * gs_review_bar_new:
+ **/
+GtkWidget *
+gs_review_bar_new (void)
+{
+ GsReviewBar *bar;
+ bar = g_object_new (GS_TYPE_REVIEW_BAR, NULL);
+ return GTK_WIDGET (bar);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-review-bar.h b/src/gs-review-bar.h
new file mode 100644
index 0000000..4510dc8
--- /dev/null
+++ b/src/gs-review-bar.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * 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_REVIEW_BAR_H
+#define GS_REVIEW_BAR_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_REVIEW_BAR (gs_review_bar_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsReviewBar, gs_review_bar, GS, REVIEW_BAR, GtkBin)
+
+GtkWidget *gs_review_bar_new (void);
+
+void gs_review_bar_set_fraction (GsReviewBar *bar,
+ gdouble fraction);
+
+G_END_DECLS
+
+#endif /* GS_REVIEW_BAR_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-review-dialog.c b/src/gs-review-dialog.c
new file mode 100644
index 0000000..a89dd1b
--- /dev/null
+++ b/src/gs-review-dialog.c
@@ -0,0 +1,98 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * 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 <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gs-review-dialog.h"
+#include "gs-star-widget.h"
+
+struct _GsReviewDialog
+{
+ GtkDialog parent_instance;
+
+ GtkWidget *star;
+ GtkWidget *summary_entry;
+ GtkWidget *text_view;
+};
+
+G_DEFINE_TYPE (GsReviewDialog, gs_review_dialog, GTK_TYPE_DIALOG)
+
+gint
+gs_review_dialog_get_rating (GsReviewDialog *dialog)
+{
+ return gs_star_widget_get_rating (GS_STAR_WIDGET (dialog->star));
+}
+
+void
+gs_review_dialog_set_rating (GsReviewDialog *dialog, gint rating)
+{
+ gs_star_widget_set_rating (GS_STAR_WIDGET (dialog->star), rating);
+}
+
+const gchar *
+gs_review_dialog_get_summary (GsReviewDialog *dialog)
+{
+ return gtk_entry_get_text (GTK_ENTRY (dialog->summary_entry));
+}
+
+gchar *
+gs_review_dialog_get_text (GsReviewDialog *dialog)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->text_view));
+ gtk_text_buffer_get_start_iter (buffer, &start);
+ gtk_text_buffer_get_end_iter (buffer, &end);
+ return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+}
+
+static void
+gs_review_dialog_init (GsReviewDialog *dialog)
+{
+ gtk_widget_init_template (GTK_WIDGET (dialog));
+ gs_star_widget_set_icon_size (GS_STAR_WIDGET (dialog->star), 32);
+}
+
+static void
+gs_review_dialog_class_init (GsReviewDialogClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-review-dialog.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, GsReviewDialog, star);
+ gtk_widget_class_bind_template_child (widget_class, GsReviewDialog, summary_entry);
+ gtk_widget_class_bind_template_child (widget_class, GsReviewDialog, text_view);
+}
+
+GtkWidget *
+gs_review_dialog_new (void)
+{
+ return GTK_WIDGET (g_object_new (GS_TYPE_REVIEW_DIALOG,
+ "use-header-bar", TRUE,
+ NULL));
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-review-dialog.h b/src/gs-review-dialog.h
new file mode 100644
index 0000000..800d616
--- /dev/null
+++ b/src/gs-review-dialog.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * 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_REVIEW_DIALOG_H
+#define GS_REVIEW_DIALOG_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_REVIEW_DIALOG (gs_review_dialog_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsReviewDialog, gs_review_dialog, GS, REVIEW_DIALOG, GtkDialog)
+
+GtkWidget *gs_review_dialog_new (void);
+gint gs_review_dialog_get_rating (GsReviewDialog *dialog);
+void gs_review_dialog_set_rating (GsReviewDialog *dialog,
+ gint rating);
+const gchar *gs_review_dialog_get_summary (GsReviewDialog *dialog);
+gchar *gs_review_dialog_get_text (GsReviewDialog *dialog);
+
+G_END_DECLS
+
+#endif /* GS_REVIEW_DIALOG_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-review-dialog.ui b/src/gs-review-dialog.ui
new file mode 100644
index 0000000..aa4b109
--- /dev/null
+++ b/src/gs-review-dialog.ui
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+ <requires lib="gtk+" version="3.10"/>
+ <template class="GsReviewDialog" parent="GtkDialog">
+ <action-widgets>
+ <action-widget response="cancel">cancel_button</action-widget>
+ <action-widget response="ok">post_button</action-widget>
+ </action-widgets>
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">Post Review</property>
+ <property name="modal">True</property>
+ <property name="default_width">600</property>
+ <property name="default_height">300</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="use_header_bar">1</property>
+ <child internal-child="headerbar">
+ <object class="GtkHeaderBar">
+ <property name="show_close_button">False</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="post_button">
+ <property name="label" translatable="yes">_Post</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox">
+ <property name="can_focus">False</property>
+ <property name="margin_start">40</property>
+ <property name="margin_end">40</property>
+ <property name="margin_top">25</property>
+ <property name="margin_bottom">25</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">9</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">20</property>
+ <child>
+ <object class="GtkBox" id="box4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Rating</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GsStarWidget" id="star">
+ <property name="visible">True</property>
+ <property name="halign">center</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Summary</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Give a short summary of your review, for
example: “Great app, would recommend”.</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="summary_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Review</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">What do you think of the app? Try to give
reasons for your views.</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="text_view_scroll">
+ <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="shadow_type">in</property>
+ <child>
+ <object class="GtkTextView" id="text_view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="height-request">120</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/gs-review-histogram.c b/src/gs-review-histogram.c
new file mode 100644
index 0000000..340982f
--- /dev/null
+++ b/src/gs-review-histogram.c
@@ -0,0 +1,129 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * 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 <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gs-review-histogram.h"
+#include "gs-review-bar.h"
+
+typedef struct
+{
+ GtkWidget *bar1;
+ GtkWidget *bar2;
+ GtkWidget *bar3;
+ GtkWidget *bar4;
+ GtkWidget *bar5;
+ GtkWidget *label_count1;
+ GtkWidget *label_count2;
+ GtkWidget *label_count3;
+ GtkWidget *label_count4;
+ GtkWidget *label_count5;
+ GtkWidget *label_total;
+} GsReviewHistogramPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsReviewHistogram, gs_review_histogram, GTK_TYPE_BIN)
+
+static void
+set_label (GtkWidget *label, guint value)
+{
+ g_autofree gchar *text = NULL;
+ text = g_strdup_printf ("%u", value);
+ gtk_label_set_text (GTK_LABEL (label), text);
+}
+
+/**
+ * gs_review_histogram_set_ratings:
+ **/
+void
+gs_review_histogram_set_ratings (GsReviewHistogram *histogram,
+ GArray *review_ratings)
+{
+ GsReviewHistogramPrivate *priv;
+ gdouble max;
+ gint count[5];
+ guint i;
+
+ g_return_if_fail (GS_IS_REVIEW_HISTOGRAM (histogram));
+ priv = gs_review_histogram_get_instance_private (histogram);
+
+ /* Scale to maximum value */
+ for (i = 0; i < 5; i++)
+ count[i] = g_array_index (review_ratings, gint, i + 1);
+ max = count[0];
+ max = count[1] > max ? count[1] : max;
+ max = count[2] > max ? count[2] : max;
+ max = count[3] > max ? count[3] : max;
+ max = count[4] > max ? count[4] : max;
+
+ gs_review_bar_set_fraction (GS_REVIEW_BAR (priv->bar5), count[4] / max);
+ set_label (priv->label_count5, count[4]);
+ gs_review_bar_set_fraction (GS_REVIEW_BAR (priv->bar4), count[3] / max);
+ set_label (priv->label_count4, count[3]);
+ gs_review_bar_set_fraction (GS_REVIEW_BAR (priv->bar3), count[2] / max);
+ set_label (priv->label_count3, count[2]);
+ gs_review_bar_set_fraction (GS_REVIEW_BAR (priv->bar2), count[1] / max);
+ set_label (priv->label_count2, count[1]);
+ gs_review_bar_set_fraction (GS_REVIEW_BAR (priv->bar1), count[0] / max);
+ set_label (priv->label_count1, count[0]);
+ set_label (priv->label_total, count[0] + count[1] + count[2] + count[3] + count[4]);
+}
+
+static void
+gs_review_histogram_init (GsReviewHistogram *histogram)
+{
+ gtk_widget_init_template (GTK_WIDGET (histogram));
+}
+
+static void
+gs_review_histogram_class_init (GsReviewHistogramClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/Software/gs-review-histogram.ui");
+
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, bar5);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, bar4);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, bar3);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, bar2);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, bar1);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, label_count5);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, label_count4);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, label_count3);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, label_count2);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, label_count1);
+ gtk_widget_class_bind_template_child_private (widget_class, GsReviewHistogram, label_total);
+}
+
+/**
+ * gs_review_histogram_new:
+ **/
+GtkWidget *
+gs_review_histogram_new (void)
+{
+ GsReviewHistogram *histogram;
+ histogram = g_object_new (GS_TYPE_REVIEW_HISTOGRAM, NULL);
+ return GTK_WIDGET (histogram);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-review-histogram.h b/src/gs-review-histogram.h
new file mode 100644
index 0000000..ea12f40
--- /dev/null
+++ b/src/gs-review-histogram.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * 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_REVIEW_HISTOGRAM_H
+#define GS_REVIEW_HISTOGRAM_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_REVIEW_HISTOGRAM (gs_review_histogram_get_type ())
+
+G_DECLARE_DERIVABLE_TYPE (GsReviewHistogram, gs_review_histogram, GS, REVIEW_HISTOGRAM, GtkBin)
+
+struct _GsReviewHistogramClass
+{
+ GtkBinClass parent_class;
+};
+
+GtkWidget *gs_review_histogram_new (void);
+
+void gs_review_histogram_set_ratings (GsReviewHistogram *histogram,
+ GArray *review_ratings);
+
+G_END_DECLS
+
+#endif /* GS_REVIEW_HISTOGRAM_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-review-histogram.ui b/src/gs-review-histogram.ui
new file mode 100644
index 0000000..45d7523
--- /dev/null
+++ b/src/gs-review-histogram.ui
@@ -0,0 +1,323 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.10 -->
+ <template class="GsReviewHistogram" parent="GtkBin">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row-spacing">10</property>
+ <property name="column-spacing">5</property>
+ <child>
+ <object class="GtkImage" id="star5">
+ <property name="visible">True</property>
+ <property name="icon_name">starred-symbolic</property>
+ <style>
+ <class name="star"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="star_label5">
+ <property name="visible">True</property>
+ <property name="label">5</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GsReviewBar" id="bar5">
+ <property name="visible">True</property>
+ <property name="margin-left">25</property>
+ <property name="width-request">120</property>
+ <style>
+ <class name="reviewbar"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_count5">
+ <property name="visible">True</property>
+ <property name="label">0</property>
+ <property name="margin-left">5</property>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="star4">
+ <property name="visible">True</property>
+ <property name="icon_name">starred-symbolic</property>
+ <style>
+ <class name="star"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="star_label4">
+ <property name="visible">True</property>
+ <property name="label">4</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GsReviewBar" id="bar4">
+ <property name="visible">True</property>
+ <property name="margin-left">25</property>
+ <style>
+ <class name="reviewbar"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_count4">
+ <property name="visible">True</property>
+ <property name="label">0</property>
+ <property name="margin-left">5</property>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="star3">
+ <property name="visible">True</property>
+ <property name="icon_name">starred-symbolic</property>
+ <style>
+ <class name="star"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="star_label3">
+ <property name="visible">True</property>
+ <property name="label">3</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GsReviewBar" id="bar3">
+ <property name="visible">True</property>
+ <property name="margin-left">25</property>
+ <style>
+ <class name="reviewbar"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_count3">
+ <property name="visible">True</property>
+ <property name="label">0</property>
+ <property name="margin-left">5</property>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="star2">
+ <property name="visible">True</property>
+ <property name="icon_name">starred-symbolic</property>
+ <style>
+ <class name="star"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="star_label2">
+ <property name="visible">True</property>
+ <property name="label">2</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GsReviewBar" id="bar2">
+ <property name="visible">True</property>
+ <property name="margin-left">25</property>
+ <style>
+ <class name="reviewbar"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_count2">
+ <property name="visible">True</property>
+ <property name="label">0</property>
+ <property name="margin-left">5</property>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="star1">
+ <property name="visible">True</property>
+ <property name="icon_name">starred-symbolic</property>
+ <style>
+ <class name="star"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="star_label1">
+ <property name="visible">True</property>
+ <property name="label">1</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GsReviewBar" id="bar1">
+ <property name="visible">True</property>
+ <property name="margin-left">25</property>
+ <style>
+ <class name="reviewbar"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_count1">
+ <property name="visible">True</property>
+ <property name="label">0</property>
+ <property name="margin-left">5</property>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Total</property>
+ <property name="halign">start</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">5</property>
+ <property name="width">3</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_total">
+ <property name="visible">True</property>
+ <property name="label">0</property>
+ <property name="margin-left">5</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">5</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index c7316ca..aa931ba 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -34,6 +34,9 @@
#include "gs-screenshot-image.h"
#include "gs-progress-button.h"
#include "gs-star-widget.h"
+#include "gs-review-histogram.h"
+#include "gs-review-dialog.h"
+#include "gs-review-row.h"
typedef enum {
GS_SHELL_DETAILS_STATE_LOADING,
@@ -50,7 +53,6 @@ struct _GsShellDetails
GCancellable *cancellable;
GsApp *app;
GsShell *shell;
- GtkWidget *star;
SoupSession *session;
GtkWidget *application_details_icon;
@@ -59,7 +61,8 @@ struct _GsShellDetails
GtkWidget *box_addons;
GtkWidget *box_details;
GtkWidget *box_details_description;
- GtkWidget *box_details_header;
+ GtkWidget *star;
+ GtkWidget *label_review_count;
GtkWidget *box_details_screenshot;
GtkWidget *box_details_screenshot_main;
GtkWidget *box_details_screenshot_thumbnails;
@@ -89,6 +92,10 @@ struct _GsShellDetails
GtkWidget *label_details_tag_webapp;
GtkWidget *label_details_info_text;
GtkWidget *list_box_addons;
+ GtkWidget *box_reviews;
+ GtkWidget *histogram;
+ GtkWidget *button_review;
+ GtkWidget *list_box_reviews;
GtkWidget *scrolledwindow_details;
GtkWidget *spinner_details;
GtkWidget *spinner_install_remove;
@@ -572,6 +579,7 @@ static void
gs_shell_details_refresh_all (GsShellDetails *self)
{
GPtrArray *history;
+ GArray *review_ratings;
GdkPixbuf *pixbuf = NULL;
GList *addons;
GtkWidget *widget;
@@ -729,6 +737,22 @@ gs_shell_details_refresh_all (GsShellDetails *self)
} else {
gtk_widget_set_visible (self->star, FALSE);
}
+ review_ratings = gs_app_get_review_ratings (self->app);
+ if (review_ratings != NULL) {
+ gtk_widget_set_visible (self->histogram, TRUE);
+ gs_review_histogram_set_ratings (GS_REVIEW_HISTOGRAM (self->histogram),
+ review_ratings);
+ } else {
+ gtk_widget_set_visible (self->histogram, FALSE);
+ }
+ if (gs_app_get_reviews (self->app) != NULL) {
+ g_autofree gchar *text = NULL;
+ gtk_widget_set_visible (self->label_review_count, TRUE);
+ text = g_strdup_printf ("(%u)", gs_app_get_reviews (self->app)->len);
+ gtk_label_set_text (GTK_LABEL (self->label_review_count), text);
+ } else {
+ gtk_widget_set_visible (self->label_review_count, FALSE);
+ }
break;
}
@@ -947,6 +971,31 @@ gs_shell_details_refresh_addons (GsShellDetails *self)
}
}
+static void
+gs_shell_details_refresh_reviews (GsShellDetails *self)
+{
+ GPtrArray *reviews;
+ guint i;
+
+ if (!gs_plugin_loader_get_plugin_supported (self->plugin_loader,
+ "gs_plugin_review_submit"))
+ return;
+
+ gs_container_remove_all (GTK_CONTAINER (self->list_box_reviews));
+
+ /* add all the reviews */
+ reviews = gs_app_get_reviews (self->app);
+ for (i = 0; i < reviews->len; i++) {
+ GsReview *review = g_ptr_array_index (reviews, i);
+ GtkWidget *row = gs_review_row_new (review);
+ gtk_container_add (GTK_CONTAINER (self->list_box_reviews), row);
+ gtk_widget_show (row);
+ }
+
+ /* FIXME: show the button only if the user never reviewed */
+ gtk_widget_set_visible (self->button_review, TRUE);
+}
+
/**
* gs_shell_details_app_refine_cb:
**/
@@ -986,6 +1035,7 @@ gs_shell_details_app_refine_cb (GObject *source,
gs_shell_details_refresh_screenshots (self);
gs_shell_details_refresh_addons (self);
+ gs_shell_details_refresh_reviews (self);
gs_shell_details_refresh_all (self);
gs_shell_details_set_state (self, GS_SHELL_DETAILS_STATE_READY);
}
@@ -1056,6 +1106,7 @@ gs_shell_details_filename_to_app_cb (GObject *source,
gs_shell_details_switch_to (self);
gs_shell_details_refresh_screenshots (self);
gs_shell_details_refresh_addons (self);
+ gs_shell_details_refresh_reviews (self);
gs_shell_details_refresh_all (self);
gs_shell_details_set_state (self, GS_SHELL_DETAILS_STATE_READY);
}
@@ -1287,6 +1338,65 @@ gs_shell_details_app_set_ratings_cb (GObject *source,
}
}
+
+/**
+ * gs_shell_details_app_set_review_cb:
+ **/
+static void
+gs_shell_details_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: %s",
+ gs_app_get_id (self->app), error->message);
+ }
+}
+
+/**
+ * gs_shell_details_write_review_cb:
+ **/
+static void
+gs_shell_details_write_review_cb (GtkButton *button,
+ GsShellDetails *self)
+{
+ GtkWidget *dialog;
+ GtkResponseType response;
+
+ dialog = gs_review_dialog_new ();
+
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), gs_shell_get_window (self->shell));
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (response == GTK_RESPONSE_OK) {
+ g_autoptr(GsReview) review = NULL;
+ g_autoptr(GDateTime) now = NULL;
+ g_autofree gchar *text = NULL;
+
+ review = gs_review_new ();
+ gs_review_set_summary (review, gs_review_dialog_get_summary (GS_REVIEW_DIALOG (dialog)));
+ text = gs_review_dialog_get_text (GS_REVIEW_DIALOG (dialog));
+ gs_review_set_text (review, text);
+ gs_review_set_rating (review, gs_review_dialog_get_rating (GS_REVIEW_DIALOG (dialog)));
+ gs_review_set_version (review, gs_app_get_version (self->app));
+ now = g_date_time_new_now_local ();
+ gs_review_set_date (review, now);
+
+ /* call into the plugins to set the new value */
+ gs_plugin_loader_review_action_async (self->plugin_loader,
+ self->app,
+ review,
+ GS_PLUGIN_LOADER_ACTION_REVIEW_SUBMIT,
+ self->cancellable,
+ gs_shell_details_app_set_review_cb,
+ self);
+ }
+ gtk_widget_destroy (dialog);
+}
+
/**
* gs_shell_details_rating_changed_cb:
**/
@@ -1341,14 +1451,18 @@ gs_shell_details_setup (GsShellDetails *self,
self->builder = g_object_ref (builder);
self->cancellable = g_object_ref (cancellable);
+ /* Show review widgets if we have plugins that provide them */
+ if (gs_plugin_loader_get_plugin_supported (plugin_loader,
+ "gs_plugin_review_submit"))
+ gtk_widget_set_visible (self->box_reviews, TRUE);
+ g_signal_connect (self->button_review, "clicked",
+ G_CALLBACK (gs_shell_details_write_review_cb),
+ self);
+
/* set up star ratings */
- self->star = gs_star_widget_new ();
g_signal_connect (self->star, "rating-changed",
G_CALLBACK (gs_shell_details_rating_changed_cb),
self);
- gtk_widget_set_visible (self->star, TRUE);
- gtk_widget_set_valign (self->star, GTK_ALIGN_START);
- gtk_box_pack_start (GTK_BOX (self->box_details_header), self->star, FALSE, FALSE, 0);
/* setup details */
g_signal_connect (self->button_install, "clicked",
@@ -1420,7 +1534,8 @@ gs_shell_details_class_init (GsShellDetailsClass *klass)
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, box_addons);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, box_details);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, box_details_description);
- gtk_widget_class_bind_template_child (widget_class, GsShellDetails, box_details_header);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, star);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_review_count);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, box_details_screenshot);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, box_details_screenshot_main);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails,
box_details_screenshot_thumbnails);
@@ -1450,6 +1565,10 @@ gs_shell_details_class_init (GsShellDetailsClass *klass)
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_details_tag_webapp);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_details_info_text);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, list_box_addons);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, box_reviews);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, histogram);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, button_review);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, list_box_reviews);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, scrolledwindow_details);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, spinner_details);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, spinner_install_remove);
diff --git a/src/gs-shell-details.ui b/src/gs-shell-details.ui
index b67d6e8..97b7f67 100644
--- a/src/gs-shell-details.ui
+++ b/src/gs-shell-details.ui
@@ -227,6 +227,45 @@
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkBox" id="star_box">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <child>
+ <object class="GsStarWidget" id="star">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_review_count">
+ <property name="visible">True</property>
+ <property name="margin_start">5</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">False</property>
@@ -1124,7 +1163,60 @@
<property name="position">12</property>
</packing>
</child>
-
+ <child>
+ <object class="GtkBox" id="box_reviews">
+ <property name="orientation">vertical</property>
+ <property name="margin_top">28</property>
+ <child>
+ <object class="GtkLabel" id="application_details_reviews_title">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_bottom">20</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Reviews</property>
+ <style>
+ <class name="application-reviews-title"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GsReviewHistogram" id="histogram">
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="margin_bottom">20</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_review">
+ <property name="use_underline">True</property>
+ <property name="label" translatable="yes">_Write a Review</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="margin_bottom">20</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="list_box_reviews">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="selection_mode">none</property>
+ <style>
+ <class name="review-listbox"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">12</property>
+ </packing>
+ </child>
</object>
</child>
</object>
diff --git a/src/gtk-style-hc.css b/src/gtk-style-hc.css
index a44213e..974c9ad 100644
--- a/src/gtk-style-hc.css
+++ b/src/gtk-style-hc.css
@@ -100,6 +100,15 @@
.application-details-summary {
}
+.application-reviews-title {
+ font-weight: bold;
+ font-size: 14px;
+}
+
+.review-summary {
+ font-weight: bold;
+}
+
.application-details-description {
}
diff --git a/src/gtk-style.css b/src/gtk-style.css
index 78b5cfa..263e4ff 100644
--- a/src/gtk-style.css
+++ b/src/gtk-style.css
@@ -138,6 +138,25 @@
.install-progress:dir(rtl) { background-position: 100% bottom; }
+.application-reviews-title {
+ font-weight: bold;
+ font-size: 14px;
+}
+
+.review-summary {
+ font-weight: bold;
+}
+
+.review-listbox {
+ all: unset;
+}
+
+.reviewbar {
+ background-image: none;
+ background-color: #babdb6;
+ color: #555753;
+}
+
.error-label {
text-shadow: none;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]