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/phone-number/PhoneNumber.hpp"
#include "core/phone-number/PhoneNumberProxy.hpp"
#include "core/register/RegisterPage.hpp"
#include "core/screen/ScreenList.hpp"
#include "core/screen/ScreenProxy.hpp"
#include "core/search/MagicSearchProxy.hpp"
@ -294,8 +295,17 @@ void App::initCore() {
void App::initCppInterfaces() {
qmlRegisterSingletonType<LoginPage>(
Constants::MainQmlUri, 1, 0, "LoginPageCpp",
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new LoginPage(engine); });
Constants::MainQmlUri, 1, 0, "LoginPageCpp", [](QQmlEngine *engine, QJSEngine *) -> QObject * {
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>(
"ConstantsCpp", 1, 0, "ConstantsCpp",
[](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/PhoneNumberList.cpp
core/phone-number/PhoneNumberProxy.cpp
core/register/RegisterPage.cpp
core/search/MagicSearchList.cpp
core/search/MagicSearchProxy.cpp

View file

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

View file

@ -19,10 +19,17 @@
*/
#include "PhoneNumber.hpp"
#include "core/App.hpp"
#include "tool/Utils.hpp"
#include <QApplication>
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) {
// Should be call from model Thread
mustBeInLinphoneThread(getClassName());

View file

@ -36,7 +36,7 @@ class PhoneNumber : public QObject, public AbstractObject {
Q_PROPERTY(QString country MEMBER mCountry CONSTANT)
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();
@ -47,6 +47,7 @@ public:
QString mInternationalCallPrefix;
QString mCountry;
private:
DECLARE_ABSTRACT_OBJECT
};

View file

@ -28,22 +28,28 @@
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) {
mustBeInMainThread(getClassName());
App::postModelAsync([=]() {
// Model thread.
auto dialPlans = linphone::Factory::get()->getDialPlans();
QList<QSharedPointer<PhoneNumber>> numbers;
QVector<QVariantMap> results;
QList<QSharedPointer<PhoneNumber>> *numbers = new QList<QSharedPointer<PhoneNumber>>();
for (auto it : dialPlans) {
auto numberModel = QSharedPointer<PhoneNumber>::create(it);
numberModel->moveToThread(this->thread());
numbers.push_back(numberModel);
auto numberModel = PhoneNumber::create(it);
numbers->push_back(numberModel);
}
// Invoke for adding stuffs in caller thread
QMetaObject::invokeMethod(this, [this, numbers]() {
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 {
Q_OBJECT
public:
static QSharedPointer<PhoneNumberList> create();
PhoneNumberList(QObject *parent = Q_NULLPTR);
~PhoneNumberList();
private:
DECLARE_ABSTRACT_OBJECT
};

View file

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

View file

@ -22,21 +22,24 @@
#define PHONE_NUMBER_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "PhoneNumberList.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class PhoneNumberProxy : public SortFilterProxy {
class PhoneNumberProxy : public SortFilterProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public:
PhoneNumberProxy(QObject *parent = Q_NULLPTR);
~PhoneNumberProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE int findIndexByCountryCallingCode(const QString& countryCallingCode);
Q_INVOKABLE int findIndexByCountryCallingCode(const QString &countryCallingCode);
signals:
void filterTextChanged();
@ -46,6 +49,10 @@ protected:
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText;
QSharedPointer<PhoneNumberList> mPhoneNumberList;
private:
DECLARE_ABSTRACT_OBJECT
};
#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
url=https://subscribe.linphone.org/api/
# replace above URL by https://staging-subscribe.linphone.org/api/ for testing
# url=https://flexisip-staging-master.linphone.org/api/
[alerts]
alerts_enabled=1

View file

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

View file

@ -21,10 +21,16 @@
#include "AccountManager.hpp"
#include <QDebug>
#include <QDesktopServices>
#include <QEventLoop>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTemporaryFile>
#include <QUrl>
#include "core/path/Paths.hpp"
#include "model/core/CoreModel.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(AccountManager)
@ -93,6 +99,172 @@ bool AccountManager::login(QString username, QString password, QString *errorMes
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,
linphone::RegistrationState state,
const std::string &message) {
@ -112,4 +284,4 @@ void AccountManager::onRegistrationStateChanged(const std::shared_ptr<linphone::
}
}
emit registrationStateChanged(state);
}
}

View file

@ -22,8 +22,11 @@
#define ACCOUNT_MANAGER_H_
#include <QObject>
#include <QTimer>
#include <linphone++/linphone.hh>
#include "AccountManagerServicesModel.hpp"
#include "AccountManagerServicesRequestModel.hpp"
#include "AccountModel.hpp"
#include "tool/AbstractObject.hpp"
@ -34,18 +37,36 @@ public:
~AccountManager();
bool login(QString username, QString password, QString *errorMessage = nullptr);
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,
linphone::RegistrationState state,
const std::string &message);
signals:
void registrationStateChanged(linphone::RegistrationState state);
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:
std::shared_ptr<AccountModel> mAccountModel;
std::shared_ptr<AccountManagerServicesModel> mAccountManagerServicesModel;
QTimer timer;
QString mCreatedSipAddress;
// std::shared_ptr<linphone::Address> mCreatedSipIdentityAddress;
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 <linphone++/linphone.hh>
#include "model/account/AccountManager.hpp"
#include "model/cli/CliModel.hpp"
#include "model/listener/Listener.hpp"
#include "model/logger/LoggerModel.hpp"

View file

@ -28,9 +28,9 @@
#include "LoggerListener.hpp"
#include "LoggerModel.hpp"
#include "model/setting/SettingsModel.hpp"
#include "tool/Constants.hpp"
#include "tool/Utils.hpp"
#include "model/setting/SettingsModel.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);
linphone::Core::setLogCollectionPath(Utils::appStringToCoreString(folder));
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() {

View file

@ -19,11 +19,10 @@
*/
#include "SettingsModel.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
#include "model/tool/ToolModel.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;
}
QString SettingsModel::getVideoDevice () const {
QString SettingsModel::getVideoDevice() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return Utils::coreStringToAppString(
CoreModel::getInstance()->getCore()->getVideoDevice()
);
return Utils::coreStringToAppString(CoreModel::getInstance()->getCore()->getVideoDevice());
}
void SettingsModel::setVideoDevice (const QString &device) {
void SettingsModel::setVideoDevice(const QString &device) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->setVideoDevice(
Utils::appStringToCoreString(device)
);
CoreModel::getInstance()->getCore()->setVideoDevice(Utils::appStringToCoreString(device));
emit videoDeviceChanged(device);
}
@ -94,8 +89,8 @@ void SettingsModel::resetCaptureGraph() {
}
void SettingsModel::createCaptureGraph() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mSimpleCaptureGraph =
new MediastreamerUtils::SimpleCaptureGraph(Utils::appStringToCoreString(getCaptureDevice()), Utils::appStringToCoreString(getPlaybackDevice()));
mSimpleCaptureGraph = new MediastreamerUtils::SimpleCaptureGraph(Utils::appStringToCoreString(getCaptureDevice()),
Utils::appStringToCoreString(getPlaybackDevice()));
mSimpleCaptureGraph->start();
emit captureGraphRunningChanged(getCaptureGraphRunning());
}
@ -135,7 +130,7 @@ void SettingsModel::deleteCaptureGraph() {
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() {
// Audio
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
@ -148,7 +143,8 @@ void SettingsModel::accessCallSettings() {
emit playbackGainChanged(getPlaybackGain());
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()) {
qDebug() << "Starting capture graph from accessing audio panel";
startCaptureGraph();
@ -193,8 +189,7 @@ void SettingsModel::setPlaybackGain(float gain) {
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
mSimpleCaptureGraph->setPlaybackGain(gain);
}
if((int)(oldGain*1000) != (int)(gain*1000))
emit playbackGainChanged(gain);
if ((int)(oldGain * 1000) != (int)(gain * 1000)) emit playbackGainChanged(gain);
}
float SettingsModel::getCaptureGain() const {
@ -210,11 +205,10 @@ void SettingsModel::setCaptureGain(float gain) {
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
mSimpleCaptureGraph->setCaptureGain(gain);
}
if((int)(oldGain *1000) != (int)(gain *1000))
emit captureGainChanged(gain);
if ((int)(oldGain * 1000) != (int)(gain * 1000)) emit captureGainChanged(gain);
}
QStringList SettingsModel::getCaptureDevices () const {
QStringList SettingsModel::getCaptureDevices() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
QStringList list;
@ -226,7 +220,7 @@ QStringList SettingsModel::getCaptureDevices () const {
return list;
}
QStringList SettingsModel::getPlaybackDevices () const {
QStringList SettingsModel::getPlaybackDevices() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
QStringList list;
@ -241,68 +235,64 @@ QStringList SettingsModel::getPlaybackDevices () const {
// -----------------------------------------------------------------------------
QString SettingsModel::getCaptureDevice () const {
QString SettingsModel::getCaptureDevice() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
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));
std::string devId = Utils::appStringToCoreString(device);
auto list = CoreModel::getInstance()->getCore()->getExtendedAudioDevices();
auto audioDevice = find_if(list.cbegin(), list.cend(), [&] ( const std::shared_ptr<linphone::AudioDevice> & audioItem) {
return audioItem->getId() == devId;
});
if(audioDevice != list.cend()){
auto audioDevice =
find_if(list.cbegin(), list.cend(),
[&](const std::shared_ptr<linphone::AudioDevice> &audioItem) { return audioItem->getId() == devId; });
if (audioDevice != list.cend()) {
CoreModel::getInstance()->getCore()->setCaptureDevice(devId);
CoreModel::getInstance()->getCore()->setInputAudioDevice(*audioDevice);
emit captureDeviceChanged(device);
resetCaptureGraph();
}else
qWarning() << "Cannot set Capture device. The ID cannot be matched with an existant device : " << device;
} else 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));
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));
std::string devId = Utils::appStringToCoreString(device);
auto list = CoreModel::getInstance()->getCore()->getExtendedAudioDevices();
auto audioDevice = find_if(list.cbegin(), list.cend(), [&] ( const std::shared_ptr<linphone::AudioDevice> & audioItem) {
return audioItem->getId() == devId;
});
if(audioDevice != list.cend()){
auto audioDevice =
find_if(list.cbegin(), list.cend(),
[&](const std::shared_ptr<linphone::AudioDevice> &audioItem) { return audioItem->getId() == devId; });
if (audioDevice != list.cend()) {
CoreModel::getInstance()->getCore()->setPlaybackDevice(devId);
CoreModel::getInstance()->getCore()->setOutputAudioDevice(*audioDevice);
emit playbackDeviceChanged(device);
resetCaptureGraph();
}else
qWarning() << "Cannot set Playback device. The ID cannot be matched with an existant device : " << device;
} else 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));
return Utils::coreStringToAppString(
CoreModel::getInstance()->getCore()->getRingerDevice()
);
return Utils::coreStringToAppString(CoreModel::getInstance()->getCore()->getRingerDevice());
}
void SettingsModel::setRingerDevice (const QString &device) {
void SettingsModel::setRingerDevice(const QString &device) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->setRingerDevice(
Utils::appStringToCoreString(device)
);
CoreModel::getInstance()->getCore()->setRingerDevice(Utils::appStringToCoreString(device));
emit ringerDeviceChanged(device);
}
@ -310,7 +300,7 @@ void SettingsModel::setRingerDevice (const QString &device) {
bool SettingsModel::getVideoEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return CoreModel::getInstance()->getCore()->videoEnabled();
return CoreModel::getInstance()->getCore()->videoEnabled();
}
void SettingsModel::setVideoEnabled(const bool enabled) {
@ -323,33 +313,33 @@ void SettingsModel::setVideoEnabled(const bool enabled) {
// -----------------------------------------------------------------------------
bool SettingsModel::getEchoCancellationEnabled () const {
bool SettingsModel::getEchoCancellationEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return CoreModel::getInstance()->getCore()->echoCancellationEnabled();
}
void SettingsModel::setEchoCancellationEnabled (bool status) {
void SettingsModel::setEchoCancellationEnabled(bool status) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->enableEchoCancellation(status);
emit echoCancellationEnabledChanged(status);
}
void SettingsModel::startEchoCancellerCalibration(){
void SettingsModel::startEchoCancellerCalibration() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->startEchoCancellerCalibration();
}
int SettingsModel::getEchoCancellationCalibration()const {
int SettingsModel::getEchoCancellationCalibration() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return CoreModel::getInstance()->getCore()->getEchoCancellationCalibration();
}
bool SettingsModel::getAutomaticallyRecordCallsEnabled () const {
bool SettingsModel::getAutomaticallyRecordCallsEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return !!mConfig->getInt(UiSection, "automatically_record_calls", 0);
}
void SettingsModel::setAutomaticallyRecordCallsEnabled (bool enabled) {
void SettingsModel::setAutomaticallyRecordCallsEnabled(bool enabled) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mConfig->setInt(UiSection, "automatically_record_calls", enabled);
emit automaticallyRecordCallsEnabledChanged(enabled);
@ -359,12 +349,12 @@ void SettingsModel::setAutomaticallyRecordCallsEnabled (bool enabled) {
// VFS.
// =============================================================================
bool SettingsModel::getVfsEnabled () const {
bool SettingsModel::getVfsEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return !!mConfig->getInt(UiSection, "vfs_enabled", 0);
}
void SettingsModel::setVfsEnabled (bool enabled) {
void SettingsModel::setVfsEnabled(bool enabled) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mConfig->setInt(UiSection, "vfs_enabled", enabled);
emit vfsEnabledChanged(enabled);
@ -374,69 +364,67 @@ void SettingsModel::setVfsEnabled (bool enabled) {
// Logs.
// =============================================================================
bool SettingsModel::getLogsEnabled () const {
bool SettingsModel::getLogsEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return getLogsEnabled(mConfig);
}
void SettingsModel::setLogsEnabled (bool status) {
void SettingsModel::setLogsEnabled(bool status) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mConfig->setInt(UiSection, "logs_enabled", status);
CoreModel::getInstance()->getLogger()->enable(status);
emit logsEnabledChanged(status);
}
bool SettingsModel::getFullLogsEnabled () const {
bool SettingsModel::getFullLogsEnabled() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return getFullLogsEnabled(mConfig);
}
void SettingsModel::setFullLogsEnabled (bool status) {
void SettingsModel::setFullLogsEnabled(bool status) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mConfig->setInt(UiSection, "full_logs_enabled", status);
CoreModel::getInstance()->getLogger()->enableFullLogs(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));
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));
return config ? config->getInt(UiSection, "full_logs_enabled", false) : false;
}
QString SettingsModel::getLogsFolder () const {
QString SettingsModel::getLogsFolder() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
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));
return config
? Utils::coreStringToAppString(config->getString(UiSection, "logs_folder", Utils::appStringToCoreString(Paths::getLogsDirPath())))
: Paths::getLogsDirPath();
return config ? Utils::coreStringToAppString(config->getString(
UiSection, "logs_folder", Utils::appStringToCoreString(Paths::getLogsDirPath())))
: Paths::getLogsDirPath();
}
void SettingsModel::cleanLogs () const {
void SettingsModel::cleanLogs() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->resetLogCollection();
}
void SettingsModel::sendLogs () const {
void SettingsModel::sendLogs() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
qInfo() << QStringLiteral("Send logs to: `%1` from `%2`.")
.arg(Utils::coreStringToAppString(core->getLogCollectionUploadServerUrl()))
.arg(Utils::coreStringToAppString(core->getLogCollectionPath()));
.arg(Utils::coreStringToAppString(core->getLogCollectionUploadServerUrl()))
.arg(Utils::coreStringToAppString(core->getLogCollectionPath()));
core->uploadLogCollection();
}
QString SettingsModel::getLogsEmail () const {
QString SettingsModel::getLogsEmail() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return Utils::coreStringToAppString(
mConfig->getString(UiSection, "logs_email", Constants::DefaultLogsEmail)
);
return Utils::coreStringToAppString(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 VersionCheckReleaseUrl[] = "https://linphone.org/releases";
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 PrivatePolicyUrl[] = "https://www.linphone.org/privacy-policy";
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);
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 {
VideoSourceScreenSharingTypeArea = int(linphone::VideoSourceScreenSharingType::Area),
VideoSourceScreenSharingTypeDisplay = int(linphone::VideoSourceScreenSharingType::Display),

View file

@ -374,6 +374,11 @@ bool Utils::copyToClipboard(const QString &text) {
return !clipboardText.isEmpty();
}
QString Utils::getClipboardText() {
QClipboard *clipboard = QApplication::clipboard();
return clipboard->text();
}
QString Utils::getApplicationProduct() {
// Note: Keep '-' as a separator between application name and application type
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 int getRandomIndex(int size);
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(QDate date, const QString &format = "");
Q_INVOKABLE static QString toDateDayString(const QDateTime &date);

View file

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

View file

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

View file

@ -92,8 +92,17 @@ AppWindow {
id: registerPage
RegisterPage {
onReturnToLogin: mainWindowStackView.replace(loginPage)
onRegisterCalled: (countryCode, phoneNumber, email) => {
mainWindowStackView.push(checkingPage, {"phoneNumber": phoneNumber, "email": email})
onBrowserValidationRequested: mainWindow.showLoadingPopup(qsTr("Veuillez valider le captcha sur la page web"), true)
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
RegisterCheckingPage {
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 {

View file

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

View file

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

View file

@ -2,7 +2,7 @@ import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Control
import Linphone
import ConstantsCpp 1.0
ColumnLayout {
id: mainItem
@ -148,7 +148,7 @@ ColumnLayout {
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 {
id: mainItem
property string text
property bool cancelButtonVisible: false
modal: true
closePolicy: Control.Popup.NoAutoClose
anchors.centerIn: parent
@ -15,6 +16,8 @@ Popup {
// onAboutToShow: width = contentText.implicitWidth
contentItem: ColumnLayout {
spacing: 15 * DefaultStyle.dp
// width: childrenRect.width
// height: childrenRect.height
BusyIndicator{
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 33 * DefaultStyle.dp
@ -28,5 +31,11 @@ Popup {
text: mainItem.text
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 {
id: mainItem
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 bool enableBackgroundColors: false
@ -101,7 +101,7 @@ ColumnLayout {
id: listPopup
y: combobox.height - 1
width: 311 * DefaultStyle.dp
height: 198 * DefaultStyle.dp
height: 250 * DefaultStyle.dp
contentItem: ListView {
id: listView
@ -109,7 +109,9 @@ ColumnLayout {
anchors.fill: parent
model: PhoneNumberProxy{}
currentIndex: combobox.highlightedIndex >= 0 ? combobox.highlightedIndex : 0
highlightFollowsCurrentItem: true
keyNavigationEnabled: true
keyNavigationWraps: true
maximumFlickVelocity: 1500
highlight: Rectangle {
anchors.left: parent.left
anchors.right: parent.right
@ -177,7 +179,7 @@ ColumnLayout {
color: DefaultStyle.main2_500main
visible: parent.containsMouse
}
onPressed: {
onClicked: {
combobox.currentIndex = index
listPopup.close()
}

View file

@ -7,13 +7,15 @@ ColumnLayout {
id: mainItem
property string label: ""
property string errorMessage: ""
property alias errorMessage: errorText.text
property string placeholderText : ""
property bool mandatory: false
property bool enableErrorText: true
property int textInputWidth: width
property string initialPhoneNumber
readonly property string phoneNumber: textField.text
readonly property string countryCode: combobox.currentText
property string defaultCallingCode
Text {
visible: label.length > 0
@ -26,52 +28,60 @@ ColumnLayout {
}
}
Rectangle {
Layout.preferredWidth: mainItem.textInputWidth
Layout.preferredHeight: 49 * DefaultStyle.dp
radius: 63 * DefaultStyle.dp
color: DefaultStyle.grey_100
border.color: mainItem.errorMessage.length > 0
? DefaultStyle.danger_500main
: (textField.hasActiveFocus || combobox.hasActiveFocus)
? DefaultStyle.main1_500_main
: DefaultStyle.grey_200
RowLayout {
anchors.fill: parent
PhoneNumberComboBox {
id: combobox
implicitWidth: 110 * DefaultStyle.dp
}
Rectangle {
Layout.preferredWidth: 1 * DefaultStyle.dp
Layout.fillHeight: true
Layout.topMargin: 10 * DefaultStyle.dp
Layout.bottomMargin: 10 * DefaultStyle.dp
color: DefaultStyle.main2_600
}
TextField {
id: textField
Layout.fillWidth: true
placeholderText: mainItem.placeholderText
background: Item{}
initialText: initialPhoneNumber
validator: RegularExpressionValidator{ regularExpression: /[0-9]+/}
Item {
Layout.preferredWidth: contentBackground.width
Layout.preferredHeight: contentBackground.height
Rectangle {
id: contentBackground
width: mainItem.textInputWidth
height: 49 * DefaultStyle.dp
radius: 63 * DefaultStyle.dp
color: DefaultStyle.grey_100
border.color: mainItem.errorMessage.length > 0
? DefaultStyle.danger_500main
: (textField.hasActiveFocus || combobox.hasActiveFocus)
? DefaultStyle.main1_500_main
: DefaultStyle.grey_200
RowLayout {
anchors.fill: parent
PhoneNumberComboBox {
id: combobox
implicitWidth: 110 * DefaultStyle.dp
defaultCallingCode: mainItem.defaultCallingCode
}
Rectangle {
Layout.preferredWidth: 1 * DefaultStyle.dp
Layout.fillHeight: true
Layout.topMargin: 10 * DefaultStyle.dp
Layout.bottomMargin: 10 * DefaultStyle.dp
color: DefaultStyle.main2_600
}
TextField {
id: textField
Layout.fillWidth: true
placeholderText: mainItem.placeholderText
background: Item{}
initialText: initialPhoneNumber
validator: RegularExpressionValidator{ regularExpression: /[0-9]+/}
}
}
}
}
Text {
visible: mainItem.errorMessage.length > 0
verticalAlignment: Text.AlignVCenter
text: mainItem.errorMessage
color: DefaultStyle.danger_500main
elide: Text.ElideRight
wrapMode: Text.Wrap
font {
pixelSize: 13 * DefaultStyle.dp
family: DefaultStyle.defaultFont
bold: true
ErrorText {
id: errorText
anchors.top: contentBackground.bottom
// visible: mainItem.enableErrorText
text: mainItem.errorMessage
color: DefaultStyle.danger_500main
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
wrapMode: Text.Wrap
font {
pixelSize: 13 * DefaultStyle.dp
family: DefaultStyle.defaultFont
bold: true
}
Layout.preferredWidth: mainItem.textInputWidth
// Layout.preferredWidth: implicitWidth
}
Layout.preferredWidth: mainItem.textInputWidth
}
}

View file

@ -86,7 +86,7 @@ Control.TextField {
}
}
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) {
enterPressed()
if (mainItem.controlIsDown) {

View file

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

View file

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

View file

@ -6,9 +6,11 @@ import Linphone
LoginLayout {
id: mainItem
signal returnToRegister()
property string phoneNumber
property string email
signal sendCode(string code)
property bool registerWithEmail
property string address
property string sipIdentityAddress
property string code
titleContent: [
RowLayout {
spacing: 21 * DefaultStyle.dp
@ -34,7 +36,7 @@ LoginLayout {
Text {
wrapMode: Text.NoWrap
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
}
font {
@ -64,7 +66,7 @@ LoginLayout {
}
color: DefaultStyle.main2_700
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:"
}
}
@ -78,10 +80,12 @@ LoginLayout {
Layout.preferredHeight: height
onTextEdited: {
if (text.length > 0 ) {
mainItem.code = mainItem.code.slice(0, index) + text + mainItem.code.slice(index)
if (index < 3)
nextItemInFocusChain(true).forceActiveFocus()
else {
// TODO : validate()
mainItem.sendCode(mainItem.code)
mainItem.code = ""
}
} else {
if (index > 0)

View file

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

View file

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