/************************************************************************** * Copyright (C) 2015-2018 by Savoir-faire Linux * * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* * Author: Anthony L�onard <anthony.leonard@savoirfairelinux.com> * * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> * * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> * * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> * * * * 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, see <http://www.gnu.org/licenses/>. * **************************************************************************/ #include "newwizardwidget.h" #include "ui_newwizardwidget.h" #include <QMovie> #include <QMessageBox> #include <QFileDialog> #include <QBitmap> #include <QtConcurrent/QtConcurrent> #include "namedirectory.h" #include "utils.h" #include "ringthemeutils.h" NewWizardWidget::NewWizardWidget(QWidget* parent) : NavWidget(parent), ui(new Ui::NewWizardWidget), wizardMode_(WizardMode::CREATE), lookupTimer_(this) { ui->setupUi(this); QPixmap logo(":/images/logo-jami-standard-coul.png"); ui->welcomeLogo->setPixmap(logo.scaledToHeight(100, Qt::SmoothTransformation)); ui->welcomeLogo->setAlignment(Qt::AlignHCenter); creationSpinnerMovie_ = new QMovie(":/images/jami_eclipse_spinner.gif"); ui->spinnerLabel->setMovie(creationSpinnerMovie_); creationSpinnerMovie_->start(); lookupSpinnerMovie_ = new QMovie(":/images/jami_rolling_spinner.gif"); lookupSpinnerMovie_->setScaledSize(QSize(30, 30)); ui->lookupStatusLabel->setMovie(lookupSpinnerMovie_); ui->lookupStatusLabel->hide(); registrationStateOk_ = false; statusSuccessPixmap_ = Utils::generateTintedPixmap(":/images/icons/baseline-done-24px.svg", RingTheme::presenceGreen_); statusInvalidPixmap_ = Utils::generateTintedPixmap(":/images/icons/baseline-error_outline-24px.svg", RingTheme::urgentOrange_); statusErrorPixmap_ = Utils::generateTintedPixmap(":/images/icons/baseline-close-24px.svg", RingTheme::red_); ui->infoWidget->hide(); setNavBarVisibility(false, true); lookupTimer_.setSingleShot(true); connect(ui->fileImportBtn, &QPushButton::clicked, [this] { QString filePath; filePath = QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("Jami archive files (*.gz); All files (*)")); fileToImport_ = QDir::toNativeSeparators(filePath); if (!fileToImport_.isEmpty()) { QFileInfo fi(filePath); ui->fileImportBtn->setText(fi.fileName()); } else { ui->fileImportBtn->setText(tr("(None)")); } validateWizardProgression(); }); connect(&lookupTimer_, &QTimer::timeout, this, &NewWizardWidget::timeoutNameLookupTimer); connect(ui->backButton, &QPushButton::clicked, [this] { emit NavigationRequested(ScreenEnum::CallScreen); }); connect(ui->confirmPasswordEdit, &QLineEdit::textChanged, [this] { validateWizardProgression(); }); connect(ui->pinEdit, &QLineEdit::textChanged, [this] { validateWizardProgression(); }); ui->containerWidget->setVisible(false); } NewWizardWidget::~NewWizardWidget() { delete ui; } void NewWizardWidget::setToMigrate(AccountInfo* toBeMigrated) { wizardMode_ = WizardMode::MIGRATE; changePage(ui->createRingAccountPage); ui->usernameEdit->setEnabled(false); ui->usernameEdit->setText(QString::fromStdString(toBeMigrated->profileInfo.alias)); ui->previousButton->hide(); ui->infoWidget->show(); ui->infoLabel->setText(tr("Your account needs to be migrated. Enter your password.")); } void NewWizardWidget::updateNameRegistrationUi(NameRegistrationUIState state) { switch (state) { case NameRegistrationUIState::BLANK: ui->lookupStatusLabel->hide(); break; case NameRegistrationUIState::INVALID: ui->lookupStatusLabel->setPixmap(statusInvalidPixmap_); break; case NameRegistrationUIState::TAKEN: ui->lookupStatusLabel->setPixmap(statusErrorPixmap_); break; case NameRegistrationUIState::FREE: ui->lookupStatusLabel->setPixmap(statusSuccessPixmap_); break; case NameRegistrationUIState::SEARCHING: ui->lookupStatusLabel->setMovie(lookupSpinnerMovie_); lookupSpinnerMovie_->stop(); lookupSpinnerMovie_->start(); ui->lookupStatusLabel->show(); break; } } void NewWizardWidget::navigated(bool to) { ui->containerWidget->setVisible(to); changePage(ui->welcomePage); Utils::setStackWidget(ui->stackedWidget, ui->welcomePage); } void NewWizardWidget::slotAccountOnBoarded() {} void NewWizardWidget::on_existingPushButton_clicked() { changePage(ui->linkRingAccountPage); } void NewWizardWidget::on_newAccountButton_clicked() { changePage(ui->createRingAccountPage); } void NewWizardWidget::on_newSIPAccountButton_clicked() { changePage(ui->createRingSIPAccountPage); } void NewWizardWidget::changePage(QWidget* toPage) { if (toPage == ui->spinnerPage) { setNavBarVisibility(false); } Utils::setStackWidget(ui->stackedWidget, toPage); if (toPage == ui->welcomePage) { fileToImport_ = QString(""); setNavBarVisibility(false, true); ui->lookupStatusLabel->hide(); ui->passwordStatusLabel->hide(); } else if (toPage == ui->createRingAccountPage) { ui->usernameEdit->clear(); ui->passwordEdit->clear(); ui->confirmPasswordEdit->clear(); ui->signUpCheckbox->setChecked(true); ui->usernameEdit->setEnabled(true); ui->fullNameEdit->setText(QString()); setNavBarVisibility(true); updateCustomUI(); registeredNameFoundConnection_ = connect( &LRCInstance::accountModel(), &lrc::api::NewAccountModel::registeredNameFound, this, &NewWizardWidget::slotRegisteredNameFound); validateWizardProgression(); ui->setAvatarWidget->startBooth(); } else if (toPage == ui->createRingSIPAccountPage) { ui->SIPusernameEdit->clear(); ui->SIPpasswordEdit->clear(); ui->SIPservernameEdit->clear(); ui->SIPproxyEdit->clear(); ui->SIPfullNameEdit->setText(QString()); ui->SIPusernameEdit->setEnabled(true); setNavBarVisibility(true); ui->nextButton->setEnabled(true); ui->setSIPAvatarWidget->startBooth(); } else if (toPage == ui->linkRingAccountPage) { fileToImport_ = QString(""); ui->fileImportBtn->setText(tr("(None)")); ui->pinEdit->clear(); ui->importPasswordEdit->clear(); ui->pinEdit->setEnabled(true); ui->fileImportBtn->setEnabled(true); setNavBarVisibility(true); ui->lookupStatusLabel->hide(); ui->passwordStatusLabel->hide(); validateWizardProgression(); } else if (toPage == ui->spinnerPage) { ui->lookupStatusLabel->hide(); ui->passwordStatusLabel->hide(); } } void NewWizardWidget::updateCustomUI() { } void NewWizardWidget::setNavBarVisibility(bool nav, bool back) { ui->navBarWidget->setVisible(nav || back); ui->nextButton->setVisible(nav); ui->previousButton->setVisible(nav); ui->backButton->setVisible(back && LRCInstance::accountModel().getAccountList().size()); } void NewWizardWidget::on_nextButton_clicked() { const QWidget* curWidget = ui->stackedWidget->currentWidget(); ui->setAvatarWidget->stopBooth(); disconnect(registeredNameFoundConnection_); if (curWidget == ui->createRingAccountPage) { wizardMode_ = WizardMode::CREATE; processWizardInformations(); } else if (curWidget == ui->linkRingAccountPage) { wizardMode_ = WizardMode::IMPORT; processWizardInformations(); } else if (curWidget == ui->createRingSIPAccountPage) { wizardMode_ = WizardMode::CREATESIP; processWizardInformations(); } } void NewWizardWidget::on_previousButton_clicked() { const QWidget* curWidget = ui->stackedWidget->currentWidget(); if (curWidget == ui->createRingAccountPage) { ui->setAvatarWidget->stopBooth(); } if (curWidget == ui->createRingSIPAccountPage) { ui->setSIPAvatarWidget->stopBooth(); } disconnect(registeredNameFoundConnection_); ui->lookupStatusLabel->hide(); ui->passwordStatusLabel->hide(); if (curWidget == ui->createRingAccountPage || curWidget == ui->linkRingAccountPage || curWidget == ui->createRingSIPAccountPage) { changePage(ui->welcomePage); } } void NewWizardWidget::on_passwordEdit_textChanged(const QString& arg1) { Q_UNUSED(arg1); validateWizardProgression(); } void NewWizardWidget::on_usernameEdit_textChanged(const QString &arg1) { registrationStateOk_ = false; if (ui->signUpCheckbox->isChecked() && !arg1.isEmpty()) { registeredName_ = ui->usernameEdit->text().simplified(); lookupTimer_.start(200); } else { updateNameRegistrationUi(NameRegistrationUIState::BLANK); lookupTimer_.stop(); if (!arg1.isEmpty()) { lookupTimer_.start(200); } } validateWizardProgression(); } void NewWizardWidget::timeoutNameLookupTimer() { if (ui->signUpCheckbox->isChecked() && !ui->usernameEdit->text().isEmpty()) { updateNameRegistrationUi(NameRegistrationUIState::SEARCHING); NameDirectory::instance().lookupName(nullptr, QString(), registeredName_); } } void NewWizardWidget::slotRegisteredNameFound(const std::string& accountId, LookupStatus status, const std::string& address, const std::string& name) { Q_UNUSED(accountId); Q_UNUSED(address); using namespace lrc::api::account; if (name.length() < 3) { registrationStateOk_ = false; updateNameRegistrationUi(NameRegistrationUIState::INVALID); } else if (registeredName_.toStdString() == name) { switch (status) { case LookupStatus::NOT_FOUND: case LookupStatus::ERROR: registrationStateOk_ = true; updateNameRegistrationUi(NameRegistrationUIState::FREE); break; case LookupStatus::INVALID_NAME: case LookupStatus::INVALID: registrationStateOk_ = false; updateNameRegistrationUi(NameRegistrationUIState::INVALID); break; case LookupStatus::SUCCESS: registrationStateOk_ = false; updateNameRegistrationUi(NameRegistrationUIState::TAKEN); break; } } validateWizardProgression(); } void NewWizardWidget::handle_nameRegistrationEnded(NameDirectory::RegisterNameStatus status, const QString& name) { Q_UNUSED(name); Q_UNUSED(status); } void NewWizardWidget::on_signUpCheckbox_toggled(bool checked) { if (checked) { ui->usernameEdit->setEnabled(true); } else { ui->usernameEdit->setEnabled(false); ui->usernameEdit->clear(); } validateWizardProgression(); } void NewWizardWidget::validateWizardProgression() { if (ui->stackedWidget->currentWidget() == ui->linkRingAccountPage) { bool validPin = !ui->pinEdit->text().isEmpty(); ui->fileImportBtn->setEnabled(!validPin); ui->fileImportLabel->setEnabled(!validPin); bool validImport = !fileToImport_.isEmpty(); ui->pinEdit->setEnabled(!validImport); ui->pinEditLabel->setEnabled(!validImport); ui->nextButton->setEnabled(validPin || validImport); return; } bool usernameOk = !ui->signUpCheckbox->isChecked() || (ui->signUpCheckbox->isChecked() && !registeredName_.isEmpty() && (registeredName_ == ui->usernameEdit->text()) && registrationStateOk_ == true); bool passwordOk = ui->passwordEdit->text() == ui->confirmPasswordEdit->text(); if (passwordOk && !ui->passwordEdit->text().isEmpty()) { ui->passwordStatusLabel->show(); ui->passwordStatusLabel->setPixmap(statusSuccessPixmap_); } else if (!passwordOk) { ui->passwordStatusLabel->show(); ui->passwordStatusLabel->setPixmap(statusErrorPixmap_); } else { ui->passwordStatusLabel->hide(); } ui->nextButton->setEnabled(usernameOk && passwordOk); } void NewWizardWidget::processWizardInformations() { inputPara_.clear(); switch (wizardMode_) { case WizardMode::CREATE: ui->progressLabel->setText(tr("Generating your Jami account...")); inputPara_["alias"] = ui->fullNameEdit->text(); inputPara_["password"] = ui->passwordEdit->text(); ui->fullNameEdit->clear(); ui->passwordEdit->clear(); ui->confirmPasswordEdit->clear(); break; case WizardMode::IMPORT: ui->progressLabel->setText(tr("Importing account archive...")); inputPara_["password"] = ui->importPasswordEdit->text(); inputPara_["archivePin"] = ui->pinEdit->text(); ui->pinEdit->clear(); ui->importPasswordEdit->clear(); break; case WizardMode::MIGRATE: ui->progressLabel->setText(tr("Migrating your Jami account...")); break; case WizardMode::CREATESIP: ui->progressLabel->setText(tr("Generating your SIP account...")); if (ui->SIPfullNameEdit->text().isEmpty()) { inputPara_["alias"] = "SIP"; } else { inputPara_["alias"] = ui->SIPfullNameEdit->text(); } inputPara_["hostname"] = ui->SIPservernameEdit->text(); inputPara_["username"] = ui->SIPusernameEdit->text(); inputPara_["password"] = ui->SIPpasswordEdit->text(); inputPara_["proxy"] = ui->SIPproxyEdit->text(); break; } inputPara_["archivePath"] = fileToImport_; if (inputPara_.find("archivePin") == inputPara_.end()) { inputPara_["archivePin"] = ""; } changePage(ui->spinnerPage); createAccount(); Utils::CreateStartupLink(); } void NewWizardWidget::createAccount() { bool isRing = wizardMode_ == WizardMode::CREATE || wizardMode_ == WizardMode::IMPORT; Utils::oneShotConnect(&LRCInstance::accountModel(), &lrc::api::NewAccountModel::accountAdded, [this, isRing](const std::string& accountId) { //set default ringtone auto confProps = LRCInstance::accountModel().getAccountConfig(accountId); confProps.Ringtone.ringtonePath = Utils::GetRingtonePath().toStdString(); if (!isRing) { // set SIP details confProps.hostname = inputPara_["hostname"].toStdString(); confProps.username = inputPara_["username"].toStdString(); confProps.password = inputPara_["password"].toStdString(); confProps.proxyServer = inputPara_["proxy"].toStdString(); } LRCInstance::accountModel().setAccountConfig(accountId, confProps); if (isRing) { if (!confProps.username.empty()) { connect(LRCInstance::editableAccountModel(), &lrc::api::NewAccountModel::nameRegistrationEnded, [this] { lrc::api::account::ConfProperties_t accountProperties = LRCInstance::accountModel().getAccountConfig(LRCInstance::getCurrAccId()); LRCInstance::accountModel().setAccountConfig(LRCInstance::getCurrAccId(), accountProperties); emit NavigationRequested(ScreenEnum::CallScreen); emit LRCInstance::instance().accountOnBoarded(); }); LRCInstance::editableAccountModel()->registerName( LRCInstance::getCurrAccId(), "", registeredName_.toStdString() ); } else { emit NavigationRequested(ScreenEnum::CallScreen); emit LRCInstance::instance().accountOnBoarded(); } LRCInstance::setCurrAccAvatar(ui->setAvatarWidget->getAvatarPixmap()); } else { LRCInstance::setCurrAccAvatar(ui->setSIPAvatarWidget->getAvatarPixmap()); } }); Utils::oneShotConnect(&LRCInstance::accountModel(), &lrc::api::NewAccountModel::accountRemoved, [this](const std::string& accountId) { Q_UNUSED(accountId); qWarning() << Q_FUNC_INFO << ": " << "accountRemoved"; reportFailure(); }); Utils::oneShotConnect(&LRCInstance::accountModel(), &lrc::api::NewAccountModel::invalidAccountDetected, [this](const std::string& accountId) { Q_UNUSED(accountId); qWarning() << Q_FUNC_INFO << ": " << "invalidAccountDetected"; reportFailure(); }); QtConcurrent::run( [this, isRing] { if (isRing) { LRCInstance::accountModel().createNewAccount( lrc::api::profile::Type::RING, inputPara_["alias"].toStdString(), inputPara_["archivePath"].toStdString(), inputPara_["password"].toStdString(), inputPara_["archivePin"].toStdString() ); } else { LRCInstance::accountModel().createNewAccount( lrc::api::profile::Type::SIP, inputPara_["alias"].toStdString(), inputPara_["archivePath"].toStdString(), "", "", inputPara_["username"].toStdString() ); QThread::sleep(2); emit NavigationRequested(ScreenEnum::CallScreen); emit LRCInstance::instance().accountOnBoarded(); } }); changePage(ui->spinnerPage); repaint(); } void NewWizardWidget::reportFailure() { auto spinnerGeometry = ui->spinnerLabel->frameGeometry(); auto pixmap = Utils::generateTintedPixmap(":/images/icons/baseline-error_outline-24px.svg", RingTheme::urgentOrange_) .scaled(spinnerGeometry.width(), spinnerGeometry.height()); ui->spinnerLabel->setPixmap(pixmap); ui->progressLabel->setStyleSheet("color:red;"); ui->progressLabel->setText(tr("Error creating account")); QTimer::singleShot(1000, this, [this] { changePage(ui->welcomePage); ui->progressLabel->setStyleSheet(""); ui->spinnerLabel->setMovie(creationSpinnerMovie_); }); }