/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * vi:set noexpandtab tabstop=8 shiftwidth=8: * * Copyright (C) 2021 Endless OS Foundation LLC * * Author: Philip Withnall * * SPDX-License-Identifier: GPL-2.0+ */ /** * SECTION:gs-app-translation-dialog * @short_description: A dialog showing translation information about an app * * #GsAppTranslationDialog is a dialog which shows a message about the * translation status of an app, and provides information and a link for how * to contribute more translations to the app. * * It is intended to be shown if the app is not sufficiently translated to the * current locale. * * The widget has no special appearance if the app is unset, so callers will * typically want to hide the dialog in that case. * * Since: 41 */ #include "config.h" #include #include #include #include #include #include #include "gs-app.h" #include "gs-app-translation-dialog.h" #include "gs-common.h" struct _GsAppTranslationDialog { GsInfoWindow parent_instance; GsApp *app; /* (not nullable) (owned) */ gulong app_notify_name_handler; GtkLabel *title; GtkLabel *description; }; G_DEFINE_TYPE (GsAppTranslationDialog, gs_app_translation_dialog, GS_TYPE_INFO_WINDOW) typedef enum { PROP_APP = 1, } GsAppTranslationDialogProperty; static GParamSpec *obj_props[PROP_APP + 1] = { NULL, }; static void update_labels (GsAppTranslationDialog *self) { g_autofree gchar *title = NULL; g_autofree gchar *description = NULL; /* Translators: The placeholder is an application name */ title = g_strdup_printf (_("Help Translate %s"), gs_app_get_name (self->app)); /* Translators: The placeholder is an application name */ description = g_strdup_printf (_("%s is designed, developed, and translated by an " "international community of volunteers." "\n\n" "This means that while it’s not yet available in " "your language, you can get involved and help " "translate it yourself."), gs_app_get_name (self->app)); gtk_label_set_text (self->title, title); gtk_label_set_text (self->description, description); } static void app_notify_cb (GObject *obj, GParamSpec *pspec, gpointer user_data) { GsAppTranslationDialog *self = GS_APP_TRANSLATION_DIALOG (user_data); update_labels (self); } static const gchar * get_url_for_app (GsApp *app) { const gchar *url; /* Try the translate URL, or a fallback */ url = gs_app_get_url (app, AS_URL_KIND_TRANSLATE); #if AS_CHECK_VERSION(0, 15, 3) if (url == NULL) url = gs_app_get_url (app, AS_URL_KIND_CONTRIBUTE); #endif if (url == NULL) url = gs_app_get_url (app, AS_URL_KIND_BUGTRACKER); return url; } static void button_clicked_cb (GtkButton *button, gpointer user_data) { GsAppTranslationDialog *self = GS_APP_TRANSLATION_DIALOG (user_data); const gchar *url = get_url_for_app (self->app); gtk_show_uri (GTK_WINDOW (self), url, GDK_CURRENT_TIME); } static void gs_app_translation_dialog_init (GsAppTranslationDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } static void gs_app_translation_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GsAppTranslationDialog *self = GS_APP_TRANSLATION_DIALOG (object); switch ((GsAppTranslationDialogProperty) prop_id) { case PROP_APP: g_value_set_object (value, gs_app_translation_dialog_get_app (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gs_app_translation_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GsAppTranslationDialog *self = GS_APP_TRANSLATION_DIALOG (object); switch ((GsAppTranslationDialogProperty) prop_id) { case PROP_APP: /* Construct only */ g_assert (self->app == NULL); g_assert (self->app_notify_name_handler == 0); self->app = g_value_dup_object (value); self->app_notify_name_handler = g_signal_connect (self->app, "notify::name", G_CALLBACK (app_notify_cb), self); /* Update the UI. */ update_labels (self); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_APP]); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gs_app_translation_dialog_dispose (GObject *object) { GsAppTranslationDialog *self = GS_APP_TRANSLATION_DIALOG (object); g_clear_signal_handler (&self->app_notify_name_handler, self->app); g_clear_object (&self->app); G_OBJECT_CLASS (gs_app_translation_dialog_parent_class)->dispose (object); } static void gs_app_translation_dialog_class_init (GsAppTranslationDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->get_property = gs_app_translation_dialog_get_property; object_class->set_property = gs_app_translation_dialog_set_property; object_class->dispose = gs_app_translation_dialog_dispose; /** * GsAppTranslationDialog:app: (not nullable) * * The app to display the translation details for. * * This must not be %NULL. * * Since: 41 */ obj_props[PROP_APP] = g_param_spec_object ("app", NULL, NULL, GS_TYPE_APP, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_props), obj_props); gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-app-translation-dialog.ui"); gtk_widget_class_bind_template_child (widget_class, GsAppTranslationDialog, title); gtk_widget_class_bind_template_child (widget_class, GsAppTranslationDialog, description); gtk_widget_class_bind_template_callback (widget_class, button_clicked_cb); } /** * gs_app_translation_dialog_new: * @app: (not nullable): the app to display translation information for * * Create a new #GsAppTranslationDialog and set its initial app to @app. * * Returns: (transfer full): a new #GsAppTranslationDialog * Since: 41 */ GsAppTranslationDialog * gs_app_translation_dialog_new (GsApp *app) { g_return_val_if_fail (GS_IS_APP (app), NULL); return g_object_new (GS_TYPE_APP_TRANSLATION_DIALOG, "app", app, NULL); } /** * gs_app_translation_dialog_get_app: * @self: a #GsAppTranslationDialog * * Gets the value of #GsAppTranslationDialog:app. * * Returns: (not nullable) (transfer none): app whose translation information is * being displayed * Since: 41 */ GsApp * gs_app_translation_dialog_get_app (GsAppTranslationDialog *self) { g_return_val_if_fail (GS_IS_APP_TRANSLATION_DIALOG (self), NULL); return self->app; } /** * gs_app_translation_dialog_app_has_url: * @app: a #GsApp * * Check @app to see if it has appropriate URLs set on it to allow the user * to be linked to a page relevant to translating the app. * * Generally this should be used to work out whether to show a * #GsAppTranslationDialog dialog for a given @app. * * Returns: %TRUE if an URL exists, %FALSE otherwise * Since: 41 */ gboolean gs_app_translation_dialog_app_has_url (GsApp *app) { g_return_val_if_fail (GS_IS_APP (app), FALSE); return (get_url_for_app (app) != NULL); }