accountcreationwizard.cpp 26.6 KB
Newer Older
aviau's avatar
aviau committed
1
/*
Sébastien Blin's avatar
Sébastien Blin committed
2
 *  Copyright (C) 2016-2019 Savoir-faire Linux Inc.
aviau's avatar
aviau committed
3
 *  Author: Alexandre Viau <alexandre.viau@savoirfairelinux.com>
4
 *  Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com>
aviau's avatar
aviau committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 */

// GTK+ related
#include <glib/gi18n.h>
#include <gtk/gtk.h>

// LRC
26
#include "api/newaccountmodel.h"
aviau's avatar
aviau committed
27 28 29 30 31

// Ring Client
#include "utils/models.h"
#include "avatarmanipulation.h"
#include "accountcreationwizard.h"
aviau's avatar
aviau committed
32
#include "usernameregistrationbox.h"
aviau's avatar
aviau committed
33 34 35

struct _AccountCreationWizard
{
36
    GtkScrolledWindow parent;
aviau's avatar
aviau committed
37 38 39 40
};

struct _AccountCreationWizardClass
{
41
    GtkScrolledWindowClass parent_class;
aviau's avatar
aviau committed
42 43 44 45 46 47
};

typedef struct _AccountCreationWizardPrivate AccountCreationWizardPrivate;

struct _AccountCreationWizardPrivate
{
48 49 50 51 52 53
    AccountInfoPointer const *accountInfo_ = nullptr;
    gchar* accountId;
    gchar* username;
    gchar* password;
    gchar* avatar;

aviau's avatar
aviau committed
54
    GtkWidget *stack_account_creation;
aviau's avatar
aviau committed
55 56
    gboolean username_available;

aviau's avatar
aviau committed
57 58 59 60 61 62
    /* choose_account_type_vbox */
    GtkWidget *choose_account_type_vbox;
    GtkWidget *choose_account_type_ring_logo;
    GtkWidget *button_new_account;
    GtkWidget *button_existing_account;
    GtkWidget *button_wizard_cancel;
63 64
    GtkWidget *button_show_advanced;
    GtkWidget *button_new_sip_account;
aviau's avatar
aviau committed
65

66 67 68 69
    /* existing account */
    GtkWidget *existing_account;
    GtkWidget *button_existing_account_next;
    GtkWidget *button_existing_account_previous;
aviau's avatar
aviau committed
70
    GtkWidget *entry_existing_account_pin;
71
    GtkWidget *entry_existing_account_archive;
aviau's avatar
aviau committed
72 73 74 75 76
    GtkWidget *entry_existing_account_password;
    GtkWidget *retrieving_account;

    /* account creation */
    GtkWidget *account_creation;
77
    GtkWidget *entry_username;
aviau's avatar
aviau committed
78 79
    GtkWidget *entry_password;
    GtkWidget *entry_password_confirm;
80
    GtkWidget *label_password_error;
aviau's avatar
aviau committed
81 82 83 84
    GtkWidget *button_account_creation_next;
    GtkWidget *button_account_creation_previous;
    GtkWidget *box_avatarselection;
    GtkWidget *avatar_manipulation;
aviau's avatar
aviau committed
85
    GtkWidget *box_username_entry;
86
    GtkWidget *switch_register;
aviau's avatar
aviau committed
87
    GtkWidget *username_registration_box;
88
    GtkWidget *entry_display_name;
aviau's avatar
aviau committed
89 90 91 92

    /* generating_account_spinner */
    GtkWidget *vbox_generating_account_spinner;

aviau's avatar
aviau committed
93 94 95
    /* registering_username_spinner */
    GtkWidget *vbox_registering_username_spinner;

aviau's avatar
aviau committed
96 97 98 99
    /* error_view */
    GtkWidget *error_view;
    GtkWidget *button_error_view_ok;

100 101
    lrc::api::AVModel* avModel_;

aviau's avatar
aviau committed
102 103
};

104
G_DEFINE_TYPE_WITH_PRIVATE(AccountCreationWizard, account_creation_wizard, GTK_TYPE_SCROLLED_WINDOW);
aviau's avatar
aviau committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

#define ACCOUNT_CREATION_WIZARD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_CREATION_WIZARD_TYPE, AccountCreationWizardPrivate))

/* signals */
enum {
    ACCOUNT_CREATION_CANCELED,
    ACCOUNT_CREATION_COMPLETED,
    LAST_SIGNAL
};

