mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
Fix crashes on SafeConnection.
Display missed notifications and fit text size from content. Add account from profile menu and display Login Page with back button. Default account selection and change avatar from accounts list. Remove deprecated function on Friends DB. Return username by default on display name computation. Update SDK.
This commit is contained in:
parent
4ea1b96246
commit
a43430fa34
35 changed files with 313 additions and 234 deletions
|
|
@ -46,6 +46,8 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &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<AccountModel>(account); // OK
|
||||
|
|
@ -58,30 +60,34 @@ AccountCore::~AccountCore() {
|
|||
}
|
||||
|
||||
void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
|
||||
mAccountModelConnection = QSharedPointer<SafeConnection>(
|
||||
new SafeConnection(me.objectCast<QObject>(), std::dynamic_pointer_cast<QObject>(mAccountModel)));
|
||||
mAccountModelConnection->makeConnect(mAccountModel.get(), &AccountModel::registrationStateChanged,
|
||||
[this](const std::shared_ptr<linphone::Account> &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<SafeConnection<AccountCore, AccountModel>>(
|
||||
new SafeConnection<AccountCore, AccountModel>(me, mAccountModel));
|
||||
mAccountModelConnection->makeConnectToModel(
|
||||
&AccountModel::registrationStateChanged, [this](const std::shared_ptr<linphone::Account> &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<linphone::Account> &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(); });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<AccountCore> create(const std::shared_ptr<linphone::Account> &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<linphone::Account> &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<AccountModel> mAccountModel;
|
||||
QSharedPointer<SafeConnection> mAccountModelConnection;
|
||||
QSharedPointer<SafeConnection<AccountCore, AccountModel>> mAccountModelConnection;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
DEFINE_ABSTRACT_OBJECT(AccountGui)
|
||||
|
||||
AccountGui::AccountGui(QSharedPointer<AccountCore> 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<AccountCore> core) {
|
|||
|
||||
AccountGui::~AccountGui() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
qDebug() << "[AccountGui] delete" << this;
|
||||
}
|
||||
|
||||
AccountCore *AccountGui::getCore() const {
|
||||
|
|
|
|||
|
|
@ -37,51 +37,54 @@ QSharedPointer<AccountList> 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<AccountList> me) {
|
||||
mModelConnection = QSharedPointer<SafeConnection>(
|
||||
new SafeConnection(me.objectCast<QObject>(), std::dynamic_pointer_cast<QObject>(CoreModel::getInstance())),
|
||||
&QObject::deleteLater);
|
||||
mModelConnection->makeConnect(this, &AccountList::lUpdate, [this]() {
|
||||
mModelConnection = QSharedPointer<SafeConnection<AccountList, CoreModel>>(
|
||||
new SafeConnection<AccountList, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
|
||||
|
||||
mModelConnection->makeConnectToCore(&AccountList::lUpdate, [this]() {
|
||||
mModelConnection->invokeToModel([this]() {
|
||||
// Avoid copy to lambdas
|
||||
QList<QSharedPointer<AccountCore>> *accounts = new QList<QSharedPointer<AccountCore>>();
|
||||
// Model thread.
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
auto linphoneAccounts = CoreModel::getInstance()->getCore()->getAccountList();
|
||||
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
QSharedPointer<AccountCore> 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<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account) {
|
||||
auto model = AccountCore::create(account);
|
||||
mModelConnection->invokeToCore([this, model]() { setDefaultAccount(model); });
|
||||
});
|
||||
lUpdate();
|
||||
}
|
||||
|
||||
QSharedPointer<AccountCore> AccountList::getDefaultAccountCore() const {
|
||||
for (auto it : mList) {
|
||||
auto account = it.objectCast<AccountCore>();
|
||||
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<AccountCore> account) {
|
||||
if (mDefaultAccount != account) {
|
||||
mDefaultAccount = account;
|
||||
emit defaultAccountChanged();
|
||||
}
|
||||
}
|
||||
bool AccountList::getHaveAccount() const {
|
||||
return mHaveAccount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<AccountCore> getDefaultAccountCore() const;
|
||||
void setDefaultAccount(QSharedPointer<AccountCore> account);
|
||||
|
||||
bool getHaveAccount() const;
|
||||
void setHaveAccount(bool haveAccount);
|
||||
|
|
@ -53,7 +55,8 @@ signals:
|
|||
|
||||
private:
|
||||
bool mHaveAccount = false;
|
||||
QSharedPointer<SafeConnection> mModelConnection;
|
||||
QSharedPointer<AccountCore> mDefaultAccount;
|
||||
QSharedPointer<SafeConnection<AccountList, CoreModel>> mModelConnection;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -67,13 +67,12 @@ CallCore::~CallCore() {
|
|||
}
|
||||
|
||||
void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
||||
mAccountModelConnection = QSharedPointer<SafeConnection>(
|
||||
new SafeConnection(me.objectCast<QObject>(), std::dynamic_pointer_cast<QObject>(mCallModel)),
|
||||
&QObject::deleteLater);
|
||||
mAccountModelConnection->makeConnect(this, &CallCore::lSetMicrophoneMuted, [this](bool isMuted) {
|
||||
mAccountModelConnection = QSharedPointer<SafeConnection<CallCore, CallModel>>(
|
||||
new SafeConnection<CallCore, CallModel>(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<CallCore> 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<linphone::Call> &call, linphone::Call::State state) {
|
||||
mAccountModelConnection->invokeToCore([this, state]() {
|
||||
QString message;
|
||||
|
|
@ -122,8 +121,8 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
setTransferState(LinphoneEnums::fromLinphone(state), message);
|
||||
});
|
||||
});
|
||||
mAccountModelConnection->makeConnect(
|
||||
mCallModel.get(), &CallModel::encryptionChanged,
|
||||
mAccountModelConnection->makeConnectToModel(
|
||||
&CallModel::encryptionChanged,
|
||||
[this](const std::shared_ptr<linphone::Call> &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<CallCore> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,11 @@
|
|||
|
||||
#include "model/call/CallModel.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
class SafeConnection;
|
||||
|
||||
class CallCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
|
@ -138,7 +137,7 @@ private:
|
|||
bool mMicrophoneMuted;
|
||||
bool mCameraEnabled;
|
||||
bool mPaused = false;
|
||||
QSharedPointer<SafeConnection> mAccountModelConnection;
|
||||
QSharedPointer<SafeConnection<CallCore, CallModel>> mAccountModelConnection;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -56,35 +56,36 @@ FriendCore::FriendCore(const FriendCore &friendCore) {
|
|||
FriendCore::~FriendCore() {
|
||||
}
|
||||
|
||||
void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
|
||||
setSelf(me.objectCast<QObject>());
|
||||
void FriendCore::setSelf(SafeSharedPointer<FriendCore> me) {
|
||||
setSelf(me.mQDataWeak.lock());
|
||||
}
|
||||
|
||||
void FriendCore::setSelf(SafeSharedPointer<QObject> me) {
|
||||
if (mFriendModel) {
|
||||
mFriendModelConnection = QSharedPointer<SafeConnection>(
|
||||
new SafeConnection(me, std::dynamic_pointer_cast<QObject>(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<FriendCore> me) {
|
||||
if (me) {
|
||||
if (mFriendModel) {
|
||||
mCoreModelConnection = nullptr; // No more needed
|
||||
mFriendModelConnection = QSharedPointer<SafeConnection<FriendCore, FriendModel>>(
|
||||
new SafeConnection<FriendCore, FriendModel>(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<SafeConnection>(
|
||||
new SafeConnection(me, std::dynamic_pointer_cast<QObject>(CoreModel::getInstance())),
|
||||
&QObject::deleteLater);
|
||||
} else { // Create
|
||||
mCoreModelConnection = QSharedPointer<SafeConnection<FriendCore, CoreModel>>(
|
||||
new SafeConnection<FriendCore, CoreModel>(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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,18 +23,19 @@
|
|||
|
||||
#include "model/friend/FriendModel.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include "tool/thread/SafeSharedPointer.hpp"
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
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<FriendCore> me);
|
||||
void setSelf(SafeSharedPointer<QObject> me);
|
||||
void setSelf(SafeSharedPointer<FriendCore> me);
|
||||
void reset(const FriendCore &contact);
|
||||
|
||||
QString getName() const;
|
||||
|
|
@ -106,7 +107,8 @@ protected:
|
|||
QString mPictureUri;
|
||||
bool mIsSaved;
|
||||
std::shared_ptr<FriendModel> mFriendModel;
|
||||
QSharedPointer<SafeConnection> mFriendModelConnection;
|
||||
QSharedPointer<SafeConnection<FriendCore, FriendModel>> mFriendModelConnection;
|
||||
QSharedPointer<SafeConnection<FriendCore, CoreModel>> mCoreModelConnection;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -57,38 +57,37 @@ MagicSearchList::~MagicSearchList() {
|
|||
}
|
||||
|
||||
void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
|
||||
mModelConnection = QSharedPointer<SafeConnection>(
|
||||
new SafeConnection(me.objectCast<QObject>(), std::dynamic_pointer_cast<QObject>(mMagicSearch)),
|
||||
&QObject::deleteLater);
|
||||
mModelConnection->makeConnect(this, &MagicSearchList::lSearch, [this](QString filter) {
|
||||
mModelConnection = QSharedPointer<SafeConnection<MagicSearchList, MagicSearchModel>>(
|
||||
new SafeConnection<MagicSearchList, MagicSearchModel>(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<std::shared_ptr<linphone::SearchResult>> &results) {
|
||||
auto *contacts = new QList<QSharedPointer<FriendCore>>();
|
||||
for (auto it : results) {
|
||||
QSharedPointer<FriendCore> 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<std::shared_ptr<linphone::SearchResult>> &results) {
|
||||
auto *contacts = new QList<QSharedPointer<FriendCore>>();
|
||||
for (auto it : results) {
|
||||
QSharedPointer<FriendCore> 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<QSharedPointer<FriendCore>> &contacts) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <QLocale>
|
||||
|
||||
class FriendCore;
|
||||
class CoreModel;
|
||||
// =============================================================================
|
||||
|
||||
// Return FriendGui list to Ui
|
||||
|
|
@ -63,8 +64,8 @@ private:
|
|||
LinphoneEnums::MagicSearchAggregation mAggregationFlag;
|
||||
|
||||
std::shared_ptr<MagicSearchModel> mMagicSearch;
|
||||
QSharedPointer<SafeConnection> mModelConnection;
|
||||
QSharedPointer<SafeConnection> mCoreModelConnection;
|
||||
QSharedPointer<SafeConnection<MagicSearchList, MagicSearchModel>> mModelConnection;
|
||||
QSharedPointer<SafeConnection<MagicSearchList, CoreModel>> mCoreModelConnection;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ AccountModel::AccountModel(const std::shared_ptr<linphone::Account> &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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public:
|
|||
|
||||
void setPictureUri(QString uri);
|
||||
void setDefault();
|
||||
void removeAccount();
|
||||
|
||||
signals:
|
||||
void registrationStateChanged(const std::shared_ptr<linphone::Account> &account,
|
||||
|
|
@ -50,6 +51,7 @@ signals:
|
|||
void defaultAccountChanged(bool isDefault);
|
||||
|
||||
void pictureUriChanged(QString uri);
|
||||
void unreadNotificationsChanged(int unreadMessagesCount, int unreadCallsCount);
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
|
|
|||
|
|
@ -63,18 +63,23 @@ std::shared_ptr<CoreModel> 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<linphone::Core> &c
|
|||
}
|
||||
void CoreModel::onCallLogUpdated(const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<linphone::CallLog> &callLog) {
|
||||
if (callLog && callLog->getStatus() == linphone::Call::Status::Missed) emit unreadNotificationsChanged();
|
||||
emit callLogUpdated(core, callLog);
|
||||
}
|
||||
void CoreModel::onCallStateChanged(const std::shared_ptr<linphone::Core> &core,
|
||||
|
|
@ -242,11 +245,13 @@ void CoreModel::onLogCollectionUploadProgressIndication(const std::shared_ptr<li
|
|||
void CoreModel::onMessageReceived(const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<linphone::ChatRoom> &room,
|
||||
const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||
emit unreadNotificationsChanged();
|
||||
emit messageReceived(core, room, message);
|
||||
}
|
||||
void CoreModel::onMessagesReceived(const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<linphone::ChatRoom> &room,
|
||||
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages) {
|
||||
emit unreadNotificationsChanged();
|
||||
emit messagesReceived(core, room, messages);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ signals:
|
|||
void loggerInitialized();
|
||||
void friendAdded();
|
||||
void friendRemoved();
|
||||
void unreadNotificationsChanged();
|
||||
|
||||
private:
|
||||
QString mConfigPath;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ public:
|
|||
setMonitor(monitor);
|
||||
}
|
||||
~Listener() {
|
||||
qDebug() << "Destroying Listener";
|
||||
setSelf(nullptr);
|
||||
}
|
||||
virtual void onRemoveListener() {
|
||||
|
|
|
|||
|
|
@ -33,17 +33,16 @@ VariantObject::VariantObject(QVariant defaultValue, QObject *parent) {
|
|||
mModelObject = QSharedPointer<SafeObject>::create();
|
||||
mModelObject->moveToThread(CoreModel::getInstance()->thread());
|
||||
|
||||
mConnection = QSharedPointer<SafeConnection>(
|
||||
new SafeConnection(mCoreObject.objectCast<QObject>(), mModelObject.objectCast<QObject>()),
|
||||
&QObject::deleteLater);
|
||||
mConnection = QSharedPointer<SafeConnection<SafeObject, SafeObject>>(
|
||||
new SafeConnection<SafeObject, SafeObject>(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);
|
||||
|
|
|
|||
|
|
@ -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 <typename Func, typename... Args>
|
||||
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 <typename SenderClass>
|
||||
void makeUpdate(const typename QtPrivate::FunctionPointer<SenderClass>::Object *sender, SenderClass signal) {
|
||||
mConnection->makeConnect(sender, signal,
|
||||
[this]() { mConnection->invokeToCore([this]() { mCoreObject->requestValue(); }); });
|
||||
template <typename Sender, typename SenderClass>
|
||||
void makeUpdate(Sender sender, SenderClass signal) {
|
||||
mConnection->makeConnectToModel(
|
||||
sender, signal, [this]() { mConnection->invokeToCore([this]() { mCoreObject->requestValue(); }); });
|
||||
}
|
||||
|
||||
QVariant getValue() const;
|
||||
void requestValue();
|
||||
|
||||
QSharedPointer<SafeObject> mCoreObject, mModelObject;
|
||||
QSharedPointer<SafeConnection> mConnection;
|
||||
QSharedPointer<SafeConnection<SafeObject, SafeObject>> mConnection;
|
||||
signals:
|
||||
void valueChanged(QVariant value);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SafeConnection.hpp"
|
||||
|
||||
SafeConnection::SafeConnection(SafeSharedPointer<QObject> core, SafeSharedPointer<QObject> 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();
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#define SAFE_CONNECTION_H_
|
||||
|
||||
#include "SafeSharedPointer.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
|
||||
|
|
@ -60,19 +61,40 @@
|
|||
*
|
||||
*/
|
||||
|
||||
template <class A, class B>
|
||||
class SafeConnection : public QObject {
|
||||
public:
|
||||
SafeConnection(SafeSharedPointer<QObject> a, SafeSharedPointer<QObject> b);
|
||||
~SafeConnection();
|
||||
SafeSharedPointer<QObject> mCore, mModel;
|
||||
// SafeConnection(SafeSharedPointer<QObject> a, SafeSharedPointer<QObject> b);
|
||||
SafeConnection(QSharedPointer<A> a, std::shared_ptr<B> b)
|
||||
: mCore(a), mModel(b), mCoreObject(a.get()), mModelObject(b.get()) {
|
||||
}
|
||||
SafeConnection(QSharedPointer<A> a, QSharedPointer<B> 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<A> mCore;
|
||||
SafeSharedPointer<B> mModel;
|
||||
QMutex mLocker;
|
||||
|
||||
template <typename Func1, typename Func2>
|
||||
static inline QMetaObject::Connection makeConnect(const typename QtPrivate::FunctionPointer<Func1>::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 <typename Sender, typename Func1, typename Func2>
|
||||
inline QMetaObject::Connection makeConnectToModel(Sender sender, Func1 signal, Func2 slot) {
|
||||
return connect(sender, signal, mCoreObject, slot, Qt::DirectConnection);
|
||||
}
|
||||
template <typename Func1, typename Func2>
|
||||
inline QMetaObject::Connection makeConnectToCore(Func1 signal, Func2 slot) {
|
||||
return connect(mCoreObject, signal, mModelObject, slot, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
template <typename Func, typename... Args>
|
||||
|
|
@ -112,6 +134,10 @@ public:
|
|||
mModel.unlock();
|
||||
mLocker.unlock();
|
||||
}
|
||||
|
||||
protected:
|
||||
A *mCoreObject = nullptr;
|
||||
B *mModelObject = nullptr; // Use only for makeConnects
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
2
external/linphone-sdk
vendored
2
external/linphone-sdk
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit bf9106ee57b8a32aea2693f0fc69c2397a66d570
|
||||
Subproject commit d07e85507cb6ddba7fe397f5fc699835516945aa
|
||||
Loading…
Add table
Reference in a new issue