Prepare Async objects for Linphone tools to be used from GUI.

Fix AccountManager for missing sdk listening.
Fix login : custom parameters were missing.
This commit is contained in:
Julien Wadel 2023-11-08 09:58:52 +00:00
parent 053d0bcacc
commit 46e91b46a8
14 changed files with 280 additions and 14 deletions

View file

@ -21,7 +21,7 @@ set(APP_TARGETS ${LinphoneCxx_TARGET})
set(QT_DEFAULT_MAJOR_VERSION 6) set(QT_DEFAULT_MAJOR_VERSION 6)
set(QT_PACKAGES Core Quick Qml Widgets Svg Multimedia)# Search Core at first for initialize Qt scripts for next find_packages. set(QT_PACKAGES Core Quick Qml Widgets Svg Multimedia Test)# Search Core at first for initialize Qt scripts for next find_packages.
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
list(APPEND QT_PACKAGES DBus) list(APPEND QT_PACKAGES DBus)
endif() endif()

View file

@ -33,7 +33,9 @@
#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/singleapplication/singleapplication.h" #include "core/singleapplication/singleapplication.h"
#include "model/object/VariantObject.hpp"
#include "tool/Constants.hpp" #include "tool/Constants.hpp"
#include "tool/Utils.hpp"
#include "tool/thread/Thread.hpp" #include "tool/thread/Thread.hpp"
#include "tool/providers/ImageProvider.hpp" #include "tool/providers/ImageProvider.hpp"
@ -99,8 +101,12 @@ void App::initCppInterfaces() {
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); });
qmlRegisterSingletonType<Utils>("UtilsCpp", 1, 0, "UtilsCpp",
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Utils(engine); });
qmlRegisterType<PhoneNumberProxy>(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy"); qmlRegisterType<PhoneNumberProxy>(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy");
qmlRegisterType<VariantObject>(Constants::MainQmlUri, 1, 0, "VariantObject");
qmlRegisterUncreatableType<PhoneNumber>(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable")); qmlRegisterUncreatableType<PhoneNumber>(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable"));
qmlRegisterType<AccountProxy>(Constants::MainQmlUri, 1, 0, "AccountProxy"); qmlRegisterType<AccountProxy>(Constants::MainQmlUri, 1, 0, "AccountProxy");
qmlRegisterUncreatableType<Account>(Constants::MainQmlUri, 1, 0, "Account", QLatin1String("Uncreatable")); qmlRegisterUncreatableType<Account>(Constants::MainQmlUri, 1, 0, "Account", QLatin1String("Uncreatable"));

View file

@ -42,12 +42,19 @@ public:
static auto postModelAsync(Func &&callable) { static auto postModelAsync(Func &&callable) {
QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable); QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable);
} }
template <typename Func> template <typename Func, typename... Args>
static auto postModelSync(Func &&callable) { static auto postModelSync(Func &&callable, Args &&...args) {
QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable, if (QThread::currentThread() != CoreModel::getInstance()->thread()) {
QThread::currentThread() != CoreModel::getInstance()->thread() bool end = false;
? Qt::BlockingQueuedConnection postModelAsync([&end, callable, args...]() mutable {
: Qt::DirectConnection); QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable, args..., Qt::DirectConnection);
end = true;
});
while (!end)
qApp->processEvents();
} else {
QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable, Qt::DirectConnection);
}
} }
void clean(); void clean();

View file

@ -10,7 +10,11 @@ list(APPEND _LINPHONEAPP_SOURCES
model/logger/LoggerModel.cpp model/logger/LoggerModel.cpp
model/logger/LoggerListener.cpp model/logger/LoggerListener.cpp
model/object/VariantObject.cpp
model/setting/SettingsModel.cpp model/setting/SettingsModel.cpp
model/tool/ToolModel.cpp
) )
set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE) set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)

View file

@ -65,6 +65,8 @@ bool AccountManager::login(QString username, QString password) {
.arg(Utils::coreStringToAppString(identity->asStringUriOnly())); .arg(Utils::coreStringToAppString(identity->asStringUriOnly()));
return false; return false;
} }
account->setParams(params);
core->addAuthInfo(factory->createAuthInfo(Utils::appStringToCoreString(username), // Username. core->addAuthInfo(factory->createAuthInfo(Utils::appStringToCoreString(username), // Username.
"", // User ID. "", // User ID.
Utils::appStringToCoreString(password), // Password. Utils::appStringToCoreString(password), // Password.
@ -73,6 +75,7 @@ bool AccountManager::login(QString username, QString password) {
identity->getDomain() // Domain. identity->getDomain() // Domain.
)); ));
mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); mAccountModel = Utils::makeQObject_ptr<AccountModel>(account);
mAccountModel->setSelf(mAccountModel);
connect(mAccountModel.get(), &AccountModel::registrationStateChanged, this, connect(mAccountModel.get(), &AccountModel::registrationStateChanged, this,
&AccountManager::onRegistrationStateChanged); &AccountManager::onRegistrationStateChanged);
core->addAccount(account); core->addAccount(account);

