diff options
Diffstat (limited to 'src/gs-review-dialog.c')
-rw-r--r-- | src/gs-review-dialog.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/src/gs-review-dialog.c b/src/gs-review-dialog.c new file mode 100644 index 0000000..686209e --- /dev/null +++ b/src/gs-review-dialog.c @@ -0,0 +1,231 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * vi:set noexpandtab tabstop=8 shiftwidth=8: + * + * Copyright (C) 2016 Canonical Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "config.h" + +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#ifdef HAVE_GSPELL +#include <gspell/gspell.h> +#endif + +#include "gs-review-dialog.h" +#include "gs-star-widget.h" + +#define DESCRIPTION_LENGTH_MAX 3000 /* chars */ +#define DESCRIPTION_LENGTH_MIN 15 /* chars */ +#define SUMMARY_LENGTH_MAX 70 /* chars */ +#define SUMMARY_LENGTH_MIN 3 /* chars */ +#define WRITING_TIME_MIN 5 /* seconds */ + +struct _GsReviewDialog +{ + GtkDialog parent_instance; + + GtkWidget *star; + GtkWidget *label_rating_desc; + GtkWidget *summary_entry; + GtkWidget *post_button; + GtkWidget *text_view; + guint timer_id; +}; + +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_update_review_comment (GsReviewDialog *dialog) +{ + const gchar *msg = NULL; + gint perc; + + /* update the rating description */ + perc = gs_star_widget_get_rating (GS_STAR_WIDGET (dialog->star)); + if (perc == 20) { + /* TRANSLATORS: lighthearted star rating description; + * A really bad application */ + msg = _("Hate it"); + } else if (perc == 40) { + /* TRANSLATORS: lighthearted star rating description; + * Not a great application */ + msg = _("Don’t like it"); + } else if (perc == 60) { + /* TRANSLATORS: lighthearted star rating description; + * A fairly-good application */ + msg = _("It’s OK"); + } else if (perc == 80) { + /* TRANSLATORS: lighthearted star rating description; + * A good application */ + msg = _("Like it"); + } else if (perc == 100) { + /* TRANSLATORS: lighthearted star rating description; + * A really awesome application */ + msg = _("Love it"); + } else { + /* just reserve space */ + msg = ""; + } + gtk_label_set_label (GTK_LABEL (dialog->label_rating_desc), msg); +} + +static void +gs_review_dialog_changed_cb (GsReviewDialog *dialog) +{ + GtkTextBuffer *buffer; + gboolean all_okay = TRUE; + const gchar *msg = NULL; + + /* update review text */ + gs_review_dialog_update_review_comment (dialog); + + /* require rating, summary and long review */ + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dialog->text_view)); + if (dialog->timer_id != 0) { + /* TRANSLATORS: the review can't just be copied and pasted */ + msg = _("Please take more time writing the review"); + 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_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, 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)); + +#ifdef HAVE_GSPELL + /* allow checking spelling */ + { + GspellEntry *gspell_entry; + GspellTextView *gspell_view; + + gspell_entry = gspell_entry_get_from_gtk_entry (GTK_ENTRY (dialog->summary_entry)); + gspell_entry_basic_setup (gspell_entry); + + gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (dialog->text_view)); + gspell_text_view_basic_setup (gspell_view); + } +#endif + + /* 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_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, 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); + dialog->timer_id = 0; + } + 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, label_rating_desc); + 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 * +gs_review_dialog_new (void) +{ + return GTK_WIDGET (g_object_new (GS_TYPE_REVIEW_DIALOG, + "use-header-bar", TRUE, + NULL)); +} |