static guint account_creation_wizard_signals[LAST_SIGNAL] = { 0 };

static void
account_creation_wizard_dispose(GObject *object)
{
120 121 122
    // make sure preview is stopped and destroyed
    account_creation_wizard_show_preview(ACCOUNT_CREATION_WIZARD(object), FALSE);

aviau's avatar
aviau committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    G_OBJECT_CLASS(account_creation_wizard_parent_class)->dispose(object);
}

static void
account_creation_wizard_init(AccountCreationWizard *view)
{
    gtk_widget_init_template(GTK_WIDGET(view));
}

static void
account_creation_wizard_class_init(AccountCreationWizardClass *klass)
{
    G_OBJECT_CLASS(klass)->dispose = account_creation_wizard_dispose;

    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
138
                                                "/net/jami/JamiGnome/accountcreationwizard.ui");
aviau's avatar
aviau committed
139 140 141 142 143 144 145 146 147

    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, stack_account_creation);

    /* choose_account_type_vbox */
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_vbox);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, choose_account_type_ring_logo);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_account);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_wizard_cancel);
148 149
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_show_advanced);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_new_sip_account);
aviau's avatar
aviau committed
150

151 152 153 154
    /* existing account */
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, existing_account);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_next);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_existing_account_previous);
aviau's avatar
aviau committed
155
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_pin);
156
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_archive);
aviau's avatar
aviau committed
157 158 159 160 161 162 163 164 165 166 167
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_existing_account_password);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, retrieving_account);

    /* account creation */
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, account_creation);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_password_confirm);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_next);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_account_creation_previous);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_avatarselection);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, label_password_error);
aviau's avatar
aviau committed
168
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, box_username_entry);
169
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, switch_register);
170
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, entry_display_name);
aviau's avatar
aviau committed
171 172 173 174

    /* generating_account_spinner */
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_generating_account_spinner);

aviau's avatar
aviau committed
175 176 177
    /* registering_username_spinner */
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, vbox_registering_username_spinner);

aviau's avatar
aviau committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    /* error view */
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, error_view);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountCreationWizard, button_error_view_ok);

    /* add signals */
    account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED] = g_signal_new("account-creation-completed",
                 G_TYPE_FROM_CLASS(klass),
                 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
                 0,
                 nullptr,
                 nullptr,
                 g_cclosure_marshal_VOID__VOID,
                 G_TYPE_NONE, 0);

    account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED] = g_signal_new("account-creation-canceled",
                 G_TYPE_FROM_CLASS(klass),
                 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
                 0,
                 nullptr,
                 nullptr,
                 g_cclosure_marshal_VOID__VOID,
                 G_TYPE_NONE, 0);
}

202 203
void
account_creation_show_error_view(AccountCreationWizard *view, const std::string& id)
aviau's avatar
aviau committed
204 205
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
206 207
    if (priv->accountId && id == priv->accountId)
        gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->error_view);
aviau's avatar
aviau committed
208 209 210 211
}

static gboolean
create_ring_account(AccountCreationWizard *view,
212 213
                    gchar *display_name,
                    gchar *username,
aviau's avatar
aviau committed
214
                    gchar *password,
215 216
                    gchar *pin,
                    gchar *archivePath)
aviau's avatar
aviau committed
217 218 219 220
{
    g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(view), G_SOURCE_REMOVE);
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);

221 222 223 224 225 226 227 228 229 230 231
    priv->username = g_strdup(username);
    priv->password = g_strdup(password);
    std::string accountId = lrc::api::NewAccountModel::createNewAccount(
                                   lrc::api::profile::Type::RING,
                                   display_name? display_name : "",
                                   archivePath? archivePath : "",
                                   password? password : "",
                                   pin? pin : "");
    priv->accountId = g_strdup(accountId.c_str());
    priv->avatar = g_strdup(avatar_manipulation_get_temporary(AVATAR_MANIPULATION(priv->avatar_manipulation)));
    // NOTE: NewAccountModel::accountAdded will be triggered here and will call account_creation_wizard_account_added
aviau's avatar
aviau committed
232

233
    g_object_ref(view);  // ref so its not destroyed too early
aviau's avatar
aviau committed
234

235 236
    return G_SOURCE_REMOVE;
}
aviau's avatar
aviau committed
237

238 239 240 241 242 243 244 245 246
void
account_creation_wizard_account_added(AccountCreationWizard *view, AccountInfoPointer const & accountInfo)
{
    g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
    priv->accountInfo_ = &accountInfo;
    if ((*priv->accountInfo_)->id != priv->accountId) {
        // Not for this account. Abort
        return;
aviau's avatar
aviau committed
247
    }
248 249 250
    // Register username
    if (priv->username) {
        (*priv->accountInfo_)->accountModel->registerName(priv->accountId, priv->password, priv->username);
251
    }
252 253 254 255 256 257
    // Set avatar if any.
    if (priv->avatar) {
        try {
            (*priv->accountInfo_)->accountModel->setAvatar(priv->accountId, priv->avatar);
        } catch (std::out_of_range&) {
            g_warning("Can't set avatar for unknown account");
aviau's avatar
aviau committed
258
        }
259
    }
aviau's avatar
aviau committed
260

261 262
    g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
    g_object_unref(view);
aviau's avatar
aviau committed
263 264 265 266 267 268 269 270
}

static gboolean
create_new_ring_account(AccountCreationWizard *win)
{
    g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);

271 272 273 274 275 276 277
    /* Tuleap: #1441
     * if the user did not validate the avatar area selection, we still take that as the image
     * for their avatar; otherwise many users end up with no avatar by default
     * TODO: improve avatar creation process to not need this fix
     */
    avatar_manipulation_wizard_completed(AVATAR_MANIPULATION(priv->avatar_manipulation));

278 279
    gchar *display_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name)));
    gchar *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_username)));
aviau's avatar
aviau committed
280 281 282 283
    gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_password)));
    gtk_entry_set_text(GTK_ENTRY(priv->entry_password), "");
    gtk_entry_set_text(GTK_ENTRY(priv->entry_password_confirm), "");

284
    auto status = create_ring_account(win, display_name, username, password, nullptr, nullptr);
aviau's avatar
aviau committed
285

286 287 288 289
    // Now that we've use the preview to generate the avatar, we can safely close it. Don't
    // assume owner will do it for us, this might not always be the case
    account_creation_wizard_show_preview(win, FALSE);

290
    g_free(display_name);
aviau's avatar
aviau committed
291
    g_free(password);
292
    g_free(username);
aviau's avatar
aviau committed
293 294 295 296 297 298 299 300 301 302 303 304 305

    return status;
}

static gboolean
create_existing_ring_account(AccountCreationWizard *win)
{
    g_return_val_if_fail(IS_ACCOUNT_CREATION_WIZARD(win), G_SOURCE_REMOVE);
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);

    gchar *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_password)));
    gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_password), "");

306 307
    gchar *pin = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin)));
    if (pin and strlen(pin) > 0) {
308 309
        gtk_entry_set_text(GTK_ENTRY(priv->entry_existing_account_pin), "");
    }
aviau's avatar
aviau committed
310

311 312
    gchar *archive = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive)));
    if (archive) {
313 314 315 316
        gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive), nullptr);
    }

    auto status = create_ring_account(win, NULL, NULL, password, pin, archive);
aviau's avatar
aviau committed
317

318
    g_free(archive);
aviau's avatar
aviau committed
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    g_free(password);
    g_free(pin);

    return status;
}

static void
show_generating_account_spinner(AccountCreationWizard *view)
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
    gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->vbox_generating_account_spinner);
}

static void
account_creation_next_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *win)
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);

    /* Check for correct password */
    const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
    const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));

    if (g_strcmp0(password, password_confirm) != 0)
    {
aviau's avatar
aviau committed
343
        gtk_label_set_text(GTK_LABEL(priv->label_password_error), _("Passwords don't match"));
aviau's avatar
aviau committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
        return;
    }

    show_generating_account_spinner(win);

    /* now create account after a short timeout so that the the save doesn't
     * happen freeze the client before the widget changes happen;
     * the timeout function should then display the next step in account creation
     */
    g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_new_ring_account, win, NULL);
}

static void
show_retrieving_account(AccountCreationWizard *win)
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);
    gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->retrieving_account);
}

static void
364
existing_account_next_clicked(AccountCreationWizard *win)
aviau's avatar
aviau committed
365 366 367 368 369 370 371 372 373 374 375 376 377 378
{
    show_retrieving_account(win);

    /* now create account after a short timeout so that the the save doesn't
     * happen freeze the client before the widget changes happen;
     * the timeout function should then display the next step in account creation
     */
    g_timeout_add_full(G_PRIORITY_DEFAULT, 300, (GSourceFunc)create_existing_ring_account, win, NULL);
}

