[gnome-software] Add content rating UI for games
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Add content rating UI for games
- Date: Wed, 21 Sep 2016 18:56:15 +0000 (UTC)
commit 573d0fe6a5d2c13817388ea2d6b447a98855e83c
Author: Richard Hughes <richard hughsie com>
Date: Tue Sep 20 21:06:48 2016 +0100
Add content rating UI for games
src/gs-common.c | 151 +++++++++++++++++++++++------------------------
src/gs-common.h | 3 +-
src/gs-shell-details.c | 127 +++++++++++++++++++++++++++++++++++++++
src/gs-shell-details.ui | 93 +++++++++++++++++++++++++++++
src/gtk-style.css | 22 +++++++
5 files changed, 319 insertions(+), 77 deletions(-)
---
diff --git a/src/gs-common.c b/src/gs-common.c
index 04a57d5..5e67945 100644
--- a/src/gs-common.c
+++ b/src/gs-common.c
@@ -311,223 +311,222 @@ gs_image_set_from_pixbuf (GtkImage *image, const GdkPixbuf *pixbuf)
gs_image_set_from_pixbuf_with_scale (image, pixbuf, scale);
}
-/**
- * gs_utils_get_content_rating:
- *
- * Note: These are strings marked for translation for comment.
- * This functionality is not currently used.
- **/
const gchar *
-gs_utils_get_content_rating (void)
+gs_utils_content_rating_kv_to_str (const gchar *id, AsContentRatingValue value)
{
+ guint i;
struct {
const gchar *id;
AsContentRatingValue value;
const gchar *desc;
- } content_rating_oars[] = {
+ } tab[] = {
{ "violence-cartoon", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating violence-cartoon", "None") },
+ _("No cartoon violence") },
{ "violence-cartoon", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Cartoon characters in unsafe situations") },
{ "violence-cartoon", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Cartoon characters in aggressive conflict") },
{ "violence-cartoon", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Graphic violence involving cartoon characters") },
{ "violence-fantasy", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating violence-fantasy", "None") },
+ _("No fantasy violence") },
{ "violence-fantasy", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Characters in unsafe situations easily distinguishable from reality") },
{ "violence-fantasy", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Characters in aggressive conflict easily distinguishable from reality") },
{ "violence-fantasy", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Graphic violence easily distinguishable from reality") },
{ "violence-realistic", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating violence-realistic", "None") },
+ _("No realistic violence") },
{ "violence-realistic", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Mildly realistic characters in unsafe situations") },
{ "violence-realistic", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Depictions of realistic characters in aggressive conflict") },
{ "violence-realistic", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Graphic violence involving realistic characters") },
{ "violence-bloodshed", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating violence-bloodshed", "None") },
+ _("No bloodshed") },
{ "violence-bloodshed", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Unrealistic bloodshed") },
{ "violence-bloodshed", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Realistic bloodshed") },
{ "violence-bloodshed", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Depictions of bloodshed and the mutilation of body parts") },
{ "violence-sexual", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating violence-sexual", "None") },
+ _("No sexual violence") },
{ "violence-sexual", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Rape or other violent sexual behavior") },
{ "drugs-alcohol", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating drugs-alcohol", "None") },
+ _("No references to alcohol") },
{ "drugs-alcohol", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("References to alcoholic beverages") },
{ "drugs-alcohol", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Use of alcoholic beverages") },
{ "drugs-narcotics", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating drugs-narcotics", "None") },
+ _("No references to illicit drugs") },
{ "drugs-narcotics", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("References to illicit drugs") },
{ "drugs-narcotics", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Use of illicit drugs") },
{ "drugs-tobacco", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("References to tobacco products") },
{ "drugs-tobacco", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Use of tobacco products") },
{ "sex-nudity", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating sex-nudity", "None") },
+ _("No nudity of any sort") },
{ "sex-nudity", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Brief artistic nudity") },
{ "sex-nudity", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Prolonged nudity") },
{ "sex-themes", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating sex-themes", "None") },
+ _("No references or depictions of sexual nature") },
{ "sex-themes", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Provocative references or depictions") },
{ "sex-themes", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Sexual references or depictions") },
{ "sex-themes", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Graphic sexual behavior") },
{ "language-profanity", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating language-profanity", "None") },
+ _("No profanity of any kind") },
{ "language-profanity", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Mild or infrequent use of profanity") },
{ "language-profanity", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Moderate use of profanity") },
{ "language-profanity", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Strong or frequent use of profanity") },
{ "language-humor", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating language-humor", "None") },
+ _("No innappropriate humor") },
{ "language-humor", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Slapstick humor") },
{ "language-humor", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Vulgar or bathroom humor") },
{ "language-humor", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Mature or sexual humor") },
{ "language-discrimination", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating language-discrimination", "None") },
+ _("No discriminatory language of any kind") },
{ "language-discrimination", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Negativity towards a specific group of people") },
{ "language-discrimination", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Discrimination designed to cause emotional harm") },
{ "language-discrimination", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Explicit discrimination based on gender, sexuality, race or religion") },
{ "money-advertising", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating money-advertising", "None") },
+ _("No advertising of any kind") },
{ "money-advertising", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Product placement") },
{ "money-advertising", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Explicit references to specific brands or trademarked products") },
{ "money-advertising", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Players are encouraged to purchase specific real-world items") },
{ "money-gambling", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating money-gambling", "None") },
+ _("No gambling of any kind") },
{ "money-gambling", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Gambling on random events using tokens or credits") },
{ "money-gambling", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Gambling using \"play\" money") },
{ "money-gambling", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Gambling using real money") },
{ "money-purchasing", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating money-purchasing", "None") },
+ _("No ability to spend money") },
{ "money-purchasing", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Ability to spend real money in-game") },
{ "social-chat", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating social-chat", "None") },
+ _("No way to chat with other players") },
{ "social-chat", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Player-to-player game interactions without chat functionality") },
{ "social-chat", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Player-to-player preset interactions without chat functionality") },
{ "social-chat", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Uncontrolled chat functionality between players") },
{ "social-audio", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating social-audio", "None") },
+ _("No way to talk with other players") },
{ "social-audio", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Uncontrolled audio or video chat functionality between players") },
{ "social-contacts", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating social-contacts", "None") },
+ _("No sharing of social network usernames or email addresses") },
{ "social-contacts", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Sharing social network usernames or email addresses") },
{ "social-info", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating social-info", "None") },
+ _("No sharing of user information with 3rd parties") },
{ "social-info", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Sharing user information with 3rd parties") },
{ "social-location", AS_CONTENT_RATING_VALUE_NONE,
/* TRANSLATORS: content rating description */
- C_("content rating social-location", "None") },
+ _("No sharing of physical location to other users") },
{ "social-location", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
+ /* TRANSLATORS: content rating description */
_("Sharing physical location to other users") },
{ NULL, 0, NULL } };
- return content_rating_oars[0].desc;
+ for (i = 0; tab[i].id != NULL; i++) {
+ if (g_strcmp0 (tab[i].id, id) == 0 && tab[i].value == value)
+ return tab[i].desc;
+ }
+ return NULL;
}
gboolean
diff --git a/src/gs-common.h b/src/gs-common.h
index e7e464d..631b9c9 100644
--- a/src/gs-common.h
+++ b/src/gs-common.h
@@ -48,7 +48,8 @@ void gs_image_set_from_pixbuf_with_scale (GtkImage *image,
void gs_image_set_from_pixbuf (GtkImage *image,
const GdkPixbuf *pixbuf);
-const gchar *gs_utils_get_content_rating (void);
+const gchar *gs_utils_content_rating_kv_to_str (const gchar *id,
+ AsContentRatingValue value);
const gchar *gs_user_agent (void);
gboolean gs_utils_is_current_desktop (const gchar *name);
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index ffb9d98..ed4f3e0 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -134,6 +134,12 @@ struct _GsShellDetails
GtkWidget *popover_license_free;
GtkWidget *popover_license_nonfree;
GtkWidget *popover_license_unknown;
+ GtkWidget *popover_content_rating;
+ GtkWidget *label_content_rating_title;
+ GtkWidget *label_content_rating_message;
+ GtkWidget *label_content_rating_none;
+ GtkWidget *button_details_rating_value;
+ GtkWidget *label_details_rating_title;
};
G_DEFINE_TYPE (GsShellDetails, gs_shell_details, GS_TYPE_PAGE)
@@ -1304,6 +1310,44 @@ gs_shell_details_app_refine2 (GsShellDetails *self)
}
static void
+gs_shell_details_content_rating_set_css (GtkWidget *widget, guint age)
+{
+ GtkStyleContext *ctx = gtk_widget_get_style_context (widget);
+ gtk_style_context_remove_class (ctx, "content-rating-adult");
+ gtk_style_context_remove_class (ctx, "content-rating-parental-guidance");
+ if (age >= 18) {
+ gtk_style_context_add_class (ctx, "content-rating-adult");
+ return;
+ }
+ if (age >= 5) {
+ gtk_style_context_add_class (ctx, "content-parental-guidance");
+ return;
+ }
+}
+
+static void
+gs_shell_details_refresh_content_rating (GsShellDetails *self)
+{
+ AsContentRating *content_rating;
+ guint age = 0;
+
+ /* only show the button if a game and has a content rating */
+ content_rating = gs_app_get_content_rating (self->app);
+ if (content_rating != NULL)
+ age = as_content_rating_get_minimum_age (content_rating);
+ if (age > 3) {
+ g_autofree gchar *tmp = g_strdup_printf ("%u+", age);
+ gtk_button_set_label (GTK_BUTTON (self->button_details_rating_value), tmp);
+ gtk_widget_set_visible (self->button_details_rating_value, TRUE);
+ gtk_widget_set_visible (self->label_details_rating_title, TRUE);
+ gs_shell_details_content_rating_set_css (self->button_details_rating_value, age);
+ } else {
+ gtk_widget_set_visible (self->button_details_rating_value, FALSE);
+ gtk_widget_set_visible (self->label_details_rating_title, FALSE);
+ }
+}
+
+static void
gs_shell_details_app_refine_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
@@ -1341,6 +1385,7 @@ gs_shell_details_app_refine_cb (GObject *source,
gs_shell_details_refresh_addons (self);
gs_shell_details_refresh_reviews (self);
gs_shell_details_refresh_all (self);
+ gs_shell_details_refresh_content_rating (self);
gs_shell_details_set_state (self, GS_SHELL_DETAILS_STATE_READY);
/* do 2nd stage refine */
@@ -1720,6 +1765,79 @@ gs_shell_details_more_reviews_button_cb (GtkWidget *widget, GsShellDetails *self
gtk_widget_set_visible (self->button_more_reviews, FALSE);
}
+static void
+gs_shell_details_content_rating_button_cb (GtkWidget *widget, GsShellDetails *self)
+{
+ AsContentRating *cr;
+ AsContentRatingValue value_bad = AS_CONTENT_RATING_VALUE_NONE;
+ const gchar *tmp;
+ guint i, j;
+ g_autoptr(GString) str = g_string_new (NULL);
+ struct {
+ const gchar *ids[5]; /* ordered inside from worst to best */
+ } id_map[] = {
+ { "violence-bloodshed",
+ "violence-realistic",
+ "violence-fantasy",
+ "violence-cartoon", NULL },
+ { "violence-sexual", NULL },
+ { "drugs-alcohol", NULL },
+ { "drugs-narcotics", NULL },
+ { "sex-nudity", NULL },
+ { "sex-themes", NULL },
+ { "language-profanity", NULL },
+ { "language-humor", NULL },
+ { "language-discrimination", NULL },
+ { "money-advertising", NULL },
+ { "money-gambling", NULL },
+ { "money-purchasing", NULL },
+ { "social-audio",
+ "social-chat",
+ "social-contacts",
+ "social-info", NULL },
+ { "social-location", NULL },
+ { NULL }
+ };
+
+ /* get the worst thing */
+ cr = gs_app_get_content_rating (self->app);
+ if (cr == NULL)
+ return;
+ for (j = 0; id_map[j].ids[0] != NULL; j++) {
+ for (i = 0; id_map[j].ids[i] != NULL; i++) {
+ AsContentRatingValue value;
+ value = as_content_rating_get_value (cr, id_map[j].ids[i]);
+ if (value > value_bad)
+ value_bad = value;
+ }
+ }
+
+ /* get the content rating description for the worst things about the app */
+ for (j = 0; id_map[j].ids[0] != NULL; j++) {
+ for (i = 0; id_map[j].ids[i] != NULL; i++) {
+ AsContentRatingValue value;
+ value = as_content_rating_get_value (cr, id_map[j].ids[i]);
+ if (value < value_bad)
+ continue;
+ tmp = gs_utils_content_rating_kv_to_str (id_map[j].ids[i], value);
+ g_string_append_printf (str, "• %s\n", tmp);
+ break;
+ }
+ }
+ if (str->len > 0)
+ g_string_truncate (str, str->len - 1);
+
+ /* enable the details if there are any */
+ gtk_label_set_label (GTK_LABEL (self->label_content_rating_message), str->str);
+ gtk_widget_set_visible (self->label_content_rating_title, str->len > 0);
+ gtk_widget_set_visible (self->label_content_rating_message, str->len > 0);
+ gtk_widget_set_visible (self->label_content_rating_none, str->len == 0);
+
+ /* show popover */
+ gtk_popover_set_relative_to (GTK_POPOVER (self->popover_content_rating), widget);
+ gtk_widget_show (self->popover_content_rating);
+}
+
static gboolean
gs_shell_details_activate_link_cb (GtkLabel *label,
const gchar *uri,
@@ -1890,6 +2008,9 @@ gs_shell_details_setup (GsShellDetails *self,
g_signal_connect (self->button_more_reviews, "clicked",
G_CALLBACK (gs_shell_details_more_reviews_button_cb),
self);
+ g_signal_connect (self->button_details_rating_value, "clicked",
+ G_CALLBACK (gs_shell_details_content_rating_button_cb),
+ self);
g_signal_connect (self->label_details_updated_value, "activate-link",
G_CALLBACK (gs_shell_details_history_cb),
self);
@@ -2033,6 +2154,12 @@ gs_shell_details_class_init (GsShellDetailsClass *klass)
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, popover_license_unknown);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_license_nonfree_details);
gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_licenses_intro);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, popover_content_rating);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_content_rating_title);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_content_rating_message);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_content_rating_none);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, button_details_rating_value);
+ gtk_widget_class_bind_template_child (widget_class, GsShellDetails, label_details_rating_title);
}
static void
diff --git a/src/gs-shell-details.ui b/src/gs-shell-details.ui
index b6f03d2..3b25610 100644
--- a/src/gs-shell-details.ui
+++ b/src/gs-shell-details.ui
@@ -145,6 +145,7 @@
<property name="position">1</property>
</packing>
</child>
+
<child>
<object class="GtkBox" id="star_box">
<property name="visible">True</property>
@@ -184,6 +185,7 @@
<property name="position">2</property>
</packing>
</child>
+
</object>
<packing>
<property name="expand">False</property>
@@ -798,6 +800,45 @@
<property name="top_attach">0</property>
</packing>
</child>
+
+ <child>
+ <object class="GtkLabel" id="label_details_rating_title">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Age Rating</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="vexpand">True</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_details_rating_value">
+ <property name="use_underline">True</property>
+ <property name="label">18</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="vexpand">False</property>
+ <property name="halign">start</property>
+ <style>
+ <class name="content-rating"/>
+ </style>
+ <accessibility>
+ <relation type="labelled-by" target="label_details_version_title"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">8</property>
+ </packing>
+ </child>
+
<child>
<object class="GtkLabel" id="label_details_updated_title">
<property name="visible">True</property>
@@ -1503,4 +1544,56 @@
</object>
</child>
</object>
+
+ <object class="GtkPopover" id="popover_content_rating">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox" id="box_content_rating">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">24</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label_content_rating_title">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">The application was rated this way because it
features:</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_content_rating_message">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label">• Use of alcoholic beverages</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_content_rating_none">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">No details were available for this rating.</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+
</interface>
diff --git a/src/gtk-style.css b/src/gtk-style.css
index 143e45b..45f2ebc 100644
--- a/src/gtk-style.css
+++ b/src/gtk-style.css
@@ -66,6 +66,28 @@
color: #ffffff;
}
+.content-rating {
+ outline-offset: 0;
+ background-image: none;
+ background-color: #dbdbdb;
+ border-image: none;
+ border-radius: 4px;
+ border-width: 0px;
+ padding: 1px 9px;
+ box-shadow: none;
+ text-shadow: none;
+}
+
+.content-rating-adult {
+ color: #ffffff;
+ background-color: #ee2222;
+}
+
+.content-rating-parental-guidance {
+ color: #ffffff;
+ background-color: #4e9a06;
+}
+
.details-license-free,
.details-license-free label,
.details-license-free:backdrop label {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]