This commit is contained in:
Christophe Deschamps 2025-04-01 09:04:19 +02:00
parent 187c6753bd
commit dad3cb084f
45 changed files with 1293 additions and 296 deletions

View file

@ -1149,6 +1149,16 @@ bool App::event(QEvent *event) {
} else if (event->type() == QEvent::ApplicationStateChange) { } else if (event->type() == QEvent::ApplicationStateChange) {
auto state = static_cast<QApplicationStateChangeEvent *>(event); auto state = static_cast<QApplicationStateChangeEvent *>(event);
if (state->applicationState() == Qt::ApplicationActive) Utils::smartShowWindow(getLastActiveWindow()); if (state->applicationState() == Qt::ApplicationActive) Utils::smartShowWindow(getLastActiveWindow());
} else if (event->type() == QEvent::ApplicationActivate) {
for (int i = 0; i < getAccountList()->rowCount(); ++i) {
auto accountCore = getAccountList()->getAt<AccountCore>(i);
emit accountCore->lSetPresence(LinphoneEnums::Presence::Online, false, false);
}
} else if (event->type() == QEvent::ApplicationDeactivate) {
for (int i = 0; i < getAccountList()->rowCount(); ++i) {
auto accountCore = getAccountList()->getAt<AccountCore>(i);
emit accountCore->lSetPresence(LinphoneEnums::Presence::Away, false, false);
}
} }
return SingleApplication::event(event); return SingleApplication::event(event);

View file

@ -85,6 +85,14 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
// Add listener // Add listener
mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); // OK mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); // OK
mAccountModel->setSelf(mAccountModel); mAccountModel->setSelf(mAccountModel);
mExplicitPresence = LinphoneEnums::fromString(
Utils::coreStringToAppString(CoreModel::getInstance()->getCore()->getConfig()->getString(
ToolModel::configAccountSection(account), "explicit_presence", "")));
mPresenceNote = Utils::coreStringToAppString(CoreModel::getInstance()->getCore()->getConfig()->getString(
ToolModel::configAccountSection(account), "presence_note", ""));
mMaxPresenceNoteSize = CoreModel::getInstance()->getCore()->getConfig()->getInt(
ToolModel::configAccountSection(account), "max_presence_note_size", 140);
mPresence = mAccountModel->getPresence();
mNotificationsAllowed = mAccountModel->getNotificationsAllowed(); mNotificationsAllowed = mAccountModel->getNotificationsAllowed();
mDialPlan = Utils::createDialPlanVariant("", " "); mDialPlan = Utils::createDialPlanVariant("", " ");
mDialPlans << mDialPlan; mDialPlans << mDialPlan;
@ -222,6 +230,16 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToModel( mAccountModelConnection->makeConnectToModel(
&AccountModel::removed, [this]() { mAccountModelConnection->invokeToCore([this]() { emit removed(); }); }); &AccountModel::removed, [this]() { mAccountModelConnection->invokeToCore([this]() { emit removed(); }); });
mAccountModelConnection->makeConnectToModel(
&AccountModel::presenceChanged, [this](LinphoneEnums::Presence presence, bool userInitiated) {
mAccountModelConnection->invokeToCore([this, presence, userInitiated]() {
if (userInitiated) mExplicitPresence = presence;
else mExplicitPresence = LinphoneEnums::Presence::Undefined;
mPresence = presence;
emit presenceChanged();
});
});
// From GUI // From GUI
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetPictureUri, [this](QString uri) { mAccountModelConnection->makeConnectToCore(&AccountCore::lSetPictureUri, [this](QString uri) {
mAccountModelConnection->invokeToModel([this, uri]() { mAccountModel->setPictureUri(uri); }); mAccountModelConnection->invokeToModel([this, uri]() { mAccountModel->setPictureUri(uri); });
@ -258,6 +276,13 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetNotificationsAllowed, [this](bool value) { mAccountModelConnection->makeConnectToCore(&AccountCore::lSetNotificationsAllowed, [this](bool value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setNotificationsAllowed(value); }); mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setNotificationsAllowed(value); });
}); });
mAccountModelConnection->makeConnectToCore(
&AccountCore::lSetPresence, [this](LinphoneEnums::Presence presence, bool userInitiated, bool resetToAuto) {
mAccountModelConnection->invokeToModel(
[this, presence, userInitiated, resetToAuto, presenceNote = mPresenceNote]() {
mAccountModel->setPresence(presence, userInitiated, resetToAuto, presenceNote);
});
});
DEFINE_CORE_GET_CONNECT(mAccountModelConnection, AccountCore, AccountModel, mAccountModel, int, voicemailCount, DEFINE_CORE_GET_CONNECT(mAccountModelConnection, AccountCore, AccountModel, mAccountModel, int, voicemailCount,
VoicemailCount) VoicemailCount)
@ -425,6 +450,30 @@ QString AccountCore::getHumanReadableRegistrationState() const {
} }
} }
QColor AccountCore::getRegistrationColor() const {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
switch (mRegistrationState) {
case LinphoneEnums::RegistrationState::Ok:
return Utils::getDefaultStyleColor("success_500main");
case LinphoneEnums::RegistrationState::Refreshing:
return Utils::getDefaultStyleColor("main2_500main");
case LinphoneEnums::RegistrationState::Progress:
return Utils::getDefaultStyleColor("main2_500main");
case LinphoneEnums::RegistrationState::Failed:
return Utils::getDefaultStyleColor("danger_500main");
case LinphoneEnums::RegistrationState::None:
case LinphoneEnums::RegistrationState::Cleared:
return Utils::getDefaultStyleColor("warning_600");
default:
return " ";
}
}
QUrl AccountCore::getRegistrationIcon() const {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
return Utils::getRegistrationStateIcon(mRegistrationState);
}
QString AccountCore::getHumanReadableRegistrationStateExplained() const { QString AccountCore::getHumanReadableRegistrationStateExplained() const {
switch (mRegistrationState) { switch (mRegistrationState) {
case LinphoneEnums::RegistrationState::Ok: case LinphoneEnums::RegistrationState::Ok:
@ -804,3 +853,38 @@ void AccountCore::undo() {
}); });
} }
} }
LinphoneEnums::Presence AccountCore::getPresence() {
return mPresence;
}
QColor AccountCore::getPresenceColor() {
return Utils::getPresenceColor(mPresence);
}
QUrl AccountCore::getPresenceIcon() {
return Utils::getPresenceIcon(mPresence);
}
QString AccountCore::getPresenceStatus() {
return Utils::getPresenceStatus(mPresence);
}
void AccountCore::resetToAutomaticPresence() {
emit lSetPresence(LinphoneEnums::Presence::Online, false, true);
}
LinphoneEnums::Presence AccountCore::getExplicitPresence() {
return mExplicitPresence;
}
void AccountCore::setPresenceNote(QString presenceNote) {
if (presenceNote != mPresenceNote) {
mPresenceNote = presenceNote;
emit lSetPresence(mPresence, mExplicitPresence != LinphoneEnums::Presence::Undefined, false);
}
}
QString AccountCore::getPresenceNote() {
return mPresenceNote;
}

View file

@ -75,6 +75,15 @@ public:
Q_PROPERTY(bool isSaved READ isSaved WRITE setIsSaved NOTIFY isSavedChanged) Q_PROPERTY(bool isSaved READ isSaved WRITE setIsSaved NOTIFY isSavedChanged)
Q_PROPERTY( Q_PROPERTY(
QString voicemailAddress READ getVoicemailAddress WRITE setVoicemailAddress NOTIFY voicemailAddressChanged) QString voicemailAddress READ getVoicemailAddress WRITE setVoicemailAddress NOTIFY voicemailAddressChanged)
Q_PROPERTY(LinphoneEnums::Presence presence READ getPresence WRITE lSetPresence NOTIFY presenceChanged)
Q_PROPERTY(QColor presenceColor READ getPresenceColor NOTIFY presenceChanged)
Q_PROPERTY(QUrl presenceIcon READ getPresenceIcon NOTIFY presenceChanged)
Q_PROPERTY(QString presenceStatus READ getPresenceStatus NOTIFY presenceChanged)
Q_PROPERTY(QColor registrationColor READ getRegistrationColor NOTIFY registrationStateChanged)
Q_PROPERTY(QUrl registrationIcon READ getRegistrationIcon NOTIFY registrationStateChanged)
Q_PROPERTY(LinphoneEnums::Presence explicitPresence MEMBER mExplicitPresence NOTIFY presenceChanged)
Q_PROPERTY(QString presenceNote READ getPresenceNote WRITE setPresenceNote NOTIFY presenceChanged)
Q_PROPERTY(int maxPresenceNoteSize MEMBER mMaxPresenceNoteSize CONSTANT)
DECLARE_CORE_GET(int, voicemailCount, VoicemailCount) DECLARE_CORE_GET(int, voicemailCount, VoicemailCount)
static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account); static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account);
@ -114,6 +123,8 @@ public:
void onDialPlanChanged(QVariantMap internationalPrefix); void onDialPlanChanged(QVariantMap internationalPrefix);
QString getHumanReadableRegistrationState() const; QString getHumanReadableRegistrationState() const;
QString getHumanReadableRegistrationStateExplained() const; QString getHumanReadableRegistrationStateExplained() const;
QColor getRegistrationColor() const;
QUrl getRegistrationIcon() const;
bool getRegisterEnabled() const; bool getRegisterEnabled() const;
void onRegisterEnabledChanged(bool enabled); void onRegisterEnabledChanged(bool enabled);
@ -170,6 +181,15 @@ public:
Q_INVOKABLE void save(); Q_INVOKABLE void save();
Q_INVOKABLE void undo(); Q_INVOKABLE void undo();
QColor getPresenceColor();
QUrl getPresenceIcon();
QString getPresenceStatus();
LinphoneEnums::Presence getPresence();
Q_INVOKABLE void resetToAutomaticPresence();
LinphoneEnums::Presence getExplicitPresence();
void setPresenceNote(QString presenceNote);
QString getPresenceNote();
signals: signals:
void pictureUriChanged(); void pictureUriChanged();
void registrationStateChanged(const QString &message); void registrationStateChanged(const QString &message);
@ -198,6 +218,7 @@ signals:
void removed(); void removed();
void isSavedChanged(); void isSavedChanged();
void voicemailAddressChanged(); void voicemailAddressChanged();
void presenceChanged();
// Account requests // Account requests
void lSetPictureUri(QString pictureUri); void lSetPictureUri(QString pictureUri);
@ -209,6 +230,7 @@ signals:
void lSetDialPlan(QVariantMap internationalPrefix); void lSetDialPlan(QVariantMap internationalPrefix);
void lSetRegisterEnabled(bool enabled); void lSetRegisterEnabled(bool enabled);
void lSetNotificationsAllowed(bool value); void lSetNotificationsAllowed(bool value);
void lSetPresence(LinphoneEnums::Presence presence, bool userInitiated = true, bool resetToAuto = false);
protected: protected:
void writeIntoModel(std::shared_ptr<AccountModel> model) const; void writeIntoModel(std::shared_ptr<AccountModel> model) const;
@ -243,6 +265,10 @@ private:
QString mAudioVideoConferenceFactoryAddress; QString mAudioVideoConferenceFactoryAddress;
QString mLimeServerUrl; QString mLimeServerUrl;
QString mVoicemailAddress; QString mVoicemailAddress;
LinphoneEnums::Presence mPresence = LinphoneEnums::Presence::Undefined;
LinphoneEnums::Presence mExplicitPresence;
QString mPresenceNote;
int mMaxPresenceNoteSize;
bool mIsSaved = true; bool mIsSaved = true;
std::shared_ptr<AccountModel> mAccountModel; std::shared_ptr<AccountModel> mAccountModel;

View file

