blob: fc9d7296220a9684431c39702f6156754eee2825 [file] [log] [blame]
aviau6aeb4852016-08-18 16:01:09 -04001/*
Guillaume Roguez77c579d2018-01-30 15:54:02 -05002 * Copyright (C) 2016-2018 Savoir-faire Linux Inc.
aviau6aeb4852016-08-18 16:01:09 -04003 * Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
Hugo Lefeuvre24356d42018-05-11 10:41:41 -04004 * Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com>
aviau6aeb4852016-08-18 16:01:09 -04005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
aviau6aeb4852016-08-18 16:01:09 -040021// GTK+ related
22#include <glib/gi18n.h>
23#include <gtk/gtk.h>
24
25// LRC
26#include <account.h>
27#include <codecmodel.h>
28#include <profilemodel.h>
29#include <profile.h>
30#include <accountmodel.h>
31#include <personmodel.h>
Sébastien Blin61c19d12018-05-16 12:55:34 -040032#include "api/newaccountmodel.h"
aviau6aeb4852016-08-18 16:01:09 -040033
34// Ring Client
35#include "utils/models.h"
36#include "avatarmanipulation.h"
37#include "accountcreationwizard.h"
aviau2da3d9c2016-09-06 11:28:36 -040038#include "usernameregistrationbox.h"
aviau6aeb4852016-08-18 16:01:09 -040039
aviau6aeb4852016-08-18 16:01:09 -040040struct _AccountCreationWizard
41{
42 GtkBox parent;
43};
44
45struct _AccountCreationWizardClass
46{
47 GtkBoxClass parent_class;
48};
49
50typedef struct _AccountCreationWizardPrivate AccountCreationWizardPrivate;
51
52struct _AccountCreationWizardPrivate
53{
Sébastien Blin61c19d12018-05-16 12:55:34 -040054 AccountInfoPointer const *accountInfo_ = nullptr;
55 gchar* accountId;
56 gchar* username;
57 gchar* password;
58 gchar* avatar;
59
aviau6aeb4852016-08-18 16:01:09 -040060 GtkWidget *stack_account_creation;
61 QMetaObject::Connection account_state_changed;
aviau2da3d9c2016-09-06 11:28:36 -040062 QMetaObject::Connection name_registration_ended;
63 gboolean username_available;
64
aviau6aeb4852016-08-18 16:01:09 -040065 /* choose_account_type_vbox */
66 GtkWidget *choose_account_type_vbox;
67 GtkWidget *choose_account_type_ring_logo;
68 GtkWidget *button_new_account;
69 GtkWidget *button_existing_account;
70 GtkWidget *button_wizard_cancel;
Sébastien Blin61c19d12018-05-16 12:55:34 -040071 GtkWidget *button_show_advanced;
72 GtkWidget *button_new_sip_account;
aviau6aeb4852016-08-18 16:01:09 -040073
Adrien Beraud50215a42017-09-15 20:24:52 +020074 /* existing account */
75 GtkWidget *existing_account;
76 GtkWidget *button_existing_account_next;
77 GtkWidget *button_existing_account_previous;
aviau6aeb4852016-08-18 16:01:09 -040078 GtkWidget *entry_existing_account_pin;
Adrien Beraud50215a42017-09-15 20:24:52 +020079 GtkWidget *entry_existing_account_archive;
aviau6aeb4852016-08-18 16:01:09 -040080 GtkWidget *entry_existing_account_password;
81 GtkWidget *retrieving_account;
82
83 /* account creation */
84 GtkWidget *account_creation;
aviau692fe6d2016-11-08 14:37:34 -050085 GtkWidget *entry_username;
aviau6aeb4852016-08-18 16:01:09 -040086 GtkWidget *entry_password;
87 GtkWidget *entry_password_confirm;
Sébastien Blina8ac86b2018-06-29 09:52:40 -040088 GtkWidget *label_password_error;
aviau6aeb4852016-08-18 16:01:09 -040089 GtkWidget *button_account_creation_next;
90 GtkWidget *button_account_creation_previous;
91 GtkWidget *box_avatarselection;
92 GtkWidget *avatar_manipulation;
aviau2da3d9c2016-09-06 11:28:36 -040093 GtkWidget *box_username_entry;
Sébastien Blina8ac86b2018-06-29 09:52:40 -040094 GtkWidget *switch_register;
aviau2da3d9c2016-09-06 11:28:36 -040095 GtkWidget *username_registration_box;
aviau692fe6d2016-11-08 14:37:34 -050096 GtkWidget *entry_display_name;
aviau6aeb4852016-08-18 16:01:09 -040097
98 /* generating_account_spinner */
99 GtkWidget *vbox_generating_account_spinner;
100
aviau2da3d9c2016-09-06 11:28:36 -0400101 /* registering_username_spinner */
102 GtkWidget *vbox_registering_username_spinner;
103
aviau6aeb4852016-08-18 16:01:09 -0400104 /* error_view */
105 GtkWidget *error_view;
106 GtkWidget *button_error_view_ok;
107
108};
109
110G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_TYPE_BOX);
111
112#define ACCOUNT_CREATION_WIZARD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_CREATION_WIZARD_TYPE, AccountCreationWizardPrivate))
113
114/* signals */
115enum {
116 ACCOUNT_CREATION_CANCELED,
117 ACCOUNT_CREATION_COMPLETED,
118 LAST_SIGNAL
119};
120
121static guint account_creation_wizard_signals[LAST_SIGNAL] = { 0 };
122
123static void
aviau6aeb4852016-08-18 16:01:09 -0400124account_creation_wizard_dispose(GObject *object)
125{
126 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(object);
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400127
128 // make sure preview is stopped and destroyed
129 account_creation_wizard_show_preview(ACCOUNT_CREATION_WIZARD(object), FALSE);
130
aviau6aeb4852016-08-18 16:01:09 -0400131 QObject::disconnect(priv->account_state_changed);
132 G_OBJECT_CLASS(account_creation_wizard_parent_class)->dispose(object);
133}
134
135static void
136account_creation_wizard_init(AccountCreationWizard *view)
137{
138 gtk_widget_init_template(GTK_WIDGET(view));
139}
140
141static void
142account_creation_wizard_class_init(AccountCreationWizardClass *klass)
143{
144 G_OBJECT_CLASS(klass)->dispose = account_creation_wizard_dispose;
145
146 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
147 "/cx/ring/RingGnome/accountcreationwizard.ui");
148
149 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, stack_account_creation);
150
151 /* choose_account_type_vbox */
152 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_vbox);
153 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_ring_logo);
154 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_account);
155 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account);
156 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_wizard_cancel);
Sébastien Blin61c19d12018-05-16 12:55:34 -0400157 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_show_advanced);
158 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_sip_account);
aviau6aeb4852016-08-18 16:01:09 -0400159
Adrien Beraud50215a42017-09-15 20:24:52 +0200160 /* existing account */
161 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account);
162 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_next);
163 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_previous);
aviau6aeb4852016-08-18 16:01:09 -0400164 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_pin);
Adrien Beraud50215a42017-09-15 20:24:52 +0200165 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_archive);
aviau6aeb4852016-08-18 16:01:09 -0400166 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_password);
167 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, retrieving_account);
168
169 /* account creation */
170 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, account_creation);
aviau6aeb4852016-08-18 16:01:09 -0400171 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password);
172 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password_confirm);
aviau6aeb4852016-08-18 16:01:09 -0400173 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_next);
174 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_previous);
175 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_avatarselection);
176 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, label_password_error);
aviau2da3d9c2016-09-06 11:28:36 -0400177 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_username_entry);
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400178 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, switch_register);
aviau692fe6d2016-11-08 14:37:34 -0500179 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_display_name);
aviau6aeb4852016-08-18 16:01:09 -0400180
181 /* generating_account_spinner */
182 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_generating_account_spinner);
183
aviau2da3d9c2016-09-06 11:28:36 -0400184 /* registering_username_spinner */
185 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_registering_username_spinner);
186
aviau6aeb4852016-08-18 16:01:09 -0400187 /* error view */
188 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, error_view);
189 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_error_view_ok);
190
191 /* add signals */
192 account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED] = g_signal_new("account-creation-completed",
193 G_TYPE_FROM_CLASS(klass),
194 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
195 0,
196 nullptr,
197 nullptr,
198 g_cclosure_marshal_VOID__VOID,
199 G_TYPE_NONE, 0);
200
201 account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED] = g_signal_new("account-creation-canceled",
202 G_TYPE_FROM_CLASS(klass),
203 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
204 0,
205 nullptr,
206 nullptr,
207 g_cclosure_marshal_VOID__VOID,
208 G_TYPE_NONE, 0);
209}
210
Sébastien Blin61c19d12018-05-16 12:55:34 -0400211void
212account_creation_show_error_view(AccountCreationWizard *view, const std::string& id)
aviau6aeb4852016-08-18 16:01:09 -0400213{
214 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Sébastien Blin61c19d12018-05-16 12:55:34 -0400215 if (priv->accountId && id == priv->accountId)
216 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->error_view);
aviau6aeb4852016-08-18 16:01:09 -0400217}
218
219static gboolean
220create_ring_account(AccountCreationWizard *view,
aviau692fe6d2016-11-08 14:37:34 -0500221 gchar *display_name,
222 gchar *username,
aviau6aeb4852016-08-18 16:01:09 -0400223 gchar *password,
Adrien Beraud50215a42017-09-15 20:24:52 +0200224 gchar *pin,
225 gchar *archivePath)
aviau6aeb4852016-08-18 16:01:09 -0400226{
227 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(view), G_SOURCE_REMOVE);
228 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
229
Sébastien Blin61c19d12018-05-16 12:55:34 -0400230 priv->username = g_strdup(username);
231 priv->password = g_strdup(password);
232 std::string accountId = lrc::api::NewAccountModel::createNewAccount(
233 lrc::api::profile::Type::RING,
234 display_name? display_name : "",
235 archivePath? archivePath : "",
236 password? password : "",
237 pin? pin : "");
238 priv->accountId = g_strdup(accountId.c_str());
239 priv->avatar = g_strdup(avatar_manipulation_get_temporary(AVATAR_MANIPULATION(priv->avatar_manipulation)));
240 // NOTE: NewAccountModel::accountAdded will be triggered here and will call account_creation_wizard_account_added
aviau2da3d9c2016-09-06 11:28:36 -0400241
Sébastien Blin61c19d12018-05-16 12:55:34 -0400242 g_object_ref(view); // ref so its not destroyed too early
aviau6aeb4852016-08-18 16:01:09 -0400243
244 return G_SOURCE_REMOVE;
245}
246
Sébastien Blin61c19d12018-05-16 12:55:34 -0400247void
248account_creation_wizard_account_added(AccountCreationWizard *view, AccountInfoPointer const & accountInfo)
249{
250 g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
251 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
252 priv->accountInfo_ = &accountInfo;
253 if ((*priv->accountInfo_)->id != priv->accountId) {
254 // Not for this account. Abort
255 return;
256 }
257 // Register username
258 if (priv->username) {
259 (*priv->accountInfo_)->accountModel->registerName(priv->accountId, priv->password, priv->username);
260 }
261 // Set avatar if any.
262 if (priv->avatar) {
263 try {
264 (*priv->accountInfo_)->accountModel->setAvatar(priv->accountId, priv->avatar);
265 } catch (std::out_of_range&) {
266 g_warning("Can't set avatar for unknown account");
267 }
268 }
269
270 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
271 g_object_unref(view);
272}
273
aviau6aeb4852016-08-18 16:01:09 -0400274static gboolean
275create_new_ring_account(AccountCreationWizard *win)
276{
277 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
278 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
279
Stepan Salenikovichec16deb2017-04-14 14:18:37 -0400280 /* Tuleap: #1441
281 * if the user did not validate the avatar area selection, we still take that as the image
282 * for their avatar; otherwise many users end up with no avatar by default
283 * TODO: improve avatar creation process to not need this fix
284 */
285 avatar_manipulation_wizard_completed(AVATAR_MANIPULATION(priv->avatar_manipulation));
286
aviau692fe6d2016-11-08 14:37:34 -0500287 gchar *display_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name)));
288 gchar *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_username)));
aviau6aeb4852016-08-18 16:01:09 -0400289 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_password)));
290 gtk_entry_set_text(GTK_ENTRY(priv->entry_password), "");
291 gtk_entry_set_text(GTK_ENTRY(priv->entry_password_confirm), "");
292
Adrien Beraud50215a42017-09-15 20:24:52 +0200293 auto status = create_ring_account(win, display_name, username, password, nullptr, nullptr);
aviau6aeb4852016-08-18 16:01:09 -0400294
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400295 // Now that we've use the preview to generate the avatar, we can safely close it. Don't
296 // assume owner will do it for us, this might not always be the case
297 account_creation_wizard_show_preview(win, FALSE);
298
aviau692fe6d2016-11-08 14:37:34 -0500299 g_free(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400300 g_free(password);
aviau692fe6d2016-11-08 14:37:34 -0500301 g_free(username);
aviau6aeb4852016-08-18 16:01:09 -0400302
303 return status;
304}
305
306static gboolean
307create_existing_ring_account(AccountCreationWizard *win)
308{
309 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
310 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
311
312 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password)));
313 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), "");
314
Adrien Beraud50215a42017-09-15 20:24:52 +0200315 gchar *pin = nullptr;
316 auto curPin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
317 if (curPin and strlen(curPin) > 0) {
318 pin = g_strdup(curPin);
319 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), "");
320 }
aviau6aeb4852016-08-18 16:01:09 -0400321
Adrien Beraud50215a42017-09-15 20:24:52 +0200322 gchar *archive = nullptr;
323 auto archivePath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
324 if (archivePath) {
325 archive = g_strdup(archivePath);
326 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive), nullptr);
327 }
328
329 auto status = create_ring_account(win, NULL, NULL, password, pin, archive);
aviau6aeb4852016-08-18 16:01:09 -0400330
331 g_free(password);
332 g_free(pin);
333
334 return status;
335}
336
aviau6aeb4852016-08-18 16:01:09 -0400337static void
338show_generating_account_spinner(AccountCreationWizard *view)
339{
340 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
341 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_generating_account_spinner);
342}
343
344static void
345account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win)
346{
347 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
348
349 /* Check for correct password */
350 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
351 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
352
353 if (g_strcmp0(password, password_confirm) != 0)
354 {
aviau2da3d9c2016-09-06 11:28:36 -0400355 gtk_label_set_text(GTK_LABEL(priv->label_password_error), _("Passwords don't match"));
aviau6aeb4852016-08-18 16:01:09 -0400356 return;
357 }
358
359 show_generating_account_spinner(win);
360
361 /* now create account after a short timeout so that the the save doesn't
362 * happen freeze the client before the widget changes happen;
363 * the timeout function should then display the next step in account creation
364 */
365 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_ring_account, win, NULL);
366}
367
368static void
369show_retrieving_account(AccountCreationWizard *win)
370{
371 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
372 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->retrieving_account);
373}
374
375static void
Adrien Beraud50215a42017-09-15 20:24:52 +0200376existing_account_next_clicked(AccountCreationWizard *win)
aviau6aeb4852016-08-18 16:01:09 -0400377{
378 show_retrieving_account(win);
379
380 /* now create account after a short timeout so that the the save doesn't
381 * happen freeze the client before the widget changes happen;
382 * the timeout function should then display the next step in account creation
383 */
384 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_existing_ring_account, win, NULL);
385}
386
387static void
aviau6aeb4852016-08-18 16:01:09 -0400388show_choose_account_type(AccountCreationWizard *view)
389{
390 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
391 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->choose_account_type_vbox);
392}
393
394static void
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400395account_creation_previous_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
396{
397 // make sure to stop preview before going back to choose account type
398 account_creation_wizard_show_preview(view, FALSE);
399 show_choose_account_type(view);
400}
401
402static void
Adrien Beraud50215a42017-09-15 20:24:52 +0200403show_existing_account(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400404{
405 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200406 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account);
aviau6aeb4852016-08-18 16:01:09 -0400407}
408
409static void
aviau6aeb4852016-08-18 16:01:09 -0400410wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
411{
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400412 account_creation_wizard_cancel(view);
aviau6aeb4852016-08-18 16:01:09 -0400413}
414
415static void
Sébastien Blin61c19d12018-05-16 12:55:34 -0400416show_advanced(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
417{
418 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
419 gtk_widget_set_visible(GTK_WIDGET(priv->button_new_sip_account), !gtk_widget_is_visible(GTK_WIDGET(priv->button_new_sip_account)));
420}
421
422static void
423create_new_sip_account(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
424{
425 lrc::api::NewAccountModel::createNewAccount(lrc::api::profile::Type::SIP, "SIP");
426 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
427 g_object_unref(view);
428}
429
430static void
aviau6aeb4852016-08-18 16:01:09 -0400431entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationWizard *view)
432{
433 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
434
435 const gchar *pin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
Adrien Beraud50215a42017-09-15 20:24:52 +0200436 const gchar *archive_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
437
438 bool hasPin = pin and strlen(pin) > 0;
439 bool hasArchive = archive_path and strlen(archive_path) > 0;
aviau6aeb4852016-08-18 16:01:09 -0400440
aviau16a94be2016-11-10 17:37:32 -0500441 gtk_widget_set_sensitive(
Adrien Beraud50215a42017-09-15 20:24:52 +0200442 priv->entry_existing_account_pin,
443 (not hasArchive)
444 );
445 gtk_widget_set_sensitive(
446 priv->entry_existing_account_archive,
447 (not hasPin)
448 );
449 gtk_widget_set_sensitive(
450 priv->button_existing_account_next,
451 (hasArchive || hasPin)
aviau16a94be2016-11-10 17:37:32 -0500452 );
aviau6aeb4852016-08-18 16:01:09 -0400453}
454
455static void
aviau2da3d9c2016-09-06 11:28:36 -0400456entries_new_account_changed(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400457{
458 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
459
aviau692fe6d2016-11-08 14:37:34 -0500460 const gchar *display_name = gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name));
461 const gchar *username = gtk_entry_get_text(GTK_ENTRY(priv->entry_username));
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400462 const gboolean sign_up_blockchain = gtk_switch_get_active(GTK_SWITCH(priv->switch_register));
aviau6aeb4852016-08-18 16:01:09 -0400463
aviau2da3d9c2016-09-06 11:28:36 -0400464 if (
aviau692fe6d2016-11-08 14:37:34 -0500465 strlen(display_name) > 0 && // Display name is longer than 0
aviau692fe6d2016-11-08 14:37:34 -0500466 (
467 (sign_up_blockchain && strlen(username) > 0 && priv->username_available) || // we are signing up, username is set and avaialble
468 !sign_up_blockchain // We are not signing up
469 )
aviau2da3d9c2016-09-06 11:28:36 -0400470 )
aviau6aeb4852016-08-18 16:01:09 -0400471 {
472 gtk_widget_set_sensitive(priv->button_account_creation_next, TRUE);
473 }
474 else
475 {
476 gtk_widget_set_sensitive(priv->button_account_creation_next, FALSE);
477 }
478}
479
480static void
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400481sign_up_blockchain_switched(GtkSwitch* switch_btn, GParamSpec*, AccountCreationWizard *view)
aviau2da3d9c2016-09-06 11:28:36 -0400482{
483 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400484 gboolean sign_up_blockchain = gtk_switch_get_active(switch_btn);
aviau2da3d9c2016-09-06 11:28:36 -0400485
486 username_registration_box_set_use_blockchain(
487 USERNAME_REGISTRATION_BOX(priv->username_registration_box),
488 sign_up_blockchain
489 );
490
aviau692fe6d2016-11-08 14:37:34 -0500491 gtk_widget_set_sensitive(priv->entry_username, sign_up_blockchain);
492
493 if (!sign_up_blockchain)
494 {
495 gtk_entry_set_text(GTK_ENTRY(priv->entry_username), "");
496 }
497
aviau2da3d9c2016-09-06 11:28:36 -0400498 /* Unchecking blockchain signup when there is an empty username should
499 * result in activating the next button.
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400500 */
aviau2da3d9c2016-09-06 11:28:36 -0400501 entries_new_account_changed(view);
502}
503
504static void
505username_availability_changed(AccountCreationWizard *view, gboolean username_available)
506{
507 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
508 priv->username_available = username_available;
509 entries_new_account_changed(view);
510}
511
512static void
513build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_button)
aviau6aeb4852016-08-18 16:01:09 -0400514{
515 g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
516 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
517
518 /* set ring logo */
519 GError *error = NULL;
520 GdkPixbuf* logo_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-logo-blue",
521 -1, 50, TRUE, &error);
522 if (logo_ring == NULL) {
523 g_debug("Could not load logo: %s", error->message);
524 g_clear_error(&error);
525 } else
526 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->choose_account_type_ring_logo), logo_ring);
527
aviau2da3d9c2016-09-06 11:28:36 -0400528 /* create the username_registration_box */
Sébastien Blin79efc022018-06-29 11:11:09 -0400529 priv->username_registration_box = username_registration_box_new_empty(false);
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400530 gtk_box_pack_end(GTK_BOX(priv->box_username_entry), GTK_WIDGET(priv->username_registration_box), false, false, 0);
aviau2da3d9c2016-09-06 11:28:36 -0400531 gtk_widget_show(priv->username_registration_box);
aviau692fe6d2016-11-08 14:37:34 -0500532 priv->entry_username = GTK_WIDGET(
aviau2da3d9c2016-09-06 11:28:36 -0400533 username_registration_box_get_entry(
534 USERNAME_REGISTRATION_BOX(priv->username_registration_box)
535 )
536 );
aviau6aeb4852016-08-18 16:01:09 -0400537
538 /* use the real name / username of the logged in user as the default */
539 const char* real_name = g_get_real_name();
540 const char* user_name = g_get_user_name();
541 g_debug("real_name = %s",real_name);
542 g_debug("user_name = %s",user_name);
543
544 /* check first if the real name was determined */
545 if (g_strcmp0 (real_name,"Unknown") != 0)
aviau692fe6d2016-11-08 14:37:34 -0500546 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), real_name);
aviau6aeb4852016-08-18 16:01:09 -0400547 else
aviau692fe6d2016-11-08 14:37:34 -0500548 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), user_name);
549
aviau6aeb4852016-08-18 16:01:09 -0400550 /* cancel button */
551 gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button);
552
553 /* choose_account_type signals */
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400554 g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(account_creation_wizard_show_preview), view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200555 g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account), view);
aviau6aeb4852016-08-18 16:01:09 -0400556 g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view);
Sébastien Blin61c19d12018-05-16 12:55:34 -0400557 g_signal_connect(priv->button_show_advanced, "clicked", G_CALLBACK(show_advanced), view);
558 g_signal_connect(priv->button_new_sip_account, "clicked", G_CALLBACK(create_new_sip_account), view);
aviau6aeb4852016-08-18 16:01:09 -0400559
560 /* account_creation signals */
aviau692fe6d2016-11-08 14:37:34 -0500561 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400562 g_signal_connect(priv->button_account_creation_next, "clicked", G_CALLBACK(account_creation_next_clicked), view);
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400563 g_signal_connect(priv->button_account_creation_previous, "clicked", G_CALLBACK(account_creation_previous_clicked), view);
aviau2da3d9c2016-09-06 11:28:36 -0400564 g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(entries_new_account_changed), view);
565 g_signal_connect_swapped(priv->entry_password_confirm, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau692fe6d2016-11-08 14:37:34 -0500566 g_signal_connect_swapped(priv->entry_display_name, "changed", G_CALLBACK(entries_new_account_changed), view);
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400567 g_signal_connect(priv->switch_register, "notify::active", G_CALLBACK(sign_up_blockchain_switched), view);
aviau2da3d9c2016-09-06 11:28:36 -0400568 g_signal_connect_swapped(priv->username_registration_box, "username-availability-changed", G_CALLBACK(username_availability_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400569
Adrien Beraud50215a42017-09-15 20:24:52 +0200570 /* existing_account signals */
571 g_signal_connect_swapped(priv->button_existing_account_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
572 g_signal_connect_swapped(priv->button_existing_account_next, "clicked", G_CALLBACK(existing_account_next_clicked), view);
aviau6aeb4852016-08-18 16:01:09 -0400573 g_signal_connect(priv->entry_existing_account_pin, "changed", G_CALLBACK(entries_existing_account_changed), view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200574 g_signal_connect(priv->entry_existing_account_archive, "file-set", G_CALLBACK(entries_existing_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400575 g_signal_connect(priv->entry_existing_account_password, "changed", G_CALLBACK(entries_existing_account_changed), view);
576
577 /* error_view signals */
578 g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(show_choose_account_type), view);
579
580 show_choose_account_type(view);
Sébastien Blin61c19d12018-05-16 12:55:34 -0400581
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400582 gtk_button_set_relief(GTK_BUTTON(priv->button_show_advanced), GTK_RELIEF_NONE);
583
Sébastien Blin61c19d12018-05-16 12:55:34 -0400584 auto provider = gtk_css_provider_new();
585 gtk_css_provider_load_from_data(provider,
586 ".black { color: grey; font-size: 0.8em; }\
587 .transparent-button { margin-left: 10px; border: 0; background-color: rgba(0,0,0,0); margin-right: 0; padding-right: 0;}",
588 -1, nullptr
589 );
590 gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()),
591 GTK_STYLE_PROVIDER(provider),
592 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
aviau6aeb4852016-08-18 16:01:09 -0400593}
594
595GtkWidget *
596account_creation_wizard_new(bool show_cancel_button)
597{
598 gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL);
599
600 build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button);
601 return (GtkWidget *)view;
602}
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400603
604void
605account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_preview)
606{
607 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
608
609 /* Similarily to general settings view, we construct and destroy the avatar manipulation widget
610 each time the profile is made visible / hidden. While not the most elegant solution, this
611 allows us to run the preview if and only if it is displayed, and always stop it when hidden. */
612 if (show_preview && !priv->avatar_manipulation) {
613 priv->avatar_manipulation = avatar_manipulation_new_from_wizard();
614 gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
615 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
616 } else if (priv->avatar_manipulation) {
617 /* make sure the AvatarManipulation widget is destroyed so the VideoWidget inside of it is too;
618 * NOTE: destorying its parent (box_avatarselection) first will cause a mystery 'BadDrawable'
619 * crash due to X error */
620 gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation);
621 priv->avatar_manipulation = nullptr;
622 }
623}
624
625void
626account_creation_wizard_cancel(AccountCreationWizard *win)
627{
628 // make sure to stop preview before doing something else
629 account_creation_wizard_show_preview(win, FALSE);
630 g_signal_emit(G_OBJECT(win), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
631}