diff --git a/Linphone/core/account/AccountCore.cpp b/Linphone/core/account/AccountCore.cpp index f27d92543..7345b9c81 100644 --- a/Linphone/core/account/AccountCore.cpp +++ b/Linphone/core/account/AccountCore.cpp @@ -46,6 +46,8 @@ AccountCore::AccountCore(const std::shared_ptr &account) : QO mPictureUri = Utils::coreStringToAppString(params->getPictureUri()); mRegistrationState = LinphoneEnums::fromLinphone(account->getState()); mIsDefaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount() == account; + // mUnreadNotifications = account->getUnreadChatMessageCount() + account->getMissedCallsCount(); // TODO + mUnreadNotifications = account->getMissedCallsCount(); // Add listener mAccountModel = Utils::makeQObject_ptr(account); // OK @@ -58,30 +60,34 @@ AccountCore::~AccountCore() { } void AccountCore::setSelf(QSharedPointer me) { - mAccountModelConnection = QSharedPointer( - new SafeConnection(me.objectCast(), std::dynamic_pointer_cast(mAccountModel))); - mAccountModelConnection->makeConnect(mAccountModel.get(), &AccountModel::registrationStateChanged, - [this](const std::shared_ptr &account, - linphone::RegistrationState state, const std::string &message) { - mAccountModelConnection->invokeToCore([this, account, state, message]() { - this->onRegistrationStateChanged(account, state, message); - }); - }); - // From Model - mAccountModelConnection->makeConnect( - mAccountModel.get(), &AccountModel::defaultAccountChanged, [this](bool isDefault) { - mAccountModelConnection->invokeToCore([this, isDefault]() { this->onDefaultAccountChanged(isDefault); }); + mAccountModelConnection = QSharedPointer>( + new SafeConnection(me, mAccountModel)); + mAccountModelConnection->makeConnectToModel( + &AccountModel::registrationStateChanged, [this](const std::shared_ptr &account, + linphone::RegistrationState state, const std::string &message) { + mAccountModelConnection->invokeToCore( + [this, account, state, message]() { this->onRegistrationStateChanged(account, state, message); }); }); + // From Model + mAccountModelConnection->makeConnectToModel(&AccountModel::defaultAccountChanged, [this](bool isDefault) { + mAccountModelConnection->invokeToCore([this, isDefault]() { this->onDefaultAccountChanged(isDefault); }); + }); - mAccountModelConnection->makeConnect(mAccountModel.get(), &AccountModel::pictureUriChanged, [this](QString uri) { + mAccountModelConnection->makeConnectToModel(&AccountModel::pictureUriChanged, [this](QString uri) { mAccountModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); }); }); + mAccountModelConnection->makeConnectToModel( + &AccountModel::unreadNotificationsChanged, [this](int unreadMessagesCount, int unreadCallsCount) { + mAccountModelConnection->invokeToCore([this, unreadMessagesCount, unreadCallsCount]() { + this->setUnreadNotifications(unreadMessagesCount + unreadCallsCount); + }); + }); // From GUI - mAccountModelConnection->makeConnect(this, &AccountCore::lSetPictureUri, [this](QString uri) { + mAccountModelConnection->makeConnectToCore(&AccountCore::lSetPictureUri, [this](QString uri) { mAccountModelConnection->invokeToModel([this, uri]() { mAccountModel->setPictureUri(uri); }); }); - mAccountModelConnection->makeConnect(this, &AccountCore::lSetDefaultAccount, [this]() { + mAccountModelConnection->makeConnectToCore(&AccountCore::lSetDefaultAccount, [this]() { mAccountModelConnection->invokeToModel([this]() { mAccountModel->setDefault(); }); }); } @@ -106,6 +112,16 @@ bool AccountCore::getIsDefaultAccount() const { return mIsDefaultAccount; } +int AccountCore::getUnreadNotifications() const { + return mUnreadNotifications; +} +void AccountCore::setUnreadNotifications(int unread) { + if (mUnreadNotifications != unread) { + mUnreadNotifications = unread; + emit unreadNotificationsChanged(unread); + } +} + void AccountCore::onRegistrationStateChanged(const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message) { @@ -124,3 +140,7 @@ void AccountCore::onPictureUriChanged(QString uri) { mPictureUri = uri; emit pictureUriChanged(); } + +void AccountCore::removeAccount() { + mAccountModelConnection->invokeToModel([this]() { mAccountModel->removeAccount(); }); +} diff --git a/Linphone/core/account/AccountCore.hpp b/Linphone/core/account/AccountCore.hpp index fa1de1184..50e17c72e 100644 --- a/Linphone/core/account/AccountCore.hpp +++ b/Linphone/core/account/AccountCore.hpp @@ -37,6 +37,7 @@ class AccountCore : public QObject, public AbstractObject { Q_PROPERTY( LinphoneEnums::RegistrationState registrationState READ getRegistrationState NOTIFY registrationStateChanged) Q_PROPERTY(bool isDefaultAccount READ getIsDefaultAccount NOTIFY defaultAccountChanged) + Q_PROPERTY(int unreadNotifications READ getUnreadNotifications NOTIFY unreadNotificationsChanged) public: static QSharedPointer create(const std::shared_ptr &account); @@ -50,6 +51,8 @@ public: QString getPictureUri() const; LinphoneEnums::RegistrationState getRegistrationState() const; bool getIsDefaultAccount() const; + int getUnreadNotifications() const; + void setUnreadNotifications(int unread); void onPictureUriChanged(QString uri); void onRegistrationStateChanged(const std::shared_ptr &account, @@ -57,11 +60,13 @@ public: const std::string &message); void onDefaultAccountChanged(bool isDefault); + Q_INVOKABLE void removeAccount(); signals: void pictureUriChanged(); void registrationStateChanged(const QString &message); void defaultAccountChanged(bool isDefault); + void unreadNotificationsChanged(int unreadNotifications); // Account requests void lSetPictureUri(QString pictureUri); @@ -73,8 +78,9 @@ private: QString mPictureUri; bool mIsDefaultAccount = false; LinphoneEnums::RegistrationState mRegistrationState; + int mUnreadNotifications = 0; std::shared_ptr mAccountModel; - QSharedPointer mAccountModelConnection; + QSharedPointer> mAccountModelConnection; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/core/account/AccountGui.cpp b/Linphone/core/account/AccountGui.cpp index 7ec4c92fa..52b64d1fb 100644 --- a/Linphone/core/account/AccountGui.cpp +++ b/Linphone/core/account/AccountGui.cpp @@ -24,7 +24,6 @@ DEFINE_ABSTRACT_OBJECT(AccountGui) AccountGui::AccountGui(QSharedPointer core) { - qDebug() << "[AccountGui] new" << this; App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); mCore = core; if (isInLinphoneThread()) moveToThread(App::getInstance()->thread()); @@ -32,7 +31,6 @@ AccountGui::AccountGui(QSharedPointer core) { AccountGui::~AccountGui() { mustBeInMainThread("~" + getClassName()); - qDebug() << "[AccountGui] delete" << this; } AccountCore *AccountGui::getCore() const { diff --git a/Linphone/core/account/AccountList.cpp b/Linphone/core/account/AccountList.cpp index 5cc089a90..3b837b5ed 100644 --- a/Linphone/core/account/AccountList.cpp +++ b/Linphone/core/account/AccountList.cpp @@ -37,51 +37,54 @@ QSharedPointer AccountList::create() { } AccountList::AccountList(QObject *parent) : ListProxy(parent) { - qDebug() << "[AccountList] new" << this; mustBeInMainThread(getClassName()); connect(CoreModel::getInstance().get(), &CoreModel::accountAdded, this, &AccountList::lUpdate); connect(CoreModel::getInstance().get(), &CoreModel::accountRemoved, this, &AccountList::lUpdate); } AccountList::~AccountList() { - qDebug() << "[AccountList] delete" << this; mustBeInMainThread("~" + getClassName()); + mModelConnection = nullptr; } void AccountList::setSelf(QSharedPointer me) { - mModelConnection = QSharedPointer( - new SafeConnection(me.objectCast(), std::dynamic_pointer_cast(CoreModel::getInstance())), - &QObject::deleteLater); - mModelConnection->makeConnect(this, &AccountList::lUpdate, [this]() { + mModelConnection = QSharedPointer>( + new SafeConnection(me, CoreModel::getInstance()), &QObject::deleteLater); + + mModelConnection->makeConnectToCore(&AccountList::lUpdate, [this]() { mModelConnection->invokeToModel([this]() { + // Avoid copy to lambdas QList> *accounts = new QList>(); - // Model thread. mustBeInLinphoneThread(getClassName()); auto linphoneAccounts = CoreModel::getInstance()->getCore()->getAccountList(); + auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount(); + QSharedPointer defaultAccountCore; for (auto it : linphoneAccounts) { auto model = AccountCore::create(it); + if (it == defaultAccount) defaultAccountCore = AccountCore::create(defaultAccount); accounts->push_back(model); } - mModelConnection->invokeToCore([this, accounts]() { + mModelConnection->invokeToCore([this, accounts, defaultAccountCore]() { mustBeInMainThread(getClassName()); resetData(); add(*accounts); setHaveAccount(accounts->size() > 0); + setDefaultAccount(defaultAccountCore); delete accounts; }); }); }); - mModelConnection->makeConnect(CoreModel::getInstance().get(), &CoreModel::defaultAccountChanged, - [this]() { mModelConnection->invokeToCore([this]() { defaultAccountChanged(); }); }); + mModelConnection->makeConnectToModel( + &CoreModel::defaultAccountChanged, + [this](const std::shared_ptr &core, const std::shared_ptr &account) { + auto model = AccountCore::create(account); + mModelConnection->invokeToCore([this, model]() { setDefaultAccount(model); }); + }); lUpdate(); } QSharedPointer AccountList::getDefaultAccountCore() const { - for (auto it : mList) { - auto account = it.objectCast(); - if (account->getIsDefaultAccount()) return account; - } - return nullptr; + return mDefaultAccount; } AccountGui *AccountList::getDefaultAccount() const { @@ -89,6 +92,13 @@ AccountGui *AccountList::getDefaultAccount() const { if (account) return new AccountGui(account); else return nullptr; } + +void AccountList::setDefaultAccount(QSharedPointer account) { + if (mDefaultAccount != account) { + mDefaultAccount = account; + emit defaultAccountChanged(); + } +} bool AccountList::getHaveAccount() const { return mHaveAccount; } diff --git a/Linphone/core/account/AccountList.hpp b/Linphone/core/account/AccountList.hpp index f99fb1efe..7b8febce2 100644 --- a/Linphone/core/account/AccountList.hpp +++ b/Linphone/core/account/AccountList.hpp @@ -28,6 +28,7 @@ class AccountGui; class AccountCore; +class CoreModel; // ============================================================================= class AccountList : public ListProxy, public AbstractObject { @@ -41,6 +42,7 @@ public: AccountGui *getDefaultAccount() const; QSharedPointer getDefaultAccountCore() const; + void setDefaultAccount(QSharedPointer account); bool getHaveAccount() const; void setHaveAccount(bool haveAccount); @@ -53,7 +55,8 @@ signals: private: bool mHaveAccount = false; - QSharedPointer mModelConnection; + QSharedPointer mDefaultAccount; + QSharedPointer> mModelConnection; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/core/account/AccountProxy.cpp b/Linphone/core/account/AccountProxy.cpp index 256dfb275..d6e36aa76 100644 --- a/Linphone/core/account/AccountProxy.cpp +++ b/Linphone/core/account/AccountProxy.cpp @@ -23,7 +23,6 @@ #include "AccountList.hpp" AccountProxy::AccountProxy(QObject *parent) : SortFilterProxy(parent) { - qDebug() << "[AccountProxy] new" << this; mList = AccountList::create(); connect(mList.get(), &AccountList::countChanged, this, &AccountProxy::resetDefaultAccount); connect(mList.get(), &AccountList::defaultAccountChanged, this, &AccountProxy::resetDefaultAccount); @@ -33,7 +32,7 @@ AccountProxy::AccountProxy(QObject *parent) : SortFilterProxy(parent) { } AccountProxy::~AccountProxy() { - qDebug() << "[AccountProxy] delete" << this; + setSourceModel(nullptr); } QString AccountProxy::getFilterText() const { @@ -59,7 +58,7 @@ void AccountProxy::setDefaultAccount(AccountGui *account) { // Reset the default account to let UI build its new object if needed. void AccountProxy::resetDefaultAccount() { mDefaultAccount = nullptr; - this->defaultAccountChanged(); // Warn the UI + emit this->defaultAccountChanged(); // Warn the UI } bool AccountProxy::getHaveAccount() const { diff --git a/Linphone/core/call/CallCore.cpp b/Linphone/core/call/CallCore.cpp index f20e2ed3a..8c6667f63 100644 --- a/Linphone/core/call/CallCore.cpp +++ b/Linphone/core/call/CallCore.cpp @@ -67,13 +67,12 @@ CallCore::~CallCore() { } void CallCore::setSelf(QSharedPointer me) { - mAccountModelConnection = QSharedPointer( - new SafeConnection(me.objectCast(), std::dynamic_pointer_cast(mCallModel)), - &QObject::deleteLater); - mAccountModelConnection->makeConnect(this, &CallCore::lSetMicrophoneMuted, [this](bool isMuted) { + mAccountModelConnection = QSharedPointer>( + new SafeConnection(me, mCallModel), &QObject::deleteLater); + mAccountModelConnection->makeConnectToCore(&CallCore::lSetMicrophoneMuted, [this](bool isMuted) { mAccountModelConnection->invokeToModel([this, isMuted]() { mCallModel->setMicrophoneMuted(isMuted); }); }); - mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::microphoneMutedChanged, [this](bool isMuted) { + mAccountModelConnection->makeConnectToModel(&CallModel::microphoneMutedChanged, [this](bool isMuted) { mAccountModelConnection->invokeToCore([this, isMuted]() { setMicrophoneMuted(isMuted); }); }); // mAccountModelConnection->makeConnect(this, &CallCore::lSetSpeakerMuted, [this](bool isMuted) { @@ -82,37 +81,37 @@ void CallCore::setSelf(QSharedPointer me) { // mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::speakerMutedChanged, [this](bool isMuted) { // mAccountModelConnection->invokeToCore([this, isMuted]() { setSpeakerMuted(isMuted); }); // }); - mAccountModelConnection->makeConnect(this, &CallCore::lSetCameraEnabled, [this](bool enabled) { + mAccountModelConnection->makeConnectToCore(&CallCore::lSetCameraEnabled, [this](bool enabled) { mAccountModelConnection->invokeToModel([this, enabled]() { mCallModel->setCameraEnabled(enabled); }); }); - mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::cameraEnabledChanged, [this](bool enabled) { + mAccountModelConnection->makeConnectToModel(&CallModel::cameraEnabledChanged, [this](bool enabled) { mAccountModelConnection->invokeToCore([this, enabled]() { setCameraEnabled(enabled); }); }); - mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::durationChanged, [this](int duration) { + mAccountModelConnection->makeConnectToModel(&CallModel::durationChanged, [this](int duration) { mAccountModelConnection->invokeToCore([this, duration]() { setDuration(duration); }); }); - connect(mCallModel.get(), &CallModel::stateChanged, this, - [this](linphone::Call::State state, const std::string &message) { - mAccountModelConnection->invokeToCore([this, state, message]() { - setState(LinphoneEnums::fromLinphone(state), Utils::coreStringToAppString(message)); - }); - }); - connect(mCallModel.get(), &CallModel::statusChanged, this, [this](linphone::Call::Status status) { + mAccountModelConnection->makeConnectToModel( + &CallModel::stateChanged, [this](linphone::Call::State state, const std::string &message) { + mAccountModelConnection->invokeToCore([this, state, message]() { + setState(LinphoneEnums::fromLinphone(state), Utils::coreStringToAppString(message)); + }); + }); + mAccountModelConnection->makeConnectToModel(&CallModel::statusChanged, [this](linphone::Call::Status status) { mAccountModelConnection->invokeToCore([this, status]() { setStatus(LinphoneEnums::fromLinphone(status)); }); }); - mAccountModelConnection->makeConnect(this, &CallCore::lSetPaused, [this](bool paused) { + mAccountModelConnection->makeConnectToCore(&CallCore::lSetPaused, [this](bool paused) { mAccountModelConnection->invokeToModel([this, paused]() { mCallModel->setPaused(paused); }); }); - mAccountModelConnection->makeConnect(mCallModel.get(), &CallModel::pausedChanged, [this](bool paused) { + mAccountModelConnection->makeConnectToModel(&CallModel::pausedChanged, [this](bool paused) { mAccountModelConnection->invokeToCore([this, paused]() { setPaused(paused); }); }); - mAccountModelConnection->makeConnect(this, &CallCore::lTransferCall, [this](const QString &address) { + mAccountModelConnection->makeConnectToCore(&CallCore::lTransferCall, [this](const QString &address) { mAccountModelConnection->invokeToModel( [this, address]() { mCallModel->transferTo(ToolModel::interpretUrl(address)); }); }); - mAccountModelConnection->makeConnect( - mCallModel.get(), &CallModel::transferStateChanged, + mAccountModelConnection->makeConnectToModel( + &CallModel::transferStateChanged, [this](const std::shared_ptr &call, linphone::Call::State state) { mAccountModelConnection->invokeToCore([this, state]() { QString message; @@ -122,8 +121,8 @@ void CallCore::setSelf(QSharedPointer me) { setTransferState(LinphoneEnums::fromLinphone(state), message); }); }); - mAccountModelConnection->makeConnect( - mCallModel.get(), &CallModel::encryptionChanged, + mAccountModelConnection->makeConnectToModel( + &CallModel::encryptionChanged, [this](const std::shared_ptr &call, bool on, const std::string &authenticationToken) { auto encryption = LinphoneEnums::fromLinphone(call->getCurrentParams()->getMediaEncryption()); auto tokenVerified = mCallModel->getAuthenticationTokenVerified(); @@ -133,13 +132,12 @@ void CallCore::setSelf(QSharedPointer me) { encryption == LinphoneEnums::MediaEncryption::Dtls); }); }); - mAccountModelConnection->makeConnect(this, &CallCore::lAccept, [this](bool withVideo) { + mAccountModelConnection->makeConnectToCore(&CallCore::lAccept, [this](bool withVideo) { mAccountModelConnection->invokeToModel([this, withVideo]() { mCallModel->accept(withVideo); }); }); - mAccountModelConnection->makeConnect(this, &CallCore::lDecline, [this]() { - mAccountModelConnection->invokeToModel([this]() { mCallModel->decline(); }); - }); - mAccountModelConnection->makeConnect(this, &CallCore::lTerminate, [this]() { + mAccountModelConnection->makeConnectToCore( + &CallCore::lDecline, [this]() { mAccountModelConnection->invokeToModel([this]() { mCallModel->decline(); }); }); + mAccountModelConnection->makeConnectToCore(&CallCore::lTerminate, [this]() { mAccountModelConnection->invokeToModel([this]() { mCallModel->terminate(); }); }); } @@ -255,4 +253,4 @@ void CallCore::setTransferState(LinphoneEnums::CallState state, const QString &m if (state == LinphoneEnums::CallState::Error) setLastErrorMessage(message); emit transferStateChanged(); } -} \ No newline at end of file +} diff --git a/Linphone/core/call/CallCore.hpp b/Linphone/core/call/CallCore.hpp index de056d003..48a1d7646 100644 --- a/Linphone/core/call/CallCore.hpp +++ b/Linphone/core/call/CallCore.hpp @@ -23,12 +23,11 @@ #include "model/call/CallModel.hpp" #include "tool/LinphoneEnums.hpp" +#include "tool/thread/SafeConnection.hpp" #include #include #include -class SafeConnection; - class CallCore : public QObject, public AbstractObject { Q_OBJECT @@ -138,7 +137,7 @@ private: bool mMicrophoneMuted; bool mCameraEnabled; bool mPaused = false; - QSharedPointer mAccountModelConnection; + QSharedPointer> mAccountModelConnection; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/core/friend/FriendCore.cpp b/Linphone/core/friend/FriendCore.cpp index b9b465929..9c0653bde 100644 --- a/Linphone/core/friend/FriendCore.cpp +++ b/Linphone/core/friend/FriendCore.cpp @@ -56,35 +56,36 @@ FriendCore::FriendCore(const FriendCore &friendCore) { FriendCore::~FriendCore() { } -void FriendCore::setSelf(QSharedPointer me) { - setSelf(me.objectCast()); +void FriendCore::setSelf(SafeSharedPointer me) { + setSelf(me.mQDataWeak.lock()); } - -void FriendCore::setSelf(SafeSharedPointer me) { - if (mFriendModel) { - mFriendModelConnection = QSharedPointer( - new SafeConnection(me, std::dynamic_pointer_cast(mFriendModel)), &QObject::deleteLater); - mFriendModelConnection->makeConnect( - mFriendModel.get(), &FriendModel::presenceReceived, - [this](LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp) { - mFriendModelConnection->invokeToCore([this, consolidatedPresence, presenceTimestamp]() { - setConsolidatedPresence(consolidatedPresence); - setPresenceTimestamp(presenceTimestamp); +void FriendCore::setSelf(QSharedPointer me) { + if (me) { + if (mFriendModel) { + mCoreModelConnection = nullptr; // No more needed + mFriendModelConnection = QSharedPointer>( + new SafeConnection(me, mFriendModel), &QObject::deleteLater); + mFriendModelConnection->makeConnectToModel( + &FriendModel::presenceReceived, + [this](LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp) { + mFriendModelConnection->invokeToCore([this, consolidatedPresence, presenceTimestamp]() { + setConsolidatedPresence(consolidatedPresence); + setPresenceTimestamp(presenceTimestamp); + }); }); - }); - mFriendModelConnection->makeConnect(mFriendModel.get(), &FriendModel::pictureUriChanged, [this](QString uri) { - mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); }); - }); + mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](QString uri) { + mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); }); + }); - // From GUI - mFriendModelConnection->makeConnect(this, &FriendCore::lSetPictureUri, [this](QString uri) { - mFriendModelConnection->invokeToModel([this, uri]() { mFriendModel->setPictureUri(uri); }); - }); + // From GUI + mFriendModelConnection->makeConnectToCore(&FriendCore::lSetPictureUri, [this](QString uri) { + mFriendModelConnection->invokeToModel([this, uri]() { mFriendModel->setPictureUri(uri); }); + }); - } else { // Create - mFriendModelConnection = QSharedPointer( - new SafeConnection(me, std::dynamic_pointer_cast(CoreModel::getInstance())), - &QObject::deleteLater); + } else { // Create + mCoreModelConnection = QSharedPointer>( + new SafeConnection(me, CoreModel::getInstance()), &QObject::deleteLater); + } } } @@ -200,7 +201,7 @@ void FriendCore::save() { // Save Value mFriendModelConnection->invokeToCore([this]() { saved(); }); }); } else { // Creation - mFriendModelConnection->invokeToModel([this, thisCopy]() { + mCoreModelConnection->invokeToModel([this, thisCopy]() { auto core = CoreModel::getInstance()->getCore(); auto contact = core->createFriend(); thisCopy->writeInto(contact); @@ -212,8 +213,8 @@ void FriendCore::save() { // Save Value core->getDefaultFriendList()->updateSubscriptions(); } emit CoreModel::getInstance()->friendAdded(); - mFriendModelConnection->invokeToCore([this, created]() { - if (created) setSelf(mFriendModelConnection->mCore); + mCoreModelConnection->invokeToCore([this, created]() { + if (created) setSelf(mCoreModelConnection->mCore); setIsSaved(created); }); }); diff --git a/Linphone/core/friend/FriendCore.hpp b/Linphone/core/friend/FriendCore.hpp index f9d0e6884..eb42d8f06 100644 --- a/Linphone/core/friend/FriendCore.hpp +++ b/Linphone/core/friend/FriendCore.hpp @@ -23,18 +23,19 @@ #include "model/friend/FriendModel.hpp" #include "tool/LinphoneEnums.hpp" +#include "tool/thread/SafeConnection.hpp" #include "tool/thread/SafeSharedPointer.hpp" #include #include #include #include -class SafeConnection; - // This object is defferent from usual Core. It set internal data from directly from GUI. // Values are saved on request. // This allow revert feature. +class CoreModel; + class FriendCore : public QObject, public AbstractObject { Q_OBJECT @@ -53,7 +54,7 @@ public: FriendCore(const FriendCore &friendCore); ~FriendCore(); void setSelf(QSharedPointer me); - void setSelf(SafeSharedPointer me); + void setSelf(SafeSharedPointer me); void reset(const FriendCore &contact); QString getName() const; @@ -106,7 +107,8 @@ protected: QString mPictureUri; bool mIsSaved; std::shared_ptr mFriendModel; - QSharedPointer mFriendModelConnection; + QSharedPointer> mFriendModelConnection; + QSharedPointer> mCoreModelConnection; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/core/path/Paths.cpp b/Linphone/core/path/Paths.cpp index f63293097..670566ef9 100644 --- a/Linphone/core/path/Paths.cpp +++ b/Linphone/core/path/Paths.cpp @@ -162,10 +162,6 @@ static inline QString getAppRootCaFilePath() { return ""; } -static inline QString getAppFriendsFilePath() { - return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + Constants::PathFriendsList; -} - static inline QString getAppMessageHistoryFilePath() { return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + Constants::PathMessageHistoryList; } @@ -243,10 +239,6 @@ QString Paths::getFactoryConfigFilePath() { return getReadableFilePath(getAppFactoryConfigFilePath()); } -QString Paths::getFriendsListFilePath() { - return getWritableFilePath(getAppFriendsFilePath()); -} - QString Paths::getDownloadDirPath() { return getWritableDirPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + QDir::separator()); } diff --git a/Linphone/core/path/Paths.hpp b/Linphone/core/path/Paths.hpp index 57b84469b..94d3b3abb 100644 --- a/Linphone/core/path/Paths.hpp +++ b/Linphone/core/path/Paths.hpp @@ -39,7 +39,6 @@ QString getConfigFilePath(const QString &configPath = QString(), bool writable = QString getDatabaseFilePath(); QString getDownloadDirPath(); QString getFactoryConfigFilePath(); -QString getFriendsListFilePath(); QString getLimeDatabasePath(); QString getLogsDirPath(); QString getMessageHistoryFilePath(); diff --git a/Linphone/core/search/MagicSearchList.cpp b/Linphone/core/search/MagicSearchList.cpp index a23cc5008..f304d05fa 100644 --- a/Linphone/core/search/MagicSearchList.cpp +++ b/Linphone/core/search/MagicSearchList.cpp @@ -57,38 +57,37 @@ MagicSearchList::~MagicSearchList() { } void MagicSearchList::setSelf(QSharedPointer me) { - mModelConnection = QSharedPointer( - new SafeConnection(me.objectCast(), std::dynamic_pointer_cast(mMagicSearch)), - &QObject::deleteLater); - mModelConnection->makeConnect(this, &MagicSearchList::lSearch, [this](QString filter) { + mModelConnection = QSharedPointer>( + new SafeConnection(me, mMagicSearch), &QObject::deleteLater); + mModelConnection->makeConnectToCore(&MagicSearchList::lSearch, [this](QString filter) { mModelConnection->invokeToModel([this, filter]() { mMagicSearch->search(filter); }); }); - mModelConnection->makeConnect(this, &MagicSearchList::lSetSourceFlags, [this](int flags) { + mModelConnection->makeConnectToCore(&MagicSearchList::lSetSourceFlags, [this](int flags) { mModelConnection->invokeToModel([this, flags]() { mMagicSearch->setSourceFlags(flags); }); }); - mModelConnection->makeConnect(mMagicSearch.get(), &MagicSearchModel::sourceFlagsChanged, [this](int flags) { + mModelConnection->makeConnectToModel(&MagicSearchModel::sourceFlagsChanged, [this](int flags) { mModelConnection->invokeToCore([this, flags]() { setSourceFlags(flags); }); }); - mModelConnection->makeConnect(mMagicSearch.get(), &MagicSearchModel::aggregationFlagChanged, - [this](LinphoneEnums::MagicSearchAggregation flag) { - mModelConnection->invokeToCore([this, flag]() { setAggregationFlag(flag); }); - }); + mModelConnection->makeConnectToModel( + &MagicSearchModel::aggregationFlagChanged, [this](LinphoneEnums::MagicSearchAggregation flag) { + mModelConnection->invokeToCore([this, flag]() { setAggregationFlag(flag); }); + }); - mModelConnection->makeConnect(mMagicSearch.get(), &MagicSearchModel::searchResultsReceived, - [this](const std::list> &results) { - auto *contacts = new QList>(); - for (auto it : results) { - QSharedPointer contact; - if (it->getFriend()) { - contact = FriendCore::create(it->getFriend()); - contacts->append(contact); - } - } - mModelConnection->invokeToCore([this, contacts]() { - setResults(*contacts); - delete contacts; - }); - }); + mModelConnection->makeConnectToModel(&MagicSearchModel::searchResultsReceived, + [this](const std::list> &results) { + auto *contacts = new QList>(); + for (auto it : results) { + QSharedPointer contact; + if (it->getFriend()) { + contact = FriendCore::create(it->getFriend()); + contacts->append(contact); + } + } + mModelConnection->invokeToCore([this, contacts]() { + setResults(*contacts); + delete contacts; + }); + }); } void MagicSearchList::setResults(const QList> &contacts) { diff --git a/Linphone/core/search/MagicSearchList.hpp b/Linphone/core/search/MagicSearchList.hpp index 672b8bafd..743eafef4 100644 --- a/Linphone/core/search/MagicSearchList.hpp +++ b/Linphone/core/search/MagicSearchList.hpp @@ -28,6 +28,7 @@ #include class FriendCore; +class CoreModel; // ============================================================================= // Return FriendGui list to Ui @@ -63,8 +64,8 @@ private: LinphoneEnums::MagicSearchAggregation mAggregationFlag; std::shared_ptr mMagicSearch; - QSharedPointer mModelConnection; - QSharedPointer mCoreModelConnection; + QSharedPointer> mModelConnection; + QSharedPointer> mCoreModelConnection; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/model/account/AccountModel.cpp b/Linphone/model/account/AccountModel.cpp index 5b4376055..0dfb4b819 100644 --- a/Linphone/model/account/AccountModel.cpp +++ b/Linphone/model/account/AccountModel.cpp @@ -38,6 +38,11 @@ AccountModel::AccountModel(const std::shared_ptr &account, QO // Hack because Account doesn't provide callbacks on updated data connect(this, &AccountModel::defaultAccountChanged, this, [this]() { emit pictureUriChanged(Utils::coreStringToAppString(mMonitor->getParams()->getPictureUri())); }); + + connect(CoreModel::getInstance().get(), &CoreModel::unreadNotificationsChanged, this, [this]() { + emit unreadNotificationsChanged(0 /*mMonitor->getUnreadChatMessageCount()*/, + mMonitor->getMissedCallsCount()); // TODO + }); } AccountModel::~AccountModel() { @@ -80,3 +85,7 @@ void AccountModel::setDefault() { auto core = CoreModel::getInstance()->getCore(); core->setDefaultAccount(mMonitor); } + +void AccountModel::removeAccount() { + CoreModel::getInstance()->getCore()->removeAccount(mMonitor); +} diff --git a/Linphone/model/account/AccountModel.hpp b/Linphone/model/account/AccountModel.hpp index bc648f9c3..940cb4021 100644 --- a/Linphone/model/account/AccountModel.hpp +++ b/Linphone/model/account/AccountModel.hpp @@ -42,6 +42,7 @@ public: void setPictureUri(QString uri); void setDefault(); + void removeAccount(); signals: void registrationStateChanged(const std::shared_ptr &account, @@ -50,6 +51,7 @@ signals: void defaultAccountChanged(bool isDefault); void pictureUriChanged(QString uri); + void unreadNotificationsChanged(int unreadMessagesCount, int unreadCallsCount); private: DECLARE_ABSTRACT_OBJECT diff --git a/Linphone/model/core/CoreModel.cpp b/Linphone/model/core/CoreModel.cpp index 1f44bc02d..4550ae7bf 100644 --- a/Linphone/model/core/CoreModel.cpp +++ b/Linphone/model/core/CoreModel.cpp @@ -63,18 +63,23 @@ std::shared_ptr CoreModel::create(const QString &configPath, QThread void CoreModel::start() { mIterateTimer = new QTimer(this); mIterateTimer->setInterval(30); - connect(mIterateTimer, &QTimer::timeout, [this]() { mCore->iterate(); }); + connect(mIterateTimer, &QTimer::timeout, [this]() { + static int iterateCount = 0; + if (iterateCount != 0) qCritical() << log().arg("Multi Iterate ! "); + ++iterateCount; + mCore->iterate(); + --iterateCount; + }); setPathBeforeCreation(); mCore = linphone::Factory::get()->createCore(Utils::appStringToCoreString(Paths::getConfigFilePath(mConfigPath)), Utils::appStringToCoreString(Paths::getFactoryConfigFilePath()), nullptr); setMonitor(mCore); setPathsAfterCreation(); - mCore->start(); - setPathAfterStart(); mCore->enableFriendListSubscription(true); mCore->enableRecordAware(true); - mCore->getCallsNb(); + mCore->start(); + setPathAfterStart(); mIterateTimer->start(); } // ----------------------------------------------------------------------------- @@ -92,7 +97,7 @@ void CoreModel::setConfigPath(QString path) { if (mConfigPath != path) { mConfigPath = path; if (!mCore) { - qWarning() << "[CoreModel] Setting config path after core creation is not yet supported"; + qWarning() << log().arg("Setting config path after core creation is not yet supported"); } } } @@ -118,9 +123,6 @@ void CoreModel::setPathBeforeCreation() { } void CoreModel::setPathsAfterCreation() { - QString friendsDb = Paths::getFriendsListFilePath(); - qInfo() << QStringLiteral("[CoreModel] Set Database `Friends` path: `%1`").arg(friendsDb); - mCore->setFriendsDatabasePath(Utils::appStringToCoreString(friendsDb)); } void CoreModel::setPathAfterStart() { @@ -169,6 +171,7 @@ void CoreModel::onCallEncryptionChanged(const std::shared_ptr &c } void CoreModel::onCallLogUpdated(const std::shared_ptr &core, const std::shared_ptr &callLog) { + if (callLog && callLog->getStatus() == linphone::Call::Status::Missed) emit unreadNotificationsChanged(); emit callLogUpdated(core, callLog); } void CoreModel::onCallStateChanged(const std::shared_ptr &core, @@ -242,11 +245,13 @@ void CoreModel::onLogCollectionUploadProgressIndication(const std::shared_ptr
  • &core, const std::shared_ptr &room, const std::shared_ptr &message) { + emit unreadNotificationsChanged(); emit messageReceived(core, room, message); } void CoreModel::onMessagesReceived(const std::shared_ptr &core, const std::shared_ptr &room, const std::list> &messages) { + emit unreadNotificationsChanged(); emit messagesReceived(core, room, messages); } diff --git a/Linphone/model/core/CoreModel.hpp b/Linphone/model/core/CoreModel.hpp index 721df83bb..8c145cd40 100644 --- a/Linphone/model/core/CoreModel.hpp +++ b/Linphone/model/core/CoreModel.hpp @@ -58,6 +58,7 @@ signals: void loggerInitialized(); void friendAdded(); void friendRemoved(); + void unreadNotificationsChanged(); private: QString mConfigPath; diff --git a/Linphone/model/listener/Listener.hpp b/Linphone/model/listener/Listener.hpp index ef9885149..64399febe 100644 --- a/Linphone/model/listener/Listener.hpp +++ b/Linphone/model/listener/Listener.hpp @@ -44,7 +44,6 @@ public: setMonitor(monitor); } ~Listener() { - qDebug() << "Destroying Listener"; setSelf(nullptr); } virtual void onRemoveListener() { diff --git a/Linphone/model/object/VariantObject.cpp b/Linphone/model/object/VariantObject.cpp index 684cda536..b12d87561 100644 --- a/Linphone/model/object/VariantObject.cpp +++ b/Linphone/model/object/VariantObject.cpp @@ -33,17 +33,16 @@ VariantObject::VariantObject(QVariant defaultValue, QObject *parent) { mModelObject = QSharedPointer::create(); mModelObject->moveToThread(CoreModel::getInstance()->thread()); - mConnection = QSharedPointer( - new SafeConnection(mCoreObject.objectCast(), mModelObject.objectCast()), - &QObject::deleteLater); + mConnection = QSharedPointer>( + new SafeConnection(mCoreObject, mModelObject), &QObject::deleteLater); - mConnection->makeConnect(mCoreObject.get(), &SafeObject::setValue, [this](QVariant value) { + mConnection->makeConnectToCore(&SafeObject::setValue, [this](QVariant value) { mConnection->invokeToModel([this, value]() { mModelObject->onSetValue(value); }); }); - mConnection->makeConnect(mModelObject.get(), &SafeObject::setValue, [this](QVariant value) { + mConnection->makeConnectToModel(&SafeObject::setValue, [this](QVariant value) { mConnection->invokeToCore([this, value]() { mCoreObject->onSetValue(value); }); }); - mConnection->makeConnect(mModelObject.get(), &SafeObject::valueChanged, [this](QVariant value) { + mConnection->makeConnectToModel(&SafeObject::valueChanged, [this](QVariant value) { mConnection->invokeToCore([this, value]() { mCoreObject->valueChanged(value); }); }); connect(mCoreObject.get(), &SafeObject::valueChanged, this, &VariantObject::valueChanged); diff --git a/Linphone/model/object/VariantObject.hpp b/Linphone/model/object/VariantObject.hpp index bb0546d28..b86a60b5c 100644 --- a/Linphone/model/object/VariantObject.hpp +++ b/Linphone/model/object/VariantObject.hpp @@ -30,6 +30,8 @@ #include "SafeObject.hpp" #include "tool/thread/SafeConnection.hpp" +class CoreModel; + class VariantObject : public QObject, public AbstractObject { Q_OBJECT Q_PROPERTY(QVariant value READ getValue NOTIFY valueChanged) @@ -40,21 +42,21 @@ public: template void makeRequest(Func &&callable, Args &&...args) { - mConnection->makeConnect(mCoreObject.get(), &SafeObject::requestValue, [this, callable, args...]() { + mConnection->makeConnectToCore(&SafeObject::requestValue, [this, callable, args...]() { mConnection->invokeToModel([this, callable, args...]() { mModelObject->setValue(callable(args...)); }); }); } - template - void makeUpdate(const typename QtPrivate::FunctionPointer::Object *sender, SenderClass signal) { - mConnection->makeConnect(sender, signal, - [this]() { mConnection->invokeToCore([this]() { mCoreObject->requestValue(); }); }); + template + void makeUpdate(Sender sender, SenderClass signal) { + mConnection->makeConnectToModel( + sender, signal, [this]() { mConnection->invokeToCore([this]() { mCoreObject->requestValue(); }); }); } QVariant getValue() const; void requestValue(); QSharedPointer mCoreObject, mModelObject; - QSharedPointer mConnection; + QSharedPointer> mConnection; signals: void valueChanged(QVariant value); diff --git a/Linphone/tool/CMakeLists.txt b/Linphone/tool/CMakeLists.txt index 5b1a32b3e..6328ed747 100644 --- a/Linphone/tool/CMakeLists.txt +++ b/Linphone/tool/CMakeLists.txt @@ -5,7 +5,7 @@ list(APPEND _LINPHONEAPP_SOURCES tool/LinphoneEnums.cpp tool/thread/SafeSharedPointer.hpp - tool/thread/SafeConnection.cpp + tool/thread/SafeConnection.hpp tool/thread/Thread.cpp tool/providers/AvatarProvider.cpp tool/providers/ImageProvider.cpp diff --git a/Linphone/tool/Constants.cpp b/Linphone/tool/Constants.cpp index 6d377f0e3..7614fa4c1 100644 --- a/Linphone/tool/Constants.cpp +++ b/Linphone/tool/Constants.cpp @@ -75,7 +75,6 @@ constexpr char Constants::PathConfig[]; constexpr char Constants::PathDatabase[]; constexpr char Constants::PathFactoryConfig[]; constexpr char Constants::PathRootCa[]; -constexpr char Constants::PathFriendsList[]; constexpr char Constants::PathLimeDatabase[]; constexpr char Constants::PathMessageHistoryList[]; constexpr char Constants::PathZrtpSecrets[]; diff --git a/Linphone/tool/Constants.hpp b/Linphone/tool/Constants.hpp index 71c921a1a..3c76b4f6b 100644 --- a/Linphone/tool/Constants.hpp +++ b/Linphone/tool/Constants.hpp @@ -146,7 +146,6 @@ public: static constexpr char PathDatabase[] = "/linphone.db"; static constexpr char PathFactoryConfig[] = "/" EXECUTABLE_NAME "/linphonerc-factory"; static constexpr char PathRootCa[] = "/" EXECUTABLE_NAME "/rootca.pem"; - static constexpr char PathFriendsList[] = "/friends.db"; static constexpr char PathLimeDatabase[] = "/x3dh.c25519.sqlite3"; static constexpr char PathMessageHistoryList[] = "/message-history.db"; static constexpr char PathZrtpSecrets[] = "/zidcache"; diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index a9ccef066..ff80b9f68 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -45,7 +45,9 @@ char *Utils::rstrstr(const char *a, const char *b) { } VariantObject *Utils::getDisplayName(const QString &address) { - VariantObject *data = new VariantObject(address); // Scope : GUI + QStringList splitted = address.split(":"); + if (splitted.size() > 0 && splitted[0] == "sip") splitted.removeFirst(); + VariantObject *data = new VariantObject(splitted.first().split("@").first()); // Scope : GUI data->makeRequest([address]() { QString displayName = ToolModel::getDisplayName(address); return displayName; diff --git a/Linphone/tool/thread/SafeConnection.cpp b/Linphone/tool/thread/SafeConnection.cpp deleted file mode 100644 index 00f315812..000000000 --- a/Linphone/tool/thread/SafeConnection.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 "SafeConnection.hpp" - -SafeConnection::SafeConnection(SafeSharedPointer core, SafeSharedPointer model) - : mCore(core), mModel(model) { -} -SafeConnection::~SafeConnection() { - mLocker.lock(); - if (mCore.mCountRef != 0 || mModel.mCountRef != 0) - qCritical() << "[SafeConnection] Destruction while still having references. CoreRef=" << mCore.mCountRef - << "ModelRef=" << mModel.mCountRef; - mLocker.unlock(); -} diff --git a/Linphone/tool/thread/SafeConnection.hpp b/Linphone/tool/thread/SafeConnection.hpp index 6b5198533..710f2ae03 100644 --- a/Linphone/tool/thread/SafeConnection.hpp +++ b/Linphone/tool/thread/SafeConnection.hpp @@ -22,6 +22,7 @@ #define SAFE_CONNECTION_H_ #include "SafeSharedPointer.hpp" +#include "model/core/CoreModel.hpp" #include #include @@ -60,19 +61,40 @@ * */ +template class SafeConnection : public QObject { public: - SafeConnection(SafeSharedPointer a, SafeSharedPointer b); - ~SafeConnection(); - SafeSharedPointer mCore, mModel; + // SafeConnection(SafeSharedPointer a, SafeSharedPointer b); + SafeConnection(QSharedPointer a, std::shared_ptr b) + : mCore(a), mModel(b), mCoreObject(a.get()), mModelObject(b.get()) { + } + SafeConnection(QSharedPointer a, QSharedPointer b) + : mCore(a), mModel(b), mCoreObject(a.get()), mModelObject(b.get()) { + } + ~SafeConnection() { + mLocker.lock(); + if (mCore.mCountRef != 0 || mModel.mCountRef != 0) + qCritical() << "[SafeConnection] Destruction while still having references. CoreRef=" << mCore.mCountRef + << "ModelRef=" << mModel.mCountRef; + mCore.reset(); + mModel.reset(); + mLocker.unlock(); + } + SafeSharedPointer mCore; + SafeSharedPointer mModel; QMutex mLocker; template - static inline QMetaObject::Connection makeConnect(const typename QtPrivate::FunctionPointer::Object *sender, - Func1 signal, - Func2 slot, - Qt::ConnectionType type = Qt::AutoConnection) { - return connect(sender, signal, sender, slot, type); + inline QMetaObject::Connection makeConnectToModel(Func1 signal, Func2 slot) { + return connect(mModelObject, signal, mCoreObject, slot, Qt::DirectConnection); + } + template + inline QMetaObject::Connection makeConnectToModel(Sender sender, Func1 signal, Func2 slot) { + return connect(sender, signal, mCoreObject, slot, Qt::DirectConnection); + } + template + inline QMetaObject::Connection makeConnectToCore(Func1 signal, Func2 slot) { + return connect(mCoreObject, signal, mModelObject, slot, Qt::DirectConnection); } template @@ -112,6 +134,10 @@ public: mModel.unlock(); mLocker.unlock(); } + +protected: + A *mCoreObject = nullptr; + B *mModelObject = nullptr; // Use only for makeConnects }; #endif diff --git a/Linphone/view/App/Layout/MainLayout.qml b/Linphone/view/App/Layout/MainLayout.qml index 4f8a9a0d9..5c684ecc8 100644 --- a/Linphone/view/App/Layout/MainLayout.qml +++ b/Linphone/view/App/Layout/MainLayout.qml @@ -13,6 +13,8 @@ import UtilsCpp Item { id: mainItem + + signal addAccountRequest() RowLayout { anchors.fill: parent @@ -79,6 +81,7 @@ Item { contentHeight: accounts.height Accounts{ id: accounts + onAddAccountRequest: mainItem.addAccountRequest() } } } diff --git a/Linphone/view/App/Main.qml b/Linphone/view/App/Main.qml index b9fcc0966..ce0a8aae6 100644 --- a/Linphone/view/App/Main.qml +++ b/Linphone/view/App/Main.qml @@ -36,6 +36,8 @@ Window { Component { id: loginPage LoginPage { + showBackButton: accountProxy.haveAccount + onGoBack: mainWindowStackView.replace(mainPage) onUseSIPButtonClicked: mainWindowStackView.push(sipLoginPage) onGoToRegister: mainWindowStackView.replace(registerPage) onConnectionSucceed: { @@ -50,7 +52,7 @@ Window { Component { id: sipLoginPage SIPLoginPage { - onReturnToLogin: mainWindowStackView.pop() + onGoBack: mainWindowStackView.pop() onGoToRegister: mainWindowStackView.replace(registerPage) onConnectionSucceed: { @@ -90,6 +92,7 @@ Window { Component { id: mainPage MainLayout { + onAddAccountRequest: mainWindowStackView.replace(loginPage) } } } diff --git a/Linphone/view/Item/Account/Accounts.qml b/Linphone/view/Item/Account/Accounts.qml index c37ff2491..a452ba59a 100644 --- a/Linphone/view/Item/Account/Accounts.qml +++ b/Linphone/view/Item/Account/Accounts.qml @@ -1,6 +1,8 @@ -import QtQuick 2.15 -import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 as Control +import QtCore +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Control +import QtQuick.Dialogs import Linphone import UtilsCpp @@ -13,6 +15,9 @@ Item { readonly property int leftPadding: 32 * DefaultStyle.dp readonly property int rightPadding: 32 * DefaultStyle.dp readonly property int spacing: 16 * DefaultStyle.dp + + signal addAccountRequest() + implicitHeight: list.contentHeight + topPadding + bottomPadding + 32 * DefaultStyle.dp + 1 + newAccountArea.height ColumnLayout{ anchors.top: parent.top @@ -28,8 +33,21 @@ Item { spacing: mainItem.spacing model: AccountProxy{} delegate: Contact{ + id: contactItem width: list.width account: modelData + onAvatarClicked: fileDialog.open() + onBackgroundClicked: modelData.core.lSetDefaultAccount() + FileDialog { + id: fileDialog + currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0] + onAccepted: { + var avatarPath = UtilsCpp.createAvatar( selectedFile ) + if(avatarPath){ + modelData.core.pictureUri = avatarPath + } + } + } } } Rectangle{ @@ -40,10 +58,10 @@ Item { height: 1 color: DefaultStyle.main2_300 } - MouseArea{ // TODO + MouseArea{ Layout.fillWidth: true Layout.preferredHeight: 32 * DefaultStyle.dp - onClicked: console.log('New!') + onClicked: mainItem.addAccountRequest() RowLayout{ id: newAccountArea anchors.fill: parent diff --git a/Linphone/view/Item/Contact/Avatar.qml b/Linphone/view/Item/Contact/Avatar.qml index a83e37c9f..8ceb5c9f0 100644 --- a/Linphone/view/Item/Contact/Avatar.qml +++ b/Linphone/view/Item/Contact/Avatar.qml @@ -13,11 +13,11 @@ StackView{ id: mainItem property FriendGui contact property AccountGui account - onAccountChanged: if(account) replace(avatar, StackView.Immediate) property string address: account ? account.core.identityAddress : '' property var displayNameObj: UtilsCpp.getDisplayName(address) property bool haveAvatar: (account && account.core.pictureUri ) || (contact && contact.core.pictureUri) + onHaveAvatarChanged: replace(haveAvatar ? avatar : initials, StackView.Immediate) initialItem: haveAvatar ? avatar : initials Component{ @@ -25,12 +25,10 @@ StackView{ Rectangle { id: initialItem property string initials: UtilsCpp.getInitials(mainItem.displayNameObj.value) - onInitialsChanged: console.log("newInit:"+initials) radius: width / 2 color: DefaultStyle.main2_200 height: mainItem.height width: height - Component.onCompleted: console.log("init:"+initials) Text { anchors.fill: parent anchors.centerIn: parent diff --git a/Linphone/view/Item/Contact/Contact.qml b/Linphone/view/Item/Contact/Contact.qml index f7993c4fc..ec103225a 100644 --- a/Linphone/view/Item/Contact/Contact.qml +++ b/Linphone/view/Item/Contact/Contact.qml @@ -1,7 +1,6 @@ -import QtCore import QtQuick import QtQuick.Effects -import QtQuick.Dialogs + import QtQuick.Layouts @@ -11,7 +10,14 @@ import UtilsCpp Rectangle{ id: mainItem property AccountGui account + signal avatarClicked() + signal backgroundClicked() + height: 45 * DefaultStyle.dp + MouseArea{ + anchors.fill: parent + onClicked: mainItem.backgroundClicked() + } RowLayout{ anchors.fill: parent spacing: 0 @@ -22,17 +28,7 @@ Rectangle{ account: mainItem.account MouseArea{ anchors.fill: parent - onClicked: fileDialog.open() - } - FileDialog { - id: fileDialog - currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0] - onAccepted: { - var avatarPath = UtilsCpp.createAvatar( selectedFile ) - if(avatarPath){ - mainItem.account.core.pictureUri = avatarPath - } - } + onClicked: mainItem.avatarClicked() } } ContactDescription{ @@ -95,7 +91,7 @@ Rectangle{ } } } - Item{ // TODO + Item{ Layout.preferredWidth: 100 * DefaultStyle.dp Layout.fillHeight: true Rectangle{ @@ -103,6 +99,7 @@ Rectangle{ anchors.left: parent.left anchors.leftMargin: 10 * DefaultStyle.dp anchors.verticalCenter: parent.verticalCenter + visible: unreadCount.text > 0 width: 22 * DefaultStyle.dp height: 22 * DefaultStyle.dp radius: width/2 @@ -112,10 +109,15 @@ Rectangle{ Text{ id: unreadCount anchors.fill: parent + anchors.margins: 2 * DefaultStyle.dp verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter color: DefaultStyle.grey_0 - text: '2' + minimumPixelSize: 5 + fontSizeMode: Text.Fit + font.pixelSize: 20 * DefaultStyle.dp + property var unread: mainItem.account.core.unreadNotifications + text: unread > 100 ? '+' : unread } } } @@ -130,7 +132,7 @@ Rectangle{ colorizationColor: DefaultStyle.main2_500main MouseArea{ // TODO anchors.fill: parent - onClicked: console.log('Manage!') + onClicked: console.log('TODO: Manage!') } } } diff --git a/Linphone/view/Page/Login/LoginPage.qml b/Linphone/view/Page/Login/LoginPage.qml index d2b6bdf9c..1f015173b 100644 --- a/Linphone/view/Page/Login/LoginPage.qml +++ b/Linphone/view/Page/Login/LoginPage.qml @@ -5,11 +5,28 @@ import Linphone LoginLayout { id: mainItem + property bool showBackButton: false + signal goBack() signal useSIPButtonClicked() signal goToRegister() signal connectionSucceed() titleContent: RowLayout { + Control.Button { + Layout.preferredHeight: 40 * DefaultStyle.dp + Layout.preferredWidth: height + visible: mainItem.showBackButton + icon.width: width + icon.height: height + icon.source: AppIcons.returnArrow + background: Rectangle { + color: "transparent" + } + onClicked: { + console.debug("[LoginLayout] User: return") + mainItem.goBack() + } + } Image { fillMode: Image.PreserveAspectFit source: AppIcons.profile @@ -24,7 +41,7 @@ LoginLayout { Layout.fillWidth: true } Text { - Layout.rightMargin: 15 + Layout.rightMargin: 15 * DefaultStyle.dp text: "No account yet ?" font.pointSize: DefaultStyle.indicatorMessageTextSize } @@ -47,7 +64,7 @@ LoginLayout { onConnectionSucceed: mainItem.connectionSucceed() } Button { - Layout.topMargin: 40 + Layout.topMargin: 40 * DefaultStyle.dp inversedColors: true text: "Use SIP Account" onClicked: {mainItem.useSIPButtonClicked()} @@ -57,8 +74,8 @@ LoginLayout { Layout.fillWidth: true } Image { - Layout.rightMargin: 40 - Layout.preferredWidth: 300 + Layout.rightMargin: 40 * DefaultStyle.dp + Layout.preferredWidth: 300 * DefaultStyle.dp fillMode: Image.PreserveAspectFit source: AppIcons.loginImage } diff --git a/Linphone/view/Page/Login/SIPLoginPage.qml b/Linphone/view/Page/Login/SIPLoginPage.qml index 64197bd2d..b4898af14 100644 --- a/Linphone/view/Page/Login/SIPLoginPage.qml +++ b/Linphone/view/Page/Login/SIPLoginPage.qml @@ -6,7 +6,7 @@ import ConstantsCpp 1.0 LoginLayout { id: mainItem - signal returnToLogin() + signal goBack() signal goToRegister() signal connectionSucceed() @@ -22,7 +22,7 @@ LoginLayout { } onClicked: { console.debug("[SIPLoginPage] User: return") - mainItem.returnToLogin() + mainItem.goBack() } } Image { diff --git a/external/linphone-sdk b/external/linphone-sdk index bf9106ee5..d07e85507 160000 --- a/external/linphone-sdk +++ b/external/linphone-sdk @@ -1 +1 @@ -Subproject commit bf9106ee57b8a32aea2693f0fc69c2397a66d570 +Subproject commit d07e85507cb6ddba7fe397f5fc699835516945aa