blob: 60bae088895dc54e81c5849758ded39d8721d39f [file] [log] [blame]
aviau6aeb4852016-08-18 16:01:09 -04001/*
Guillaume Roguez77c579d2018-01-30 15:54:02 -05002 * Copyright (C) 2016-2018 Savoir-faire Linux Inc.
aviau6aeb4852016-08-18 16:01:09 -04003 * Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
Hugo Lefeuvre24356d42018-05-11 10:41:41 -04004 * Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com>
aviau6aeb4852016-08-18 16:01:09 -04005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
aviau6aeb4852016-08-18 16:01:09 -040021// GTK+ related
22#include <glib/gi18n.h>
23#include <gtk/gtk.h>
24
25// LRC
26#include <account.h>
27#include <codecmodel.h>
28#include <profilemodel.h>
29#include <profile.h>
30#include <accountmodel.h>
31#include <personmodel.h>
32
33// Ring Client
34#include "utils/models.h"
35#include "avatarmanipulation.h"
36#include "accountcreationwizard.h"
aviau2da3d9c2016-09-06 11:28:36 -040037#include "usernameregistrationbox.h"
aviau6aeb4852016-08-18 16:01:09 -040038
aviau6aeb4852016-08-18 16:01:09 -040039struct _AccountCreationWizard
40{
41 GtkBox parent;
42};
43
44struct _AccountCreationWizardClass
45{
46 GtkBoxClass parent_class;
47};
48
49typedef struct _AccountCreationWizardPrivate AccountCreationWizardPrivate;
50
51struct _AccountCreationWizardPrivate
52{
53 GtkWidget *stack_account_creation;
54 QMetaObject::Connection account_state_changed;
aviau2da3d9c2016-09-06 11:28:36 -040055 QMetaObject::Connection name_registration_ended;
56 gboolean username_available;
57
58 QString* password;
aviau692fe6d2016-11-08 14:37:34 -050059 QString* username;
aviau6aeb4852016-08-18 16:01:09 -040060
61 /* choose_account_type_vbox */
62 GtkWidget *choose_account_type_vbox;
63 GtkWidget *choose_account_type_ring_logo;
64 GtkWidget *button_new_account;
65 GtkWidget *button_existing_account;
66 GtkWidget *button_wizard_cancel;
67
Adrien Beraud50215a42017-09-15 20:24:52 +020068 /* existing account */
69 GtkWidget *existing_account;
70 GtkWidget *button_existing_account_next;
71 GtkWidget *button_existing_account_previous;
aviau6aeb4852016-08-18 16:01:09 -040072 GtkWidget *entry_existing_account_pin;
Adrien Beraud50215a42017-09-15 20:24:52 +020073 GtkWidget *entry_existing_account_archive;
aviau6aeb4852016-08-18 16:01:09 -040074 GtkWidget *entry_existing_account_password;
75 GtkWidget *retrieving_account;
76
77 /* account creation */
78 GtkWidget *account_creation;
aviau692fe6d2016-11-08 14:37:34 -050079 GtkWidget *entry_username;
aviau6aeb4852016-08-18 16:01:09 -040080 GtkWidget *entry_password;
81 GtkWidget *entry_password_confirm;
aviau6aeb4852016-08-18 16:01:09 -040082 GtkWidget *button_account_creation_next;
83 GtkWidget *button_account_creation_previous;
84 GtkWidget *box_avatarselection;
85 GtkWidget *avatar_manipulation;
86 GtkWidget *label_password_error;
aviau2da3d9c2016-09-06 11:28:36 -040087 GtkWidget *box_username_entry;
88 GtkWidget *checkbutton_sign_up_blockchain;
89 GtkWidget *username_registration_box;
aviau692fe6d2016-11-08 14:37:34 -050090 GtkWidget *entry_display_name;
aviau6aeb4852016-08-18 16:01:09 -040091
92 /* generating_account_spinner */
93 GtkWidget *vbox_generating_account_spinner;
94
aviau2da3d9c2016-09-06 11:28:36 -040095 /* registering_username_spinner */
96 GtkWidget *vbox_registering_username_spinner;
97
aviau6aeb4852016-08-18 16:01:09 -040098 /* error_view */
99 GtkWidget *error_view;
100 GtkWidget *button_error_view_ok;
101
102};
103
104G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_TYPE_BOX);
105
106#define ACCOUNT_CREATION_WIZARD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_CREATION_WIZARD_TYPE, AccountCreationWizardPrivate))
107
108/* signals */
109enum {
110 ACCOUNT_CREATION_CANCELED,
111 ACCOUNT_CREATION_COMPLETED,
112 LAST_SIGNAL
113};
114
115static guint account_creation_wizard_signals[LAST_SIGNAL] = { 0 };
116
117static void
aviau6aeb4852016-08-18 16:01:09 -0400118account_creation_wizard_dispose(GObject *object)
119{
120 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(object);
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400121
122 // make sure preview is stopped and destroyed
123 account_creation_wizard_show_preview(ACCOUNT_CREATION_WIZARD(object), FALSE);
124
aviau6aeb4852016-08-18 16:01:09 -0400125 QObject::disconnect(priv->account_state_changed);
126 G_OBJECT_CLASS(account_creation_wizard_parent_class)->dispose(object);
127}
128
129static void
130account_creation_wizard_init(AccountCreationWizard *view)
131{
132 gtk_widget_init_template(GTK_WIDGET(view));
133}
134
135static void
136account_creation_wizard_class_init(AccountCreationWizardClass *klass)
137{
138 G_OBJECT_CLASS(klass)->dispose = account_creation_wizard_dispose;
139
140 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
141 "/cx/ring/RingGnome/accountcreationwizard.ui");
142
143 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, stack_account_creation);
144
145 /* choose_account_type_vbox */
146 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_vbox);
147 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_ring_logo);
148 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_account);
149 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account);
150 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_wizard_cancel);
151
Adrien Beraud50215a42017-09-15 20:24:52 +0200152 /* existing account */
153 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account);
154 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_next);
155 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_previous);
aviau6aeb4852016-08-18 16:01:09 -0400156 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_pin);
Adrien Beraud50215a42017-09-15 20:24:52 +0200157 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_archive);
aviau6aeb4852016-08-18 16:01:09 -0400158 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_password);
159 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, retrieving_account);
160
161 /* account creation */
162 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, account_creation);
aviau6aeb4852016-08-18 16:01:09 -0400163 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password);
164 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password_confirm);
aviau6aeb4852016-08-18 16:01:09 -0400165 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_next);
166 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_previous);
167 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_avatarselection);
168 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, label_password_error);
aviau2da3d9c2016-09-06 11:28:36 -0400169 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_username_entry);
170 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, checkbutton_sign_up_blockchain);
aviau692fe6d2016-11-08 14:37:34 -0500171 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_display_name);
aviau6aeb4852016-08-18 16:01:09 -0400172
173 /* generating_account_spinner */
174 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_generating_account_spinner);
175
aviau2da3d9c2016-09-06 11:28:36 -0400176 /* registering_username_spinner */
177 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_registering_username_spinner);
178
aviau6aeb4852016-08-18 16:01:09 -0400179 /* error view */
180 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, error_view);
181 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_error_view_ok);
182
183 /* add signals */
184 account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED] = g_signal_new("account-creation-completed",
185 G_TYPE_FROM_CLASS(klass),
186 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
187 0,
188 nullptr,
189 nullptr,
190 g_cclosure_marshal_VOID__VOID,
191 G_TYPE_NONE, 0);
192
193 account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED] = g_signal_new("account-creation-canceled",
194 G_TYPE_FROM_CLASS(klass),
195 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
196 0,
197 nullptr,
198 nullptr,
199 g_cclosure_marshal_VOID__VOID,
200 G_TYPE_NONE, 0);
201}
202
203static void
204show_error_view(AccountCreationWizard *view)
205{
206 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
207 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->error_view);
208}
209
aviau2da3d9c2016-09-06 11:28:36 -0400210static void
211could_not_register_username_dialog(AccountCreationWizard *view)
212{
213 GtkWidget* dialog = gtk_message_dialog_new(
214 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))),
215 GTK_DIALOG_DESTROY_WITH_PARENT,
216 GTK_MESSAGE_ERROR,
217 GTK_BUTTONS_OK,
218 _("Your account was created, but we could not register your username. Try again from the settings menu.")
219 );
220 gtk_dialog_run(GTK_DIALOG (dialog));
221 gtk_widget_destroy(dialog);
222}
223
224static void
225show_registering_on_blockchain_spinner(AccountCreationWizard *view)
226{
227 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
228 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_registering_username_spinner);
229}
230
aviau6aeb4852016-08-18 16:01:09 -0400231static gboolean
232create_ring_account(AccountCreationWizard *view,
aviau692fe6d2016-11-08 14:37:34 -0500233 gchar *display_name,
234 gchar *username,
aviau6aeb4852016-08-18 16:01:09 -0400235 gchar *password,
Adrien Beraud50215a42017-09-15 20:24:52 +0200236 gchar *pin,
237 gchar *archivePath)
aviau6aeb4852016-08-18 16:01:09 -0400238{
aviau692fe6d2016-11-08 14:37:34 -0500239
aviau6aeb4852016-08-18 16:01:09 -0400240 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(view), G_SOURCE_REMOVE);
241 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
242
aviau2da3d9c2016-09-06 11:28:36 -0400243 // Copy password and alias, which will be used in our callbacks
aviau692fe6d2016-11-08 14:37:34 -0500244 priv->username = new QString(username);
aviau2da3d9c2016-09-06 11:28:36 -0400245 priv->password = new QString(password);
aviau2da3d9c2016-09-06 11:28:36 -0400246
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400247 g_object_ref(view); // ref so its not destroyed too early
aviau6aeb4852016-08-18 16:01:09 -0400248
249 /* create account and set UPnP enabled, as its not by default in the daemon */
250 Account *account = nullptr;
251
252 /* get profile (if so) */
253 auto profile = ProfileModel::instance().selectedProfile();
254
aviau692fe6d2016-11-08 14:37:34 -0500255 if (display_name && strlen(display_name) > 0) {
256 account = AccountModel::instance().add(display_name, Account::Protocol::RING);
aviau6aeb4852016-08-18 16:01:09 -0400257 if(profile && AccountModel::instance().size() == 1)
258 {
aviau692fe6d2016-11-08 14:37:34 -0500259 profile->person()->setFormattedName(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400260 }
261 } else {
262 auto unknown_alias = C_("The default username / account alias, if none is set by the user", "Unknown");
263 account = AccountModel::instance().add(unknown_alias, Account::Protocol::RING);
264 if (profile && AccountModel::instance().size() == 1)
265 {
266 profile->person()->setFormattedName(unknown_alias);
267 }
268 }
269
270 /* Set the archive password */
271 account->setArchivePassword(password);
272
273 /* Set the archive pin (existng accounts) */
274 if(pin)
275 {
276 account->setArchivePin(pin);
277 }
Adrien Beraud50215a42017-09-15 20:24:52 +0200278 if (archivePath)
279 {
280 account->setArchivePath(archivePath);
281 }
aviau6aeb4852016-08-18 16:01:09 -0400282
aviau692fe6d2016-11-08 14:37:34 -0500283 account->setDisplayName(display_name); // set the display name to the same as the alias
aviau6aeb4852016-08-18 16:01:09 -0400284
285 account->setUpnpEnabled(TRUE);
286
287 /* show error window if the account errors */
288 priv->account_state_changed = QObject::connect(
289 account,
290 &Account::stateChanged,
291 [=] (Account::RegistrationState state) {
292 switch(state)
293 {
294 case Account::RegistrationState::ERROR:
295 {
296 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
297 QObject::disconnect(priv->account_state_changed);
298 show_error_view(view);
299 g_object_unref(view);
300 break;
301 }
302 case Account::RegistrationState::READY:
303 case Account::RegistrationState::TRYING:
304 case Account::RegistrationState::UNREGISTERED:
305 {
306 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
307 QObject::disconnect(priv->account_state_changed);
308
309 account << Account::EditAction::RELOAD;
aviau2da3d9c2016-09-06 11:28:36 -0400310
311 // Now try to register the username
aviau692fe6d2016-11-08 14:37:34 -0500312 if (priv->username && !priv->username->isEmpty() && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->checkbutton_sign_up_blockchain)))
aviau2da3d9c2016-09-06 11:28:36 -0400313 {
314 priv->name_registration_ended = QObject::connect(
315 account,
316 &Account::nameRegistrationEnded,
317 [=] (NameDirectory::RegisterNameStatus status, G_GNUC_UNUSED const QString& name) {
318 QObject::disconnect(priv->name_registration_ended);
319 switch(status)
320 {
321 case NameDirectory::RegisterNameStatus::INVALID_NAME:
322 case NameDirectory::RegisterNameStatus::WRONG_PASSWORD:
323 case NameDirectory::RegisterNameStatus::ALREADY_TAKEN:
324 case NameDirectory::RegisterNameStatus::NETWORK_ERROR:
325 {
326 could_not_register_username_dialog(view);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400327 // Reload so that the username is displayed in the settings
328 account << Account::EditAction::RELOAD;
329 break;
aviau2da3d9c2016-09-06 11:28:36 -0400330 }
331 case NameDirectory::RegisterNameStatus::SUCCESS:
332 {
333 // Reload so that the username is displayed in the settings
334 account << Account::EditAction::RELOAD;
335 break;
336 }
337 }
338 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
339 g_object_unref(view);
340 }
341 );
342
343 show_registering_on_blockchain_spinner(view);
344
aviau692fe6d2016-11-08 14:37:34 -0500345 bool register_name_result = account->registerName(*priv->password, *priv->username);
346 priv->username->clear();
aviau2da3d9c2016-09-06 11:28:36 -0400347 priv->password->clear();
aviau2da3d9c2016-09-06 11:28:36 -0400348
349 if (register_name_result == FALSE)
350 {
351 g_debug("Could not initialize registerName operation");
352 could_not_register_username_dialog(view);
353 QObject::disconnect(priv->name_registration_ended);
354 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
355 g_object_unref(view);
356 }
357 }
358 else
359 {
360 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
361 g_object_unref(view);
362 }
aviau6aeb4852016-08-18 16:01:09 -0400363 break;
364 }
365 case Account::RegistrationState::INITIALIZING:
366 case Account::RegistrationState::COUNT__:
367 {
368 // Keep waiting...
369 break;
370 }
371 }
372 }
373 );
374
375 account->performAction(Account::EditAction::SAVE);
376 profile->save();
377
378 return G_SOURCE_REMOVE;
379}
380
381static gboolean
382create_new_ring_account(AccountCreationWizard *win)
383{
384 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
385 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
386
Stepan Salenikovichec16deb2017-04-14 14:18:37 -0400387 /* Tuleap: #1441
388 * if the user did not validate the avatar area selection, we still take that as the image
389 * for their avatar; otherwise many users end up with no avatar by default
390 * TODO: improve avatar creation process to not need this fix
391 */
392 avatar_manipulation_wizard_completed(AVATAR_MANIPULATION(priv->avatar_manipulation));
393
aviau692fe6d2016-11-08 14:37:34 -0500394 gchar *display_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name)));
395 gchar *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_username)));
aviau6aeb4852016-08-18 16:01:09 -0400396 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_password)));
397 gtk_entry_set_text(GTK_ENTRY(priv->entry_password), "");
398 gtk_entry_set_text(GTK_ENTRY(priv->entry_password_confirm), "");
399
Adrien Beraud50215a42017-09-15 20:24:52 +0200400 auto status = create_ring_account(win, display_name, username, password, nullptr, nullptr);
aviau6aeb4852016-08-18 16:01:09 -0400401
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400402 // Now that we've use the preview to generate the avatar, we can safely close it. Don't
403 // assume owner will do it for us, this might not always be the case
404 account_creation_wizard_show_preview(win, FALSE);
405
aviau692fe6d2016-11-08 14:37:34 -0500406 g_free(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400407 g_free(password);
aviau692fe6d2016-11-08 14:37:34 -0500408 g_free(username);
aviau6aeb4852016-08-18 16:01:09 -0400409
410 return status;
411}
412
413static gboolean
414create_existing_ring_account(AccountCreationWizard *win)
415{
416 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
417 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
418
419 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password)));
420 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), "");
421
Adrien Beraud50215a42017-09-15 20:24:52 +0200422 gchar *pin = nullptr;
423 auto curPin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
424 if (curPin and strlen(curPin) > 0) {
425 pin = g_strdup(curPin);
426 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), "");
427 }
aviau6aeb4852016-08-18 16:01:09 -0400428
Adrien Beraud50215a42017-09-15 20:24:52 +0200429 gchar *archive = nullptr;
430 auto archivePath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
431 if (archivePath) {
432 archive = g_strdup(archivePath);
433 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive), nullptr);
434 }
435
436 auto status = create_ring_account(win, NULL, NULL, password, pin, archive);
aviau6aeb4852016-08-18 16:01:09 -0400437
438 g_free(password);
439 g_free(pin);
440
441 return status;
442}
443
aviau6aeb4852016-08-18 16:01:09 -0400444static void
445show_generating_account_spinner(AccountCreationWizard *view)
446{
447 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
448 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_generating_account_spinner);
449}
450
451static void
452account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win)
453{
454 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
455
456 /* Check for correct password */
457 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
458 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
459
460 if (g_strcmp0(password, password_confirm) != 0)
461 {
aviau2da3d9c2016-09-06 11:28:36 -0400462 gtk_label_set_text(GTK_LABEL(priv->label_password_error), _("Passwords don't match"));
aviau6aeb4852016-08-18 16:01:09 -0400463 return;
464 }
465
466 show_generating_account_spinner(win);
467
468 /* now create account after a short timeout so that the the save doesn't
469 * happen freeze the client before the widget changes happen;
470 * the timeout function should then display the next step in account creation
471 */
472 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_ring_account, win, NULL);
473}
474
475static void
476show_retrieving_account(AccountCreationWizard *win)
477{
478 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
479 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->retrieving_account);
480}
481
482static void
Adrien Beraud50215a42017-09-15 20:24:52 +0200483existing_account_next_clicked(AccountCreationWizard *win)
aviau6aeb4852016-08-18 16:01:09 -0400484{
485 show_retrieving_account(win);
486
487 /* now create account after a short timeout so that the the save doesn't
488 * happen freeze the client before the widget changes happen;
489 * the timeout function should then display the next step in account creation
490 */
491 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_existing_ring_account, win, NULL);
492}
493
494static void
aviau6aeb4852016-08-18 16:01:09 -0400495show_choose_account_type(AccountCreationWizard *view)
496{
497 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
498 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->choose_account_type_vbox);
499}
500
501static void
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400502account_creation_previous_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
503{
504 // make sure to stop preview before going back to choose account type
505 account_creation_wizard_show_preview(view, FALSE);
506 show_choose_account_type(view);
507}
508
509static void
Adrien Beraud50215a42017-09-15 20:24:52 +0200510show_existing_account(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400511{
512 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200513 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account);
aviau6aeb4852016-08-18 16:01:09 -0400514}
515
516static void
aviau6aeb4852016-08-18 16:01:09 -0400517wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
518{
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400519 account_creation_wizard_cancel(view);
aviau6aeb4852016-08-18 16:01:09 -0400520}
521
522static void
523entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationWizard *view)
524{
525 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
526
527 const gchar *pin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
Adrien Beraud50215a42017-09-15 20:24:52 +0200528 const gchar *archive_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
529
530 bool hasPin = pin and strlen(pin) > 0;
531 bool hasArchive = archive_path and strlen(archive_path) > 0;
aviau6aeb4852016-08-18 16:01:09 -0400532
aviau16a94be2016-11-10 17:37:32 -0500533 gtk_widget_set_sensitive(
Adrien Beraud50215a42017-09-15 20:24:52 +0200534 priv->entry_existing_account_pin,
535 (not hasArchive)
536 );
537 gtk_widget_set_sensitive(
538 priv->entry_existing_account_archive,
539 (not hasPin)
540 );
541 gtk_widget_set_sensitive(
542 priv->button_existing_account_next,
543 (hasArchive || hasPin)
aviau16a94be2016-11-10 17:37:32 -0500544 );
aviau6aeb4852016-08-18 16:01:09 -0400545}
546
547static void
aviau2da3d9c2016-09-06 11:28:36 -0400548entries_new_account_changed(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400549{
550 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
551
aviau692fe6d2016-11-08 14:37:34 -0500552 const gchar *display_name = gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name));
553 const gchar *username = gtk_entry_get_text(GTK_ENTRY(priv->entry_username));
aviau2da3d9c2016-09-06 11:28:36 -0400554 const gboolean sign_up_blockchain = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->checkbutton_sign_up_blockchain));
aviau6aeb4852016-08-18 16:01:09 -0400555
aviau2da3d9c2016-09-06 11:28:36 -0400556 if (
aviau692fe6d2016-11-08 14:37:34 -0500557 strlen(display_name) > 0 && // Display name is longer than 0
aviau692fe6d2016-11-08 14:37:34 -0500558 (
559 (sign_up_blockchain && strlen(username) > 0 && priv->username_available) || // we are signing up, username is set and avaialble
560 !sign_up_blockchain // We are not signing up
561 )
aviau2da3d9c2016-09-06 11:28:36 -0400562 )
aviau6aeb4852016-08-18 16:01:09 -0400563 {
564 gtk_widget_set_sensitive(priv->button_account_creation_next, TRUE);
565 }
566 else
567 {
568 gtk_widget_set_sensitive(priv->button_account_creation_next, FALSE);
569 }
570}
571
572static void
aviau2da3d9c2016-09-06 11:28:36 -0400573checkbutton_sign_up_blockchain_toggled(GtkToggleButton *toggle_button, AccountCreationWizard *view)
574{
575 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
576 gboolean sign_up_blockchain = gtk_toggle_button_get_active(toggle_button);
577
578
579 username_registration_box_set_use_blockchain(
580 USERNAME_REGISTRATION_BOX(priv->username_registration_box),
581 sign_up_blockchain
582 );
583
aviau692fe6d2016-11-08 14:37:34 -0500584 gtk_widget_set_sensitive(priv->entry_username, sign_up_blockchain);
585
586 if (!sign_up_blockchain)
587 {
588 gtk_entry_set_text(GTK_ENTRY(priv->entry_username), "");
589 }
590
aviau2da3d9c2016-09-06 11:28:36 -0400591 /* Unchecking blockchain signup when there is an empty username should
592 * result in activating the next button.
593 */
594 entries_new_account_changed(view);
595}
596
597static void
598username_availability_changed(AccountCreationWizard *view, gboolean username_available)
599{
600 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
601 priv->username_available = username_available;
602 entries_new_account_changed(view);
603}
604
605static void
606build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_button)
aviau6aeb4852016-08-18 16:01:09 -0400607{
608 g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
609 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
610
611 /* set ring logo */
612 GError *error = NULL;
613 GdkPixbuf* logo_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-logo-blue",
614 -1, 50, TRUE, &error);
615 if (logo_ring == NULL) {
616 g_debug("Could not load logo: %s", error->message);
617 g_clear_error(&error);
618 } else
619 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->choose_account_type_ring_logo), logo_ring);
620
aviau2da3d9c2016-09-06 11:28:36 -0400621 /* create the username_registration_box */
Sébastien Blin79efc022018-06-29 11:11:09 -0400622 priv->username_registration_box = username_registration_box_new_empty(false);
aviau2da3d9c2016-09-06 11:28:36 -0400623 gtk_container_add(GTK_CONTAINER(priv->box_username_entry), priv->username_registration_box);
624 gtk_widget_show(priv->username_registration_box);
aviau692fe6d2016-11-08 14:37:34 -0500625 priv->entry_username = GTK_WIDGET(
aviau2da3d9c2016-09-06 11:28:36 -0400626 username_registration_box_get_entry(
627 USERNAME_REGISTRATION_BOX(priv->username_registration_box)
628 )
629 );
aviau6aeb4852016-08-18 16:01:09 -0400630
631 /* use the real name / username of the logged in user as the default */
632 const char* real_name = g_get_real_name();
633 const char* user_name = g_get_user_name();
634 g_debug("real_name = %s",real_name);
635 g_debug("user_name = %s",user_name);
636
637 /* check first if the real name was determined */
638 if (g_strcmp0 (real_name,"Unknown") != 0)
aviau692fe6d2016-11-08 14:37:34 -0500639 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), real_name);
aviau6aeb4852016-08-18 16:01:09 -0400640 else
aviau692fe6d2016-11-08 14:37:34 -0500641 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), user_name);
642
aviau6aeb4852016-08-18 16:01:09 -0400643 /* cancel button */
644 gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button);
645
646 /* choose_account_type signals */
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400647 g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(account_creation_wizard_show_preview), view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200648 g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account), view);
aviau6aeb4852016-08-18 16:01:09 -0400649 g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view);
650
651 /* account_creation signals */
aviau692fe6d2016-11-08 14:37:34 -0500652 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400653 g_signal_connect(priv->button_account_creation_next, "clicked", G_CALLBACK(account_creation_next_clicked), view);
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400654 g_signal_connect(priv->button_account_creation_previous, "clicked", G_CALLBACK(account_creation_previous_clicked), view);
aviau2da3d9c2016-09-06 11:28:36 -0400655 g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(entries_new_account_changed), view);
656 g_signal_connect_swapped(priv->entry_password_confirm, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau692fe6d2016-11-08 14:37:34 -0500657 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
658 g_signal_connect_swapped(priv->entry_display_name, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau2da3d9c2016-09-06 11:28:36 -0400659 g_signal_connect(priv->checkbutton_sign_up_blockchain, "toggled", G_CALLBACK(checkbutton_sign_up_blockchain_toggled), view);
660 g_signal_connect_swapped(priv->username_registration_box, "username-availability-changed", G_CALLBACK(username_availability_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400661
Adrien Beraud50215a42017-09-15 20:24:52 +0200662 /* existing_account signals */
663 g_signal_connect_swapped(priv->button_existing_account_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
664 g_signal_connect_swapped(priv->button_existing_account_next, "clicked", G_CALLBACK(existing_account_next_clicked), view);
aviau6aeb4852016-08-18 16:01:09 -0400665 g_signal_connect(priv->entry_existing_account_pin, "changed", G_CALLBACK(entries_existing_account_changed), view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200666 g_signal_connect(priv->entry_existing_account_archive, "file-set", G_CALLBACK(entries_existing_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400667 g_signal_connect(priv->entry_existing_account_password, "changed", G_CALLBACK(entries_existing_account_changed), view);
668
669 /* error_view signals */
670 g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(show_choose_account_type), view);
671
672 show_choose_account_type(view);
673}
674
675GtkWidget *
676account_creation_wizard_new(bool show_cancel_button)
677{
678 gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL);
679
680 build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button);
681 return (GtkWidget *)view;
682}
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400683
684void
685account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_preview)
686{
687 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
688
689 /* Similarily to general settings view, we construct and destroy the avatar manipulation widget
690 each time the profile is made visible / hidden. While not the most elegant solution, this
691 allows us to run the preview if and only if it is displayed, and always stop it when hidden. */
692 if (show_preview && !priv->avatar_manipulation) {
693 priv->avatar_manipulation = avatar_manipulation_new_from_wizard();
694 gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
695 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
696 } else if (priv->avatar_manipulation) {
697 /* make sure the AvatarManipulation widget is destroyed so the VideoWidget inside of it is too;
698 * NOTE: destorying its parent (box_avatarselection) first will cause a mystery 'BadDrawable'
699 * crash due to X error */
700 gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation);
701 priv->avatar_manipulation = nullptr;
702 }
703}
704
705void
706account_creation_wizard_cancel(AccountCreationWizard *win)
707{
708 // make sure to stop preview before doing something else
709 account_creation_wizard_show_preview(win, FALSE);
710 g_signal_emit(G_OBJECT(win), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
711}