[gnome-software] Only allow the user to enter a review if it matches our style guide



commit 1217511e5601a5b4fd9d2d33bf6f00b3411691c6
Author: Richard Hughes <richard hughsie com>
Date:   Tue Feb 9 16:20:54 2016 +0000

    Only allow the user to enter a review if it matches our style guide
    
    We don't want one or two word reviews, we want thoughtful prose that's taken
    time to write.

 src/gs-review-dialog.c  |   89 +++++++++++++++++++++++++++++++++++++++++++++++
 src/gs-review-dialog.ui |    3 ++
 2 files changed, 92 insertions(+), 0 deletions(-)
---
diff --git a/src/gs-review-dialog.c b/src/gs-review-dialog.c
index a89dd1b..7712044 100644
--- a/src/gs-review-dialog.c
+++ b/src/gs-review-dialog.c
@@ -27,13 +27,21 @@
 #include "gs-review-dialog.h"
 #include "gs-star-widget.h"
 
+#define DESCRIPTION_LENGTH_MAX         3000    /* chars */
+#define DESCRIPTION_LENGTH_MIN         60      /* chars */
+#define SUMMARY_LENGTH_MAX             70      /* chars */
+#define SUMMARY_LENGTH_MIN             15      /* chars */
+#define WRITING_TIME_MIN               20      /* seconds */
+
 struct _GsReviewDialog
 {
        GtkDialog        parent_instance;
 
        GtkWidget       *star;
        GtkWidget       *summary_entry;
+       GtkWidget       *post_button;
        GtkWidget       *text_view;
+       guint            timer_id;
 };
 
 G_DEFINE_TYPE (GsReviewDialog, gs_review_dialog, GTK_TYPE_DIALOG)
@@ -69,22 +77,103 @@ gs_review_dialog_get_text (GsReviewDialog *dialog)
 }
 
 static void
+gs_review_dialog_changed_cb (GsReviewDialog *dialog)
+{
+       GtkTextBuffer *buffer;
+       gboolean all_okay = TRUE;
+       const gchar *msg = NULL;
+
+       /* require rating, summary and long review */
+       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->text_view));
+       if (dialog->timer_id != 0) {
+               /* display nothing */
+               all_okay = FALSE;
+       } else if (gs_star_widget_get_rating (GS_STAR_WIDGET (dialog->star)) == 0) {
+               /* TRANSLATORS: the review is not acceptable */
+               msg = _("Please choose a star rating");
+               all_okay = FALSE;
+       } else if (gtk_entry_get_text_length (GTK_ENTRY (dialog->summary_entry)) < SUMMARY_LENGTH_MIN) {
+               /* TRANSLATORS: the review is not acceptable */
+               msg = _("The summary is too short");
+               all_okay = FALSE;
+       } else if (gtk_entry_get_text_length (GTK_ENTRY (dialog->summary_entry)) > SUMMARY_LENGTH_MAX) {
+               /* TRANSLATORS: the review is not acceptable */
+               msg = _("The summary is too long");
+               all_okay = FALSE;
+       } else if (gtk_text_buffer_get_char_count (buffer) < DESCRIPTION_LENGTH_MIN) {
+               /* TRANSLATORS: the review is not acceptable */
+               msg = _("The description is too short");
+               all_okay = FALSE;
+       } else if (gtk_text_buffer_get_char_count (buffer) > DESCRIPTION_LENGTH_MAX) {
+               /* TRANSLATORS: the review is not acceptable */
+               msg = _("The description is too long");
+               all_okay = FALSE;
+       }
+
+       /* tell the user what's happening */
+       gtk_widget_set_tooltip_text (dialog->post_button, msg);
+
+       /* can the user submit this? */
+       gtk_widget_set_sensitive (dialog->post_button, all_okay);
+}
+
+static gboolean
+gs_review_dialog_timeout_cb (gpointer user_data)
+{
+       GsReviewDialog *dialog = GS_REVIEW_DIALOG (user_data);
+       dialog->timer_id = 0;
+       gs_review_dialog_changed_cb (dialog);
+       return FALSE;
+}
+
+static void
 gs_review_dialog_init (GsReviewDialog *dialog)
 {
+       GtkTextBuffer *buffer;
        gtk_widget_init_template (GTK_WIDGET (dialog));
        gs_star_widget_set_icon_size (GS_STAR_WIDGET (dialog->star), 32);
+
+       /* require the user to spend at least 30 seconds on writing a review */
+       dialog->timer_id = g_timeout_add_seconds (WRITING_TIME_MIN,
+                                                 gs_review_dialog_timeout_cb,
+                                                 dialog);
+
+       /* update UI */
+       g_signal_connect_swapped (dialog->star, "rating-changed",
+                                 G_CALLBACK (gs_review_dialog_changed_cb), dialog);
+       g_signal_connect_swapped (dialog->summary_entry, "notify::text",
+                                 G_CALLBACK (gs_review_dialog_changed_cb), dialog);
+       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->text_view));
+       g_signal_connect_swapped (buffer, "changed",
+                                 G_CALLBACK (gs_review_dialog_changed_cb), dialog);
+
+       gtk_widget_set_sensitive (dialog->post_button, FALSE);
+
+}
+
+static void
+gs_review_row_dispose (GObject *object)
+{
+       GsReviewDialog *dialog = GS_REVIEW_DIALOG (object);
+       if (dialog->timer_id > 0)
+               g_source_remove (dialog->timer_id);
+       G_OBJECT_CLASS (gs_review_dialog_parent_class)->dispose (object);
 }
 
 static void
 gs_review_dialog_class_init (GsReviewDialogClass *klass)
 {
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
+       object_class->dispose = gs_review_row_dispose;
+
        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);
+       gtk_widget_class_bind_template_child (widget_class, GsReviewDialog, post_button);
 }
 
 GtkWidget *
diff --git a/src/gs-review-dialog.ui b/src/gs-review-dialog.ui
index aa4b109..a9c2e18 100644
--- a/src/gs-review-dialog.ui
+++ b/src/gs-review-dialog.ui
@@ -37,6 +37,9 @@
             <property name="can_focus">True</property>
             <property name="receives_default">True</property>
             <property name="use_underline">True</property>
+            <style>
+              <class name="suggested-action"/>
+            </style>
           </object>
           <packing>
             <property name="pack-type">end</property>


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