blob: efaf806881a4b0b8c89f1a983f06789c6f14daa7 [file] [log] [blame]
aviau6aeb4852016-08-18 16:01:09 -04001/*
Guillaume Roguez2a6150d2017-07-19 18:24:47 -04002 * Copyright (C) 2016-2017 Savoir-faire Linux Inc.
aviau6aeb4852016-08-18 16:01:09 -04003 * Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20
21// 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
39
40struct _AccountCreationWizard
41{
42 GtkBox parent;
43};
44
45struct _AccountCreationWizardClass
46{
47 GtkBoxClass parent_class;
48};
49
50typedef struct _AccountCreationWizardPrivate AccountCreationWizardPrivate;
51
52struct _AccountCreationWizardPrivate
53{
54 GtkWidget *stack_account_creation;
55 QMetaObject::Connection account_state_changed;
aviau2da3d9c2016-09-06 11:28:36 -040056 QMetaObject::Connection name_registration_ended;
57 gboolean username_available;
58
59 QString* password;
aviau692fe6d2016-11-08 14:37:34 -050060 QString* username;
aviau6aeb4852016-08-18 16:01:09 -040061
62 /* choose_account_type_vbox */
63 GtkWidget *choose_account_type_vbox;
64 GtkWidget *choose_account_type_ring_logo;
65 GtkWidget *button_new_account;
66 GtkWidget *button_existing_account;
67 GtkWidget *button_wizard_cancel;
68
aviau16a94be2016-11-10 17:37:32 -050069 /* existing account step1 */
70 GtkWidget *existing_account_step1;
71 GtkWidget *button_existing_account_step1_next;
72 GtkWidget *button_existing_account_step1_previous;
aviau6aeb4852016-08-18 16:01:09 -040073 GtkWidget *entry_existing_account_pin;
74 GtkWidget *entry_existing_account_password;
75 GtkWidget *retrieving_account;
76
aviau16a94be2016-11-10 17:37:32 -050077 /* existing account step 2 */
78 GtkWidget *existing_account_step2;
79 GtkWidget *button_existing_account_step2_next;
80 GtkWidget *button_existing_account_step2_previous;
81
aviau6aeb4852016-08-18 16:01:09 -040082 /* account creation */
83 GtkWidget *account_creation;
aviau692fe6d2016-11-08 14:37:34 -050084 GtkWidget *entry_username;
aviau6aeb4852016-08-18 16:01:09 -040085 GtkWidget *entry_password;
86 GtkWidget *entry_password_confirm;
aviau6aeb4852016-08-18 16:01:09 -040087 GtkWidget *button_account_creation_next;
88 GtkWidget *button_account_creation_previous;
89 GtkWidget *box_avatarselection;
90 GtkWidget *avatar_manipulation;
91 GtkWidget *label_password_error;
aviau2da3d9c2016-09-06 11:28:36 -040092 GtkWidget *box_username_entry;
93 GtkWidget *checkbutton_sign_up_blockchain;
94 GtkWidget *username_registration_box;
aviau692fe6d2016-11-08 14:37:34 -050095 GtkWidget *entry_display_name;
aviau6aeb4852016-08-18 16:01:09 -040096
97 /* generating_account_spinner */
98 GtkWidget *vbox_generating_account_spinner;
99
aviau2da3d9c2016-09-06 11:28:36 -0400100 /* registering_username_spinner */
101 GtkWidget *vbox_registering_username_spinner;
102
aviau6aeb4852016-08-18 16:01:09 -0400103 /* error_view */
104 GtkWidget *error_view;
105 GtkWidget *button_error_view_ok;
106
107};
108
109G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_TYPE_BOX);
110
111#define ACCOUNT_CREATION_WIZARD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_CREATION_WIZARD_TYPE, AccountCreationWizardPrivate))
112
113/* signals */
114enum {
115 ACCOUNT_CREATION_CANCELED,
116 ACCOUNT_CREATION_COMPLETED,
117 LAST_SIGNAL
118};
119
120static guint account_creation_wizard_signals[LAST_SIGNAL] = { 0 };
121
122static void
123destroy_avatar_manipulation(AccountCreationWizard *view)
124{
125 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
126
127 /* make sure the AvatarManipulation widget is destroyed so the VideoWidget inside of it is too;
128 * NOTE: destorying its parent (box_avatarselection) first will cause a mystery 'BadDrawable'
129 * crash due to X error */
130 if (priv->avatar_manipulation)
131 {
132 gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation);
133 priv->avatar_manipulation = nullptr;
134 }
135}
136
137static void
138account_creation_wizard_dispose(GObject *object)
139{
140 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(object);
141 destroy_avatar_manipulation(ACCOUNT_CREATION_WIZARD(object));
142 QObject::disconnect(priv->account_state_changed);
143 G_OBJECT_CLASS(account_creation_wizard_parent_class)->dispose(object);
144}
145
146static void
147account_creation_wizard_init(AccountCreationWizard *view)
148{
149 gtk_widget_init_template(GTK_WIDGET(view));
150}
151
152static void
153account_creation_wizard_class_init(AccountCreationWizardClass *klass)
154{
155 G_OBJECT_CLASS(klass)->dispose = account_creation_wizard_dispose;
156
157 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
158 "/cx/ring/RingGnome/accountcreationwizard.ui");
159
160 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, stack_account_creation);
161
162 /* choose_account_type_vbox */
163 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_vbox);
164 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_ring_logo);
165 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_account);
166 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account);
167 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_wizard_cancel);
168
aviau16a94be2016-11-10 17:37:32 -0500169 /* existing account step1 */
170 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account_step1);
171 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_step1_next);
172 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_step1_previous);
173
174 /* existing account step2 */
175 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account_step2);
176 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_step2_next);
177 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_step2_previous);
aviau6aeb4852016-08-18 16:01:09 -0400178 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_pin);
179 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_password);
180 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_password);
181 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, retrieving_account);
182
183 /* account creation */
184 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, account_creation);
aviau6aeb4852016-08-18 16:01:09 -0400185 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password);
186 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password_confirm);
aviau6aeb4852016-08-18 16:01:09 -0400187 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_next);
188 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_previous);
189 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_avatarselection);
190 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, label_password_error);
aviau2da3d9c2016-09-06 11:28:36 -0400191 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_username_entry);
192 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, checkbutton_sign_up_blockchain);
aviau692fe6d2016-11-08 14:37:34 -0500193 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_display_name);
aviau6aeb4852016-08-18 16:01:09 -0400194
195 /* generating_account_spinner */
196 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_generating_account_spinner);
197
aviau2da3d9c2016-09-06 11:28:36 -0400198 /* registering_username_spinner */
199 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_registering_username_spinner);
200
aviau6aeb4852016-08-18 16:01:09 -0400201 /* error view */
202 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, error_view);
203 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_error_view_ok);
204
205 /* add signals */
206 account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED] = g_signal_new("account-creation-completed",
207 G_TYPE_FROM_CLASS(klass),
208 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
209 0,
210 nullptr,
211 nullptr,
212 g_cclosure_marshal_VOID__VOID,
213 G_TYPE_NONE, 0);
214
215 account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED] = g_signal_new("account-creation-canceled",
216 G_TYPE_FROM_CLASS(klass),
217 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
218 0,
219 nullptr,
220 nullptr,
221 g_cclosure_marshal_VOID__VOID,
222 G_TYPE_NONE, 0);
223}
224
225static void
226show_error_view(AccountCreationWizard *view)
227{
228 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
229 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->error_view);
230}
231
aviau2da3d9c2016-09-06 11:28:36 -0400232static void
233could_not_register_username_dialog(AccountCreationWizard *view)
234{
235 GtkWidget* dialog = gtk_message_dialog_new(
236 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))),
237 GTK_DIALOG_DESTROY_WITH_PARENT,
238 GTK_MESSAGE_ERROR,
239 GTK_BUTTONS_OK,
240 _("Your account was created, but we could not register your username. Try again from the settings menu.")
241 );
242 gtk_dialog_run(GTK_DIALOG (dialog));
243 gtk_widget_destroy(dialog);
244}
245
246static void
247show_registering_on_blockchain_spinner(AccountCreationWizard *view)
248{
249 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
250 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_registering_username_spinner);
251}
252
aviau6aeb4852016-08-18 16:01:09 -0400253static gboolean
254create_ring_account(AccountCreationWizard *view,
aviau692fe6d2016-11-08 14:37:34 -0500255 gchar *display_name,
256 gchar *username,
aviau6aeb4852016-08-18 16:01:09 -0400257 gchar *password,
258 gchar *pin)
259{
aviau692fe6d2016-11-08 14:37:34 -0500260
aviau6aeb4852016-08-18 16:01:09 -0400261 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(view), G_SOURCE_REMOVE);
262 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
263
aviau2da3d9c2016-09-06 11:28:36 -0400264 // Copy password and alias, which will be used in our callbacks
aviau692fe6d2016-11-08 14:37:34 -0500265 priv->username = new QString(username);
aviau2da3d9c2016-09-06 11:28:36 -0400266 priv->password = new QString(password);
aviau2da3d9c2016-09-06 11:28:36 -0400267
aviau6aeb4852016-08-18 16:01:09 -0400268 g_object_ref(view); // ref so its not desroyed too early
269
270 /* create account and set UPnP enabled, as its not by default in the daemon */
271 Account *account = nullptr;
272
273 /* get profile (if so) */
274 auto profile = ProfileModel::instance().selectedProfile();
275
aviau692fe6d2016-11-08 14:37:34 -0500276 if (display_name && strlen(display_name) > 0) {
277 account = AccountModel::instance().add(display_name, Account::Protocol::RING);
aviau6aeb4852016-08-18 16:01:09 -0400278 if(profile && AccountModel::instance().size() == 1)
279 {
aviau692fe6d2016-11-08 14:37:34 -0500280 profile->person()->setFormattedName(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400281 }
282 } else {
283 auto unknown_alias = C_("The default username / account alias, if none is set by the user", "Unknown");
284 account = AccountModel::instance().add(unknown_alias, Account::Protocol::RING);
285 if (profile && AccountModel::instance().size() == 1)
286 {
287 profile->person()->setFormattedName(unknown_alias);
288 }
289 }
290
291 /* Set the archive password */
292 account->setArchivePassword(password);
293
294 /* Set the archive pin (existng accounts) */
295 if(pin)
296 {
297 account->setArchivePin(pin);
298 }
299
aviau692fe6d2016-11-08 14:37:34 -0500300 account->setDisplayName(display_name); // set the display name to the same as the alias
aviau6aeb4852016-08-18 16:01:09 -0400301
302 account->setUpnpEnabled(TRUE);
303
304 /* show error window if the account errors */
305 priv->account_state_changed = QObject::connect(
306 account,
307 &Account::stateChanged,
308 [=] (Account::RegistrationState state) {
309 switch(state)
310 {
311 case Account::RegistrationState::ERROR:
312 {
313 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
314 QObject::disconnect(priv->account_state_changed);
315 show_error_view(view);
316 g_object_unref(view);
317 break;
318 }
319 case Account::RegistrationState::READY:
320 case Account::RegistrationState::TRYING:
321 case Account::RegistrationState::UNREGISTERED:
322 {
323 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
324 QObject::disconnect(priv->account_state_changed);
325
326 account << Account::EditAction::RELOAD;
aviau2da3d9c2016-09-06 11:28:36 -0400327
328 // Now try to register the username
aviau692fe6d2016-11-08 14:37:34 -0500329 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 -0400330 {
331 priv->name_registration_ended = QObject::connect(
332 account,
333 &Account::nameRegistrationEnded,
334 [=] (NameDirectory::RegisterNameStatus status, G_GNUC_UNUSED const QString& name) {
335 QObject::disconnect(priv->name_registration_ended);
336 switch(status)
337 {
338 case NameDirectory::RegisterNameStatus::INVALID_NAME:
339 case NameDirectory::RegisterNameStatus::WRONG_PASSWORD:
340 case NameDirectory::RegisterNameStatus::ALREADY_TAKEN:
341 case NameDirectory::RegisterNameStatus::NETWORK_ERROR:
342 {
343 could_not_register_username_dialog(view);
344 }
345 case NameDirectory::RegisterNameStatus::SUCCESS:
346 {
347 // Reload so that the username is displayed in the settings
348 account << Account::EditAction::RELOAD;
349 break;
350 }
351 }
352 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
353 g_object_unref(view);
354 }
355 );
356
357 show_registering_on_blockchain_spinner(view);
358
aviau692fe6d2016-11-08 14:37:34 -0500359 bool register_name_result = account->registerName(*priv->password, *priv->username);
360 priv->username->clear();
aviau2da3d9c2016-09-06 11:28:36 -0400361 priv->password->clear();
aviau2da3d9c2016-09-06 11:28:36 -0400362
363 if (register_name_result == FALSE)
364 {
365 g_debug("Could not initialize registerName operation");
366 could_not_register_username_dialog(view);
367 QObject::disconnect(priv->name_registration_ended);
368 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
369 g_object_unref(view);
370 }
371 }
372 else
373 {
374 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
375 g_object_unref(view);
376 }
aviau6aeb4852016-08-18 16:01:09 -0400377 break;
378 }
379 case Account::RegistrationState::INITIALIZING:
380 case Account::RegistrationState::COUNT__:
381 {
382 // Keep waiting...
383 break;
384 }
385 }
386 }
387 );
388
389 account->performAction(Account::EditAction::SAVE);
390 profile->save();
391
392 return G_SOURCE_REMOVE;
393}
394
395static gboolean
396create_new_ring_account(AccountCreationWizard *win)
397{
398 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
399 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
400
Stepan Salenikovichec16deb2017-04-14 14:18:37 -0400401 /* Tuleap: #1441
402 * if the user did not validate the avatar area selection, we still take that as the image
403 * for their avatar; otherwise many users end up with no avatar by default
404 * TODO: improve avatar creation process to not need this fix
405 */
406 avatar_manipulation_wizard_completed(AVATAR_MANIPULATION(priv->avatar_manipulation));
407
aviau692fe6d2016-11-08 14:37:34 -0500408 gchar *display_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name)));
409 gchar *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_username)));
aviau6aeb4852016-08-18 16:01:09 -0400410 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_password)));
411 gtk_entry_set_text(GTK_ENTRY(priv->entry_password), "");
412 gtk_entry_set_text(GTK_ENTRY(priv->entry_password_confirm), "");
413
aviau692fe6d2016-11-08 14:37:34 -0500414 auto status = create_ring_account(win, display_name, username, password, NULL);
aviau6aeb4852016-08-18 16:01:09 -0400415
aviau692fe6d2016-11-08 14:37:34 -0500416 g_free(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400417 g_free(password);
aviau692fe6d2016-11-08 14:37:34 -0500418 g_free(username);
aviau6aeb4852016-08-18 16:01:09 -0400419
420 return status;
421}
422
423static gboolean
424create_existing_ring_account(AccountCreationWizard *win)
425{
426 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
427 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
428
429 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password)));
430 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), "");
431
432 gchar *pin = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin)));
433 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), "");
434
aviau692fe6d2016-11-08 14:37:34 -0500435 auto status = create_ring_account(win, NULL, NULL, password, pin);
aviau6aeb4852016-08-18 16:01:09 -0400436
437 g_free(password);
438 g_free(pin);
439
440 return status;
441}
442
aviau6aeb4852016-08-18 16:01:09 -0400443static void
444show_generating_account_spinner(AccountCreationWizard *view)
445{
446 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
447 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_generating_account_spinner);
448}
449
450static void
451account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win)
452{
453 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
454
455 /* Check for correct password */
456 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
457 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
458
459 if (g_strcmp0(password, password_confirm) != 0)
460 {
aviau2da3d9c2016-09-06 11:28:36 -0400461 gtk_label_set_text(GTK_LABEL(priv->label_password_error), _("Passwords don't match"));
aviau6aeb4852016-08-18 16:01:09 -0400462 return;
463 }
464
465 show_generating_account_spinner(win);
466
467 /* now create account after a short timeout so that the the save doesn't
468 * happen freeze the client before the widget changes happen;
469 * the timeout function should then display the next step in account creation
470 */
471 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_ring_account, win, NULL);
472}
473
474static void
475show_retrieving_account(AccountCreationWizard *win)
476{
477 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
478 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->retrieving_account);
479}
480
481static void
aviau16a94be2016-11-10 17:37:32 -0500482existing_account_step2_next_clicked(AccountCreationWizard *win)
aviau6aeb4852016-08-18 16:01:09 -0400483{
484 show_retrieving_account(win);
485
486 /* now create account after a short timeout so that the the save doesn't
487 * happen freeze the client before the widget changes happen;
488 * the timeout function should then display the next step in account creation
489 */
490 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_existing_ring_account, win, NULL);
491}
492
493static void
aviau6aeb4852016-08-18 16:01:09 -0400494show_choose_account_type(AccountCreationWizard *view)
495{
496 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
497 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->choose_account_type_vbox);
498}
499
500static void
aviau16a94be2016-11-10 17:37:32 -0500501show_existing_account_step2(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400502{
503 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
aviau16a94be2016-11-10 17:37:32 -0500504 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account_step2);
505}
506
507static void
508show_existing_account_step1(AccountCreationWizard *view)
509{
510 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
511 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account_step1);
aviau6aeb4852016-08-18 16:01:09 -0400512}
513
514static void
515show_account_creation(AccountCreationWizard *win)
516{
517 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
518
519 /* avatar manipulation widget */
520 if (!priv->avatar_manipulation)
521 {
522 priv->avatar_manipulation = avatar_manipulation_new_from_wizard();
523 gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
524 }
525
aviau6aeb4852016-08-18 16:01:09 -0400526 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
527}
528
529static void
530wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
531{
532 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
533}
534
535static void
536entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationWizard *view)
537{
538 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
539
540 const gchar *pin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
541 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password));
542
aviau16a94be2016-11-10 17:37:32 -0500543 gtk_widget_set_sensitive(
544 priv->button_existing_account_step2_next,
545 (strlen(pin) > 0 && strlen(password) > 0)
546 );
aviau6aeb4852016-08-18 16:01:09 -0400547}
548
549static void
aviau2da3d9c2016-09-06 11:28:36 -0400550entries_new_account_changed(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400551{
552 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
553
aviau692fe6d2016-11-08 14:37:34 -0500554 const gchar *display_name = gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name));
555 const gchar *username = gtk_entry_get_text(GTK_ENTRY(priv->entry_username));
aviau6aeb4852016-08-18 16:01:09 -0400556 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
557 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
aviau2da3d9c2016-09-06 11:28:36 -0400558 const gboolean sign_up_blockchain = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->checkbutton_sign_up_blockchain));
aviau6aeb4852016-08-18 16:01:09 -0400559
aviau2da3d9c2016-09-06 11:28:36 -0400560 if (
aviau692fe6d2016-11-08 14:37:34 -0500561 strlen(display_name) > 0 && // Display name is longer than 0
aviau2da3d9c2016-09-06 11:28:36 -0400562 strlen(password) > 0 && // Password is longer than 0
563 strlen(password_confirm) > 0 && // Confirmation is also longer than 0
aviau692fe6d2016-11-08 14:37:34 -0500564 (
565 (sign_up_blockchain && strlen(username) > 0 && priv->username_available) || // we are signing up, username is set and avaialble
566 !sign_up_blockchain // We are not signing up
567 )
aviau2da3d9c2016-09-06 11:28:36 -0400568 )
aviau6aeb4852016-08-18 16:01:09 -0400569 {
570 gtk_widget_set_sensitive(priv->button_account_creation_next, TRUE);
571 }
572 else
573 {
574 gtk_widget_set_sensitive(priv->button_account_creation_next, FALSE);
575 }
576}
577
578static void
aviau2da3d9c2016-09-06 11:28:36 -0400579checkbutton_sign_up_blockchain_toggled(GtkToggleButton *toggle_button, AccountCreationWizard *view)
580{
581 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
582 gboolean sign_up_blockchain = gtk_toggle_button_get_active(toggle_button);
583
584
585 username_registration_box_set_use_blockchain(
586 USERNAME_REGISTRATION_BOX(priv->username_registration_box),
587 sign_up_blockchain
588 );
589
aviau692fe6d2016-11-08 14:37:34 -0500590 gtk_widget_set_sensitive(priv->entry_username, sign_up_blockchain);
591
592 if (!sign_up_blockchain)
593 {
594 gtk_entry_set_text(GTK_ENTRY(priv->entry_username), "");
595 }
596
aviau2da3d9c2016-09-06 11:28:36 -0400597 /* Unchecking blockchain signup when there is an empty username should
598 * result in activating the next button.
599 */
600 entries_new_account_changed(view);
601}
602
603static void
604username_availability_changed(AccountCreationWizard *view, gboolean username_available)
605{
606 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
607 priv->username_available = username_available;
608 entries_new_account_changed(view);
609}
610
611static void
612build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_button)
aviau6aeb4852016-08-18 16:01:09 -0400613{
614 g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
615 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
616
617 /* set ring logo */
618 GError *error = NULL;
619 GdkPixbuf* logo_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-logo-blue",
620 -1, 50, TRUE, &error);
621 if (logo_ring == NULL) {
622 g_debug("Could not load logo: %s", error->message);
623 g_clear_error(&error);
624 } else
625 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->choose_account_type_ring_logo), logo_ring);
626
aviau2da3d9c2016-09-06 11:28:36 -0400627 /* create the username_registration_box */
628 priv->username_registration_box = username_registration_box_new(nullptr, FALSE);
629 gtk_container_add(GTK_CONTAINER(priv->box_username_entry), priv->username_registration_box);
630 gtk_widget_show(priv->username_registration_box);
aviau692fe6d2016-11-08 14:37:34 -0500631 priv->entry_username = GTK_WIDGET(
aviau2da3d9c2016-09-06 11:28:36 -0400632 username_registration_box_get_entry(
633 USERNAME_REGISTRATION_BOX(priv->username_registration_box)
634 )
635 );
aviau6aeb4852016-08-18 16:01:09 -0400636
637 /* use the real name / username of the logged in user as the default */
638 const char* real_name = g_get_real_name();
639 const char* user_name = g_get_user_name();
640 g_debug("real_name = %s",real_name);
641 g_debug("user_name = %s",user_name);
642
643 /* check first if the real name was determined */
644 if (g_strcmp0 (real_name,"Unknown") != 0)
aviau692fe6d2016-11-08 14:37:34 -0500645 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), real_name);
aviau6aeb4852016-08-18 16:01:09 -0400646 else
aviau692fe6d2016-11-08 14:37:34 -0500647 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), user_name);
648
aviau6aeb4852016-08-18 16:01:09 -0400649 /* cancel button */
650 gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button);
651
652 /* choose_account_type signals */
653 g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(show_account_creation), view);
aviau16a94be2016-11-10 17:37:32 -0500654 g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account_step1), view);
aviau6aeb4852016-08-18 16:01:09 -0400655 g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view);
656
657 /* account_creation signals */
658 g_signal_connect_swapped(priv->button_account_creation_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
aviau692fe6d2016-11-08 14:37:34 -0500659 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400660 g_signal_connect(priv->button_account_creation_next, "clicked", G_CALLBACK(account_creation_next_clicked), view);
aviau2da3d9c2016-09-06 11:28:36 -0400661 g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(entries_new_account_changed), view);
662 g_signal_connect_swapped(priv->entry_password_confirm, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau692fe6d2016-11-08 14:37:34 -0500663 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
664 g_signal_connect_swapped(priv->entry_display_name, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau2da3d9c2016-09-06 11:28:36 -0400665 g_signal_connect(priv->checkbutton_sign_up_blockchain, "toggled", G_CALLBACK(checkbutton_sign_up_blockchain_toggled), view);
666 g_signal_connect_swapped(priv->username_registration_box, "username-availability-changed", G_CALLBACK(username_availability_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400667
aviau16a94be2016-11-10 17:37:32 -0500668 /* existing_account_step1 singals */
669 g_signal_connect_swapped(priv->button_existing_account_step1_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
670 g_signal_connect_swapped(priv->button_existing_account_step1_next, "clicked", G_CALLBACK(show_existing_account_step2), view);
671
672 /* existing_account_step2 signals */
673 g_signal_connect_swapped(priv->button_existing_account_step2_previous, "clicked", G_CALLBACK(show_existing_account_step1), view);
674 g_signal_connect_swapped(priv->button_existing_account_step2_next, "clicked", G_CALLBACK(existing_account_step2_next_clicked), view);
aviau6aeb4852016-08-18 16:01:09 -0400675 g_signal_connect(priv->entry_existing_account_pin, "changed", G_CALLBACK(entries_existing_account_changed), view);
676 g_signal_connect(priv->entry_existing_account_password, "changed", G_CALLBACK(entries_existing_account_changed), view);
677
678 /* error_view signals */
679 g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(show_choose_account_type), view);
680
681 show_choose_account_type(view);
682}
683
684GtkWidget *
685account_creation_wizard_new(bool show_cancel_button)
686{
687 gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL);
688
689 build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button);
690 return (GtkWidget *)view;
691}