static void
show_choose_account_type(AccountCreationWizard *view)
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
379 380 381 382 383 384

    /* Make sure other stack elements are hidden, otherwise their width will prevent
       the window to be correctly resized at this stage. */
    gtk_widget_hide(priv->account_creation);
    gtk_widget_hide(priv->existing_account);

aviau's avatar
aviau committed
385 386 387 388
    gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->choose_account_type_vbox);
}

static void
389
account_creation_previous_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
390
{
391 392 393
    // make sure to stop preview before going back to choose account type
    account_creation_wizard_show_preview(view, FALSE);
    show_choose_account_type(view);
aviau's avatar
aviau committed
394 395 396
}

static void
397
show_existing_account(AccountCreationWizard *view)
aviau's avatar
aviau committed
398
{
399
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
400 401

    gtk_widget_show(priv->existing_account);
402
    gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->existing_account);
aviau's avatar
aviau committed
403 404 405 406 407
}

static void
wizard_cancel_clicked(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
{
408
    account_creation_wizard_cancel(view);
aviau's avatar
aviau committed
409 410
}

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
static void
show_advanced(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
    gtk_widget_set_visible(GTK_WIDGET(priv->button_new_sip_account), !gtk_widget_is_visible(GTK_WIDGET(priv->button_new_sip_account)));
}

static void
create_new_sip_account(G_GNUC_UNUSED GtkButton *button, AccountCreationWizard *view)
{
    lrc::api::NewAccountModel::createNewAccount(lrc::api::profile::Type::SIP, "SIP");
    g_signal_emit(G_OBJECT(view), account_creation_wizard_signals[ACCOUNT_CREATION_COMPLETED], 0);
    g_object_unref(view);
}

aviau's avatar
aviau committed
426 427 428 429 430 431
static void
entries_existing_account_changed(G_GNUC_UNUSED GtkEntry *entry, AccountCreationWizard *view)
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);

    const gchar *pin = gtk_entry_get_text(GTK_ENTRY(priv->entry_existing_account_pin));
432
    gchar *archive_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->entry_existing_account_archive));
433 434 435

    bool hasPin = pin and strlen(pin) > 0;
    bool hasArchive = archive_path and strlen(archive_path) > 0;
aviau's avatar
aviau committed
436

437
    gtk_widget_set_sensitive(
438 439 440 441 442 443 444 445 446 447
        priv->entry_existing_account_pin,
        (not hasArchive)
    );
    gtk_widget_set_sensitive(
        priv->entry_existing_account_archive,
        (not hasPin)
    );
    gtk_widget_set_sensitive(
        priv->button_existing_account_next,
        (hasArchive || hasPin)
448
    );
449 450

    g_free(archive_path);
aviau's avatar
aviau committed
451 452 453
}

static void
aviau's avatar
aviau committed
454
entries_new_account_changed(AccountCreationWizard *view)
aviau's avatar
aviau committed
455 456 457
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);

458 459
    const gchar *display_name = gtk_entry_get_text(GTK_ENTRY(priv->entry_display_name));
    const gchar *username = gtk_entry_get_text(GTK_ENTRY(priv->entry_username));
460
    const gboolean sign_up_blockchain = gtk_switch_get_active(GTK_SWITCH(priv->switch_register));
aviau's avatar
aviau committed
461 462

    if (
463 464
            (sign_up_blockchain && strlen(username) > 0 && priv->username_available) || // we are signing up, username is set and avaialble
            !sign_up_blockchain // We are not signing up
aviau's avatar
aviau committed
465
        )
aviau's avatar
aviau committed
466 467 468 469 470 471 472 473 474 475
    {
        gtk_widget_set_sensitive(priv->button_account_creation_next, TRUE);
    }
    else
    {
        gtk_widget_set_sensitive(priv->button_account_creation_next, FALSE);
    }
}

static void
476
sign_up_blockchain_switched(GtkSwitch* switch_btn, GParamSpec*, AccountCreationWizard *view)
aviau's avatar
aviau committed
477 478
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
479
    gboolean sign_up_blockchain = gtk_switch_get_active(switch_btn);
aviau's avatar
aviau committed
480 481 482 483 484 485

    username_registration_box_set_use_blockchain(
        USERNAME_REGISTRATION_BOX(priv->username_registration_box),
        sign_up_blockchain
    );