@ -68,6 +68,10 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
setHaveAccount(accounts->size() > 0); setHaveAccount(accounts->size() > 0);
setDefaultAccount(defaultAccountCore); setDefaultAccount(defaultAccountCore);
if (isInitialization) setInitialized(true); if (isInitialization) setInitialized(true);
for (const QSharedPointer<AccountCore> &accountCore : *accounts) {
if (accountCore->getExplicitPresence() != LinphoneEnums::Presence::Undefined)
emit accountCore->lSetPresence(accountCore->getExplicitPresence(), true, false);
}
delete accounts; delete accounts;
}); });
}); });
@ -88,7 +92,8 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
// with the open id account // with the open id account
mModelConnection->makeConnectToModel(&CoreModel::bearerAccountAdded, [this] { mModelConnection->makeConnectToModel(&CoreModel::bearerAccountAdded, [this] {
setInitialized(false); setInitialized(false);
emit lUpdate(true); }); emit lUpdate(true);
});
mModelConnection->makeConnectToModel( mModelConnection->makeConnectToModel(
&CoreModel::globalStateChanged, &CoreModel::globalStateChanged,

View file

@ -48,8 +48,9 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool is
mustBeInLinphoneThread(getClassName()); mustBeInLinphoneThread(getClassName());
mFriendModel = Utils::makeQObject_ptr<FriendModel>(contact); mFriendModel = Utils::makeQObject_ptr<FriendModel>(contact);
mFriendModel->setSelf(mFriendModel); mFriendModel->setSelf(mFriendModel);
mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence()); auto presence = mFriendModel->getPresence(contact);
mPresenceTimestamp = mFriendModel->getPresenceTimestamp(); auto note = mFriendModel->getPresenceNote(contact);
App::postCoreAsync([this, presence, note]() { setPresence(presence, note); });
mPictureUri = Utils::coreStringToAppString(contact->getPhoto()); mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
mFullName = mFriendModel->getFullName(); mFullName = mFriendModel->getFullName();
auto defaultAddress = contact->getAddress(); auto defaultAddress = contact->getAddress();
@ -65,7 +66,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool is
auto addresses = contact->getAddresses(); auto addresses = contact->getAddresses();
for (auto &address : addresses) { for (auto &address : addresses) {
mAddressList.append(Utils::createFriendAddressVariant( mAddressList.append(Utils::createFriendAddressVariant(
tr("sip_address"), Utils::coreStringToAppString(address->asStringUriOnly()))); tr("sip_address"), Utils::coreStringToAppString(address->asStringUriOnly())));
} }
mDefaultAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asStringUriOnly()) : QString(); mDefaultAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asStringUriOnly()) : QString();
mDefaultFullAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asString()) : QString(); mDefaultFullAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asString()) : QString();
@ -142,8 +143,7 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
mFriendModelConnection->makeConnectToModel( mFriendModelConnection->makeConnectToModel(
&FriendModel::removed, [this]() { mFriendModelConnection->invokeToCore([this]() { removed(this); }); }); &FriendModel::removed, [this]() { mFriendModelConnection->invokeToCore([this]() { removed(this); }); });
mFriendModelConnection->makeConnectToModel( mFriendModelConnection->makeConnectToModel(
&FriendModel::presenceReceived, &FriendModel::presenceReceived, [this](LinphoneEnums::Presence presence, QString presenceNote) {
[this](LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp) {
auto devices = mFriendModel->getDevices(); auto devices = mFriendModel->getDevices();
QVariantList devicesList; QVariantList devicesList;
for (auto &device : devices) { for (auto &device : devices) {
@ -153,14 +153,11 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
Utils::coreStringToAppString(device->getAddress()->asString()), Utils::coreStringToAppString(device->getAddress()->asString()),
LinphoneEnums::fromLinphone(device->getSecurityLevel()))); LinphoneEnums::fromLinphone(device->getSecurityLevel())));
} }
mFriendModelConnection->invokeToCore( mFriendModelConnection->invokeToCore([this, presence, devicesList, presenceNote]() {
[this, consolidatedPresence, presenceTimestamp, devicesList]() { setPresence(presence, presenceNote);
setConsolidatedPresence(consolidatedPresence); setDevices(devicesList);
setPresenceTimestamp(presenceTimestamp); updateVerifiedDevicesCount();
});
setDevices(devicesList);
updateVerifiedDevicesCount();
});
}); });
mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](const QString &uri) { mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](const QString &uri) {
mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); }); mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); });
@ -188,7 +185,7 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
QList<QVariant> addr; QList<QVariant> addr;
for (auto &num : numbers) { for (auto &num : numbers) {
addr.append(Utils::createFriendAddressVariant( addr.append(Utils::createFriendAddressVariant(
tr("sip_address"), Utils::coreStringToAppString(num->asStringUriOnly()))); tr("sip_address"), Utils::coreStringToAppString(num->asStringUriOnly())));
} }
mFriendModelConnection->invokeToCore([this, addr]() { resetPhoneNumbers(addr); }); mFriendModelConnection->invokeToCore([this, addr]() { resetPhoneNumbers(addr); });
}); });
@ -419,9 +416,10 @@ void FriendCore::appendAddress(const QString &addr) {
QString interpretedFullAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asString()) : ""; QString interpretedFullAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asString()) : "";
QString interpretedAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asStringUriOnly()) : ""; QString interpretedAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asStringUriOnly()) : "";
mCoreModelConnection->invokeToCore([this, interpretedAddress, interpretedFullAddress]() { mCoreModelConnection->invokeToCore([this, interpretedAddress, interpretedFullAddress]() {
if (interpretedAddress.isEmpty()) Utils::showInformationPopup(tr("information_popup_error_title"), if (interpretedAddress.isEmpty())
//: "Adresse invalide" Utils::showInformationPopup(tr("information_popup_error_title"),
tr("information_popup_invalid_address_message"), false); //: "Adresse invalide"
tr("information_popup_invalid_address_message"), false);
else { else {
mAddressList.append(Utils::createFriendAddressVariant(tr("sip_address"), interpretedAddress)); mAddressList.append(Utils::createFriendAddressVariant(tr("sip_address"), interpretedAddress));
if (mDefaultFullAddress.isEmpty()) mDefaultFullAddress = interpretedFullAddress; if (mDefaultFullAddress.isEmpty()) mDefaultFullAddress = interpretedFullAddress;
@ -507,30 +505,6 @@ void FriendCore::setDefaultAddress(const QString &address) {
} }
} }
LinphoneEnums::ConsolidatedPresence FriendCore::getConsolidatedPresence() const {
return mConsolidatedPresence;
}
void FriendCore::setConsolidatedPresence(LinphoneEnums::ConsolidatedPresence presence) {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
if (mConsolidatedPresence != presence) {
mConsolidatedPresence = presence;
emit consolidatedPresenceChanged(mConsolidatedPresence);
}
}
QDateTime FriendCore::getPresenceTimestamp() const {
return mPresenceTimestamp;
}
void FriendCore::setPresenceTimestamp(QDateTime presenceTimestamp) {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
if (mPresenceTimestamp != presenceTimestamp) {
mPresenceTimestamp = presenceTimestamp;
emit presenceTimestampChanged(mPresenceTimestamp);
}
}
QString FriendCore::getPictureUri() const { QString FriendCore::getPictureUri() const {
return mPictureUri; return mPictureUri;
} }
@ -612,8 +586,8 @@ void FriendCore::writeFromModel(const std::shared_ptr<FriendModel> &model) {
QList<QVariant> addresses; QList<QVariant> addresses;
for (auto &addr : model->getAddresses()) { for (auto &addr : model->getAddresses()) {
addresses.append( addresses.append(Utils::createFriendAddressVariant(tr("sip_address"),
Utils::createFriendAddressVariant(tr("sip_address"), Utils::coreStringToAppString(addr->asStringUriOnly()))); Utils::coreStringToAppString(addr->asStringUriOnly())));
} }
mAddressList = addresses; mAddressList = addresses;
mDefaultAddress = model->getDefaultAddress(); mDefaultAddress = model->getDefaultAddress();
@ -759,3 +733,29 @@ bool FriendCore::getReadOnly() const {
std::shared_ptr<FriendModel> FriendCore::getFriendModel() { std::shared_ptr<FriendModel> FriendCore::getFriendModel() {
return mFriendModel; return mFriendModel;
} }
void FriendCore::setPresence(LinphoneEnums::Presence presence, QString presenceNote) {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
bool notify = false;
if (presence != mPresence) {
mPresence = presence;
notify = true;
}
if (presenceNote != mPresenceNote) {
mPresenceNote = presenceNote;
notify = true;
}
if (notify) emit presenceChanged();
}
QUrl FriendCore::getPresenceIcon() {
return Utils::getPresenceIcon(mPresence);
}
QColor FriendCore::getPresenceColor() {
return Utils::getPresenceColor(mPresence);
}
QString FriendCore::getPresenceStatus() {
return Utils::getPresenceStatus(mPresence);
}

View file

@ -29,6 +29,7 @@
#include "tool/thread/SafeSharedPointer.hpp" #include "tool/thread/SafeSharedPointer.hpp"
#include <linphone++/linphone.hh> #include <linphone++/linphone.hh>
#include <QColor>
#include <QDateTime> #include <QDateTime>
#include <QMap> #include <QMap>
#include <QObject> #include <QObject>
@ -63,9 +64,11 @@ class FriendCore : public QObject, public AbstractObject {
Q_PROPERTY(QString defaultAddress READ getDefaultAddress WRITE setDefaultAddress NOTIFY defaultAddressChanged) Q_PROPERTY(QString defaultAddress READ getDefaultAddress WRITE setDefaultAddress NOTIFY defaultAddressChanged)
Q_PROPERTY(QString defaultFullAddress READ getDefaultFullAddress WRITE setDefaultFullAddress NOTIFY Q_PROPERTY(QString defaultFullAddress READ getDefaultFullAddress WRITE setDefaultFullAddress NOTIFY
defaultFullAddressChanged) defaultFullAddressChanged)
Q_PROPERTY(QDateTime presenceTimestamp READ getPresenceTimestamp NOTIFY presenceTimestampChanged) Q_PROPERTY(LinphoneEnums::Presence presence MEMBER mPresence NOTIFY presenceChanged)
Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY Q_PROPERTY(QUrl presenceIcon READ getPresenceIcon NOTIFY presenceChanged)
consolidatedPresenceChanged) Q_PROPERTY(QColor presenceColor READ getPresenceColor NOTIFY presenceChanged)
Q_PROPERTY(QString presenceStatus READ getPresenceStatus NOTIFY presenceChanged)
Q_PROPERTY(QString presenceNote MEMBER mPresenceNote NOTIFY presenceChanged)
Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged) Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged)
Q_PROPERTY(bool isStored READ getIsStored NOTIFY isStoredChanged) Q_PROPERTY(bool isStored READ getIsStored NOTIFY isStoredChanged)
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE setPictureUri NOTIFY pictureUriChanged) Q_PROPERTY(QString pictureUri READ getPictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
@ -130,12 +133,6 @@ public:
void setDevices(QVariantList devices); void setDevices(QVariantList devices);
Q_INVOKABLE LinphoneEnums::SecurityLevel getSecurityLevelForAddress(const QString &address) const; Q_INVOKABLE LinphoneEnums::SecurityLevel getSecurityLevelForAddress(const QString &address) const;
LinphoneEnums::ConsolidatedPresence getConsolidatedPresence() const;
void setConsolidatedPresence(LinphoneEnums::ConsolidatedPresence presence);
QDateTime getPresenceTimestamp() const;
void setPresenceTimestamp(QDateTime presenceTimestamp);
bool getIsSaved() const; bool getIsSaved() const;
void setIsSaved(bool isSaved); void setIsSaved(bool isSaved);
@ -146,8 +143,6 @@ public:
void setPictureUri(const QString &uri); void setPictureUri(const QString &uri);
void onPictureUriChanged(QString uri); void onPictureUriChanged(QString uri);
void onPresenceReceived(LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp);
bool isLdap() const; bool isLdap() const;
bool isAppFriend() const; bool isAppFriend() const;
bool isCardDAV() const; bool isCardDAV() const;
@ -159,6 +154,10 @@ public:
Q_INVOKABLE void save(); Q_INVOKABLE void save();
Q_INVOKABLE void undo(); Q_INVOKABLE void undo();
QColor getPresenceColor();
QString getPresenceStatus();
QUrl getPresenceIcon();
protected: protected:
void resetPhoneNumbers(QList<QVariant> newList); void resetPhoneNumbers(QList<QVariant> newList);
void resetAddresses(QList<QVariant> newList); void resetAddresses(QList<QVariant> newList);
@ -173,8 +172,6 @@ signals:
void addressChanged(); void addressChanged();
void organizationChanged(); void organizationChanged();
void jobChanged(); void jobChanged();
void consolidatedPresenceChanged(LinphoneEnums::ConsolidatedPresence level);
void presenceTimestampChanged(QDateTime presenceTimestamp);
void pictureUriChanged(); void pictureUriChanged();
void saved(); void saved();
void isSavedChanged(bool isSaved); void isSavedChanged(bool isSaved);
@ -186,13 +183,16 @@ signals:
void devicesChanged(); void devicesChanged();
void verifiedDevicesChanged(); void verifiedDevicesChanged();
void lSetStarred(bool starred); void lSetStarred(bool starred);
void presenceChanged();
protected: protected:
void writeIntoModel(std::shared_ptr<FriendModel> model) const; void writeIntoModel(std::shared_ptr<FriendModel> model) const;
void writeFromModel(const std::shared_ptr<FriendModel> &model); void writeFromModel(const std::shared_ptr<FriendModel> &model);
LinphoneEnums::ConsolidatedPresence mConsolidatedPresence = LinphoneEnums::ConsolidatedPresence::Offline; LinphoneEnums::Presence mPresence = LinphoneEnums::Presence::Undefined;
QDateTime mPresenceTimestamp; QColor mPresenceColor;
QString mPresenceStatus;
QString mPresenceNote = "";
QString mGivenName; QString mGivenName;
QString mFamilyName; QString mFamilyName;
QString mFullName; QString mFullName;
@ -214,6 +214,9 @@ protected:
QSharedPointer<SafeConnection<FriendCore, FriendModel>> mFriendModelConnection; QSharedPointer<SafeConnection<FriendCore, FriendModel>> mFriendModelConnection;
QSharedPointer<SafeConnection<FriendCore, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<FriendCore, CoreModel>> mCoreModelConnection;
private:
void setPresence(LinphoneEnums::Presence presence, QString presenceNote);
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -290,6 +290,15 @@ void Notifier::notifyReceivedCall(const shared_ptr<linphone::Call> &call) {
if (!accountModel->getNotificationsAllowed()) { if (!accountModel->getNotificationsAllowed()) {
qInfo() qInfo()
<< "Notifications have been disabled for this account - not creating a notification for incoming call"; << "Notifications have been disabled for this account - not creating a notification for incoming call";
if (accountModel->forwardToVoiceMailInDndPresence()) {
lInfo() << log().arg("Transferring call to voicemail");
auto voicemailAddress = linphone::Factory::get()->createAddress(
Utils::appStringToCoreString(accountModel->getVoicemailAddress()));
if (voicemailAddress) call->transferTo(voicemailAddress);
} else {
lInfo() << log().arg("Declining call.");
call->decline(linphone::Reason::Busy);
}
return; return;
} }
} }
@ -337,7 +346,7 @@ void Notifier::notifyReceivedMessages(const std::shared_ptr<linphone::ChatRoom>
remoteAddress = Utils::coreStringToAppString(remoteAddr->asStringUriOnly()); remoteAddress = Utils::coreStringToAppString(remoteAddr->asStringUriOnly());
auto fileContent = message->getFileTransferInformation(); auto fileContent = message->getFileTransferInformation();
if (!fileContent) { if (!fileContent) {
foreach (auto content, message->getContents()) { for (auto content : message->getContents()) {
if (content->isText()) txt += content->getUtf8Text().c_str(); if (content->isText()) txt += content->getUtf8Text().c_str();
} }
} else if (fileContent->isVoiceRecording()) } else if (fileContent->isVoiceRecording())

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="17" viewBox="0 0 18 17" fill="none">
<path d="M9.26562 1.59375C7.50502 1.59568 5.81707 2.29594 4.57213 3.54088C3.32719 4.78582 2.62693 6.47377 2.625 8.23438V13.8344C2.62535 14.1103 2.7351 14.3748 2.93017 14.5698C3.12524 14.7649 3.38971 14.8746 3.66559 14.875H9.26562C11.0268 14.875 12.7159 14.1754 13.9613 12.93C15.2066 11.6846 15.9062 9.99558 15.9062 8.23438C15.9062 6.47317 15.2066 4.7841 13.9613 3.53874C12.7159 2.29339 11.0268 1.59375 9.26562 1.59375ZM9.26562 13.8125H3.6875V8.23438C3.6875 7.13113 4.01465 6.05265 4.62758 5.13533C5.24052 4.21802 6.1117 3.50305 7.13097 3.08086C8.15024 2.65866 9.27181 2.5482 10.3539 2.76343C11.4359 2.97867 12.4298 3.50993 13.21 4.29004C13.9901 5.07016 14.5213 6.06409 14.7366 7.14614C14.9518 8.22819 14.8413 9.34976 14.4191 10.369C13.9969 11.3883 13.282 12.2595 12.3647 12.8724C11.4473 13.4853 10.3689 13.8125 9.26562 13.8125ZM10.0625 8.5C10.0625 8.65761 10.0158 8.81167 9.9282 8.94272C9.84064 9.07377 9.71619 9.1759 9.57058 9.23622C9.42497 9.29653 9.26474 9.31231 9.11016 9.28156C8.95558 9.25082 8.81359 9.17492 8.70215 9.06348C8.5907 8.95203 8.51481 8.81004 8.48406 8.65546C8.45331 8.50088 8.46909 8.34066 8.52941 8.19505C8.58972 8.04944 8.69186 7.92498 8.82291 7.83742C8.95395 7.74986 9.10802 7.70312 9.26562 7.70312C9.47697 7.70312 9.67966 7.78708 9.8291 7.93652C9.97854 8.08597 10.0625 8.28866 10.0625 8.5ZM7.14062 8.5C7.14062 8.65761 7.09389 8.81167 7.00633 8.94272C6.91877 9.07377 6.79431 9.1759 6.6487 9.23622C6.50309 9.29653 6.34287 9.31231 6.18829 9.28156C6.03371 9.25082 5.89172 9.17492 5.78027 9.06348C5.66883 8.95203 5.59293 8.81004 5.56219 8.65546C5.53144 8.50088 5.54722 8.34066 5.60753 8.19505C5.66785 8.04944 5.76998 7.92498 5.90103 7.83742C6.03208 7.74986 6.18614 7.70312 6.34375 7.70312C6.55509 7.70312 6.75778 7.78708 6.90723 7.93652C7.05667 8.08597 7.14062 8.28866 7.14062 8.5ZM12.9844 8.5C12.9844 8.65761 12.9376 8.81167 12.8501 8.94272C12.7625 9.07377 12.6381 9.1759 12.4925 9.23622C12.3468 9.29653 12.1866 9.31231 12.032 9.28156C11.8775 9.25082 11.7355 9.17492 11.624 9.06348C11.5126 8.95203 11.4367 8.81004 11.4059 8.65546C11.3752 8.50088 11.391 8.34066 11.4513 8.19505C11.5116 8.04944 11.6137 7.92498 11.7448 7.83742C11.8758 7.74986 12.0299 7.70312 12.1875 7.70312C12.3988 7.70312 12.6015 7.78708 12.751 7.93652C12.9004 8.08597 12.9844 8.28866 12.9844 8.5Z" fill="#4E6074"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11" fill="none">
<circle cx="5.5" cy="5.5" r="5" fill="#FFDC2E" stroke="white"/>
</svg>

After

Width:  |  Height:  |  Size: 167 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11" fill="none">
<circle cx="5.5" cy="5.5" r="5" fill="#DD5F5F" stroke="white"/>
</svg>

After

Width:  |  Height:  |  Size: 167 B

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11" fill="none">
<circle cx="5.5" cy="5.5" r="5" fill="#DD5F5F" stroke="white"/>
<path d="M3.4375 5.5H7.5625" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 255 B

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11" fill="none">
<circle cx="5.5" cy="5.5" r="5" fill="#4E6074" stroke="white"/>
</svg>

After

Width:  |  Height:  |  Size: 168 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11" fill="none">
<circle cx="5.5" cy="5.5" r="5" fill="#4FAE80" stroke="white"/>
</svg>

After

Width:  |  Height:  |  Size: 167 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="none">
<path d="M3.52 3.83333V0.5C3.52 0.367392 3.57057 0.240215 3.66059 0.146447C3.75061 0.0526784 3.8727 0 4 0C4.1273 0 4.24939 0.0526784 4.33941 0.146447C4.42943 0.240215 4.48 0.367392 4.48 0.5V3.83333C4.48 3.96594 4.42943 4.09312 4.33941 4.18689C4.24939 4.28065 4.1273 4.33333 4 4.33333C3.8727 4.33333 3.75061 4.28065 3.66059 4.18689C3.57057 4.09312 3.52 3.96594 3.52 3.83333ZM6.182 0.416667C6.07542 0.348304 5.94741 0.326015 5.82528 0.354551C5.70314 0.383086 5.59654 0.460189 5.5282 0.569422C5.45985 0.678655 5.43517 0.811376 5.45942 0.939291C5.48367 1.0672 5.55493 1.18019 5.658 1.25417C6.5364 1.84875 7.04 2.79167 7.04 3.83333C7.04 4.67319 6.71972 5.47864 6.1496 6.0725C5.57949 6.66637 4.80626 7 4 7C3.19374 7 2.42051 6.66637 1.8504 6.0725C1.28028 5.47864 0.96 4.67319 0.96 3.83333C0.96 2.79167 1.4636 1.84875 2.342 1.25208C2.43959 1.1759 2.50568 1.06387 2.52684 0.938764C2.54801 0.813656 2.52267 0.684847 2.45596 0.578498C2.38926 0.47215 2.28619 0.396237 2.1677 0.36618C2.04921 0.336122 1.92418 0.354173 1.818 0.416667C0.6624 1.19917 0 2.44542 0 3.83333C0 4.9384 0.421427 5.99821 1.17157 6.77961C1.92172 7.56101 2.93913 8 4 8C5.06087 8 6.07828 7.56101 6.82843 6.77961C7.57857 5.99821 8 4.9384 8 3.83333C8 2.44542 7.3376 1.19917 6.182 0.416667Z" fill="#DBB820"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="none">
<path d="M4 0C3.20888 0 2.43552 0.234596 1.77772 0.674121C1.11992 1.11365 0.607234 1.73836 0.304484 2.46927C0.00173314 3.20017 -0.0774802 4.00444 0.0768607 4.78036C0.231202 5.55628 0.612165 6.26902 1.17157 6.82843C1.73098 7.38784 2.44372 7.7688 3.21964 7.92314C3.99556 8.07748 4.79983 7.99827 5.53073 7.69552C6.26164 7.39277 6.88635 6.88008 7.32588 6.22228C7.7654 5.56448 8 4.79112 8 4C7.99882 2.93949 7.57702 1.92276 6.82713 1.17287C6.07724 0.422981 5.06051 0.00117638 4 0ZM4 7.11111C3.38468 7.11111 2.78318 6.92865 2.27156 6.58679C1.75994 6.24494 1.36118 5.75905 1.12571 5.19057C0.890237 4.62209 0.828627 3.99655 0.94867 3.39305C1.06871 2.78956 1.36502 2.23521 1.80011 1.80011C2.23521 1.36502 2.78956 1.06871 3.39305 0.948668C3.99655 0.828625 4.62209 0.890235 5.19057 1.12571C5.75905 1.36118 6.24494 1.75994 6.58679 2.27156C6.92865 2.78318 7.11111 3.38468 7.11111 4C7.11023 4.82485 6.78217 5.61566 6.19891 6.19891C5.61566 6.78217 4.82485 7.11023 4 7.11111ZM3.55556 4.14815V2.22222C3.55556 2.10435 3.60238 1.9913 3.68573 1.90795C3.76908 1.8246 3.88213 1.77778 4 1.77778C4.11788 1.77778 4.23092 1.8246 4.31427 1.90795C4.39762 1.9913 4.44445 2.10435 4.44445 2.22222V4.14815C4.44445 4.26602 4.39762 4.37907 4.31427 4.46242C4.23092 4.54577 4.11788 4.59259 4 4.59259C3.88213 4.59259 3.76908 4.54577 3.68573 4.46242C3.60238 4.37907 3.55556 4.26602 3.55556 4.14815ZM4.59259 5.62963C4.59259 5.74683 4.55784 5.8614 4.49272 5.95886C4.42761 6.05631 4.33506 6.13226 4.22678 6.17711C4.11849 6.22196 3.99934 6.2337 3.88439 6.21083C3.76944 6.18797 3.66385 6.13153 3.58097 6.04865C3.4981 5.96578 3.44166 5.86019 3.41879 5.74524C3.39593 5.63029 3.40766 5.51114 3.45252 5.40285C3.49737 5.29457 3.57332 5.20202 3.67077 5.13691C3.76823 5.07179 3.8828 5.03704 4 5.03704C4.15717 5.03704 4.30789 5.09947 4.41903 5.2106C4.53016 5.32173 4.59259 5.47246 4.59259 5.62963Z" fill="#DD5F5F"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8" fill="none">
<circle cx="3.99999" cy="3.99999" r="3.5" transform="rotate(30 3.99999 3.99999)" fill="#EDEDED" stroke="#4FAE80" stroke-linecap="round" stroke-dasharray="4 5"/>
</svg>

After

Width:  |  Height:  |  Size: 260 B

View file

@ -704,30 +704,6 @@
</context> </context>
<context> <context>
<name>CallHistoryLayout</name> <name>CallHistoryLayout</name>
<message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="131"/>
<source>contact_presence_status_online</source>
<extracomment>&quot;En ligne&quot;</extracomment>
<translation>Online</translation>
</message>
<message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="134"/>
<source>contact_presence_status_busy</source>
<extracomment>&quot;Occupé&quot;</extracomment>
<translation>Busy</translation>
</message>
<message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="137"/>
<source>contact_presence_status_do_not_disturb</source>
<extracomment>&quot;Ne pas déranger&quot;</extracomment>
<translation>Do not disturb</translation>
</message>
<message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="139"/>
<source>contact_presence_status_offline</source>
<extracomment>&quot;Hors ligne&quot;</extracomment>
<translation>Offline</translation>
</message>
<message> <message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="163"/> <location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="163"/>
<source>meeting_info_join_title</source> <source>meeting_info_join_title</source>
@ -4049,6 +4025,36 @@ To enable them in a commercial project, please contact us.</translation>
</context> </context>
<context> <context>
<name>Utils</name> <name>Utils</name>
<message>
<location filename="../../tool/Utils.cpp" line="1519"/>
<source>contact_presence_status_available</source>
<extracomment>&quot;En ligne&quot;</extracomment>
<translation>Available</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="1525"/>
<source>contact_presence_status_busy</source>
<extracomment>&quot;Occupé&quot;</extracomment>
<translation>Busy</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="1528"/>
<source>contact_presence_status_do_not_disturb</source>
<extracomment>&quot;Ne pas déranger&quot;</extracomment>
<translation>Do not disturb</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="1531"/>
<source>contact_presence_status_offline</source>
<extracomment>&quot;Hors ligne&quot;</extracomment>
<translation>Offline</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="1522"/>
<source>contact_presence_status_away</source>
<extracomment>&quot;Absent&quot;</extracomment>
<translation>Idle/Away</translation>
</message>
<message> <message>
<location filename="../../tool/Utils.cpp" line="151"/> <location filename="../../tool/Utils.cpp" line="151"/>
<source>information_popup_call_not_created_message</source> <source>information_popup_call_not_created_message</source>
@ -5605,4 +5611,131 @@ To enable them in a commercial project, please contact us.</translation>
<translation>Call forward deactivated</translation> <translation>Call forward deactivated</translation>
</message> </message>
</context> </context>
<context>
<name>Presence</name>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="12"/>
<source>contact_presence_status_available</source>
<extracomment>&quot;En ligne&quot;</extracomment>
<translation>Available</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="14"/>
<source>contact_presence_status_busy</source>
<extracomment>&quot;Occupé&quot;</extracomment>
<translation>Busy</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="15"/>
<source>contact_presence_status_do_not_disturb</source>
<extracomment>&quot;Ne pas déranger&quot;</extracomment>
<translation>Do not disturb</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="16"/>
<source>contact_presence_status_offline</source>
<extracomment>&quot;Hors ligne&quot;</extracomment>
<translation>Offline</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="13"/>
<source>contact_presence_status_away</source>
<extracomment>&quot;Absent&quot;</extracomment>
<translation>Idle/Away</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="13"/>
<source>contact_presence_reset_status</source>
<extracomment>&quot;Reset status&quot;</extracomment>
<translation>Reset status</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_save_status</source>
<extracomment>&quot;Save&quot;</extracomment>
<translation>Save</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_edit_status</source>
<extracomment>&quot;Edit&quot;</extracomment>
<translation>Edit</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_delete_status</source>
<extracomment>&quot;Delete&quot;</extracomment>
<translation>Delete</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_delete_status</source>
<extracomment>&quot;Delete&quot;</extracomment>
<translation>Delete</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_button_set_custom_status</source>
<extracomment>&quot;Set&quot;</extracomment>
<translation>Set</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_button_edit_custom_status</source>
<extracomment>&quot;Edit&quot;</extracomment>
<translation>Edit</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_button_delete_custom_status</source>
<extracomment>&quot;Delete&quot;</extracomment>
<translation>Delete</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_button_set_custom_status_title</source>
<extracomment>&quot;Set a custom status message&quot;</extracomment>
<translation>Set a custom status message</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_custom_status</source>
<extracomment>&quot;Custom status&quot;</extracomment>
<translation>Custom status</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml"/>
<source>contact_presence_custom_status</source>
<extracomment>&quot;Custom status&quot;</extracomment>
<translation>Custom status</translation>
</message>
</context>
<context>
<name>PresenceSetCustomStatus</name>
<message>
<location filename="../../view/Control/Display/Contact/PresenceSetCustomStatus.qml"/>
<source>contact_presence_button_set_custom_status_title</source>
<extracomment>&quot;Set a custom status message&quot;</extracomment>
<translation>Set a custom status message</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/PresenceSetCustomStatus.qml"/>
<source>contact_presence_button_save_custom_status</source>
<extracomment>&quot;Save&quot;</extracomment>
<translation>Save</translation>
</message>
</context>
<context>
<name>PresenceNoteLayout</name>
<message>
<location filename="../../view/Control/Container/Contact/PresenceNoteLayout.qml"/>
<source>contact_presence_note_title</source>
<extracomment>&quot;Message personnalisé&quot;</extracomment>
<translation>Custom message</translation>
</message>
</context>
</TS> </TS>

View file

@ -704,30 +704,6 @@
</context> </context>
<context> <context>
<name>CallHistoryLayout</name> <name>CallHistoryLayout</name>
<message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="131"/>
<source>contact_presence_status_online</source>
<extracomment>&quot;En ligne&quot;</extracomment>
<translation>En ligne</translation>
</message>
<message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="134"/>
<source>contact_presence_status_busy</source>
<extracomment>&quot;Occupé&quot;</extracomment>
<translation>Occupé</translation>
</message>
<message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="137"/>
<source>contact_presence_status_do_not_disturb</source>
<extracomment>&quot;Ne pas déranger&quot;</extracomment>
<translation>Ne pas déranger</translation>
</message>
<message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="139"/>
<source>contact_presence_status_offline</source>
<extracomment>&quot;Hors ligne&quot;</extracomment>
<translation>Hors ligne</translation>
</message>
<message> <message>
<location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="163"/> <location filename="../../view/Control/Container/Call/CallHistoryLayout.qml" line="163"/>
<source>meeting_info_join_title</source> <source>meeting_info_join_title</source>
@ -4041,6 +4017,36 @@ Pour les activer dans un projet commercial, merci de nous contacter.</translatio
</context> </context>
<context> <context>
<name>Utils</name> <name>Utils</name>
<message>
<location filename="../../tool/Utils.cpp" line="1519"/>
<source>contact_presence_status_available</source>
<extracomment>&quot;En ligne&quot;</extracomment>
<translation>Disponible</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="1525"/>
<source>contact_presence_status_busy</source>
<extracomment>&quot;Occupé&quot;</extracomment>
<translation>Occupé</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="1528"/>
<source>contact_presence_status_do_not_disturb</source>
<extracomment>&quot;Ne pas déranger&quot;</extracomment>
<translation>Ne pas déranger</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="1531"/>
<source>contact_presence_status_offline</source>
<extracomment>&quot;Hors ligne&quot;</extracomment>
<translation>Hors ligne</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="1522"/>
<source>contact_presence_status_away</source>
<extracomment>&quot;Absent&quot;</extracomment>
<translation>Inactif/Absent</translation>
</message>
<message> <message>
<location filename="../../tool/Utils.cpp" line="151"/> <location filename="../../tool/Utils.cpp" line="151"/>
<source>information_popup_call_not_created_message</source> <source>information_popup_call_not_created_message</source>
@ -5520,4 +5526,46 @@ Pour les activer dans un projet commercial, merci de nous contacter.</translatio
<translation>Ok</translation> <translation>Ok</translation>
</message> </message>
</context> </context>
<context>
<name>Presence</name>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="12"/>
<source>contact_presence_status_available</source>
<extracomment>&quot;En ligne&quot;</extracomment>
<translation>Disponible</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="14"/>
<source>contact_presence_status_busy</source>
<extracomment>&quot;Occupé&quot;</extracomment>
<translation>Occupé</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="15"/>
<source>contact_presence_status_do_not_disturb</source>
<extracomment>&quot;Ne pas déranger&quot;</extracomment>
<translation>Ne pas déranger</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="16"/>
<source>contact_presence_status_offline</source>
<extracomment>&quot;Hors ligne&quot;</extracomment>
<translation>Hors ligne</translation>
</message>
<message>
<location filename="../../view/Control/Display/Contact/Presence.qml" line="13"/>
<source>contact_presence_status_away</source>
<extracomment>&quot;Absent&quot;</extracomment>
<translation>Inactif/Absent</translation>
</message>
</context>
<context>
<name>PresenceNoteLayout</name>
<message>
<location filename="../../view/Control/Container/Contact/PresenceNoteLayout.qml"/>
<source>contact_presence_note_title</source>
<extracomment>&quot;Message personnalisé&quot;</extracomment>
<translation>Message personnalisé</translation>
</message>
</context>
</TS> </TS>

View file

@ -22,6 +22,8 @@
#include "core/path/Paths.hpp" #include "core/path/Paths.hpp"
#include "model/core/CoreModel.hpp" #include "model/core/CoreModel.hpp"
#include "model/setting/SettingsModel.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp" #include "tool/Utils.hpp"
#include "tool/providers/AvatarProvider.hpp" #include "tool/providers/AvatarProvider.hpp"
#include <QDebug> #include <QDebug>
@ -467,3 +469,94 @@ void AccountModel::removeUserData(const std::shared_ptr<linphone::Account> &acco
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
userDataMap.remove(account); userDataMap.remove(account);
} }
// Up to date there are api to get/set presence from/to a linphone account object
// therefore retrieved/set from core
LinphoneEnums::Presence AccountModel::getPresence() {
auto presenceModel = CoreModel::getInstance()->getCore()->getPresenceModel(); // No api (yet) at the account level
return ToolModel::corePresenceModelToAppPresence(presenceModel);
}
void AccountModel::setPresence(LinphoneEnums::Presence presence,
bool userInitiated,
bool resetToAuto,
QString presenceNote) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
lDebug() << log().arg("presence set request to: " + LinphoneEnums::toString(presence) + " user initiated? " +
(userInitiated ? "true" : "false") + " reset to auto? " + (resetToAuto ? "true" : "false"));
auto core = CoreModel::getInstance()->getCore();
if (core->getGlobalState() != linphone::GlobalState::On) {
lWarning() << log().arg("Unable to set presence this time as core state is not ON");
return;
}
if (presence == LinphoneEnums::Presence::Undefined) {
lWarning() << log().arg("Unable to set Undefined presence");
return;
}
auto accountSection = ToolModel::configAccountSection(mMonitor);
if (!resetToAuto && !userInitiated &&
!core->getConfig()->getString(accountSection, "explicit_presence", "").empty()) {
lDebug() << log().arg("Ignoring automatic presence update, as user already set a presence explicitely : ")
<< Utils::coreStringToAppString(core->getConfig()->getString(accountSection, "explicit_presence", ""));
return;
}
if (userInitiated) {
core->getConfig()->setString(accountSection, "explicit_presence",
Utils::appStringToCoreString(LinphoneEnums::toString(presence)));
core->getConfig()->sync();
}
if (resetToAuto) {
core->getConfig()->cleanEntry(accountSection, "explicit_presence");
core->getConfig()->sync();
}
if (!presenceNote.isEmpty()) {
core->getConfig()->setString(accountSection, "presence_note", Utils::appStringToCoreString(presenceNote));
core->getConfig()->sync();
}
if (!mMonitor->getParams()->publishEnabled()) {
auto params = mMonitor->getParams()->clone();
params->enablePublish(true);
mMonitor->setParams(params);
}
auto presenceModel = ToolModel::appPresenceToCorePresenceModel(presence, presenceNote);
core->setPresenceModel(presenceModel); // No api (yet) at the account level
if (presence == LinphoneEnums::Presence::Offline) {
for (auto friendList : core->getFriendsLists())
friendList->enableSubscriptions(false);
} else {
for (auto friendList : core->getFriendsLists())
friendList->enableSubscriptions(true);
}
setNotificationsAllowed(
presence != LinphoneEnums::Presence::DoNotDisturb &&
(presence != LinphoneEnums::Presence::Away ||
core->getConfig()->getBool(accountSection, "allow_notifications_in_presence_away", true)) &&
(presence != LinphoneEnums::Presence::Busy ||
core->getConfig()->getBool(accountSection, "allow_notifications_in_presence_busy", true)));
if (!SettingsModel::dndEnabled(core->getConfig())) {
SettingsModel::getInstance()->enableRinging(presence != LinphoneEnums::Presence::DoNotDisturb);
}
emit presenceChanged(presence, userInitiated);
}
bool AccountModel::forwardToVoiceMailInDndPresence() {
auto accountSection = ToolModel::configAccountSection(mMonitor);
auto core = CoreModel::getInstance()->getCore();
return core->getConfig()->getBool(accountSection, "forward_to_voicemail_in_dnd_presence", false);
}

