Commit 796d20b4 authored by Andrea Azzarone's avatar Andrea Azzarone 🚴 Committed by Robert Ancell

gs-shell: Add a menu popover with sign in/out shortcuts.

parent 97c81fcb
...@@ -558,6 +558,68 @@ gs_auth_store_save (GsAuth *auth, GsAuthStoreFlags flags, ...@@ -558,6 +558,68 @@ gs_auth_store_save (GsAuth *auth, GsAuthStoreFlags flags,
return TRUE; 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 static void
gs_auth_get_property (GObject *object, guint prop_id, gs_auth_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec) GValue *value, GParamSpec *pspec)
......
...@@ -108,6 +108,10 @@ gboolean gs_auth_store_save (GsAuth *auth, ...@@ -108,6 +108,10 @@ gboolean gs_auth_store_save (GsAuth *auth,
GsAuthStoreFlags flags, GsAuthStoreFlags flags,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
gboolean gs_auth_store_clear (GsAuth *auth,
GsAuthStoreFlags flags,
GCancellable *cancellable,
GError **error);
G_END_DECLS G_END_DECLS
......
...@@ -2266,6 +2266,13 @@ gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader, ...@@ -2266,6 +2266,13 @@ gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
return NULL; 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 void
gs_plugin_loader_add_location (GsPluginLoader *plugin_loader, const gchar *location) gs_plugin_loader_add_location (GsPluginLoader *plugin_loader, const gchar *location)
{ {
......
...@@ -82,6 +82,7 @@ void gs_plugin_loader_add_location (GsPluginLoader *plugin_loader, ...@@ -82,6 +82,7 @@ void gs_plugin_loader_add_location (GsPluginLoader *plugin_loader,
const gchar *location); const gchar *location);
GsAuth *gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader, GsAuth *gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
const gchar *provider_id); const gchar *provider_id);
GPtrArray *gs_plugin_loader_get_auths (GsPluginLoader *plugin_loader);
guint gs_plugin_loader_get_scale (GsPluginLoader *plugin_loader); guint gs_plugin_loader_get_scale (GsPluginLoader *plugin_loader);
void gs_plugin_loader_set_scale (GsPluginLoader *plugin_loader, void gs_plugin_loader_set_scale (GsPluginLoader *plugin_loader,
guint scale); guint scale);
......
...@@ -74,7 +74,7 @@ gs_plugin_initialize (GsPlugin *plugin) ...@@ -74,7 +74,7 @@ gs_plugin_initialize (GsPlugin *plugin)
priv->auth = gs_auth_new ("snapd"); priv->auth = gs_auth_new ("snapd");
gs_auth_set_provider_name (priv->auth, "Snap Store"); 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_auth (plugin, priv->auth);
gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "desktop-categories"); gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "desktop-categories");
...@@ -183,6 +183,7 @@ load_auth (GsPlugin *plugin) ...@@ -183,6 +183,7 @@ load_auth (GsPlugin *plugin)
g_variant_get (macaroon_variant, "(&s^as)", &macaroon, &discharges); g_variant_get (macaroon_variant, "(&s^as)", &macaroon, &discharges);
g_clear_object (&priv->auth_data); g_clear_object (&priv->auth_data);
priv->auth_data = snapd_auth_data_new (macaroon, discharges); priv->auth_data = snapd_auth_data_new (macaroon, discharges);
gs_auth_add_flags (priv->auth, GS_AUTH_FLAG_VALID);
} }
gboolean gboolean
...@@ -1071,6 +1072,27 @@ gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth, ...@@ -1071,6 +1072,27 @@ gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
return TRUE; 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 gboolean
gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth, gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth,
GCancellable *cancellable, GError **error) GCancellable *cancellable, GError **error)
......
...@@ -233,6 +233,27 @@ gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth, ...@@ -233,6 +233,27 @@ gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
return TRUE; 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 gboolean
gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth, gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth,
GCancellable *cancellable, GError **error) GCancellable *cancellable, GError **error)
......
...@@ -17,6 +17,18 @@ ...@@ -17,6 +17,18 @@
</object> </object>
</child> </child>
</object> </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"> <object class="GtkApplicationWindow" id="window_software">
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="default-width">1200</property> <property name="default-width">1200</property>
...@@ -263,8 +275,28 @@ ...@@ -263,8 +275,28 @@
</object> </object>
</child> </child>
</object> </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> <packing>
<property name="pack-type">end</property> <property name="pack-type">end</property>
<property name="position">0</property>
</packing> </packing>
</child> </child>
</object> </object>
...@@ -274,7 +306,6 @@ ...@@ -274,7 +306,6 @@
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkSearchBar" id="search_bar"> <object class="GtkSearchBar" id="search_bar">
<property name="visible">True</property> <property name="visible">True</property>
......
...@@ -335,7 +335,7 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader, ...@@ -335,7 +335,7 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader,
GS_PLUGIN_ERROR, GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_FAILED, GS_PLUGIN_ERROR_FAILED,
"no auth-provider given for %s", "no auth-provider given for %s",
gs_app_get_id (app)); app != NULL ? gs_app_get_id (app) : NULL);
return NULL; return NULL;
} }
auth = gs_plugin_loader_get_auth_by_id (plugin_loader, provider_id); auth = gs_plugin_loader_get_auth_by_id (plugin_loader, provider_id);
...@@ -344,7 +344,8 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader, ...@@ -344,7 +344,8 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader,
GS_PLUGIN_ERROR, GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_NOT_SUPPORTED, GS_PLUGIN_ERROR_NOT_SUPPORTED,
"no auth-provider %s for %s", "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; return NULL;
} }
...@@ -353,7 +354,7 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader, ...@@ -353,7 +354,7 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader,
"use-header-bar", TRUE, "use-header-bar", TRUE,
NULL); NULL);
dialog->plugin_loader = g_object_ref (plugin_loader); 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); dialog->auth = g_object_ref (auth);
gs_auth_dialog_setup (dialog); gs_auth_dialog_setup (dialog);
......
...@@ -1608,5 +1608,4 @@ ...@@ -1608,5 +1608,4 @@
</object> </object>
</child> </child>
</object> </object>
</interface> </interface>
...@@ -85,7 +85,8 @@ gs_page_authenticate_cb (GtkDialog *dialog, ...@@ -85,7 +85,8 @@ gs_page_authenticate_cb (GtkDialog *dialog,
/* unmap the dialog */ /* unmap the dialog */
gtk_widget_destroy (GTK_WIDGET (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 void
...@@ -102,6 +103,7 @@ gs_page_authenticate (GsPage *page, ...@@ -102,6 +103,7 @@ gs_page_authenticate (GsPage *page,
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
helper = g_slice_new0 (GsPageHelper); helper = g_slice_new0 (GsPageHelper);
helper->app = app != NULL ? g_object_ref (app) : NULL;
helper->page = g_object_ref (page); helper->page = g_object_ref (page);
helper->callback = callback; helper->callback = callback;
helper->callback_data = user_data; helper->callback_data = user_data;
......
...@@ -242,6 +242,17 @@ gs_shell_clean_back_entry_stack (GsShell *shell) ...@@ -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 void
gs_shell_change_mode (GsShell *shell, gs_shell_change_mode (GsShell *shell,
GsShellMode mode, GsShellMode mode,
...@@ -377,6 +388,8 @@ gs_shell_change_mode (GsShell *shell, ...@@ -377,6 +388,8 @@ gs_shell_change_mode (GsShell *shell,
widget = gs_page_get_header_end_widget (page); widget = gs_page_get_header_end_widget (page);
gs_shell_set_header_end_widget (shell, widget); gs_shell_set_header_end_widget (shell, widget);
gs_shell_update_account_button_visibility (shell);
/* destroy any existing modals */ /* destroy any existing modals */
if (priv->modal_dialogs != NULL) { if (priv->modal_dialogs != NULL) {
gsize i = 0; gsize i = 0;
...@@ -648,6 +661,132 @@ search_mode_enabled_cb (GtkSearchBar *search_bar, GParamSpec *pspec, GsShell *sh ...@@ -648,6 +661,132 @@ search_mode_enabled_cb (GtkSearchBar *search_bar, GParamSpec *pspec, GsShell *sh
gtk_search_bar_get_search_mode (search_bar)); 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 static gboolean
window_key_press_event (GtkWidget *win, GdkEventKey *event, GsShell *shell) window_key_press_event (GtkWidget *win, GdkEventKey *event, GsShell *shell)
{ {
...@@ -1895,6 +2034,12 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can ...@@ -1895,6 +2034,12 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
G_CALLBACK (search_mode_enabled_cb), G_CALLBACK (search_mode_enabled_cb),
shell); 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 */ /* setup buttons */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back")); widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
g_signal_connect (widget, "clicked", g_signal_connect (widget, "clicked",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment