This commit is contained in:
Gaelle Braud 2024-06-24 16:26:28 +02:00
parent 16757d0a85
commit 5beb0b84d0
41 changed files with 1119 additions and 271 deletions

View file

@ -58,6 +58,7 @@
#include "core/participant/ParticipantProxy.hpp" #include "core/participant/ParticipantProxy.hpp"
#include "core/phone-number/PhoneNumber.hpp" #include "core/phone-number/PhoneNumber.hpp"
#include "core/phone-number/PhoneNumberProxy.hpp" #include "core/phone-number/PhoneNumberProxy.hpp"
#include "core/register/RegisterPage.hpp"
#include "core/screen/ScreenList.hpp" #include "core/screen/ScreenList.hpp"
#include "core/screen/ScreenProxy.hpp" #include "core/screen/ScreenProxy.hpp"
#include "core/search/MagicSearchProxy.hpp" #include "core/search/MagicSearchProxy.hpp"
@ -294,8 +295,17 @@ void App::initCore() {
void App::initCppInterfaces() { void App::initCppInterfaces() {
qmlRegisterSingletonType<LoginPage>( qmlRegisterSingletonType<LoginPage>(
Constants::MainQmlUri, 1, 0, "LoginPageCpp", Constants::MainQmlUri, 1, 0, "LoginPageCpp", [](QQmlEngine *engine, QJSEngine *) -> QObject * {
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new LoginPage(engine); }); static auto loginPage = new LoginPage(engine);
App::getInstance()->mEngine->setObjectOwnership(loginPage, QQmlEngine::CppOwnership);
return loginPage;
});
qmlRegisterSingletonType<RegisterPage>(
Constants::MainQmlUri, 1, 0, "RegisterPageCpp", [](QQmlEngine *engine, QJSEngine *) -> QObject * {
static RegisterPage *registerPage = new RegisterPage();
App::getInstance()->mEngine->setObjectOwnership(registerPage, QQmlEngine::CppOwnership);
return registerPage;
});
qmlRegisterSingletonType<Constants>( qmlRegisterSingletonType<Constants>(
"ConstantsCpp", 1, 0, "ConstantsCpp", "ConstantsCpp", 1, 0, "ConstantsCpp",
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Constants(engine); }); [](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Constants(engine); });

View file

@ -25,6 +25,7 @@ list(APPEND _LINPHONEAPP_SOURCES
core/phone-number/PhoneNumber.cpp core/phone-number/PhoneNumber.cpp
core/phone-number/PhoneNumberList.cpp core/phone-number/PhoneNumberList.cpp
core/phone-number/PhoneNumberProxy.cpp core/phone-number/PhoneNumberProxy.cpp
core/register/RegisterPage.cpp
core/search/MagicSearchList.cpp core/search/MagicSearchList.cpp
core/search/MagicSearchProxy.cpp core/search/MagicSearchProxy.cpp

View file

@ -71,14 +71,27 @@ void LoginPage::login(const QString &username, const QString &password) {
switch (state) { switch (state) {
case linphone::RegistrationState::Failed: { case linphone::RegistrationState::Failed: {
emit accountManager->errorMessageChanged(*error); emit accountManager->errorMessageChanged(*error);
if (accountManager) {
accountManager->deleteLater(); accountManager->deleteLater();
accountManager = nullptr;
}
break; break;
} }
case linphone::RegistrationState::Ok: { case linphone::RegistrationState::Ok: {
emit accountManager->errorMessageChanged(""); emit accountManager->errorMessageChanged("");
if (accountManager) {
accountManager->deleteLater();
accountManager = nullptr;
}
break;
}
case linphone::RegistrationState::Cleared: {
if (accountManager) {
accountManager->deleteLater();
accountManager = nullptr;
}
break; break;
} }
case linphone::RegistrationState::Cleared:
case linphone::RegistrationState::None: case linphone::RegistrationState::None:
case linphone::RegistrationState::Progress: case linphone::RegistrationState::Progress:
case linphone::RegistrationState::Refreshing: case linphone::RegistrationState::Refreshing:

View file

@ -19,10 +19,17 @@
*/ */
#include "PhoneNumber.hpp" #include "PhoneNumber.hpp"
#include "core/App.hpp"
#include "tool/Utils.hpp" #include "tool/Utils.hpp"
#include <QApplication> #include <QApplication>
DEFINE_ABSTRACT_OBJECT(PhoneNumber) DEFINE_ABSTRACT_OBJECT(PhoneNumber)
QSharedPointer<PhoneNumber> PhoneNumber::create(const std::shared_ptr<linphone::DialPlan> &dialPlan) {
auto sharedPointer = QSharedPointer<PhoneNumber>(new PhoneNumber(dialPlan), &QObject::deleteLater);
sharedPointer->moveToThread(App::getInstance()->thread());
return sharedPointer;
}
PhoneNumber::PhoneNumber(const std::shared_ptr<linphone::DialPlan> &dialPlan) : QObject(nullptr) { PhoneNumber::PhoneNumber(const std::shared_ptr<linphone::DialPlan> &dialPlan) : QObject(nullptr) {
// Should be call from model Thread // Should be call from model Thread
mustBeInLinphoneThread(getClassName()); mustBeInLinphoneThread(getClassName());

View file

@ -36,7 +36,7 @@ class PhoneNumber : public QObject, public AbstractObject {
Q_PROPERTY(QString country MEMBER mCountry CONSTANT) Q_PROPERTY(QString country MEMBER mCountry CONSTANT)
public: public:
// Should be call from model Thread. Will be automatically in App thread after initialization static QSharedPointer<PhoneNumber> create(const std::shared_ptr<linphone::DialPlan> &dialPlan);
PhoneNumber(const std::shared_ptr<linphone::DialPlan> &dialPlan); PhoneNumber(const std::shared_ptr<linphone::DialPlan> &dialPlan);
~PhoneNumber(); ~PhoneNumber();
@ -47,6 +47,7 @@ public:
QString mInternationalCallPrefix; QString mInternationalCallPrefix;
QString mCountry; QString mCountry;
private:
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -28,22 +28,28 @@
DEFINE_ABSTRACT_OBJECT(PhoneNumberList) DEFINE_ABSTRACT_OBJECT(PhoneNumberList)
QSharedPointer<PhoneNumberList> PhoneNumberList::create() {
auto model = QSharedPointer<PhoneNumberList>(new PhoneNumberList(), &QObject::deleteLater);
model->moveToThread(App::getInstance()->thread());
return model;
}
PhoneNumberList::PhoneNumberList(QObject *parent) : ListProxy(parent) { PhoneNumberList::PhoneNumberList(QObject *parent) : ListProxy(parent) {
mustBeInMainThread(getClassName()); mustBeInMainThread(getClassName());
App::postModelAsync([=]() { App::postModelAsync([=]() {
// Model thread. // Model thread.
auto dialPlans = linphone::Factory::get()->getDialPlans(); auto dialPlans = linphone::Factory::get()->getDialPlans();
QList<QSharedPointer<PhoneNumber>> numbers; QList<QSharedPointer<PhoneNumber>> *numbers = new QList<QSharedPointer<PhoneNumber>>();
QVector<QVariantMap> results;
for (auto it : dialPlans) { for (auto it : dialPlans) {
auto numberModel = QSharedPointer<PhoneNumber>::create(it); auto numberModel = PhoneNumber::create(it);
numberModel->moveToThread(this->thread()); numbers->push_back(numberModel);
numbers.push_back(numberModel);
} }
// Invoke for adding stuffs in caller thread // Invoke for adding stuffs in caller thread
QMetaObject::invokeMethod(this, [this, numbers]() { QMetaObject::invokeMethod(this, [this, numbers]() {
mustBeInMainThread(this->log().arg(Q_FUNC_INFO)); mustBeInMainThread(this->log().arg(Q_FUNC_INFO));
add(numbers); resetData();
add(*numbers);
delete numbers;
}); });
}); });
} }

View file

@ -29,9 +29,11 @@
class PhoneNumberList : public ListProxy, public AbstractObject { class PhoneNumberList : public ListProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
public: public:
static QSharedPointer<PhoneNumberList> create();
PhoneNumberList(QObject *parent = Q_NULLPTR); PhoneNumberList(QObject *parent = Q_NULLPTR);
~PhoneNumberList(); ~PhoneNumberList();
private:
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -20,13 +20,19 @@
#include "PhoneNumberProxy.hpp" #include "PhoneNumberProxy.hpp"
#include "PhoneNumber.hpp" #include "PhoneNumber.hpp"
#include "PhoneNumberList.hpp"
DEFINE_ABSTRACT_OBJECT(PhoneNumberProxy)
PhoneNumberProxy::PhoneNumberProxy(QObject *parent) : SortFilterProxy(parent) { PhoneNumberProxy::PhoneNumberProxy(QObject *parent) : SortFilterProxy(parent) {
setSourceModel(new PhoneNumberList(this)); mPhoneNumberList = PhoneNumberList::create();
setSourceModel(mPhoneNumberList.get());
sort(0); sort(0);
} }
PhoneNumberProxy::~PhoneNumberProxy() {
setSourceModel(nullptr);
}
QString PhoneNumberProxy::getFilterText() const { QString PhoneNumberProxy::getFilterText() const {
return mFilterText; return mFilterText;
} }

View file

@ -22,21 +22,24 @@
#define PHONE_NUMBER_PROXY_H_ #define PHONE_NUMBER_PROXY_H_
#include "../proxy/SortFilterProxy.hpp" #include "../proxy/SortFilterProxy.hpp"
#include "PhoneNumberList.hpp"
#include "tool/AbstractObject.hpp"
// ============================================================================= // =============================================================================
class PhoneNumberProxy : public SortFilterProxy { class PhoneNumberProxy : public SortFilterProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged) Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public: public:
PhoneNumberProxy(QObject *parent = Q_NULLPTR); PhoneNumberProxy(QObject *parent = Q_NULLPTR);
~PhoneNumberProxy();
QString getFilterText() const; QString getFilterText() const;
void setFilterText(const QString &filter); void setFilterText(const QString &filter);
Q_INVOKABLE int findIndexByCountryCallingCode(const QString& countryCallingCode); Q_INVOKABLE int findIndexByCountryCallingCode(const QString &countryCallingCode);
signals: signals:
void filterTextChanged(); void filterTextChanged();
@ -46,6 +49,10 @@ protected:
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText; QString mFilterText;
QSharedPointer<PhoneNumberList> mPhoneNumberList;
private:
DECLARE_ABSTRACT_OBJECT
}; };
#endif #endif

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 "RegisterPage.hpp"
#include <QTimer>
#include "core/App.hpp"
#include "model/account/AccountManager.hpp"
DEFINE_ABSTRACT_OBJECT(RegisterPage)
RegisterPage::RegisterPage(QObject *parent) : QObject(parent) {
mustBeInMainThread(getClassName());
}
RegisterPage::~RegisterPage() {
mustBeInMainThread("~" + getClassName());
}
void RegisterPage::registerNewAccount(const QString &username,
const QString &password,
const QString &email,
const QString &phoneNumber) {
App::postModelAsync([=]() {
// Create on Model thread.
// registrationFailed(error); });
AccountManager::RegisterType registerType;
QString address;
if (email.isEmpty()) {
registerType = AccountManager::RegisterType::PhoneNumber;
address = phoneNumber;
} else {
registerType = AccountManager::RegisterType::Email;
address = email;
}
auto accountManager = new AccountManager();
connect(accountManager, &AccountManager::newAccountCreationSucceed, this,
[this, registerType, address, accountManager](const QString &sipAddress) mutable {
App::postCoreAsync([this, registerType, address, sipAddress, accountManager]() {
emit newAccountCreationSucceed(registerType == AccountManager::RegisterType::Email, address,
sipAddress);
});
if (accountManager) {
accountManager->deleteLater();
accountManager = nullptr;
}
});
connect(accountManager, &AccountManager::registerNewAccountFailed, this,
[this, accountManager](const QString &errorMessage) mutable {
App::postCoreAsync(
[this, errorMessage, accountManager]() { emit registerNewAccountFailed(errorMessage); });
if (accountManager) {
accountManager->deleteLater();
accountManager = nullptr;
}
});
connect(accountManager, &AccountManager::errorInField, this,
[this, accountManager](const QString &field, const QString &errorMessage) mutable {
App::postCoreAsync([this, field, errorMessage]() { emit errorInField(field, errorMessage); });
if (accountManager) {
accountManager->deleteLater();
accountManager = nullptr;
}
});
connect(accountManager, &AccountManager::tokenConversionSucceed, this,
[this, accountManager]() { App::postCoreAsync([this]() { emit tokenConversionSucceed(); }); });
accountManager->registerNewAccount(username, password, registerType, address);
});
}
void RegisterPage::linkNewAccountUsingCode(const QString &code,
bool registerWithEmail,
const QString &sipIdentityAddress) {
App::postModelAsync([=]() {
auto accountManager = new AccountManager();
connect(accountManager, &AccountManager::linkingNewAccountWithCodeSucceed, this, [this, accountManager]() {
App::postCoreAsync([this]() { emit linkingNewAccountWithCodeSucceed(); });
accountManager->deleteLater();
});
connect(accountManager, &AccountManager::linkingNewAccountWithCodeFailed, this,
[this, accountManager](const QString &errorMessage) {
App::postCoreAsync([this, errorMessage]() { emit linkingNewAccountWithCodeFailed(errorMessage); });
accountManager->deleteLater();
});
accountManager->linkNewAccountUsingCode(
code, registerWithEmail ? AccountManager::RegisterType::Email : AccountManager::RegisterType::PhoneNumber,
sipIdentityAddress);
});
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef REGISTERPAGE_H_
#define REGISTERPAGE_H_
#include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QObject>
#include <linphone++/linphone.hh>
class AccountManager;
class RegisterPage : public QObject, public AbstractObject {
Q_OBJECT
public:
RegisterPage(QObject *parent = nullptr);
~RegisterPage();
// Q_PROPERTY(linphone::RegistrationState registrationState READ getRegistrationState NOTIFY
// registrationStateChanged) Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY errorMessageChanged)
Q_INVOKABLE void registerNewAccount(const QString &username,
const QString &password,
const QString &email,
const QString &phoneNumber);
Q_INVOKABLE void
linkNewAccountUsingCode(const QString &code, bool registerWithEmail, const QString &sipIdentityAddress);
signals:
void registrationFailed(const QString &errorMessage);
void errorMessageChanged();
void newAccountCreationSucceed(bool withEmail, // false if creation with phone number
const QString &address,
const QString &sipIdentityAddress);
void registerNewAccountFailed(const QString &error);
void errorInField(const QString &field, const QString &error);
void tokenConversionSucceed();
void linkingNewAccountWithCodeSucceed();
void linkingNewAccountWithCodeFailed(const QString &error);
private:
linphone::RegistrationState mRegistrationState = linphone::RegistrationState::None;
QSharedPointer<SafeConnection<RegisterPage, AccountManager>> mAccountManagerConnection;
std::shared_ptr<AccountManager> mAccountManager;
QString mErrorMessage;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -3,6 +3,7 @@ backend=1
# 1 means FlexiAPI, 0 is XMLRPC # 1 means FlexiAPI, 0 is XMLRPC
url=https://subscribe.linphone.org/api/ url=https://subscribe.linphone.org/api/
# replace above URL by https://staging-subscribe.linphone.org/api/ for testing # replace above URL by https://staging-subscribe.linphone.org/api/ for testing
# url=https://flexisip-staging-master.linphone.org/api/
[alerts] [alerts]
alerts_enabled=1 alerts_enabled=1

View file

@ -1,6 +1,8 @@
list(APPEND _LINPHONEAPP_SOURCES list(APPEND _LINPHONEAPP_SOURCES
model/account/AccountModel.cpp model/account/AccountModel.cpp
model/account/AccountManager.cpp model/account/AccountManager.cpp
model/account/AccountManagerServicesModel.cpp
model/account/AccountManagerServicesRequestModel.cpp
model/call/CallModel.cpp model/call/CallModel.cpp

View file

@ -21,10 +21,16 @@
#include "AccountManager.hpp" #include "AccountManager.hpp"
#include <QDebug> #include <QDebug>
#include <QDesktopServices>
#include <QEventLoop>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QUrl>
#include "core/path/Paths.hpp" #include "core/path/Paths.hpp"
#include "model/core/CoreModel.hpp" #include "model/core/CoreModel.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp" #include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(AccountManager) DEFINE_ABSTRACT_OBJECT(AccountManager)
@ -93,6 +99,172 @@ bool AccountManager::login(QString username, QString password, QString *errorMes
return true; return true;
} }
void AccountManager::registerNewAccount(const QString &username,
const QString &password,
RegisterType type,
const QString &registerAddress) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
if (!mAccountManagerServicesModel) {
auto core = CoreModel::getInstance()->getCore();
auto ams = core->createAccountManagerServices();
mAccountManagerServicesModel = Utils::makeQObject_ptr<AccountManagerServicesModel>(ams);
}
connect(
mAccountManagerServicesModel.get(), &AccountManagerServicesModel::requestSuccessfull, this,
[this, username, password, type, registerAddress](
const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, const std::string &data) {
if (request->getType() == linphone::AccountManagerServicesRequest::Type::AccountCreationRequestToken) {
QString verifyTokenUrl = Utils::coreStringToAppString(data);
qDebug() << "[AccountManager] request token succeed" << verifyTokenUrl;
QDesktopServices::openUrl(verifyTokenUrl);
auto creationToken = verifyTokenUrl.mid(verifyTokenUrl.lastIndexOf("/") + 1);
// QNetworkRequest req;
timer.setSingleShot(true);
timer.setInterval(2000);
QObject::connect(&timer, &QTimer::timeout, this, [this, creationToken]() {
mAccountManagerServicesModel->convertCreationRequestTokenIntoCreationToken(
Utils::appStringToCoreString(creationToken));
});
timer.start();
// req.setUrl(QUrl(verifyTokenUrl));
} else if (request->getType() == linphone::AccountManagerServicesRequest::Type::
AccountCreationTokenFromAccountCreationRequestToken) {
qDebug() << "[AccountManager] request token conversion succeed" << data;
emit tokenConversionSucceed();
timer.stop();
mAccountManagerServicesModel->createAccountUsingToken(Utils::appStringToCoreString(username),
Utils::appStringToCoreString(password), data);
} else if (request->getType() == linphone::AccountManagerServicesRequest::Type::CreateAccountUsingToken) {
auto core = CoreModel::getInstance()->getCore();
auto factory = linphone::Factory::get();
mCreatedSipAddress = Utils::coreStringToAppString(data);
auto createdSipIdentityAddress = ToolModel::interpretUrl(mCreatedSipAddress);
core->addAuthInfo(factory->createAuthInfo(Utils::appStringToCoreString(username), // Username.
"", // User ID.
Utils::appStringToCoreString(password), // Password.
"", // HA1.
"", // Realm.
createdSipIdentityAddress->getDomain() // Domain.
));
if (type == RegisterType::Email) {
qDebug() << "[AccountManager] creation succeed, email verification" << registerAddress;
mAccountManagerServicesModel->linkEmailByEmail(
ToolModel::interpretUrl(Utils::coreStringToAppString(data)),
Utils::appStringToCoreString(registerAddress));
} else {
qDebug() << "[AccountManager] creation succeed, sms verification" << registerAddress;
mAccountManagerServicesModel->linkPhoneNumberBySms(
ToolModel::interpretUrl(Utils::coreStringToAppString(data)),
Utils::appStringToCoreString(registerAddress));
}
} else if (request->getType() ==
linphone::AccountManagerServicesRequest::Type::SendEmailLinkingCodeByEmail) {
qDebug() << "[AccountManager] send email succeed, link account using code";
emit newAccountCreationSucceed(mCreatedSipAddress, type, registerAddress);
mCreatedSipAddress.clear();
} else if (request->getType() ==
linphone::AccountManagerServicesRequest::Type::SendPhoneNumberLinkingCodeBySms) {
qDebug() << "[AccountManager] send phone number succeed, link account using code";
emit newAccountCreationSucceed(mCreatedSipAddress, type, registerAddress);
mCreatedSipAddress.clear();
}
});
connect(
mAccountManagerServicesModel.get(), &AccountManagerServicesModel::requestError, this,
[this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, int statusCode,
const std::string &errorMessage, const std::shared_ptr<const linphone::Dictionary> &parameterErrors) {
if (request->getType() == linphone::AccountManagerServicesRequest::Type::AccountCreationRequestToken) {
qDebug() << "[AccountManager] error creating request token :" << errorMessage;
emit registerNewAccountFailed(Utils::coreStringToAppString(errorMessage));
} else if (request->getType() == linphone::AccountManagerServicesRequest::Type::
AccountCreationTokenFromAccountCreationRequestToken) {
qDebug() << "[AccountManager] error converting token into creation token :" << errorMessage;
if (parameterErrors) {
timer.stop();
emit registerNewAccountFailed(Utils::coreStringToAppString(errorMessage));
} else {
timer.start();
}
} else if (request->getType() == linphone::AccountManagerServicesRequest::Type::CreateAccountUsingToken) {
qDebug() << "[AccountManager] error creating account :" << errorMessage;
if (parameterErrors) {
for (const std::string &key : parameterErrors->getKeys()) {
emit errorInField(Utils::coreStringToAppString(key),
Utils::coreStringToAppString(errorMessage));
}
} else {
emit registerNewAccountFailed(Utils::coreStringToAppString(errorMessage));
}
} else if (request->getType() ==
linphone::AccountManagerServicesRequest::Type::SendEmailLinkingCodeByEmail) {
qDebug() << "[AccountManager] error sending code to email" << errorMessage;
if (parameterErrors) {
for (const std::string &key : parameterErrors->getKeys()) {
emit errorInField(Utils::coreStringToAppString(key),
Utils::coreStringToAppString(errorMessage));
}
} else {
emit registerNewAccountFailed(Utils::coreStringToAppString(errorMessage));
}
} else if (request->getType() ==
linphone::AccountManagerServicesRequest::Type::SendPhoneNumberLinkingCodeBySms) {
qDebug() << "[AccountManager] error sending code to phone number" << errorMessage;
if (parameterErrors) {
for (const std::string &key : parameterErrors->getKeys()) {
emit errorInField(Utils::coreStringToAppString(key),
Utils::coreStringToAppString(errorMessage));
}
} else {
emit registerNewAccountFailed(Utils::coreStringToAppString(errorMessage));
}
}
});
mAccountManagerServicesModel->requestToken();
}
void AccountManager::linkNewAccountUsingCode(const QString &code,
RegisterType registerType,
const QString &sipAddress) {
auto sipIdentityAddress = ToolModel::interpretUrl(sipAddress);
if (!mAccountManagerServicesModel) {
auto core = CoreModel::getInstance()->getCore();
auto ams = core->createAccountManagerServices();
mAccountManagerServicesModel = Utils::makeQObject_ptr<AccountManagerServicesModel>(ams);
}
connect(
mAccountManagerServicesModel.get(), &AccountManagerServicesModel::requestSuccessfull, this,
[this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, const std::string &data) {
if (request->getType() == linphone::AccountManagerServicesRequest::Type::LinkEmailUsingCode) {
qDebug() << "[AccountManager] link email to account succeed" << data;
emit linkingNewAccountWithCodeSucceed();
} else if (request->getType() == linphone::AccountManagerServicesRequest::Type::LinkPhoneNumberUsingCode) {
qDebug() << "[AccountManager] link phone number to account succeed" << data;
emit linkingNewAccountWithCodeSucceed();
}
});
connect(
mAccountManagerServicesModel.get(), &AccountManagerServicesModel::requestError, this,
[this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, int statusCode,
const std::string &errorMessage, const std::shared_ptr<const linphone::Dictionary> &parameterErrors) {
if (request->getType() == linphone::AccountManagerServicesRequest::Type::LinkEmailUsingCode) {
qDebug() << "[AccountManager] error linking email to account" << errorMessage;
} else if (request->getType() == linphone::AccountManagerServicesRequest::Type::LinkPhoneNumberUsingCode) {
qDebug() << "[AccountManager] error linking phone number to account" << errorMessage;
}
emit linkingNewAccountWithCodeFailed(Utils::coreStringToAppString(errorMessage));
});
if (registerType == RegisterType::Email)
mAccountManagerServicesModel->linkEmailToAccountUsingCode(sipIdentityAddress,
Utils::appStringToCoreString(code));
else
mAccountManagerServicesModel->linkPhoneNumberToAccountUsingCode(sipIdentityAddress,
Utils::appStringToCoreString(code));
}
void AccountManager::onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account, void AccountManager::onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account,
linphone::RegistrationState state, linphone::RegistrationState state,
const std::string &message) { const std::string &message) {

View file

@ -22,8 +22,11 @@
#define ACCOUNT_MANAGER_H_ #define ACCOUNT_MANAGER_H_
#include <QObject> #include <QObject>
#include <QTimer>
#include <linphone++/linphone.hh> #include <linphone++/linphone.hh>
#include "AccountManagerServicesModel.hpp"
#include "AccountManagerServicesRequestModel.hpp"
#include "AccountModel.hpp" #include "AccountModel.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
@ -34,18 +37,36 @@ public:
~AccountManager(); ~AccountManager();
bool login(QString username, QString password, QString *errorMessage = nullptr); bool login(QString username, QString password, QString *errorMessage = nullptr);
std::shared_ptr<linphone::Account> createAccount(const QString &assistantFile); std::shared_ptr<linphone::Account> createAccount(const QString &assistantFile);
enum RegisterType { PhoneNumber = 0, Email = 1 };
void registerNewAccount(const QString &username,
const QString &password,
RegisterType type,
const QString &registerAddress);
void linkNewAccountUsingCode(const QString &code, RegisterType registerType, const QString &sipAddress);
void onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account, void onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account,
linphone::RegistrationState state, linphone::RegistrationState state,
const std::string &message); const std::string &message);
signals: signals:
void registrationStateChanged(linphone::RegistrationState state); void registrationStateChanged(linphone::RegistrationState state);
void errorMessageChanged(const QString &errorMessage); void errorMessageChanged(const QString &errorMessage);
void newAccountCreationSucceed(QString sipAddress, RegisterType registerType, const QString &registerAddress);
void registerNewAccountFailed(const QString &error);
void tokenConversionSucceed();
void errorInField(const QString &field, const QString &error);
void linkingNewAccountWithCodeSucceed();
void linkingNewAccountWithCodeFailed(const QString &error);
private: private:
std::shared_ptr<AccountModel> mAccountModel; std::shared_ptr<AccountModel> mAccountModel;
std::shared_ptr<AccountManagerServicesModel> mAccountManagerServicesModel;
QTimer timer;
QString mCreatedSipAddress;
// std::shared_ptr<linphone::Address> mCreatedSipIdentityAddress;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 "AccountManagerServicesModel.hpp"
#include "core/path/Paths.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
#include "tool/providers/AvatarProvider.hpp"
#include <QDebug>
#include <QUrl>
DEFINE_ABSTRACT_OBJECT(AccountManagerServicesModel)
AccountManagerServicesModel::AccountManagerServicesModel(
const std::shared_ptr<linphone::AccountManagerServices> &accountManagerServices, QObject *parent)
: mAccountManagerServices(accountManagerServices) {
mustBeInLinphoneThread(getClassName());
}
AccountManagerServicesModel::~AccountManagerServicesModel() {
mustBeInLinphoneThread("~" + getClassName());
}
void AccountManagerServicesModel::setRequestAndSubmit(
const std::shared_ptr<linphone::AccountManagerServicesRequest> &request) {
if (mRequest) {
disconnect(mRequest.get(), &AccountManagerServicesRequestModel::requestSuccessfull, this, nullptr);
disconnect(mRequest.get(), &AccountManagerServicesRequestModel::requestError, this, nullptr);
disconnect(mRequest.get(), &AccountManagerServicesRequestModel::devicesListFetched, this, nullptr);
mRequest = nullptr;
}
mRequest = Utils::makeQObject_ptr<AccountManagerServicesRequestModel>(request);
mRequest->setSelf(mRequest);
connect(mRequest.get(), &AccountManagerServicesRequestModel::requestSuccessfull, this,
&AccountManagerServicesModel::requestSuccessfull);
connect(mRequest.get(), &AccountManagerServicesRequestModel::requestError, this,
&AccountManagerServicesModel::requestError);
connect(mRequest.get(), &AccountManagerServicesRequestModel::devicesListFetched, this,
&AccountManagerServicesModel::devicesListFetched);
mRequest->submit();
}
void AccountManagerServicesModel::requestToken() {
auto req = mAccountManagerServices->createGetAccountCreationRequestTokenRequest();
setRequestAndSubmit(req);
}
void AccountManagerServicesModel::convertCreationRequestTokenIntoCreationToken(const std::string &token) {
auto req = mAccountManagerServices->createGetAccountCreationTokenFromRequestTokenRequest(token);
setRequestAndSubmit(req);
}
void AccountManagerServicesModel::createAccountUsingToken(const std::string &username,
const std::string &password,
const std::string &token,
const std::string &algorithm) {
auto req = mAccountManagerServices->createNewAccountUsingTokenRequest(username, password, algorithm, token);
setRequestAndSubmit(req);
}
void AccountManagerServicesModel::linkPhoneNumberBySms(const std::shared_ptr<linphone::Address> &sipIdentityAddress,
const std::string &phoneNumber) {
auto req = mAccountManagerServices->createSendPhoneNumberLinkingCodeBySmsRequest(sipIdentityAddress, phoneNumber);
setRequestAndSubmit(req);
}
void AccountManagerServicesModel::linkEmailByEmail(const std::shared_ptr<linphone::Address> &sipIdentityAddress,
const std::string &emailAddress) {
auto req = mAccountManagerServices->createSendEmailLinkingCodeByEmailRequest(sipIdentityAddress, emailAddress);
setRequestAndSubmit(req);
}
void AccountManagerServicesModel::linkPhoneNumberToAccountUsingCode(
const std::shared_ptr<linphone::Address> &sipIdentityAddress, const std::string &code) {
auto req = mAccountManagerServices->createLinkPhoneNumberToAccountUsingCodeRequest(sipIdentityAddress, code);
setRequestAndSubmit(req);
}
void AccountManagerServicesModel::linkEmailToAccountUsingCode(
const std::shared_ptr<linphone::Address> &sipIdentityAddress, const std::string &code) {
auto req = mAccountManagerServices->createLinkEmailToAccountUsingCodeRequest(sipIdentityAddress, code);
setRequestAndSubmit(req);
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef ACCOUNT_MANAGER_SERVICES_MODEL_H_
#define ACCOUNT_MANAGER_SERVICES_MODEL_H_
#include "AccountManagerServicesRequestModel.hpp"
#include "model/listener/Listener.hpp"
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <linphone++/linphone.hh>
class AccountManagerServicesModel : public QObject, public AbstractObject {
Q_OBJECT
public:
AccountManagerServicesModel(const std::shared_ptr<linphone::AccountManagerServices> &accountManagerServices,
QObject *parent = nullptr);
~AccountManagerServicesModel();
void requestToken();
void convertCreationRequestTokenIntoCreationToken(const std::string &token);
void createAccountUsingToken(const std::string &username,
const std::string &password,
const std::string &token,
const std::string &algorithm = "SHA-256");
void linkPhoneNumberBySms(const std::shared_ptr<linphone::Address> &sipIdentityAddress,
const std::string &phoneNumber);
void linkEmailByEmail(const std::shared_ptr<linphone::Address> &sipIdentityAddress,
const std::string &emailAddress);
void linkPhoneNumberToAccountUsingCode(const std::shared_ptr<linphone::Address> &sipIdentityAddress,
const std::string &code);
void linkEmailToAccountUsingCode(const std::shared_ptr<linphone::Address> &sipIdentityAddress,
const std::string &code);
void setRequestAndSubmit(const std::shared_ptr<linphone::AccountManagerServicesRequest> &request);
signals:
void requestSuccessfull(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
const std::string &data);
void requestError(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
int statusCode,
const std::string &errorMessage,
const std::shared_ptr<const linphone::Dictionary> &parameterErrors);
void devicesListFetched(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
const std::list<std::shared_ptr<linphone::AccountDevice>> &devicesList);
private:
DECLARE_ABSTRACT_OBJECT
std::shared_ptr<linphone::AccountManagerServices> mAccountManagerServices;
std::shared_ptr<AccountManagerServicesRequestModel> mRequest;
};
#endif

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 "AccountManagerServicesRequestModel.hpp"
#include "core/path/Paths.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
#include "tool/providers/AvatarProvider.hpp"
#include <QDebug>
#include <QUrl>
DEFINE_ABSTRACT_OBJECT(AccountManagerServicesRequestModel)
AccountManagerServicesRequestModel::AccountManagerServicesRequestModel(
const std::shared_ptr<linphone::AccountManagerServicesRequest> &accountManagerServicesRequest, QObject *parent)
: ::Listener<linphone::AccountManagerServicesRequest, linphone::AccountManagerServicesRequestListener>(
accountManagerServicesRequest, parent) {
mustBeInLinphoneThread(getClassName());
}
AccountManagerServicesRequestModel::~AccountManagerServicesRequestModel() {
mustBeInLinphoneThread("~" + getClassName());
}
void AccountManagerServicesRequestModel::submit() {
mMonitor->submit();
}
linphone::AccountManagerServicesRequest::Type AccountManagerServicesRequestModel::getType() const {
return mMonitor->getType();
}
//--------------------------------------------------------------------------------
// LINPHONE
//--------------------------------------------------------------------------------
void AccountManagerServicesRequestModel::onRequestSuccessful(
const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, const std::string &data) {
emit requestSuccessfull(request, data);
}
void AccountManagerServicesRequestModel::onRequestError(
const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
int statusCode,
const std::string &errorMessage,
const std::shared_ptr<const linphone::Dictionary> &parameterErrors) {
emit requestError(request, statusCode, errorMessage, parameterErrors);
}
void AccountManagerServicesRequestModel::onDevicesListFetched(
const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
const std::list<std::shared_ptr<linphone::AccountDevice>> &devicesList) {
emit devicesListFetched(request, devicesList);
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef ACCOUNT_MANAGER_SERVICES_REQUEST_MODEL_H_
#define ACCOUNT_MANAGER_SERVICES_REQUEST_MODEL_H_
#include "model/listener/Listener.hpp"
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <linphone++/linphone.hh>
class AccountManagerServicesRequestModel
: public ::Listener<linphone::AccountManagerServicesRequest, linphone::AccountManagerServicesRequestListener>,
public linphone::AccountManagerServicesRequestListener,
public AbstractObject {
Q_OBJECT
public:
AccountManagerServicesRequestModel(
const std::shared_ptr<linphone::AccountManagerServicesRequest> &accountManagerServicesRequest,
QObject *parent = nullptr);
~AccountManagerServicesRequestModel();
void submit();
linphone::AccountManagerServicesRequest::Type getType() const;
signals:
void requestSuccessfull(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
const std::string &data);
void requestError(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
int statusCode,
const std::string &errorMessage,
const std::shared_ptr<const linphone::Dictionary> &parameterErrors);
void devicesListFetched(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
const std::list<std::shared_ptr<linphone::AccountDevice>> &devicesList);
private:
DECLARE_ABSTRACT_OBJECT
//--------------------------------------------------------------------------------
// LINPHONE
//--------------------------------------------------------------------------------
virtual void onRequestSuccessful(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
const std::string &data) override;
virtual void onRequestError(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
int statusCode,
const std::string &errorMessage,
const std::shared_ptr<const linphone::Dictionary> &parameterErrors) override;
virtual void onDevicesListFetched(const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request,
const std::list<std::shared_ptr<linphone::AccountDevice>> &devicesList) override;
};
#endif

View file

@ -28,6 +28,7 @@
#include <QTimer> #include <QTimer>
#include <linphone++/linphone.hh> #include <linphone++/linphone.hh>
#include "model/account/AccountManager.hpp"
#include "model/cli/CliModel.hpp" #include "model/cli/CliModel.hpp"
#include "model/listener/Listener.hpp" #include "model/listener/Listener.hpp"
#include "model/logger/LoggerModel.hpp" #include "model/logger/LoggerModel.hpp"

View file

@ -28,9 +28,9 @@
#include "LoggerListener.hpp" #include "LoggerListener.hpp"
#include "LoggerModel.hpp" #include "LoggerModel.hpp"
#include "model/setting/SettingsModel.hpp"
#include "tool/Constants.hpp" #include "tool/Constants.hpp"
#include "tool/Utils.hpp" #include "tool/Utils.hpp"
#include "model/setting/SettingsModel.hpp"
#include "core/logger/QtLogger.hpp" #include "core/logger/QtLogger.hpp"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -127,7 +127,9 @@ void LoggerModel::applyConfig(const std::shared_ptr<linphone::Config> &config) {
const QString folder = SettingsModel::getLogsFolder(config); const QString folder = SettingsModel::getLogsFolder(config);
linphone::Core::setLogCollectionPath(Utils::appStringToCoreString(folder)); linphone::Core::setLogCollectionPath(Utils::appStringToCoreString(folder));
enableFullLogs(SettingsModel::getFullLogsEnabled(config)); enableFullLogs(SettingsModel::getFullLogsEnabled(config));
enable(SettingsModel::getLogsEnabled(config)); // TODO : uncomment when it is possible to change the config from settings
// enable(SettingsModel::getLogsEnabled(config));
enable(true);
} }
void LoggerModel::init() { void LoggerModel::init() {

View file

@ -19,11 +19,10 @@
*/ */
#include "SettingsModel.hpp" #include "SettingsModel.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
#include "model/tool/ToolModel.hpp"
#include "core/path/Paths.hpp" #include "core/path/Paths.hpp"
#include "model/core/CoreModel.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp"
// ============================================================================= // =============================================================================
@ -63,18 +62,14 @@ QStringList SettingsModel::getVideoDevices() const {
return result; return result;
} }
QString SettingsModel::getVideoDevice () const { QString SettingsModel::getVideoDevice() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return Utils::coreStringToAppString( return Utils::coreStringToAppString(CoreModel::getInstance()->getCore()->getVideoDevice());
CoreModel::getInstance()->getCore()->getVideoDevice()
);
} }
void SettingsModel::setVideoDevice (const QString &device) { void SettingsModel::setVideoDevice(const QString &device) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->setVideoDevice( CoreModel::getInstance()->getCore()->setVideoDevice(Utils::appStringToCoreString(device));
Utils::appStringToCoreString(device)
);
emit videoDeviceChanged(device); emit videoDeviceChanged(device);
} }
@ -94,8 +89,8 @@ void SettingsModel::resetCaptureGraph() {
} }
void SettingsModel::createCaptureGraph() { void SettingsModel::createCaptureGraph() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mSimpleCaptureGraph = mSimpleCaptureGraph = new MediastreamerUtils::SimpleCaptureGraph(Utils::appStringToCoreString(getCaptureDevice()),
new MediastreamerUtils::SimpleCaptureGraph(Utils::appStringToCoreString(getCaptureDevice()), Utils::appStringToCoreString(getPlaybackDevice())); Utils::appStringToCoreString(getPlaybackDevice()));
mSimpleCaptureGraph->start(); mSimpleCaptureGraph->start();
emit captureGraphRunningChanged(getCaptureGraphRunning()); emit captureGraphRunningChanged(getCaptureGraphRunning());
} }
@ -135,7 +130,7 @@ void SettingsModel::deleteCaptureGraph() {
mSimpleCaptureGraph = nullptr; mSimpleCaptureGraph = nullptr;
} }
} }
//Force a call on the 'detect' method of all audio filters, updating new or removed devices // Force a call on the 'detect' method of all audio filters, updating new or removed devices
void SettingsModel::accessCallSettings() { void SettingsModel::accessCallSettings() {
// Audio // Audio
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
@ -148,7 +143,8 @@ void SettingsModel::accessCallSettings() {
emit playbackGainChanged(getPlaybackGain()); emit playbackGainChanged(getPlaybackGain());
emit captureGainChanged(getCaptureGain()); emit captureGainChanged(getCaptureGain());
// Media cards must not be used twice (capture card + call) else we will get latencies issues and bad echo calibrations in call. // Media cards must not be used twice (capture card + call) else we will get latencies issues and bad echo
// calibrations in call.
if (!getIsInCall()) { if (!getIsInCall()) {
qDebug() << "Starting capture graph from accessing audio panel"; qDebug() << "Starting capture graph from accessing audio panel";
startCaptureGraph(); startCaptureGraph();
@ -193,8 +189,7 @@ void SettingsModel::setPlaybackGain(float gain) {
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) { if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
mSimpleCaptureGraph->setPlaybackGain(gain); mSimpleCaptureGraph->setPlaybackGain(gain);
} }
if((int)(oldGain*1000) != (int)(gain*1000)) if ((int)(oldGain * 1000) != (int)(gain * 1000)) emit playbackGainChanged(gain);
emit playbackGainChanged(gain);
} }
float SettingsModel::getCaptureGain() const { float SettingsModel::getCaptureGain() const {
@ -210,11 +205,10 @@ void SettingsModel::setCaptureGain(float gain) {
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) { if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
mSimpleCaptureGraph->setCaptureGain(gain); mSimpleCaptureGraph->setCaptureGain(gain);
} }
if((int)(oldGain *1000) != (int)(gain *1000)) if ((int)(oldGain * 1000) != (int)(gain * 1000)) emit captureGainChanged(gain);
emit captureGainChanged(gain);
} }
QStringList SettingsModel::getCaptureDevices () const { QStringList SettingsModel::getCaptureDevices() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore(); shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
QStringList list; QStringList list;
@ -226,7 +220,7 @@ QStringList SettingsModel::getCaptureDevices () const {
return list; return list;
} }
QStringList SettingsModel::getPlaybackDevices () const { QStringList SettingsModel::getPlaybackDevices() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore(); shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
QStringList list; QStringList list;
@ -241,68 +235,64 @@ QStringList SettingsModel::getPlaybackDevices () const {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
QString SettingsModel::getCaptureDevice () const { QString SettingsModel::getCaptureDevice() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto audioDevice = CoreModel::getInstance()->getCore()->getInputAudioDevice(); auto audioDevice = CoreModel::getInstance()->getCore()->getInputAudioDevice();
return Utils::coreStringToAppString(audioDevice? audioDevice->getId() : CoreModel::getInstance()->getCore()->getCaptureDevice()); return Utils::coreStringToAppString(audioDevice ? audioDevice->getId()
: CoreModel::getInstance()->getCore()->getCaptureDevice());
} }
void SettingsModel::setCaptureDevice (const QString &device) { void SettingsModel::setCaptureDevice(const QString &device) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
std::string devId = Utils::appStringToCoreString(device); std::string devId = Utils::appStringToCoreString(device);
auto list = CoreModel::getInstance()->getCore()->getExtendedAudioDevices(); auto list = CoreModel::getInstance()->getCore()->getExtendedAudioDevices();
auto audioDevice = find_if(list.cbegin(), list.cend(), [&] ( const std::shared_ptr<linphone::AudioDevice> & audioItem) { auto audioDevice =
return audioItem->getId() == devId; find_if(list.cbegin(), list.cend(),
}); [&](const std::shared_ptr<linphone::AudioDevice> &audioItem) { return audioItem->getId() == devId; });
if(audioDevice != list.cend()){ if (audioDevice != list.cend()) {
CoreModel::getInstance()->getCore()->setCaptureDevice(devId); CoreModel::getInstance()->getCore()->setCaptureDevice(devId);
CoreModel::getInstance()->getCore()->setInputAudioDevice(*audioDevice); CoreModel::getInstance()->getCore()->setInputAudioDevice(*audioDevice);
emit captureDeviceChanged(device); emit captureDeviceChanged(device);
resetCaptureGraph(); resetCaptureGraph();
}else } else qWarning() << "Cannot set Capture device. The ID cannot be matched with an existant device : " << device;
qWarning() << "Cannot set Capture device. The ID cannot be matched with an existant device : " << device;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
QString SettingsModel::getPlaybackDevice () const { QString SettingsModel::getPlaybackDevice() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto audioDevice = CoreModel::getInstance()->getCore()->getOutputAudioDevice(); auto audioDevice = CoreModel::getInstance()->getCore()->getOutputAudioDevice();
return Utils::coreStringToAppString(audioDevice? audioDevice->getId() : CoreModel::getInstance()->getCore()->getPlaybackDevice()); return Utils::coreStringToAppString(audioDevice ? audioDevice->getId()
: CoreModel::getInstance()->getCore()->getPlaybackDevice());
} }
void SettingsModel::setPlaybackDevice (const QString &device) { void SettingsModel::setPlaybackDevice(const QString &device) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
std::string devId = Utils::appStringToCoreString(device); std::string devId = Utils::appStringToCoreString(device);
auto list = CoreModel::getInstance()->getCore()->getExtendedAudioDevices(); auto list = CoreModel::getInstance()->getCore()->getExtendedAudioDevices();
auto audioDevice = find_if(list.cbegin(), list.cend(), [&] ( const std::shared_ptr<linphone::AudioDevice> & audioItem) { auto audioDevice =
return audioItem->getId() == devId; find_if(list.cbegin(), list.cend(),
}); [&](const std::shared_ptr<linphone::AudioDevice> &audioItem) { return audioItem->getId() == devId; });
if(audioDevice != list.cend()){ if (audioDevice != list.cend()) {
CoreModel::getInstance()->getCore()->setPlaybackDevice(devId); CoreModel::getInstance()->getCore()->setPlaybackDevice(devId);
CoreModel::getInstance()->getCore()->setOutputAudioDevice(*audioDevice); CoreModel::getInstance()->getCore()->setOutputAudioDevice(*audioDevice);
emit playbackDeviceChanged(device); emit playbackDeviceChanged(device);
resetCaptureGraph(); resetCaptureGraph();
}else } else qWarning() << "Cannot set Playback device. The ID cannot be matched with an existant device : " << device;
qWarning() << "Cannot set Playback device. The ID cannot be matched with an existant device : " << device;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
QString SettingsModel::getRingerDevice () const { QString SettingsModel::getRingerDevice() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return Utils::coreStringToAppString( return Utils::coreStringToAppString(CoreModel::getInstance()->getCore()->getRingerDevice());
CoreModel::getInstance()->getCore()->getRingerDevice()
);
} }
void SettingsModel::setRingerDevice (const QString &device) { void SettingsModel::setRingerDevice(const QString &device) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->setRingerDevice( CoreModel::getInstance()->getCore()->setRingerDevice(Utils::appStringToCoreString(device));
Utils::appStringToCoreString(device)
);
emit ringerDeviceChanged(device); emit ringerDeviceChanged(device);
} }
@ -323,33 +313,33 @@ void SettingsModel::setVideoEnabled(const bool enabled) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool SettingsModel::getEchoCancellationEnabled () const { bool SettingsModel::getEchoCancellationEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return CoreModel::getInstance()->getCore()->echoCancellationEnabled(); return CoreModel::getInstance()->getCore()->echoCancellationEnabled();
} }
void SettingsModel::setEchoCancellationEnabled (bool status) { void SettingsModel::setEchoCancellationEnabled(bool status) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->enableEchoCancellation(status); CoreModel::getInstance()->getCore()->enableEchoCancellation(status);
emit echoCancellationEnabledChanged(status); emit echoCancellationEnabledChanged(status);
} }
void SettingsModel::startEchoCancellerCalibration(){ void SettingsModel::startEchoCancellerCalibration() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->startEchoCancellerCalibration(); CoreModel::getInstance()->getCore()->startEchoCancellerCalibration();
} }
int SettingsModel::getEchoCancellationCalibration()const { int SettingsModel::getEchoCancellationCalibration() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return CoreModel::getInstance()->getCore()->getEchoCancellationCalibration(); return CoreModel::getInstance()->getCore()->getEchoCancellationCalibration();
} }
bool SettingsModel::getAutomaticallyRecordCallsEnabled () const { bool SettingsModel::getAutomaticallyRecordCallsEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return !!mConfig->getInt(UiSection, "automatically_record_calls", 0); return !!mConfig->getInt(UiSection, "automatically_record_calls", 0);
} }
void SettingsModel::setAutomaticallyRecordCallsEnabled (bool enabled) { void SettingsModel::setAutomaticallyRecordCallsEnabled(bool enabled) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mConfig->setInt(UiSection, "automatically_record_calls", enabled); mConfig->setInt(UiSection, "automatically_record_calls", enabled);
emit automaticallyRecordCallsEnabledChanged(enabled); emit automaticallyRecordCallsEnabledChanged(enabled);
@ -359,12 +349,12 @@ void SettingsModel::setAutomaticallyRecordCallsEnabled (bool enabled) {
// VFS. // VFS.
// ============================================================================= // =============================================================================
bool SettingsModel::getVfsEnabled () const { bool SettingsModel::getVfsEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return !!mConfig->getInt(UiSection, "vfs_enabled", 0); return !!mConfig->getInt(UiSection, "vfs_enabled", 0);
} }
void SettingsModel::setVfsEnabled (bool enabled) { void SettingsModel::setVfsEnabled(bool enabled) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mConfig->setInt(UiSection, "vfs_enabled", enabled); mConfig->setInt(UiSection, "vfs_enabled", enabled);
emit vfsEnabledChanged(enabled); emit vfsEnabledChanged(enabled);
@ -374,58 +364,58 @@ void SettingsModel::setVfsEnabled (bool enabled) {
// Logs. // Logs.
// ============================================================================= // =============================================================================
bool SettingsModel::getLogsEnabled () const { bool SettingsModel::getLogsEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return getLogsEnabled(mConfig); return getLogsEnabled(mConfig);
} }
void SettingsModel::setLogsEnabled (bool status) { void SettingsModel::setLogsEnabled(bool status) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mConfig->setInt(UiSection, "logs_enabled", status); mConfig->setInt(UiSection, "logs_enabled", status);
CoreModel::getInstance()->getLogger()->enable(status); CoreModel::getInstance()->getLogger()->enable(status);
emit logsEnabledChanged(status); emit logsEnabledChanged(status);
} }
bool SettingsModel::getFullLogsEnabled () const { bool SettingsModel::getFullLogsEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return getFullLogsEnabled(mConfig); return getFullLogsEnabled(mConfig);
} }
void SettingsModel::setFullLogsEnabled (bool status) { void SettingsModel::setFullLogsEnabled(bool status) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mConfig->setInt(UiSection, "full_logs_enabled", status); mConfig->setInt(UiSection, "full_logs_enabled", status);
CoreModel::getInstance()->getLogger()->enableFullLogs(status); CoreModel::getInstance()->getLogger()->enableFullLogs(status);
emit fullLogsEnabledChanged(status); emit fullLogsEnabledChanged(status);
} }
bool SettingsModel::getLogsEnabled (const shared_ptr<linphone::Config> &config) { bool SettingsModel::getLogsEnabled(const shared_ptr<linphone::Config> &config) {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
return config ? config->getInt(UiSection, "logs_enabled", false) : true; return config ? config->getInt(UiSection, "logs_enabled", false) : true;
} }
bool SettingsModel::getFullLogsEnabled (const shared_ptr<linphone::Config> &config) { bool SettingsModel::getFullLogsEnabled(const shared_ptr<linphone::Config> &config) {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
return config ? config->getInt(UiSection, "full_logs_enabled", false) : false; return config ? config->getInt(UiSection, "full_logs_enabled", false) : false;
} }
QString SettingsModel::getLogsFolder () const { QString SettingsModel::getLogsFolder() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return getLogsFolder(mConfig); return getLogsFolder(mConfig);
} }
QString SettingsModel::getLogsFolder (const shared_ptr<linphone::Config> &config) { QString SettingsModel::getLogsFolder(const shared_ptr<linphone::Config> &config) {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
return config return config ? Utils::coreStringToAppString(config->getString(
? Utils::coreStringToAppString(config->getString(UiSection, "logs_folder", Utils::appStringToCoreString(Paths::getLogsDirPath()))) UiSection, "logs_folder", Utils::appStringToCoreString(Paths::getLogsDirPath())))
: Paths::getLogsDirPath(); : Paths::getLogsDirPath();
} }
void SettingsModel::cleanLogs () const { void SettingsModel::cleanLogs() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->resetLogCollection(); CoreModel::getInstance()->getCore()->resetLogCollection();
} }
void SettingsModel::sendLogs () const { void SettingsModel::sendLogs() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore(); auto core = CoreModel::getInstance()->getCore();
qInfo() << QStringLiteral("Send logs to: `%1` from `%2`.") qInfo() << QStringLiteral("Send logs to: `%1` from `%2`.")
@ -434,9 +424,7 @@ void SettingsModel::sendLogs () const {
core->uploadLogCollection(); core->uploadLogCollection();
} }
QString SettingsModel::getLogsEmail () const { QString SettingsModel::getLogsEmail() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return Utils::coreStringToAppString( return Utils::coreStringToAppString(mConfig->getString(UiSection, "logs_email", Constants::DefaultLogsEmail));
mConfig->getString(UiSection, "logs_email", Constants::DefaultLogsEmail)
);
} }

View file

@ -64,7 +64,7 @@ public:
static constexpr char DownloadUrl[] = "https://www.linphone.org/technical-corner/linphone"; static constexpr char DownloadUrl[] = "https://www.linphone.org/technical-corner/linphone";
static constexpr char VersionCheckReleaseUrl[] = "https://linphone.org/releases"; static constexpr char VersionCheckReleaseUrl[] = "https://linphone.org/releases";
static constexpr char VersionCheckNightlyUrl[] = "https://linphone.org/snapshots"; static constexpr char VersionCheckNightlyUrl[] = "https://linphone.org/snapshots";
static constexpr char PasswordRecoveryUrl[] = "https://subscribe.linphone.org/login/email"; static constexpr char PasswordRecoveryUrl[] = "https://subscribe.linphone.org/recovery/email";
static constexpr char CguUrl[] = "https://www.linphone.org/general-terms"; static constexpr char CguUrl[] = "https://www.linphone.org/general-terms";
static constexpr char PrivatePolicyUrl[] = "https://www.linphone.org/privacy-policy"; static constexpr char PrivatePolicyUrl[] = "https://www.linphone.org/privacy-policy";
static constexpr char ContactUrl[] = "https://www.linphone.org/contact"; static constexpr char ContactUrl[] = "https://www.linphone.org/contact";

View file

@ -323,6 +323,29 @@ LinphoneEnums::TransportType fromLinphone(const linphone::TransportType &type);
QString toString(const LinphoneEnums::TransportType &type); QString toString(const LinphoneEnums::TransportType &type);
void fromString(const QString &transportType, LinphoneEnums::TransportType *transport); void fromString(const QString &transportType, LinphoneEnums::TransportType *transport);
enum class AccountManagerServicesRequestType {
SendAccountCreationTokenByPush = int(linphone::AccountManagerServicesRequest::Type::SendAccountCreationTokenByPush),
AccountCreationRequestToken = int(linphone::AccountManagerServicesRequest::Type::AccountCreationRequestToken),
AccountCreationTokenFromAccountCreationRequestToken =
int(linphone::AccountManagerServicesRequest::Type::AccountCreationTokenFromAccountCreationRequestToken),
CreateAccountUsingToken = int(linphone::AccountManagerServicesRequest::Type::CreateAccountUsingToken),
SendPhoneNumberLinkingCodeBySms =
int(linphone::AccountManagerServicesRequest::Type::SendPhoneNumberLinkingCodeBySms),
LinkPhoneNumberUsingCode = int(linphone::AccountManagerServicesRequest::Type::LinkPhoneNumberUsingCode),
SendEmailLinkingCodeByEmail = int(linphone::AccountManagerServicesRequest::Type::SendEmailLinkingCodeByEmail),
LinkEmailUsingCode = int(linphone::AccountManagerServicesRequest::Type::LinkEmailUsingCode),
GetDevicesList = int(linphone::AccountManagerServicesRequest::Type::GetDevicesList),
DeleteDevice = int(linphone::AccountManagerServicesRequest::Type::DeleteDevice),
GetCreationTokenAsAdmin = int(linphone::AccountManagerServicesRequest::Type::GetCreationTokenAsAdmin),
GetAccountInfoAsAdmin = int(linphone::AccountManagerServicesRequest::Type::GetAccountInfoAsAdmin),
DeleteAccountAsAdmin = int(linphone::AccountManagerServicesRequest::Type::DeleteAccountAsAdmin)
};
Q_ENUM_NS(AccountManagerServicesRequestType)
// linphone::AccountManagerServicesRequest::Type toLinphone(const LinphoneEnums::AccountManagerServicesRequestType
// &type); LinphoneEnums::AccountManagerServicesRequestType fromLinphone(const
// linphone::AccountManagerServicesRequest::Type &type);
enum VideoSourceScreenSharingType { enum VideoSourceScreenSharingType {
VideoSourceScreenSharingTypeArea = int(linphone::VideoSourceScreenSharingType::Area), VideoSourceScreenSharingTypeArea = int(linphone::VideoSourceScreenSharingType::Area),
VideoSourceScreenSharingTypeDisplay = int(linphone::VideoSourceScreenSharingType::Display), VideoSourceScreenSharingTypeDisplay = int(linphone::VideoSourceScreenSharingType::Display),

View file

@ -374,6 +374,11 @@ bool Utils::copyToClipboard(const QString &text) {
return !clipboardText.isEmpty(); return !clipboardText.isEmpty();
} }
QString Utils::getClipboardText() {
QClipboard *clipboard = QApplication::clipboard();
return clipboard->text();
}
QString Utils::getApplicationProduct() { QString Utils::getApplicationProduct() {
// Note: Keep '-' as a separator between application name and application type // Note: Keep '-' as a separator between application name and application type
return QString(APPLICATION_NAME "-Desktop").remove(' ') + "/" + QCoreApplication::applicationVersion(); return QString(APPLICATION_NAME "-Desktop").remove(' ') + "/" + QCoreApplication::applicationVersion();

View file

@ -85,6 +85,7 @@ public:
Q_INVOKABLE static QStringList generateSecurityLettersArray(int arraySize, int correctIndex, QString correctCode); Q_INVOKABLE static QStringList generateSecurityLettersArray(int arraySize, int correctIndex, QString correctCode);
Q_INVOKABLE static int getRandomIndex(int size); Q_INVOKABLE static int getRandomIndex(int size);
Q_INVOKABLE static bool copyToClipboard(const QString &text); Q_INVOKABLE static bool copyToClipboard(const QString &text);
Q_INVOKABLE static QString getClipboardText();
Q_INVOKABLE static QString toDateString(QDateTime date, const QString &format = ""); Q_INVOKABLE static QString toDateString(QDateTime date, const QString &format = "");
Q_INVOKABLE static QString toDateString(QDate date, const QString &format = ""); Q_INVOKABLE static QString toDateString(QDate date, const QString &format = "");
Q_INVOKABLE static QString toDateDayString(const QDateTime &date); Q_INVOKABLE static QString toDateDayString(const QDateTime &date);

View file

@ -38,8 +38,10 @@ ApplicationWindow {
infoPopup.open() infoPopup.open()
infoPopup.closePopup.connect(removeFromPopupLayout) infoPopup.closePopup.connect(removeFromPopupLayout)
} }
function showLoadingPopup(text) { function showLoadingPopup(text, cancelButtonVisible) {
if (cancelButtonVisible == undefined) cancelButtonVisible = false
loadingPopup.text = text loadingPopup.text = text
loadingPopup.cancelButtonVisible = cancelButtonVisible
loadingPopup.open() loadingPopup.open()
} }
function closeLoadingPopup() { function closeLoadingPopup() {

View file

@ -15,10 +15,12 @@ Rectangle {
color: DefaultStyle.grey_0 color: DefaultStyle.grey_0
ColumnLayout { ColumnLayout {
// anchors.leftMargin: 119 * DefaultStyle.dp // anchors.leftMargin: 119 * DefaultStyle.dp
anchors.top: parent.top id: contentLayout
anchors.left: parent.left // anchors.top: parent.top
anchors.right: parent.right // anchors.left: parent.left
anchors.bottom: bottomMountains.top // anchors.right: parent.right
anchors.fill: parent
// anchors.bottom: bottomMountains.top
spacing: 0 spacing: 0
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
@ -63,17 +65,16 @@ Rectangle {
id: centerLayout id: centerLayout
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
z: 1
} }
}
Image { Image {
id: bottomMountains id: bottomMountains
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: 108 * DefaultStyle.dp
source: AppIcons.belledonne source: AppIcons.belledonne
fillMode: Image.Stretch fillMode: Image.Stretch
Layout.fillWidth: true
Layout.preferredHeight: 108 * DefaultStyle.dp
} }
}
} }

View file

@ -92,8 +92,17 @@ AppWindow {
id: registerPage id: registerPage
RegisterPage { RegisterPage {
onReturnToLogin: mainWindowStackView.replace(loginPage) onReturnToLogin: mainWindowStackView.replace(loginPage)
onRegisterCalled: (countryCode, phoneNumber, email) => { onBrowserValidationRequested: mainWindow.showLoadingPopup(qsTr("Veuillez valider le captcha sur la page web"), true)
mainWindowStackView.push(checkingPage, {"phoneNumber": phoneNumber, "email": email}) Connections {
target: RegisterPageCpp
onNewAccountCreationSucceed: (withEmail, address, sipIdentityAddress) => {
mainWindowStackView.push(checkingPage, {"registerWithEmail": withEmail, "address": address, "sipIdentityAddress": sipIdentityAddress})
}
onRegisterNewAccountFailed: (errorMessage) => {
mainWindow.showInformationPopup(qsTr("Erreur lors de la création"), errorMessage, false)
mainWindow.closeLoadingPopup()
}
onTokenConversionSucceed: mainWindow.closeLoadingPopup()
} }
} }
} }
@ -101,6 +110,20 @@ AppWindow {
id: checkingPage id: checkingPage
RegisterCheckingPage { RegisterCheckingPage {
onReturnToRegister: mainWindowStackView.pop() onReturnToRegister: mainWindowStackView.pop()
onSendCode: (code) => {
RegisterPageCpp.linkNewAccountUsingCode(code, registerWithEmail, sipIdentityAddress)
}
Connections {
target: RegisterPageCpp
onLinkingNewAccountWithCodeSucceed: {
mainWindowStackView.replace(loginPage)
mainWindow.showInformationPopup(qsTr("Compte créé"), qsTr("Le compte a été créé avec succès. Vous pouvez maintenant vous connecter"), true)
}
onLinkingNewAccountWithCodeFailed: (errorMessage) => {
if (errorMessage.length === 0) errorMessage = qsTr("Erreur dans le code de validation")
mainWindow.showInformationPopup(qsTr("Erreur"), errorMessage, false)
}
}
} }
} }
Component { Component {

View file

@ -12,6 +12,7 @@ Control.TextField {
height: inputSize height: inputSize
horizontalAlignment: TextInput.AlignHCenter horizontalAlignment: TextInput.AlignHCenter
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
overwriteMode: true
// just reserve the space for the background // just reserve the space for the background
placeholderText: "0" placeholderText: "0"

View file

@ -8,12 +8,6 @@ Text {
id: mainItem id: mainItem
color: DefaultStyle.danger_500main color: DefaultStyle.danger_500main
opacity: 0 opacity: 0
function displayText() {
mainItem.state = "Visible"
}
function hideText() {
mainItem.state = "Invisible"
}
font { font {
pixelSize: 12 * DefaultStyle.dp pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp weight: 300 * DefaultStyle.dp
@ -25,7 +19,7 @@ Text {
}, },
State{ State{
name:"Invisible" name:"Invisible"
PropertyChanges{target: mainItem; opacity: 0.0} PropertyChanges{target: mainItem; opacity: 0.0; text: ""}
} }
] ]
transitions: [ transitions: [
@ -34,7 +28,7 @@ Text {
to: "Invisible" to: "Invisible"
NumberAnimation { NumberAnimation {
property: "opacity" property: "opacity"
duration: 1000 duration: 500
} }
} }
] ]
@ -51,6 +45,8 @@ Text {
onTextChanged: { onTextChanged: {
if (mainItem.text.length > 0) { if (mainItem.text.length > 0) {
mainItem.state = "Visible" mainItem.state = "Visible"
} else {
mainItem.state = "Invisible"
} }
} }
} }

View file

@ -2,7 +2,7 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls as Control import QtQuick.Controls as Control
import Linphone import Linphone
import ConstantsCpp 1.0
ColumnLayout { ColumnLayout {
id: mainItem id: mainItem
@ -148,7 +148,7 @@ ColumnLayout {
weight: 600 * DefaultStyle.dp weight: 600 * DefaultStyle.dp
} }
} }
onClicked: console.debug("[LoginForm]User: forgotten password button clicked") onClicked: Qt.openUrlExternally(ConstantsCpp.PasswordRecoveryUrl)
} }
} }

View file

@ -6,6 +6,7 @@ import Linphone
Popup { Popup {
id: mainItem id: mainItem
property string text property string text
property bool cancelButtonVisible: false
modal: true modal: true
closePolicy: Control.Popup.NoAutoClose closePolicy: Control.Popup.NoAutoClose
anchors.centerIn: parent anchors.centerIn: parent
@ -15,6 +16,8 @@ Popup {
// onAboutToShow: width = contentText.implicitWidth // onAboutToShow: width = contentText.implicitWidth
contentItem: ColumnLayout { contentItem: ColumnLayout {
spacing: 15 * DefaultStyle.dp spacing: 15 * DefaultStyle.dp
// width: childrenRect.width
// height: childrenRect.height
BusyIndicator{ BusyIndicator{
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 33 * DefaultStyle.dp Layout.preferredWidth: 33 * DefaultStyle.dp
@ -28,5 +31,11 @@ Popup {
text: mainItem.text text: mainItem.text
font.pixelSize: 14 * DefaultStyle.dp font.pixelSize: 14 * DefaultStyle.dp
} }
Button {
visible: mainItem.cancelButtonVisible
Layout.alignment: Qt.AlignHCenter
text: qsTr("Annuler")
onClicked: mainItem.close()
}
} }
} }

View file

@ -7,7 +7,7 @@ import Linphone
ColumnLayout { ColumnLayout {
id: mainItem id: mainItem
property string label: "" property string label: ""
readonly property string currentText: combobox.model.getAt(combobox.currentIndex) ? combobox.model.getAt(combobox.currentIndex).countryCallingCode : "" readonly property string currentText: combobox.model.getAt(combobox.currentIndex) ? "+" + combobox.model.getAt(combobox.currentIndex).countryCallingCode : ""
property string defaultCallingCode: "" property string defaultCallingCode: ""
property bool enableBackgroundColors: false property bool enableBackgroundColors: false
@ -101,7 +101,7 @@ ColumnLayout {
id: listPopup id: listPopup
y: combobox.height - 1 y: combobox.height - 1
width: 311 * DefaultStyle.dp width: 311 * DefaultStyle.dp
height: 198 * DefaultStyle.dp height: 250 * DefaultStyle.dp
contentItem: ListView { contentItem: ListView {
id: listView id: listView
@ -109,7 +109,9 @@ ColumnLayout {
anchors.fill: parent anchors.fill: parent
model: PhoneNumberProxy{} model: PhoneNumberProxy{}
currentIndex: combobox.highlightedIndex >= 0 ? combobox.highlightedIndex : 0 currentIndex: combobox.highlightedIndex >= 0 ? combobox.highlightedIndex : 0
highlightFollowsCurrentItem: true keyNavigationEnabled: true
keyNavigationWraps: true
maximumFlickVelocity: 1500
highlight: Rectangle { highlight: Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@ -177,7 +179,7 @@ ColumnLayout {
color: DefaultStyle.main2_500main color: DefaultStyle.main2_500main
visible: parent.containsMouse visible: parent.containsMouse
} }
onPressed: { onClicked: {
combobox.currentIndex = index combobox.currentIndex = index
listPopup.close() listPopup.close()
} }

View file

@ -7,13 +7,15 @@ ColumnLayout {
id: mainItem id: mainItem
property string label: "" property string label: ""
property string errorMessage: "" property alias errorMessage: errorText.text
property string placeholderText : "" property string placeholderText : ""
property bool mandatory: false property bool mandatory: false
property bool enableErrorText: true
property int textInputWidth: width property int textInputWidth: width
property string initialPhoneNumber property string initialPhoneNumber
readonly property string phoneNumber: textField.text readonly property string phoneNumber: textField.text
readonly property string countryCode: combobox.currentText readonly property string countryCode: combobox.currentText
property string defaultCallingCode
Text { Text {
visible: label.length > 0 visible: label.length > 0
@ -26,9 +28,13 @@ ColumnLayout {
} }
} }
Item {
Layout.preferredWidth: contentBackground.width
Layout.preferredHeight: contentBackground.height
Rectangle { Rectangle {
Layout.preferredWidth: mainItem.textInputWidth id: contentBackground
Layout.preferredHeight: 49 * DefaultStyle.dp width: mainItem.textInputWidth
height: 49 * DefaultStyle.dp
radius: 63 * DefaultStyle.dp radius: 63 * DefaultStyle.dp
color: DefaultStyle.grey_100 color: DefaultStyle.grey_100
border.color: mainItem.errorMessage.length > 0 border.color: mainItem.errorMessage.length > 0
@ -41,6 +47,7 @@ ColumnLayout {
PhoneNumberComboBox { PhoneNumberComboBox {
id: combobox id: combobox
implicitWidth: 110 * DefaultStyle.dp implicitWidth: 110 * DefaultStyle.dp
defaultCallingCode: mainItem.defaultCallingCode
} }
Rectangle { Rectangle {
Layout.preferredWidth: 1 * DefaultStyle.dp Layout.preferredWidth: 1 * DefaultStyle.dp
@ -59,12 +66,13 @@ ColumnLayout {
} }
} }
} }
ErrorText {
Text { id: errorText
visible: mainItem.errorMessage.length > 0 anchors.top: contentBackground.bottom
verticalAlignment: Text.AlignVCenter // visible: mainItem.enableErrorText
text: mainItem.errorMessage text: mainItem.errorMessage
color: DefaultStyle.danger_500main color: DefaultStyle.danger_500main
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.Wrap wrapMode: Text.Wrap
font { font {
@ -73,5 +81,7 @@ ColumnLayout {
bold: true bold: true
} }
Layout.preferredWidth: mainItem.textInputWidth Layout.preferredWidth: mainItem.textInputWidth
// Layout.preferredWidth: implicitWidth
}
} }
} }

View file

@ -86,7 +86,7 @@ Control.TextField {
} }
} }
Keys.onPressed: (event) => { Keys.onPressed: (event) => {
if (event.jey == Qt.Key_Control) mainItem.controlIsDown = true if (event.key == Qt.Key_Control) mainItem.controlIsDown = true
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
enterPressed() enterPressed()
if (mainItem.controlIsDown) { if (mainItem.controlIsDown) {

View file

@ -10,7 +10,7 @@ ColumnLayout {
property string label: "" property string label: ""
property bool mandatory: false property bool mandatory: false
property string errorMessage: "" property alias errorMessage: errorText.text
property bool enableErrorText: false property bool enableErrorText: false
property bool errorTextVisible: errorText.opacity > 0 property bool errorTextVisible: errorText.opacity > 0
spacing: 5 * DefaultStyle.dp spacing: 5 * DefaultStyle.dp
@ -31,17 +31,20 @@ ColumnLayout {
} }
} }
Item {
Layout.preferredHeight: contentItem.height
Layout.preferredWidth: contentItem.width
Item { Item {
id: contentItem id: contentItem
Layout.preferredHeight: childrenRect.height height: childrenRect.height
Layout.preferredWidth: childrenRect.width width: childrenRect.width
} }
ErrorText { ErrorText {
id: errorText id: errorText
visible: mainItem.enableErrorText anchors.top: contentItem.bottom
text: mainItem.errorMessage color: DefaultStyle.danger_500main
color: DefaultStyle.main2_600
Layout.preferredWidth: implicitWidth Layout.preferredWidth: implicitWidth
} }
}
} }

View file

@ -104,6 +104,7 @@ LoginLayout {
} }
}, },
Image { Image {
z: -1
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 129 * DefaultStyle.dp anchors.topMargin: 129 * DefaultStyle.dp

View file

@ -6,9 +6,11 @@ import Linphone
LoginLayout { LoginLayout {
id: mainItem id: mainItem
signal returnToRegister() signal returnToRegister()
property string phoneNumber signal sendCode(string code)
property string email property bool registerWithEmail
property string address
property string sipIdentityAddress
property string code
titleContent: [ titleContent: [
RowLayout { RowLayout {
spacing: 21 * DefaultStyle.dp spacing: 21 * DefaultStyle.dp
@ -34,7 +36,7 @@ LoginLayout {
Text { Text {
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
text: { text: {
var completeString = (mainItem.email.length > 0) ? qsTr("email") : qsTr("numéro") var completeString = mainItem.registerWithEmail ? qsTr("email") : qsTr("numéro")
text = qsTr("Inscription | Confirmer votre ") + completeString text = qsTr("Inscription | Confirmer votre ") + completeString
} }
font { font {
@ -64,7 +66,7 @@ LoginLayout {
} }
color: DefaultStyle.main2_700 color: DefaultStyle.main2_700
text: { text: {
var completeString = (mainItem.email.length > 0) ? ("email \"" + mainItem.email + "\"") : ("phone number \"" + mainItem.phoneNumber + "\"") var completeString = mainItem.registerWithEmail ? ("email \"") : ("phone number \"") + address + "\""
text = "We have sent a verification code on your " + completeString + " <br>Please enter the verification code below:" text = "We have sent a verification code on your " + completeString + " <br>Please enter the verification code below:"
} }
} }
@ -78,10 +80,12 @@ LoginLayout {
Layout.preferredHeight: height Layout.preferredHeight: height
onTextEdited: { onTextEdited: {
if (text.length > 0 ) { if (text.length > 0 ) {
mainItem.code = mainItem.code.slice(0, index) + text + mainItem.code.slice(index)
if (index < 3) if (index < 3)
nextItemInFocusChain(true).forceActiveFocus() nextItemInFocusChain(true).forceActiveFocus()
else { else {
// TODO : validate() mainItem.sendCode(mainItem.code)
mainItem.code = ""
} }
} else { } else {
if (index > 0) if (index > 0)

View file

@ -2,15 +2,27 @@ import QtQuick 2.15
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import QtQuick.Controls as Control import QtQuick.Controls as Control
import Linphone import Linphone
import UtilsCpp 1.0
import ConstantsCpp 1.0
LoginLayout { LoginLayout {
id: mainItem id: mainItem
signal returnToLogin() signal returnToLogin()
signal registerCalled(countryCode: string, phoneNumber: string, email: string) signal browserValidationRequested()
readonly property string countryCode: phoneNumberInput.countryCode readonly property string countryCode: phoneNumberInput.countryCode
readonly property string phoneNumber: phoneNumberInput.phoneNumber readonly property string phoneNumber: phoneNumberInput.phoneNumber
readonly property string email: emailInput.text readonly property string email: emailInput.text
Connections {
target: RegisterPageCpp
onErrorInField: (field, errorMessage) => {
if (field == "username") usernameItem.errorMessage = errorMessage
else if (field == "password") pwdItem.errorMessage = errorMessage
else if (field == "phone") phoneNumberInput.errorMessage = errorMessage
else if (field == "email") emailItem.errorMessage = errorMessage
}
}
titleContent: [ titleContent: [
RowLayout { RowLayout {
spacing: 21 * DefaultStyle.dp spacing: 21 * DefaultStyle.dp
@ -80,11 +92,13 @@ LoginLayout {
RowLayout { RowLayout {
spacing: 16 * DefaultStyle.dp spacing: 16 * DefaultStyle.dp
FormItemLayout { FormItemLayout {
id: usernameItem
label: qsTr("Username") label: qsTr("Username")
mandatory: true mandatory: true
contentItem: TextField { contentItem: TextField {
id: usernameInput id: usernameInput
Layout.preferredWidth: 346 * DefaultStyle.dp Layout.preferredWidth: 346 * DefaultStyle.dp
backgroundBorderColor: usernameItem.errorMessage.length > 0 ? DefaultStyle.danger_500main : DefaultStyle.grey_200
} }
} }
RowLayout { RowLayout {
@ -109,17 +123,22 @@ LoginLayout {
Layout.fillWidth: true Layout.fillWidth: true
PhoneNumberInput { PhoneNumberInput {
id: phoneNumberInput id: phoneNumberInput
label: qsTr("Phone number") property string completePhoneNumber: countryCode + phoneNumber
label: qsTr("Numéro de téléphone")
mandatory: true mandatory: true
placeholderText: "Phone number" placeholderText: "Phone number"
defaultCallingCode: "33"
Layout.preferredWidth: 346 * DefaultStyle.dp Layout.preferredWidth: 346 * DefaultStyle.dp
} }
FormItemLayout { FormItemLayout {
id: emailItem
label: qsTr("Email") label: qsTr("Email")
mandatory: true mandatory: true
enableErrorText: true
contentItem: TextField { contentItem: TextField {
id: emailInput id: emailInput
Layout.preferredWidth: 346 * DefaultStyle.dp Layout.preferredWidth: 346 * DefaultStyle.dp
backgroundBorderColor: emailItem.errorMessage.length > 0 ? DefaultStyle.danger_500main : DefaultStyle.grey_200
} }
} }
} }
@ -128,57 +147,53 @@ LoginLayout {
ColumnLayout { ColumnLayout {
spacing: 5 * DefaultStyle.dp spacing: 5 * DefaultStyle.dp
FormItemLayout { FormItemLayout {
label: qsTr("Password") id: passwordItem
label: qsTr("Mot de passe")
mandatory: true mandatory: true
enableErrorText: true
contentItem: TextField { contentItem: TextField {
id: pwdInput id: pwdInput
hidden: true hidden: true
Layout.preferredWidth: 346 * DefaultStyle.dp Layout.preferredWidth: 346 * DefaultStyle.dp
} backgroundBorderColor: passwordItem.errorMessage.length > 0 ? DefaultStyle.danger_500main : DefaultStyle.grey_200
}
Text {
text: qsTr("The password must contain 6 characters minimum")
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
} }
} }
} }
ColumnLayout { ColumnLayout {
spacing: 5 * DefaultStyle.dp spacing: 5 * DefaultStyle.dp
FormItemLayout { FormItemLayout {
label: qsTr("Confirm password") label: qsTr("Confirmation mot de passe")
mandatory: true mandatory: true
enableErrorText: true
contentItem: TextField { contentItem: TextField {
id: confirmPwdInput id: confirmPwdInput
hidden: true hidden: true
Layout.preferredWidth: 346 * DefaultStyle.dp Layout.preferredWidth: 346 * DefaultStyle.dp
} backgroundBorderColor: passwordItem.errorMessage.length > 0 ? DefaultStyle.danger_500main : DefaultStyle.grey_200
}
Text {
text: qsTr("The password must contain 6 characters minimum")
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
} }
} }
} }
} }
} }
ColumnLayout { // ColumnLayout {
spacing: 18 * DefaultStyle.dp // spacing: 18 * DefaultStyle.dp
RowLayout { // RowLayout {
spacing: 10 * DefaultStyle.dp // spacing: 10 * DefaultStyle.dp
CheckBox { // CheckBox {
} // id: subscribeToNewsletterCheckBox
Text { // }
text: qsTr("I would like to suscribe to the newsletter") // Text {
font { // text: qsTr("Je souhaite souscrire à la newletter Linphone.")
pixelSize: 14 * DefaultStyle.dp // font {
weight: 400 * DefaultStyle.dp // pixelSize: 14 * DefaultStyle.dp
} // weight: 400 * DefaultStyle.dp
} // }
} // MouseArea {
// anchors.fill: parent
// onClicked: subscribeToNewsletterCheckBox.toggle()
// }
// }
// }
RowLayout { RowLayout {
spacing: 10 * DefaultStyle.dp spacing: 10 * DefaultStyle.dp
CheckBox { CheckBox {
@ -188,70 +203,91 @@ LoginLayout {
spacing: 0 spacing: 0
Layout.fillWidth: true Layout.fillWidth: true
Text { Text {
// Layout.preferredWidth: 450 * DefaultStyle.dp text: qsTr("J'accepte les ")
text: qsTr("I accept the Terms and Conditions: ")
font { font {
pixelSize: 14 * DefaultStyle.dp pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp weight: 400 * DefaultStyle.dp
} }
MouseArea {
anchors.fill: parent
onClicked: termsCheckBox.toggle()
}
} }
Text { Text {
// Layout.preferredWidth: 450 * DefaultStyle.dp
font { font {
underline: true underline: true
pixelSize: 14 * DefaultStyle.dp pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp weight: 400 * DefaultStyle.dp
} }
text: qsTr("Read the Terms and Conditions.") text: qsTr("conditions dutilisation")
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: console.log("TODO : display terms and conditions") onClicked: Qt.openUrlExternally(ConstantsCpp.CguUrl)
} }
} }
Text { Text {
// Layout.preferredWidth: 450 * DefaultStyle.dp text: qsTr(" et la ")
text: qsTr("I accept the Privacy policy: ")
font { font {
pixelSize: 14 * DefaultStyle.dp pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp weight: 400 * DefaultStyle.dp
} }
} }
Text { Text {
// Layout.preferredWidth: 450 * DefaultStyle.dp
font { font {
underline: true underline: true
pixelSize: 14 * DefaultStyle.dp pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp weight: 400 * DefaultStyle.dp
} }
text: qsTr("Read the Privacy policy.") text: qsTr("politique de confidentialité.")
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: console.log("TODO : display privacy policy") onClicked: Qt.openUrlExternally(ConstantsCpp.PrivatePolicyUrl)
}
} }
} }
} }
} }
// }
Button { Button {
// enabled: termsCheckBox.checked && usernameInput.text.length != 0 && pwdInput.text.length != 0 && confirmPwdInput.text.length != 0 enabled: termsCheckBox.checked
// && (phoneNumberInput.phoneNumber.length != 0 || emailInput.text.length != 0)
leftPadding: 20 * DefaultStyle.dp leftPadding: 20 * DefaultStyle.dp
rightPadding: 20 * DefaultStyle.dp rightPadding: 20 * DefaultStyle.dp
topPadding: 11 * DefaultStyle.dp topPadding: 11 * DefaultStyle.dp
bottomPadding: 11 * DefaultStyle.dp bottomPadding: 11 * DefaultStyle.dp
text: qsTr("Register") text: qsTr("Créer")
onClicked:{ onClicked:{
console.log("[RegisterPage] User: Call register with phone number", phoneNumberInput.phoneNumber) if (usernameInput.text.length === 0) {
mainItem.registerCalled(phoneNumberInput.countryCode, phoneNumberInput.phoneNumber, emailInput.text) console.log("ERROR username")
usernameItem.errorMessage = qsTr("Veuillez entrer un nom d'utilisateur")
} else if (pwdInput.text.length === 0) {
console.log("ERROR password")
passwordItem.errorMessage = qsTr("Veuillez entrer un mot de passe")
} else if (pwdInput.text != confirmPwdInput.text) {
console.log("ERROR confirm pwd")
passwordItem.errorMessage = qsTr("Les mots de passe sont différents")
} else if (bar.currentIndex === 0 && phoneNumberInput.phoneNumber.length === 0) {
console.log("ERROR phone number")
phoneNumberInput.errorMessage = qsTr("Veuillez entrer un numéro de téléphone")
} else if (bar.currentIndex === 1 && emailInput.text.length === 0) {
console.log("ERROR email")
emailItem.errorMessage = qsTr("Veuillez entrer un email")
} else {
console.log("[RegisterPage] User: Call register")
mainItem.browserValidationRequested()
if (bar.currentIndex === 0)
RegisterPageCpp.registerNewAccount(usernameInput.text, pwdInput.text, "", phoneNumberInput.completePhoneNumber)
else
RegisterPageCpp.registerNewAccount(usernameInput.text, pwdInput.text, emailInput.text, "")
}
} }
} }
} }
}, },
Image { Image {
z: -1
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 129 * DefaultStyle.dp anchors.topMargin: 129 * DefaultStyle.dp

View file

@ -229,6 +229,7 @@ LoginLayout {
clip: true clip: true
}, },
Image { Image {
z: -1
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 129 * DefaultStyle.dp anchors.topMargin: 129 * DefaultStyle.dp