486 487 488 489 490 491 492
    gtk_widget_set_sensitive(priv->entry_username, sign_up_blockchain);

    if (!sign_up_blockchain)
    {
        gtk_entry_set_text(GTK_ENTRY(priv->entry_username), "");
    }

aviau's avatar
aviau committed
493 494
    /* Unchecking blockchain signup when there is an empty username should
     * result in activating the next button.
495
     */
aviau's avatar
aviau committed
496 497 498 499 500 501 502 503 504 505 506 507 508
    entries_new_account_changed(view);
}

static void
username_availability_changed(AccountCreationWizard *view, gboolean username_available)
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
    priv->username_available = username_available;
    entries_new_account_changed(view);
}

static void
build_creation_wizard_view(AccountCreationWizard *view, gboolean show_cancel_button)
aviau's avatar
aviau committed
509 510 511 512 513 514
{
    g_return_if_fail(IS_ACCOUNT_CREATION_WIZARD(view));
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);

    /* set ring logo */
    GError *error = NULL;
515
    GdkPixbuf* logo_ring = gdk_pixbuf_new_from_resource_at_scale("/net/jami/JamiGnome/jami-logo-blue",
aviau's avatar
aviau committed
516 517 518 519 520 521 522
                                                                  -1, 50, TRUE, &error);
    if (logo_ring == NULL) {
        g_debug("Could not load logo: %s", error->message);
        g_clear_error(&error);
    } else
        gtk_image_set_from_pixbuf(GTK_IMAGE(priv->choose_account_type_ring_logo), logo_ring);

aviau's avatar
aviau committed
523
    /* create the username_registration_box */
524
    priv->username_registration_box = username_registration_box_new_empty(false);
525
    gtk_box_pack_end(GTK_BOX(priv->box_username_entry), GTK_WIDGET(priv->username_registration_box), false, false, 0);
aviau's avatar
aviau committed
526
    gtk_widget_show(priv->username_registration_box);
527
    priv->entry_username = GTK_WIDGET(
aviau's avatar
aviau committed
528 529 530 531
        username_registration_box_get_entry(
            USERNAME_REGISTRATION_BOX(priv->username_registration_box)
        )
    );
aviau's avatar
aviau committed
532 533 534 535 536 537 538 539 540

    /* use the real name / username of the logged in user as the default */
    const char* real_name = g_get_real_name();
    const char* user_name = g_get_user_name();
    g_debug("real_name = %s",real_name);
    g_debug("user_name = %s",user_name);

    /* check first if the real name was determined */
    if (g_strcmp0 (real_name,"Unknown") != 0)
541
        gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), real_name);
aviau's avatar
aviau committed
542
    else
543 544
        gtk_entry_set_text(GTK_ENTRY(priv->entry_display_name), user_name);

aviau's avatar
aviau committed
545 546 547 548
    /* cancel button */
    gtk_widget_set_visible(priv->button_wizard_cancel, show_cancel_button);

    /* choose_account_type signals */
549
    g_signal_connect_swapped(priv->button_new_account, "clicked", G_CALLBACK(account_creation_wizard_show_preview), view);
550
    g_signal_connect_swapped(priv->button_existing_account, "clicked", G_CALLBACK(show_existing_account), view);
aviau's avatar
aviau committed
551
    g_signal_connect(priv->button_wizard_cancel, "clicked", G_CALLBACK(wizard_cancel_clicked), view);
552 553
    g_signal_connect(priv->button_show_advanced, "clicked", G_CALLBACK(show_advanced), view);
    g_signal_connect(priv->button_new_sip_account, "clicked", G_CALLBACK(create_new_sip_account), view);
aviau's avatar
aviau committed
554 555

    /* account_creation signals */
556
    g_signal_connect_swapped(priv->entry_username, "changed", G_CALLBACK(entries_new_account_changed), view);
aviau's avatar
aviau committed
557
    g_signal_connect(priv->button_account_creation_next, "clicked", G_CALLBACK(account_creation_next_clicked), view);
558
    g_signal_connect(priv->button_account_creation_previous, "clicked", G_CALLBACK(account_creation_previous_clicked), view);
aviau's avatar
aviau committed
559 560
    g_signal_connect_swapped(priv->entry_password, "changed", G_CALLBACK(entries_new_account_changed), view);
    g_signal_connect_swapped(priv->entry_password_confirm, "changed", G_CALLBACK(entries_new_account_changed), view);
