diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index d358897b0..8f281ac41 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -41,8 +41,10 @@ #include "core/account/AccountCore.hpp" #include "core/account/AccountDeviceGui.hpp" #include "core/account/AccountDeviceProxy.hpp" -#include "core/address-books/LdapGui.hpp" -#include "core/address-books/LdapProxy.hpp" +#include "core/address-books/carddav/CarddavGui.hpp" +#include "core/address-books/carddav/CarddavProxy.hpp" +#include "core/address-books/ldap/LdapGui.hpp" +#include "core/address-books/ldap/LdapProxy.hpp" #include "core/call-history/CallHistoryProxy.hpp" #include "core/call/CallCore.hpp" #include "core/call/CallGui.hpp" @@ -594,6 +596,8 @@ void App::initCppInterfaces() { QLatin1String("Uncreatable")); qmlRegisterType(Constants::MainQmlUri, 1, 0, "LdapGui"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "LdapProxy"); + qmlRegisterType(Constants::MainQmlUri, 1, 0, "CarddavGui"); + qmlRegisterType(Constants::MainQmlUri, 1, 0, "CarddavProxy"); LinphoneEnums::registerMetaTypes(); } diff --git a/Linphone/core/CMakeLists.txt b/Linphone/core/CMakeLists.txt index 0f55ed67b..d9db6c8f6 100644 --- a/Linphone/core/CMakeLists.txt +++ b/Linphone/core/CMakeLists.txt @@ -68,10 +68,15 @@ list(APPEND _LINPHONEAPP_SOURCES core/videoSource/VideoSourceDescriptorCore.cpp core/videoSource/VideoSourceDescriptorGui.cpp - core/address-books/LdapCore.cpp - core/address-books/LdapGui.cpp - core/address-books/LdapProxy.cpp - core/address-books/LdapList.cpp + core/address-books/ldap/LdapCore.cpp + core/address-books/ldap/LdapGui.cpp + core/address-books/ldap/LdapProxy.cpp + core/address-books/ldap/LdapList.cpp + + core/address-books/carddav/CarddavCore.cpp + core/address-books/carddav/CarddavGui.cpp + core/address-books/carddav/CarddavProxy.cpp + core/address-books/carddav/CarddavList.cpp ) diff --git a/Linphone/core/address-books/carddav/CarddavCore.cpp b/Linphone/core/address-books/carddav/CarddavCore.cpp new file mode 100644 index 000000000..e338f4ff8 --- /dev/null +++ b/Linphone/core/address-books/carddav/CarddavCore.cpp @@ -0,0 +1,84 @@ +/* + * 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 "CarddavCore.hpp" +#include "core/App.hpp" + +DEFINE_ABSTRACT_OBJECT(CarddavCore) + +QSharedPointer CarddavCore::create(const std::shared_ptr &carddavFriendList) { + auto sharedPointer = QSharedPointer(new CarddavCore(carddavFriendList), &QObject::deleteLater); + sharedPointer->setSelf(sharedPointer); + sharedPointer->moveToThread(App::getInstance()->thread()); + return sharedPointer; +} + +CarddavCore::CarddavCore(const std::shared_ptr &carddavFriendList) : QObject(nullptr) { + App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + mCarddavModel = CarddavModel::create(carddavFriendList); + if (carddavFriendList) { + mDisplayName = Utils::coreStringToAppString(carddavFriendList->getDisplayName()); + mUri = Utils::coreStringToAppString(carddavFriendList->getUri()); + } + mStoreNewFriendsInIt = mCarddavModel->storeNewFriendsInIt(); +} + +CarddavCore::~CarddavCore() { + mustBeInMainThread(log().arg(Q_FUNC_INFO)); +} + +void CarddavCore::save() { + if (!mUri.startsWith("http://") && !mUri.startsWith("https://")) { + mUri = "https://" + mUri; + emit uriChanged(); + } + + auto displayName = Utils::appStringToCoreString(mDisplayName); + auto uri = Utils::appStringToCoreString(mUri); + auto username = Utils::appStringToCoreString(mUsername); + auto password = Utils::appStringToCoreString(mPassword); + auto realm = Utils::appStringToCoreString(mRealm); + auto storeNewFriendsInIt = mStoreNewFriendsInIt; + + mCarddavModelConnection->invokeToModel([this, displayName, uri, username, password, realm, storeNewFriendsInIt]() { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + mCarddavModel->save(displayName, uri, username, password, realm, storeNewFriendsInIt); + }); +} + +void CarddavCore::remove() { + mCarddavModelConnection->invokeToModel([this]() { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + mCarddavModel->remove(); + }); +} + +void CarddavCore::setSelf(QSharedPointer me) { + mCarddavModelConnection = QSharedPointer>( + new SafeConnection(me, mCarddavModel), &QObject::deleteLater); + mCarddavModelConnection->makeConnectToModel(&CarddavModel::saved, [this](bool success) { + mCarddavModelConnection->invokeToCore([this, success]() { emit saved(success); }); + }); +} + +bool CarddavCore::isValid() { + return !mDisplayName.isEmpty() && !mUri.isEmpty(); // Auth info is optional. +} diff --git a/Linphone/core/address-books/carddav/CarddavCore.hpp b/Linphone/core/address-books/carddav/CarddavCore.hpp new file mode 100644 index 000000000..89b4a69cc --- /dev/null +++ b/Linphone/core/address-books/carddav/CarddavCore.hpp @@ -0,0 +1,62 @@ +/* + * 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 CARDDAV_CORE_H_ +#define CARDDAV_CORE_H_ + +#include "model/address-books/carddav/CarddavModel.hpp" +#include "tool/AbstractObject.hpp" +#include "tool/thread/SafeConnection.hpp" +#include +#include +#include + +class CarddavCore : public QObject, public AbstractObject { + Q_OBJECT + +public: + static QSharedPointer create(const std::shared_ptr &carddavFriendList); + CarddavCore(const std::shared_ptr &carddavFriendList); + ~CarddavCore(); + + void setSelf(QSharedPointer me); + + Q_INVOKABLE void remove(); + Q_INVOKABLE void save(); + Q_INVOKABLE bool isValid(); + + DECLARE_CORE_MEMBER(QString, displayName, DisplayName) + DECLARE_CORE_MEMBER(QString, uri, Uri) + DECLARE_CORE_MEMBER(QString, username, Username) + DECLARE_CORE_MEMBER(QString, password, Password) + DECLARE_CORE_MEMBER(QString, realm, Realm) + DECLARE_CORE_MEMBER(bool, storeNewFriendsInIt, StoreNewFriendsInIt) + +signals: + void saved(bool success); + +private: + std::shared_ptr mCarddavModel; + QSharedPointer> mCarddavModelConnection; + + DECLARE_ABSTRACT_OBJECT +}; +Q_DECLARE_METATYPE(CarddavCore *) +#endif diff --git a/Linphone/core/address-books/carddav/CarddavGui.cpp b/Linphone/core/address-books/carddav/CarddavGui.cpp new file mode 100644 index 000000000..842c2fa57 --- /dev/null +++ b/Linphone/core/address-books/carddav/CarddavGui.cpp @@ -0,0 +1,46 @@ +/* + * 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 "CarddavGui.hpp" +#include "core/App.hpp" + +DEFINE_ABSTRACT_OBJECT(CarddavGui) + +CarddavGui::CarddavGui(QObject *parent) : QObject(parent) { + mustBeInMainThread(getClassName()); + App::postModelSync([this]() { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + mCore = CarddavCore::create(nullptr); + }); +} + +CarddavGui::CarddavGui(QSharedPointer core) { + App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); + mCore = core; + if (isInLinphoneThread()) moveToThread(App::getInstance()->thread()); +} + +CarddavGui::~CarddavGui() { + mustBeInMainThread("~" + getClassName()); +} + +CarddavCore *CarddavGui::getCore() const { + return mCore.get(); +} diff --git a/Linphone/core/address-books/carddav/CarddavGui.hpp b/Linphone/core/address-books/carddav/CarddavGui.hpp new file mode 100644 index 000000000..5bc4d2400 --- /dev/null +++ b/Linphone/core/address-books/carddav/CarddavGui.hpp @@ -0,0 +1,42 @@ +/* + * 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 CARDDAV_GUI_H_ +#define CARDDAV_GUI_H_ + +#include "CarddavCore.hpp" +#include +#include + +class CarddavGui : public QObject, public AbstractObject { + Q_OBJECT + + Q_PROPERTY(CarddavCore *core READ getCore CONSTANT) + +public: + CarddavGui(QObject *parent = nullptr); + CarddavGui(QSharedPointer core); + ~CarddavGui(); + CarddavCore *getCore() const; + QSharedPointer mCore; + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/core/address-books/carddav/CarddavList.cpp b/Linphone/core/address-books/carddav/CarddavList.cpp new file mode 100644 index 000000000..e1f87433e --- /dev/null +++ b/Linphone/core/address-books/carddav/CarddavList.cpp @@ -0,0 +1,108 @@ +/* + * 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 "CarddavList.hpp" +#include "CarddavGui.hpp" +#include "core/App.hpp" +#include "model/object/VariantObject.hpp" +#include +#include + +// ============================================================================= + +DEFINE_ABSTRACT_OBJECT(CarddavList) + +QSharedPointer CarddavList::create() { + auto model = QSharedPointer(new CarddavList(), &QObject::deleteLater); + model->moveToThread(App::getInstance()->thread()); + model->setSelf(model); + return model; +} + +QSharedPointer +CarddavList::createCarddavCore(const std::shared_ptr &carddavFriendList) { + auto CarddavCore = CarddavCore::create(carddavFriendList); + return CarddavCore; +} + +CarddavList::CarddavList(QObject *parent) : ListProxy(parent) { + mustBeInMainThread(getClassName()); + App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +CarddavList::~CarddavList() { + mustBeInMainThread("~" + getClassName()); + mModelConnection = nullptr; +} + +void CarddavList::setSelf(QSharedPointer me) { + mModelConnection = QSharedPointer>( + new SafeConnection(me, CoreModel::getInstance()), &QObject::deleteLater); + mModelConnection->makeConnectToCore(&CarddavList::lUpdate, [this]() { + mModelConnection->invokeToModel([this]() { + mustBeInLinphoneThread(getClassName()); + QList> *carddavs = new QList>(); + for (auto friendList : CoreModel::getInstance()->getCore()->getFriendsLists()) { + if (friendList->getType() == linphone::FriendList::Type::CardDAV) { + auto model = createCarddavCore(friendList); + carddavs->push_back(model); + } + } + mModelConnection->invokeToCore([this, carddavs]() { + mustBeInMainThread(getClassName()); + resetData(); + add(*carddavs); + delete carddavs; + }); + }); + }); + QObject::connect( + CoreModel::getInstance().get(), &CoreModel::friendListRemoved, this, + [this](const std::shared_ptr &core, const std::shared_ptr &friendList) { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + emit lUpdate(); + }); + emit lUpdate(); +} + +void CarddavList::removeAllEntries() { + beginResetModel(); + for (auto it = mList.rbegin(); it != mList.rend(); ++it) { + auto carddavFriendList = it->objectCast(); + carddavFriendList->remove(); + } + mList.clear(); + endResetModel(); +} + +void CarddavList::remove(const int &row) { + beginRemoveRows(QModelIndex(), row, row); + mList.takeAt(row).objectCast()->remove(); + endRemoveRows(); +} + +QVariant CarddavList::data(const QModelIndex &index, int role) const { + int row = index.row(); + if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant(); + if (role == Qt::DisplayRole) { + return QVariant::fromValue(new CarddavGui(mList[row].objectCast())); + } + return QVariant(); +} diff --git a/Linphone/core/address-books/carddav/CarddavList.hpp b/Linphone/core/address-books/carddav/CarddavList.hpp new file mode 100644 index 000000000..7ba9df2ac --- /dev/null +++ b/Linphone/core/address-books/carddav/CarddavList.hpp @@ -0,0 +1,58 @@ +/* + * 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 CARDDAV_LIST_H_ +#define CARDDAV_LIST_H_ + +#include "../../proxy/ListProxy.hpp" +#include "tool/AbstractObject.hpp" +#include "tool/thread/SafeConnection.hpp" +#include + +class CarddavCore; +class CoreModel; +// ============================================================================= + +class CarddavList : public ListProxy, public AbstractObject { + Q_OBJECT + +public: + static QSharedPointer create(); + // Create a CarddavCore and make connections to List. + QSharedPointer createCarddavCore(const std::shared_ptr &carddavFriendList); + CarddavList(QObject *parent = Q_NULLPTR); + ~CarddavList(); + + void setSelf(QSharedPointer me); + + void removeAllEntries(); + void remove(const int &row); + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +signals: + void lUpdate(); + +private: + QSharedPointer> mModelConnection; + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/core/address-books/carddav/CarddavProxy.cpp b/Linphone/core/address-books/carddav/CarddavProxy.cpp new file mode 100644 index 000000000..d7559784e --- /dev/null +++ b/Linphone/core/address-books/carddav/CarddavProxy.cpp @@ -0,0 +1,77 @@ +/* + * 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 "CarddavProxy.hpp" +#include "CarddavGui.hpp" +#include "CarddavList.hpp" + +DEFINE_ABSTRACT_OBJECT(CarddavProxy) + +CarddavProxy::CarddavProxy(QObject *parent) : SortFilterProxy(parent) { + mCarddavList = CarddavList::create(); + setSourceModel(mCarddavList.get()); +} + +CarddavProxy::~CarddavProxy() { + setSourceModel(nullptr); +} + +QString CarddavProxy::getFilterText() const { + return mFilterText; +} + +void CarddavProxy::setFilterText(const QString &filter) { + if (mFilterText != filter) { + mFilterText = filter; + invalidate(); + emit filterTextChanged(); + } +} + +void CarddavProxy::removeAllEntries() { + static_cast(sourceModel())->removeAllEntries(); +} + +void CarddavProxy::removeEntriesWithFilter() { + std::list> itemList(rowCount()); + for (auto i = rowCount() - 1; i >= 0; --i) { + auto item = getItemAt(i); + itemList.emplace_back(item); + } + for (auto item : itemList) { + mCarddavList->ListProxy::remove(item.get()); + if (item) item->remove(); + } +} + +bool CarddavProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { + return true; +} + +bool CarddavProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { + auto l = getItemAt(left.row()); + auto r = getItemAt(right.row()); + + return l->mDisplayName < r->mDisplayName; +} + +void CarddavProxy::updateView() { + mCarddavList->lUpdate(); +} diff --git a/Linphone/core/address-books/carddav/CarddavProxy.hpp b/Linphone/core/address-books/carddav/CarddavProxy.hpp new file mode 100644 index 000000000..143616203 --- /dev/null +++ b/Linphone/core/address-books/carddav/CarddavProxy.hpp @@ -0,0 +1,60 @@ +/* + * 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 CARDDAV_PROXY_H_ +#define CARDDAV_PROXY_H_ + +#include "../../proxy/SortFilterProxy.hpp" +#include "CarddavGui.hpp" +#include "CarddavList.hpp" +#include "tool/AbstractObject.hpp" + +// ============================================================================= + +class CarddavProxy : public SortFilterProxy, public AbstractObject { + Q_OBJECT + + Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged) + +public: + CarddavProxy(QObject *parent = Q_NULLPTR); + ~CarddavProxy(); + + QString getFilterText() const; + void setFilterText(const QString &filter); + + Q_INVOKABLE void removeAllEntries(); + Q_INVOKABLE void removeEntriesWithFilter(); + Q_INVOKABLE void updateView(); + +signals: + void filterTextChanged(); + +protected: + virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + + QString mFilterText; + QSharedPointer mCarddavList; + + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/core/address-books/LdapCore.cpp b/Linphone/core/address-books/ldap/LdapCore.cpp similarity index 98% rename from Linphone/core/address-books/LdapCore.cpp rename to Linphone/core/address-books/ldap/LdapCore.cpp index fe5e43db1..0e08a780e 100644 --- a/Linphone/core/address-books/LdapCore.cpp +++ b/Linphone/core/address-books/ldap/LdapCore.cpp @@ -105,9 +105,9 @@ void LdapCore::setSelf(QSharedPointer me) { debugLevel, DebugLevel) mLdapModelConnection->makeConnectToModel(&LdapModel::saved, [this]() { - mLdapModelConnection->invokeToCore([this]() { emit App::getInstance() -> getSettings()->ldapConfigChanged(); }); + mLdapModelConnection->invokeToCore([this]() { emit App::getInstance()->getSettings()->ldapConfigChanged(); }); }); mLdapModelConnection->makeConnectToModel(&LdapModel::removed, [this]() { - mLdapModelConnection->invokeToCore([this]() { emit App::getInstance() -> getSettings()->ldapConfigChanged(); }); + mLdapModelConnection->invokeToCore([this]() { emit App::getInstance()->getSettings()->ldapConfigChanged(); }); }); } diff --git a/Linphone/core/address-books/LdapCore.hpp b/Linphone/core/address-books/ldap/LdapCore.hpp similarity index 98% rename from Linphone/core/address-books/LdapCore.hpp rename to Linphone/core/address-books/ldap/LdapCore.hpp index 25f414243..b07d21ad2 100644 --- a/Linphone/core/address-books/LdapCore.hpp +++ b/Linphone/core/address-books/ldap/LdapCore.hpp @@ -21,7 +21,7 @@ #ifndef LDAP_CORE_H_ #define LDAP_CORE_H_ -#include "model/address-books/LdapModel.hpp" +#include "model/address-books/ldap/LdapModel.hpp" #include "tool/AbstractObject.hpp" #include "tool/thread/SafeConnection.hpp" #include diff --git a/Linphone/core/address-books/LdapGui.cpp b/Linphone/core/address-books/ldap/LdapGui.cpp similarity index 100% rename from Linphone/core/address-books/LdapGui.cpp rename to Linphone/core/address-books/ldap/LdapGui.cpp diff --git a/Linphone/core/address-books/LdapGui.hpp b/Linphone/core/address-books/ldap/LdapGui.hpp similarity index 100% rename from Linphone/core/address-books/LdapGui.hpp rename to Linphone/core/address-books/ldap/LdapGui.hpp diff --git a/Linphone/core/address-books/LdapList.cpp b/Linphone/core/address-books/ldap/LdapList.cpp similarity index 97% rename from Linphone/core/address-books/LdapList.cpp rename to Linphone/core/address-books/ldap/LdapList.cpp index 751262cee..aebabc348 100644 --- a/Linphone/core/address-books/LdapList.cpp +++ b/Linphone/core/address-books/ldap/LdapList.cpp @@ -85,9 +85,7 @@ void LdapList::removeAllEntries() { void LdapList::remove(const int &row) { beginRemoveRows(QModelIndex(), row, row); - auto item = mList[row].objectCast(); - item->remove(); - mList.takeAt(row); + mList.takeAt(row).objectCast()->remove(); endRemoveRows(); } diff --git a/Linphone/core/address-books/LdapList.hpp b/Linphone/core/address-books/ldap/LdapList.hpp similarity index 97% rename from Linphone/core/address-books/LdapList.hpp rename to Linphone/core/address-books/ldap/LdapList.hpp index 74283d098..ced6517e7 100644 --- a/Linphone/core/address-books/LdapList.hpp +++ b/Linphone/core/address-books/ldap/LdapList.hpp @@ -21,7 +21,7 @@ #ifndef LDAP_LIST_H_ #define LDAP_LIST_H_ -#include "../proxy/ListProxy.hpp" +#include "../../proxy/ListProxy.hpp" #include "tool/AbstractObject.hpp" #include "tool/thread/SafeConnection.hpp" #include diff --git a/Linphone/core/address-books/LdapProxy.cpp b/Linphone/core/address-books/ldap/LdapProxy.cpp similarity index 100% rename from Linphone/core/address-books/LdapProxy.cpp rename to Linphone/core/address-books/ldap/LdapProxy.cpp diff --git a/Linphone/core/address-books/LdapProxy.hpp b/Linphone/core/address-books/ldap/LdapProxy.hpp similarity index 97% rename from Linphone/core/address-books/LdapProxy.hpp rename to Linphone/core/address-books/ldap/LdapProxy.hpp index 4c485719a..4295063ab 100644 --- a/Linphone/core/address-books/LdapProxy.hpp +++ b/Linphone/core/address-books/ldap/LdapProxy.hpp @@ -21,7 +21,7 @@ #ifndef LDAP_PROXY_H_ #define LDAP_PROXY_H_ -#include "../proxy/SortFilterProxy.hpp" +#include "../../proxy/SortFilterProxy.hpp" #include "LdapGui.hpp" #include "LdapList.hpp" #include "tool/AbstractObject.hpp" diff --git a/Linphone/core/friend/FriendCore.cpp b/Linphone/core/friend/FriendCore.cpp index abd07a54d..39ed38727 100644 --- a/Linphone/core/friend/FriendCore.cpp +++ b/Linphone/core/friend/FriendCore.cpp @@ -620,10 +620,15 @@ void FriendCore::save() { // Save Values to model thisCopy->writeIntoModel(mFriendModel); thisCopy->deleteLater(); mVCardString = mFriendModel->getVCardAsString(); - bool created = - (core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK); + auto carddavListForNewFriends = SettingsModel::getCarddavListForNewFriends(); + auto listWhereToAddFriend = carddavListForNewFriends != nullptr ? carddavListForNewFriends + : core->getDefaultFriendList(); + bool created = (listWhereToAddFriend->addFriend(contact) == linphone::FriendList::Status::OK); if (created) { - core->getDefaultFriendList()->updateSubscriptions(); + listWhereToAddFriend->updateSubscriptions(); + if (listWhereToAddFriend->getType() == linphone::FriendList::Type::CardDAV) { + listWhereToAddFriend->synchronizeFriendsFromServer(); + } emit CoreModel::getInstance()->friendCreated(contact); } mCoreModelConnection->invokeToCore([this, created]() { diff --git a/Linphone/model/CMakeLists.txt b/Linphone/model/CMakeLists.txt index f89e14b0a..256c9c444 100644 --- a/Linphone/model/CMakeLists.txt +++ b/Linphone/model/CMakeLists.txt @@ -41,7 +41,9 @@ list(APPEND _LINPHONEAPP_SOURCES model/videoSource/VideoSourceDescriptorModel.cpp - model/address-books/LdapModel.cpp + model/address-books/ldap/LdapModel.cpp + model/address-books/carddav/CarddavModel.cpp + ) set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE) diff --git a/Linphone/model/address-books/carddav/CarddavModel.cpp b/Linphone/model/address-books/carddav/CarddavModel.cpp new file mode 100644 index 000000000..53a217b73 --- /dev/null +++ b/Linphone/model/address-books/carddav/CarddavModel.cpp @@ -0,0 +1,111 @@ +/* + * 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 "CarddavModel.hpp" +#include "model/core/CoreModel.hpp" +#include "model/setting/SettingsModel.hpp" +#include "tool/Utils.hpp" + +DEFINE_ABSTRACT_OBJECT(CarddavModel) + +using namespace std; + +std::shared_ptr CarddavModel::create(const std::shared_ptr &carddavFriendList, + QObject *parent) { + auto model = std::make_shared(carddavFriendList, parent); + model->setSelf(model); + return model; +} + +CarddavModel::CarddavModel(const std::shared_ptr &carddavFriendList, QObject *parent) + : ::Listener(nullptr, parent) { + mustBeInLinphoneThread(getClassName()); + mCarddavFriendList = carddavFriendList; + mStoreNewFriendsInIt = storeNewFriendsInIt(); + mCreatedAuthInfo = nullptr; + mRemovedAuthInfo = nullptr; +} + +CarddavModel::~CarddavModel() { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); +} + +bool CarddavModel::storeNewFriendsInIt() { + if (!mCarddavFriendList) return false; + auto carddavListForNewFriends = SettingsModel::getCarddavListForNewFriends(); + return carddavListForNewFriends != nullptr && + mCarddavFriendList->getDisplayName() == carddavListForNewFriends->getDisplayName(); +} + +void CarddavModel::save( + string displayName, string uri, string username, string password, string realm, bool storeNewFriendsInIt) { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + auto core = CoreModel::getInstance()->getCore(); + + // Auth info handled in lazy mode, if provided handle otherwise ignore. + // TODO: add dialog to ask user before removing existing auth info if existing already - (comment from Android) + if (!username.empty() && !realm.empty()) { + mRemovedAuthInfo = core->findAuthInfo(realm, username, ""); + if (mRemovedAuthInfo != nullptr) { + lWarning() << log().arg("Auth info with username ") << username << " already exists, removing it first."; + core->removeAuthInfo(mRemovedAuthInfo); + } + lInfo() << log().arg("Adding auth info with username") << username; + mCreatedAuthInfo = linphone::Factory::get()->createAuthInfo(username, "", password, "", realm, ""); + core->addAuthInfo(mCreatedAuthInfo); + } else { + lInfo() << log().arg("No auth info provided upon saving."); + } + + if (!mCarddavFriendList) { + mCarddavFriendList = CoreModel::getInstance()->getCore()->createFriendList(); + mCarddavFriendList->setType(linphone::FriendList::Type::CardDAV); + mCarddavFriendList->enableDatabaseStorage(true); + core->addFriendList(mCarddavFriendList); + } + mCarddavFriendList->setDisplayName(displayName); + mCarddavFriendList->setUri(uri); + mStoreNewFriendsInIt = storeNewFriendsInIt; + setMonitor(mCarddavFriendList); + mCarddavFriendList->synchronizeFriendsFromServer(); +} + +void CarddavModel::remove() { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + CoreModel::getInstance()->getCore()->removeFriendList(mCarddavFriendList); + lInfo() << log().arg("Friend list removed:") << mCarddavFriendList->getUri(); + emit removed(); +} + +void CarddavModel::onSyncStatusChanged(const std::shared_ptr &friendList, + linphone::FriendList::SyncStatus status, + const std::string &message) { + if (status == linphone::FriendList::SyncStatus::Successful) { + lInfo() << log().arg("Successfully synchronized:") << mCarddavFriendList->getUri(); + setMonitor(nullptr); + if (mStoreNewFriendsInIt) SettingsModel::setCarddavListForNewFriends(friendList->getDisplayName()); + emit saved(true); + } + if (status == linphone::FriendList::SyncStatus::Failure) { + lWarning() << log().arg("Synchronization failure:") << mCarddavFriendList->getUri(); + setMonitor(nullptr); + emit saved(false); + } +} diff --git a/Linphone/model/address-books/carddav/CarddavModel.hpp b/Linphone/model/address-books/carddav/CarddavModel.hpp new file mode 100644 index 000000000..30287a063 --- /dev/null +++ b/Linphone/model/address-books/carddav/CarddavModel.hpp @@ -0,0 +1,63 @@ +/* + * 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 CARDDAV_MODEL_H_ +#define CARDDAV_MODEL_H_ + +#include "model/listener/Listener.hpp" +#include "tool/AbstractObject.hpp" +#include +#include + +class CarddavModel : public ::Listener, + public linphone::FriendListListener, + public AbstractObject { + Q_OBJECT +public: + static std::shared_ptr create(const std::shared_ptr &carddavFriendList, + QObject *parent = nullptr); + CarddavModel(const std::shared_ptr &carddavFriendList, QObject *parent = nullptr); + ~CarddavModel(); + + void save(std::string displayName, std::string uri, std::string username, std::string password, std::string realm, bool storeNewFriendsInIt); + void remove(); + bool storeNewFriendsInIt(); + +signals: + void saved(bool success); + void removed(); + +private: + bool mStoreNewFriendsInIt; + std::shared_ptr mCarddavFriendList; + std::shared_ptr mRemovedAuthInfo; + std::shared_ptr mCreatedAuthInfo; + + DECLARE_ABSTRACT_OBJECT + + //-------------------------------------------------------------------------------- + // LINPHONE + //-------------------------------------------------------------------------------- + virtual void onSyncStatusChanged(const std::shared_ptr &friendList, + linphone::FriendList::SyncStatus status, + const std::string &message) override; +}; + +#endif diff --git a/Linphone/model/address-books/LdapModel.cpp b/Linphone/model/address-books/ldap/LdapModel.cpp similarity index 100% rename from Linphone/model/address-books/LdapModel.cpp rename to Linphone/model/address-books/ldap/LdapModel.cpp diff --git a/Linphone/model/address-books/LdapModel.hpp b/Linphone/model/address-books/ldap/LdapModel.hpp similarity index 100% rename from Linphone/model/address-books/LdapModel.hpp rename to Linphone/model/address-books/ldap/LdapModel.hpp diff --git a/Linphone/model/core/CoreModel.cpp b/Linphone/model/core/CoreModel.cpp index 51a3ec517..2a9718532 100644 --- a/Linphone/model/core/CoreModel.cpp +++ b/Linphone/model/core/CoreModel.cpp @@ -399,3 +399,7 @@ void CoreModel::onVersionUpdateCheckResultReceived(const std::shared_ptr &core, + const std::shared_ptr &friendList) { + emit friendListRemoved(core, friendList); +} diff --git a/Linphone/model/core/CoreModel.hpp b/Linphone/model/core/CoreModel.hpp index 252b4f0a8..96a0a1dda 100644 --- a/Linphone/model/core/CoreModel.hpp +++ b/Linphone/model/core/CoreModel.hpp @@ -180,6 +180,8 @@ private: linphone::VersionUpdateCheckResult result, const std::string &version, const std::string &url) override; + virtual void onFriendListRemoved(const std::shared_ptr &core, + const std::shared_ptr &friendList) override; signals: void accountAdded(const std::shared_ptr &core, const std::shared_ptr &account); @@ -260,6 +262,8 @@ signals: linphone::VersionUpdateCheckResult result, const std::string &version, const std::string &url); + void friendListRemoved(const std::shared_ptr &core, + const std::shared_ptr &friendList); }; #endif diff --git a/Linphone/model/setting/SettingsModel.cpp b/Linphone/model/setting/SettingsModel.cpp index ff9795115..290d98f70 100644 --- a/Linphone/model/setting/SettingsModel.cpp +++ b/Linphone/model/setting/SettingsModel.cpp @@ -502,6 +502,30 @@ void SettingsModel::enableDnd(bool enableDnd) { emit dndChanged(enableDnd); } +// ============================================================================= +// Carddav storage list +// ============================================================================= + +const std::shared_ptr SettingsModel::getCarddavListForNewFriends() { + mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); + auto core = CoreModel::getInstance()->getCore(); + if (core) { + auto config = core->getConfig(); + auto listName = config->getString(UiSection, "friend_list_to_store_newly_created_contacts", ""); + if (!listName.empty()) return core->getFriendListByName(listName); + else return nullptr; + } else return nullptr; +} + +void SettingsModel::setCarddavListForNewFriends(std::string name) { + mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); + auto core = CoreModel::getInstance()->getCore(); + if (core) { + auto config = core->getConfig(); + config->setString(UiSection, "friend_list_to_store_newly_created_contacts", name); + } +} + // ============================================================================= // Ui. // ============================================================================= diff --git a/Linphone/model/setting/SettingsModel.hpp b/Linphone/model/setting/SettingsModel.hpp index 860e915d9..e58a29e6c 100644 --- a/Linphone/model/setting/SettingsModel.hpp +++ b/Linphone/model/setting/SettingsModel.hpp @@ -127,6 +127,9 @@ public: QString getLogsEmail() const; + static const std::shared_ptr getCarddavListForNewFriends(); + static void setCarddavListForNewFriends(std::string listName); + // UI DECLARE_GETSET(bool, disableChatFeature, DisableChatFeature) DECLARE_GETSET(bool, disableMeetingsFeature, DisableMeetingsFeature) diff --git a/Linphone/tool/AbstractObject.hpp b/Linphone/tool/AbstractObject.hpp index ae49f2ac0..506f90d34 100644 --- a/Linphone/tool/AbstractObject.hpp +++ b/Linphone/tool/AbstractObject.hpp @@ -38,8 +38,7 @@ } #define DECLARE_GUI_OBJECT \ -Q_SIGNALS: \ - void qmlNameChanged(); \ +Q_SIGNALS : void qmlNameChanged(); \ \ public: \ Q_PROPERTY(QString qmlName READ getQmlName WRITE setQmlName NOTIFY qmlNameChanged) \ @@ -67,6 +66,11 @@ public: Q_SIGNAL void x##Changed(); \ type m##X; +#define DECLARE_CORE_MEMBER(type, x, X) \ + Q_PROPERTY(type x MEMBER m##X NOTIFY x##Changed) \ + Q_SIGNAL void x##Changed(); \ + type m##X; + #define DECLARE_CORE_GETSET(type, x, X) \ Q_PROPERTY(type x READ get##X WRITE set##X NOTIFY x##Changed) \ Q_SIGNAL void set##X(type data); \ diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index 5da315010..c0bc5a2c6 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -104,8 +104,10 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Page/Layout/Settings/AccountSettingsParametersLayout.qml view/Page/Layout/Settings/CallSettingsLayout.qml view/Page/Layout/Settings/ContactsSettingsLayout.qml + view/Page/Layout/Settings/ContactsSettingsProviderLayout.qml view/Page/Layout/Settings/DebugSettingsLayout.qml view/Page/Layout/Settings/LdapSettingsLayout.qml + view/Page/Layout/Settings/CarddavSettingsLayout.qml view/Page/Layout/Settings/SecuritySettingsLayout.qml view/Page/Main/AbstractMainPage.qml diff --git a/Linphone/view/Page/Layout/Settings/CarddavSettingsLayout.qml b/Linphone/view/Page/Layout/Settings/CarddavSettingsLayout.qml new file mode 100644 index 000000000..a1ae1e0ea --- /dev/null +++ b/Linphone/view/Page/Layout/Settings/CarddavSettingsLayout.qml @@ -0,0 +1,146 @@ +import QtCore +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls.Basic as Control +import QtQuick.Dialogs +import Linphone +import SettingsCpp 1.0 +import UtilsCpp + +AbstractSettingsLayout { + id: mainItem + contentComponent: content + topbarOptionalComponent: topBar + property alias carddavGui: mainItem.model + property bool isNew: false + Component { + id: topBar + RowLayout { + spacing: 20 * DefaultStyle.dp + Button { + background: Item{} + icon.source: AppIcons.trashCan + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + contentImageColor: DefaultStyle.main2_600 + visible: !isNew + onClicked: { + var mainWin = UtilsCpp.getMainWindow() + mainWin.showConfirmationLambdaPopup( + qsTr("Supprimer le carnet d'adresse CardDAV ?"), + "", + function (confirmed) { + if (confirmed) { + carddavGui.core.remove() + mainItem.container.pop() + } + } + ) + } + } + Button { + text: qsTr("Enregistrer") + onClicked: { + if (carddavGui.core.isValid()) { + carddavGui.core.save() + } else { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Vérifiez que toutes les informations ont été saisies."), false, mainWindow) + } + } + Connections { + target: carddavGui.core + function onSaved(success) { + if (success) + UtilsCpp.showInformationPopup(qsTr("Succès"), qsTr("Le carnet d'adresse CardDAV est synchronisé."), true, mainWindow) + else + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Erreur de synchronisation!"), false, mainWindow) + } + } + } + } + } + + Component { + id: content + ColumnLayout { + width: parent.width + spacing: 5 * DefaultStyle.dp + RowLayout { + Layout.topMargin: 16 * DefaultStyle.dp + spacing: 5 * DefaultStyle.dp + ColumnLayout { + Layout.fillWidth: true + spacing: 5 * DefaultStyle.dp + ColumnLayout { + Layout.preferredWidth: 341 * DefaultStyle.dp + Layout.maximumWidth: 341 * DefaultStyle.dp + Layout.minimumWidth: 341 * DefaultStyle.dp + spacing: 5 * DefaultStyle.dp + Text { + Layout.fillWidth: true + text: qsTr("Carnet d'adresse CardDAV") + font: Typography.h4 + wrapMode: Text.WordWrap + color: DefaultStyle.main2_600 + } + Text { + text: qsTr("Ajouter un carnet d’adresse CardDAV pour synchroniser vos contacts Linphone avec un carnet d’adresse tiers.") + font: Typography.p1s + wrapMode: Text.WordWrap + color: DefaultStyle.main2_600 + Layout.fillWidth: true + } + } + Item { + Layout.fillHeight: true + } + } + ColumnLayout { + Layout.fillWidth: true + spacing: 20 * DefaultStyle.dp + Layout.rightMargin: 44 * DefaultStyle.dp + Layout.topMargin: 20 * DefaultStyle.dp + Layout.leftMargin: 64 * DefaultStyle.dp + DecoratedTextField { + propertyName: "displayName" + propertyOwner: carddavGui.core + title: qsTr("Nom d’affichage") + canBeEmpty: false + toValidate: true + } + DecoratedTextField { + propertyName: "uri" + propertyOwner: carddavGui.core + title: qsTr("URL du serveur") + canBeEmpty: false + toValidate: true + } + DecoratedTextField { + propertyName: "username" + propertyOwner: carddavGui.core + title: qsTr("Nom d’utilisateur") + toValidate: true + } + DecoratedTextField { + propertyName: "password" + hidden: true + propertyOwner: carddavGui.core + title: qsTr("Mot de passe") + toValidate: true + } + DecoratedTextField { + propertyName: "realm" + propertyOwner: carddavGui.core + title: qsTr("Domaine d’authentification") + toValidate: true + } + SwitchSetting { + titleText: qsTr("Stocker ici les contacts nouvellement crées") + propertyName: "storeNewFriendsInIt" + propertyOwner: carddavGui.core + } + } + } + } + } +} diff --git a/Linphone/view/Page/Layout/Settings/ContactsSettingsLayout.qml b/Linphone/view/Page/Layout/Settings/ContactsSettingsLayout.qml index b715be1cc..269e0b5d5 100644 --- a/Linphone/view/Page/Layout/Settings/ContactsSettingsLayout.qml +++ b/Linphone/view/Page/Layout/Settings/ContactsSettingsLayout.qml @@ -11,127 +11,51 @@ AbstractSettingsLayout { function layoutUrl(name) { return layoutsPath+"/"+name+".qml" } + function createGuiObject(name) { + return Qt.createQmlObject('import Linphone; '+name+'Gui{}', mainItem) + } Component { id: content - RowLayout { + ColumnLayout { spacing: 5 * DefaultStyle.dp - ColumnLayout { - Layout.fillWidth: true - spacing: 5 * DefaultStyle.dp - ColumnLayout { - Layout.preferredWidth: 341 * DefaultStyle.dp - Layout.maximumWidth: 341 * DefaultStyle.dp - spacing: 5 * DefaultStyle.dp - Text { - text: qsTr("Annuaires LDAP") - font: Typography.h4 - wrapMode: Text.WordWrap - color: DefaultStyle.main2_600 - Layout.fillWidth: true - } - Text { - text: qsTr("Ajouter vos annuaires LDAP pour pouvoir effectuer des recherches dans la magic search bar.") - font: Typography.p1s - wrapMode: Text.WordWrap - color: DefaultStyle.main2_600 - Layout.fillWidth: true - } - } - Item { - Layout.fillHeight: true - } + ContactsSettingsProviderLayout { + title: qsTr("Annuaires LDAP") + addText: qsTr("Ajouter un annuaire LDAP") + addTextDescription: qsTr("Ajouter vos annuaires LDAP pour pouvoir effectuer des recherches dans la magic search bar.") + editText: qsTr("Modifier un annuaire LDAP") + proxyModel: LdapProxy {} + newItemGui: createGuiObject('Ldap') + settingsLayout: layoutUrl("LdapSettingsLayout") + owner: mainItem + titleProperty: "server" + supportsEnableDisable: true + showAddButton: true } - ColumnLayout { - Layout.rightMargin: 25 * DefaultStyle.dp + Rectangle { Layout.fillWidth: true - Layout.fillHeight: true - spacing: 27 * DefaultStyle.dp - Layout.leftMargin: 76 * DefaultStyle.dp - Layout.topMargin: 16 * DefaultStyle.dp - Repeater { - model: LdapProxy { - id: proxyModel - } - RowLayout { - Layout.fillWidth: true - Layout.alignment: Qt.AlignLeft|Qt.AlignHCenter - spacing: 5 * DefaultStyle.dp - Text { - text: modelData.core.server - font: Typography.p2l - wrapMode: Text.WordWrap - color: DefaultStyle.main2_600 - Layout.fillWidth: true - Layout.leftMargin: 17 * DefaultStyle.dp - } - Item { - Layout.fillWidth: true - } - Button { - background: Item{} - icon.source: AppIcons.pencil - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - contentImageColor: DefaultStyle.main2_600 - onClicked: { - var ldapGui = Qt.createQmlObject('import Linphone - LdapGui{ - }', mainItem) - mainItem.container.push(layoutUrl("LdapSettingsLayout"), { - titleText: qsTr("Modifier un annuaire LDAP"), - model: modelData, - container: mainItem.container, - isNew: false}) - } - } - Switch { - id: switchButton - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - Layout.rightMargin: 17 * DefaultStyle.dp - checked: modelData.core["enabled"] - onToggled: { - binding.when = true - modelData.core.save() - } - } - Binding { - id: binding - target: modelData.core - property: "enabled" - value: switchButton.checked - when: false - } - } - onVisibleChanged: { - proxyModel.updateView() - } - Component.onCompleted: { - proxyModel.updateView() - } - } - RowLayout { - Layout.fillWidth: true - spacing: 5 * DefaultStyle.dp - Item { - Layout.fillWidth: true - } - Button { - Layout.alignment: Qt.AlignRight | Qt.AlignHCenter - text: qsTr("Ajouter") - onClicked: { - var ldapGui = Qt.createQmlObject('import Linphone - LdapGui{ - }', mainItem) - mainItem.container.push(layoutUrl("LdapSettingsLayout"), { - titleText: qsTr("Ajouter un annuaire LDAP"), - model: ldapGui, - container: mainItem.container, - isNew: true}) - } - } - } + Layout.topMargin: 35 * DefaultStyle.dp + Layout.bottomMargin: 9 * DefaultStyle.dp + height: 1 * DefaultStyle.dp + color: DefaultStyle.main2_500main + } + ContactsSettingsProviderLayout { + id: carddavProvider + title: qsTr("Carnet d'adresse CardDAV") + addText: qsTr("Ajouter un carnet d'adresse CardDAV") + addTextDescription: qsTr("Ajouter un carnet d’adresse CardDAV pour synchroniser vos contacts Linphone avec un carnet d’adresse tiers.") + editText: qsTr("Modifier un carnet d'adresse CardDAV") + proxyModel: CarddavProxy { + onModelReset: { + carddavProvider.showAddButton = carddavProvider.proxyModel.count == 0 + carddavProvider.newItemGui = createGuiObject('Carddav') + } + } + newItemGui: createGuiObject('Carddav') + settingsLayout: layoutUrl("CarddavSettingsLayout") + owner: mainItem + titleProperty: "displayName" + supportsEnableDisable: false } - } } } diff --git a/Linphone/view/Page/Layout/Settings/ContactsSettingsProviderLayout.qml b/Linphone/view/Page/Layout/Settings/ContactsSettingsProviderLayout.qml new file mode 100644 index 000000000..700bfd051 --- /dev/null +++ b/Linphone/view/Page/Layout/Settings/ContactsSettingsProviderLayout.qml @@ -0,0 +1,135 @@ + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls.Basic as Control +import SettingsCpp 1.0 +import Linphone + +RowLayout { + id: mainItem + + property string title + property string addText + property string addTextDescription + property string editText + property var newItemGui + property string settingsLayout + property var proxyModel + property var owner + property string titleProperty + property bool supportsEnableDisable + property bool showAddButton + + spacing: 5 * DefaultStyle.dp + ColumnLayout { + Layout.fillWidth: true + spacing: 5 * DefaultStyle.dp + ColumnLayout { + Layout.preferredWidth: 341 * DefaultStyle.dp + Layout.maximumWidth: 341 * DefaultStyle.dp + spacing: 5 * DefaultStyle.dp + Text { + text: mainItem.title + font: Typography.h4 + wrapMode: Text.WordWrap + color: DefaultStyle.main2_600 + Layout.fillWidth: true + } + Text { + text: mainItem.addTextDescription + font: Typography.p1s + wrapMode: Text.WordWrap + color: DefaultStyle.main2_600 + Layout.fillWidth: true + } + } + Item { + Layout.fillHeight: true + } + } + ColumnLayout { + Layout.rightMargin: 25 * DefaultStyle.dp + Layout.fillWidth: true + Layout.fillHeight: true + spacing: 27 * DefaultStyle.dp + Layout.leftMargin: 76 * DefaultStyle.dp + Layout.topMargin: 16 * DefaultStyle.dp + Repeater { + model: mainItem.proxyModel + RowLayout { + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft|Qt.AlignHCenter + spacing: 5 * DefaultStyle.dp + Text { + text: modelData.core[titleProperty] + font: Typography.p2l + wrapMode: Text.WordWrap + color: DefaultStyle.main2_600 + Layout.fillWidth: true + Layout.leftMargin: 17 * DefaultStyle.dp + } + Item { + Layout.fillWidth: true + } + Button { + background: Item{} + icon.source: AppIcons.pencil + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + contentImageColor: DefaultStyle.main2_600 + onClicked: { + mainItem.owner.container.push(mainItem.settingsLayout, { + titleText: mainItem.editText, + model: modelData, + container: mainItem.owner.container, + isNew: false}) + } + } + Switch { + id: switchButton + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.rightMargin: 17 * DefaultStyle.dp + checked: supportsEnableDisable && modelData.core["enabled"] + visible: supportsEnableDisable + onToggled: { + binding.when = true + modelData.core.save() + } + } + Binding { + id: binding + target: modelData.core + property: "enabled" + value: switchButton.checked + when: false + } + } + onVisibleChanged: { + proxyModel.updateView() + } + Component.onCompleted: { + proxyModel.updateView() + } + } + RowLayout { + Layout.fillWidth: true + spacing: 5 * DefaultStyle.dp + Item { + Layout.fillWidth: true + } + Button { + Layout.preferredHeight: 47 * DefaultStyle.dp + Layout.alignment: Qt.AlignRight | Qt.AlignHCenter + text: qsTr("Ajouter") + visible: mainItem.showAddButton + onClicked: { + mainItem.owner.container.push(mainItem.settingsLayout, { + titleText: mainItem.addText, + model: mainItem.newItemGui, + container: mainItem.owner.container, + isNew: true}) + } + } + } + } +}