View file

@ -35,9 +35,9 @@
class CoreModel : public QObject { class CoreModel : public QObject {
Q_OBJECT Q_OBJECT
public: public:
CoreModel(const QString &configPath, QThread * parent); CoreModel(const QString &configPath, QThread *parent);
~CoreModel(); ~CoreModel();
static QSharedPointer<CoreModel> create(const QString &configPath, QThread * parent); static QSharedPointer<CoreModel> create(const QString &configPath, QThread *parent);
static QSharedPointer<CoreModel> getInstance(); static QSharedPointer<CoreModel> getInstance();
std::shared_ptr<linphone::Core> getCore(); std::shared_ptr<linphone::Core> getCore();
@ -45,7 +45,6 @@ public:
void start(); void start();
void setConfigPath(QString path); void setConfigPath(QString path);
bool mEnd = false; bool mEnd = false;
std::shared_ptr<linphone::Core> mCore; std::shared_ptr<linphone::Core> mCore;
@ -53,6 +52,7 @@ public:
signals: signals:
void loggerInitialized(); void loggerInitialized();
private: private:
QString mConfigPath; QString mConfigPath;
QTimer *mIterateTimer = nullptr; QTimer *mIterateTimer = nullptr;

View file

@ -58,7 +58,7 @@ public:
protected: protected:
std::shared_ptr<LinphoneClass> mMonitor; std::shared_ptr<LinphoneClass> mMonitor;
std::shared_ptr<ListenerClass> mSelf; std::shared_ptr<ListenerClass> mSelf = nullptr;
}; };
#endif #endif

View file