561
    g_signal_connect_swapped(priv->entry_display_name, "changed", G_CALLBACK(entries_new_account_changed), view);
562
    g_signal_connect(priv->switch_register, "notify::active", G_CALLBACK(sign_up_blockchain_switched), view);
aviau's avatar
aviau committed
563
    g_signal_connect_swapped(priv->username_registration_box, "username-availability-changed", G_CALLBACK(username_availability_changed), view);
aviau's avatar
aviau committed
564

565 566 567
    /* existing_account signals */
    g_signal_connect_swapped(priv->button_existing_account_previous, "clicked", G_CALLBACK(show_choose_account_type), view);
    g_signal_connect_swapped(priv->button_existing_account_next, "clicked", G_CALLBACK(existing_account_next_clicked), view);
aviau's avatar
aviau committed
568
    g_signal_connect(priv->entry_existing_account_pin, "changed", G_CALLBACK(entries_existing_account_changed), view);
569
    g_signal_connect(priv->entry_existing_account_archive, "file-set", G_CALLBACK(entries_existing_account_changed), view);
aviau's avatar
aviau committed
570 571 572 573 574 575
    g_signal_connect(priv->entry_existing_account_password, "changed", G_CALLBACK(entries_existing_account_changed), view);

    /* error_view signals */
    g_signal_connect_swapped(priv->button_error_view_ok, "clicked", G_CALLBACK(show_choose_account_type), view);

    show_choose_account_type(view);
576

577 578
    gtk_button_set_relief(GTK_BUTTON(priv->button_show_advanced), GTK_RELIEF_NONE);

579 580 581 582 583 584 585 586 587
    auto provider = gtk_css_provider_new();
    gtk_css_provider_load_from_data(provider,
        ".black { color: grey; font-size: 0.8em; }\
        .transparent-button { margin-left: 10px; border: 0; background-color: rgba(0,0,0,0); margin-right: 0; padding-right: 0;}",
        -1, nullptr
    );
    gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()),
                                              GTK_STYLE_PROVIDER(provider),
                                              GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
aviau's avatar
aviau committed
588 589 590
}

GtkWidget *
591
account_creation_wizard_new(bool show_cancel_button, lrc::api::AVModel& avModel)
aviau's avatar
aviau committed
592 593 594
{
    gpointer view = g_object_new(ACCOUNT_CREATION_WIZARD_TYPE, NULL);

595 596 597
    auto* priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(view);
    priv->avModel_ = &avModel;

aviau's avatar
aviau committed
598 599 600
    build_creation_wizard_view(ACCOUNT_CREATION_WIZARD(view), show_cancel_button);
    return (GtkWidget *)view;
}
601 602 603 604 605 606

void
account_creation_wizard_show_preview(AccountCreationWizard *win, gboolean show_preview)
{
    AccountCreationWizardPrivate *priv = ACCOUNT_CREATION_WIZARD_GET_PRIVATE(win);

607 608 609 610 611 612 613 614
    if (priv->account_creation) {
        if (show_preview)
            gtk_widget_show(priv->account_creation);
        else
            gtk_widget_hide(priv->account_creation);
    }

    /* Similarily to general settings view, we construct and destroy the avatar manipulation widget
615 616 617
       each time the profile is made visible / hidden. While not the most elegant solution, this
       allows us to run the preview if and only if it is displayed, and always stop it when hidden. */
    if (show_preview && !priv->avatar_manipulation) {
618
        priv->avatar_manipulation = avatar_manipulation_new_from_wizard(priv->avModel_);
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
        gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), priv->avatar_manipulation, true, true, 0);
        gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_creation), priv->account_creation);
    } else if (priv->avatar_manipulation) {
        /* make sure the AvatarManipulation widget is destroyed so the VideoWidget inside of it is too;
         * NOTE: destorying its parent (box_avatarselection) first will cause a mystery 'BadDrawable'
         * crash due to X error */
        gtk_container_remove(GTK_CONTAINER(priv->box_avatarselection), priv->avatar_manipulation);
        priv->avatar_manipulation = nullptr;
    }
}

void
account_creation_wizard_cancel(AccountCreationWizard *win)
{
    // make sure to stop preview before doing something else
    account_creation_wizard_show_preview(win, FALSE);
    g_signal_emit(G_OBJECT(win), account_creation_wizard_signals[ACCOUNT_CREATION_CANCELED], 0);
}