diff options
Diffstat (limited to 'panels/online-accounts')
-rw-r--r-- | panels/online-accounts/cc-online-accounts-panel.c | 992 | ||||
-rw-r--r-- | panels/online-accounts/cc-online-accounts-panel.h | 31 | ||||
-rw-r--r-- | panels/online-accounts/gnome-online-accounts-panel.desktop.in.in | 21 | ||||
-rw-r--r-- | panels/online-accounts/icons/16x16/goa-panel.png | bin | 0 -> 917 bytes | |||
-rw-r--r-- | panels/online-accounts/icons/22x22/goa-panel.png | bin | 0 -> 1431 bytes | |||
-rw-r--r-- | panels/online-accounts/icons/24x24/goa-panel.png | bin | 0 -> 1469 bytes | |||
-rw-r--r-- | panels/online-accounts/icons/256x256/goa-panel.png | bin | 0 -> 42185 bytes | |||
-rw-r--r-- | panels/online-accounts/icons/32x32/goa-panel.png | bin | 0 -> 2170 bytes | |||
-rw-r--r-- | panels/online-accounts/icons/48x48/goa-panel.png | bin | 0 -> 3747 bytes | |||
-rw-r--r-- | panels/online-accounts/icons/meson.build | 15 | ||||
-rw-r--r-- | panels/online-accounts/meson.build | 45 | ||||
-rw-r--r-- | panels/online-accounts/online-accounts.gresource.xml | 6 | ||||
-rw-r--r-- | panels/online-accounts/online-accounts.ui | 252 |
13 files changed, 1362 insertions, 0 deletions
diff --git a/panels/online-accounts/cc-online-accounts-panel.c b/panels/online-accounts/cc-online-accounts-panel.c new file mode 100644 index 0000000..e6d6a3d --- /dev/null +++ b/panels/online-accounts/cc-online-accounts-panel.c @@ -0,0 +1,992 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2011 - 2017 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: David Zeuthen <davidz@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <string.h> +#include <glib/gi18n-lib.h> + +#define GOA_API_IS_SUBJECT_TO_CHANGE +#include <goa/goa.h> +#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE +#include <goabackend/goabackend.h> + +#include "cc-online-accounts-panel.h" +#include "cc-online-accounts-resources.h" + +#include "list-box-helper.h" + +struct _CcGoaPanel +{ + CcPanel parent_instance; + + GtkFrame *accounts_frame; + GtkListBox *accounts_listbox; + GtkDialog *edit_account_dialog; + GtkHeaderBar *edit_account_headerbar; + GtkBox *editor_box; + GtkListBoxRow *more_providers_row; + GtkBox *new_account_vbox; + GtkLabel *notification_label; + GtkRevealer *notification_revealer; + GtkLabel *offline_label; + GtkListBox *providers_listbox; + GtkButton *remove_account_button; + GtkStack *stack; + GtkBox *accounts_vbox; + + GoaClient *client; + GoaObject *active_object; + GoaObject *removed_object; + + guint remove_account_timeout_id; +}; + +static gboolean on_edit_account_dialog_delete_event (CcGoaPanel *self); + +static void on_listbox_row_activated (CcGoaPanel *self, + GtkListBoxRow *activated_row); + +static void fill_accounts_listbox (CcGoaPanel *self); + +static void on_account_added (GoaClient *client, + GoaObject *object, + gpointer user_data); + +static void on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data); + +static void on_account_removed (GoaClient *client, + GoaObject *object, + gpointer user_data); + +static void select_account_by_id (CcGoaPanel *panel, + const gchar *account_id); + +static void get_all_providers_cb (GObject *source, + GAsyncResult *res, + gpointer user_data); + +static void show_page_account (CcGoaPanel *panel, + GoaObject *object); + +static void on_remove_button_clicked (CcGoaPanel *self); + +static void on_notification_closed (GtkButton *button, + CcGoaPanel *self); + +static void on_undo_button_clicked (GtkButton *button, + CcGoaPanel *self); + +CC_PANEL_REGISTER (CcGoaPanel, cc_goa_panel); + +enum { + PROP_0, + PROP_PARAMETERS +}; + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +reset_headerbar (CcGoaPanel *self) +{ + gtk_header_bar_set_title (self->edit_account_headerbar, NULL); + gtk_header_bar_set_subtitle (self->edit_account_headerbar, NULL); + gtk_header_bar_set_show_close_button (self->edit_account_headerbar, TRUE); + + /* Remove any leftover widgets */ + gtk_container_foreach (GTK_CONTAINER (self->edit_account_headerbar), + (GtkCallback) gtk_widget_destroy, + NULL); + +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +add_provider_row (CcGoaPanel *self, + GoaProvider *provider) +{ + GIcon *icon; + GoaProviderFeatures features; + GtkWidget *image; + GtkWidget *label; + GtkWidget *row; + GtkWidget *row_grid; + gchar *markup; + gchar *name; + + row = gtk_list_box_row_new (); + + row_grid = gtk_grid_new (); + gtk_widget_show (row_grid); + gtk_orientable_set_orientation (GTK_ORIENTABLE (row_grid), GTK_ORIENTATION_HORIZONTAL); + gtk_grid_set_column_spacing (GTK_GRID (row_grid), 6); + gtk_container_add (GTK_CONTAINER (row), row_grid); + + if (provider == NULL) + { + g_object_set_data (G_OBJECT (row), "goa-provider", NULL); + icon = g_themed_icon_new_with_default_fallbacks ("goa-account"); + name = g_strdup (C_("Online Account", "Other")); + } + else + { + g_object_set_data_full (G_OBJECT (row), "goa-provider", g_object_ref (provider), g_object_unref); + icon = goa_provider_get_provider_icon (provider, NULL); + name = goa_provider_get_provider_name (provider, NULL); + } + + image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG); + gtk_style_context_add_class (gtk_widget_get_style_context (image), "lowres-icon"); + gtk_widget_show (image); + gtk_container_add (GTK_CONTAINER (row_grid), image); + g_object_set (image, "margin", 6, NULL); + + markup = g_strdup_printf ("<b>%s</b>", name); + label = gtk_label_new (NULL); + gtk_widget_show (label); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); + gtk_label_set_xalign (GTK_LABEL (label), 0.0f); + gtk_label_set_markup (GTK_LABEL (label), markup); + gtk_container_add (GTK_CONTAINER (row_grid), label); + + /* Check if the row should be shown initially */ + features = goa_provider_get_provider_features (provider); + + if ((features & GOA_PROVIDER_FEATURE_BRANDED) != 0) + gtk_widget_show (row); + + gtk_container_add (GTK_CONTAINER (self->providers_listbox), row); + + g_free (markup); + g_free (name); + g_object_unref (icon); +} + +static gint +sort_providers_func (GtkListBoxRow *a, + GtkListBoxRow *b, + gpointer user_data) +{ + GoaProvider *a_provider, *b_provider; + CcGoaPanel *self; + gboolean a_branded, b_branded; + + self = user_data; + + if (a == self->more_providers_row) + return 1; + else if (b == self->more_providers_row) + return -1; + + a_provider = g_object_get_data (G_OBJECT (a), "goa-provider"); + b_provider = g_object_get_data (G_OBJECT (b), "goa-provider"); + + a_branded = (goa_provider_get_provider_features (a_provider) & GOA_PROVIDER_FEATURE_BRANDED) != 0; + b_branded = (goa_provider_get_provider_features (b_provider) & GOA_PROVIDER_FEATURE_BRANDED) != 0; + + if (a_branded != b_branded) + { + if (a_branded) + return -1; + else + return 1; + } + + return gtk_list_box_row_get_index (b) - gtk_list_box_row_get_index (a); +} + +static void +show_non_branded_providers (CcGoaPanel *self) +{ + GList *children, *l; + + children = gtk_container_get_children (GTK_CONTAINER (self->providers_listbox)); + + for (l = children; l != NULL; l = l->next) + { + GoaProvider *provider = g_object_get_data (l->data, "goa-provider"); + + if (!provider) + continue; + + if ((goa_provider_get_provider_features (provider) & GOA_PROVIDER_FEATURE_BRANDED) == 0) + gtk_widget_show (l->data); + } + + gtk_widget_hide (GTK_WIDGET (self->more_providers_row)); + + g_list_free (children); +} + +static void +add_account (CcGoaPanel *self, + GoaProvider *provider) +{ + GoaObject *object; + g_autoptr(GError) error = NULL; + + gtk_container_foreach (GTK_CONTAINER (self->new_account_vbox), + (GtkCallback) gtk_widget_destroy, + NULL); + + reset_headerbar (self); + + /* Move to the new account page */ + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->new_account_vbox)); + + /* Reset the dialog size */ + gtk_window_resize (GTK_WINDOW (self->edit_account_dialog), 1, 1); + + /* This spins gtk_dialog_run() */ + object = goa_provider_add_account (provider, + self->client, + self->edit_account_dialog, + self->new_account_vbox, + &error); + + if (object == NULL) + gtk_widget_hide (GTK_WIDGET (self->edit_account_dialog)); + else + show_page_account (self, object); +} + +static void +on_provider_row_activated (CcGoaPanel *self, + GtkListBoxRow *activated_row) +{ + GoaProvider *provider; + + /* Show More row */ + if (activated_row == self->more_providers_row) + { + show_non_branded_providers (self); + return; + } + + provider = g_object_get_data (G_OBJECT (activated_row), "goa-provider"); + + add_account (self, provider); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gint +sort_func (GtkListBoxRow *a, + GtkListBoxRow *b, + gpointer user_data) +{ + GoaObject *a_obj, *b_obj; + GoaAccount *a_account, *b_account; + + a_obj = g_object_get_data (G_OBJECT (a), "goa-object"); + a_account = goa_object_peek_account (a_obj); + + b_obj = g_object_get_data (G_OBJECT (b), "goa-object"); + b_account = goa_object_peek_account (b_obj); + + return g_strcmp0 (goa_account_get_id (a_account), goa_account_get_id (b_account)); +} + +static void +command_add (CcGoaPanel *panel, + GVariant *parameters) +{ + GVariant *v = NULL; + GoaProvider *provider = NULL; + const gchar *provider_name = NULL; + + g_assert (panel != NULL); + g_assert (parameters != NULL); + + switch (g_variant_n_children (parameters)) + { + case 2: + g_variant_get_child (parameters, 1, "v", &v); + if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)) + provider_name = g_variant_get_string (v, NULL); + else + g_warning ("Wrong type for the second argument (provider name) GVariant, expected 's' but got '%s'", + (gchar *)g_variant_get_type (v)); + g_variant_unref (v); + break; + default: + g_warning ("Unexpected parameters found, ignore request"); + goto out; + } + + if (provider_name != NULL) + { + provider = goa_provider_get_for_provider_type (provider_name); + if (provider == NULL) + { + g_warning ("Unable to get a provider for type '%s'", provider_name); + goto out; + } + + add_account (panel, provider); + } + +out: + g_clear_object (&provider); +} + +static void +cc_goa_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + case PROP_PARAMETERS: + { + GVariant *parameters, *v; + const gchar *first_arg = NULL; + + parameters = g_value_get_variant (value); + if (parameters == NULL) + return; + + if (g_variant_n_children (parameters) > 0) + { + g_variant_get_child (parameters, 0, "v", &v); + if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)) + first_arg = g_variant_get_string (v, NULL); + else + g_warning ("Wrong type for the second argument GVariant, expected 's' but got '%s'", + (gchar *)g_variant_get_type (v)); + g_variant_unref (v); + } + + if (g_strcmp0 (first_arg, "add") == 0) + command_add (CC_GOA_PANEL (object), parameters); + else if (first_arg != NULL) + select_account_by_id (CC_GOA_PANEL (object), first_arg); + + return; + } + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +cc_goa_panel_dispose (GObject *object) +{ + CcGoaPanel *panel = CC_GOA_PANEL (object); + + /* Must be destroyed in dispose, not finalize. */ + g_clear_pointer ((GtkWidget **) &panel->edit_account_dialog, gtk_widget_destroy); + + G_OBJECT_CLASS (cc_goa_panel_parent_class)->dispose (object); +} + +static void +cc_goa_panel_finalize (GObject *object) +{ + CcGoaPanel *panel = CC_GOA_PANEL (object); + + if (panel->removed_object != NULL) + { + g_autoptr(GError) error = NULL; + goa_account_call_remove_sync (goa_object_peek_account (panel->removed_object), + NULL, /* GCancellable */ + &error); + + if (error != NULL) + { + g_warning ("Error removing account: %s (%s, %d)", + error->message, + g_quark_to_string (error->domain), + error->code); + } + } + + g_clear_object (&panel->client); + + G_OBJECT_CLASS (cc_goa_panel_parent_class)->finalize (object); +} + +static void +cc_goa_panel_init (CcGoaPanel *panel) +{ + GNetworkMonitor *monitor; + g_autoptr(GError) error = NULL; + + g_resources_register (cc_online_accounts_get_resource ()); + + gtk_widget_init_template (GTK_WIDGET (panel)); + + gtk_list_box_set_header_func (panel->accounts_listbox, + cc_list_box_update_header_func, + NULL, + NULL); + gtk_list_box_set_sort_func (panel->accounts_listbox, + sort_func, + panel, + NULL); + + gtk_list_box_set_header_func (panel->providers_listbox, + cc_list_box_update_header_func, + NULL, + NULL); + gtk_list_box_set_sort_func (panel->providers_listbox, + sort_providers_func, + panel, + NULL); + + monitor = g_network_monitor_get_default(); + + g_object_bind_property (monitor, "network-available", + panel->offline_label, "visible", + G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + + g_object_bind_property (monitor, "network-available", + panel->providers_listbox, "sensitive", + G_BINDING_SYNC_CREATE); + + /* TODO: probably want to avoid _sync() ... */ + panel->client = goa_client_new_sync (cc_panel_get_cancellable (CC_PANEL (panel)), &error); + if (panel->client == NULL) + { + g_warning ("Error getting a GoaClient: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); + gtk_widget_set_sensitive (GTK_WIDGET (panel), FALSE); + return; + } + + g_signal_connect (panel->client, + "account-added", + G_CALLBACK (on_account_added), + panel); + + g_signal_connect (panel->client, + "account-changed", + G_CALLBACK (on_account_changed), + panel); + + g_signal_connect (panel->client, + "account-removed", + G_CALLBACK (on_account_removed), + panel); + + fill_accounts_listbox (panel); + + gtk_widget_show (GTK_WIDGET (panel)); +} + +static const char * +cc_goa_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/accounts"; +} + +static void +cc_goa_panel_constructed (GObject *object) +{ + CcGoaPanel *self = CC_GOA_PANEL (object); + GtkWindow *parent; + + /* Setup account editor dialog */ + parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)))); + + gtk_window_set_transient_for (GTK_WINDOW (self->edit_account_dialog), parent); + + goa_provider_get_all (get_all_providers_cb, g_object_ref_sink (self)); + + G_OBJECT_CLASS (cc_goa_panel_parent_class)->constructed (object); +} + +static void +cc_goa_panel_class_init (CcGoaPanelClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + panel_class->get_help_uri = cc_goa_panel_get_help_uri; + + object_class->set_property = cc_goa_panel_set_property; + object_class->finalize = cc_goa_panel_finalize; + object_class->constructed = cc_goa_panel_constructed; + object_class->dispose = cc_goa_panel_dispose; + + g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters"); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/online-accounts/online-accounts.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, accounts_frame); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, accounts_listbox); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, accounts_vbox); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, edit_account_dialog); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, edit_account_headerbar); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, editor_box); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, more_providers_row); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, new_account_vbox); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, notification_label); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, notification_revealer); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, offline_label); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, providers_listbox); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, remove_account_button); + gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, stack); + + gtk_widget_class_bind_template_callback (widget_class, on_edit_account_dialog_delete_event); + gtk_widget_class_bind_template_callback (widget_class, on_listbox_row_activated); + gtk_widget_class_bind_template_callback (widget_class, on_notification_closed); + gtk_widget_class_bind_template_callback (widget_class, on_provider_row_activated); + gtk_widget_class_bind_template_callback (widget_class, on_remove_button_clicked); + gtk_widget_class_bind_template_callback (widget_class, on_undo_button_clicked); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +show_page_nothing_selected (CcGoaPanel *panel) +{ +} + +static void +show_page_account (CcGoaPanel *panel, + GoaObject *object) +{ + GList *children; + GList *l; + GoaProvider *provider; + GoaAccount *account; + gboolean is_locked; + const gchar *provider_name; + const gchar *provider_type; + gchar *title; + + provider = NULL; + + panel->active_object = object; + reset_headerbar (panel); + + /* Move to the account editor page */ + gtk_stack_set_visible_child (panel->stack, GTK_WIDGET (panel->editor_box)); + + /* Out with the old */ + children = gtk_container_get_children (GTK_CONTAINER (panel->accounts_vbox)); + for (l = children; l != NULL; l = l->next) + gtk_container_remove (GTK_CONTAINER (panel->accounts_vbox), GTK_WIDGET (l->data)); + g_list_free (children); + + account = goa_object_peek_account (object); + + is_locked = goa_account_get_is_locked (account); + gtk_widget_set_visible (GTK_WIDGET (panel->remove_account_button), !is_locked); + + provider_type = goa_account_get_provider_type (account); + provider = goa_provider_get_for_provider_type (provider_type); + + if (provider != NULL) + { + goa_provider_show_account (provider, + panel->client, + object, + panel->accounts_vbox, + NULL, + NULL); + /* + * The above call doesn't set any widgets to visible, so we have to do that. + * https://gitlab.gnome.org/GNOME/gnome-online-accounts/issues/56 + */ + gtk_widget_show_all (GTK_WIDGET (panel->accounts_vbox)); + } + + provider_name = goa_account_get_provider_name (account); + /* translators: This is the title of the "Show Account" dialog. The + * %s is the name of the provider. e.g., 'Google'. */ + title = g_strdup_printf (_("%s Account"), provider_name); + gtk_header_bar_set_title (panel->edit_account_headerbar, title); + g_free (title); + + /* Reset the dialog size */ + gtk_window_resize (GTK_WINDOW (panel->edit_account_dialog), 1, 1); + + gtk_widget_show (GTK_WIDGET (panel->accounts_vbox)); + gtk_widget_show (GTK_WIDGET (panel->edit_account_dialog)); + + g_clear_object (&provider); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +select_account_by_id (CcGoaPanel *panel, + const gchar *account_id) +{ + GList *children, *l; + + children = gtk_container_get_children (GTK_CONTAINER (panel->accounts_listbox)); + + for (l = children; l != NULL; l = l->next) + { + GoaAccount *account; + GoaObject *row_object; + + row_object = g_object_get_data (l->data, "goa-object"); + account = goa_object_peek_account (row_object); + + if (g_strcmp0 (goa_account_get_id (account), account_id) == 0) + { + show_page_account (panel, row_object); + break; + } + } + + g_list_free (children); +} + +static gboolean +on_edit_account_dialog_delete_event (CcGoaPanel *self) +{ + self->active_object = NULL; + gtk_widget_hide (GTK_WIDGET (self->edit_account_dialog)); + return TRUE; +} + +static void +on_listbox_row_activated (CcGoaPanel *self, + GtkListBoxRow *activated_row) +{ + GoaObject *object; + + object = g_object_get_data (G_OBJECT (activated_row), "goa-object"); + show_page_account (self, object); +} + +static void +fill_accounts_listbox (CcGoaPanel *self) +{ + GList *accounts, *l; + + accounts = goa_client_get_accounts (self->client); + + if (accounts == NULL) + { + show_page_nothing_selected (self); + } + else + { + for (l = accounts; l != NULL; l = l->next) + on_account_added (self->client, l->data, self); + } + + g_list_free_full (accounts, g_object_unref); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef void (*RowForAccountCallback) (CcGoaPanel *self, GtkWidget *row, GList *other_rows); + +static void +hide_row_for_account (CcGoaPanel *self, GtkWidget *row, GList *other_rows) +{ + gtk_widget_hide (row); + gtk_widget_set_visible (GTK_WIDGET (self->accounts_frame), other_rows != NULL); +} + +static void +remove_row_for_account (CcGoaPanel *self, GtkWidget *row, GList *other_rows) +{ + gtk_widget_destroy (row); + gtk_widget_set_visible (GTK_WIDGET (self->accounts_frame), other_rows != NULL); +} + +static void +show_row_for_account (CcGoaPanel *self, GtkWidget *row, GList *other_rows) +{ + gtk_widget_show (row); + gtk_widget_show (GTK_WIDGET (self->accounts_frame)); +} + +static void +modify_row_for_account (CcGoaPanel *self, + GoaObject *object, + RowForAccountCallback callback) +{ + GList *children, *l; + + children = gtk_container_get_children (GTK_CONTAINER (self->accounts_listbox)); + + for (l = children; l != NULL; l = l->next) + { + GoaObject *row_object; + + row_object = g_object_get_data (G_OBJECT (l->data), "goa-object"); + if (row_object == object) + { + GtkWidget *row = GTK_WIDGET (l->data); + + children = g_list_remove_link (children, l); + callback (self, row, children); + g_list_free (l); + break; + } + } + + g_list_free (children); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_account_added (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + CcGoaPanel *self = user_data; + GtkWidget *row, *icon, *label, *box; + GoaAccount *account; + GIcon *gicon; + gchar* title = NULL; + g_autoptr(GError) error = NULL; + + account = goa_object_peek_account (object); + + /* The main grid */ + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + gtk_widget_show (box); + + /* The provider icon */ + icon = gtk_image_new (); + gtk_widget_show (icon); + + gicon = g_icon_new_for_string (goa_account_get_provider_icon (account), &error); + if (error != NULL) + { + g_warning ("Error creating GIcon for account: %s (%s, %d)", + error->message, + g_quark_to_string (error->domain), + error->code); + } + else + { + gtk_image_set_from_gicon (GTK_IMAGE (icon), gicon, GTK_ICON_SIZE_DIALOG); + } + + g_object_set (icon, "margin", 6, NULL); + + gtk_container_add (GTK_CONTAINER (box), icon); + + /* The name of the provider */ + title = g_strdup_printf ("<b>%s</b>\n<small>%s</small>", + goa_account_get_provider_name (account), + goa_account_get_presentation_identity (account)); + + label = g_object_new (GTK_TYPE_LABEL, + "ellipsize", PANGO_ELLIPSIZE_END, + "label", title, + "xalign", 0.0, + "use-markup", TRUE, + "hexpand", TRUE, + NULL); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (box), label); + + /* "Needs attention" icon */ + icon = gtk_image_new_from_icon_name ("dialog-warning-symbolic", GTK_ICON_SIZE_BUTTON); + gtk_widget_hide (icon); + g_object_set (icon, "margin_end", 30, NULL); + g_object_bind_property (goa_object_peek_account (object), + "attention-needed", + icon, + "visible", + G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); + gtk_container_add (GTK_CONTAINER (box), icon); + + /* The row */ + row = gtk_list_box_row_new (); + gtk_widget_show (row); + g_object_set_data (G_OBJECT (row), "goa-object", object); + gtk_container_add (GTK_CONTAINER (row), box); + + /* Add to the listbox */ + gtk_container_add (GTK_CONTAINER (self->accounts_listbox), row); + gtk_widget_show (GTK_WIDGET (self->accounts_frame)); + + g_clear_pointer (&title, g_free); + g_clear_object (&gicon); +} + +static void +on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + CcGoaPanel *panel = CC_GOA_PANEL (user_data); + + if (panel->active_object != object) + return; + + show_page_account (panel, panel->active_object); +} + +static void +on_account_removed (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + CcGoaPanel *self = user_data; + modify_row_for_account (self, object, remove_row_for_account); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +get_all_providers_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(CcGoaPanel) self = user_data; + GList *providers; + GList *l; + g_autoptr(GError) error = NULL; + + providers = NULL; + if (!goa_provider_get_all_finish (&providers, res, &error)) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Failed to get GOA providers: %s", error->message); + + return; + } + + for (l = providers; l != NULL; l = l->next) + { + GoaProvider *provider; + provider = GOA_PROVIDER (l->data); + + add_provider_row (self, provider); + } + + g_list_free_full (providers, g_object_unref); +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +cancel_notification_timeout (CcGoaPanel *self) +{ + if (self->remove_account_timeout_id == 0) + return; + + g_source_remove (self->remove_account_timeout_id); + + self->remove_account_timeout_id = 0; +} + +static void +remove_account_cb (GoaAccount *account, + GAsyncResult *res, + gpointer user_data) +{ + CcGoaPanel *panel = CC_GOA_PANEL (user_data); + g_autoptr(GError) error = NULL; + + if (!goa_account_call_remove_finish (account, res, &error)) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error removing account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + g_object_unref (panel); +} + +static void +on_notification_closed (GtkButton *button, + CcGoaPanel *self) +{ + goa_account_call_remove (goa_object_peek_account (self->removed_object), + cc_panel_get_cancellable (CC_PANEL (self)), + (GAsyncReadyCallback) remove_account_cb, + g_object_ref (self)); + + gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); + + cancel_notification_timeout (self); + self->removed_object = NULL; +} + +static void +on_undo_button_clicked (GtkButton *button, + CcGoaPanel *self) +{ + /* Simply show the account row and hide the notification */ + modify_row_for_account (self, self->removed_object, show_row_for_account); + gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); + + cancel_notification_timeout (self); + self->removed_object = NULL; +} + +static gboolean +on_remove_account_timeout (gpointer user_data) +{ + on_notification_closed (NULL, user_data); + return G_SOURCE_REMOVE; +} + +static void +on_remove_button_clicked (CcGoaPanel *panel) +{ + GoaAccount *account; + g_autofree gchar *id = NULL; + g_autofree gchar *label = NULL; + + if (panel->active_object == NULL) + return; + + if (panel->removed_object != NULL) + on_notification_closed (NULL, panel); + + panel->removed_object = panel->active_object; + panel->active_object = NULL; + + account = goa_object_peek_account (panel->removed_object); + id = g_strdup_printf ("<b>%s</b>", goa_account_get_presentation_identity (account)); + /* Translators: The %s is the username (eg., debarshi.ray@gmail.com + * or rishi). + */ + label = g_strdup_printf (_("%s removed"), id); + gtk_label_set_markup (panel->notification_label, label); + gtk_revealer_set_reveal_child (panel->notification_revealer, TRUE); + + modify_row_for_account (panel, panel->removed_object, hide_row_for_account); + gtk_widget_hide (GTK_WIDGET (panel->edit_account_dialog)); + + panel->remove_account_timeout_id = g_timeout_add_seconds (10, on_remove_account_timeout, panel); +} diff --git a/panels/online-accounts/cc-online-accounts-panel.h b/panels/online-accounts/cc-online-accounts-panel.h new file mode 100644 index 0000000..68d5e93 --- /dev/null +++ b/panels/online-accounts/cc-online-accounts-panel.h @@ -0,0 +1,31 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: David Zeuthen <davidz@redhat.com> + */ + +#pragma once + +#include <shell/cc-panel.h> + +G_BEGIN_DECLS + +#define CC_TYPE_GOA_PANEL (cc_goa_panel_get_type ()) + +G_DECLARE_FINAL_TYPE (CcGoaPanel, cc_goa_panel, CC, GOA_PANEL, CcPanel) + +G_END_DECLS diff --git a/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in b/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in new file mode 100644 index 0000000..f30aff5 --- /dev/null +++ b/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in @@ -0,0 +1,21 @@ +[Desktop Entry] +Name=Online Accounts +Comment=Connect to your online accounts and decide what to use them for +Exec=gnome-control-center online-accounts +# Translators: Do NOT translate or transliterate this text (this is an icon file name)! +Icon=goa-panel +Terminal=false +Type=Application +NoDisplay=true +StartupNotify=true +Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-AccountSettings; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=Online Accounts +X-GNOME-Bugzilla-Version=@VERSION@ +# Translators: Search terms to find the Online Accounts panel. +# Do NOT translate or localize the semicolons! +# The list MUST also end with a semicolon! +# For ReadItLater and Pocket, see http://en.wikipedia.org/wiki/Pocket_(application) +Keywords=Google;Facebook;Twitter;Yahoo;Web;Online;Chat;Calendar;Mail;Contact;ownCloud;Kerberos;IMAP;SMTP;Pocket;ReadItLater; diff --git a/panels/online-accounts/icons/16x16/goa-panel.png b/panels/online-accounts/icons/16x16/goa-panel.png Binary files differnew file mode 100644 index 0000000..79af92c --- /dev/null +++ b/panels/online-accounts/icons/16x16/goa-panel.png diff --git a/panels/online-accounts/icons/22x22/goa-panel.png b/panels/online-accounts/icons/22x22/goa-panel.png Binary files differnew file mode 100644 index 0000000..90e3e35 --- /dev/null +++ b/panels/online-accounts/icons/22x22/goa-panel.png diff --git a/panels/online-accounts/icons/24x24/goa-panel.png b/panels/online-accounts/icons/24x24/goa-panel.png Binary files differnew file mode 100644 index 0000000..2bf182e --- /dev/null +++ b/panels/online-accounts/icons/24x24/goa-panel.png diff --git a/panels/online-accounts/icons/256x256/goa-panel.png b/panels/online-accounts/icons/256x256/goa-panel.png Binary files differnew file mode 100644 index 0000000..4ee2d0f --- /dev/null +++ b/panels/online-accounts/icons/256x256/goa-panel.png diff --git a/panels/online-accounts/icons/32x32/goa-panel.png b/panels/online-accounts/icons/32x32/goa-panel.png Binary files differnew file mode 100644 index 0000000..302f2d3 --- /dev/null +++ b/panels/online-accounts/icons/32x32/goa-panel.png diff --git a/panels/online-accounts/icons/48x48/goa-panel.png b/panels/online-accounts/icons/48x48/goa-panel.png Binary files differnew file mode 100644 index 0000000..7756b52 --- /dev/null +++ b/panels/online-accounts/icons/48x48/goa-panel.png diff --git a/panels/online-accounts/icons/meson.build b/panels/online-accounts/icons/meson.build new file mode 100644 index 0000000..7184824 --- /dev/null +++ b/panels/online-accounts/icons/meson.build @@ -0,0 +1,15 @@ +icon_sizes = [ + '16x16', + '22x22', + '24x24', + '32x32', + '48x48', + '256x256' +] + +foreach icon_size: icon_sizes + install_data( + join_paths(icon_size, 'goa-panel.png'), + install_dir: join_paths(control_center_icondir, 'hicolor', icon_size, 'apps') + ) +endforeach diff --git a/panels/online-accounts/meson.build b/panels/online-accounts/meson.build new file mode 100644 index 0000000..82f1d56 --- /dev/null +++ b/panels/online-accounts/meson.build @@ -0,0 +1,45 @@ +panels_list += cappletname +desktop = 'gnome-@0@-panel.desktop'.format(cappletname) + +desktop_in = configure_file( + input: desktop + '.in.in', + output: desktop + '.in', + configuration: desktop_conf +) + +i18n.merge_file( + desktop, + type: 'desktop', + input: desktop_in, + output: desktop, + po_dir: po_dir, + install: true, + install_dir: control_center_desktopdir +) + +sources = files('cc-online-accounts-panel.c') + +resource_data = files('online-accounts.ui') + +sources += gnome.compile_resources( + 'cc-' + cappletname + '-resources', + cappletname + '.gresource.xml', + c_name: 'cc_' + cappletname.underscorify(), + dependencies: resource_data, + export: true +) + +deps = common_deps + [ + goa_dep, + dependency('goa-backend-1.0', version: goa_req_version) +] + +panels_libs += static_library( + cappletname, + sources: sources, + include_directories: [ top_inc, common_inc ], + dependencies: deps, + c_args: cflags +) + +subdir('icons') diff --git a/panels/online-accounts/online-accounts.gresource.xml b/panels/online-accounts/online-accounts.gresource.xml new file mode 100644 index 0000000..b428394 --- /dev/null +++ b/panels/online-accounts/online-accounts.gresource.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/gnome/control-center/online-accounts"> + <file preprocess="xml-stripblanks">online-accounts.ui</file> + </gresource> +</gresources> diff --git a/panels/online-accounts/online-accounts.ui b/panels/online-accounts/online-accounts.ui new file mode 100644 index 0000000..c101964 --- /dev/null +++ b/panels/online-accounts/online-accounts.ui @@ -0,0 +1,252 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 3.0 --> + <template class="CcGoaPanel" parent="CcPanel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkOverlay"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child type="overlay"> + <object class="GtkRevealer" id="notification_revealer"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">center</property> + <property name="valign">start</property> + <property name="transition_type">slide-down</property> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="notification_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_markup">True</property> + </object> + </child> + <child> + <object class="GtkButton" id="undo_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Undo</property> + <signal name="clicked" handler="on_undo_button_clicked" object="CcGoaPanel" swapped="no" /> + </object> + </child> + <child> + <object class="GtkButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">none</property> + <signal name="clicked" handler="on_notification_closed" object="CcGoaPanel" swapped="no" /> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon-name">window-close-symbolic</property> + </object> + </child> + </object> + </child> + </object> + </child> + <style> + <class name="app-notification" /> + </style> + </object> + </child> + </object> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">never</property> + <property name="min_content_height">500</property> + <child> + <object class="HdyClamp"> + <property name="visible">True</property> + <property name="margin_top">32</property> + <property name="margin_bottom">32</property> + <property name="margin_start">12</property> + <property name="margin_end">12</property> + + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <property name="orientation">vertical</property> + <property name="hexpand">True</property> + + <child> + <object class="GtkLabel" id="accounts_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="wrap">True</property> + <property name="justify">center</property> + <property name="label" translatable="yes">Connect to your data in the cloud</property> + <property name="margin_bottom">20</property> + <attributes> + <attribute name="scale" value="1.66" /> + </attributes> + <accessibility> + <relation target="accounts_listbox" type="label-for"/> + </accessibility> + </object> + </child> + <child> + <object class="GtkLabel" id="offline_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="wrap">True</property> + <property name="label" translatable="yes">No internet connection — connect to set up new online accounts</property> + </object> + </child> + <child> + <object class="GtkFrame" id="accounts_frame"> + <property name="can_focus">False</property> + <child> + <object class="GtkListBox" id="accounts_listbox"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="selection_mode">none</property> + <signal name="row-activated" handler="on_listbox_row_activated" object="CcGoaPanel" swapped="yes" /> + <accessibility> + <relation target="accounts_label" type="labelled-by"/> + </accessibility> + </object> + </child> + </object> + </child> + <child> + <object class="GtkLabel" id="providers_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin-top">20</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Add an account</property> + <attributes> + <attribute name="weight" value="bold" /> + </attributes> + <accessibility> + <relation target="providers_listbox" type="label-for"/> + </accessibility> + </object> + </child> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkListBox" id="providers_listbox"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="selection_mode">none</property> + <signal name="row-activated" handler="on_provider_row_activated" object="CcGoaPanel" swapped="yes" /> + <accessibility> + <relation target="providers_label" type="labelled-by"/> + </accessibility> + <child> + <object class="GtkListBoxRow" id="more_providers_row"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="margin">22</property> + <property name="icon-name">view-more-symbolic</property> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </template> + <object class="GtkDialog" id="edit_account_dialog"> + <property name="can_focus">False</property> + <property name="type_hint">dialog</property> + <property name="use_header_bar">1</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <signal name="delete-event" handler="on_edit_account_dialog_delete_event" object="CcGoaPanel" swapped="yes" /> + <child type="titlebar"> + <object class="GtkHeaderBar" id="edit_account_headerbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="show_close_button">True</property> + </object> + </child> + <child internal-child="vbox"> + <object class="GtkBox"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="border_width">0</property> + <child> + <object class="GtkStack" id="stack"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="transition_type">crossfade</property> + <property name="homogeneous">False</property> + <child> + <object class="GtkBox" id="new_account_vbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + </child> + <child> + <object class="GtkBox" id="editor_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin-bottom">24</property> + <property name="spacing">42</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox" id="accounts_vbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + </object> + </child> + <child> + <object class="GtkButton" id="remove_account_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="margin-start">24</property> + <property name="margin-end">24</property> + <property name="valign">end</property> + <property name="halign">end</property> + <property name="label" translatable="yes">Remove Account</property> + <signal name="clicked" handler="on_remove_button_clicked" object="CcGoaPanel" swapped="yes" /> + <style> + <class name="destructive-action" /> + </style> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> +</interface> |