[gnome-software] Convert the modal failure dialogs to in-app notifications
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Convert the modal failure dialogs to in-app notifications
- Date: Thu, 8 Sep 2016 20:56:20 +0000 (UTC)
commit 9cab99c1c7b5f5d850839f4e89b48beb2b6c9814
Author: Richard Hughes <richard hughsie com>
Date: Thu Sep 8 15:24:45 2016 +0100
Convert the modal failure dialogs to in-app notifications
Also, add more types of buttons to the in-app notifications.
src/gnome-software.ui | 79 ++++----
src/gs-common.c | 73 ------
src/gs-common.h | 4 -
src/gs-shell.c | 606 ++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 638 insertions(+), 124 deletions(-)
---
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index 8bd5d7d..7014390 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -280,19 +280,33 @@
<property name="visible">True</property>
<property name="halign">fill</property>
<property name="valign">fill</property>
-
<child type="overlay">
<object class="GdNotification" id="notification_event">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
-
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="spacing">24</property>
<property name="visible">True</property>
-
+ <child>
+ <object class="GtkLabel" id="label_events">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label">Some Title</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">word-char</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
<child>
<object class="GtkButtonBox">
<property name="can_focus">False</property>
@@ -307,65 +321,50 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">0</property>
</packing>
</child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <property name="border_width">12</property>
- <property name="visible">True</property>
<child>
- <object class="GtkLabel" id="label_events_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label">Some Title</property>
- <property name="wrap">True</property>
- <property name="wrap_mode">word-char</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
+ <object class="GtkButton" id="button_events_no_space">
+ <property name="label" translatable="yes" comments="button in the info
bar">Examine Disk</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
</object>
<packing>
- <property name="expand">False</property>
+ <property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label_events">
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label">Longer text that explains things some more.</property>
+ <object class="GtkButton" id="button_events_network_settings">
+ <property name="label" translatable="yes" comments="button in the info
bar">Network Settings</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_events_more_info">
+ <property name="label" translatable="yes" comments="button in the info bar">More
Information</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">0</property>
</packing>
</child>
</object>
-
</child>
</object>
-
</child>
<child>
diff --git a/src/gs-common.c b/src/gs-common.c
index 2d45ca3..3fbf8d3 100644
--- a/src/gs-common.c
+++ b/src/gs-common.c
@@ -147,79 +147,6 @@ gs_app_notify_installed (GsApp *app)
g_application_send_notification (g_application_get_default (), "installed", n);
}
-void
-gs_app_notify_failed_modal (GsApp *app,
- GtkWindow *parent_window,
- GsPluginAction action,
- const GError *error)
-{
- const gchar *title;
- gboolean show_detailed_error;
- g_autoptr(GString) msg = NULL;
-
- /* TRANSLATORS: install or removed failed */
- title = _("Sorry, this did not work");
-
- /* say what we tried to do */
- msg = g_string_new ("");
- switch (action) {
- case GS_PLUGIN_ACTION_INSTALL:
- /* TRANSLATORS: this is when the install fails */
- g_string_append_printf (msg, _("Installation of %s failed."),
- gs_app_get_name (app));
- break;
- case GS_PLUGIN_ACTION_REMOVE:
- /* TRANSLATORS: this is when the remove fails */
- g_string_append_printf (msg, _("Removal of %s failed."),
- gs_app_get_name (app));
- break;
- case GS_PLUGIN_ACTION_UPGRADE_DOWNLOAD:
- {
- g_autofree gchar *name_version = g_strdup_printf ("%s %s",
- gs_app_get_name (app),
- gs_app_get_version (app));
- /* TRANSLATORS: this is when the upgrade download fails */
- g_string_append_printf (msg, _("Upgrade to %s failed."), name_version);
- break;
- }
- default:
- break;
- }
- if (msg->len == 0)
- return;
- g_string_append (msg, " ");
-
- /* give details about the error */
- switch (error->code) {
- case GS_PLUGIN_ERROR_NO_NETWORK:
- /* TRANSLATORS: the package manager needed to download
- * something with no network available */
- g_string_append (msg, _("Internet access was required but wasn’t available."));
- g_string_append (msg, " ");
- /* TRANSLATORS: plug in the network cable... */
- g_string_append (msg, _("Please make sure that you have internet access and try again."));
- show_detailed_error = FALSE;
- break;
- case GS_PLUGIN_ERROR_NO_SPACE:
- /* TRANSLATORS: we ran out of disk space */
- g_string_append (msg, _("There wasn’t enough disk space."));
- g_string_append (msg, " ");
- /* TRANSLATORS: delete some stuff! */
- g_string_append (msg, _("Please free up some space and try again."));
- show_detailed_error = FALSE;
- break;
- default:
- /* TRANSLATORS: we didn't handle the error type */
- g_string_append (msg, _("If the problem persists, contact your software provider."));
- show_detailed_error = TRUE;
- }
-
- gs_utils_show_error_dialog (parent_window,
- title,
- msg->str,
- show_detailed_error ? error->message : NULL);
-}
-
typedef enum {
GS_APP_LICENSE_FREE = 0,
GS_APP_LICENSE_NONFREE = 1,
diff --git a/src/gs-common.h b/src/gs-common.h
index f31f0d9..5ce0771 100644
--- a/src/gs-common.h
+++ b/src/gs-common.h
@@ -36,10 +36,6 @@ void gs_container_remove_all (GtkContainer *container);
void gs_grab_focus_when_mapped (GtkWidget *widget);
void gs_app_notify_installed (GsApp *app);
-void gs_app_notify_failed_modal (GsApp *app,
- GtkWindow *parent_window,
- GsPluginAction action,
- const GError *error);
GtkResponseType
gs_app_notify_unavailable (GsApp *app,
GtkWindow *parent);
diff --git a/src/gs-shell.c b/src/gs-shell.c
index bf5e57a..e0ea391 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -85,6 +85,7 @@ typedef struct
GQueue *back_entry_stack;
GPtrArray *modal_dialogs;
gulong search_changed_id;
+ gchar *events_info_uri;
} GsShellPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (GsShell, gs_shell, G_TYPE_OBJECT)
@@ -421,6 +422,33 @@ gs_shell_plugin_events_sources_cb (GtkWidget *widget, GsShell *shell)
}
static void
+gs_shell_plugin_events_no_space_cb (GtkWidget *widget, GsShell *shell)
+{
+ g_autoptr(GError) error = NULL;
+ if (!g_spawn_command_line_async ("baobab", &error))
+ g_warning ("failed to exec baobab: %s", error->message);
+}
+
+static void
+gs_shell_plugin_events_network_settings_cb (GtkWidget *widget, GsShell *shell)
+{
+ g_autoptr(GError) error = NULL;
+ if (!g_spawn_command_line_async ("gnome-control-center network", &error))
+ g_warning ("failed to exec gnome-control-center: %s", error->message);
+}
+
+static void
+gs_shell_plugin_events_more_info_cb (GtkWidget *widget, GsShell *shell)
+{
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ g_autoptr(GError) error = NULL;
+ if (!g_app_info_launch_default_for_uri (priv->events_info_uri, NULL, &error)) {
+ g_warning ("failed to launch URI %s: %s",
+ priv->events_info_uri, error->message);
+ }
+}
+
+static void
gs_shell_back_button_cb (GtkWidget *widget, GsShell *shell)
{
GsShellPrivate *priv = gs_shell_get_instance_private (shell);
@@ -622,16 +650,570 @@ gs_shell_monitor_permission (GsShell *shell)
G_CALLBACK (on_permission_changed), shell);
}
+typedef enum {
+ GS_SHELL_EVENT_BUTTON_NONE = 0,
+ GS_SHELL_EVENT_BUTTON_SOURCES = 1 << 0,
+ GS_SHELL_EVENT_BUTTON_NO_SPACE = 1 << 1,
+ GS_SHELL_EVENT_BUTTON_NETWORK_SETTINGS = 1 << 2,
+ GS_SHELL_EVENT_BUTTON_MORE_INFO = 1 << 3,
+ GS_SHELL_EVENT_BUTTON_LAST
+} GsShellEventButtons;
+
+static void
+gs_shell_show_event_app_notify (GsShell *shell,
+ const gchar *title,
+ GsShellEventButtons buttons)
+{
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ GtkWidget *widget;
+
+ /* set visible */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "notification_event"));
+ gtk_widget_set_visible (widget, TRUE);
+
+ /* sources button */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_sources"));
+ gtk_widget_set_visible (widget, (buttons & GS_SHELL_EVENT_BUTTON_SOURCES) > 0);
+
+ /* no-space button */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_no_space"));
+ gtk_widget_set_visible (widget, (buttons & GS_SHELL_EVENT_BUTTON_NO_SPACE) > 0);
+
+ /* no-space button */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_network_settings"));
+ gtk_widget_set_visible (widget, (buttons & GS_SHELL_EVENT_BUTTON_NETWORK_SETTINGS) > 0);
+
+ /* more-info button */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_more_info"));
+ gtk_widget_set_visible (widget, (buttons & GS_SHELL_EVENT_BUTTON_MORE_INFO) > 0);
+
+ /* set title */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_events"));
+ gtk_label_set_markup (GTK_LABEL (widget), title);
+ gtk_widget_set_visible (widget, title != NULL);
+}
+
+static gchar *
+gs_shell_get_title_from_origin (GsApp *app)
+{
+ /* get a title, falling back */
+ if (gs_app_get_origin_ui (app) != NULL &&
+ gs_app_get_origin_hostname (app) != NULL) {
+ return g_strdup_printf ("“%s” [%s]",
+ gs_app_get_origin_ui (app),
+ gs_app_get_origin_hostname (app));
+ } else if (gs_app_get_origin_ui (app) != NULL) {
+ return g_strdup_printf ("“%s”", gs_app_get_origin_ui (app));
+ } else if (gs_app_get_origin_hostname (app) != NULL) {
+ return g_strdup_printf ("“%s”", gs_app_get_origin_hostname (app));
+ }
+ return g_strdup_printf ("“%s”", gs_app_get_id (app));
+}
+
+static gchar *
+gs_shell_get_title_from_app (GsApp *app)
+{
+ /* get a title, falling back */
+ if (gs_app_get_name (app) != NULL)
+ return g_strdup_printf ("“%s”", gs_app_get_name (app));
+ return g_strdup_printf ("“%s”", gs_app_get_id (app));
+}
+
static gboolean
-gs_shell_show_event (GsShell *shell, GsPluginEvent *event)
+gs_shell_show_event_refresh (GsShell *shell, GsPluginEvent *event)
+{
+ GsApp *origin = gs_plugin_event_get_origin (event);
+ GsShellEventButtons buttons = GS_SHELL_EVENT_BUTTON_NONE;
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ const GError *error = gs_plugin_event_get_error (event);
+ g_autofree gchar *str_origin = NULL;
+ g_autoptr(GString) str = g_string_new (NULL);
+
+ switch (error->code) {
+ case GS_PLUGIN_ERROR_DOWNLOAD_FAILED:
+ if (origin != NULL) {
+ str_origin = gs_shell_get_title_from_origin (origin);
+ if (gs_app_get_bundle_kind (origin) == AS_BUNDLE_KIND_CABINET) {
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to download "
+ "firmware updates from %s"),
+ str_origin);
+ } else {
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to download updates from %s"),
+ str_origin);
+ if (gs_app_get_management_plugin (origin) != NULL)
+ buttons |= GS_SHELL_EVENT_BUTTON_SOURCES;
+ }
+ } else {
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to download updates"));
+ }
+ break;
+ case GS_PLUGIN_ERROR_NO_NETWORK:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to download updates: "
+ "internet access was required but wasn’t available"));
+ buttons |= GS_SHELL_EVENT_BUTTON_NETWORK_SETTINGS;
+ break;
+ case GS_PLUGIN_ERROR_NO_SPACE:
+ if (origin != NULL) {
+ str_origin = gs_shell_get_title_from_origin (origin);
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to download updates "
+ "from %s: not enough disk space"),
+ str_origin);
+ } else {
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to download updates: "
+ "not enough disk space"));
+ }
+ buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
+ break;
+ case GS_PLUGIN_ERROR_AUTH_REQUIRED:
+ case GS_PLUGIN_ERROR_PIN_REQUIRED:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to download updates: "
+ "authentication was required"));
+ break;
+ case GS_PLUGIN_ERROR_AUTH_INVALID:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to download updates: "
+ "authentication was invalid"));
+ break;
+ case GS_PLUGIN_ERROR_NO_SECURITY:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to download updates: you do not have"
+ " permission to install software"));
+ break;
+ default:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to get list of updates"));
+ break;
+ }
+ if (str->len == 0)
+ return FALSE;
+
+ /* add more-info button */
+ if (origin != NULL) {
+ const gchar *uri = gs_app_get_url (origin, AS_URL_KIND_HELP);
+ if (uri != NULL) {
+ g_free (priv->events_info_uri);
+ priv->events_info_uri = g_strdup (uri);
+ buttons |= GS_SHELL_EVENT_BUTTON_MORE_INFO;
+ }
+ }
+
+ /* show in-app notification */
+ gs_shell_show_event_app_notify (shell, str->str, buttons);
+ return TRUE;
+}
+
+static gboolean
+gs_shell_show_event_install (GsShell *shell, GsPluginEvent *event)
+{
+ GsApp *app = gs_plugin_event_get_app (event);
+ GsApp *origin = gs_plugin_event_get_origin (event);
+ GsShellEventButtons buttons = GS_SHELL_EVENT_BUTTON_NONE;
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ const GError *error = gs_plugin_event_get_error (event);
+ g_autofree gchar *msg = NULL;
+ g_autofree gchar *str_app = NULL;
+ g_autofree gchar *str_origin = NULL;
+ g_autoptr(GString) str = g_string_new (NULL);
+
+ str_app = gs_shell_get_title_from_app (app);
+ switch (error->code) {
+ case GS_PLUGIN_ERROR_DOWNLOAD_FAILED:
+ if (origin != NULL) {
+ str_origin = gs_shell_get_title_from_origin (origin);
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to install %s as "
+ "download failed from %s"),
+ str_app, str_origin);
+ } else {
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to install %s "
+ "as download failed"),
+ str_app);
+ }
+ break;
+ case GS_PLUGIN_ERROR_NO_NETWORK:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to install: internet access was "
+ "required but wasn’t available"));
+ buttons |= GS_SHELL_EVENT_BUTTON_NETWORK_SETTINGS;
+ break;
+ case GS_PLUGIN_ERROR_NO_SPACE:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to install %s: "
+ "not enough disk space"),
+ str_app);
+ buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
+ break;
+ case GS_PLUGIN_ERROR_AUTH_REQUIRED:
+ case GS_PLUGIN_ERROR_PIN_REQUIRED:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to install %s: "
+ "authentication was required"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_AUTH_INVALID:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to install %s: "
+ "authentication was invalid"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_NO_SECURITY:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to install %s: "
+ "you do not have permission to "
+ "install software"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED:
+ case GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED:
+ if (origin != NULL) {
+ const gchar *url_homepage;
+
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Your %s account has been suspended."),
+ gs_app_get_name (origin));
+ g_string_append (str, " ");
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("It is not possible to install "
+ "software until this has been resolved."));
+ url_homepage = gs_app_get_url (origin, AS_URL_KIND_HOMEPAGE);
+ if (url_homepage != NULL) {
+ g_autofree gchar *url = NULL;
+ url = g_strdup_printf ("<a href=\"%s\">%s</a>",
+ url_homepage,
+ url_homepage);
+ /* TRANSLATORS: failure text for the in-app notification */
+ msg = g_strdup_printf (_("For more information, visit %s."),
+ url);
+ }
+ }
+ break;
+ default:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to install %s"), str_app);
+ break;
+ }
+ if (str->len == 0)
+ return FALSE;
+
+ /* add more-info button */
+ if (origin != NULL) {
+ const gchar *uri = gs_app_get_url (origin, AS_URL_KIND_HELP);
+ if (uri != NULL) {
+ g_free (priv->events_info_uri);
+ priv->events_info_uri = g_strdup (uri);
+ buttons |= GS_SHELL_EVENT_BUTTON_MORE_INFO;
+ }
+ }
+
+ /* show in-app notification */
+ gs_shell_show_event_app_notify (shell, str->str, buttons);
+ return TRUE;
+}
+
+static gboolean
+gs_shell_show_event_update (GsShell *shell, GsPluginEvent *event)
+{
+ GsApp *app = gs_plugin_event_get_app (event);
+ GsApp *origin = gs_plugin_event_get_origin (event);
+ GsShellEventButtons buttons = GS_SHELL_EVENT_BUTTON_NONE;
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ const GError *error = gs_plugin_event_get_error (event);
+ g_autofree gchar *str_app = NULL;
+ g_autofree gchar *str_origin = NULL;
+ g_autoptr(GString) str = g_string_new (NULL);
+
+ str_app = gs_shell_get_title_from_app (app);
+ switch (error->code) {
+ case GS_PLUGIN_ERROR_DOWNLOAD_FAILED:
+ if (origin != NULL) {
+ str_origin = gs_shell_get_title_from_origin (origin);
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to update %s from %s"),
+ str_app, str_origin);
+ buttons = TRUE;
+ } else {
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to update %s as download failed"),
+ str_app);
+ }
+ break;
+ case GS_PLUGIN_ERROR_NO_NETWORK:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to update: "
+ "internet access was required but "
+ "wasn’t available"));
+ buttons |= GS_SHELL_EVENT_BUTTON_NETWORK_SETTINGS;
+ break;
+ case GS_PLUGIN_ERROR_NO_SPACE:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to update %s: "
+ "not enough disk space"),
+ str_app);
+ buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
+ break;
+ case GS_PLUGIN_ERROR_AUTH_REQUIRED:
+ case GS_PLUGIN_ERROR_PIN_REQUIRED:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to update %s: "
+ "authentication was required"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_AUTH_INVALID:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to update %s: "
+ "authentication was invalid"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_NO_SECURITY:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to update %s: "
+ "you do not have permission to "
+ "update software"),
+ str_app);
+ break;
+ default:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to update %s"), str_app);
+ break;
+ }
+ if (str->len == 0)
+ return FALSE;
+
+ /* add more-info button */
+ if (origin != NULL) {
+ const gchar *uri = gs_app_get_url (origin, AS_URL_KIND_HELP);
+ if (uri != NULL) {
+ g_free (priv->events_info_uri);
+ priv->events_info_uri = g_strdup (uri);
+ buttons |= GS_SHELL_EVENT_BUTTON_MORE_INFO;
+ }
+ }
+
+ /* show in-app notification */
+ gs_shell_show_event_app_notify (shell, str->str, buttons);
+ return TRUE;
+}
+
+static gboolean
+gs_shell_show_event_upgrade (GsShell *shell, GsPluginEvent *event)
{
+ GsApp *app = gs_plugin_event_get_app (event);
+ GsApp *origin = gs_plugin_event_get_origin (event);
+ GsShellEventButtons buttons = GS_SHELL_EVENT_BUTTON_NONE;
GsShellPrivate *priv = gs_shell_get_instance_private (shell);
- gs_app_notify_failed_modal (gs_plugin_event_get_app (event),
- priv->main_window,
- gs_plugin_event_get_action (event),
- gs_plugin_event_get_error (event));
- /* we want to mark the event as invalid */
- return FALSE;
+ const GError *error = gs_plugin_event_get_error (event);
+ g_autoptr(GString) str = g_string_new (NULL);
+ g_autofree gchar *str_app = NULL;
+ g_autofree gchar *str_origin = NULL;
+
+ str_app = gs_shell_get_title_from_app (app);
+ switch (error->code) {
+ case GS_PLUGIN_ERROR_DOWNLOAD_FAILED:
+ if (origin != NULL) {
+ str_origin = gs_shell_get_title_from_origin (origin);
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to upgrade to %s from %s"),
+ str_app, str_origin);
+ } else {
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to upgrade to %s "
+ "as download failed"),
+ str_app);
+ }
+ break;
+ case GS_PLUGIN_ERROR_NO_NETWORK:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Unable to upgrade: "
+ "internet access was required but "
+ "wasn’t available"));
+ buttons |= GS_SHELL_EVENT_BUTTON_NETWORK_SETTINGS;
+ break;
+ case GS_PLUGIN_ERROR_NO_SPACE:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to upgrade to %s: "
+ "not enough disk space"),
+ str_app);
+ buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
+ break;
+ case GS_PLUGIN_ERROR_AUTH_REQUIRED:
+ case GS_PLUGIN_ERROR_PIN_REQUIRED:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to upgrade to %s: "
+ "authentication was required"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_AUTH_INVALID:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to upgrade to %s: "
+ "authentication was invalid"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_NO_SECURITY:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to upgrade to %s: "
+ "you do not have permission to upgrade"),
+ str_app);
+ break;
+ default:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to upgrade to %s"), str_app);
+ break;
+ }
+ if (str->len == 0)
+ return FALSE;
+
+ /* add more-info button */
+ if (origin != NULL) {
+ const gchar *uri = gs_app_get_url (origin, AS_URL_KIND_HELP);
+ if (uri != NULL) {
+ g_free (priv->events_info_uri);
+ priv->events_info_uri = g_strdup (uri);
+ buttons |= GS_SHELL_EVENT_BUTTON_MORE_INFO;
+ }
+ }
+
+ /* show in-app notification */
+ gs_shell_show_event_app_notify (shell, str->str, buttons);
+ return TRUE;
+}
+
+static gboolean
+gs_shell_show_event_remove (GsShell *shell, GsPluginEvent *event)
+{
+ GsApp *app = gs_plugin_event_get_app (event);
+ GsApp *origin = gs_plugin_event_get_origin (event);
+ GsShellEventButtons buttons = GS_SHELL_EVENT_BUTTON_NONE;
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ const GError *error = gs_plugin_event_get_error (event);
+ g_autoptr(GString) str = g_string_new (NULL);
+ g_autofree gchar *str_app = NULL;
+
+ str_app = gs_shell_get_title_from_app (app);
+ switch (error->code) {
+ case GS_PLUGIN_ERROR_AUTH_REQUIRED:
+ case GS_PLUGIN_ERROR_PIN_REQUIRED:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to remove %s: authentication was required"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_AUTH_INVALID:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to remove %s: authentication was invalid"),
+ str_app);
+ break;
+ case GS_PLUGIN_ERROR_NO_SECURITY:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to remove %s: you do not have"
+ " permission to remove software"),
+ str_app);
+ break;
+ default:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to remove %s"), str_app);
+ break;
+ }
+ if (str->len == 0)
+ return FALSE;
+
+ /* add more-info button */
+ if (origin != NULL) {
+ const gchar *uri = gs_app_get_url (origin, AS_URL_KIND_HELP);
+ if (uri != NULL) {
+ g_free (priv->events_info_uri);
+ priv->events_info_uri = g_strdup (uri);
+ buttons |= GS_SHELL_EVENT_BUTTON_MORE_INFO;
+ }
+ }
+
+ /* show in-app notification */
+ gs_shell_show_event_app_notify (shell, str->str, buttons);
+ return TRUE;
+}
+
+static gboolean
+gs_shell_show_event_fallback (GsShell *shell, GsPluginEvent *event)
+{
+ GsApp *origin = gs_plugin_event_get_origin (event);
+ GsShellEventButtons buttons = GS_SHELL_EVENT_BUTTON_NONE;
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ const GError *error = gs_plugin_event_get_error (event);
+ g_autoptr(GString) str = g_string_new (NULL);
+ g_autofree gchar *str_origin = NULL;
+
+ switch (error->code) {
+ case GS_PLUGIN_ERROR_DOWNLOAD_FAILED:
+ if (origin != NULL) {
+ str_origin = gs_shell_get_title_from_origin (origin);
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append_printf (str, _("Unable to contact %s"),
+ str_origin);
+ }
+ break;
+ case GS_PLUGIN_ERROR_NO_SPACE:
+ /* TRANSLATORS: failure text for the in-app notification */
+ g_string_append (str, _("Not enough disk space — free up some space "
+ "and try again"));
+ buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
+ break;
+ default:
+ break;
+ }
+ if (str->len == 0)
+ return FALSE;
+
+ /* add more-info button */
+ if (origin != NULL) {
+ const gchar *uri = gs_app_get_url (origin, AS_URL_KIND_HELP);
+ if (uri != NULL) {
+ g_free (priv->events_info_uri);
+ priv->events_info_uri = g_strdup (uri);
+ buttons |= GS_SHELL_EVENT_BUTTON_MORE_INFO;
+ }
+ }
+
+ /* show in-app notification */
+ gs_shell_show_event_app_notify (shell, str->str, buttons);
+ return TRUE;
+}
+
+static gboolean
+gs_shell_show_event (GsShell *shell, GsPluginEvent *event)
+{
+ const GError *error;
+ GsPluginAction action;
+
+ /* get error */
+ error = gs_plugin_event_get_error (event);
+ if (error == NULL)
+ return FALSE;
+
+ /* split up the events by action */
+ action = gs_plugin_event_get_action (event);
+ switch (action) {
+ case GS_PLUGIN_ACTION_REFRESH:
+ return gs_shell_show_event_refresh (shell, event);
+ case GS_PLUGIN_ACTION_INSTALL:
+ return gs_shell_show_event_install (shell, event);
+ case GS_PLUGIN_ACTION_UPDATE:
+ return gs_shell_show_event_update (shell, event);
+ case GS_PLUGIN_ACTION_UPGRADE_DOWNLOAD:
+ return gs_shell_show_event_upgrade (shell, event);
+ case GS_PLUGIN_ACTION_REMOVE:
+ return gs_shell_show_event_remove (shell, event);
+ default:
+ break;
+ }
+
+ /* capture some warnings every time */
+ return gs_shell_show_event_fallback (shell, event);
}
static void
@@ -773,6 +1355,15 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_sources"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gs_shell_plugin_events_sources_cb), shell);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_no_space"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_plugin_events_no_space_cb), shell);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_network_settings"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_plugin_events_network_settings_cb), shell);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_more_info"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_plugin_events_more_info_cb), shell);
priv->shell_overview = GS_SHELL_OVERVIEW (gtk_builder_get_object (priv->builder, "shell_overview"));
gs_shell_overview_setup (priv->shell_overview,
@@ -978,6 +1569,7 @@ gs_shell_dispose (GObject *object)
g_clear_object (&priv->plugin_loader);
g_clear_object (&priv->header_start_widget);
g_clear_object (&priv->header_end_widget);
+ g_clear_pointer (&priv->events_info_uri, (GDestroyNotify) g_free);
g_clear_pointer (&priv->modal_dialogs, (GDestroyNotify) g_ptr_array_unref);
G_OBJECT_CLASS (gs_shell_parent_class)->dispose (object);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]