blob: dc5504da3dd13b83af841cc0565c66e7bf43274d [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>
aviau6aeb4852016-08-18 16:01:09 -040027#include <profilemodel.h>
28#include <profile.h>
29#include <accountmodel.h>
30#include <personmodel.h>
Sébastien Blin61c19d12018-05-16 12:55:34 -040031#include "api/newaccountmodel.h"
aviau6aeb4852016-08-18 16:01:09 -040032
33// Ring Client
34#include "utils/models.h"
35#include "avatarmanipulation.h"
36#include "accountcreationwizard.h"
aviau2da3d9c2016-09-06 11:28:36 -040037#include "usernameregistrationbox.h"
aviau6aeb4852016-08-18 16:01:09 -040038
aviau6aeb4852016-08-18 16:01:09 -040039struct _AccountCreationWizard
40{
Hugo Lefeuvre395931b2018-07-17 12:13:14 -040041 GtkScrolledWindow parent;
aviau6aeb4852016-08-18 16:01:09 -040042};
43
44struct _AccountCreationWizardClass
45{
Hugo Lefeuvre395931b2018-07-17 12:13:14 -040046 GtkScrolledWindowClass parent_class;
aviau6aeb4852016-08-18 16:01:09 -040047};
48
49typedef struct _AccountCreationWizardPrivate AccountCreationWizardPrivate;
50
51struct _AccountCreationWizardPrivate
52{
Sébastien Blin61c19d12018-05-16 12:55:34 -040053 AccountInfoPointer const *accountInfo_ = nullptr;
54 gchar* accountId;
55 gchar* username;
56 gchar* password;
57 gchar* avatar;
58
aviau6aeb4852016-08-18 16:01:09 -040059 GtkWidget *stack_account_creation;
60 QMetaObject::Connection account_state_changed;
aviau2da3d9c2016-09-06 11:28:36 -040061 QMetaObject::Connection name_registration_ended;
62 gboolean username_available;
63
aviau6aeb4852016-08-18 16:01:09 -040064 /* choose_account_type_vbox */
65 GtkWidget *choose_account_type_vbox;
66 GtkWidget *choose_account_type_ring_logo;
67 GtkWidget *button_new_account;
68 GtkWidget *button_existing_account;
69 GtkWidget *button_wizard_cancel;
Sébastien Blin61c19d12018-05-16 12:55:34 -040070 GtkWidget *button_show_advanced;
71 GtkWidget *button_new_sip_account;
aviau6aeb4852016-08-18 16:01:09 -040072
Adrien Beraud50215a42017-09-15 20:24:52 +020073 /* existing account */
74 GtkWidget *existing_account;
75 GtkWidget *button_existing_account_next;
76 GtkWidget *button_existing_account_previous;
aviau6aeb4852016-08-18 16:01:09 -040077 GtkWidget *entry_existing_account_pin;
Adrien Beraud50215a42017-09-15 20:24:52 +020078 GtkWidget *entry_existing_account_archive;
aviau6aeb4852016-08-18 16:01:09 -040079 GtkWidget *entry_existing_account_password;
80 GtkWidget *retrieving_account;
81
82 /* 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;
Sébastien Blina8ac86b2018-06-29 09:52:40 -040087 GtkWidget *label_password_error;
aviau6aeb4852016-08-18 16:01:09 -040088 GtkWidget *button_account_creation_next;
89 GtkWidget *button_account_creation_previous;
90 GtkWidget *box_avatarselection;
91 GtkWidget *avatar_manipulation;
aviau2da3d9c2016-09-06 11:28:36 -040092 GtkWidget *box_username_entry;
Sébastien Blina8ac86b2018-06-29 09:52:40 -040093 GtkWidget *switch_register;
aviau2da3d9c2016-09-06 11:28:36 -040094 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
Hugo Lefeuvre395931b2018-07-17 12:13:14 -0400109G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_TYPE_SCROLLED_WINDOW);
aviau6aeb4852016-08-18 16:01:09 -0400110
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
aviau6aeb4852016-08-18 16:01:09 -0400123account_creation_wizard_dispose(GObject *object)
124{
125 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(object);
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400126
127 // make sure preview is stopped and destroyed
128 account_creation_wizard_show_preview(ACCOUNT_CREATION_WIZARD(object), FALSE);
129
aviau6aeb4852016-08-18 16:01:09 -0400130 QObject::disconnect(priv->account_state_changed);
131 G_OBJECT_CLASS(account_creation_wizard_parent_class)->dispose(object);
132}
133
134static void
135account_creation_wizard_init(AccountCreationWizard *view)
136{
137 gtk_widget_init_template(GTK_WIDGET(view));
138}
139
140static void
141account_creation_wizard_class_init(AccountCreationWizardClass *klass)
142{
143 G_OBJECT_CLASS(klass)->dispose = account_creation_wizard_dispose;
144
145 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
146 "/cx/ring/RingGnome/accountcreationwizard.ui");
147
148 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, stack_account_creation);
149
150 /* choose_account_type_vbox */
151 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_vbox);
152 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_ring_logo);
153 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_account);
154 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account);
155 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_wizard_cancel);
Sébastien Blin61c19d12018-05-16 12:55:34 -0400156 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_show_advanced);
157 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_sip_account);
aviau6aeb4852016-08-18 16:01:09 -0400158
Adrien Beraud50215a42017-09-15 20:24:52 +0200159 /* existing account */
160 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account);
161 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_next);
162 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_previous);
aviau6aeb4852016-08-18 16:01:09 -0400163 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_pin);
Adrien Beraud50215a42017-09-15 20:24:52 +0200164 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_archive);
aviau6aeb4852016-08-18 16:01:09 -0400165 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_password);
166 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, retrieving_account);
167
168 /* account creation */
169 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, account_creation);
aviau6aeb4852016-08-18 16:01:09 -0400170 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password);
171 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password_confirm);
aviau6aeb4852016-08-18 16:01:09 -0400172 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_next);
173 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_previous);
174 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_avatarselection);
175 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, label_password_error);
aviau2da3d9c2016-09-06 11:28:36 -0400176 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_username_entry);
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400177 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, switch_register);
aviau692fe6d2016-11-08 14:37:34 -0500178 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_display_name);
aviau6aeb4852016-08-18 16:01:09 -0400179
180 /* generating_account_spinner */
181 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_generating_account_spinner);
182
aviau2da3d9c2016-09-06 11:28:36 -0400183 /* registering_username_spinner */
184 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_registering_username_spinner);
185
aviau6aeb4852016-08-18 16:01:09 -0400186 /* error view */
187 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, error_view);
188 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_error_view_ok);
189
190 /* add signals */
191 account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED] = g_signal_new("account-creation-completed",
192 G_TYPE_FROM_CLASS(klass),
193 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
194 0,
195 nullptr,
196 nullptr,
197 g_cclosure_marshal_VOID__VOID,
198 G_TYPE_NONE, 0);
199
200 account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED] = g_signal_new("account-creation-canceled",
201 G_TYPE_FROM_CLASS(klass),
202 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
203 0,
204 nullptr,
205 nullptr,
206 g_cclosure_marshal_VOID__VOID,
207 G_TYPE_NONE, 0);
208}
209
Sébastien Blin61c19d12018-05-16 12:55:34 -0400210void
211account_creation_show_error_view(AccountCreationWizard *view, const std::string& id)
aviau6aeb4852016-08-18 16:01:09 -0400212{
213 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Sébastien Blin61c19d12018-05-16 12:55:34 -0400214 if (priv->accountId && id == priv->accountId)
215 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->error_view);
aviau6aeb4852016-08-18 16:01:09 -0400216}
217
218static gboolean
219create_ring_account(AccountCreationWizard *view,
aviau692fe6d2016-11-08 14:37:34 -0500220 gchar *display_name,
221 gchar *username,
aviau6aeb4852016-08-18 16:01:09 -0400222 gchar *password,
Adrien Beraud50215a42017-09-15 20:24:52 +0200223 gchar *pin,
224 gchar *archivePath)
aviau6aeb4852016-08-18 16:01:09 -0400225{
226 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(view), G_SOURCE_REMOVE);
227 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
228
Sébastien Blin61c19d12018-05-16 12:55:34 -0400229 priv->username = g_strdup(username);
230 priv->password = g_strdup(password);
231 std::string accountId = lrc::api::NewAccountModel::createNewAccount(
232 lrc::api::profile::Type::RING,
233 display_name? display_name : "",
234 archivePath? archivePath : "",
235 password? password : "",
236 pin? pin : "");
237 priv->accountId = g_strdup(accountId.c_str());
238 priv->avatar = g_strdup(avatar_manipulation_get_temporary(AVATAR_MANIPULATION(priv->avatar_manipulation)));
239 // NOTE: NewAccountModel::accountAdded will be triggered here and will call account_creation_wizard_account_added
aviau2da3d9c2016-09-06 11:28:36 -0400240
Sébastien Blin61c19d12018-05-16 12:55:34 -0400241 g_object_ref(view); // ref so its not destroyed too early
aviau6aeb4852016-08-18 16:01:09 -0400242
243 return G_SOURCE_REMOVE;
244}
245
Sébastien Blin61c19d12018-05-16 12:55:34 -0400246void
247account_creation_wizard_account_added(AccountCreationWizard *view, AccountInfoPointer const & accountInfo)
248{
249 g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
250 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
251 priv->accountInfo_ = &accountInfo;
252 if ((*priv->accountInfo_)->id != priv->accountId) {
253 // Not for this account. Abort
254 return;
255 }
256 // Register username
257 if (priv->username) {
258 (*priv->accountInfo_)->accountModel->registerName(priv->accountId, priv->password, priv->username);
259 }
260 // Set avatar if any.
261 if (priv->avatar) {
262 try {
263 (*priv->accountInfo_)->accountModel->setAvatar(priv->accountId, priv->avatar);
264 } catch (std::out_of_range&) {
265 g_warning("Can't set avatar for unknown account");
266 }
267 }
268
269 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
270 g_object_unref(view);
271}
272
aviau6aeb4852016-08-18 16:01:09 -0400273static gboolean
274create_new_ring_account(AccountCreationWizard *win)
275{
276 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
277 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
278
Stepan Salenikovichec16deb2017-04-14 14:18:37 -0400279 /* Tuleap: #1441
280 * if the user did not validate the avatar area selection, we still take that as the image
281 * for their avatar; otherwise many users end up with no avatar by default
282 * TODO: improve avatar creation process to not need this fix
283 */
284 avatar_manipulation_wizard_completed(AVATAR_MANIPULATION(priv->avatar_manipulation));
285
aviau692fe6d2016-11-08 14:37:34 -0500286 gchar *display_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name)));
287 gchar *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_username)));
aviau6aeb4852016-08-18 16:01:09 -0400288 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_password)));
289 gtk_entry_set_text(GTK_ENTRY(priv->entry_password), "");
290 gtk_entry_set_text(GTK_ENTRY(priv->entry_password_confirm), "");
291
Adrien Beraud50215a42017-09-15 20:24:52 +0200292 auto status = create_ring_account(win, display_name, username, password, nullptr, nullptr);
aviau6aeb4852016-08-18 16:01:09 -0400293
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400294 // Now that we've use the preview to generate the avatar, we can safely close it. Don't
295 // assume owner will do it for us, this might not always be the case
296 account_creation_wizard_show_preview(win, FALSE);
297
aviau692fe6d2016-11-08 14:37:34 -0500298 g_free(display_name);
aviau6aeb4852016-08-18 16:01:09 -0400299 g_free(password);
aviau692fe6d2016-11-08 14:37:34 -0500300 g_free(username);
aviau6aeb4852016-08-18 16:01:09 -0400301
302 return status;
303}
304
305static gboolean
306create_existing_ring_account(AccountCreationWizard *win)
307{
308 g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
309 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
310
311 gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password)));
312 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), "");
313
Adrien Beraud50215a42017-09-15 20:24:52 +0200314 gchar *pin = nullptr;
315 auto curPin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
316 if (curPin and strlen(curPin) > 0) {
317 pin = g_strdup(curPin);
318 gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), "");
319 }
aviau6aeb4852016-08-18 16:01:09 -0400320
Adrien Beraud50215a42017-09-15 20:24:52 +0200321 gchar *archive = nullptr;
322 auto archivePath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
323 if (archivePath) {
324 archive = g_strdup(archivePath);
325 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive), nullptr);
326 }
327
328 auto status = create_ring_account(win, NULL, NULL, password, pin, archive);
aviau6aeb4852016-08-18 16:01:09 -0400329
330 g_free(password);
331 g_free(pin);
332
333 return status;
334}
335
aviau6aeb4852016-08-18 16:01:09 -0400336static void
337show_generating_account_spinner(AccountCreationWizard *view)
338{
339 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
340 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_generating_account_spinner);
341}
342
343static void
344account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win)
345{
346 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
347
348 /* Check for correct password */
349 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
350 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
351
352 if (g_strcmp0(password, password_confirm) != 0)
353 {
aviau2da3d9c2016-09-06 11:28:36 -0400354 gtk_label_set_text(GTK_LABEL(priv->label_password_error), _("Passwords don't match"));
aviau6aeb4852016-08-18 16:01:09 -0400355 return;
356 }
357
358 show_generating_account_spinner(win);
359
360 /* now create account after a short timeout so that the the save doesn't
361 * happen freeze the client before the widget changes happen;
362 * the timeout function should then display the next step in account creation
363 */
364 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_ring_account, win, NULL);
365}
366
367static void
368show_retrieving_account(AccountCreationWizard *win)
369{
370 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
371 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->retrieving_account);
372}
373
374static void
Adrien Beraud50215a42017-09-15 20:24:52 +0200375existing_account_next_clicked(AccountCreationWizard *win)
aviau6aeb4852016-08-18 16:01:09 -0400376{
377 show_retrieving_account(win);
378
379 /* now create account after a short timeout so that the the save doesn't
380 * happen freeze the client before the widget changes happen;
381 * the timeout function should then display the next step in account creation
382 */
383 g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_existing_ring_account, win, NULL);
384}
385
386static void
aviau6aeb4852016-08-18 16:01:09 -0400387show_choose_account_type(AccountCreationWizard *view)
388{
389 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Hugo Lefeuvre395931b2018-07-17 12:13:14 -0400390
391 /* Make sure other stack elements are hidden, otherwise their width will prevent
392 the window to be correctly resized at this stage. */
393 gtk_widget_hide(priv->account_creation);
394 gtk_widget_hide(priv->existing_account);
395
aviau6aeb4852016-08-18 16:01:09 -0400396 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->choose_account_type_vbox);
397}
398
399static void
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400400account_creation_previous_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
401{
402 // make sure to stop preview before going back to choose account type
403 account_creation_wizard_show_preview(view, FALSE);
404 show_choose_account_type(view);
405}
406
407static void
Adrien Beraud50215a42017-09-15 20:24:52 +0200408show_existing_account(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400409{
410 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Hugo Lefeuvre395931b2018-07-17 12:13:14 -0400411
412 gtk_widget_show(priv->existing_account);
Adrien Beraud50215a42017-09-15 20:24:52 +0200413 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account);
aviau6aeb4852016-08-18 16:01:09 -0400414}
415
416static void
aviau6aeb4852016-08-18 16:01:09 -0400417wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
418{
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400419 account_creation_wizard_cancel(view);
aviau6aeb4852016-08-18 16:01:09 -0400420}
421
422static void
Sébastien Blin61c19d12018-05-16 12:55:34 -0400423show_advanced(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
424{
425 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
426 gtk_widget_set_visible(GTK_WIDGET(priv->button_new_sip_account), !gtk_widget_is_visible(GTK_WIDGET(priv->button_new_sip_account)));
427}
428
429static void
430create_new_sip_account(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
431{
432 lrc::api::NewAccountModel::createNewAccount(lrc::api::profile::Type::SIP, "SIP");
433 g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
434 g_object_unref(view);
435}
436
437static void
aviau6aeb4852016-08-18 16:01:09 -0400438entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationWizard *view)
439{
440 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
441
442 const gchar *pin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
Adrien Beraud50215a42017-09-15 20:24:52 +0200443 const gchar *archive_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
444
445 bool hasPin = pin and strlen(pin) > 0;
446 bool hasArchive = archive_path and strlen(archive_path) > 0;
aviau6aeb4852016-08-18 16:01:09 -0400447
aviau16a94be2016-11-10 17:37:32 -0500448 gtk_widget_set_sensitive(
Adrien Beraud50215a42017-09-15 20:24:52 +0200449 priv->entry_existing_account_pin,
450 (not hasArchive)
451 );
452 gtk_widget_set_sensitive(
453 priv->entry_existing_account_archive,
454 (not hasPin)
455 );
456 gtk_widget_set_sensitive(
457 priv->button_existing_account_next,
458 (hasArchive || hasPin)
aviau16a94be2016-11-10 17:37:32 -0500459 );
aviau6aeb4852016-08-18 16:01:09 -0400460}
461
462static void
aviau2da3d9c2016-09-06 11:28:36 -0400463entries_new_account_changed(AccountCreationWizard *view)
aviau6aeb4852016-08-18 16:01:09 -0400464{
465 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
466
aviau692fe6d2016-11-08 14:37:34 -0500467 const gchar *display_name = gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name));
468 const gchar *username = gtk_entry_get_text(GTK_ENTRY(priv->entry_username));
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400469 const gboolean sign_up_blockchain = gtk_switch_get_active(GTK_SWITCH(priv->switch_register));
aviau6aeb4852016-08-18 16:01:09 -0400470
aviau2da3d9c2016-09-06 11:28:36 -0400471 if (
aviau692fe6d2016-11-08 14:37:34 -0500472 strlen(display_name) > 0 && // Display name is longer than 0
aviau692fe6d2016-11-08 14:37:34 -0500473 (
474 (sign_up_blockchain && strlen(username) > 0 && priv->username_available) || // we are signing up, username is set and avaialble
475 !sign_up_blockchain // We are not signing up
476 )
aviau2da3d9c2016-09-06 11:28:36 -0400477 )
aviau6aeb4852016-08-18 16:01:09 -0400478 {
479 gtk_widget_set_sensitive(priv->button_account_creation_next, TRUE);
480 }
481 else
482 {
483 gtk_widget_set_sensitive(priv->button_account_creation_next, FALSE);
484 }
485}
486
487static void
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400488sign_up_blockchain_switched(GtkSwitch* switch_btn, GParamSpec*, AccountCreationWizard *view)
aviau2da3d9c2016-09-06 11:28:36 -0400489{
490 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400491 gboolean sign_up_blockchain = gtk_switch_get_active(switch_btn);
aviau2da3d9c2016-09-06 11:28:36 -0400492
493 username_registration_box_set_use_blockchain(
494 USERNAME_REGISTRATION_BOX(priv->username_registration_box),
495 sign_up_blockchain
496 );
497
aviau692fe6d2016-11-08 14:37:34 -0500498 gtk_widget_set_sensitive(priv->entry_username, sign_up_blockchain);
499
500 if (!sign_up_blockchain)
501 {
502 gtk_entry_set_text(GTK_ENTRY(priv->entry_username), "");
503 }
504
aviau2da3d9c2016-09-06 11:28:36 -0400505 /* Unchecking blockchain signup when there is an empty username should
506 * result in activating the next button.
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400507 */
aviau2da3d9c2016-09-06 11:28:36 -0400508 entries_new_account_changed(view);
509}
510
511static void
512username_availability_changed(AccountCreationWizard *view, gboolean username_available)
513{
514 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
515 priv->username_available = username_available;
516 entries_new_account_changed(view);
517}
518
519static void
520build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_button)
aviau6aeb4852016-08-18 16:01:09 -0400521{
522 g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
523 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
524
525 /* set ring logo */
526 GError *error = NULL;
527 GdkPixbuf* logo_ring = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-logo-blue",
528 -1, 50, TRUE, &error);
529 if (logo_ring == NULL) {
530 g_debug("Could not load logo: %s", error->message);
531 g_clear_error(&error);
532 } else
533 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->choose_account_type_ring_logo), logo_ring);
534
aviau2da3d9c2016-09-06 11:28:36 -0400535 /* create the username_registration_box */
Sébastien Blin79efc022018-06-29 11:11:09 -0400536 priv->username_registration_box = username_registration_box_new_empty(false);
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400537 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 -0400538 gtk_widget_show(priv->username_registration_box);
aviau692fe6d2016-11-08 14:37:34 -0500539 priv->entry_username = GTK_WIDGET(
aviau2da3d9c2016-09-06 11:28:36 -0400540 username_registration_box_get_entry(
541 USERNAME_REGISTRATION_BOX(priv->username_registration_box)
542 )
543 );
aviau6aeb4852016-08-18 16:01:09 -0400544
545 /* use the real name / username of the logged in user as the default */
546 const char* real_name = g_get_real_name();
547 const char* user_name = g_get_user_name();
548 g_debug("real_name = %s",real_name);
549 g_debug("user_name = %s",user_name);
550
551 /* check first if the real name was determined */
552 if (g_strcmp0 (real_name,"Unknown") != 0)
aviau692fe6d2016-11-08 14:37:34 -0500553 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), real_name);
aviau6aeb4852016-08-18 16:01:09 -0400554 else
aviau692fe6d2016-11-08 14:37:34 -0500555 gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), user_name);
556
aviau6aeb4852016-08-18 16:01:09 -0400557 /* cancel button */
558 gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button);
559
560 /* choose_account_type signals */
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400561 g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(account_creation_wizard_show_preview), view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200562 g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account), view);
aviau6aeb4852016-08-18 16:01:09 -0400563 g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view);
Sébastien Blin61c19d12018-05-16 12:55:34 -0400564 g_signal_connect(priv->button_show_advanced, "clicked", G_CALLBACK(show_advanced), view);
565 g_signal_connect(priv->button_new_sip_account, "clicked", G_CALLBACK(create_new_sip_account), view);
aviau6aeb4852016-08-18 16:01:09 -0400566
567 /* account_creation signals */
aviau692fe6d2016-11-08 14:37:34 -0500568 g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400569 g_signal_connect(priv->button_account_creation_next, "clicked", G_CALLBACK(account_creation_next_clicked), view);
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400570 g_signal_connect(priv->button_account_creation_previous, "clicked", G_CALLBACK(account_creation_previous_clicked), view);
aviau2da3d9c2016-09-06 11:28:36 -0400571 g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(entries_new_account_changed), view);
572 g_signal_connect_swapped(priv->entry_password_confirm, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau692fe6d2016-11-08 14:37:34 -0500573 g_signal_connect_swapped(priv->entry_display_name, "changed", G_CALLBACK(entries_new_account_changed), view);
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400574 g_signal_connect(priv->switch_register, "notify::active", G_CALLBACK(sign_up_blockchain_switched), view);
aviau2da3d9c2016-09-06 11:28:36 -0400575 g_signal_connect_swapped(priv->username_registration_box, "username-availability-changed", G_CALLBACK(username_availability_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400576
Adrien Beraud50215a42017-09-15 20:24:52 +0200577 /* existing_account signals */
578 g_signal_connect_swapped(priv->button_existing_account_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
579 g_signal_connect_swapped(priv->button_existing_account_next, "clicked", G_CALLBACK(existing_account_next_clicked), view);
aviau6aeb4852016-08-18 16:01:09 -0400580 g_signal_connect(priv->entry_existing_account_pin, "changed", G_CALLBACK(entries_existing_account_changed), view);
Adrien Beraud50215a42017-09-15 20:24:52 +0200581 g_signal_connect(priv->entry_existing_account_archive, "file-set", G_CALLBACK(entries_existing_account_changed), view);
aviau6aeb4852016-08-18 16:01:09 -0400582 g_signal_connect(priv->entry_existing_account_password, "changed", G_CALLBACK(entries_existing_account_changed), view);
583
584 /* error_view signals */
585 g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(show_choose_account_type), view);
586
587 show_choose_account_type(view);
Sébastien Blin61c19d12018-05-16 12:55:34 -0400588
Sébastien Blina8ac86b2018-06-29 09:52:40 -0400589 gtk_button_set_relief(GTK_BUTTON(priv->button_show_advanced), GTK_RELIEF_NONE);
590
Sébastien Blin61c19d12018-05-16 12:55:34 -0400591 auto provider = gtk_css_provider_new();
592 gtk_css_provider_load_from_data(provider,
593 ".black { color: grey; font-size: 0.8em; }\
594 .transparent-button { margin-left: 10px; border: 0; background-color: rgba(0,0,0,0); margin-right: 0; padding-right: 0;}",
595 -1, nullptr
596 );
597 gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()),
598 GTK_STYLE_PROVIDER(provider),
599 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
aviau6aeb4852016-08-18 16:01:09 -0400600}
601
602GtkWidget *
603account_creation_wizard_new(bool show_cancel_button)
604{
605 gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL);
606
607 build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button);
608 return (GtkWidget *)view;
609}
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400610
611void
612account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_preview)
613{
614 AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
615
Hugo Lefeuvre395931b2018-07-17 12:13:14 -0400616 if (priv->account_creation) {
617 if (show_preview)
618 gtk_widget_show(priv->account_creation);
619 else
620 gtk_widget_hide(priv->account_creation);
621 }
622
623 /* Similarily to general settings view, we construct and destroy the avatar manipulation widget
Hugo Lefeuvre24356d42018-05-11 10:41:41 -0400624 each time the profile is made visible / hidden. While not the most elegant solution, this
625 allows us to run the preview if and only if it is displayed, and always stop it when hidden. */
626 if (show_preview && !priv->avatar_manipulation) {
627 priv->avatar_manipulation = avatar_manipulation_new_from_wizard();
628 gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
629 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
630 } else if (priv->avatar_manipulation) {
631 /* make sure the AvatarManipulation widget is destroyed so the VideoWidget inside of it is too;
632 * NOTE: destorying its parent (box_avatarselection) first will cause a mystery 'BadDrawable'
633 * crash due to X error */
634 gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation);
635 priv->avatar_manipulation = nullptr;
636 }
637}
638
639void
640account_creation_wizard_cancel(AccountCreationWizard *win)
641{
642 // make sure to stop preview before doing something else
643 account_creation_wizard_show_preview(win, FALSE);
644 g_signal_emit(G_OBJECT(win), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
645}