blob: df06e181a90678349782ab51882bdc66f9c4623a [file] [log] [blame]
aviau6aeb4852016-08-18 16:01:09 -04001/*
2 * Copyright (C) 2016 Savoir-faire Linux Inc.
3 * 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
aviau692fe6d2016-11-08 14:37:34 -0500401 gchar *display_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name)));
402 gchar *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_username)));
aviau6aeb4852016-08-18 16:01:09 -0400403 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_password)));
404 gtk_entry_set_text(GTK_ENTRY(priv->entry_password), "");
405 gtk_entry_set_text(GTK_ENTRY(priv->entry_password_confirm), "");
406
aviau692fe6d2016-11-08 14:37:34 -0500407 auto status = create_ring_account(win, display_name, username, password, NULL);
aviau6aeb4852016-08-18 16:01:09 -0400408
aviau692fe6d2016-11-08 14:37:34 -0500409 g_free(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400410 g_free(password);
aviau692fe6d2016-11-08 14:37:34 -0500411 g_free(username);
aviau6aeb4852016-08-18 16:01:09 -0400412
413 return status;
414}
415
416static gboolean
417create_existing_ring_account(AccountCreationWizard *win)
418{
419 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
420 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
421
422 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password)));
423 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), "");
424
425 gchar *pin = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin)));
426 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), "");
427
aviau692fe6d2016-11-08 14:37:34 -0500428 auto status = create_ring_account(win, NULL, NULL, password, pin);
aviau6aeb4852016-08-18 16:01:09 -0400429
430 g_free(password);
431 g_free(pin);
432
433 return status;
434}
435
aviau6aeb4852016-08-18 16:01:09 -0400436static void
437show_generating_account_spinner(AccountCreationWizard *view)
438{
439 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
440 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_generating_account_spinner);
441}
442
443static void
444account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win)
445{
446 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
447
448 /* Check for correct password */
449 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
450 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
451
452 if (g_strcmp0(password, password_confirm) != 0)
453 {
aviau2da3d9c2016-09-06 11:28:36 -0400454 gtk_label_set_text(GTK_LABEL(priv->label_password_error), _("Passwords don't match"));
aviau6aeb4852016-08-18 16:01:09 -0400455 return;
456 }
457
458 show_generating_account_spinner(win);
459
460 /* now create account after a short timeout so that the the save doesn't
461 * happen freeze the client before the widget changes happen;
462 * the timeout function should then display the next step in account creation
463 */
464 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_ring_account, win, NULL);
465}
466
467static void
468show_retrieving_account(AccountCreationWizard *win)
469{
470 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
471 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->retrieving_account);
472}
473
474static void
aviau16a94be2016-11-10 17:37:32 -0500475existing_account_step2_next_clicked(AccountCreationWizard *win)
aviau6aeb4852016-08-18 16:01:09 -0400476{
477 show_retrieving_account(win);
478
479 /* now create account after a short timeout so that the the save doesn't
480 * happen freeze the client before the widget changes happen;
481 * the timeout function should then display the next step in account creation
482 */
483 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_existing_ring_account, win, NULL);
484}
485
486static void
aviau6aeb4852016-08-18 16:01:09 -0400487show_choose_account_type(AccountCreationWizard *view)
488{
489 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
490 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->choose_account_type_vbox);
491}
492
493static void
aviau16a94be2016-11-10 17:37:32 -0500494show_existing_account_step2(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400495{
496 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
aviau16a94be2016-11-10 17:37:32 -0500497 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account_step2);
498}
499
500static void
501show_existing_account_step1(AccountCreationWizard *view)
502{
503 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
504 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account_step1);
aviau6aeb4852016-08-18 16:01:09 -0400505}
506
507static void
508show_account_creation(AccountCreationWizard *win)
509{
510 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
511
512 /* avatar manipulation widget */
513 if (!priv->avatar_manipulation)
514 {
515 priv->avatar_manipulation = avatar_manipulation_new_from_wizard();
516 gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
517 }
518
aviau6aeb4852016-08-18 16:01:09 -0400519 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
520}
521
522static void
523wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
524{
525 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
526}
527
528static void
529entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationWizard *view)
530{
531 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
532
533 const gchar *pin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
534 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password));
535
aviau16a94be2016-11-10 17:37:32 -0500536 gtk_widget_set_sensitive(
537 priv->button_existing_account_step2_next,
538 (strlen(pin) > 0 && strlen(password) > 0)
539 );
aviau6aeb4852016-08-18 16:01:09 -0400540}
541
542static void
aviau2da3d9c2016-09-06 11:28:36 -0400543entries_new_account_changed(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400544{
545 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
546
aviau692fe6d2016-11-08 14:37:34 -0500547 const gchar *display_name = gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name));
548 const gchar *username = gtk_entry_get_text(GTK_ENTRY(priv->entry_username));
aviau6aeb4852016-08-18 16:01:09 -0400549 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
550 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
aviau2da3d9c2016-09-06 11:28:36 -0400551 const gboolean sign_up_blockchain = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->checkbutton_sign_up_blockchain));
aviau6aeb4852016-08-18 16:01:09 -0400552
aviau2da3d9c2016-09-06 11:28:36 -0400553 if (
aviau692fe6d2016-11-08 14:37:34 -0500554 strlen(display_name) > 0 && // Display name is longer than 0
aviau2da3d9c2016-09-06 11:28:36 -0400555 strlen(password) > 0 && // Password is longer than 0
556 strlen(password_confirm) > 0 && // Confirmation is also longer than 0
aviau692fe6d2016-11-08 14:37:34 -0500557 (
558 (sign_up_blockchain && strlen(username) > 0 && priv->username_available) || // we are signing up, username is set and avaialble
559 !sign_up_blockchain // We are not signing up
560 )
aviau2da3d9c2016-09-06 11:28:36 -0400561 )
aviau6aeb4852016-08-18 16:01:09 -0400562 {
563 gtk_widget_set_sensitive(priv->button_account_creation_next, TRUE);
564 }
565 else
566 {
567 gtk_widget_set_sensitive(priv->button_account_creation_next, FALSE);
568 }
569}
570
571static void
aviau2da3d9c2016-09-06 11:28:36 -0400572checkbutton_sign_up_blockchain_toggled(GtkToggleButton *toggle_button, AccountCreationWizard *view)
573{
574 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
575 gboolean sign_up_blockchain = gtk_toggle_button_get_active(toggle_button);
576
577
578 username_registration_box_set_use_blockchain(
579 USERNAME_REGISTRATION_BOX(priv->username_registration_box),
580 sign_up_blockchain
581 );
582
aviau692fe6d2016-11-08 14:37:34 -0500583 gtk_widget_set_sensitive(priv->entry_username, sign_up_blockchain);
584
585 if (!sign_up_blockchain)
586 {
587 gtk_entry_set_text(GTK_ENTRY(priv->entry_username), "");
588 }
589
aviau2da3d9c2016-09-06 11:28:36 -0400590 /* Unchecking blockchain signup when there is an empty username should
591 * result in activating the next button.
592 */
593 entries_new_account_changed(view);
594}
595
596static void
597username_availability_changed(AccountCreationWizard *view, gboolean username_available)
598{
599 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
600 priv->username_available = username_available;
601 entries_new_account_changed(view);
602}
603
604static void
605build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_button)
aviau6aeb4852016-08-18 16:01:09 -0400606{
607 g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
608 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
609
610 /* set ring logo */
611 GError *error = NULL;
612 GdkPixbuf* logo_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-logo-blue",
613 -1, 50, TRUE, &error);
614 if (logo_ring == NULL) {
615 g_debug("Could not load logo: %s", error->message);
616 g_clear_error(&error);
617 } else
618 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->choose_account_type_ring_logo), logo_ring);
619
aviau2da3d9c2016-09-06 11:28:36 -0400620 /* create the username_registration_box */
621 priv->username_registration_box = username_registration_box_new(nullptr, FALSE);
622 gtk_container_add(GTK_CONTAINER(priv->box_username_entry), priv->username_registration_box);
623 gtk_widget_show(priv->username_registration_box);
aviau692fe6d2016-11-08 14:37:34 -0500624 priv->entry_username = GTK_WIDGET(
aviau2da3d9c2016-09-06 11:28:36 -0400625 username_registration_box_get_entry(
626 USERNAME_REGISTRATION_BOX(priv->username_registration_box)
627 )
628 );
aviau6aeb4852016-08-18 16:01:09 -0400629
630 /* use the real name / username of the logged in user as the default */
631 const char* real_name = g_get_real_name();
632 const char* user_name = g_get_user_name();
633 g_debug("real_name = %s",real_name);
634 g_debug("user_name = %s",user_name);
635
636 /* check first if the real name was determined */
637 if (g_strcmp0 (real_name,"Unknown") != 0)
aviau692fe6d2016-11-08 14:37:34 -0500638 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), real_name);
aviau6aeb4852016-08-18 16:01:09 -0400639 else
aviau692fe6d2016-11-08 14:37:34 -0500640 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), user_name);
641
aviau6aeb4852016-08-18 16:01:09 -0400642 /* cancel button */
643 gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button);
644
645 /* choose_account_type signals */
646 g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(show_account_creation), view);
aviau16a94be2016-11-10 17:37:32 -0500647 g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account_step1), view);
aviau6aeb4852016-08-18 16:01:09 -0400648 g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view);
649
650 /* account_creation signals */
651 g_signal_connect_swapped(priv->button_account_creation_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
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);
aviau2da3d9c2016-09-06 11:28:36 -0400654 g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(entries_new_account_changed), view);
655 g_signal_connect_swapped(priv->entry_password_confirm, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau692fe6d2016-11-08 14:37:34 -0500656 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
657 g_signal_connect_swapped(priv->entry_display_name, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau2da3d9c2016-09-06 11:28:36 -0400658 g_signal_connect(priv->checkbutton_sign_up_blockchain, "toggled", G_CALLBACK(checkbutton_sign_up_blockchain_toggled), view);
659 g_signal_connect_swapped(priv->username_registration_box, "username-availability-changed", G_CALLBACK(username_availability_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400660
aviau16a94be2016-11-10 17:37:32 -0500661 /* existing_account_step1 singals */
662 g_signal_connect_swapped(priv->button_existing_account_step1_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
663 g_signal_connect_swapped(priv->button_existing_account_step1_next, "clicked", G_CALLBACK(show_existing_account_step2), view);
664
665 /* existing_account_step2 signals */
666 g_signal_connect_swapped(priv->button_existing_account_step2_previous, "clicked", G_CALLBACK(show_existing_account_step1), view);
667 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 -0400668 g_signal_connect(priv->entry_existing_account_pin, "changed", G_CALLBACK(entries_existing_account_changed), view);
669 g_signal_connect(priv->entry_existing_account_password, "changed", G_CALLBACK(entries_existing_account_changed), view);
670
671 /* error_view signals */
672 g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(show_choose_account_type), view);
673
674 show_choose_account_type(view);
675}
676
677GtkWidget *
678account_creation_wizard_new(bool show_cancel_button)
679{
680 gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL);
681
682 build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button);
683 return (GtkWidget *)view;
684}