View file

@ -24,6 +24,7 @@
#include "model/listener/Listener.hpp" #include "model/listener/Listener.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
#include "tool/LinphoneEnums.hpp"
#include <QObject> #include <QObject>
#include <linphone++/linphone.hh> #include <linphone++/linphone.hh>
@ -83,6 +84,10 @@ public:
bool getShowMwi(); bool getShowMwi();
void setVoicemailAddress(QString value); void setVoicemailAddress(QString value);
QString getVoicemailAddress() const; QString getVoicemailAddress() const;
LinphoneEnums::Presence getPresence();
void setPresence(LinphoneEnums::Presence presence, bool userInitiated, bool resetToAuto, QString presenceNote);
std::string configAccountSection();
bool forwardToVoiceMailInDndPresence();
signals: signals:
void registrationStateChanged(const std::shared_ptr<linphone::Account> &account, void registrationStateChanged(const std::shared_ptr<linphone::Account> &account,
@ -112,6 +117,7 @@ signals:
void voicemailCountChanged(int count); void voicemailCountChanged(int count);
void showMwiChanged(bool show); void showMwiChanged(bool show);
void voicemailAddressChanged(QString value); void voicemailAddressChanged(QString value);
void presenceChanged(LinphoneEnums::Presence presence, bool userInitiated);
private: private:
/**Linphone **/ /**Linphone **/

View file

@ -310,7 +310,7 @@ void OIDCModel::setBearers() {
qWarning() << "No refresh token found"; qWarning() << "No refresh token found";
} }
CoreModel::getInstance()->getCore()->addAuthInfo(mAuthInfo); CoreModel::getInstance()->getCore()->addAuthInfo(mAuthInfo);
emit CoreModel::getInstance() -> bearerAccountAdded(); emit CoreModel::getInstance()->bearerAccountAdded();
emit finished(); emit finished();
} }
QString OIDCModel::idToken() const { QString OIDCModel::idToken() const {
@ -319,4 +319,4 @@ QString OIDCModel::idToken() const {
#else #else
return mIdToken; return mIdToken;
#endif #endif
} }

View file

@ -425,6 +425,14 @@ void CoreModel::onCallStateChanged(const std::shared_ptr<linphone::Core> &core,
core->getCallsNb() == 0) { // Disable tones in DND mode if no more calls are running. core->getCallsNb() == 0) { // Disable tones in DND mode if no more calls are running.
SettingsModel::getInstance()->setCallToneIndicationsEnabled(false); SettingsModel::getInstance()->setCallToneIndicationsEnabled(false);
} }
App::postModelAsync([core]() {
for (int i = 0; i < App::getInstance()->getAccountList()->rowCount(); ++i) {
auto accountCore = App::getInstance()->getAccountList()->getAt<AccountCore>(i);
emit accountCore->lSetPresence(core->getCallsNb() == 0 ? LinphoneEnums::Presence::Online
: LinphoneEnums::Presence::Busy,
false, false);
}
});
emit callStateChanged(core, call, state, message); emit callStateChanged(core, call, state, message);
} }
void CoreModel::onCallStatsUpdated(const std::shared_ptr<linphone::Core> &core, void CoreModel::onCallStatsUpdated(const std::shared_ptr<linphone::Core> &core,

View file

@ -71,14 +71,6 @@ std::shared_ptr<linphone::Friend> FriendModel::getFriend() const {
return mMonitor; return mMonitor;
} }
QDateTime FriendModel::getPresenceTimestamp() const {
if (mMonitor && mMonitor->getPresenceModel()) {
time_t timestamp = mMonitor->getPresenceModel()->getLatestActivityTimestamp();
if (timestamp == -1) return QDateTime();
else return QDateTime::fromMSecsSinceEpoch(timestamp * 1000);
} else return QDateTime();
}
void FriendModel::setAddress(const std::shared_ptr<linphone::Address> &address) { void FriendModel::setAddress(const std::shared_ptr<linphone::Address> &address) {
if (!mMonitor) return; if (!mMonitor) return;
if (address) { if (address) {
@ -316,8 +308,22 @@ void FriendModel::setStarred(bool starred) {
mMonitor->setStarred(starred); mMonitor->setStarred(starred);
emit starredChanged(starred); emit starredChanged(starred);
} }
void FriendModel::onPresenceReceived(const std::shared_ptr<linphone::Friend> &contact) { void FriendModel::onPresenceReceived(const std::shared_ptr<linphone::Friend> &contact) {
emit presenceReceived(LinphoneEnums::fromLinphone(contact->getConsolidatedPresence()), getPresenceTimestamp()); emit presenceReceived(getPresence(contact), getPresenceNote(contact));
}
LinphoneEnums::Presence FriendModel::getPresence(const std::shared_ptr<linphone::Friend> &contact) {
auto presenceModel = contact->getPresenceModel();
return ToolModel::corePresenceModelToAppPresence(presenceModel);
}
QString FriendModel::getPresenceNote(const std::shared_ptr<linphone::Friend> &contact) {
auto presenceModel = contact->getPresenceModel();
auto note = presenceModel && presenceModel->getNote(Utils::appStringToCoreString(QLocale().name().left(2)))
? presenceModel->getNote(Utils::appStringToCoreString(QLocale().name().left(2)))->getContent()
: "";
return Utils::coreStringToAppString(note);
} }
QString FriendModel::getPictureUri() const { QString FriendModel::getPictureUri() const {

View file

@ -91,6 +91,8 @@ public:
void onUpdated(const std::shared_ptr<linphone::Friend> &data); void onUpdated(const std::shared_ptr<linphone::Friend> &data);
void onRemoved(const std::shared_ptr<linphone::Friend> &data); void onRemoved(const std::shared_ptr<linphone::Friend> &data);
LinphoneEnums::Presence getPresence(const std::shared_ptr<linphone::Friend> &contact);
QString mFullName; QString mFullName;
signals: signals:
@ -105,12 +107,13 @@ signals:
void familyNameChanged(const QString &name); void familyNameChanged(const QString &name);
void organizationChanged(const QString &orga); void organizationChanged(const QString &orga);
void jobChanged(const QString &job); void jobChanged(const QString &job);
void presenceReceived(LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp); void presenceReceived(LinphoneEnums::Presence presence, QString presenceNote);
void updated(); void updated();
void removed(); void removed();
private: private:
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
QString getPresenceNote(const std::shared_ptr<linphone::Friend> &contact);
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// LINPHONE // LINPHONE

View file

@ -579,4 +579,85 @@ std::shared_ptr<linphone::ChatRoom> ToolModel::createChatForAddress(std::shared_
} }
auto chatRoom = core->createChatRoom(params, participants); auto chatRoom = core->createChatRoom(params, participants);
return chatRoom; return chatRoom;
} }
// Presence mapping from SDK PresenceModel/RFC 3863 <-> Linphone UI (5 statuses Online, Offline, Away, Busy, DND).
// Online = Basic Status open with no activity
// Busy = Basic Status open with activity Busy and description busy
// Away = Basic Status open with activity Away and description away
// Offline = Basic Status open with activity PermanentAbsence and description offline
// DND = Basic Status open with activity Other and description dnd
// Note : close status on the last 2 items would be preferrable, but they currently trigger multiple tuple NOTIFY from
// flexisip presence server Note 2 : close status with no activity triggers an unsubscribe.
LinphoneEnums::Presence
ToolModel::corePresenceModelToAppPresence(std::shared_ptr<const linphone::PresenceModel> presenceModel) {
if (!presenceModel) {
lWarning() << sLog().arg("presence model is null.");
return LinphoneEnums::Presence::Undefined;
}
auto presenceActivity = presenceModel->getActivity();
if (presenceModel->getBasicStatus() == linphone::PresenceBasicStatus::Open) {
if (!presenceActivity) return LinphoneEnums::Presence::Online;
else if (presenceActivity->getType() == linphone::PresenceActivity::Type::Busy)
return LinphoneEnums::Presence::Busy;
else if (presenceActivity->getType() == linphone::PresenceActivity::Type::Away)
return LinphoneEnums::Presence::Away;
else if (presenceActivity->getType() == linphone::PresenceActivity::Type::PermanentAbsence)
return LinphoneEnums::Presence::Offline;
else if (presenceActivity->getType() == linphone::PresenceActivity::Type::Other)
return LinphoneEnums::Presence::DoNotDisturb;
else {
lWarning() << sLog().arg("unhandled core activity type : ") << (int)presenceActivity->getType();
return LinphoneEnums::Presence::Undefined;
}
}
return LinphoneEnums::Presence::Undefined;
}
std::shared_ptr<linphone::PresenceModel> ToolModel::appPresenceToCorePresenceModel(LinphoneEnums::Presence presence,
QString presenceNote) {
auto presenceModel = CoreModel::getInstance()->getCore()->createPresenceModel();
switch (presence) {
case LinphoneEnums::Presence::Online:
presenceModel->setBasicStatus(linphone::PresenceBasicStatus::Open);
break;
case LinphoneEnums::Presence::Busy:
presenceModel->setBasicStatus(linphone::PresenceBasicStatus::Open);
presenceModel->setActivity(linphone::PresenceActivity::Type::Busy, "busy");
break;
case LinphoneEnums::Presence::Away:
presenceModel->setBasicStatus(linphone::PresenceBasicStatus::Open);
presenceModel->setActivity(linphone::PresenceActivity::Type::Away, "away");
break;
case LinphoneEnums::Presence::Offline:
presenceModel->setBasicStatus(linphone::PresenceBasicStatus::Open);
presenceModel->setActivity(linphone::PresenceActivity::Type::PermanentAbsence, "offline");
break;
case LinphoneEnums::Presence::DoNotDisturb:
presenceModel->setBasicStatus(linphone::PresenceBasicStatus::Open);
presenceModel->setActivity(linphone::PresenceActivity::Type::Other, "dnd");
break;
case LinphoneEnums::Presence::Undefined:
lWarning() << sLog().arg("Trying to build PresenceModel from Undefined presence ");
return nullptr;
}
if (!presenceNote.isEmpty()) {
auto note = CoreModel::getInstance()->getCore()->createPresenceNote(
Utils::appStringToCoreString(presenceNote), Utils::appStringToCoreString(QLocale().name().left(2)));
auto service = presenceModel->getNthService(0);
service->addNote(note);
}
return presenceModel;
}
std::string ToolModel::configAccountSection(const std::shared_ptr<linphone::Account> &account) {
int count = 0;
for (auto item : CoreModel::getInstance()->getCore()->getAccountList()) {
if (account == item) return "proxy_" + std::to_string(count);
count++;
}
return "account";
}

View file

@ -88,6 +88,12 @@ public:
static std::shared_ptr<linphone::ChatRoom> lookupChatForAddress(std::shared_ptr<linphone::Address> remoteAddress); static std::shared_ptr<linphone::ChatRoom> lookupChatForAddress(std::shared_ptr<linphone::Address> remoteAddress);
static std::shared_ptr<linphone::ChatRoom> createChatForAddress(std::shared_ptr<linphone::Address> remoteAddress); static std::shared_ptr<linphone::ChatRoom> createChatForAddress(std::shared_ptr<linphone::Address> remoteAddress);
static LinphoneEnums::Presence
corePresenceModelToAppPresence(std::shared_ptr<const linphone::PresenceModel> presenceModel);
static std::shared_ptr<linphone::PresenceModel> appPresenceToCorePresenceModel(LinphoneEnums::Presence presence,
QString presenceNote);
static std::string configAccountSection(const std::shared_ptr<linphone::Account> &account);
private: private:
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -44,6 +44,7 @@ void LinphoneEnums::registerMetaTypes() {
qRegisterMetaType<LinphoneEnums::TunnelMode>(); qRegisterMetaType<LinphoneEnums::TunnelMode>();
qRegisterMetaType<LinphoneEnums::TransportType>(); qRegisterMetaType<LinphoneEnums::TransportType>();
qRegisterMetaType<LinphoneEnums::VideoSourceScreenSharingType>(); qRegisterMetaType<LinphoneEnums::VideoSourceScreenSharingType>();
qRegisterMetaType<LinphoneEnums::Presence>();
qmlRegisterUncreatableMetaObject(LinphoneEnums::staticMetaObject, Constants::MainQmlUri, 1, 0, "LinphoneEnums", qmlRegisterUncreatableMetaObject(LinphoneEnums::staticMetaObject, Constants::MainQmlUri, 1, 0, "LinphoneEnums",
"Only enums"); "Only enums");
} }
@ -207,7 +208,8 @@ LinphoneEnums::ConferenceLayout LinphoneEnums::fromLinphone(const linphone::Conf
QString LinphoneEnums::toString(LinphoneEnums::ConferenceLayout layout) { QString LinphoneEnums::toString(LinphoneEnums::ConferenceLayout layout) {
//: "Participant actif" //: "Participant actif"
if (layout == LinphoneEnums::ConferenceLayout::ActiveSpeaker) return QObject::tr("conference_layout_active_speaker"); if (layout == LinphoneEnums::ConferenceLayout::ActiveSpeaker)
return QObject::tr("conference_layout_active_speaker");
//: "Mosaïque" //: "Mosaïque"
else if (layout == LinphoneEnums::ConferenceLayout::Grid) return QObject::tr("conference_layout_grid"); else if (layout == LinphoneEnums::ConferenceLayout::Grid) return QObject::tr("conference_layout_grid");
//: "Audio uniquement" //: "Audio uniquement"
@ -249,11 +251,22 @@ LinphoneEnums::ConferenceSchedulerState LinphoneEnums::fromLinphone(const linpho
return static_cast<LinphoneEnums::ConferenceSchedulerState>(state); return static_cast<LinphoneEnums::ConferenceSchedulerState>(state);
} }
linphone::ConsolidatedPresence LinphoneEnums::toLinphone(const LinphoneEnums::ConsolidatedPresence &data) { QString LinphoneEnums::toString(Presence presence) {
return static_cast<linphone::ConsolidatedPresence>(data); const QMetaObject &metaObj = LinphoneEnums::staticMetaObject;
int index = metaObj.indexOfEnumerator("Presence");
QMetaEnum metaEnum = metaObj.enumerator(index);
return metaEnum.valueToKey(static_cast<int>(presence));
} }
LinphoneEnums::ConsolidatedPresence LinphoneEnums::fromLinphone(const linphone::ConsolidatedPresence &data) {
return static_cast<LinphoneEnums::ConsolidatedPresence>(data); LinphoneEnums::Presence LinphoneEnums::fromString(const QString &key) {
const QMetaObject &metaObj = LinphoneEnums::staticMetaObject;
int index = metaObj.indexOfEnumerator("Presence");
QMetaEnum metaEnum = metaObj.enumerator(index);
int value = metaEnum.keyToValue(key.toUtf8().constData());
if (value == -1) {
return LinphoneEnums::Presence::Undefined;
}
return static_cast<LinphoneEnums::Presence>(value);
} }
linphone::MagicSearch::Aggregation LinphoneEnums::toLinphone(const LinphoneEnums::MagicSearchAggregation &data) { linphone::MagicSearch::Aggregation LinphoneEnums::toLinphone(const LinphoneEnums::MagicSearchAggregation &data) {

View file

@ -250,16 +250,12 @@ Q_ENUM_NS(ConferenceSchedulerState)
linphone::ConferenceScheduler::State toLinphone(const LinphoneEnums::ConferenceSchedulerState &state); linphone::ConferenceScheduler::State toLinphone(const LinphoneEnums::ConferenceSchedulerState &state);
LinphoneEnums::ConferenceSchedulerState fromLinphone(const linphone::ConferenceScheduler::State &state); LinphoneEnums::ConferenceSchedulerState fromLinphone(const linphone::ConferenceScheduler::State &state);
enum class ConsolidatedPresence { // App Presence
Online = int(linphone::ConsolidatedPresence::Online), enum class Presence { Undefined, Online, Busy, DoNotDisturb, Offline, Away };
Busy = int(linphone::ConsolidatedPresence::Busy), Q_ENUM_NS(Presence);
DoNotDisturb = int(linphone::ConsolidatedPresence::DoNotDisturb),
Offline = int(linphone::ConsolidatedPresence::Offline)
};
Q_ENUM_NS(ConsolidatedPresence);
linphone::ConsolidatedPresence toLinphone(const LinphoneEnums::ConsolidatedPresence &state); QString toString(Presence presence);
LinphoneEnums::ConsolidatedPresence fromLinphone(const linphone::ConsolidatedPresence &state); Presence fromString(const QString &key);
enum class MagicSearchAggregation { enum class MagicSearchAggregation {
Friend = int(linphone::MagicSearch::Aggregation::Friend), Friend = int(linphone::MagicSearch::Aggregation::Friend),

View file

@ -43,6 +43,8 @@
#include <QHostAddress> #include <QHostAddress>
#include <QImageReader> #include <QImageReader>
#include <QProcess> #include <QProcess>
#include <QQmlComponent>
#include <QQmlProperty>
#include <QQuickWindow> #include <QQuickWindow>
#include <QRandomGenerator> #include <QRandomGenerator>
#include <QRegularExpression> #include <QRegularExpression>
@ -1620,3 +1622,126 @@ void Utils::runCommandLine(const QString command) {
lWarning() << "Unsupported OS!"; lWarning() << "Unsupported OS!";
#endif #endif
} }
// Presence
QColor Utils::getDefaultStyleColor(const QString &colorName) {
static QObject *defaultStyleSingleton = nullptr;
if (!defaultStyleSingleton) {
QQmlComponent component(App::getInstance()->mEngine, QUrl("qrc:/qt/qml/Linphone/view/Style/DefaultStyle.qml"));
defaultStyleSingleton = component.create();
}
return QQmlProperty::read(defaultStyleSingleton, colorName).value<QColor>();
}
QUrl Utils::getAppIcon(const QString &iconName) {
static QObject *appIconsSingleton = nullptr;
if (!appIconsSingleton) {
QQmlComponent component(App::getInstance()->mEngine, QUrl("qrc:/qt/qml/Linphone/view/Style/AppIcons.qml"));
appIconsSingleton = component.create();
}
return QQmlProperty::read(appIconsSingleton, iconName).value<QUrl>();
}
QColor Utils::getPresenceColor(LinphoneEnums::Presence presence) {
mustBeInMainThread(sLog().arg(Q_FUNC_INFO));
QColor presenceColor = QColorConstants::Transparent;
switch (presence) {
case LinphoneEnums::Presence::Online:
presenceColor = Utils::getDefaultStyleColor("success_500main");
break;
case LinphoneEnums::Presence::Away:
presenceColor = Utils::getDefaultStyleColor("warning_500_main");
break;
case LinphoneEnums::Presence::Busy:
presenceColor = Utils::getDefaultStyleColor("danger_500main");
break;
case LinphoneEnums::Presence::DoNotDisturb:
presenceColor = Utils::getDefaultStyleColor("danger_500main");
break;
case LinphoneEnums::Presence::Offline:
presenceColor = Utils::getDefaultStyleColor("main2_600");
break;
case LinphoneEnums::Presence::Undefined:
presenceColor = Utils::getDefaultStyleColor("transparent");
break;
}
return presenceColor;
}
QUrl Utils::getPresenceIcon(LinphoneEnums::Presence presence) {
mustBeInMainThread(sLog().arg(Q_FUNC_INFO));
QUrl presenceIcon;
switch (presence) {
case LinphoneEnums::Presence::Online:
presenceIcon = Utils::getAppIcon("presenceOnline");
break;
case LinphoneEnums::Presence::Away:
presenceIcon = Utils::getAppIcon("presenceAway");
break;
case LinphoneEnums::Presence::Busy:
presenceIcon = Utils::getAppIcon("presenceBusy");
break;
case LinphoneEnums::Presence::DoNotDisturb:
presenceIcon = Utils::getAppIcon("presenceDoNotDisturb");
break;
case LinphoneEnums::Presence::Offline:
presenceIcon = Utils::getAppIcon("presenceOffline");
break;
case LinphoneEnums::Presence::Undefined:
presenceIcon = QUrl("");
break;
}
return presenceIcon;
}
QUrl Utils::getRegistrationStateIcon(LinphoneEnums::RegistrationState state) {
mustBeInMainThread(sLog().arg(Q_FUNC_INFO));
QUrl registrationStateIcon;
switch (state) {
case LinphoneEnums::RegistrationState::Refreshing:
registrationStateIcon = Utils::getAppIcon("regitrationProgress");
break;
case LinphoneEnums::RegistrationState::Progress:
registrationStateIcon = Utils::getAppIcon("regitrationProgress");
break;
case LinphoneEnums::RegistrationState::Failed:
registrationStateIcon = Utils::getAppIcon("regitrationError");
break;
case LinphoneEnums::RegistrationState::Cleared:
registrationStateIcon = Utils::getAppIcon("regitrationDeactivated");
break;
case LinphoneEnums::RegistrationState::None:
registrationStateIcon = Utils::getAppIcon("regitrationDeactivated");
break;
default:
registrationStateIcon = QUrl();
}
return registrationStateIcon;
}
QString Utils::getPresenceStatus(LinphoneEnums::Presence presence) {
mustBeInMainThread(sLog().arg(Q_FUNC_INFO));
QString presenceStatus = "";
switch (presence) {
case LinphoneEnums::Presence::Online:
presenceStatus = tr("contact_presence_status_available");
break;
case LinphoneEnums::Presence::Away:
presenceStatus = tr("contact_presence_status_away");
break;
case LinphoneEnums::Presence::Busy:
presenceStatus = tr("contact_presence_status_busy");
break;
case LinphoneEnums::Presence::DoNotDisturb:
presenceStatus = tr("contact_presence_status_do_not_disturb");
break;
case LinphoneEnums::Presence::Offline:
presenceStatus = tr("contact_presence_status_offline");
break;
case LinphoneEnums::Presence::Undefined:
presenceStatus = "";
break;
}
return presenceStatus;
}

View file

@ -142,6 +142,9 @@ public:
Q_INVOKABLE static QString getFileChecksum(const QString &filePath); Q_INVOKABLE static QString getFileChecksum(const QString &filePath);
Q_INVOKABLE QList<QVariant> append(const QList<QVariant> a, const QList<QVariant> b); Q_INVOKABLE QList<QVariant> append(const QList<QVariant> a, const QList<QVariant> b);
Q_INVOKABLE QString getAddressToDisplay(QVariantList addressList, QString filter, QString defaultAddress); Q_INVOKABLE QString getAddressToDisplay(QVariantList addressList, QString filter, QString defaultAddress);
Q_INVOKABLE static QColor getPresenceColor(LinphoneEnums::Presence presence);
Q_INVOKABLE static QUrl getPresenceIcon(LinphoneEnums::Presence presence);
Q_INVOKABLE static QString getPresenceStatus(LinphoneEnums::Presence presence);
Q_INVOKABLE static VariantObject *getCurrentCallChat(CallGui *call); Q_INVOKABLE static VariantObject *getCurrentCallChat(CallGui *call);
Q_INVOKABLE static VariantObject *getChatForAddress(QString address); Q_INVOKABLE static VariantObject *getChatForAddress(QString address);
@ -195,6 +198,12 @@ public:
static void runCommandLine(QString command); static void runCommandLine(QString command);
// Presence
static QColor getDefaultStyleColor(const QString &colorName);
static QUrl getAppIcon(const QString &iconName);
static QUrl getRegistrationStateIcon(LinphoneEnums::RegistrationState state);
private: private:
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -34,6 +34,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Control/Container/Call/CallGridLayout.qml view/Control/Container/Call/CallGridLayout.qml
view/Control/Container/Call/Mosaic.qml view/Control/Container/Call/Mosaic.qml
view/Control/Container/Contact/ContactLayout.qml view/Control/Container/Contact/ContactLayout.qml
view/Control/Container/Contact/PresenceNoteLayout.qml
view/Control/Container/Main/MainRightPanel.qml view/Control/Container/Main/MainRightPanel.qml
view/Control/Display/BusyIndicator.qml view/Control/Display/BusyIndicator.qml
@ -54,6 +55,9 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Control/Display/Chat/ChatMessagesListView.qml view/Control/Display/Chat/ChatMessagesListView.qml
view/Control/Display/Contact/Avatar.qml view/Control/Display/Contact/Avatar.qml
view/Control/Display/Contact/Contact.qml view/Control/Display/Contact/Contact.qml
view/Control/Display/Contact/Presence.qml
view/Control/Display/Contact/PresenceStatusItem.qml
view/Control/Display/Contact/PresenceSetCustomStatus.qml
view/Control/Display/Contact/ContactListItem.qml view/Control/Display/Contact/ContactListItem.qml
view/Control/Display/Contact/ContactListView.qml view/Control/Display/Contact/ContactListView.qml
view/Control/Display/Contact/AllContactListView.qml view/Control/Display/Contact/AllContactListView.qml

View file

@ -122,29 +122,12 @@ ColumnLayout {
} }
} }
Text { Text {
property var mode : contact ? contact.core.consolidatedPresence : -1
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true Layout.fillWidth: true
visible: mainItem.contact visible: mainItem.contact
text: mode === LinphoneEnums.ConsolidatedPresence.Online text: contact ? contact.core.presenceStatus : ""
//: "En ligne" color: contact ? contact.core.presenceColor : 'transparent'
? qsTr("contact_presence_status_online")
: mode === LinphoneEnums.ConsolidatedPresence.Busy
//: "Occupé"
? qsTr("contact_presence_status_busy")
: mode === LinphoneEnums.ConsolidatedPresence.DoNotDisturb
//: "Ne pas déranger"
? qsTr("contact_presence_status_do_not_disturb")
//: "Hors ligne"
: qsTr("contact_presence_status_offline")
color: mode === LinphoneEnums.ConsolidatedPresence.Online
? DefaultStyle.success_500main
: mode === LinphoneEnums.ConsolidatedPresence.Busy
? DefaultStyle.warning_600
: mode === LinphoneEnums.ConsolidatedPresence.DoNotDisturb
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
font { font {
pixelSize: Math.round(12 * DefaultStyle.dp) pixelSize: Math.round(12 * DefaultStyle.dp)
weight: Math.round(300 * DefaultStyle.dp) weight: Math.round(300 * DefaultStyle.dp)

View file

@ -30,40 +30,50 @@ ColumnLayout {
columnSpacing: Math.round(49 * DefaultStyle.dp) columnSpacing: Math.round(49 * DefaultStyle.dp)
rowSpacing: Math.round(27 * DefaultStyle.dp) rowSpacing: Math.round(27 * DefaultStyle.dp)
RowLayout { ColumnLayout {
Layout.preferredWidth: Math.round(341 * DefaultStyle.dp) spacing: Math.round(16 * DefaultStyle.dp)
Control.Control { Layout.preferredWidth: Math.round(341 * DefaultStyle.dp)
// Layout.preferredWidth: Math.round(734 * DefaultStyle.dp) RowLayout {
Layout.fillWidth: true Layout.preferredWidth: Math.round(341 * DefaultStyle.dp)
width: Math.round(734 * DefaultStyle.dp) Control.Control {
height: Math.round(100 * DefaultStyle.dp) // Layout.preferredWidth: Math.round(734 * DefaultStyle.dp)
rightPadding: Math.round(21 * DefaultStyle.dp) Layout.fillWidth: true
background: GradientRectangle { width: Math.round(734 * DefaultStyle.dp)
anchors.fill: parent height: Math.round(100 * DefaultStyle.dp)
anchors.leftMargin: avatar.width / 2 rightPadding: Math.round(21 * DefaultStyle.dp)
radius: Math.round(15 * DefaultStyle.dp) background: GradientRectangle {
borderGradient: Gradient { anchors.fill: parent
orientation: Gradient.Horizontal anchors.leftMargin: avatar.width / 2
GradientStop { position: 0.0; color: DefaultStyle.grey_100 } radius: Math.round(15 * DefaultStyle.dp)
GradientStop { position: 1.0; color: DefaultStyle.main2_200 } borderGradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: DefaultStyle.grey_100 }
GradientStop { position: 1.0; color: DefaultStyle.main2_200 }
}
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: DefaultStyle.grey_0 }
GradientStop { position: 1.0; color: DefaultStyle.grey_100 }
}
} }
gradient: Gradient { contentItem: RowLayout {
orientation: Gradient.Horizontal id: bannerLayout
GradientStop { position: 0.0; color: DefaultStyle.grey_0 } spacing: Math.round(32 * DefaultStyle.dp)
GradientStop { position: 1.0; color: DefaultStyle.grey_100 } Avatar {
} id: avatar
} contact: mainItem.contact
contentItem: RowLayout { Layout.preferredWidth: Math.round(100 * DefaultStyle.dp)
id: bannerLayout Layout.preferredHeight: Math.round(100 * DefaultStyle.dp)
spacing: Math.round(32 * DefaultStyle.dp) }
Avatar {
id: avatar
contact: mainItem.contact
Layout.preferredWidth: Math.round(100 * DefaultStyle.dp)
Layout.preferredHeight: Math.round(100 * DefaultStyle.dp)
} }
} }
} }
PresenceNoteLayout {
visible: contact.core.presenceNote.length > 0 && mainItem.useVerticalLayout
friendCore: contact.core
Layout.preferredWidth: 412 * DefaultStyle.dp
Layout.preferredHeight: 85 * DefaultStyle.dp
}
} }
Item { Item {
id: verticalLayoutSecondLine id: verticalLayoutSecondLine
@ -78,6 +88,18 @@ ColumnLayout {
style: ButtonStyle.main style: ButtonStyle.main
} }
} }
Rectangle {
Layout.fillWidth:true
Layout.preferredHeight: 79 * DefaultStyle.dp
color: 'transparent'
visible: contact.core.presenceNote.length > 0 && !mainItem.useVerticalLayout
PresenceNoteLayout {
anchors.centerIn: parent
friendCore: contact.core
width: 412 * DefaultStyle.dp
height: 85 * DefaultStyle.dp
}
}
StackLayout { StackLayout {
id: detailLayout id: detailLayout
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter

View file

@ -0,0 +1,52 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import QtQuick.Controls.Basic as Control
import Linphone
import UtilsCpp
import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
Rectangle {
id: mainItem
property var friendCore
color: DefaultStyle.grey_0
radius: 20 * DefaultStyle.dp
border.color: DefaultStyle.main2_200
border.width: 2 * DefaultStyle.dp
ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 16 * DefaultStyle.dp
anchors.rightMargin: 16 * DefaultStyle.dp
spacing: 8 * DefaultStyle.dp
RowLayout {
spacing: 6 * DefaultStyle.dp
EffectImage {
fillMode: Image.PreserveAspectFit
imageSource: AppIcons.presenceNote
colorizationColor: DefaultStyle.main2_600
Layout.preferredHeight: Math.round(17 * DefaultStyle.dp)
Layout.preferredWidth: Math.round(17 * DefaultStyle.dp)
}
Text {
font: Typography.p2
color: DefaultStyle.main2_600
text: qsTr("contact_presence_note_title")
}
}
Text {
font: Typography.p3
color: DefaultStyle.main2_500main
text: mainItem.friendCore.presenceNote
wrapMode: Text.Wrap
Layout.fillWidth: true
}
}
}

View file

@ -52,14 +52,8 @@ Loader{
: false : false
property bool securityBreach: securityLevel === LinphoneEnums.SecurityLevel.Unsafe property bool securityBreach: securityLevel === LinphoneEnums.SecurityLevel.Unsafe
property bool displayPresence: true
property bool displayPresence: account
? account.core?.registrationState != LinphoneEnums.RegistrationState.Progress && account.core?.registrationState != LinphoneEnums.RegistrationState.Refreshing || false
: contact
? contact.core?.consolidatedPresence != LinphoneEnums.ConsolidatedPresence.Offline || false
: false
asynchronous: true asynchronous: true
sourceComponent: Component{ sourceComponent: Component{
Item { Item {
@ -108,39 +102,22 @@ Loader{
} }
} }
Rectangle {
Image {
visible: mainItem.displayPresence visible: mainItem.displayPresence
width: stackView.width/4.5 width: stackView.width/4.5
height: width height: width
radius: width / 2 sourceSize.width: width
sourceSize.height: width
smooth: false
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: stackView.width / 15 anchors.rightMargin: stackView.width / 15
z: 1 z: 1
color: account source: account ? (account.core?.registrationState != LinphoneEnums.RegistrationState.Ok ? account.core?.registrationStateIcon : account.core?.presenceIcon)
? account.core?.registrationState == LinphoneEnums.RegistrationState.Ok : (contact ? contact.core?.presenceIcon : "")
? DefaultStyle.success_500main
: account.core?.registrationState == LinphoneEnums.RegistrationState.Cleared || account.core?.registrationState == LinphoneEnums.RegistrationState.None
? DefaultStyle.warning_600
: account.core?.registrationState == LinphoneEnums.RegistrationState.Progress || account.core?.registrationState == LinphoneEnums.RegistrationState.Refreshing
? DefaultStyle.main2_500main
: DefaultStyle.danger_500main
: contact
? contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.Online
? DefaultStyle.success_500main
: contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.Busy
? DefaultStyle.warning_600
: contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.DoNotDisturb
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
: "transparent"
border {
width: Math.round(2 * DefaultStyle.dp)
color: DefaultStyle.grey_0
}
} }
} }
Component{ Component{

View file

@ -8,6 +8,8 @@ import QtQuick.Controls.Basic as Control
import Linphone import Linphone
import UtilsCpp import UtilsCpp
import SettingsCpp import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
Control.Control{ Control.Control{
id: mainItem id: mainItem
@ -55,66 +57,87 @@ Control.Control{
} }
} }
} }
Control.Control { PopupButton {
id: registrationStatusItem id: presenceAndRegistrationItem
Layout.minimumWidth: Math.round(49 * DefaultStyle.dp) Layout.minimumWidth: Math.round(86 * DefaultStyle.dp)
Layout.maximumWidth: 150 Layout.maximumWidth: Math.round(150 * DefaultStyle.dp)
Layout.preferredHeight: Math.round(24 * DefaultStyle.dp) Layout.preferredHeight: Math.round(24 * DefaultStyle.dp)
topPadding: Math.round(4 * DefaultStyle.dp) Layout.preferredWidth: presenceOrRegistrationText.implicitWidth + Math.round(50 * DefaultStyle.dp)
bottomPadding: Math.round(4 * DefaultStyle.dp) contentItem:
leftPadding: Math.round(8 * DefaultStyle.dp) Rectangle{
rightPadding: Math.round(8 * DefaultStyle.dp) id: presenceBar
Layout.preferredWidth: text.implicitWidth + (2 * Math.round(8 * DefaultStyle.dp)) property bool isRegistered: mainItem.account?.core.registrationState == LinphoneEnums.RegistrationState.Ok
background: Rectangle{ color: DefaultStyle.main2_200
id: registrationStatus radius: Math.round(15 * DefaultStyle.dp)
anchors.fill: parent RowLayout {
color: DefaultStyle.main2_200 anchors.fill: parent
radius: Math.round(90 * DefaultStyle.dp) Image {
} sourceSize.width: 11 * DefaultStyle.dp
contentItem: Text { sourceSize.height: 11 * DefaultStyle.dp
id: text smooth: false
anchors.fill: parent Layout.preferredWidth: 11 * DefaultStyle.dp
anchors.leftMargin: registrationStatusItem.leftPadding Layout.preferredHeight: 11 * DefaultStyle.dp
anchors.rightMargin: registrationStatusItem.rightPadding source: presenceBar.isRegistered ? mainItem.account.core.presenceIcon : mainItem.account?.core.registrationStateIcon
verticalAlignment: Text.AlignVCenter Layout.leftMargin: 8 * DefaultStyle.dp
horizontalAlignment: Text.AlignHCenter }
visible: mainItem.account Text {
property int mode : !mainItem.account || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Ok id: presenceOrRegistrationText
? 0 verticalAlignment: Text.AlignVCenter
: mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Cleared || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.None horizontalAlignment: Text.AlignHCenter
? 1 visible: mainItem.account
: mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Progress || mainItem.account.core.registrationState == LinphoneEnums.RegistrationState.Refreshing // Test texts
? 2 // Timer{
: 3 // running: true
// Test texts // interval: 1000
// Timer{ // repeat: true
// running: true // onTriggered: text.mode = (++text.mode) % 4
// interval: 1000 // }
// repeat: true font.weight: Math.round(300 * DefaultStyle.dp)
// onTriggered: text.mode = (++text.mode) % 4 font.pixelSize: Math.round(12 * DefaultStyle.dp)
// } color: presenceBar.isRegistered ? mainItem.account.core.presenceColor : mainItem.account?.core.registrationColor
font.weight: Math.round(300 * DefaultStyle.dp) text: presenceBar.isRegistered ? mainItem.account.core.presenceStatus : mainItem.account?.core.humaneReadableRegistrationState
font.pixelSize: Math.round(12 * DefaultStyle.dp) }
color: mode == 0 EffectImage {
? DefaultStyle.success_500main fillMode: Image.PreserveAspectFit
: mode == 1 imageSource: AppIcons.downArrow
? DefaultStyle.warning_600 colorizationColor: DefaultStyle.main2_600
: mode == 2 Layout.preferredHeight: Math.round(14 * DefaultStyle.dp)
? DefaultStyle.main2_500main Layout.preferredWidth: Math.round(14 * DefaultStyle.dp)
: DefaultStyle.danger_500main Layout.rightMargin: 8 * DefaultStyle.dp
text: mode == 0 }
//: "Connecté" }
? qsTr("drawer_menu_account_connection_status_connected") }
: mode == 1 popup.contentItem: Rectangle {
//: "Désactivé" implicitWidth: 280 * DefaultStyle.dp
? qsTr("drawer_menu_account_connection_status_cleared") implicitHeight: 20 * DefaultStyle.dp + (setCustomStatus.visible ? 240 * DefaultStyle.dp : setPresence.implicitHeight)
: mode == 2 Presence {
//: "Connexion" id: setPresence
? qsTr("drawer_menu_account_connection_status_refreshing") anchors.fill: parent
//: "Erreur" anchors.margins: 20 * DefaultStyle.dp
: qsTr("drawer_menu_account_connection_status_failed") accountCore: mainItem.account.core
onSetCustomStatusClicked: {
setPresence.visible = false
setCustomStatus.visible = true
}
onIsSet: presenceAndRegistrationItem.popup.close()
}
PresenceSetCustomStatus {
id: setCustomStatus
visible: false
anchors.fill: parent
anchors.margins: 20 * DefaultStyle.dp
accountCore: mainItem.account.core
onVisibleChanged: {
if (!visible) {
setPresence.visible = true
setCustomStatus.visible = false
}
}
onIsSet: presenceAndRegistrationItem.popup.close()
}
} }
} }
Item{ Item{
Layout.preferredWidth: Math.round(26 * DefaultStyle.dp) Layout.preferredWidth: Math.round(26 * DefaultStyle.dp)
Layout.preferredHeight: Math.round(26 * DefaultStyle.dp) Layout.preferredHeight: Math.round(26 * DefaultStyle.dp)

View file

@ -0,0 +1,114 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Linphone
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
ColumnLayout {
id: mainItem
property var accountCore
signal setCustomStatusClicked
signal isSet
spacing: 8 * DefaultStyle.dp
PresenceStatusItem { presence: LinphoneEnums.Presence.Online; accountCore: mainItem.accountCore; onClick: mainItem.isSet()}
PresenceStatusItem { presence: LinphoneEnums.Presence.Away; accountCore: mainItem.accountCore; onClick: mainItem.isSet()}
PresenceStatusItem { presence: LinphoneEnums.Presence.Busy; accountCore: mainItem.accountCore; onClick: mainItem.isSet()}
PresenceStatusItem { presence: LinphoneEnums.Presence.DoNotDisturb; accountCore: mainItem.accountCore; onClick: mainItem.isSet()}
PresenceStatusItem { presence: LinphoneEnums.Presence.Offline; accountCore: mainItem.accountCore; onClick: mainItem.isSet()}
RowLayout {
spacing: 0
visible: accountCore.explicitPresence != LinphoneEnums.Presence.Undefined
Layout.alignment: Qt.AlignLeft
Layout.topMargin: Math.round(3 * DefaultStyle.dp)
Layout.bottomMargin: Math.round(3 * DefaultStyle.dp)
Label {
font: Typography.p1
text: qsTr("contact_presence_reset_status")
color: DefaultStyle.main2_600
}
Item {
Layout.fillWidth: true
}
Item {
width: Math.round(17 * DefaultStyle.dp)
height: Math.round(17 * DefaultStyle.dp)
MouseArea {
id: hoverArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
accountCore.resetToAutomaticPresence()
}
}
EffectImage {
fillMode: Image.PreserveAspectFit
imageSource: AppIcons.reloadArrow
colorizationColor: hoverArea.containsMouse ? DefaultStyle.main2_800 : DefaultStyle.main2_600
anchors.fill: parent
}
}
}
Rectangle {
height: 1
width: parent.width
color: DefaultStyle.main2_500main
Layout.topMargin: 8 * DefaultStyle.dp
}
ColumnLayout {
spacing: 19 * DefaultStyle.dp
RowLayout {
spacing: 10 * DefaultStyle.dp
Layout.topMargin: Math.round(3 * DefaultStyle.dp)
Layout.alignment: Qt.AlignLeft
Text {
font: Typography.p1
text: accountCore.presenceNote.length > 0 ? accountCore.presenceNote : qsTr("contact_presence_custom_status")
color: DefaultStyle.main2_600
wrapMode: Text.WordWrap
Layout.preferredWidth: (accountCore.presenceNote.length == 0 ? 175 : 230) * DefaultStyle.dp
}
Item {
Layout.fillWidth: true
}
SmallButton {
visible: accountCore.presenceNote.length == 0
style: ButtonStyle.secondary
text: qsTr("contact_presence_button_set_custom_status")
onClicked: {
mainItem.setCustomStatusClicked()
}
}
}
RowLayout {
visible: accountCore.presenceNote.length > 0
spacing: 10 * DefaultStyle.dp
Item {
Layout.fillWidth: true
}
SmallButton {
style: ButtonStyle.secondary
text: qsTr("contact_presence_button_edit_custom_status")
onClicked: {
mainItem.setCustomStatusClicked()
}
}
SmallButton {
style: ButtonStyle.secondary
visible: accountCore.presenceNote.length > 0
text: qsTr("contact_presence_button_delete_custom_status")
onClicked: {
mainItem.accountCore.presenceNote = ""
}
}
}
}
Item {
Layout.fillHeight: true
}
}

View file

@ -0,0 +1,78 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Linphone
import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
Column {
id: mainItem
spacing: 20 * DefaultStyle.dp
anchors.centerIn: parent
property var accountCore
signal isSet
Text {
text: qsTr("contact_presence_button_set_custom_status_title")
horizontalAlignment: Text.AlignHCenter
color: DefaultStyle.main2_600
font: Typography.p2
}
Rectangle {
width: parent.width
height: 150 * DefaultStyle.dp
color: "transparent"
border.color: DefaultStyle.main1_500_main
border.width: 1 * DefaultStyle.dp
radius: 8 * DefaultStyle.dp
ColumnLayout {
anchors.fill: parent
anchors.margins: 10 * DefaultStyle.dp
TextEdit {
id: statusMessage
wrapMode: TextEdit.Wrap
font: Typography.p1
color: DefaultStyle.main2_500main
Layout.fillHeight: true
Layout.fillWidth: true
property string previoustext: ""
text: mainItem.accountCore.presenceNote
onTextChanged: {
if (statusMessage.text.length > accountCore.maxPresenceNoteSize) {
statusMessage.text = previoustext
statusMessage.cursorPosition = statusMessage.text.length
} else {
previoustext = statusMessage.text
}
}
}
Item {
Layout.fillHeight: true
}
Text {
Layout.fillWidth: true
text: statusMessage.text.length + " / " + accountCore.maxPresenceNoteSize
font: Typography.p1
color: DefaultStyle.main2_400
horizontalAlignment: Text.AlignRight
}
}
}
Row {
spacing: 10 * DefaultStyle.dp
anchors.right: parent.right
SmallButton {
style: ButtonStyle.secondary
text: qsTr("contact_presence_button_save_custom_status")
enabled: statusMessage.text.length > 0
onClicked: {
mainItem.accountCore.presenceNote = statusMessage.text
mainItem.isSet()
}
}
}
}

View file

@ -0,0 +1,53 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Linphone
import UtilsCpp
Rectangle {
id: mainItem
property var accountCore
property var presence
signal click()
color: mouseArea.containsMouse ? DefaultStyle.main2_100 : "transparent"
width: 236 * DefaultStyle.dp
height: 22 * DefaultStyle.dp
radius: 5 * DefaultStyle.dp
RowLayout {
anchors.fill: parent
spacing: 10 * DefaultStyle.dp
Layout.alignment: Qt.AlignLeft
Image {
sourceSize.width: 11 * DefaultStyle.dp
sourceSize.height: 11 * DefaultStyle.dp
smooth: false
Layout.preferredWidth: 11 * DefaultStyle.dp
Layout.preferredHeight: 11 * DefaultStyle.dp
source: UtilsCpp.getPresenceIcon(mainItem.presence)
}
Text {
text: UtilsCpp.getPresenceStatus(mainItem.presence)
font: Typography.p1
horizontalAlignment: Text.AlignLeft
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
color: UtilsCpp.getPresenceColor(mainItem.presence)
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
mainItem.accountCore.presence = mainItem.presence
mainItem.click()
}
}
}

View file

@ -53,6 +53,9 @@ Item {
: call.core.remoteName : call.core.remoteName
: "" : ""
property var contactObj: UtilsCpp.findFriendByAddress(call.core.remoteAddress)
property var contact: contactObj && contactObj.value || null
property var identityAddress: account ? UtilsCpp.getDisplayName(account.core.identityAddress) : null property var identityAddress: account ? UtilsCpp.getDisplayName(account.core.identityAddress) : null
property bool videoEnabled: (previewEnabled && call && call.core.localVideoEnabled) property bool videoEnabled: (previewEnabled && call && call.core.localVideoEnabled)
|| (!previewEnabled && call && call.core.remoteVideoEnabled) || (!previewEnabled && call && call.core.remoteVideoEnabled)
@ -168,6 +171,7 @@ Item {
anchors.topMargin: Math.round(21 * DefaultStyle.dp) anchors.topMargin: Math.round(21 * DefaultStyle.dp)
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
Text { Text {
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter

View file

@ -52,7 +52,8 @@ Window{
RowLayout{ RowLayout{
anchors.fill: parent anchors.fill: parent
Text{ Text{
text: modelData.core.presenceTimestamp + " == " +modelData.core.consolidatedPresence + " / " text: modelData.core.presenceStatus
color: modelData.core.presenceColor
} }
Button { Button {
text: 'X' text: 'X'

View file

@ -454,27 +454,10 @@ FriendGui{
} }
Text { Text {
visible: contactDetail.contact visible: contactDetail.contact
property var mode: contactDetail.contact ? contactDetail.contact.core.consolidatedPresence : -1
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true Layout.fillWidth: true
text: mode === LinphoneEnums.ConsolidatedPresence.Online text: contactDetail.contact ? contactDetail.contact.core.presenceStatus : ""
//: "En ligne" color: contactDetail.contact ? contactDetail.contact.core.presenceColor : 'transparent'
? qsTr("contact_presence_status_online")
: mode === LinphoneEnums.ConsolidatedPresence.Busy
//: "Occupé"
? qsTr("contact_presence_status_busy")
: mode === LinphoneEnums.ConsolidatedPresence.DoNotDisturb
//: "Ne pas déranger"
? qsTr("contact_presence_status_do_not_disturb")
//: "Hors ligne"
: qsTr("contact_presence_status_offline")
color: mode === LinphoneEnums.ConsolidatedPresence.Online
? DefaultStyle.success_500main
: mode === LinphoneEnums.ConsolidatedPresence.Busy
? DefaultStyle.warning_600
: mode === LinphoneEnums.ConsolidatedPresence.DoNotDisturb
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
font.pixelSize: Math.round(14 * DefaultStyle.dp) font.pixelSize: Math.round(14 * DefaultStyle.dp)
} }
}, },

View file

@ -128,4 +128,13 @@ QtObject {
property string appWindow: "image://internal/app-window.svg" property string appWindow: "image://internal/app-window.svg"
property string bellMwi: "image://internal/bell-simple.svg" property string bellMwi: "image://internal/bell-simple.svg"
property string callForward: "image://internal/call-forward.svg" property string callForward: "image://internal/call-forward.svg"
property string regitrationDeactivated: "image://internal/regitration_deactivated.svg"
property string regitrationProgress: "image://internal/regitration_progress.svg"
property string regitrationError: "image://internal/regitration_error.svg"
property string presenceOnline: "image://internal/presence_online.svg"
property string presenceAway: "image://internal/presence_away.svg"
property string presenceBusy: "image://internal/presence_busy.svg"
property string presenceDoNotDisturb: "image://internal/presence_do_not_disturb.svg"
property string presenceOffline: "image://internal/presence_offline.svg"
property string presenceNote: "image://internal/presence-note.svg"
} }

View file

@ -33,6 +33,7 @@ QtObject {
property color warning_600: "#DBB820" property color warning_600: "#DBB820"
property color danger_500main: "#DD5F5F" property color danger_500main: "#DD5F5F"
property color warning_500_main: "#FFDC2E"
property color danger_700: "#9E3548" property color danger_700: "#9E3548"
property color danger_900: "#723333" property color danger_900: "#723333"
property color success_500main: "#4FAE80" property color success_500main: "#4FAE80"
@ -62,5 +63,4 @@ QtObject {
property color placeholders: '#CACACA' // No name in design property color placeholders: '#CACACA' // No name in design
property color warning_500_main: "#FFDC2E"
} }

View file

@ -51,7 +51,7 @@ QtObject {
pixelSize: Math.round(13 * DefaultStyle.dp), pixelSize: Math.round(13 * DefaultStyle.dp),
weight: Math.min(Math.round(700 * DefaultStyle.dp), 1000) weight: Math.min(Math.round(700 * DefaultStyle.dp), 1000)
}) })
// Text/P2 - Large Bold, reduced paragraph text // Text/P2 - Large Bold, reduced paragraph text
property font p2l: Qt.font( { property font p2l: Qt.font( {
family: DefaultStyle.defaultFont, family: DefaultStyle.defaultFont,