blob: 1073aa70ae4cbe17137c3e431ff5e7e235e17d70 [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
Adrien Beraud50215a42017-09-15 20:24:52 +020069 /* existing account */
70 GtkWidget *existing_account;
71 GtkWidget *button_existing_account_next;
72 GtkWidget *button_existing_account_previous;
aviau6aeb4852016-08-18 16:01:09 -040073 GtkWidget *entry_existing_account_pin;
Adrien Beraud50215a42017-09-15 20:24:52 +020074 GtkWidget *entry_existing_account_archive;
aviau6aeb4852016-08-18 16:01:09 -040075 GtkWidget *entry_existing_account_password;
76 GtkWidget *retrieving_account;
77
78 /* account creation */
79 GtkWidget *account_creation;
aviau692fe6d2016-11-08 14:37:34 -050080 GtkWidget *entry_username;
aviau6aeb4852016-08-18 16:01:09 -040081 GtkWidget *entry_password;
82 GtkWidget *entry_password_confirm;
aviau6aeb4852016-08-18 16:01:09 -040083 GtkWidget *button_account_creation_next;
84 GtkWidget *button_account_creation_previous;
85 GtkWidget *box_avatarselection;
86 GtkWidget *avatar_manipulation;
87 GtkWidget *label_password_error;
aviau2da3d9c2016-09-06 11:28:36 -040088 GtkWidget *box_username_entry;
89 GtkWidget *checkbutton_sign_up_blockchain;
90 GtkWidget *username_registration_box;
aviau692fe6d2016-11-08 14:37:34 -050091 GtkWidget *entry_display_name;
aviau6aeb4852016-08-18 16:01:09 -040092
93 /* generating_account_spinner */
94 GtkWidget *vbox_generating_account_spinner;
95
aviau2da3d9c2016-09-06 11:28:36 -040096 /* registering_username_spinner */
97 GtkWidget *vbox_registering_username_spinner;
98
aviau6aeb4852016-08-18 16:01:09 -040099 /* error_view */
100 GtkWidget *error_view;
101 GtkWidget *button_error_view_ok;
102
103};
104
105G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_TYPE_BOX);
106
107#define ACCOUNT_CREATION_WIZARD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_CREATION_WIZARD_TYPE, AccountCreationWizardPrivate))
108
109/* signals */
110enum {
111 ACCOUNT_CREATION_CANCELED,
112 ACCOUNT_CREATION_COMPLETED,
113 LAST_SIGNAL
114};
115
116static guint account_creation_wizard_signals[LAST_SIGNAL] = { 0 };
117
118static void
119destroy_avatar_manipulation(AccountCreationWizard *view)
120{
121 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
122
123 /* make sure the AvatarManipulation widget is destroyed so the VideoWidget inside of it is too;
124 * NOTE: destorying its parent (box_avatarselection) first will cause a mystery 'BadDrawable'
125 * crash due to X error */
126 if (priv->avatar_manipulation)
127 {
128 gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation);
129 priv->avatar_manipulation = nullptr;
130 }
131}
132
133static void
134account_creation_wizard_dispose(GObject *object)
135{
136 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(object);
137 destroy_avatar_manipulation(ACCOUNT_CREATION_WIZARD(object));
138 QObject::disconnect(priv->account_state_changed);
139 G_OBJECT_CLASS(account_creation_wizard_parent_class)->dispose(object);
140}
141
142static void
143account_creation_wizard_init(AccountCreationWizard *view)
144{
145 gtk_widget_init_template(GTK_WIDGET(view));
146}
147
148static void
149account_creation_wizard_class_init(AccountCreationWizardClass *klass)
150{
151 G_OBJECT_CLASS(klass)->dispose = account_creation_wizard_dispose;
152
153 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
154 "/cx/ring/RingGnome/accountcreationwizard.ui");
155
156 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, stack_account_creation);
157
158 /* choose_account_type_vbox */
159 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_vbox);
160 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_ring_logo);
161 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_account);
162 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account);
163 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_wizard_cancel);
164
Adrien Beraud50215a42017-09-15 20:24:52 +0200165 /* existing account */
166 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account);
167 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_next);
168 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_previous);
aviau6aeb4852016-08-18 16:01:09 -0400169 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_pin);
Adrien Beraud50215a42017-09-15 20:24:52 +0200170 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_archive);
aviau6aeb4852016-08-18 16:01:09 -0400171 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_password);
172 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, retrieving_account);
173
174 /* account creation */
175 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, account_creation);
aviau6aeb4852016-08-18 16:01:09 -0400176 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password);
177 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password_confirm);
aviau6aeb4852016-08-18 16:01:09 -0400178 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_next);
179 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_previous);
180 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_avatarselection);
181 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, label_password_error);
aviau2da3d9c2016-09-06 11:28:36 -0400182 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_username_entry);
183 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, checkbutton_sign_up_blockchain);
aviau692fe6d2016-11-08 14:37:34 -0500184 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_display_name);
aviau6aeb4852016-08-18 16:01:09 -0400185
186 /* generating_account_spinner */
187 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_generating_account_spinner);
188
aviau2da3d9c2016-09-06 11:28:36 -0400189 /* registering_username_spinner */
190 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_registering_username_spinner);
191
aviau6aeb4852016-08-18 16:01:09 -0400192 /* error view */
193 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, error_view);
194 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_error_view_ok);
195
196 /* add signals */
197 account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED] = g_signal_new("account-creation-completed",
198 G_TYPE_FROM_CLASS(klass),
199 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
200 0,
201 nullptr,
202 nullptr,
203 g_cclosure_marshal_VOID__VOID,
204 G_TYPE_NONE, 0);
205
206 account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED] = g_signal_new("account-creation-canceled",
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
216static void
217show_error_view(AccountCreationWizard *view)
218{
219 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
220 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->error_view);
221}
222
aviau2da3d9c2016-09-06 11:28:36 -0400223static void
224could_not_register_username_dialog(AccountCreationWizard *view)
225{
226 GtkWidget* dialog = gtk_message_dialog_new(
227 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))),
228 GTK_DIALOG_DESTROY_WITH_PARENT,
229 GTK_MESSAGE_ERROR,
230 GTK_BUTTONS_OK,
231 _("Your account was created, but we could not register your username. Try again from the settings menu.")
232 );
233 gtk_dialog_run(GTK_DIALOG (dialog));
234 gtk_widget_destroy(dialog);
235}
236
237static void
238show_registering_on_blockchain_spinner(AccountCreationWizard *view)
239{
240 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
241 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_registering_username_spinner);
242}
243
aviau6aeb4852016-08-18 16:01:09 -0400244static gboolean
245create_ring_account(AccountCreationWizard *view,
aviau692fe6d2016-11-08 14:37:34 -0500246 gchar *display_name,
247 gchar *username,
aviau6aeb4852016-08-18 16:01:09 -0400248 gchar *password,
Adrien Beraud50215a42017-09-15 20:24:52 +0200249 gchar *pin,
250 gchar *archivePath)
aviau6aeb4852016-08-18 16:01:09 -0400251{
aviau692fe6d2016-11-08 14:37:34 -0500252
aviau6aeb4852016-08-18 16:01:09 -0400253 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(view), G_SOURCE_REMOVE);
254 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
255
aviau2da3d9c2016-09-06 11:28:36 -0400256 // Copy password and alias, which will be used in our callbacks
aviau692fe6d2016-11-08 14:37:34 -0500257 priv->username = new QString(username);
aviau2da3d9c2016-09-06 11:28:36 -0400258 priv->password = new QString(password);
aviau2da3d9c2016-09-06 11:28:36 -0400259
aviau6aeb4852016-08-18 16:01:09 -0400260 g_object_ref(view); // ref so its not desroyed too early
261
262 /* create account and set UPnP enabled, as its not by default in the daemon */
263 Account *account = nullptr;
264
265 /* get profile (if so) */
266 auto profile = ProfileModel::instance().selectedProfile();
267
aviau692fe6d2016-11-08 14:37:34 -0500268 if (display_name && strlen(display_name) > 0) {
269 account = AccountModel::instance().add(display_name, Account::Protocol::RING);
aviau6aeb4852016-08-18 16:01:09 -0400270 if(profile && AccountModel::instance().size() == 1)
271 {
aviau692fe6d2016-11-08 14:37:34 -0500272 profile->person()->setFormattedName(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400273 }
274 } else {
275 auto unknown_alias = C_("The default username / account alias, if none is set by the user", "Unknown");
276 account = AccountModel::instance().add(unknown_alias, Account::Protocol::RING);
277 if (profile && AccountModel::instance().size() == 1)
278 {
279 profile->person()->setFormattedName(unknown_alias);
280 }
281 }
282
283 /* Set the archive password */
284 account->setArchivePassword(password);
285
286 /* Set the archive pin (existng accounts) */
287 if(pin)
288 {
289 account->setArchivePin(pin);
290 }
Adrien Beraud50215a42017-09-15 20:24:52 +0200291 if (archivePath)
292 {
293 account->setArchivePath(archivePath);
294 }
aviau6aeb4852016-08-18 16:01:09 -0400295
aviau692fe6d2016-11-08 14:37:34 -0500296 account->setDisplayName(display_name); // set the display name to the same as the alias
aviau6aeb4852016-08-18 16:01:09 -0400297
298 account->setUpnpEnabled(TRUE);
299
300 /* show error window if the account errors */
301 priv->account_state_changed = QObject::connect(
302 account,
303 &Account::stateChanged,
304 [=] (Account::RegistrationState state) {
305 switch(state)
306 {
307 case Account::RegistrationState::ERROR:
308 {
309 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
310 QObject::disconnect(priv->account_state_changed);
311 show_error_view(view);
312 g_object_unref(view);
313 break;
314 }
315 case Account::RegistrationState::READY:
316 case Account::RegistrationState::TRYING:
317 case Account::RegistrationState::UNREGISTERED:
318 {
319 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
320 QObject::disconnect(priv->account_state_changed);
321
322 account << Account::EditAction::RELOAD;
aviau2da3d9c2016-09-06 11:28:36 -0400323
324 // Now try to register the username
aviau692fe6d2016-11-08 14:37:34 -0500325 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 -0400326 {
327 priv->name_registration_ended = QObject::connect(
328 account,
329 &Account::nameRegistrationEnded,
330 [=] (NameDirectory::RegisterNameStatus status, G_GNUC_UNUSED const QString& name) {
331 QObject::disconnect(priv->name_registration_ended);
332 switch(status)
333 {
334 case NameDirectory::RegisterNameStatus::INVALID_NAME:
335 case NameDirectory::RegisterNameStatus::WRONG_PASSWORD:
336 case NameDirectory::RegisterNameStatus::ALREADY_TAKEN:
337 case NameDirectory::RegisterNameStatus::NETWORK_ERROR:
338 {
339 could_not_register_username_dialog(view);
Sébastien Blin55bff9d2017-10-03 15:15:23 -0400340 // Reload so that the username is displayed in the settings
341 account << Account::EditAction::RELOAD;
342 break;
aviau2da3d9c2016-09-06 11:28:36 -0400343 }
344 case NameDirectory::RegisterNameStatus::SUCCESS:
345 {
346 // Reload so that the username is displayed in the settings
347 account << Account::EditAction::RELOAD;
348 break;
349 }
350 }
351 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
352 g_object_unref(view);
353 }
354 );
355
356 show_registering_on_blockchain_spinner(view);
357
aviau692fe6d2016-11-08 14:37:34 -0500358 bool register_name_result = account->registerName(*priv->password, *priv->username);
359 priv->username->clear();
aviau2da3d9c2016-09-06 11:28:36 -0400360 priv->password->clear();
aviau2da3d9c2016-09-06 11:28:36 -0400361
362 if (register_name_result == FALSE)
363 {
364 g_debug("Could not initialize registerName operation");
365 could_not_register_username_dialog(view);
366 QObject::disconnect(priv->name_registration_ended);
367 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
368 g_object_unref(view);
369 }
370 }
371 else
372 {
373 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
374 g_object_unref(view);
375 }
aviau6aeb4852016-08-18 16:01:09 -0400376 break;
377 }
378 case Account::RegistrationState::INITIALIZING:
379 case Account::RegistrationState::COUNT__:
380 {
381 // Keep waiting...
382 break;
383 }
384 }
385 }
386 );
387
388 account->performAction(Account::EditAction::SAVE);
389 profile->save();
390
391 return G_SOURCE_REMOVE;
392}
393
394static gboolean
395create_new_ring_account(AccountCreationWizard *win)
396{
397 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
398 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
399
Stepan Salenikovichec16deb2017-04-14 14:18:37 -0400400 /* Tuleap: #1441
401 * if the user did not validate the avatar area selection, we still take that as the image
402 * for their avatar; otherwise many users end up with no avatar by default
403 * TODO: improve avatar creation process to not need this fix
404 */
405 avatar_manipulation_wizard_completed(AVATAR_MANIPULATION(priv->avatar_manipulation));
406
aviau692fe6d2016-11-08 14:37:34 -0500407 gchar *display_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name)));
408 gchar *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_username)));
aviau6aeb4852016-08-18 16:01:09 -0400409 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_password)));
410 gtk_entry_set_text(GTK_ENTRY(priv->entry_password), "");
411 gtk_entry_set_text(GTK_ENTRY(priv->entry_password_confirm), "");
412
Adrien Beraud50215a42017-09-15 20:24:52 +0200413 auto status = create_ring_account(win, display_name, username, password, nullptr, nullptr);
aviau6aeb4852016-08-18 16:01:09 -0400414
aviau692fe6d2016-11-08 14:37:34 -0500415 g_free(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400416 g_free(password);
aviau692fe6d2016-11-08 14:37:34 -0500417 g_free(username);
aviau6aeb4852016-08-18 16:01:09 -0400418
419 return status;
420}
421
422static gboolean
423create_existing_ring_account(AccountCreationWizard *win)
424{
425 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
426 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
427
428 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password)));
429 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), "");
430
Adrien Beraud50215a42017-09-15 20:24:52 +0200431 gchar *pin = nullptr;
432 auto curPin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
433 if (curPin and strlen(curPin) > 0) {
434 pin = g_strdup(curPin);
435 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), "");
436 }
aviau6aeb4852016-08-18 16:01:09 -0400437
Adrien Beraud50215a42017-09-15 20:24:52 +0200438 gchar *archive = nullptr;
439 auto archivePath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
440 if (archivePath) {
441 archive = g_strdup(archivePath);
442 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive), nullptr);
443 }
444
445 auto status = create_ring_account(win, NULL, NULL, password, pin, archive);
aviau6aeb4852016-08-18 16:01:09 -0400446
447 g_free(password);
448 g_free(pin);
449
450 return status;
451}
452
aviau6aeb4852016-08-18 16:01:09 -0400453static void
454show_generating_account_spinner(AccountCreationWizard *view)
455{
456 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
457 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_generating_account_spinner);
458}
459
460static void
461account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win)
462{
463 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
464
465 /* Check for correct password */
466 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
467 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
468
469 if (g_strcmp0(password, password_confirm) != 0)
470 {
aviau2da3d9c2016-09-06 11:28:36 -0400471 gtk_label_set_text(GTK_LABEL(priv->label_password_error), _("Passwords don't match"));
aviau6aeb4852016-08-18 16:01:09 -0400472 return;
473 }
474
475 show_generating_account_spinner(win);
476
477 /* now create account after a short timeout so that the the save doesn't
478 * happen freeze the client before the widget changes happen;
479 * the timeout function should then display the next step in account creation
480 */
481 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_ring_account, win, NULL);
482}
483
484static void
485show_retrieving_account(AccountCreationWizard *win)
486{
487 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
488 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->retrieving_account);
489}
490
491static void
Adrien Beraud50215a42017-09-15 20:24:52 +0200492existing_account_next_clicked(AccountCreationWizard *win)
aviau6aeb4852016-08-18 16:01:09 -0400493{
494 show_retrieving_account(win);
495
496 /* now create account after a short timeout so that the the save doesn't
497 * happen freeze the client before the widget changes happen;
498 * the timeout function should then display the next step in account creation
499 */
500 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_existing_ring_account, win, NULL);
501}
502
503static void
aviau6aeb4852016-08-18 16:01:09 -0400504show_choose_account_type(AccountCreationWizard *view)
505{
506 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
507 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->choose_account_type_vbox);
508}
509
510static void
Adrien Beraud50215a42017-09-15 20:24:52 +0200511show_existing_account(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400512{
513 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200514 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account);
aviau6aeb4852016-08-18 16:01:09 -0400515}
516
517static void
518show_account_creation(AccountCreationWizard *win)
519{
520 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
521
522 /* avatar manipulation widget */
523 if (!priv->avatar_manipulation)
524 {
525 priv->avatar_manipulation = avatar_manipulation_new_from_wizard();
526 gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
527 }
528
aviau6aeb4852016-08-18 16:01:09 -0400529 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
530}
531
532static void
533wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
534{
535 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
536}
537
538static void
539entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationWizard *view)
540{
541 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
542
543 const gchar *pin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
Adrien Beraud50215a42017-09-15 20:24:52 +0200544 const gchar *archive_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
545
546 bool hasPin = pin and strlen(pin) > 0;
547 bool hasArchive = archive_path and strlen(archive_path) > 0;
aviau6aeb4852016-08-18 16:01:09 -0400548
aviau16a94be2016-11-10 17:37:32 -0500549 gtk_widget_set_sensitive(
Adrien Beraud50215a42017-09-15 20:24:52 +0200550 priv->entry_existing_account_pin,
551 (not hasArchive)
552 );
553 gtk_widget_set_sensitive(
554 priv->entry_existing_account_archive,
555 (not hasPin)
556 );
557 gtk_widget_set_sensitive(
558 priv->button_existing_account_next,
559 (hasArchive || hasPin)
aviau16a94be2016-11-10 17:37:32 -0500560 );
aviau6aeb4852016-08-18 16:01:09 -0400561}
562
563static void
aviau2da3d9c2016-09-06 11:28:36 -0400564entries_new_account_changed(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400565{
566 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
567
aviau692fe6d2016-11-08 14:37:34 -0500568 const gchar *display_name = gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name));
569 const gchar *username = gtk_entry_get_text(GTK_ENTRY(priv->entry_username));
aviau2da3d9c2016-09-06 11:28:36 -0400570 const gboolean sign_up_blockchain = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->checkbutton_sign_up_blockchain));
aviau6aeb4852016-08-18 16:01:09 -0400571
aviau2da3d9c2016-09-06 11:28:36 -0400572 if (
aviau692fe6d2016-11-08 14:37:34 -0500573 strlen(display_name) > 0 && // Display name is longer than 0
aviau692fe6d2016-11-08 14:37:34 -0500574 (
575 (sign_up_blockchain && strlen(username) > 0 && priv->username_available) || // we are signing up, username is set and avaialble
576 !sign_up_blockchain // We are not signing up
577 )
aviau2da3d9c2016-09-06 11:28:36 -0400578 )
aviau6aeb4852016-08-18 16:01:09 -0400579 {
580 gtk_widget_set_sensitive(priv->button_account_creation_next, TRUE);
581 }
582 else
583 {
584 gtk_widget_set_sensitive(priv->button_account_creation_next, FALSE);
585 }
586}
587
588static void
aviau2da3d9c2016-09-06 11:28:36 -0400589checkbutton_sign_up_blockchain_toggled(GtkToggleButton *toggle_button, AccountCreationWizard *view)
590{
591 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
592 gboolean sign_up_blockchain = gtk_toggle_button_get_active(toggle_button);
593
594
595 username_registration_box_set_use_blockchain(
596 USERNAME_REGISTRATION_BOX(priv->username_registration_box),
597 sign_up_blockchain
598 );
599
aviau692fe6d2016-11-08 14:37:34 -0500600 gtk_widget_set_sensitive(priv->entry_username, sign_up_blockchain);
601
602 if (!sign_up_blockchain)
603 {
604 gtk_entry_set_text(GTK_ENTRY(priv->entry_username), "");
605 }
606
aviau2da3d9c2016-09-06 11:28:36 -0400607 /* Unchecking blockchain signup when there is an empty username should
608 * result in activating the next button.
609 */
610 entries_new_account_changed(view);
611}
612
613static void
614username_availability_changed(AccountCreationWizard *view, gboolean username_available)
615{
616 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
617 priv->username_available = username_available;
618 entries_new_account_changed(view);
619}
620
621static void
622build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_button)
aviau6aeb4852016-08-18 16:01:09 -0400623{
624 g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
625 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
626
627 /* set ring logo */
628 GError *error = NULL;
629 GdkPixbuf* logo_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-logo-blue",
630 -1, 50, TRUE, &error);
631 if (logo_ring == NULL) {
632 g_debug("Could not load logo: %s", error->message);
633 g_clear_error(&error);
634 } else
635 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->choose_account_type_ring_logo), logo_ring);
636
aviau2da3d9c2016-09-06 11:28:36 -0400637 /* create the username_registration_box */
638 priv->username_registration_box = username_registration_box_new(nullptr, FALSE);
639 gtk_container_add(GTK_CONTAINER(priv->box_username_entry), priv->username_registration_box);
640 gtk_widget_show(priv->username_registration_box);
aviau692fe6d2016-11-08 14:37:34 -0500641 priv->entry_username = GTK_WIDGET(
aviau2da3d9c2016-09-06 11:28:36 -0400642 username_registration_box_get_entry(
643 USERNAME_REGISTRATION_BOX(priv->username_registration_box)
644 )
645 );
aviau6aeb4852016-08-18 16:01:09 -0400646
647 /* use the real name / username of the logged in user as the default */
648 const char* real_name = g_get_real_name();
649 const char* user_name = g_get_user_name();
650 g_debug("real_name = %s",real_name);
651 g_debug("user_name = %s",user_name);
652
653 /* check first if the real name was determined */
654 if (g_strcmp0 (real_name,"Unknown") != 0)
aviau692fe6d2016-11-08 14:37:34 -0500655 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), real_name);
aviau6aeb4852016-08-18 16:01:09 -0400656 else
aviau692fe6d2016-11-08 14:37:34 -0500657 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), user_name);
658
aviau6aeb4852016-08-18 16:01:09 -0400659 /* cancel button */
660 gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button);
661
662 /* choose_account_type signals */
663 g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(show_account_creation), view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200664 g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account), view);
aviau6aeb4852016-08-18 16:01:09 -0400665 g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view);
666
667 /* account_creation signals */
668 g_signal_connect_swapped(priv->button_account_creation_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
aviau692fe6d2016-11-08 14:37:34 -0500669 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400670 g_signal_connect(priv->button_account_creation_next, "clicked", G_CALLBACK(account_creation_next_clicked), view);
aviau2da3d9c2016-09-06 11:28:36 -0400671 g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(entries_new_account_changed), view);
672 g_signal_connect_swapped(priv->entry_password_confirm, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau692fe6d2016-11-08 14:37:34 -0500673 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
674 g_signal_connect_swapped(priv->entry_display_name, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau2da3d9c2016-09-06 11:28:36 -0400675 g_signal_connect(priv->checkbutton_sign_up_blockchain, "toggled", G_CALLBACK(checkbutton_sign_up_blockchain_toggled), view);
676 g_signal_connect_swapped(priv->username_registration_box, "username-availability-changed", G_CALLBACK(username_availability_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400677
Adrien Beraud50215a42017-09-15 20:24:52 +0200678 /* existing_account signals */
679 g_signal_connect_swapped(priv->button_existing_account_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
680 g_signal_connect_swapped(priv->button_existing_account_next, "clicked", G_CALLBACK(existing_account_next_clicked), view);
aviau6aeb4852016-08-18 16:01:09 -0400681 g_signal_connect(priv->entry_existing_account_pin, "changed", G_CALLBACK(entries_existing_account_changed), view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200682 g_signal_connect(priv->entry_existing_account_archive, "file-set", G_CALLBACK(entries_existing_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400683 g_signal_connect(priv->entry_existing_account_password, "changed", G_CALLBACK(entries_existing_account_changed), view);
684
685 /* error_view signals */
686 g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(show_choose_account_type), view);
687
688 show_choose_account_type(view);
689}
690
691GtkWidget *
692account_creation_wizard_new(bool show_cancel_button)
693{
694 gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL);
695
696 build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button);
697 return (GtkWidget *)view;
698}