@ -0,0 +1,55 @@
/*
* 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 "VariantObject.hpp"
#include <QDebug>
#include <QTest>
DEFINE_ABSTRACT_OBJECT(VariantObject)
VariantObject::VariantObject(QObject *parent) {
mustBeInMainThread(getClassName());
}
VariantObject::VariantObject(QVariant value, QObject *parent) : mValue(value) {
mustBeInMainThread(getClassName());
connect(this, &VariantObject::updateValue, this, &VariantObject::setValue);
mCoreObject = new VariantObject();
connect(mCoreObject, &VariantObject::valueChanged, this, &VariantObject::setValue);
connect(mCoreObject, &VariantObject::valueChanged, mCoreObject, &QObject::deleteLater);
}
VariantObject::~VariantObject() {
mustBeInMainThread("~" + getClassName());
}
QVariant VariantObject::getValue() const {
mustBeInMainThread(QString(gClassName) + " : " + Q_FUNC_INFO);
return mValue;
}
void VariantObject::setValue(QVariant value) {
mustBeInMainThread(QString(gClassName) + " : " + Q_FUNC_INFO);
if (value != mValue) {
mValue = value;
emit valueChanged(mValue);
}
}

View file

@ -0,0 +1,56 @@
/*
* 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 VARIANT_OBJECT_H_
#define VARIANT_OBJECT_H_
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <QVariant>
// Store the VariantObject on a propery and use value.
// Do not use direcly teh value like VariantObject.value : in this case if value change, VariantObject will be
// reevaluated.
class VariantObject : public QObject, public AbstractObject {
Q_OBJECT
public:
Q_PROPERTY(QVariant value READ getValue WRITE setValue NOTIFY valueChanged)
VariantObject(QObject *parent = nullptr);
VariantObject(QVariant value, QObject *parent = nullptr);
~VariantObject();
QVariant getValue() const;
void setValue(QVariant value);
VariantObject *mCoreObject; // Ensure to use DeleteLater() after updating value
signals:
void valueChanged(QVariant value);
void updateValue(QVariant value);
private:
QVariant mValue;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -0,0 +1,69 @@
/*
* 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 "ToolModel.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
#include <QDebug>
#include <QTest>
DEFINE_ABSTRACT_OBJECT(ToolModel)
ToolModel::ToolModel(QObject *parent) {
}
ToolModel::~ToolModel() {
}
std::shared_ptr<linphone::Address> ToolModel::interpretUrl(const QString &address) {
bool usePrefix = false; // TODO
// CoreManager::getInstance()->getAccountSettingsModel()->getUseInternationalPrefixForCallsAndChats();
auto interpretedAddress =
CoreModel::getInstance()->getCore()->interpretUrl(Utils::appStringToCoreString(address), usePrefix);
if (!interpretedAddress) { // Try by removing scheme.
QStringList splitted = address.split(":");
if (splitted.size() > 0 && splitted[0] == "sip") {
splitted.removeFirst();
interpretedAddress = CoreModel::getInstance()->getCore()->interpretUrl(
Utils::appStringToCoreString(splitted.join(":")), usePrefix);
}
}
return interpretedAddress;
}
QString ToolModel::getDisplayName(const std::shared_ptr<const linphone::Address> &address) {
QString displayName;
if (address) {
displayName = Utils::coreStringToAppString(address->getDisplayName());
// TODO
// std::shared_ptr<linphone::Address> cleanAddress = address->clone();
// cleanAddress->clean();
// QString qtAddress = Utils::coreStringToAppString(cleanAddress->asStringUriOnly());
// auto sipAddressEntry = getSipAddressEntry(qtAddress, cleanAddress);
// displayName = sipAddressEntry->displayNames.get();
}
return displayName;
}
QString ToolModel::getDisplayName(QString address) {
mustBeInLinphoneThread(QString(gClassName) + " : " + Q_FUNC_INFO);
QString displayName = getDisplayName(interpretUrl(address));
return displayName.isEmpty() ? address : displayName;
}

View file

@ -0,0 +1,44 @@
/*
* 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 TOOL_MODEL_H_
#define TOOL_MODEL_H_
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <linphone++/linphone.hh>
class ToolModel : public QObject, public AbstractObject {
Q_OBJECT
public:
ToolModel(QObject *parent = nullptr);
~ToolModel();
static std::shared_ptr<linphone::Address> interpretUrl(const QString &address);
static QString getDisplayName(const std::shared_ptr<const linphone::Address> &address);
static QString getDisplayName(QString address);
private:
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -20,6 +20,10 @@
#include "Utils.hpp" #include "Utils.hpp"
#include "core/App.hpp"
#include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp"
// ============================================================================= // =============================================================================
char *Utils::rstrstr(const char *a, const char *b) { char *Utils::rstrstr(const char *a, const char *b) {
@ -34,3 +38,12 @@ char *Utils::rstrstr(const char *a, const char *b) {
return nullptr; return nullptr;
} }
VariantObject *Utils::getDisplayName(const QString &address) {
VariantObject *data = new VariantObject(address); // Scope : GUI
App::postModelAsync([coreObject = data->mCoreObject, address]() mutable {
QString displayName = ToolModel::getDisplayName(address);
emit coreObject->valueChanged(displayName);
});
return data;
}

View file

@ -40,12 +40,16 @@
#endif // if defined(__GNUC__) && __GNUC__ >= 7 #endif // if defined(__GNUC__) && __GNUC__ >= 7
#endif // ifndef UTILS_NO_BREAK #endif // ifndef UTILS_NO_BREAK
class VariantObject;
class Utils : public QObject { class Utils : public QObject {
Q_OBJECT Q_OBJECT
public: public:
Utils(QObject *parent = nullptr) : QObject(parent) { Utils(QObject *parent = nullptr) : QObject(parent) {
} }
Q_INVOKABLE static VariantObject *getDisplayName(const QString &address);
static inline QString coreStringToAppString(const std::string &str) { static inline QString coreStringToAppString(const std::string &str) {
if (Constants::LinphoneLocaleEncoding == QString("UTF-8")) return QString::fromStdString(str); if (Constants::LinphoneLocaleEncoding == QString("UTF-8")) return QString::fromStdString(str);
else else

View file

@ -2,6 +2,8 @@ import QtQuick 2.15
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.0
import QtQuick.Controls as Control import QtQuick.Controls as Control
import Linphone import Linphone
import UtilsCpp 1.0
// Snippet // Snippet
ListView{ ListView{
@ -34,7 +36,10 @@ ListView{
} }
} }
Text{ Text{
text: $modelData.identityAddress // Store the VariantObject and use value on this object. Do not use value in one line because of looping signals.
property var displayName: UtilsCpp.getDisplayName($modelData.identityAddress)
text: displayName.value
onTextChanged: console.log('[ProtoAccounts] Async account displayName: ' +$modelData.identityAddress + " => " +text)
} }
Text{ Text{
text: $modelData.registrationState == LinphoneEnums.RegistrationState.Ok text: $modelData.registrationState == LinphoneEnums.RegistrationState.Ok