From 18d308be730a415d29f5ce8b635a74c514f93c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Wed, 28 Aug 2019 16:56:04 -0400 Subject: [PATCH] wizard: re-work account creation + Add backup page + Separate PIN/backup + Some renames + Add connect to JAMS Change-Id: Ia173231837d6ef560957d99728f1b87447319ccc --- data/net.jami.Jami.gschema.xml | 5 + src/accountcreationwizard.cpp | 448 +++++++++++++++++++---- src/accountcreationwizard.h | 6 +- src/chatview.cpp | 2 +- src/currentcallview.cpp | 2 +- src/generalsettingsview.cpp | 4 +- src/incomingcallview.cpp | 2 +- src/ring_client.cpp | 2 +- src/ringmainwindow.cpp | 31 +- src/utils/files.cpp | 2 +- src/utils/files.h | 2 +- ui/accountcreationwizard.ui | 632 ++++++++++++++++++++++++++++----- 12 files changed, 963 insertions(+), 175 deletions(-) diff --git a/data/net.jami.Jami.gschema.xml b/data/net.jami.Jami.gschema.xml index 21aaf268..cb443677 100644 --- a/data/net.jami.Jami.gschema.xml +++ b/data/net.jami.Jami.gschema.xml @@ -26,6 +26,11 @@ <summary>Display the chat to the rigth (default) or at the bottom.</summary> <description>If the chat pane is horizontal then the chat is displayed to the right of the video; otherwise it will be displayed bellow it.</description> </key> + <key name="never-show-backup-again" type="b"> + <default>false</default> + <summary>Never display the backup key window.</summary> + <description>At the end of the account creation, the wizard show a window to export the account's key. This boolean is used to avoid to show this window again</description> + </key> <key name="enable-display-links" type="b"> <default>true</default> <summary>Enable chatview to display external images.</summary> diff --git a/src/accountcreationwizard.cpp b/src/accountcreationwizard.cpp index 7ba97902..1ac27da2 100644 --- a/src/accountcreationwizard.cpp +++ b/src/accountcreationwizard.cpp @@ -30,6 +30,7 @@ #include "avatarmanipulation.h" #include "accountcreationwizard.h" #include "usernameregistrationbox.h" +#include "utils/files.h" struct _AccountCreationWizard { @@ -43,6 +44,13 @@ struct _AccountCreationWizardClass typedef struct _AccountCreationWizardPrivate AccountCreationWizardPrivate; +enum class Mode { + ADD_LOCAL, + IMPORT_FROM_DEVICE, + IMPORT_FROM_BACKUP, + CONNECT_TO_MANAGER +}; + struct _AccountCreationWizardPrivate { AccountInfoPointer const *accountInfo_ = nullptr; @@ -58,15 +66,21 @@ struct _AccountCreationWizardPrivate GtkWidget *choose_account_type_vbox; GtkWidget *choose_account_type_ring_logo; GtkWidget *button_new_account; - GtkWidget *button_existing_account; - GtkWidget *button_wizard_cancel; + GtkWidget *button_import_from_device; + GtkWidget *button_import_from_backup; GtkWidget *button_show_advanced; + GtkWidget *button_connect_account_manager; GtkWidget *button_new_sip_account; /* existing account */ GtkWidget *existing_account; - GtkWidget *button_existing_account_next; - GtkWidget *button_existing_account_previous; + GtkWidget *existing_account_label; + GtkWidget *row_archive; + GtkWidget *row_pin; + GtkWidget *button_pin_info; + GtkWidget *row_pin_label; + GtkWidget *button_import_from_next; + GtkWidget *button_import_from_previous; GtkWidget *entry_existing_account_pin; GtkWidget *entry_existing_account_archive; GtkWidget *entry_existing_account_password; @@ -93,12 +107,33 @@ struct _AccountCreationWizardPrivate /* registering_username_spinner */ GtkWidget *vbox_registering_username_spinner; + /* backup */ + GtkWidget *info_backup; + GtkWidget *button_never_show_again; + GtkWidget *button_export_account; + GtkWidget *button_skip_backup; + GtkWidget *button_backup_info; + GtkWidget *row_backup_label; + /* error_view */ GtkWidget *error_view; + GtkWidget *label_error_view; GtkWidget *button_error_view_ok; + /* connect to account_manager */ + GtkWidget *connect_to_account_manager; + GtkWidget *entry_account_manager_username; + GtkWidget *entry_account_manager_password; + GtkWidget *entry_account_manager_uri; + GtkWidget *button_account_manager_connect_previous; + GtkWidget *button_account_manager_connect_next; + lrc::api::AVModel* avModel_; + lrc::api::NewAccountModel* accountModel_; + + Mode mode; + GSettings *settings; }; G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_TYPE_SCROLLED_WINDOW); @@ -107,7 +142,8 @@ G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_T /* signals */ enum { - ACCOUNT_CREATION_CANCELED, + ACCOUNT_CREATION_LOCK, + ACCOUNT_CREATION_UNLOCK, ACCOUNT_CREATION_COMPLETED, LAST_SIGNAL }; @@ -120,6 +156,9 @@ account_creation_wizard_dispose(GObject *object) // make sure preview is stopped and destroyed account_creation_wizard_show_preview(ACCOUNT_CREATION_WIZARD(object), FALSE); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(object); + g_clear_object(&priv->settings); + G_OBJECT_CLASS(account_creation_wizard_parent_class)->dispose(object); } @@ -127,6 +166,14 @@ static void account_creation_wizard_init(AccountCreationWizard *view) { gtk_widget_init_template(GTK_WIDGET(view)); + + auto *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + priv->settings = g_settings_new_full(get_settings_schema(), NULL, NULL); + + + g_settings_bind(priv->settings, "never-show-backup-again", + priv->button_never_show_again, "active", + G_SETTINGS_BIND_DEFAULT); } static void @@ -143,15 +190,21 @@ account_creation_wizard_class_init(AccountCreationWizardClass *klass) gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_vbox); gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_ring_logo); gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_account); - gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account); - gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_wizard_cancel); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_import_from_device); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_import_from_backup); gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_show_advanced); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_connect_account_manager); gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_sip_account); /* existing account */ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account); - gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_next); - gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_previous); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account_label); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, row_archive); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, row_pin); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_pin_info); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, row_pin_label); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_import_from_next); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_import_from_previous); gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_pin); gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_archive); gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_password); @@ -175,10 +228,27 @@ account_creation_wizard_class_init(AccountCreationWizardClass *klass) /* registering_username_spinner */ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_registering_username_spinner); + /* info backup */ + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, info_backup); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_never_show_again); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_export_account); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, row_backup_label); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_backup_info); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_skip_backup); + /* error view */ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, error_view); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, label_error_view); gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_error_view_ok); + /* connect to account_manager */ + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, connect_to_account_manager); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_account_manager_username); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_account_manager_password); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_account_manager_uri); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_manager_connect_previous); + gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_manager_connect_next); + /* add signals */ account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED] = g_signal_new("account-creation-completed", G_TYPE_FROM_CLASS(klass), @@ -189,7 +259,16 @@ account_creation_wizard_class_init(AccountCreationWizardClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED] = g_signal_new("account-creation-canceled", + account_creation_wizard_signals[ACCOUNT_CREATION_LOCK] = g_signal_new("account-creation-lock", + G_TYPE_FROM_CLASS(klass), + (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), + 0, + nullptr, + nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + account_creation_wizard_signals[ACCOUNT_CREATION_UNLOCK] = g_signal_new("account-creation-unlock", G_TYPE_FROM_CLASS(klass), (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), 0, @@ -202,13 +281,51 @@ account_creation_wizard_class_init(AccountCreationWizardClass *klass) void account_creation_show_error_view(AccountCreationWizard *view, const std::string& id) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); - if (priv->accountId && id == priv->accountId) + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + if (priv->accountId && id == priv->accountId) { + switch (priv->mode) { + case Mode::ADD_LOCAL: + gtk_label_set_text(GTK_LABEL(priv->label_error_view), + _("An error occured during the account creation.")); + break; + case Mode::IMPORT_FROM_DEVICE: + gtk_label_set_text(GTK_LABEL(priv->label_error_view), + _("Cannot retrieve any account, please verify your PIN and your password.")); + break; + case Mode::IMPORT_FROM_BACKUP: + gtk_label_set_text(GTK_LABEL(priv->label_error_view), + _("annot retrieve any account, please verify your archive and your password.")); + break; + case Mode::CONNECT_TO_MANAGER: + gtk_label_set_text(GTK_LABEL(priv->label_error_view), + _("Cannot connect to provided account manager. Please check your credentials.")); + break; + } gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->error_view); + } +} + +static gboolean +connect_to_manager(AccountCreationWizard *view, gchar* username, gchar* password, gchar* managerUri) +{ + g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(view), G_SOURCE_REMOVE); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_LOCK], 0); + + std::string accountId = lrc::api::NewAccountModel::connectToAccountManager( + username? username : "", + password? password : "", + managerUri? managerUri : ""); + priv->accountId = g_strdup(accountId.c_str()); + // NOTE: NewAccountModel::accountAdded will be triggered here and will call account_creation_wizard_account_added + + g_object_ref(view); // ref so its not destroyed too early + + return G_SOURCE_REMOVE; } static gboolean -create_ring_account(AccountCreationWizard *view, +create_account(AccountCreationWizard *view, gchar *display_name, gchar *username, gchar *password, @@ -216,7 +333,9 @@ create_ring_account(AccountCreationWizard *view, gchar *archivePath) { g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(view), G_SOURCE_REMOVE); - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + + g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_LOCK], 0); priv->username = g_strdup(username); priv->password = g_strdup(password); @@ -236,37 +355,43 @@ create_ring_account(AccountCreationWizard *view, } void -account_creation_wizard_account_added(AccountCreationWizard *view, AccountInfoPointer const & accountInfo) +account_creation_wizard_account_added(AccountCreationWizard *view, const std::string& id) { g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view)); - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); - priv->accountInfo_ = &accountInfo; - if ((*priv->accountInfo_)->id != priv->accountId) { + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + if (id != priv->accountId) { // Not for this account. Abort return; } // Register username if (priv->username) { - (*priv->accountInfo_)->accountModel->registerName(priv->accountId, priv->password, priv->username); + priv->accountModel_->registerName(priv->accountId, priv->password, priv->username); } // Set avatar if any. if (priv->avatar) { try { - (*priv->accountInfo_)->accountModel->setAvatar(priv->accountId, priv->avatar); + priv->accountModel_->setAvatar(priv->accountId, priv->avatar); } catch (std::out_of_range&) { g_warning("Can't set avatar for unknown account"); } } - g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0); + if (!g_settings_get_boolean(priv->settings, "never-show-backup-again") && priv->mode == Mode::ADD_LOCAL) { + gtk_button_set_label(GTK_BUTTON(priv->button_export_account), _("Export account")); + gtk_widget_show_all(priv->info_backup); + gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->info_backup); + } else { + g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0); + } + g_object_unref(view); } static gboolean -create_new_ring_account(AccountCreationWizard *win) +create_new_account(AccountCreationWizard *win) { g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE); - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); /* Tuleap: #1441 * if the user did not validate the avatar area selection, we still take that as the image @@ -281,7 +406,7 @@ create_new_ring_account(AccountCreationWizard *win) gtk_entry_set_text(GTK_ENTRY(priv->entry_password), ""); gtk_entry_set_text(GTK_ENTRY(priv->entry_password_confirm), ""); - auto status = create_ring_account(win, display_name, username, password, nullptr, nullptr); + auto status = create_account(win, display_name, username, password, nullptr, nullptr); // Now that we've use the preview to generate the avatar, we can safely close it. Don't // assume owner will do it for us, this might not always be the case @@ -294,11 +419,30 @@ create_new_ring_account(AccountCreationWizard *win) return status; } +static gboolean +connect_to_account_manager(AccountCreationWizard *win) +{ + g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); + + gchar *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_account_manager_username))); + gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_account_manager_password))); + gchar *managerUri = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_account_manager_uri))); + + auto status = connect_to_manager(win, username, password, managerUri); + + g_free(username); + g_free(password); + g_free(managerUri); + + return status; +} + static gboolean create_existing_ring_account(AccountCreationWizard *win) { g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE); - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password))); gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), ""); @@ -313,7 +457,7 @@ create_existing_ring_account(AccountCreationWizard *win) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive), nullptr); } - auto status = create_ring_account(win, NULL, NULL, password, pin, archive); + auto status = create_account(win, NULL, NULL, password, pin, archive); g_free(archive); g_free(password); @@ -325,14 +469,14 @@ create_existing_ring_account(AccountCreationWizard *win) static void show_generating_account_spinner(AccountCreationWizard *view) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_generating_account_spinner); } static void account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); /* Check for correct password */ const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password)); @@ -350,13 +494,25 @@ account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWi * happen freeze the client before the widget changes happen; * the timeout function should then display the next step in account creation */ - g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_ring_account, win, NULL); + g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_account, win, NULL); +} + +static void +connect_account_manager_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win) +{ + show_generating_account_spinner(win); + + /* now create account after a short timeout so that the the save doesn't + * happen freeze the client before the widget changes happen; + * the timeout function should then display the next step in account creation + */ + g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)connect_to_account_manager, win, NULL); } static void show_retrieving_account(AccountCreationWizard *win) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->retrieving_account); } @@ -375,16 +531,44 @@ existing_account_next_clicked(AccountCreationWizard *win) static void show_choose_account_type(AccountCreationWizard *view) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); /* Make sure other stack elements are hidden, otherwise their width will prevent the window to be correctly resized at this stage. */ gtk_widget_hide(priv->account_creation); gtk_widget_hide(priv->existing_account); + gtk_widget_hide(priv->connect_to_account_manager); gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->choose_account_type_vbox); } +static void +show_pin_label(AccountCreationWizard *view) +{ + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + gtk_widget_set_visible(priv->row_pin_label, !gtk_widget_is_visible(priv->row_pin_label)); +} + +static void +show_backup_label(AccountCreationWizard *view) +{ + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + gtk_widget_set_visible(priv->row_backup_label, !gtk_widget_is_visible(priv->row_backup_label)); +} + +static void +error_ok_clicked(AccountCreationWizard *view) +{ + g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_UNLOCK], 0); + show_choose_account_type(view); +} + +static void +skip_backup_clicked(AccountCreationWizard *view) +{ + g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0); +} + static void account_creation_previous_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view) { @@ -394,24 +578,64 @@ account_creation_previous_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreati } static void -show_existing_account(AccountCreationWizard *view) +connect_account_manager_previous_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view) +{ + show_choose_account_type(view); +} + +static void +show_import_from_device(AccountCreationWizard *view) +{ + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + + gtk_label_set_text(GTK_LABEL(priv->existing_account_label), _("Import from device")); + gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), ""); + gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), ""); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive), nullptr); + + gtk_widget_show_all(priv->existing_account); + gtk_widget_hide(priv->row_archive); + gtk_widget_hide(priv->row_pin_label); + gtk_widget_hide(priv->row_backup_label); + + gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account); + priv->mode = Mode::IMPORT_FROM_DEVICE; +} + +static void +show_import_from_backup(AccountCreationWizard *view) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + + gtk_label_set_text(GTK_LABEL(priv->existing_account_label), _("Import from backup")); + gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), ""); + gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), ""); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive), nullptr); + + gtk_widget_show_all(priv->existing_account); + gtk_widget_hide(priv->row_pin); + gtk_widget_hide(priv->row_pin_label); + gtk_widget_hide(priv->row_backup_label); - gtk_widget_show(priv->existing_account); gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account); + priv->mode = Mode::IMPORT_FROM_BACKUP; } static void -wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view) +show_connect_account_manager(AccountCreationWizard *view) { - account_creation_wizard_cancel(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + + gtk_widget_show(priv->connect_to_account_manager); + gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->connect_to_account_manager); + priv->mode = Mode::CONNECT_TO_MANAGER; } static void show_advanced(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + gtk_widget_set_visible(GTK_WIDGET(priv->button_connect_account_manager), !gtk_widget_is_visible(GTK_WIDGET(priv->button_connect_account_manager))); gtk_widget_set_visible(GTK_WIDGET(priv->button_new_sip_account), !gtk_widget_is_visible(GTK_WIDGET(priv->button_new_sip_account))); } @@ -426,7 +650,7 @@ create_new_sip_account(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *v static void entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationWizard *view) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); const gchar *pin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin)); gchar *archive_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive)); @@ -443,7 +667,7 @@ entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationW (not hasPin) ); gtk_widget_set_sensitive( - priv->button_existing_account_next, + priv->button_import_from_next, (hasArchive || hasPin) ); @@ -453,9 +677,8 @@ entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationW static void entries_new_account_changed(AccountCreationWizard *view) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); - const gchar *display_name = gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name)); const gchar *username = gtk_entry_get_text(GTK_ENTRY(priv->entry_username)); const gboolean sign_up_blockchain = gtk_switch_get_active(GTK_SWITCH(priv->switch_register)); @@ -472,10 +695,22 @@ entries_new_account_changed(AccountCreationWizard *view) } } +static void +entries_connect_account_manager_changed(AccountCreationWizard *view) +{ + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + + const std::string username = gtk_entry_get_text(GTK_ENTRY(priv->entry_account_manager_username)); + const std::string managerUri = gtk_entry_get_text(GTK_ENTRY(priv->entry_account_manager_uri)); + const std::string password = gtk_entry_get_text(GTK_ENTRY(priv->entry_account_manager_password)); + + gtk_widget_set_sensitive(priv->button_account_manager_connect_next, (!username.empty() && !managerUri.empty() && !password.empty())); +} + static void sign_up_blockchain_switched(GtkSwitch* switch_btn, GParamSpec*, AccountCreationWizard *view) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); gboolean sign_up_blockchain = gtk_switch_get_active(switch_btn); username_registration_box_set_use_blockchain( @@ -499,16 +734,90 @@ sign_up_blockchain_switched(GtkSwitch* switch_btn, GParamSpec*, AccountCreationW static void username_availability_changed(AccountCreationWizard *view, gboolean username_available) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); priv->username_available = username_available; entries_new_account_changed(view); } +// Export file static void -build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_button) +choose_export_file(AccountCreationWizard *view) { g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view)); - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); + // Get preferred path + GtkWidget* dialog; + GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE; + gint res; + gchar* filename = nullptr; + + dialog = gtk_file_chooser_dialog_new(_("Save File"), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))), + action, + _("_Cancel"), + GTK_RESPONSE_CANCEL, + _("_Save"), + GTK_RESPONSE_ACCEPT, + nullptr); + + const auto& accountInfo = priv->accountModel_->getAccountInfo(priv->accountId); + std::string alias = accountInfo.profileInfo.alias; + std::string uri = alias.empty()? "export.gz" : alias + ".gz"; + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), uri.c_str()); + res = gtk_dialog_run(GTK_DIALOG(dialog)); + + if (res == GTK_RESPONSE_ACCEPT) { + auto chooser = GTK_FILE_CHOOSER(dialog); + filename = gtk_file_chooser_get_filename(chooser); + } + gtk_widget_destroy(dialog); + + if (!filename) return; + + std::string password = {}; + auto prop = priv->accountModel_->getAccountConfig(priv->accountId); + if (prop.archiveHasPassword) { + auto* top_window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); + auto* password_dialog = gtk_message_dialog_new(top_window, + GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, + _("You need to enter your password to export the full archive.")); + gtk_window_set_title(GTK_WINDOW(password_dialog), _("Enter password to export archive")); + gtk_dialog_set_default_response(GTK_DIALOG(password_dialog), GTK_RESPONSE_OK); + + auto* message_area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(password_dialog)); + auto* password_entry = gtk_entry_new(); + gtk_entry_set_visibility(GTK_ENTRY(password_entry), false); + gtk_entry_set_invisible_char(GTK_ENTRY(password_entry), '*'); + gtk_box_pack_start(GTK_BOX(message_area), password_entry, true, true, 0); + gtk_widget_show_all(password_dialog); + + auto res = gtk_dialog_run(GTK_DIALOG(password_dialog)); + if (res == GTK_RESPONSE_OK) { + password = gtk_entry_get_text(GTK_ENTRY(password_entry)); + } else { + gtk_widget_destroy(password_dialog); + return; + } + + gtk_widget_destroy(password_dialog); + } + + // export account + auto success = priv->accountModel_->exportToFile(priv->accountId, filename, password); + std::string label = success? _("Account exported!") : _("Export account failure."); + gtk_button_set_label(GTK_BUTTON(priv->button_export_account), label.c_str()); + g_free(filename); + + if (success) { + g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0); + } +} + +static void +build_creation_wizard_view(AccountCreationWizard *view) +{ + g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view)); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); /* set ring logo */ GError *error = NULL; @@ -542,14 +851,12 @@ build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_but else gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), user_name); - /* cancel button */ - gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button); - /* choose_account_type signals */ g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(account_creation_wizard_show_preview), view); - g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account), view); - g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view); + g_signal_connect_swapped(priv->button_import_from_device, "clicked", G_CALLBACK(show_import_from_device), view); + g_signal_connect_swapped(priv->button_import_from_backup, "clicked", G_CALLBACK(show_import_from_backup), view); g_signal_connect(priv->button_show_advanced, "clicked", G_CALLBACK(show_advanced), view); + g_signal_connect_swapped(priv->button_connect_account_manager, "clicked", G_CALLBACK(show_connect_account_manager), view); g_signal_connect(priv->button_new_sip_account, "clicked", G_CALLBACK(create_new_sip_account), view); /* account_creation signals */ @@ -563,14 +870,28 @@ build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_but g_signal_connect_swapped(priv->username_registration_box, "username-availability-changed", G_CALLBACK(username_availability_changed), view); /* existing_account signals */ - g_signal_connect_swapped(priv->button_existing_account_previous, "clicked", G_CALLBACK(show_choose_account_type), view); - g_signal_connect_swapped(priv->button_existing_account_next, "clicked", G_CALLBACK(existing_account_next_clicked), view); + g_signal_connect_swapped(priv->button_import_from_previous, "clicked", G_CALLBACK(show_choose_account_type), view); + g_signal_connect_swapped(priv->button_pin_info, "clicked", G_CALLBACK(show_pin_label), view); + g_signal_connect_swapped(priv->button_import_from_next, "clicked", G_CALLBACK(existing_account_next_clicked), view); g_signal_connect(priv->entry_existing_account_pin, "changed", G_CALLBACK(entries_existing_account_changed), view); g_signal_connect(priv->entry_existing_account_archive, "file-set", G_CALLBACK(entries_existing_account_changed), view); g_signal_connect(priv->entry_existing_account_password, "changed", G_CALLBACK(entries_existing_account_changed), view); + /* Backup */ + g_signal_connect_swapped(priv->button_export_account, "clicked", G_CALLBACK(choose_export_file), view); + g_signal_connect_swapped(priv->button_skip_backup, "clicked", G_CALLBACK(skip_backup_clicked), view); + g_signal_connect_swapped(priv->button_backup_info, "clicked", G_CALLBACK(show_backup_label), view); + /* error_view signals */ - g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(show_choose_account_type), view); + g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(error_ok_clicked), view); + + + /* Connect to account_manager */ + g_signal_connect_swapped(priv->entry_account_manager_username, "changed", G_CALLBACK(entries_connect_account_manager_changed), view); + g_signal_connect_swapped(priv->entry_account_manager_password, "changed", G_CALLBACK(entries_connect_account_manager_changed), view); + g_signal_connect_swapped(priv->entry_account_manager_uri, "changed", G_CALLBACK(entries_connect_account_manager_changed), view); + g_signal_connect(priv->button_account_manager_connect_previous, "clicked", G_CALLBACK(connect_account_manager_previous_clicked), view); + g_signal_connect(priv->button_account_manager_connect_next, "clicked", G_CALLBACK(connect_account_manager_next_clicked), view); show_choose_account_type(view); @@ -579,7 +900,8 @@ build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_but auto provider = gtk_css_provider_new(); gtk_css_provider_load_from_data(provider, ".black { color: grey; font-size: 0.8em; }\ - .transparent-button { margin-left: 10px; border: 0; background-color: rgba(0,0,0,0); margin-right: 0; padding-right: 0;}", + .transparent-button { margin-left: 10px; border: 0; background-color: rgba(0,0,0,0); margin-right: 0; padding-right: 0;}\ + .infos-button { margin: 0; border: 0; background-color: rgba(0,0,0,0); padding: 0; box-shadow: 0;}", -1, nullptr ); gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()), @@ -588,21 +910,22 @@ build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_but } GtkWidget * -account_creation_wizard_new(bool show_cancel_button, lrc::api::AVModel& avModel) +account_creation_wizard_new(lrc::api::AVModel& avModel, lrc::api::NewAccountModel& accountModel) { gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL); auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view); priv->avModel_ = &avModel; + priv->accountModel_ = &accountModel; - build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button); + build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view)); return (GtkWidget *)view; } void account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_preview) { - AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); + auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win); if (priv->account_creation) { if (show_preview) @@ -610,6 +933,7 @@ account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_p else gtk_widget_hide(priv->account_creation); } + priv->mode = Mode::ADD_LOCAL; /* Similarily to general settings view, we construct and destroy the avatar manipulation widget each time the profile is made visible / hidden. While not the most elegant solution, this @@ -625,12 +949,4 @@ account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_p gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation); priv->avatar_manipulation = nullptr; } -} - -void -account_creation_wizard_cancel(AccountCreationWizard *win) -{ - // make sure to stop preview before doing something else - account_creation_wizard_show_preview(win, FALSE); - g_signal_emit(G_OBJECT(win), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0); -} +} \ No newline at end of file diff --git a/src/accountcreationwizard.h b/src/accountcreationwizard.h index 3e537ea2..c2f0e841 100644 --- a/src/accountcreationwizard.h +++ b/src/accountcreationwizard.h @@ -32,6 +32,7 @@ namespace lrc namespace api { class AVModel; + class NewAccountModel; } } @@ -47,11 +48,10 @@ typedef struct _AccountCreationWizard AccountCreationWizard; typedef struct _AccountCreationWizardClass AccountCreationWizardClass; GType account_creation_wizard_get_type (void) G_GNUC_CONST; -GtkWidget *account_creation_wizard_new (bool cancel_button, lrc::api::AVModel& avModel); +GtkWidget *account_creation_wizard_new (lrc::api::AVModel& avModel, lrc::api::NewAccountModel& accountModel); void account_creation_wizard_show_preview (AccountCreationWizard *win, gboolean show_preview = TRUE); -void account_creation_wizard_cancel (AccountCreationWizard *win); -void account_creation_wizard_account_added (AccountCreationWizard *view, AccountInfoPointer const & accountInfo); +void account_creation_wizard_account_added (AccountCreationWizard *view, const std::string& id); void account_creation_show_error_view (AccountCreationWizard *view, const std::string& id); G_END_DECLS diff --git a/src/chatview.cpp b/src/chatview.cpp index cf89a9bc..63842501 100644 --- a/src/chatview.cpp +++ b/src/chatview.cpp @@ -343,7 +343,7 @@ chat_view_init(ChatView *view) gtk_widget_init_template(GTK_WIDGET(view)); ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(view); - priv->settings = g_settings_new_full(get_ring_schema(), NULL, NULL); + priv->settings = g_settings_new_full(get_settings_schema(), NULL, NULL); } static void diff --git a/src/currentcallview.cpp b/src/currentcallview.cpp index 769b322a..2f81add2 100644 --- a/src/currentcallview.cpp +++ b/src/currentcallview.cpp @@ -947,7 +947,7 @@ CppImpl::insertControls() g_signal_connect(widgets->togglebutton_chat, "toggled", G_CALLBACK(on_togglebutton_chat_toggled), self); /* bind the chat orientation to the gsetting */ - widgets->settings = g_settings_new_full(get_ring_schema(), nullptr, nullptr); + widgets->settings = g_settings_new_full(get_settings_schema(), nullptr, nullptr); g_settings_bind_with_mapping(widgets->settings, "chat-pane-horizontal", widgets->paned_call, "orientation", G_SETTINGS_BIND_GET, diff --git a/src/generalsettingsview.cpp b/src/generalsettingsview.cpp index 445d5f19..1c0e9f85 100644 --- a/src/generalsettingsview.cpp +++ b/src/generalsettingsview.cpp @@ -198,7 +198,7 @@ change_prefered_directory (gchar * directory, GeneralSettingsView *self, gchar * g_return_if_fail(IS_GENERAL_SETTINGS_VIEW(self)); GeneralSettingsViewPrivate *priv = GENERAL_SETTINGS_VIEW_GET_PRIVATE(self); - priv->settings = g_settings_new_full(get_ring_schema(), NULL, NULL); + priv->settings = g_settings_new_full(get_settings_schema(), NULL, NULL); g_settings_set_value(priv->settings, id, g_variant_new("s", directory)); cb(self); } @@ -291,7 +291,7 @@ general_settings_view_init(GeneralSettingsView *self) GeneralSettingsViewPrivate *priv = GENERAL_SETTINGS_VIEW_GET_PRIVATE(self); - priv->settings = g_settings_new_full(get_ring_schema(), NULL, NULL); + priv->settings = g_settings_new_full(get_settings_schema(), NULL, NULL); GtkStyleContext* context; context = gtk_widget_get_style_context(GTK_WIDGET(priv->button_clear_history)); diff --git a/src/incomingcallview.cpp b/src/incomingcallview.cpp index c60e45b4..cfbeab3a 100644 --- a/src/incomingcallview.cpp +++ b/src/incomingcallview.cpp @@ -184,7 +184,7 @@ incoming_call_view_init(IncomingCallView *view) auto priv = INCOMING_CALL_VIEW_GET_PRIVATE(view); /* bind the chat orientation to the gsetting */ - priv->settings = g_settings_new_full(get_ring_schema(), NULL, NULL); + priv->settings = g_settings_new_full(get_settings_schema(), NULL, NULL); g_settings_bind_with_mapping(priv->settings, "chat-pane-horizontal", priv->paned_call, "orientation", G_SETTINGS_BIND_GET, diff --git a/src/ring_client.cpp b/src/ring_client.cpp index 2831dcba..d580ac86 100644 --- a/src/ring_client.cpp +++ b/src/ring_client.cpp @@ -604,7 +604,7 @@ ring_client_init(RingClient *self) priv->win = NULL; priv->qtapp = NULL; - priv->settings = g_settings_new_full(get_ring_schema(), NULL, NULL); + priv->settings = g_settings_new_full(get_settings_schema(), NULL, NULL); /* add custom cmd line options */ ring_client_add_options(G_APPLICATION(self)); diff --git a/src/ringmainwindow.cpp b/src/ringmainwindow.cpp index 57f6c64b..63475a40 100644 --- a/src/ringmainwindow.cpp +++ b/src/ringmainwindow.cpp @@ -371,6 +371,8 @@ public: std::string eventUid_; std::string eventBody_; + + bool isCreatingAccount {false}; private: CppImpl() = delete; CppImpl(const CppImpl&) = delete; @@ -519,9 +521,26 @@ on_account_creation_completed(RingMainWindow* self) { g_return_if_fail(IS_RING_MAIN_WINDOW(self)); auto* priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(self)); + priv->cpp->isCreatingAccount = false; priv->cpp->leaveAccountCreationWizard(); } +static void +on_account_creation_unlock(RingMainWindow* self) +{ + g_return_if_fail(IS_RING_MAIN_WINDOW(self)); + auto* priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(self)); + priv->cpp->isCreatingAccount = false; +} + +static void +on_account_creation_lock(RingMainWindow* self) +{ + g_return_if_fail(IS_RING_MAIN_WINDOW(self)); + auto* priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(self)); + priv->cpp->isCreatingAccount = true; +} + static void on_account_changed(RingMainWindow* self) { @@ -542,7 +561,7 @@ on_account_changed(RingMainWindow* self) if (g_strcmp0("", accountId) == 0) { priv->cpp->enterAccountCreationWizard(true); } else { - priv->cpp->leaveAccountCreationWizard(); + if (!priv->cpp->isCreatingAccount) priv->cpp->leaveAccountCreationWizard(); if (priv->cpp->accountInfo_ && changeTopAccount) { priv->cpp->accountInfo_->accountModel->setTopAccount(accountId); } @@ -1170,7 +1189,7 @@ CppImpl::init() [this](const std::string& id){ slotInvalidAccountFromLrc(id); }); /* bind to window size settings */ - widgets->settings = g_settings_new_full(get_ring_schema(), nullptr, nullptr); + widgets->settings = g_settings_new_full(get_settings_schema(), nullptr, nullptr); auto width = g_settings_get_int(widgets->settings, "window-width"); auto height = g_settings_get_int(widgets->settings, "window-height"); gtk_window_set_default_size(GTK_WINDOW(self), width, height); @@ -1654,9 +1673,13 @@ void CppImpl::enterAccountCreationWizard(bool showControls) { if (!widgets->account_creation_wizard) { - widgets->account_creation_wizard = account_creation_wizard_new(false, lrc_->getAVModel()); + widgets->account_creation_wizard = account_creation_wizard_new(lrc_->getAVModel(), lrc_->getAccountModel()); g_object_add_weak_pointer(G_OBJECT(widgets->account_creation_wizard), reinterpret_cast<gpointer*>(&widgets->account_creation_wizard)); + g_signal_connect_swapped(widgets->account_creation_wizard, "account-creation-lock", + G_CALLBACK(on_account_creation_lock), self); + g_signal_connect_swapped(widgets->account_creation_wizard, "account-creation-unlock", + G_CALLBACK(on_account_creation_unlock), self); g_signal_connect_swapped(widgets->account_creation_wizard, "account-creation-completed", G_CALLBACK(on_account_creation_completed), self); @@ -2000,7 +2023,7 @@ CppImpl::slotAccountAddedFromLrc(const std::string& id) auto old_view = gtk_stack_get_visible_child(GTK_STACK(widgets->stack_main_view)); if(IS_ACCOUNT_CREATION_WIZARD(old_view)) { // TODO finalize (set avatar + register name) - account_creation_wizard_account_added(ACCOUNT_CREATION_WIZARD(old_view), &account_info); + account_creation_wizard_account_added(ACCOUNT_CREATION_WIZARD(old_view), id); } if (!accountInfo_) { updateLrc(id); diff --git a/src/utils/files.cpp b/src/utils/files.cpp index 02b1c3e4..e78a6ca0 100644 --- a/src/utils/files.cpp +++ b/src/utils/files.cpp @@ -133,7 +133,7 @@ autostart_symlink(gboolean autostart) } GSettingsSchema * -get_ring_schema() +get_settings_schema() { static std::unique_ptr<GSettingsSchema, decltype(g_settings_schema_unref )&> ring_schema(nullptr, g_settings_schema_unref); diff --git a/src/utils/files.h b/src/utils/files.h index b3133146..5d2f2775 100644 --- a/src/utils/files.h +++ b/src/utils/files.h @@ -26,7 +26,7 @@ G_BEGIN_DECLS void autostart_symlink(gboolean autostart); -GSettingsSchema *get_ring_schema(); +GSettingsSchema *get_settings_schema(); G_END_DECLS diff --git a/ui/accountcreationwizard.ui b/ui/accountcreationwizard.ui index a443d74b..52892946 100644 --- a/ui/accountcreationwizard.ui +++ b/ui/accountcreationwizard.ui @@ -1,6 +1,18 @@ <?xml version="1.0" encoding="UTF-8"?> <interface> <requires lib="gtk+" version="3.10"/> + <object class="GtkImage" id="image-export-account"> + <property name="visible">True</property> + <property name="icon_name">document-save-symbolic</property> + </object> + <object class="GtkImage" id="image-infos-pin"> + <property name="visible">True</property> + <property name="icon_name">dialog-information-symbolic</property> + </object> + <object class="GtkImage" id="image-infos-backup"> + <property name="visible">True</property> + <property name="icon_name">dialog-information-symbolic</property> + </object> <template class="AccountCreationWizard" parent="GtkScrolledWindow"> <child> <object class="GtkScrolledWindow"> @@ -61,23 +73,25 @@ <property name="homogeneous">True</property> <child> <object class="GtkButton" id="button_new_account"> - <property name="label" translatable="yes">Create Jami Account</property> - <property name="tooltip_text" translatable="yes">Create a new Jami account (for new users)</property> + <property name="label" translatable="yes">Create local account</property> + <property name="tooltip_text" translatable="yes">Create a new Jami account on this device (for new users)</property> <property name="visible">True</property> <property name="can_focus">True</property> </object> </child> <child> - <object class="GtkButton" id="button_existing_account"> - <property name="label" translatable="yes">Import an existing account</property> - <property name="tooltip_text" translatable="yes">Import an account with your PIN or your account's archive</property> + <object class="GtkButton" id="button_import_from_device"> + <property name="label" translatable="yes">Import from device</property> + <property name="tooltip_text" translatable="yes">Import an account with your PIN generated on another device</property> <property name="visible">True</property> <property name="can_focus">True</property> </object> </child> <child> - <object class="GtkButton" id="button_wizard_cancel"> - <property name="label" translatable="yes">Cancel</property> + <object class="GtkButton" id="button_import_from_backup"> + <property name="label" translatable="yes">Import from archive backup</property> + <property name="tooltip_text" translatable="yes">Import an account via your archive</property> + <property name="visible">True</property> <property name="can_focus">True</property> </object> </child> @@ -92,6 +106,14 @@ </style> </object> </child> + <child> + <object class="GtkButton" id="button_connect_account_manager"> + <property name="label" translatable="yes">Connect to account manager</property> + <property name="tooltip_text" translatable="yes">Get your account via your credentials.</property> + <property name="visible">False</property> + <property name="can_focus">True</property> + </object> + </child> <child> <object class="GtkButton" id="button_new_sip_account"> <property name="label" translatable="yes">Add a new SIP account</property> @@ -104,141 +126,292 @@ </object> </child> <!-- End Choose account type wizard --> - <!-- Existing account wizard --> + <!-- Import existing --> <child> <object class="GtkBox" id="existing_account"> <property name="visible">False</property> <property name="valign">center</property> + <property name="halign">center</property> <property name="border_width">10</property> <property name="orientation">vertical</property> <property name="spacing">15</property> + <child> - <object class="GtkLabel"> + <object class="GtkLabel" id="existing_account_label"> <property name="visible">True</property> + <property name="halign">start</property> <property name="can_focus">False</property> - <property name="label" translatable="yes">Link this device to an existing account</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> </child> + <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="valign">center</property> - <property name="halign">center</property> - <property name="max-width-chars">80</property> - <property name="can_focus">True</property> - <property name="wrap">True</property> - <property name="justify">fill</property> - <property name="label" translatable="yes">To link this device to another account, you have two possibilities. You can import your account from the DHT, but first, you need to obtain a PIN code. To generate the PIN code, go to the account management setting of a previous device, choose the Jami Account to use and select "Link another device to this account". You will get the necessary PIN to complete this form. The PIN is only valid for 10 minutes. Or, you can directly import your account from an archive.</property> - </object> - </child> - <child> - <object class="GtkBox" id="vbox_existing_account_entry"> + <object class="GtkBox"> <property name="visible">True</property> - <property name="valign">center</property> - <property name="halign">center</property> + <property name="valign">end</property> <property name="orientation">vertical</property> - <property name="spacing">10</property> + <property name="spacing">8</property> <child> - <object class="GtkBox" id="import_hbox"> + <object class="GtkFrame"> <property name="visible">True</property> - <property name="valign">center</property> - <property name="halign">center</property> - <property name="border_width">10</property> - <property name="orientation">horizontal</property> - <property name="spacing">15</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">out</property> + <child> - <object class="GtkBox" id="import_by_pin"> + <!-- Export label --> + <object class="GtkListBox"> <property name="visible">True</property> - <property name="valign">center</property> - <property name="border_width">10</property> - <property name="orientation">vertical</property> - <property name="spacing">15</property> + <property name="can_focus">True</property> + <property name="halign">fill</property> + <property name="selection_mode">none</property> + <child> - <object class="GtkLabel"> + <!-- Password --> + <object class="GtkListBoxRow"> <property name="visible">True</property> - <property name="label" translatable="yes">Enter your pin:</property> + <property name="can_focus">True</property> + <property name="halign">fill</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="halign">fill</property> + <property name="orientation">horizontal</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <property name="spacing">10</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Password</property> + </object> + </child> + <child> + <object class="GtkEntry" id="entry_existing_account_password"> + <property name="halign">center</property> + <property name="width_request">320</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="xalign">0.5</property> + <property name="primary_icon_stock">gtk-dialog-authentication</property> + <property name="input_purpose">password</property> + <property name="visibility">False</property> + </object> + <packing> + <property name="pack_type">end</property> + </packing> + </child> + </object> + </child> </object> </child> + <child> - <object class="GtkEntry" id="entry_existing_account_pin"> - <property name="halign">center</property> - <property name="width-chars">40</property> + <!-- Account archive --> + <object class="GtkListBoxRow" id="row_archive"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="xalign">0.5</property> - <property name="primary_icon_stock">gtk-dialog-authentication</property> - <property name="input_purpose">password</property> + <property name="halign">fill</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="halign">fill</property> + <property name="orientation">horizontal</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <property name="spacing">10</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Archive</property> + </object> + </child> + <child> + <object class="GtkButton" id="button_backup_info"> + <property name="image">image-infos-backup</property> + <property name="tooltip_text" translatable="yes">Informations.</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">fill</property> + <property name="margin_right">10</property> + <style> + <class name="infos-button"/> + </style> + </object> + </child> + <child> + <object class="GtkFileChooserButton" id="entry_existing_account_archive"> + <property name="width_request">320</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">center</property> + <property name="title" translatable="yes"/> + </object> + <packing> + <property name="pack_type">end</property> + </packing> + </child> + </object> + </child> </object> </child> - </object> - </child> - <child> - <object class="GtkBox" id="import_by_file"> - <property name="visible">True</property> - <property name="valign">center</property> - <property name="border_width">10</property> - <property name="orientation">vertical</property> - <property name="spacing">15</property> + <child> - <object class="GtkLabel"> + <!-- PIN --> + <object class="GtkListBoxRow" id="row_pin"> <property name="visible">True</property> - <property name="label" translatable="yes">Or import a file:</property> + <property name="can_focus">True</property> + <property name="halign">fill</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="halign">fill</property> + <property name="orientation">horizontal</property> + <property name="margin_left">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <property name="spacing">10</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">PIN</property> + </object> + </child> + <child> + <object class="GtkButton" id="button_pin_info"> + <property name="image">image-infos-pin</property> + <property name="tooltip_text" translatable="yes">Informations.</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">fill</property> + <property name="margin_right">10</property> + <style> + <class name="infos-button"/> + </style> + </object> + </child> + <child> + <object class="GtkEntry" id="entry_existing_account_pin"> + <property name="halign">center</property> + <property name="width_request">320</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="xalign">0.5</property> + <property name="primary_icon_stock">gtk-dialog-authentication</property> + <property name="input_purpose">password</property> + <property name="margin_right">10</property> + </object> + <packing> + <property name="pack_type">end</property> + </packing> + </child> + </object> + </child> </object> </child> + <child> - <object class="GtkFileChooserButton" id="entry_existing_account_archive"> - <property name="width_request">320</property> + <!-- Label backup --> + <object class="GtkListBoxRow" id="row_backup_label"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="halign">center</property> - <property name="title" translatable="yes"/> + <property name="halign">fill</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="halign">fill</property> + <property name="orientation">horizontal</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <property name="spacing">10</property> + <property name="valign">center</property> + <property name="halign">center</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="wrap">True</property> + <property name="justify">fill</property> + <property name="max-width-chars">40</property> + <property name="label" translatable="yes">You can obtain an archive by clicking on "Export account" in the account settings. This will create a .gz file on your device.</property> + </object> + </child> + </object> + </child> </object> </child> + + <child> + <!-- Label PIN --> + <object class="GtkListBoxRow" id="row_pin_label"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">fill</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="halign">fill</property> + <property name="orientation">horizontal</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <property name="spacing">10</property> + <property name="valign">center</property> + <property name="halign">center</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="wrap">True</property> + <property name="justify">fill</property> + <property name="max-width-chars">40</property> + <property name="label" translatable="yes">To obtain a PIN (valid for 10 minutes), you need to open the account settings on the other device and click on "Link to another device".</property> + </object> + </child> + </object> + </child> + </object> + </child> + </object> </child> </object> </child> + </object> + </child> + + <child> + <object class="GtkButtonBox"> + <property name="visible">True</property> <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="label" translatable="yes">Enter your password:</property> - </object> - </child> - <child> - <object class="GtkEntry" id="entry_existing_account_password"> - <property name="halign">center</property> - <property name="width-chars">40</property> + <object class="GtkButton" id="button_import_from_previous"> + <property name="label" translatable="yes">Previous</property> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="xalign">0.5</property> - <property name="primary_icon_stock">gtk-dialog-authentication</property> - <property name="input_purpose">password</property> - <property name="visibility">False</property> + <property name="halign">start</property> </object> </child> <child> - <object class="GtkButtonBox"> + <object class="GtkButton" id="button_import_from_next"> + <property name="label" translatable="yes">Next</property> <property name="visible">True</property> - <child> - <object class="GtkButton" id="button_existing_account_previous"> - <property name="label" translatable="yes">Previous</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="halign">start</property> - </object> - </child> - <child> - <object class="GtkButton" id="button_existing_account_next"> - <property name="label" translatable="yes">Next</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="halign">end</property> - </object> - </child> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="halign">end</property> </object> </child> </object> @@ -343,7 +516,7 @@ <property name="orientation">vertical</property> <property name="spacing">8</property> <child> - <object class="GtkLabel" id="label_name_server"> + <object class="GtkLabel"> <property name="visible">True</property> <property name="halign">start</property> <property name="can_focus">False</property> @@ -573,6 +746,84 @@ </object> </child> <!-- End Generating account spinner --> + + <!-- Info backup --> + <child> + <object class="GtkBox" id="info_backup"> + <property name="visible">False</property> + <property name="valign">center</property> + <property name="halign">center</property> + <property name="border_width">10</property> + <property name="orientation">vertical</property> + <property name="spacing">15</property> + + + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="halign">start</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Backup your account!</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="valign">center</property> + <property name="halign">center</property> + <property name="justify">fill</property> + <property name="wrap">True</property> + <property name="max-width-chars">80</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">This account only exists on this device. If you lost your device or uninstall the application, your account will be deleted. You can backup your account now or later.</property> + </object> + </child> + + + <child> + <object class="GtkCheckButton" id="button_never_show_again"> + <property name="label" translatable="yes">Never show me this again</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">fill</property> + </object> + </child> + + + <child> + <object class="GtkButtonBox"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="button_export_account"> + <property name="label" translatable="yes">Export account</property> + <property name="image">image-export-account</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">fill</property> + </object> + </child> + <child> + <object class="GtkButton" id="button_skip_backup"> + <property name="label" translatable="yes">Skip</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">fill</property> + </object> + </child> + </object> + </child> + + </object> + </child> + <!-- End existing account wizard --> + <!-- Registering username spinner --> <child> <object class="GtkBox" id="vbox_registering_username_spinner"> @@ -637,14 +888,24 @@ <object class="GtkBox" id="error_view"> <property name="visible">True</property> <property name="valign">center</property> + <property name="halign">center</property> <property name="border_width">10</property> <property name="orientation">vertical</property> <property name="spacing">15</property> <child> - <object class="GtkLabel"> + <object class="GtkImage" id="image-error"> + <property name="visible">True</property> + <property name="icon_size">6</property> + <property name="icon_name">dialog-warning-symbolic</property> + </object> + </child> + <child> + <object class="GtkLabel" id="label_error_view"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="label" translatable="yes">Error creating/loading account.</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> </object> </child> <child> @@ -652,11 +913,194 @@ <property name="label" translatable="yes">OK</property> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="halign">center</property> </object> </child> </object> </child> <!-- End error view --> + + <!-- Connect to account manager --> + <child> + <object class="GtkBox" id="connect_to_account_manager"> + <property name="visible">False</property> + <property name="valign">center</property> + <property name="halign">center</property> + <property name="border_width">10</property> + <property name="orientation">vertical</property> + <property name="spacing">15</property> + + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="halign">start</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Sign in</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="valign">end</property> + <property name="orientation">vertical</property> + <property name="spacing">8</property> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">out</property> + <child> + <object class="GtkListBox"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">fill</property> + <property name="selection_mode">none</property> + <child> + <!-- entry username --> + <object class="GtkListBoxRow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">fill</property> + <child> + <object class="GtkBox" id="box_account_manager_username_entry"> + <property name="visible">True</property> + <property name="halign">fill</property> + <property name="orientation">horizontal</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Username</property> + </object> + </child> + <child> + <object class="GtkEntry" id="entry_account_manager_username"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="pack_type">end</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child> + <!-- Password --> + <object class="GtkListBoxRow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">fill</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="halign">fill</property> + <property name="orientation">horizontal</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <property name="spacing">10</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Password</property> + </object> + </child> + <child> + <object class="GtkEntry" id="entry_account_manager_password"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="primary_icon_stock">gtk-dialog-authentication</property> + <property name="visibility">False</property> + <property name="input_purpose">password</property> + </object> + <packing> + <property name="pack_type">end</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child> + <!-- Account Manager URL --> + <object class="GtkListBoxRow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">fill</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="halign">fill</property> + <property name="orientation">horizontal</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <property name="spacing">10</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Account manager</property> + </object> + </child> + <child> + <object class="GtkEntry" id="entry_account_manager_uri"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="pack_type">end</property> + </packing> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="GtkButtonBox"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="button_account_manager_connect_previous"> + <property name="label" translatable="yes">Previous</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">start</property> + </object> + </child> + <child> + <object class="GtkButton" id="button_account_manager_connect_next"> + <property name="label" translatable="yes">Next</property> + <property name="sensitive">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">end</property> + </object> + </child> + </object> + </child> + </object> + </child> + <!-- end account wizard --> </object> </child> </object> -- GitLab