[gnome-software] gs-shell: Add a menu popover with sign in/out shortcuts.
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] gs-shell: Add a menu popover with sign in/out shortcuts.
- Date: Tue, 26 Jun 2018 23:12:00 +0000 (UTC)
commit 796d20b4c5c243c87f43850db948fc871437fcf3
Author: Andrea Azzarone <azzaronea gmail com>
Date: Wed May 16 16:31:11 2018 -0500
gs-shell: Add a menu popover with sign in/out shortcuts.
lib/gs-auth.c | 62 ++++++++++++++
lib/gs-auth.h | 4 +
lib/gs-plugin-loader.c | 7 ++
lib/gs-plugin-loader.h | 1 +
plugins/snap/gs-plugin-snap.c | 24 +++++-
plugins/ubuntuone/gs-plugin-ubuntuone.c | 21 +++++
src/gnome-software.ui | 33 +++++++-
src/gs-auth-dialog.c | 7 +-
src/gs-details-page.ui | 1 -
src/gs-page.c | 4 +-
src/gs-shell.c | 145 ++++++++++++++++++++++++++++++++
11 files changed, 302 insertions(+), 7 deletions(-)
---
diff --git a/lib/gs-auth.c b/lib/gs-auth.c
index 78c6aef9..098efd13 100644
--- a/lib/gs-auth.c
+++ b/lib/gs-auth.c
@@ -558,6 +558,68 @@ gs_auth_store_save (GsAuth *auth, GsAuthStoreFlags flags,
return TRUE;
}
+gboolean
+gs_auth_store_clear (GsAuth *auth, GsAuthStoreFlags flags,
+ GCancellable *cancellable, GError **error)
+{
+ SecretSchema schema = {
+ auth->provider_schema,
+ SECRET_SCHEMA_NONE,
+ { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
+ };
+
+ /* no schema */
+ if (auth->provider_schema == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "No provider schema set for %s",
+ auth->provider_id);
+ return FALSE;
+ }
+
+ /* username */
+ if ((flags & GS_AUTH_STORE_FLAG_USERNAME) > 0) {
+ if (!secret_password_clear_sync (&schema,
+ cancellable, error,
+ "key", "username", NULL))
+ return FALSE;
+ }
+
+ g_free (auth->username);
+ auth->username = NULL;
+
+ /* password */
+ if ((flags & GS_AUTH_STORE_FLAG_PASSWORD) > 0) {
+ if (!secret_password_clear_sync (&schema,
+ cancellable, error,
+ "key", "password", NULL))
+ return FALSE;
+ }
+
+ g_free (auth->password);
+ auth->password = NULL;
+
+ /* metadata */
+ if (flags & GS_AUTH_STORE_FLAG_METADATA) {
+ g_autoptr(GList) keys = NULL;
+ keys = g_hash_table_get_keys (auth->metadata);
+ for (GList *l = keys; l != NULL; l = l->next) {
+ const gchar *key = l->data;
+ if (!secret_password_clear_sync (&schema,
+ cancellable, error,
+ "key", key, NULL))
+ return FALSE;
+
+ }
+ }
+
+ g_hash_table_remove_all (auth->metadata);
+
+ /* success */
+ return TRUE;
+}
+
static void
gs_auth_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
diff --git a/lib/gs-auth.h b/lib/gs-auth.h
index c9f572f7..55df1a7d 100644
--- a/lib/gs-auth.h
+++ b/lib/gs-auth.h
@@ -108,6 +108,10 @@ gboolean gs_auth_store_save (GsAuth *auth,
GsAuthStoreFlags flags,
GCancellable *cancellable,
GError **error);
+gboolean gs_auth_store_clear (GsAuth *auth,
+ GsAuthStoreFlags flags,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 2fb02e3c..55ddc95d 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -2266,6 +2266,13 @@ gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
return NULL;
}
+GPtrArray *
+gs_plugin_loader_get_auths (GsPluginLoader *plugin_loader)
+{
+ GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (plugin_loader);
+ return priv->auth_array;
+}
+
void
gs_plugin_loader_add_location (GsPluginLoader *plugin_loader, const gchar *location)
{
diff --git a/lib/gs-plugin-loader.h b/lib/gs-plugin-loader.h
index ea603985..ac1c2204 100644
--- a/lib/gs-plugin-loader.h
+++ b/lib/gs-plugin-loader.h
@@ -82,6 +82,7 @@ void gs_plugin_loader_add_location (GsPluginLoader *plugin_loader,
const gchar *location);
GsAuth *gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
const gchar *provider_id);
+GPtrArray *gs_plugin_loader_get_auths (GsPluginLoader *plugin_loader);
guint gs_plugin_loader_get_scale (GsPluginLoader *plugin_loader);
void gs_plugin_loader_set_scale (GsPluginLoader *plugin_loader,
guint scale);
diff --git a/plugins/snap/gs-plugin-snap.c b/plugins/snap/gs-plugin-snap.c
index b45f87ea..2a26fe6a 100644
--- a/plugins/snap/gs-plugin-snap.c
+++ b/plugins/snap/gs-plugin-snap.c
@@ -74,7 +74,7 @@ gs_plugin_initialize (GsPlugin *plugin)
priv->auth = gs_auth_new ("snapd");
gs_auth_set_provider_name (priv->auth, "Snap Store");
- gs_auth_set_provider_schema (priv->auth, "com.ubuntu.UbuntuOne.GnomeSoftware");
+ gs_auth_set_provider_schema (priv->auth, "com.ubuntu.SnapStore.GnomeSoftware");
gs_plugin_add_auth (plugin, priv->auth);
gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "desktop-categories");
@@ -183,6 +183,7 @@ load_auth (GsPlugin *plugin)
g_variant_get (macaroon_variant, "(&s^as)", &macaroon, &discharges);
g_clear_object (&priv->auth_data);
priv->auth_data = snapd_auth_data_new (macaroon, discharges);
+ gs_auth_add_flags (priv->auth, GS_AUTH_FLAG_VALID);
}
gboolean
@@ -1071,6 +1072,27 @@ gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
return TRUE;
}
+gboolean
+gs_plugin_auth_logout (GsPlugin *plugin, GsAuth *auth,
+ GCancellable *cancellable, GError **error)
+{
+ GsPluginData *priv = gs_plugin_get_data (plugin);
+
+ if (auth != priv->auth)
+ return TRUE;
+
+ /* clear */
+ if (!gs_auth_store_clear (auth,
+ GS_AUTH_STORE_FLAG_USERNAME |
+ GS_AUTH_STORE_FLAG_METADATA,
+ cancellable, error))
+ return FALSE;
+
+ g_clear_object (&priv->auth_data);
+ gs_auth_set_flags (priv->auth, 0);
+ return TRUE;
+}
+
gboolean
gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth,
GCancellable *cancellable, GError **error)
diff --git a/plugins/ubuntuone/gs-plugin-ubuntuone.c b/plugins/ubuntuone/gs-plugin-ubuntuone.c
index 9d693572..00f2a4f2 100644
--- a/plugins/ubuntuone/gs-plugin-ubuntuone.c
+++ b/plugins/ubuntuone/gs-plugin-ubuntuone.c
@@ -233,6 +233,27 @@ gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
return TRUE;
}
+gboolean
+gs_plugin_auth_logout (GsPlugin *plugin, GsAuth *auth,
+ GCancellable *cancellable, GError **error)
+{
+ GsPluginData *priv = gs_plugin_get_data (plugin);
+
+ if (auth != priv->auth)
+ return TRUE;
+
+ /* clear */
+ if (!gs_auth_store_clear (auth,
+ GS_AUTH_STORE_FLAG_USERNAME |
+ GS_AUTH_STORE_FLAG_METADATA,
+ cancellable, error))
+ return FALSE;
+
+ gs_auth_set_flags (priv->auth, 0);
+ return TRUE;
+}
+
+
gboolean
gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth,
GCancellable *cancellable, GError **error)
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index 33c8bb4d..a8755701 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -17,6 +17,18 @@
</object>
</child>
</object>
+ <object class="GtkPopoverMenu" id="account_popover">
+ <child>
+ <object class="GtkBox" id="account_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="margin">6</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
<object class="GtkApplicationWindow" id="window_software">
<property name="can_focus">False</property>
<property name="default-width">1200</property>
@@ -263,8 +275,28 @@
</object>
</child>
</object>
+ <packing>
+ <property name="position">1</property>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="account_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="sensitive">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">open-menu-symbolic</property>
+ <property name="icon_size">1</property>
+ </object>
+ </child>
+ </object>
<packing>
<property name="pack-type">end</property>
+ <property name="position">0</property>
</packing>
</child>
</object>
@@ -274,7 +306,6 @@
<property name="position">0</property>
</packing>
</child>
-
<child>
<object class="GtkSearchBar" id="search_bar">
<property name="visible">True</property>
diff --git a/src/gs-auth-dialog.c b/src/gs-auth-dialog.c
index 4b8a2bbf..9eff3404 100644
--- a/src/gs-auth-dialog.c
+++ b/src/gs-auth-dialog.c
@@ -335,7 +335,7 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_FAILED,
"no auth-provider given for %s",
- gs_app_get_id (app));
+ app != NULL ? gs_app_get_id (app) : NULL);
return NULL;
}
auth = gs_plugin_loader_get_auth_by_id (plugin_loader, provider_id);
@@ -344,7 +344,8 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_NOT_SUPPORTED,
"no auth-provider %s for %s",
- provider_id, gs_app_get_id (app));
+ provider_id,
+ app != NULL ? gs_app_get_id (app) : NULL);
return NULL;
}
@@ -353,7 +354,7 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader,
"use-header-bar", TRUE,
NULL);
dialog->plugin_loader = g_object_ref (plugin_loader);
- dialog->app = g_object_ref (app);
+ dialog->app = app != NULL ? g_object_ref (app) : NULL;
dialog->auth = g_object_ref (auth);
gs_auth_dialog_setup (dialog);
diff --git a/src/gs-details-page.ui b/src/gs-details-page.ui
index e6cb7dc0..9836384d 100644
--- a/src/gs-details-page.ui
+++ b/src/gs-details-page.ui
@@ -1608,5 +1608,4 @@
</object>
</child>
</object>
-
</interface>
diff --git a/src/gs-page.c b/src/gs-page.c
index 7819523c..9b34310e 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -85,7 +85,8 @@ gs_page_authenticate_cb (GtkDialog *dialog,
/* unmap the dialog */
gtk_widget_destroy (GTK_WIDGET (dialog));
- helper->callback (helper->page, response_type == GTK_RESPONSE_OK, helper->callback_data);
+ if (helper->callback != NULL)
+ helper->callback (helper->page, response_type == GTK_RESPONSE_OK, helper->callback_data);
}
void
@@ -102,6 +103,7 @@ gs_page_authenticate (GsPage *page,
g_autoptr(GError) error = NULL;
helper = g_slice_new0 (GsPageHelper);
+ helper->app = app != NULL ? g_object_ref (app) : NULL;
helper->page = g_object_ref (page);
helper->callback = callback;
helper->callback_data = user_data;
diff --git a/src/gs-shell.c b/src/gs-shell.c
index be0c9a77..1d59228b 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -242,6 +242,17 @@ gs_shell_clean_back_entry_stack (GsShell *shell)
}
}
+static void
+gs_shell_update_account_button_visibility (GsShell *shell)
+{
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ GPtrArray *auths = gs_plugin_loader_get_auths (priv->plugin_loader);
+ GtkWidget *account_button;
+
+ account_button = GTK_WIDGET (gtk_builder_get_object (priv->builder, "account_button"));
+ gtk_widget_set_visible (account_button, auths->len > 0);
+}
+
void
gs_shell_change_mode (GsShell *shell,
GsShellMode mode,
@@ -377,6 +388,8 @@ gs_shell_change_mode (GsShell *shell,
widget = gs_page_get_header_end_widget (page);
gs_shell_set_header_end_widget (shell, widget);
+ gs_shell_update_account_button_visibility (shell);
+
/* destroy any existing modals */
if (priv->modal_dialogs != NULL) {
gsize i = 0;
@@ -648,6 +661,132 @@ search_mode_enabled_cb (GtkSearchBar *search_bar, GParamSpec *pspec, GsShell *sh
gtk_search_bar_get_search_mode (search_bar));
}
+static void
+gs_shell_signin_button_cb (GtkButton *button, GsShell *shell)
+{
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ GsAuth *auth;
+
+ auth = GS_AUTH (g_object_get_data (G_OBJECT (button), "auth"));
+ gs_page_authenticate (priv->page_last, NULL,
+ gs_auth_get_provider_id (auth),
+ priv->cancellable,
+ NULL, NULL);
+}
+
+static void
+gs_shell_logout_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
+ g_autoptr(GError) error = NULL;
+
+ if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
+ g_warning ("failed to logout: %s", error->message);
+ return;
+ }
+}
+
+static void
+gs_shell_signout_button_cb (GtkButton *button, GsShell *shell)
+{
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ g_autoptr(GsPluginJob) plugin_job = NULL;
+
+ plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGOUT,
+ "auth", g_object_get_data (G_OBJECT (button), "auth"),
+ NULL);
+
+ gs_plugin_loader_job_process_async (priv->plugin_loader, plugin_job,
+ priv->cancellable,
+ gs_shell_logout_cb,
+ shell);
+
+}
+
+static void
+add_buttons_for_auth (GsShell *shell, GsAuth *auth)
+{
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ GtkWidget *account_box;
+ gboolean logged_in;
+ GtkWidget *signin_button;
+ GtkWidget *signout_button;
+ g_autofree gchar *signout_label = NULL;
+ g_autofree gchar *signin_label = NULL;
+
+ account_box = GTK_WIDGET (gtk_builder_get_object (priv->builder, "account_box"));
+ logged_in = gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID);
+ signin_button = gtk_model_button_new ();
+ signout_button = gtk_model_button_new ();
+
+ signout_label = g_strdup_printf (_("Sign out from %s"),
+ gs_auth_get_provider_name (auth));
+ if (logged_in)
+ signin_label = g_strdup_printf (_("Signed in into %s as %s"),
+ gs_auth_get_provider_name (auth),
+ gs_auth_get_username (auth));
+ else
+ signin_label = g_strdup_printf (_("Sign in to %s…"),
+ gs_auth_get_provider_name (auth));
+
+ g_object_set (signin_button,
+ "text", signin_label,
+ "sensitive", !logged_in, NULL);
+ g_object_set_data (G_OBJECT (signin_button), "auth", auth);
+
+ g_object_set (signout_button,
+ "text", signout_label,
+ "sensitive", logged_in, NULL);
+ g_object_set_data (G_OBJECT (signout_button), "auth", auth);
+
+ g_signal_connect (signin_button, "clicked",
+ G_CALLBACK (gs_shell_signin_button_cb), shell);
+ g_signal_connect (signout_button, "clicked",
+ G_CALLBACK (gs_shell_signout_button_cb), shell);
+
+ gtk_widget_show (signin_button);
+ gtk_widget_show (signout_button);
+ gtk_box_pack_start (GTK_BOX (account_box), signin_button, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (account_box), signout_button, TRUE, TRUE, 0);
+}
+
+static void
+account_button_clicked_cb (GtkButton *button, GsShell *shell)
+{
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ GPtrArray *auth_array;
+ GtkWidget *account_popover;
+ GtkWidget *account_box;
+ g_autoptr(GList) children = NULL;
+
+ auth_array = gs_plugin_loader_get_auths (priv->plugin_loader);
+ account_popover = GTK_WIDGET (gtk_builder_get_object (priv->builder, "account_popover"));
+ account_box = GTK_WIDGET (gtk_builder_get_object (priv->builder, "account_box"));
+
+ /* Remove existing buttons... */
+ children = gtk_container_get_children (GTK_CONTAINER (account_box));
+ for (GList *l = children; l != NULL; l = l->next)
+ gtk_container_remove (GTK_CONTAINER (account_box), GTK_WIDGET (l->data));
+
+ /* Add new ones... */
+ for (guint i = 0; i < auth_array->len; i++) {
+ GsAuth *auth = g_ptr_array_index (auth_array, i);
+ add_buttons_for_auth (shell, auth);
+
+ /* Add sepeartor between each block */
+ if (i < auth_array->len - 1) {
+ GtkWidget *seprator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_widget_show (seprator);
+ gtk_box_pack_start (GTK_BOX (account_box), seprator, TRUE, TRUE, 0);
+ }
+ }
+
+ gtk_popover_set_relative_to (GTK_POPOVER (account_popover), GTK_WIDGET (button));
+ gtk_popover_popup (GTK_POPOVER (account_popover));
+}
+
static gboolean
window_key_press_event (GtkWidget *win, GdkEventKey *event, GsShell *shell)
{
@@ -1895,6 +2034,12 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
G_CALLBACK (search_mode_enabled_cb),
shell);
+ /* show the account popover when clicking on the account button */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "account_button"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (account_button_clicked_cb),
+ shell);
+
/* setup buttons */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
g_signal_connect (widget, "clicked",
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]