From 680d398c36e549800cd27f99c808dfb8273ca801 Mon Sep 17 00:00:00 2001 From: Gaelle Braud Date: Mon, 26 Aug 2024 12:16:02 +0200 Subject: [PATCH] account device list --- Linphone/core/App.cpp | 2 + Linphone/core/CMakeLists.txt | 2 + Linphone/core/account/AccountDeviceCore.cpp | 15 +- Linphone/core/account/AccountDeviceCore.hpp | 17 +- Linphone/core/account/AccountDeviceList.cpp | 189 ++++++++++++++++++ Linphone/core/account/AccountDeviceList.hpp | 72 +++++++ Linphone/core/account/AccountDeviceProxy.cpp | 71 +++++++ Linphone/core/account/AccountDeviceProxy.hpp | 63 ++++++ Linphone/core/account/AccountProxy.cpp | 4 +- Linphone/core/account/AccountProxy.hpp | 2 +- .../participant/ParticipantDeviceList.cpp | 2 +- Linphone/model/CMakeLists.txt | 1 + Linphone/model/account/AccountDeviceModel.cpp | 40 ++++ Linphone/model/account/AccountDeviceModel.hpp | 44 ++++ Linphone/model/account/AccountManager.cpp | 4 +- Linphone/model/account/AccountManager.hpp | 2 +- .../account/AccountManagerServicesModel.cpp | 13 +- .../account/AccountManagerServicesModel.hpp | 3 + Linphone/view/App/AppWindow.qml | 4 +- .../Account/AccountSettingsGeneralLayout.qml | 61 +++--- 20 files changed, 558 insertions(+), 53 deletions(-) create mode 100644 Linphone/core/account/AccountDeviceList.cpp create mode 100644 Linphone/core/account/AccountDeviceList.hpp create mode 100644 Linphone/core/account/AccountDeviceProxy.cpp create mode 100644 Linphone/core/account/AccountDeviceProxy.hpp create mode 100644 Linphone/model/account/AccountDeviceModel.cpp create mode 100644 Linphone/model/account/AccountDeviceModel.hpp diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index 49ce1c3f9..cfa0b2fee 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -37,6 +37,7 @@ #include "core/account/AccountCore.hpp" #include "core/account/AccountDeviceGui.hpp" +#include "core/account/AccountDeviceProxy.hpp" #include "core/account/AccountProxy.hpp" #include "core/call-history/CallHistoryProxy.hpp" #include "core/call/CallCore.hpp" @@ -365,6 +366,7 @@ void App::initCppInterfaces() { qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable")); qmlRegisterType(Constants::MainQmlUri, 1, 0, "AccountProxy"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "AccountGui"); + qmlRegisterType(Constants::MainQmlUri, 1, 0, "AccountDeviceProxy"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "AccountDeviceGui"); qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "AccountCore", QLatin1String("Uncreatable")); qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "CallCore", QLatin1String("Uncreatable")); diff --git a/Linphone/core/CMakeLists.txt b/Linphone/core/CMakeLists.txt index 1c9ef5b87..cf3b50378 100644 --- a/Linphone/core/CMakeLists.txt +++ b/Linphone/core/CMakeLists.txt @@ -5,6 +5,8 @@ list(APPEND _LINPHONEAPP_SOURCES core/account/AccountProxy.cpp core/account/AccountDeviceCore.cpp core/account/AccountDeviceGui.cpp + core/account/AccountDeviceList.cpp + core/account/AccountDeviceProxy.cpp core/App.cpp core/call/CallCore.cpp core/call/CallGui.cpp diff --git a/Linphone/core/account/AccountDeviceCore.cpp b/Linphone/core/account/AccountDeviceCore.cpp index c50b36e2e..2d9e181b5 100644 --- a/Linphone/core/account/AccountDeviceCore.cpp +++ b/Linphone/core/account/AccountDeviceCore.cpp @@ -28,19 +28,20 @@ DEFINE_ABSTRACT_OBJECT(AccountDeviceCore) AccountDeviceCore::AccountDeviceCore(QString name, QString userAgent, QDateTime last) : QObject(nullptr) { App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); mustBeInLinphoneThread(getClassName()); - + mDeviceName = name; mUserAgent = userAgent; mLastUpdateTimestamp = last; } QSharedPointer AccountDeviceCore::createDummy(QString name, QString userAgent, QDateTime last) { - auto core = QSharedPointer(new AccountDeviceCore(name,userAgent,last)); + auto core = QSharedPointer(new AccountDeviceCore(name, userAgent, last)); core->moveToThread(App::getInstance()->thread()); return core; } QSharedPointer AccountDeviceCore::create(const std::shared_ptr &device) { + mustBeInLinphoneThread(Q_FUNC_INFO); auto core = QSharedPointer(new AccountDeviceCore(device)); core->moveToThread(App::getInstance()->thread()); return core; @@ -49,9 +50,9 @@ QSharedPointer AccountDeviceCore::create(const std::shared_pt AccountDeviceCore::AccountDeviceCore(const std::shared_ptr &device) : QObject(nullptr) { App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); mustBeInLinphoneThread(getClassName()); - + mAccountDeviceModel = Utils::makeQObject_ptr(device); mDeviceName = Utils::coreStringToAppString(device->getName()); - mUserAgent = Utils::coreStringToAppString(device->getUserAgent()); + mUserAgent = Utils::coreStringToAppString(device->getUserAgent()); mLastUpdateTimestamp = QDateTime::fromSecsSinceEpoch(device->getLastUpdateTimestamp()); } @@ -59,6 +60,6 @@ AccountDeviceCore::~AccountDeviceCore() { mustBeInMainThread("~" + getClassName()); } -void AccountDeviceCore::removeDevice() { - // TODO (core thread) -} +const std::shared_ptr &AccountDeviceCore::getModel() const { + return mAccountDeviceModel; +} \ No newline at end of file diff --git a/Linphone/core/account/AccountDeviceCore.hpp b/Linphone/core/account/AccountDeviceCore.hpp index 062b558d9..a47253dd8 100644 --- a/Linphone/core/account/AccountDeviceCore.hpp +++ b/Linphone/core/account/AccountDeviceCore.hpp @@ -21,10 +21,11 @@ #ifndef ACCOUNT_DEVICE_CORE_H_ #define ACCOUNT_DEVICE_CORE_H_ +#include "model/account/AccountDeviceModel.hpp" +#include "tool/AbstractObject.hpp" +#include #include #include -#include -#include "tool/AbstractObject.hpp" #include class AccountDeviceCore : public QObject, public AbstractObject { @@ -35,24 +36,22 @@ class AccountDeviceCore : public QObject, public AbstractObject { Q_PROPERTY(QDateTime lastUpdateTimestamp MEMBER mLastUpdateTimestamp CONSTANT) public: - static QSharedPointer create(const std::shared_ptr &device); AccountDeviceCore(const std::shared_ptr &device); AccountDeviceCore(QString name, QString userAgent, QDateTime last); static QSharedPointer createDummy(QString name, QString userAgent, QDateTime last); - - - + ~AccountDeviceCore(); - Q_INVOKABLE void removeDevice(); + + const std::shared_ptr &getModel() const; private: QString mDeviceName; QString mUserAgent; QDateTime mLastUpdateTimestamp; - + std::shared_ptr mAccountDeviceModel; + DECLARE_ABSTRACT_OBJECT - }; #endif diff --git a/Linphone/core/account/AccountDeviceList.cpp b/Linphone/core/account/AccountDeviceList.cpp new file mode 100644 index 000000000..dcb89010b --- /dev/null +++ b/Linphone/core/account/AccountDeviceList.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 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 . + */ + +#include "AccountDeviceList.hpp" +#include "core/App.hpp" +#include "core/account/AccountDeviceGui.hpp" +#include "tool/Utils.hpp" + +#include +#include + +DEFINE_ABSTRACT_OBJECT(AccountDeviceList) + +QSharedPointer AccountDeviceList::create() { + auto model = QSharedPointer(new AccountDeviceList(), &QObject::deleteLater); + model->moveToThread(App::getInstance()->thread()); + model->setSelf(model); + return model; +} + +QSharedPointer AccountDeviceList::create(const std::shared_ptr &accountModel) { + auto model = create(); + model->setAccountModel(accountModel); + return model; +} + +AccountDeviceList::AccountDeviceList() { + App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +AccountDeviceList::~AccountDeviceList() { +} + +QList> +AccountDeviceList::buildDevices(const std::list> &devicesList) { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + QList> devices; + for (auto &device : devicesList) { + auto deviceCore = AccountDeviceCore::create(device); + devices << deviceCore; + } + return devices; +} + +const std::shared_ptr &AccountDeviceList::getAccountModel() const { + return mAccountModel; +} + +void AccountDeviceList::setAccountModel(const std::shared_ptr &accountModel) { + mustBeInMainThread(log().arg(Q_FUNC_INFO)); + if (mAccountModel != accountModel) { + mAccountModel = accountModel; + lDebug() << log().arg("Set account model") << mAccountModel.get(); + // oldConnect.unlock(); + refreshDevices(); + // } + } +} + +void AccountDeviceList::refreshDevices() { + mustBeInMainThread(log().arg(Q_FUNC_INFO)); + beginResetModel(); + clearData(); + endResetModel(); + if (mAccountModel) { + auto requestDeviceList = [this] { + if (!mAccountManagerServicesModelConnection) return; + mAccountManagerServicesModelConnection->invokeToModel([this]() { + auto identityAddress = mAccountModel->getMonitor()->getParams()->getIdentityAddress(); + auto authinfo = mAccountModel->getMonitor()->findAuthInfo(); + qDebug() << "[AccountDeviceList] request devices for address" << identityAddress->asStringUriOnly(); + mAccountManagerServicesModel->getDeviceList(identityAddress); + }); + }; + if (mIsComponentReady) { + requestDeviceList(); + } else { + connect(this, &AccountDeviceList::componentReady, this, requestDeviceList, Qt::SingleShotConnection); + } + } +} + +void AccountDeviceList::setDevices(QList> devices) { + mustBeInMainThread(log().arg(Q_FUNC_INFO)); + add(devices); + lDebug() << log().arg("Add %1 devices").arg(devices.size()); +} + +void AccountDeviceList::deleteDevice(AccountDeviceGui *deviceGui) { + auto requestDeviceDeletion = [this, deviceGui] { + if (!mAccountManagerServicesModelConnection) return; + auto deviceCore = deviceGui->getCore(); + auto deviceModel = deviceCore->getModel(); + mAccountManagerServicesModelConnection->invokeToModel([this, deviceModel]() { + auto linphoneDevice = deviceModel->getDevice(); + auto identityAddress = mAccountModel->getMonitor()->getParams()->getIdentityAddress(); + auto authinfo = mAccountModel->getMonitor()->findAuthInfo(); + qDebug() << "[AccountDeviceList] delete device" << linphoneDevice->getName() << "of address" + << identityAddress->asStringUriOnly(); + mAccountManagerServicesModel->deleteDevice(identityAddress, linphoneDevice); + }); + }; + if (mIsComponentReady) { + requestDeviceDeletion(); + } else { + connect(this, &AccountDeviceList::componentReady, this, requestDeviceDeletion); + } +} + +void AccountDeviceList::setSelf(QSharedPointer me) { + if (mCoreModelConnection) mCoreModelConnection->disconnect(); + mCoreModelConnection = QSharedPointer>( + new SafeConnection(me, CoreModel::getInstance()), &QObject::deleteLater); + mCoreModelConnection->invokeToModel([=] { + auto core = CoreModel::getInstance()->getCore(); + auto ams = core->createAccountManagerServices(); + auto amsModel = Utils::makeQObject_ptr(ams); + mCoreModelConnection->invokeToCore([this, amsModel, me]() { + mAccountManagerServicesModel = amsModel; + if (mAccountManagerServicesModelConnection) mAccountManagerServicesModelConnection->disconnect(); + mAccountManagerServicesModelConnection = + QSharedPointer>( + new SafeConnection(me, + mAccountManagerServicesModel), + &QObject::deleteLater); + mAccountManagerServicesModelConnection->makeConnectToModel( + &AccountManagerServicesModel::requestSuccessfull, + [this](const std::shared_ptr &request, + const std::string &data) { + if (request->getType() == linphone::AccountManagerServicesRequest::Type::DeleteDevice) { + mAccountManagerServicesModelConnection->invokeToCore([this] { refreshDevices(); }); + } + }); + mAccountManagerServicesModelConnection->makeConnectToModel( + &AccountManagerServicesModel::requestError, + [this](const std::shared_ptr &request, int statusCode, + const std::string &errorMessage, + const std::shared_ptr ¶meterErrors) { + lDebug() << "REQUEST ERROR" << errorMessage; + if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) { + } + }); + mAccountManagerServicesModelConnection->makeConnectToModel( + &AccountManagerServicesModel::devicesListFetched, + [this](const std::shared_ptr &request, + const std::list> &devicesList) { + mAccountManagerServicesModelConnection->invokeToModel([this, request, devicesList]() { + if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) { + QList> devices; + for (auto &device : devicesList) { + auto deviceCore = AccountDeviceCore::create(device); + devices << deviceCore; + } + // auto devices = buildDevices(devicesList); + mAccountManagerServicesModelConnection->invokeToCore( + [this, devices]() { setDevices(devices); }); + } + }); + }); + mIsComponentReady = true; + emit componentReady(); + }); + }); +} + +QVariant AccountDeviceList::data(const QModelIndex &index, int role) const { + int row = index.row(); + if (!index.isValid() || row < 0 || row >= rowCount()) return QVariant(); + if (role == Qt::DisplayRole) + return QVariant::fromValue(new AccountDeviceGui(mList[row].objectCast())); + return QVariant(); +} diff --git a/Linphone/core/account/AccountDeviceList.hpp b/Linphone/core/account/AccountDeviceList.hpp new file mode 100644 index 000000000..98a2dba69 --- /dev/null +++ b/Linphone/core/account/AccountDeviceList.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 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 . + */ + +#ifndef ACCOUNT_DEVICE_LIST_H_ +#define ACCOUNT_DEVICE_LIST_H_ + +#include "../proxy/ListProxy.hpp" +#include "AccountDeviceCore.hpp" +#include "core/account/AccountGui.hpp" +#include "model/account/AccountManagerServicesModel.hpp" +#include "model/account/AccountModel.hpp" +#include "tool/AbstractObject.hpp" +#include "tool/thread/SafeConnection.hpp" + +class AccountDeviceGui; +class AccountDeviceList : public ListProxy, public AbstractObject { + Q_OBJECT + +public: + static QSharedPointer create(); + static QSharedPointer create(const std::shared_ptr &accountModel); + + AccountDeviceList(); + ~AccountDeviceList(); + + QList> + buildDevices(const std::list> &devicesList); + + const std::shared_ptr &getAccountModel() const; + void setAccountModel(const std::shared_ptr &accountModel); + void refreshDevices(); + + void setDevices(QList> devices); + void deleteDevice(AccountDeviceGui *deviceGui); + + void setSelf(QSharedPointer me); + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +signals: + void componentReady(); + +private: + std::shared_ptr mAccountModel; + std::shared_ptr mAccountManagerServicesModel; + QSharedPointer> + mAccountManagerServicesModelConnection; + QSharedPointer> mCoreModelConnection; + bool mIsComponentReady = false; + + DECLARE_ABSTRACT_OBJECT +}; +Q_DECLARE_METATYPE(QSharedPointer); + +#endif // ACCOUNT_DEVICE_LIST_H_ diff --git a/Linphone/core/account/AccountDeviceProxy.cpp b/Linphone/core/account/AccountDeviceProxy.cpp new file mode 100644 index 000000000..ccec35f8c --- /dev/null +++ b/Linphone/core/account/AccountDeviceProxy.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 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 . + */ + +#include "AccountDeviceProxy.hpp" +#include "AccountDeviceList.hpp" +#include "core/App.hpp" +#include "tool/Utils.hpp" + +#include + +// ============================================================================= + +DEFINE_ABSTRACT_OBJECT(AccountDeviceProxy) +DEFINE_GUI_OBJECT(AccountDeviceProxy) + +AccountDeviceProxy::AccountDeviceProxy(QObject *parent) : SortFilterProxy(parent) { + mAccountDeviceList = AccountDeviceList::create(); + setSourceModel(mAccountDeviceList.get()); + sort(0); //, Qt::DescendingOrder); +} + +AccountDeviceProxy::~AccountDeviceProxy() { + setSourceModel(nullptr); +} + +AccountGui *AccountDeviceProxy::getAccount() const { + return mAccount ? new AccountGui(mAccount) : nullptr; +} + +void AccountDeviceProxy::setAccount(AccountGui *accountGui) { + auto currentAccountModel = mAccountDeviceList->getAccountModel(); + auto accountCore = accountGui ? QSharedPointer(accountGui->getCore()) : nullptr; + auto newModel = accountCore ? accountCore->getModel() : nullptr; + if (newModel != currentAccountModel) { + mAccount = accountCore; + mAccountDeviceList->setAccountModel(accountGui->getCore()->getModel()); + emit accountChanged(); + } +} + +void AccountDeviceProxy::deleteDevice(AccountDeviceGui *device) { + mAccountDeviceList->deleteDevice(device); +} + +bool AccountDeviceProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { + return true; +} + +bool AccountDeviceProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { + auto deviceA = sourceModel()->data(left).value()->getCore(); + auto deviceB = sourceModel()->data(right).value()->getCore(); + + return left.row() < right.row(); +} diff --git a/Linphone/core/account/AccountDeviceProxy.hpp b/Linphone/core/account/AccountDeviceProxy.hpp new file mode 100644 index 000000000..af8135f6a --- /dev/null +++ b/Linphone/core/account/AccountDeviceProxy.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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 . + */ + +#ifndef ACCOUNT_DEVICE_PROXY_MODEL_H_ +#define ACCOUNT_DEVICE_PROXY_MODEL_H_ + +#include "../proxy/SortFilterProxy.hpp" +#include "core/account/AccountDeviceGui.hpp" +#include "core/account/AccountGui.hpp" +#include "core/call/CallGui.hpp" +#include "tool/AbstractObject.hpp" + +class AccountDeviceList; +class AccountDeviceGui; + +class AccountDeviceProxy : public SortFilterProxy, public AbstractObject { + Q_OBJECT + Q_PROPERTY(AccountGui *account READ getAccount WRITE setAccount NOTIFY accountChanged) + +public: + DECLARE_GUI_OBJECT + AccountDeviceProxy(QObject *parent = Q_NULLPTR); + ~AccountDeviceProxy(); + + AccountGui *getAccount() const; + void setAccount(AccountGui *accountGui); + Q_INVOKABLE void deleteDevice(AccountDeviceGui *device); + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + +signals: + void lUpdate(); + void accountChanged(); + +private: + QSharedPointer mAccount; + QString mSearchText; + QSharedPointer mAccountDeviceList; + QSharedPointer> mCoreModelConnection; + + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/core/account/AccountProxy.cpp b/Linphone/core/account/AccountProxy.cpp index f4972e9eb..fb16c36cb 100644 --- a/Linphone/core/account/AccountProxy.cpp +++ b/Linphone/core/account/AccountProxy.cpp @@ -48,8 +48,8 @@ void AccountProxy::setFilterText(const QString &filter) { } AccountGui *AccountProxy::getDefaultAccount() { - if (!mDefaultAccount) mDefaultAccount = dynamic_cast(sourceModel())->getDefaultAccount(); - return mDefaultAccount; + if (!mDefaultAccount) mDefaultAccount = dynamic_cast(sourceModel())->getDefaultAccountCore(); + return new AccountGui(mDefaultAccount); } void AccountProxy::setDefaultAccount(AccountGui *account) { diff --git a/Linphone/core/account/AccountProxy.hpp b/Linphone/core/account/AccountProxy.hpp index aaee2da68..18572fed3 100644 --- a/Linphone/core/account/AccountProxy.hpp +++ b/Linphone/core/account/AccountProxy.hpp @@ -59,7 +59,7 @@ protected: virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; QString mFilterText; - AccountGui *mDefaultAccount = nullptr; // When null, a new UI object is build from List + QSharedPointer mDefaultAccount; // When null, a new UI object is build from List QSharedPointer mAccountList; }; diff --git a/Linphone/core/participant/ParticipantDeviceList.cpp b/Linphone/core/participant/ParticipantDeviceList.cpp index e9f29ccca..373168c71 100644 --- a/Linphone/core/participant/ParticipantDeviceList.cpp +++ b/Linphone/core/participant/ParticipantDeviceList.cpp @@ -95,7 +95,7 @@ void ParticipantDeviceList::setConferenceModel(const std::shared_ptrmCore.lock()) { // Unsure to get myself + if (mConferenceModelConnection->mCore.lock()) { // Ensure to get myself auto oldConnect = mConferenceModelConnection->mCore; // Setself rebuild safepointer setSelf(mConferenceModelConnection->mCore.mQData); // reset connections oldConnect.unlock(); diff --git a/Linphone/model/CMakeLists.txt b/Linphone/model/CMakeLists.txt index 5cb903321..1566e7464 100644 --- a/Linphone/model/CMakeLists.txt +++ b/Linphone/model/CMakeLists.txt @@ -1,4 +1,5 @@ list(APPEND _LINPHONEAPP_SOURCES + model/account/AccountDeviceModel.cpp model/account/AccountModel.cpp model/account/AccountManager.cpp model/account/AccountManagerServicesModel.cpp diff --git a/Linphone/model/account/AccountDeviceModel.cpp b/Linphone/model/account/AccountDeviceModel.cpp new file mode 100644 index 000000000..b80d6af7f --- /dev/null +++ b/Linphone/model/account/AccountDeviceModel.cpp @@ -0,0 +1,40 @@ +/* + * 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 . + */ + +#include "AccountDeviceModel.hpp" + +#include + +#include "model/core/CoreModel.hpp" + +DEFINE_ABSTRACT_OBJECT(AccountDeviceModel) + +AccountDeviceModel::AccountDeviceModel(const std::shared_ptr &accountDevice, QObject *parent) + : accountDevice(accountDevice) { + mustBeInLinphoneThread(getClassName()); +} + +const std::shared_ptr AccountDeviceModel::getDevice() const { + return accountDevice; +} + +AccountDeviceModel::~AccountDeviceModel() { + // mustBeInLinphoneThread("~" + getClassName()); +} \ No newline at end of file diff --git a/Linphone/model/account/AccountDeviceModel.hpp b/Linphone/model/account/AccountDeviceModel.hpp new file mode 100644 index 000000000..6ff2cb785 --- /dev/null +++ b/Linphone/model/account/AccountDeviceModel.hpp @@ -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 . + */ + +#ifndef ACCOUNT_DEVICE_MODEL_H_ +#define ACCOUNT_DEVICE_MODEL_H_ + +#include "model/listener/Listener.hpp" +#include "tool/AbstractObject.hpp" + +#include +#include +#include + +class AccountDeviceModel : public QObject, public AbstractObject { + Q_OBJECT +public: + AccountDeviceModel(const std::shared_ptr &accountDevice, QObject *parent = nullptr); + ~AccountDeviceModel(); + + const std::shared_ptr getDevice() const; + +private: + std::shared_ptr accountDevice; + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/model/account/AccountManager.cpp b/Linphone/model/account/AccountManager.cpp index e4677a8ad..004e8819f 100644 --- a/Linphone/model/account/AccountManager.cpp +++ b/Linphone/model/account/AccountManager.cpp @@ -85,7 +85,7 @@ bool AccountManager::login(QString username, if (!displayName.isEmpty()) identity->setDisplayName(Utils::appStringToCoreString(displayName)); if (!domain.isEmpty()) { identity->setDomain(Utils::appStringToCoreString(domain)); - if (!domain.isEmpty() && QString::compare(domain, "sip.linphone.org")) { + if (QString::compare(domain, "sip.linphone.org")) { params->setLimeServerUrl(""); auto serverAddress = factory->createAddress(Utils::appStringToCoreString(QStringLiteral("sip:%1").arg(domain))); @@ -314,4 +314,4 @@ void AccountManager::onRegistrationStateChanged(const std::shared_ptr createAccount(const QString &assistantFile); diff --git a/Linphone/model/account/AccountManagerServicesModel.cpp b/Linphone/model/account/AccountManagerServicesModel.cpp index 6eb8a8fc2..ef1966123 100644 --- a/Linphone/model/account/AccountManagerServicesModel.cpp +++ b/Linphone/model/account/AccountManagerServicesModel.cpp @@ -98,4 +98,15 @@ void AccountManagerServicesModel::linkEmailToAccountUsingCode( const std::shared_ptr &sipIdentityAddress, const std::string &code) { auto req = mAccountManagerServices->createLinkEmailToAccountUsingCodeRequest(sipIdentityAddress, code); setRequestAndSubmit(req); -} \ No newline at end of file +} + +void AccountManagerServicesModel::getDeviceList(const std::shared_ptr &sipIdentityAddress) { + auto req = mAccountManagerServices->createGetDevicesListRequest(sipIdentityAddress); + setRequestAndSubmit(req); +} + +void AccountManagerServicesModel::deleteDevice(const std::shared_ptr &sipIdentityAddress, + const std::shared_ptr &device) { + auto req = mAccountManagerServices->createDeleteDeviceRequest(sipIdentityAddress, device); + setRequestAndSubmit(req); +} diff --git a/Linphone/model/account/AccountManagerServicesModel.hpp b/Linphone/model/account/AccountManagerServicesModel.hpp index 6a5b27b96..df38bd1b1 100644 --- a/Linphone/model/account/AccountManagerServicesModel.hpp +++ b/Linphone/model/account/AccountManagerServicesModel.hpp @@ -50,6 +50,9 @@ public: const std::string &code); void linkEmailToAccountUsingCode(const std::shared_ptr &sipIdentityAddress, const std::string &code); + void getDeviceList(const std::shared_ptr &sipIdentityAddress); + void deleteDevice(const std::shared_ptr &sipIdentityAddress, + const std::shared_ptr &device); void setRequestAndSubmit(const std::shared_ptr &request); diff --git a/Linphone/view/App/AppWindow.qml b/Linphone/view/App/AppWindow.qml index a4d9a72ad..c0414cb8c 100644 --- a/Linphone/view/App/AppWindow.qml +++ b/Linphone/view/App/AppWindow.qml @@ -30,8 +30,8 @@ ApplicationWindow { property var callback: requestDialog?.result signal closePopup(int index) onClosed: closePopup(index) - text: requestDialog.message - details: requestDialog.details + text: requestDialog?.message + details: requestDialog?.details // For C++, requestDialog need to be call directly onAccepted: requestDialog ? requestDialog.result(1) : callback(1) onRejected: requestDialog ? requestDialog.result(0) : callback(0) diff --git a/Linphone/view/App/Layout/Account/AccountSettingsGeneralLayout.qml b/Linphone/view/App/Layout/Account/AccountSettingsGeneralLayout.qml index fd69c9192..36c233238 100644 --- a/Linphone/view/App/Layout/Account/AccountSettingsGeneralLayout.qml +++ b/Linphone/view/App/Layout/Account/AccountSettingsGeneralLayout.qml @@ -260,7 +260,7 @@ AbstractDetailsLayout { color: DefaultStyle.main2_600 } Text { - text: qsTr("La liste des appareils connectés à votre compte. Vous pouvez retirer les appareils que vous n’utilisez plus. (TODO connecter API SDK quand dispo)") + text: qsTr("La liste des appareils connectés à votre compte. Vous pouvez retirer les appareils que vous n’utilisez plus.") font: Typography.p1s wrapMode: Text.WordWrap color: DefaultStyle.main2_600 @@ -271,46 +271,55 @@ AbstractDetailsLayout { Layout.fillHeight: true } } - Rectangle { - color: DefaultStyle.grey_100 + RoundedBackgroundControl { Layout.fillWidth: true - Layout.minimumHeight: account.core.devices.length * 133 * DefaultStyle.dp + (account.core.devices.length - 1) * 15 * DefaultStyle.dp + 2 * 21 * DefaultStyle.dp - radius: 15 * DefaultStyle.dp + Layout.fillHeight: true + // Layout.minimumHeight: account.core.devices.length * 133 * DefaultStyle.dp + (account.core.devices.length - 1) * 15 * DefaultStyle.dp + 2 * 21 * DefaultStyle.dp Layout.rightMargin: 30 * DefaultStyle.dp Layout.topMargin: 20 * DefaultStyle.dp - Layout.bottomMargin: 21 * DefaultStyle.dp + Layout.bottomMargin: 4 * DefaultStyle.dp Layout.leftMargin: 44 * DefaultStyle.dp - ColumnLayout { + topPadding: 21 * DefaultStyle.dp + bottomPadding: 21 * DefaultStyle.dp + leftPadding: 17 * DefaultStyle.dp + rightPadding: 17 * DefaultStyle.dp + background: Rectangle { anchors.fill: parent - anchors.bottomMargin: 21 * DefaultStyle.dp + color: DefaultStyle.grey_100 + radius: 15 * DefaultStyle.dp + } + contentItem: ColumnLayout { spacing: 15 * DefaultStyle.dp Repeater { id: devices - model: account.core.devices - Rectangle { + model: AccountDeviceProxy { + id: accountDeviceProxy + account: model + } + Control.Control{ Layout.fillWidth: true - Layout.preferredHeight: 133 * DefaultStyle.dp - Layout.topMargin: (index == 0 ? 21 : 0) * DefaultStyle.dp - Layout.leftMargin: 17 * DefaultStyle.dp - Layout.rightMargin: 17 * DefaultStyle.dp - color: 'white' - radius: 10 * DefaultStyle.dp - ColumnLayout { - anchors.topMargin: 26 * DefaultStyle.dp - anchors.bottomMargin: 26 * DefaultStyle.dp - anchors.centerIn: parent + height: 133 * DefaultStyle.dp + topPadding: 26 * DefaultStyle.dp + bottomPadding: 26 * DefaultStyle.dp + rightPadding: 36 * DefaultStyle.dp + leftPadding: 33 * DefaultStyle.dp + + background: Rectangle { + anchors.fill: parent + color: DefaultStyle.grey_0 + radius: 10 * DefaultStyle.dp + } + contentItem: ColumnLayout { width: parent.width spacing: 20 * DefaultStyle.dp RowLayout { - Layout.rightMargin: 36 * DefaultStyle.dp - Layout.leftMargin: 33 * DefaultStyle.dp spacing: 5 * DefaultStyle.dp EffectImage { Layout.preferredWidth: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp fillMode: Image.PreserveAspectFit colorizationColor: DefaultStyle.main2_600 - imageSource: modelData.core.userAgent.toLowerCase().includes('ios') || modelData.core.userAgent.toLowerCase().includes('android') ? AppIcons.mobile : AppIcons.desktop + imageSource: modelData.core.userAgent.toLowerCase().includes('ios') | modelData.core.userAgent.toLowerCase().includes('android') ? AppIcons.mobile : AppIcons.desktop } Text { text: modelData.core.deviceName @@ -330,10 +339,10 @@ AbstractDetailsLayout { onClicked: { var mainWin = UtilsCpp.getMainWindow() mainWin.showConfirmationLambdaPopup( - qsTr("Supprimer ") + modelData.core.deviceName + " ?", + qsTr("Supprimer ") + modelData.core.deviceName + " ?", "", function (confirmed) { if (confirmed) { - modelData.core.removeDevice() + accountDeviceProxy.deleteDevice(modelData) } } ) @@ -341,8 +350,6 @@ AbstractDetailsLayout { } } RowLayout { - Layout.rightMargin: 36 * DefaultStyle.dp - Layout.leftMargin: 33 * DefaultStyle.dp spacing: 5 * DefaultStyle.dp Text { text: qsTr("Dernière connexion:")