Account settings & parameters

This commit is contained in:
Christophe Deschamps 2024-07-25 08:34:11 +00:00
parent cddaa90dcb
commit 4143d15f34
39 changed files with 1800 additions and 157 deletions

View file

@ -36,6 +36,7 @@
#include <QTimer> #include <QTimer>
#include "core/account/AccountCore.hpp" #include "core/account/AccountCore.hpp"
#include "core/account/AccountDeviceGui.hpp"
#include "core/account/AccountProxy.hpp" #include "core/account/AccountProxy.hpp"
#include "core/call-history/CallHistoryProxy.hpp" #include "core/call-history/CallHistoryProxy.hpp"
#include "core/call/CallCore.hpp" #include "core/call/CallCore.hpp"
@ -334,6 +335,7 @@ void App::initCppInterfaces() {
qmlRegisterUncreatableType<PhoneNumber>(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable")); qmlRegisterUncreatableType<PhoneNumber>(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable"));
qmlRegisterType<AccountProxy>(Constants::MainQmlUri, 1, 0, "AccountProxy"); qmlRegisterType<AccountProxy>(Constants::MainQmlUri, 1, 0, "AccountProxy");
qmlRegisterType<AccountGui>(Constants::MainQmlUri, 1, 0, "AccountGui"); qmlRegisterType<AccountGui>(Constants::MainQmlUri, 1, 0, "AccountGui");
qmlRegisterType<AccountDeviceGui>(Constants::MainQmlUri, 1, 0, "AccountDeviceGui");
qmlRegisterUncreatableType<AccountCore>(Constants::MainQmlUri, 1, 0, "AccountCore", QLatin1String("Uncreatable")); qmlRegisterUncreatableType<AccountCore>(Constants::MainQmlUri, 1, 0, "AccountCore", QLatin1String("Uncreatable"));
qmlRegisterUncreatableType<CallCore>(Constants::MainQmlUri, 1, 0, "CallCore", QLatin1String("Uncreatable")); qmlRegisterUncreatableType<CallCore>(Constants::MainQmlUri, 1, 0, "CallCore", QLatin1String("Uncreatable"));
qmlRegisterType<CallProxy>(Constants::MainQmlUri, 1, 0, "CallProxy"); qmlRegisterType<CallProxy>(Constants::MainQmlUri, 1, 0, "CallProxy");

View file

@ -3,6 +3,8 @@ list(APPEND _LINPHONEAPP_SOURCES
core/account/AccountGui.cpp core/account/AccountGui.cpp
core/account/AccountList.cpp core/account/AccountList.cpp
core/account/AccountProxy.cpp core/account/AccountProxy.cpp
core/account/AccountDeviceCore.cpp
core/account/AccountDeviceGui.cpp
core/App.cpp core/App.cpp
core/call/CallCore.cpp core/call/CallCore.cpp
core/call/CallGui.cpp core/call/CallGui.cpp

View file

@ -22,6 +22,7 @@
#include "core/App.hpp" #include "core/App.hpp"
#include "tool/Utils.hpp" #include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp" #include "tool/thread/SafeConnection.hpp"
#include <QHostInfo>
DEFINE_ABSTRACT_OBJECT(AccountCore) DEFINE_ABSTRACT_OBJECT(AccountCore)
@ -47,10 +48,42 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
mIsDefaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount() == account; mIsDefaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount() == account;
// mUnreadNotifications = account->getUnreadChatMessageCount() + account->getMissedCallsCount(); // TODO // mUnreadNotifications = account->getUnreadChatMessageCount() + account->getMissedCallsCount(); // TODO
mUnreadNotifications = account->getMissedCallsCount(); mUnreadNotifications = account->getMissedCallsCount();
mDisplayName = Utils::coreStringToAppString(identityAddress->getDisplayName());
mRegisterEnabled = params->registerEnabled();
mMwiServerAddress =
params->getMwiServerAddress() ? Utils::coreStringToAppString(params->getMwiServerAddress()->asString()) : "";
mTransports << "TCP" << "UDP" << "TLS" << "DTLS";
mTransport = LinphoneEnums::toString(LinphoneEnums::fromLinphone(params->getTransport()));
mServerAddress =
params->getServerAddress() ? Utils::coreStringToAppString(params->getServerAddress()->asString()) : "";
mOutboundProxyEnabled = params->outboundProxyEnabled();
auto policy = params->getNatPolicy() ? params->getNatPolicy() : account->getCore()->createNatPolicy();
mStunServer = Utils::coreStringToAppString(policy->getStunServer());
mIceEnabled = policy->iceEnabled();
mAvpfEnabled = account->avpfEnabled();
mBundleModeEnabled = params->rtpBundleEnabled();
mExpire = params->getExpires();
mConferenceFactoryAddress = params->getConferenceFactoryAddress()
? Utils::coreStringToAppString(params->getConferenceFactoryAddress()->asString())
: "";
mAudioVideoConferenceFactoryAddress =
params->getAudioVideoConferenceFactoryAddress()
? Utils::coreStringToAppString(params->getAudioVideoConferenceFactoryAddress()->asString())
: "";
mLimeServerUrl = Utils::coreStringToAppString(params->getLimeServerUrl());
// Add listener // Add listener
mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); // OK mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); // OK
mAccountModel->setSelf(mAccountModel); mAccountModel->setSelf(mAccountModel);
mNotificationsAllowed = mAccountModel->getNotificationsAllowed();
mDialPlan = " ";
mDialPlans << mDialPlan;
for (auto dialPlan : linphone::Factory::get()->getDialPlans()) {
mDialPlans << mAccountModel->dialPlanAsString(dialPlan);
if (dialPlan->getCountryCallingCode() == account->getParams()->getInternationalPrefix()) {
mDialPlan = mAccountModel->dialPlanAsString(dialPlan);
}
}
} }
AccountCore::~AccountCore() { AccountCore::~AccountCore() {
@ -83,6 +116,59 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
this->setUnreadMessageNotifications(unreadMessagesCount); this->setUnreadMessageNotifications(unreadMessagesCount);
}); });
}); });
mAccountModelConnection->makeConnectToModel(&AccountModel::displayNameChanged, [this](QString displayName) {
mAccountModelConnection->invokeToCore([this, displayName]() { this->onDisplayNameChanged(displayName); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::dialPlanChanged, [this](int index) {
auto dialPlan = mDialPlans[index + 1];
mAccountModelConnection->invokeToCore([this, dialPlan]() { this->onDialPlanChanged(dialPlan); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::registerEnabledChanged, [this](bool enabled) {
mAccountModelConnection->invokeToCore([this, enabled]() { this->onRegisterEnabledChanged(enabled); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::notificationsAllowedChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onNotificationsAllowedChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::mwiServerAddressChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onMwiServerAddressChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::transportChanged, [this](linphone::TransportType value) {
mAccountModelConnection->invokeToCore(
[this, value]() { this->onTransportChanged(LinphoneEnums::toString(LinphoneEnums::fromLinphone(value))); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::serverAddressChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onServerAddressChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::outboundProxyEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onOutboundProxyEnabledChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::stunServerChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onStunServerChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::iceEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onIceEnabledChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::avpfEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onAvpfEnabledChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::bundleModeEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onBundleModeEnabledChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::expireChanged, [this](int value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onExpireChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::conferenceFactoryAddressChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onConferenceFactoryAddressChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::audioVideoConferenceFactoryAddressChanged,
[this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() {
this->onAudioVideoConferenceFactoryAddressChanged(value);
});
});
mAccountModelConnection->makeConnectToModel(&AccountModel::limeServerUrlChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onLimeServerUrlChanged(value); });
});
// From GUI // From GUI
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetPictureUri, [this](QString uri) { mAccountModelConnection->makeConnectToCore(&AccountCore::lSetPictureUri, [this](QString uri) {
@ -108,6 +194,62 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToCore(&AccountCore::unreadNotificationsChanged, [this]() { mAccountModelConnection->makeConnectToCore(&AccountCore::unreadNotificationsChanged, [this]() {
mAccountModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); }); mAccountModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); });
}); });
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetDisplayName, [this](QString displayName) {
mAccountModelConnection->invokeToModel([this, displayName]() { mAccountModel->setDisplayName(displayName); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetDialPlan, [this](QString dialPlan) {
auto dialPlanIndex = getDialPlanIndex(dialPlan);
mAccountModelConnection->invokeToModel(
[this, dialPlanIndex]() { mAccountModel->setDialPlan(dialPlanIndex - 1); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetRegisterEnabled, [this](bool enabled) {
mAccountModelConnection->invokeToModel([this, enabled]() { mAccountModel->setRegisterEnabled(enabled); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetNotificationsAllowed, [this](bool value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setNotificationsAllowed(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetMwiServerAddress, [this](QString value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setMwiServerAddress(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetTransport, [this](QString value) {
LinphoneEnums::TransportType transport;
LinphoneEnums::fromString(value, &transport);
mAccountModelConnection->invokeToModel(
[this, value, transport]() { mAccountModel->setTransport(LinphoneEnums::toLinphone(transport)); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetServerAddress, [this](QString value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setServerAddress(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetOutboundProxyEnabled, [this](bool value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setOutboundProxyEnabled(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetStunServer, [this](QString value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setStunServer(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetIceEnabled, [this](bool value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setIceEnabled(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetAvpfEnabled, [this](bool value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setAvpfEnabled(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetBundleModeEnabled, [this](bool value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setBundleModeEnabled(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetExpire, [this](int value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setExpire(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetConferenceFactoryAddress, [this](QString value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setConferenceFactoryAddress(value); });
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetAudioVideoConferenceFactoryAddress,
[this](QString value) {
mAccountModelConnection->invokeToModel([this, value]() {
mAccountModel->setAudioVideoConferenceFactoryAddress(value);
});
});
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetLimeServerUrl, [this](QString value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setLimeServerUrl(value); });
});
} }
QString AccountCore::getContactAddress() const { QString AccountCore::getContactAddress() const {
@ -176,10 +318,231 @@ void AccountCore::onDefaultAccountChanged(bool isDefault) {
} }
void AccountCore::onPictureUriChanged(QString uri) { void AccountCore::onPictureUriChanged(QString uri) {
mPictureUri = uri; if (uri != mPictureUri) {
emit pictureUriChanged(); mPictureUri = uri;
emit pictureUriChanged();
}
} }
void AccountCore::removeAccount() { void AccountCore::removeAccount() {
mAccountModelConnection->invokeToModel([this]() { mAccountModel->removeAccount(); }); mAccountModelConnection->invokeToModel([this]() { mAccountModel->removeAccount(); });
} }
QString AccountCore::getDisplayName() const {
return mDisplayName;
}
void AccountCore::onDisplayNameChanged(QString displayName) {
if (displayName != mDisplayName) {
mDisplayName = displayName;
emit displayNameChanged();
}
}
QStringList AccountCore::getDialPlans() {
return mDialPlans;
}
QString AccountCore::getDialPlan() const {
return mDialPlan;
}
void AccountCore::onDialPlanChanged(QString dialPlan) {
if (dialPlan != mDialPlan) {
mDialPlan = dialPlan;
emit dialPlanChanged();
}
}
int AccountCore::getDialPlanIndex(QString dialPlanString) {
return mDialPlans.indexOf(dialPlanString);
}
QString AccountCore::getHumanReadableRegistrationState() const {
switch (mRegistrationState) {
case LinphoneEnums::RegistrationState::Ok:
return tr("Connecté");
case LinphoneEnums::RegistrationState::Refreshing:
return tr("En cours de rafraîchissement…");
case LinphoneEnums::RegistrationState::Progress:
return tr("En cours de connexion…");
case LinphoneEnums::RegistrationState::Failed:
return tr("Erreur");
case LinphoneEnums::RegistrationState::None:
case LinphoneEnums::RegistrationState::Cleared:
return tr("Désactivé");
default:
return " ";
}
}
QString AccountCore::getHumanReadableRegistrationStateExplained() const {
switch (mRegistrationState) {
case LinphoneEnums::RegistrationState::Ok:
return tr("Vous êtes en ligne et joignable.");
case LinphoneEnums::RegistrationState::Failed:
return tr("Erreur de connexion, vérifiez vos paramètres.");
case LinphoneEnums::RegistrationState::None:
case LinphoneEnums::RegistrationState::Cleared:
return tr("Compte désactivé, vous ne recevrez ni appel ni message.");
default:
return " ";
}
}
bool AccountCore::getRegisterEnabled() const {
return mRegisterEnabled;
}
void AccountCore::onRegisterEnabledChanged(bool enabled) {
if (enabled != mRegisterEnabled) {
mRegisterEnabled = enabled;
emit registerEnabledChanged();
}
}
bool AccountCore::getNotificationsAllowed() {
return mNotificationsAllowed;
}
QString AccountCore::getMwiServerAddress() {
return mMwiServerAddress;
}
QStringList AccountCore::getTransports() {
return mTransports;
}
QString AccountCore::getTransport() {
return mTransport;
}
QString AccountCore::getServerAddress() {
return mServerAddress;
}
bool AccountCore::getOutboundProxyEnabled() {
return mOutboundProxyEnabled;
}
QString AccountCore::getStunServer() {
return mStunServer;
}
bool AccountCore::getIceEnabled() {
return mIceEnabled;
}
bool AccountCore::getAvpfEnabled() {
return mAvpfEnabled;
}
bool AccountCore::getBundleModeEnabled() {
return mBundleModeEnabled;
}
int AccountCore::getExpire() {
return mExpire;
}
QString AccountCore::getConferenceFactoryAddress() {
return mConferenceFactoryAddress;
}
QString AccountCore::getAudioVideoConferenceFactoryAddress() {
return mAudioVideoConferenceFactoryAddress;
}
QString AccountCore::getLimeServerUrl() {
return mLimeServerUrl;
}
void AccountCore::onNotificationsAllowedChanged(bool value) {
if (value != mNotificationsAllowed) {
mNotificationsAllowed = value;
emit notificationsAllowedChanged();
}
}
void AccountCore::onMwiServerAddressChanged(QString value) {
if (value != mMwiServerAddress) {
mMwiServerAddress = value;
emit mwiServerAddressChanged();
}
}
void AccountCore::onTransportChanged(QString value) {
if (value != mTransport) {
mTransport = value;
emit transportChanged();
}
}
void AccountCore::onServerAddressChanged(QString value) {
if (value != mServerAddress) {
mServerAddress = value;
emit serverAddressChanged();
}
}
void AccountCore::onOutboundProxyEnabledChanged(bool value) {
if (value != mOutboundProxyEnabled) {
mOutboundProxyEnabled = value;
emit outboundProxyEnabledChanged();
}
}
void AccountCore::onStunServerChanged(QString value) {
if (value != mStunServer) {
mStunServer = value;
emit stunServerChanged();
}
}
void AccountCore::onIceEnabledChanged(bool value) {
if (value != mIceEnabled) {
mIceEnabled = value;
emit iceEnabledChanged();
}
}
void AccountCore::onAvpfEnabledChanged(bool value) {
if (value != mAvpfEnabled) {
mAvpfEnabled = value;
emit avpfEnabledChanged();
}
}
void AccountCore::onBundleModeEnabledChanged(bool value) {
if (value != mBundleModeEnabled) {
mBundleModeEnabled = value;
emit bundleModeEnabledChanged();
}
}
void AccountCore::onExpireChanged(int value) {
if (value != mExpire) {
mExpire = value;
emit expireChanged();
}
}
void AccountCore::onConferenceFactoryAddressChanged(QString value) {
if (value != mConferenceFactoryAddress) {
mConferenceFactoryAddress = value;
emit conferenceFactoryAddressChanged();
}
}
void AccountCore::onAudioVideoConferenceFactoryAddressChanged(QString value) {
if (value != mAudioVideoConferenceFactoryAddress) {
mAudioVideoConferenceFactoryAddress = value;
emit audioVideoConferenceFactoryAddressChanged();
}
}
void AccountCore::onLimeServerUrlChanged(QString value) {
if (value != mLimeServerUrl) {
mLimeServerUrl = value;
emit limeServerUrlChanged();
}
}

View file

@ -41,6 +41,36 @@ class AccountCore : public QObject, public AbstractObject {
Q_PROPERTY(int unreadCallNotifications READ getUnreadCallNotifications NOTIFY unreadCallNotificationsChanged) Q_PROPERTY(int unreadCallNotifications READ getUnreadCallNotifications NOTIFY unreadCallNotificationsChanged)
Q_PROPERTY( Q_PROPERTY(
int unreadMessageNotifications READ getUnreadMessageNotifications NOTIFY unreadMessageNotificationsChanged) int unreadMessageNotifications READ getUnreadMessageNotifications NOTIFY unreadMessageNotificationsChanged)
Q_PROPERTY(QString displayName READ getDisplayName WRITE lSetDisplayName NOTIFY displayNameChanged)
Q_PROPERTY(QStringList dialPlans READ getDialPlans CONSTANT)
Q_PROPERTY(QString dialPlan READ getDialPlan WRITE lSetDialPlan NOTIFY dialPlanChanged)
Q_PROPERTY(
QString humaneReadableRegistrationState READ getHumanReadableRegistrationState NOTIFY registrationStateChanged)
Q_PROPERTY(QString humaneReadableRegistrationStateExplained READ getHumanReadableRegistrationStateExplained NOTIFY
registrationStateChanged)
Q_PROPERTY(bool registerEnabled READ getRegisterEnabled WRITE lSetRegisterEnabled NOTIFY registerEnabledChanged)
Q_PROPERTY(QVariantList devices MEMBER mDevices NOTIFY devicesChanged)
Q_PROPERTY(bool notificationsAllowed READ getNotificationsAllowed WRITE lSetNotificationsAllowed NOTIFY
notificationsAllowedChanged)
Q_PROPERTY(
QString mwiServerAddress READ getMwiServerAddress WRITE lSetMwiServerAddress NOTIFY mwiServerAddressChanged)
Q_PROPERTY(QStringList transports READ getTransports CONSTANT)
Q_PROPERTY(QString transport READ getTransport WRITE lSetTransport NOTIFY transportChanged)
Q_PROPERTY(QString serverAddress READ getServerAddress WRITE lSetServerAddress NOTIFY serverAddressChanged)
Q_PROPERTY(bool outboundProxyEnabled READ getOutboundProxyEnabled WRITE lSetOutboundProxyEnabled NOTIFY
outboundProxyEnabledChanged)
Q_PROPERTY(QString stunServer READ getStunServer WRITE lSetStunServer NOTIFY stunServerChanged)
Q_PROPERTY(bool iceEnabled READ getIceEnabled WRITE lSetIceEnabled NOTIFY iceEnabledChanged)
Q_PROPERTY(bool avpfEnabled READ getAvpfEnabled WRITE lSetAvpfEnabled NOTIFY avpfEnabledChanged)
Q_PROPERTY(
bool bundleModeEnabled READ getBundleModeEnabled WRITE lSetBundleModeEnabled NOTIFY bundleModeEnabledChanged)
Q_PROPERTY(int expire READ getExpire WRITE lSetExpire NOTIFY expireChanged)
Q_PROPERTY(QString conferenceFactoryAddress READ getConferenceFactoryAddress WRITE lSetConferenceFactoryAddress
NOTIFY conferenceFactoryAddressChanged)
Q_PROPERTY(QString audioVideoConferenceFactoryAddress READ getAudioVideoConferenceFactoryAddress WRITE
lSetAudioVideoConferenceFactoryAddress NOTIFY audioVideoConferenceFactoryAddressChanged)
Q_PROPERTY(QString limeServerUrl READ getLimeServerUrl WRITE lSetLimeServerUrl NOTIFY limeServerUrlChanged)
public: public:
static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account); static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account);
@ -68,6 +98,45 @@ public:
void onDefaultAccountChanged(bool isDefault); void onDefaultAccountChanged(bool isDefault);
Q_INVOKABLE void removeAccount(); Q_INVOKABLE void removeAccount();
QString getDisplayName() const;
void onDisplayNameChanged(QString displayName);
QStringList getDialPlans();
int getDialPlanIndex(QString dialPlanString);
QString getDialPlan() const;
void onDialPlanChanged(QString internationalPrefix);
QString getHumanReadableRegistrationState() const;
QString getHumanReadableRegistrationStateExplained() const;
bool getRegisterEnabled() const;
void onRegisterEnabledChanged(bool enabled);
bool getNotificationsAllowed();
QString getMwiServerAddress();
QString getTransport();
QStringList getTransports();
QString getServerAddress();
bool getOutboundProxyEnabled();
QString getStunServer();
bool getIceEnabled();
bool getAvpfEnabled();
bool getBundleModeEnabled();
int getExpire();
QString getConferenceFactoryAddress();
QString getAudioVideoConferenceFactoryAddress();
QString getLimeServerUrl();
void onNotificationsAllowedChanged(bool value);
void onMwiServerAddressChanged(QString value);
void onTransportChanged(QString value);
void onServerAddressChanged(QString value);
void onOutboundProxyEnabledChanged(bool value);
void onStunServerChanged(QString value);
void onIceEnabledChanged(bool value);
void onAvpfEnabledChanged(bool value);
void onBundleModeEnabledChanged(bool value);
void onExpireChanged(int value);
void onConferenceFactoryAddressChanged(QString value);
void onAudioVideoConferenceFactoryAddressChanged(QString value);
void onLimeServerUrlChanged(QString value);
signals: signals:
void pictureUriChanged(); void pictureUriChanged();
@ -76,22 +145,76 @@ signals:
void unreadNotificationsChanged(int unread); void unreadNotificationsChanged(int unread);
void unreadCallNotificationsChanged(int unread); void unreadCallNotificationsChanged(int unread);
void unreadMessageNotificationsChanged(int unread); void unreadMessageNotificationsChanged(int unread);
void displayNameChanged();
void dialPlanChanged();
void registerEnabledChanged();
void allAddressesChanged();
void devicesChanged();
void notificationsAllowedChanged();
void mwiServerAddressChanged();
void transportChanged();
void serverAddressChanged();
void outboundProxyEnabledChanged();
void stunServerChanged();
void iceEnabledChanged();
void avpfEnabledChanged();
void bundleModeEnabledChanged();
void expireChanged();
void conferenceFactoryAddressChanged();
void audioVideoConferenceFactoryAddressChanged();
void limeServerUrlChanged();
// Account requests // Account requests
void lSetPictureUri(QString pictureUri); void lSetPictureUri(QString pictureUri);
void lSetDefaultAccount(); void lSetDefaultAccount();
void lResetMissedCalls(); void lResetMissedCalls();
void lRefreshNotifications(); void lRefreshNotifications();
void lSetDisplayName(QString displayName);
void lSetDialPlan(QString internationalPrefix);
void lSetRegisterEnabled(bool enabled);
void lSetNotificationsAllowed(bool value);
void lSetMwiServerAddress(QString value);
void lSetTransport(QString value);
void lSetServerAddress(QString value);
void lSetOutboundProxyEnabled(bool value);
void lSetStunServer(QString value);
void lSetIceEnabled(bool value);
void lSetAvpfEnabled(bool value);
void lSetBundleModeEnabled(bool value);
void lSetExpire(int value);
void lSetConferenceFactoryAddress(QString value);
void lSetAudioVideoConferenceFactoryAddress(QString value);
void lSetLimeServerUrl(QString value);
private: private:
QString mContactAddress; QString mContactAddress;
QString mIdentityAddress; QString mIdentityAddress;
QString mPictureUri; QString mPictureUri;
QString mDisplayName;
QStringList mDialPlans;
QString mDialPlan;
bool mRegisterEnabled;
bool mIsDefaultAccount = false; bool mIsDefaultAccount = false;
LinphoneEnums::RegistrationState mRegistrationState; LinphoneEnums::RegistrationState mRegistrationState;
int mUnreadNotifications = 0; int mUnreadNotifications = 0;
int mUnreadCallNotifications = 0; int mUnreadCallNotifications = 0;
int mUnreadMessageNotifications = 0; int mUnreadMessageNotifications = 0;
QVariantList mDevices;
bool mNotificationsAllowed;
QString mMwiServerAddress;
QString mTransport;
QStringList mTransports;
QString mServerAddress;
bool mOutboundProxyEnabled;
QString mStunServer;
bool mIceEnabled;
bool mAvpfEnabled;
bool mBundleModeEnabled;
int mExpire;
QString mConferenceFactoryAddress;
QString mAudioVideoConferenceFactoryAddress;
QString mLimeServerUrl;
std::shared_ptr<AccountModel> mAccountModel; std::shared_ptr<AccountModel> mAccountModel;
QSharedPointer<SafeConnection<AccountCore, AccountModel>> mAccountModelConnection; QSharedPointer<SafeConnection<AccountCore, AccountModel>> mAccountModelConnection;
QSharedPointer<SafeConnection<AccountCore, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<AccountCore, CoreModel>> mCoreModelConnection;

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AccountDeviceCore.hpp"
#include "core/App.hpp"
#include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp"
DEFINE_ABSTRACT_OBJECT(AccountDeviceCore)
AccountDeviceCore::AccountDeviceCore(QString name, QString userAgent, QDateTime last) : QObject(nullptr) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
mustBeInLinphoneThread(getClassName());
mDeviceName = name;
mUserAgent = userAgent;
mLastUpdateTimestamp = last;
}
QSharedPointer<AccountDeviceCore> AccountDeviceCore::createDummy(QString name, QString userAgent, QDateTime last) {
auto core = QSharedPointer<AccountDeviceCore>(new AccountDeviceCore(name,userAgent,last));
core->moveToThread(App::getInstance()->thread());
return core;
}
QSharedPointer<AccountDeviceCore> AccountDeviceCore::create(const std::shared_ptr<linphone::AccountDevice> &device) {
auto core = QSharedPointer<AccountDeviceCore>(new AccountDeviceCore(device));
core->moveToThread(App::getInstance()->thread());
return core;
}
AccountDeviceCore::AccountDeviceCore(const std::shared_ptr<linphone::AccountDevice> &device) : QObject(nullptr) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
mustBeInLinphoneThread(getClassName());
mDeviceName = Utils::coreStringToAppString(device->getName());
mUserAgent = Utils::coreStringToAppString(device->getUserAgent());
mLastUpdateTimestamp = QDateTime::fromSecsSinceEpoch(device->getLastUpdateTimestamp());
}
AccountDeviceCore::~AccountDeviceCore() {
mustBeInMainThread("~" + getClassName());
}
void AccountDeviceCore::removeDevice() {
// TODO (core thread)
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACCOUNT_DEVICE_CORE_H_
#define ACCOUNT_DEVICE_CORE_H_
#include <QObject>
#include <QSharedPointer>
#include <QDateTime>
#include "tool/AbstractObject.hpp"
#include <linphone++/linphone.hh>
class AccountDeviceCore : public QObject, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString deviceName MEMBER mDeviceName CONSTANT)
Q_PROPERTY(QString userAgent MEMBER mUserAgent CONSTANT)
Q_PROPERTY(QDateTime lastUpdateTimestamp MEMBER mLastUpdateTimestamp CONSTANT)
public:
static QSharedPointer<AccountDeviceCore> create(const std::shared_ptr<linphone::AccountDevice> &device);
AccountDeviceCore(const std::shared_ptr<linphone::AccountDevice> &device);
AccountDeviceCore(QString name, QString userAgent, QDateTime last);
static QSharedPointer<AccountDeviceCore> createDummy(QString name, QString userAgent, QDateTime last);
~AccountDeviceCore();
Q_INVOKABLE void removeDevice();
private:
QString mDeviceName;
QString mUserAgent;
QDateTime mLastUpdateTimestamp;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AccountDeviceGui.hpp"
#include "core/App.hpp"
DEFINE_ABSTRACT_OBJECT(AccountDeviceGui)
AccountDeviceGui::AccountDeviceGui(QSharedPointer<AccountDeviceCore> core) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
mCore = core;
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
}
AccountDeviceGui::~AccountDeviceGui() {
mustBeInMainThread("~" + getClassName());
}
AccountDeviceCore *AccountDeviceGui::getCore() const {
return mCore.get();
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACCOUNT_DEVICE_GUI_H_
#define ACCOUNT_DEVICE_GUI_H_
#include "AccountDeviceCore.hpp"
#include <QObject>
#include <QSharedPointer>
class AccountDeviceGui : public QObject, public AbstractObject {
Q_OBJECT
Q_PROPERTY(AccountDeviceCore *core READ getCore CONSTANT)
public:
AccountDeviceGui(QSharedPointer<AccountDeviceCore> core);
~AccountDeviceGui();
AccountDeviceCore *getCore() const;
QSharedPointer<AccountDeviceCore> mCore;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -36,6 +36,7 @@
#include "tool/LinphoneEnums.hpp" #include "tool/LinphoneEnums.hpp"
#include "tool/providers/AvatarProvider.hpp" #include "tool/providers/AvatarProvider.hpp"
#include "tool/providers/ImageProvider.hpp" #include "tool/providers/ImageProvider.hpp"
#include "model/tool/ToolModel.hpp"
DEFINE_ABSTRACT_OBJECT(Notifier) DEFINE_ABSTRACT_OBJECT(Notifier)
@ -277,6 +278,16 @@ void Notifier::deleteNotification(QVariant notification) {
void Notifier::notifyReceivedCall(const shared_ptr<linphone::Call> &call) { void Notifier::notifyReceivedCall(const shared_ptr<linphone::Call> &call) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto account = ToolModel::findAccount(call->getToAddress());
if (account) {
auto accountModel = Utils::makeQObject_ptr<AccountModel>(account);
accountModel->setSelf(accountModel);
if (!accountModel->getNotificationsAllowed()) {
qInfo() << "Notifications have been disabled for this account - not creating a notification for incoming call";
return;
}
}
auto model = CallCore::create(call); auto model = CallCore::create(call);
auto gui = new CallGui(model); auto gui = new CallGui(model);
gui->moveToThread(App::getInstance()->thread()); gui->moveToThread(App::getInstance()->thread());

View file

@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-96-88v64a8,8,0,0,1-16,0V132.94l-4.42,2.22a8,8,0,0,1-7.16-14.32l16-8A8,8,0,0,1,112,120Zm59.16,30.45L152,176h16a8,8,0,0,1,0,16H136a8,8,0,0,1-6.4-12.8l28.78-38.37A8,8,0,1,0,145.07,132a8,8,0,1,1-13.85-8A24,24,0,0,1,176,136,23.76,23.76,0,0,1,171.16,150.45Z"></path></svg> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.25 3.125H14.375V2.5C14.375 2.33424 14.3092 2.17527 14.1919 2.05806C14.0747 1.94085 13.9158 1.875 13.75 1.875C13.5842 1.875 13.4253 1.94085 13.3081 2.05806C13.1908 2.17527 13.125 2.33424 13.125 2.5V3.125H6.875V2.5C6.875 2.33424 6.80915 2.17527 6.69194 2.05806C6.57473 1.94085 6.41576 1.875 6.25 1.875C6.08424 1.875 5.92527 1.94085 5.80806 2.05806C5.69085 2.17527 5.625 2.33424 5.625 2.5V3.125H3.75C3.41848 3.125 3.10054 3.2567 2.86612 3.49112C2.6317 3.72554 2.5 4.04348 2.5 4.375V16.875C2.5 17.2065 2.6317 17.5245 2.86612 17.7589C3.10054 17.9933 3.41848 18.125 3.75 18.125H16.25C16.5815 18.125 16.8995 17.9933 17.1339 17.7589C17.3683 17.5245 17.5 17.2065 17.5 16.875V4.375C17.5 4.04348 17.3683 3.72554 17.1339 3.49112C16.8995 3.2567 16.5815 3.125 16.25 3.125ZM5.625 4.375V5C5.625 5.16576 5.69085 5.32473 5.80806 5.44194C5.92527 5.55915 6.08424 5.625 6.25 5.625C6.41576 5.625 6.57473 5.55915 6.69194 5.44194C6.80915 5.32473 6.875 5.16576 6.875 5V4.375H13.125V5C13.125 5.16576 13.1908 5.32473 13.3081 5.44194C13.4253 5.55915 13.5842 5.625 13.75 5.625C13.9158 5.625 14.0747 5.55915 14.1919 5.44194C14.3092 5.32473 14.375 5.16576 14.375 5V4.375H16.25V6.875H3.75V4.375H5.625ZM16.25 16.875H3.75V8.125H16.25V16.875Z" fill="#4E6074"/>
</svg>

Before

Width:  |  Height:  |  Size: 604 B

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.6923 2.75H4.30769C3.69565 2.75 3.10868 2.99313 2.67591 3.42591C2.24313 3.85868 2 4.44565 2 5.05769V15.8269C2 16.439 2.24313 17.0259 2.67591 17.4587C3.10868 17.8915 3.69565 18.1346 4.30769 18.1346H11.2308V19.6731H8.92308C8.71906 19.6731 8.52341 19.7541 8.37915 19.8984C8.23489 20.0426 8.15385 20.2383 8.15385 20.4423C8.15385 20.6463 8.23489 20.842 8.37915 20.9862C8.52341 21.1305 8.71906 21.2115 8.92308 21.2115H15.0769C15.2809 21.2115 15.4766 21.1305 15.6209 20.9862C15.7651 20.842 15.8462 20.6463 15.8462 20.4423C15.8462 20.2383 15.7651 20.0426 15.6209 19.8984C15.4766 19.7541 15.2809 19.6731 15.0769 19.6731H12.7692V18.1346H19.6923C20.3043 18.1346 20.8913 17.8915 21.3241 17.4587C21.7569 17.0259 22 16.439 22 15.8269V5.05769C22 4.44565 21.7569 3.85868 21.3241 3.42591C20.8913 2.99313 20.3043 2.75 19.6923 2.75ZM4.30769 4.28846H19.6923C19.8963 4.28846 20.092 4.36951 20.2362 4.51376C20.3805 4.65802 20.4615 4.85368 20.4615 5.05769V12.75H3.53846V5.05769C3.53846 4.85368 3.61951 4.65802 3.76376 4.51376C3.90802 4.36951 4.10368 4.28846 4.30769 4.28846ZM19.6923 16.5962H4.30769C4.10368 16.5962 3.90802 16.5151 3.76376 16.3709C3.61951 16.2266 3.53846 16.0309 3.53846 15.8269V14.2885H20.4615V15.8269C20.4615 16.0309 20.3805 16.2266 20.2362 16.3709C20.092 16.5151 19.8963 16.5962 19.6923 16.5962Z" fill="#4E6074"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.25 1.5H7.25C6.65326 1.5 6.08097 1.73705 5.65901 2.15901C5.23705 2.58097 5 3.15326 5 3.75V20.25C5 20.8467 5.23705 21.419 5.65901 21.841C6.08097 22.2629 6.65326 22.5 7.25 22.5H16.25C16.8467 22.5 17.419 22.2629 17.841 21.841C18.2629 21.419 18.5 20.8467 18.5 20.25V3.75C18.5 3.15326 18.2629 2.58097 17.841 2.15901C17.419 1.73705 16.8467 1.5 16.25 1.5ZM17 20.25C17 20.4489 16.921 20.6397 16.7803 20.7803C16.6397 20.921 16.4489 21 16.25 21H7.25C7.05109 21 6.86032 20.921 6.71967 20.7803C6.57902 20.6397 6.5 20.4489 6.5 20.25V3.75C6.5 3.55109 6.57902 3.36032 6.71967 3.21967C6.86032 3.07902 7.05109 3 7.25 3H16.25C16.4489 3 16.6397 3.07902 16.7803 3.21967C16.921 3.36032 17 3.55109 17 3.75V20.25ZM12.875 5.625C12.875 5.8475 12.809 6.06501 12.6854 6.25002C12.5618 6.43502 12.3861 6.57922 12.1805 6.66436C11.975 6.74951 11.7488 6.77179 11.5305 6.72838C11.3123 6.68498 11.1118 6.57783 10.9545 6.4205C10.7972 6.26316 10.69 6.06271 10.6466 5.84448C10.6032 5.62625 10.6255 5.40005 10.7106 5.19448C10.7958 4.98891 10.94 4.81321 11.125 4.6896C11.31 4.56598 11.5275 4.5 11.75 4.5C12.0484 4.5 12.3345 4.61853 12.5455 4.8295C12.7565 5.04048 12.875 5.32663 12.875 5.625Z" fill="#4E6074"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -3,7 +3,7 @@ list(APPEND _LINPHONEAPP_SOURCES
model/account/AccountManager.cpp model/account/AccountManager.cpp
model/account/AccountManagerServicesModel.cpp model/account/AccountManagerServicesModel.cpp
model/account/AccountManagerServicesRequestModel.cpp model/account/AccountManagerServicesRequestModel.cpp
model/auth/OIDCModel.cpp model/auth/OIDCModel.cpp
model/call/CallModel.cpp model/call/CallModel.cpp

View file

@ -57,8 +57,7 @@ void AccountModel::onRegistrationStateChanged(const std::shared_ptr<linphone::Ac
void AccountModel::setPictureUri(QString uri) { void AccountModel::setPictureUri(QString uri) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto account = std::dynamic_pointer_cast<linphone::Account>(mMonitor); auto params = mMonitor->getParams()->clone();
auto params = account->getParams()->clone();
auto oldPictureUri = Utils::coreStringToAppString(params->getPictureUri()); auto oldPictureUri = Utils::coreStringToAppString(params->getPictureUri());
if (!oldPictureUri.isEmpty()) { if (!oldPictureUri.isEmpty()) {
QString appPrefix = QStringLiteral("image://%1/").arg(AvatarProvider::ProviderId); QString appPrefix = QStringLiteral("image://%1/").arg(AvatarProvider::ProviderId);
@ -69,11 +68,11 @@ void AccountModel::setPictureUri(QString uri) {
if (!oldPicture.remove()) qWarning() << log().arg("Cannot delete old avatar file at " + oldPictureUri); if (!oldPicture.remove()) qWarning() << log().arg("Cannot delete old avatar file at " + oldPictureUri);
} }
params->setPictureUri(Utils::appStringToCoreString(uri)); params->setPictureUri(Utils::appStringToCoreString(uri));
account->setParams(params); mMonitor->setParams(params);
// Hack because Account doesn't provide callbacks on updated data // Hack because Account doesn't provide callbacks on updated data
// emit pictureUriChanged(uri); // emit pictureUriChanged(uri);
emit CoreModel::getInstance()->defaultAccountChanged(CoreModel::getInstance()->getCore(), emit CoreModel::getInstance() -> defaultAccountChanged(CoreModel::getInstance()->getCore(),
CoreModel::getInstance()->getCore()->getDefaultAccount()); CoreModel::getInstance()->getCore()->getDefaultAccount());
} }
void AccountModel::onDefaultAccountChanged() { void AccountModel::onDefaultAccountChanged() {
@ -107,4 +106,179 @@ int AccountModel::getMissedCallsCount() const {
int AccountModel::getUnreadMessagesCount() const { int AccountModel::getUnreadMessagesCount() const {
return mMonitor->getUnreadChatMessageCount(); return mMonitor->getUnreadChatMessageCount();
} }
void AccountModel::setDisplayName(QString displayName) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
auto address = params->getIdentityAddress()->clone();
address->setDisplayName(Utils::appStringToCoreString(displayName));
params->setIdentityAddress(address);
mMonitor->setParams(params);
emit displayNameChanged(displayName);
}
void AccountModel::setDialPlan(int index) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
std::string callingCode = "";
std::string countryCode = "";
if (index != -1) {
auto plans = linphone::Factory::get()->getDialPlans();
std::vector<std::shared_ptr<linphone::DialPlan>> vectorPlans(plans.begin(), plans.end());
auto plan = vectorPlans[index];
callingCode = plan->getCountryCallingCode();
countryCode = plan->getIsoCountryCode();
}
auto params = mMonitor->getParams()->clone();
params->setInternationalPrefix(callingCode);
params->setInternationalPrefixIsoCountryCode(countryCode);
mMonitor->setParams(params);
emit dialPlanChanged(index);
}
void AccountModel::setRegisterEnabled(bool enabled) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
params->enableRegister(enabled);
mMonitor->setParams(params);
emit registerEnabledChanged(enabled);
}
std::string AccountModel::getConfigAccountUiSection() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return "ui_" + mMonitor->getParams()->getIdentityAddress()->asStringUriOnly();
}
bool AccountModel::getNotificationsAllowed() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return mMonitor->getCore()->getConfig()->getBool(getConfigAccountUiSection(), "notifications_allowed", true);
}
void AccountModel::setNotificationsAllowed(bool value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->getCore()->getConfig()->setBool(getConfigAccountUiSection(), "notifications_allowed", value);
emit notificationsAllowedChanged(value);
}
void AccountModel::setMwiServerAddress(QString value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
auto address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(value));
if (address) {
params->setMwiServerAddress(address);
mMonitor->setParams(params);
emit mwiServerAddressChanged(value);
} else qWarning() << "Unable to set MWI address, failed creating address from" << value;
}
void AccountModel::setTransport(linphone::TransportType value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
params->setTransport(value);
mMonitor->setParams(params);
emit transportChanged(value);
}
void AccountModel::setServerAddress(QString value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
auto address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(value));
if (address) {
params->setServerAddress(address);
mMonitor->setParams(params);
emit serverAddressChanged(value);
} else qWarning() << "Unable to set ServerAddress, failed creating address from" << value;
}
void AccountModel::setOutboundProxyEnabled(bool value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
params->enableOutboundProxy(value);
mMonitor->setParams(params);
emit outboundProxyEnabledChanged(value);
}
void AccountModel::setStunServer(QString value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
auto policy = params->getNatPolicy();
if (!policy) policy = mMonitor->getCore()->createNatPolicy();
policy->setStunServer(Utils::appStringToCoreString(value));
params->setNatPolicy(policy);
mMonitor->setParams(params);
emit stunServerChanged(value);
qWarning() << "cdes stun server set to" << value;
}
void AccountModel::setIceEnabled(bool value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
auto policy = params->getNatPolicy();
if (!policy) policy = mMonitor->getCore()->createNatPolicy();
policy->enableIce(value);
params->setNatPolicy(policy);
mMonitor->setParams(params);
emit iceEnabledChanged(value);
}
void AccountModel::setAvpfEnabled(bool value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
params->setAvpfMode(value ? linphone::AVPFMode::Enabled : linphone::AVPFMode::Disabled);
mMonitor->setParams(params);
emit avpfEnabledChanged(value);
}
void AccountModel::setBundleModeEnabled(bool value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
params->enableRtpBundle(value);
mMonitor->setParams(params);
emit bundleModeEnabledChanged(value);
}
void AccountModel::setExpire(int value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
params->setExpires(value);
mMonitor->setParams(params);
emit expireChanged(value);
}
void AccountModel::setConferenceFactoryAddress(QString value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
auto address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(value));
if (address) {
params->setConferenceFactoryAddress(address);
mMonitor->setParams(params);
emit conferenceFactoryAddressChanged(value);
} else qWarning() << "Unable to set ConferenceFactoryAddress address, failed creating address from" << value;
}
void AccountModel::setAudioVideoConferenceFactoryAddress(QString value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
auto address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(value));
if (address) {
params->setAudioVideoConferenceFactoryAddress(address);
mMonitor->setParams(params);
emit audioVideoConferenceFactoryAddressChanged(value);
} else
qWarning() << "Unable to set AudioVideoConferenceFactoryAddress address, failed creating address from" << value;
}
void AccountModel::setLimeServerUrl(QString value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
auto address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(value));
params->setLimeServerUrl(Utils::appStringToCoreString(value));
mMonitor->setParams(params);
emit limeServerUrlChanged(value);
}
QString AccountModel::dialPlanAsString(const std::shared_ptr<linphone::DialPlan> &dialPlan) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return Utils::coreStringToAppString(dialPlan->getFlag() + " " + dialPlan->getCountry() + " | +" +
dialPlan->getCountryCallingCode());
}

View file

@ -40,6 +40,8 @@ public:
const std::string &message) override; const std::string &message) override;
void onDefaultAccountChanged(); void onDefaultAccountChanged();
std::string getConfigAccountUiSection();
void setPictureUri(QString uri); void setPictureUri(QString uri);
void setDefault(); void setDefault();
void removeAccount(); void removeAccount();
@ -47,6 +49,24 @@ public:
void refreshUnreadNotifications(); void refreshUnreadNotifications();
int getMissedCallsCount() const; int getMissedCallsCount() const;
int getUnreadMessagesCount() const; int getUnreadMessagesCount() const;
void setDisplayName(QString displayName);
void setDialPlan(int index);
void setRegisterEnabled(bool enabled);
bool getNotificationsAllowed();
void setNotificationsAllowed(bool value);
void setMwiServerAddress(QString value);
void setTransport(linphone::TransportType value);
void setServerAddress(QString value);
void setOutboundProxyEnabled(bool value);
void setStunServer(QString value);
void setIceEnabled(bool value);
void setAvpfEnabled(bool value);
void setBundleModeEnabled(bool value);
void setExpire(int value);
void setConferenceFactoryAddress(QString value);
void setAudioVideoConferenceFactoryAddress(QString value);
void setLimeServerUrl(QString value);
QString dialPlanAsString(const std::shared_ptr<linphone::DialPlan> &dialPlan);
signals: signals:
void registrationStateChanged(const std::shared_ptr<linphone::Account> &account, void registrationStateChanged(const std::shared_ptr<linphone::Account> &account,
@ -56,6 +76,22 @@ signals:
void pictureUriChanged(QString uri); void pictureUriChanged(QString uri);
void unreadNotificationsChanged(int unreadMessagesCount, int unreadCallsCount); void unreadNotificationsChanged(int unreadMessagesCount, int unreadCallsCount);
void displayNameChanged(QString displayName);
void dialPlanChanged(int index);
void registerEnabledChanged(bool enabled);
void notificationsAllowedChanged(bool value);
void mwiServerAddressChanged(QString value);
void transportChanged(linphone::TransportType value);
void serverAddressChanged(QString value);
void outboundProxyEnabledChanged(bool value);
void stunServerChanged(QString value);
void iceEnabledChanged(bool value);
void avpfEnabledChanged(bool value);
void bundleModeEnabledChanged(bool value);
void expireChanged(int value);
void conferenceFactoryAddressChanged(QString value);
void audioVideoConferenceFactoryAddressChanged(QString value);
void limeServerUrlChanged(QString value);
private: private:
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -32,9 +32,11 @@
#include <QClipboard> #include <QClipboard>
#include <QDesktopServices> #include <QDesktopServices>
#include <QHostAddress>
#include <QImageReader> #include <QImageReader>
#include <QQuickWindow> #include <QQuickWindow>
#include <QRandomGenerator> #include <QRandomGenerator>
#include <QRegularExpression>
// ============================================================================= // =============================================================================
@ -260,6 +262,10 @@ QString Utils::formatDate(const QDateTime &date, bool includeTime) {
return dateDay + " | " + time; return dateDay + " | " + time;
} }
QString Utils::formatTime(const QDateTime &date) {
return date.time().toString("hh:mm");
}
QString Utils::formatDateElapsedTime(const QDateTime &date) { QString Utils::formatDateElapsedTime(const QDateTime &date) {
// auto y = floor(seconds / 31104000); // auto y = floor(seconds / 31104000);
// if (y > 0) return QString::number(y) + " years"; // if (y > 0) return QString::number(y) + " years";
@ -300,6 +306,35 @@ QString Utils::interpretUrl(const QString &uri) {
return address; return address;
} }
bool Utils::isValidSIPAddress(const QString &uri) {
bool isValid = false;
App::postModelBlock([&isValid, uri]() mutable {
isValid = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(uri)) != nullptr;
});
return isValid;
}
bool Utils::isValidIPAddress(const QString &host) {
QHostAddress address;
return address.setAddress(host);
}
bool Utils::isValidHostname(const QString &hostname) {
QRegularExpression regex("^[a-zA-Z0-9]([a-zA-Z0-9-]{0,62}[a-zA-Z0-9])?$");
QStringList labels = hostname.split('.');
if (labels.size() > 127) // More than 127 labels is invalid
return false;
foreach (const QString &label, labels) {
if (!regex.match(label).hasMatch() || label.length() > 63) // Label length must be between 1 and 63
return false;
}
return hostname.length() <= 253; // Total length should be <= 253
}
bool Utils::isValidURL(const QString &url) {
return QUrl(url).isValid();
}
QString Utils::findAvatarByAddress(const QString &address) { QString Utils::findAvatarByAddress(const QString &address) {
QString avatar; QString avatar;

View file

@ -82,6 +82,7 @@ public:
bool dotsSeparator = true); // Return the elapsed time formated bool dotsSeparator = true); // Return the elapsed time formated
Q_INVOKABLE static QString formatDate(const QDateTime &date, bool includeTime = true); // Return the date formated Q_INVOKABLE static QString formatDate(const QDateTime &date, bool includeTime = true); // Return the date formated
Q_INVOKABLE static QString formatDateElapsedTime(const QDateTime &date); Q_INVOKABLE static QString formatDateElapsedTime(const QDateTime &date);
Q_INVOKABLE static QString formatTime(const QDateTime &date); // Return the time formated
Q_INVOKABLE static QStringList generateSecurityLettersArray(int arraySize, int correctIndex, QString correctCode); Q_INVOKABLE static QStringList generateSecurityLettersArray(int arraySize, int correctIndex, QString correctCode);
Q_INVOKABLE static int getRandomIndex(int size); Q_INVOKABLE static int getRandomIndex(int size);
Q_INVOKABLE static bool copyToClipboard(const QString &text); Q_INVOKABLE static bool copyToClipboard(const QString &text);
@ -112,6 +113,10 @@ public:
Q_INVOKABLE static QDateTime addSecs(QDateTime date, int secs); Q_INVOKABLE static QDateTime addSecs(QDateTime date, int secs);
Q_INVOKABLE static QDateTime addYears(QDateTime date, int years); Q_INVOKABLE static QDateTime addYears(QDateTime date, int years);
Q_INVOKABLE static QString interpretUrl(const QString &uri); Q_INVOKABLE static QString interpretUrl(const QString &uri);
Q_INVOKABLE static bool isValidSIPAddress(const QString &uri);
Q_INVOKABLE static bool isValidIPAddress(const QString &host);
Q_INVOKABLE static bool isValidHostname(const QString& hostname);
Q_INVOKABLE static bool isValidURL(const QString& url);
Q_INVOKABLE static QString findAvatarByAddress(const QString &address); Q_INVOKABLE static QString findAvatarByAddress(const QString &address);
Q_INVOKABLE static VariantObject *findFriendByAddress(const QString &address); Q_INVOKABLE static VariantObject *findFriendByAddress(const QString &address);
static QString generateSavedFilename(const QString &from, const QString &to); static QString generateSavedFilename(const QString &from, const QString &to);

View file

@ -7,17 +7,35 @@ import Linphone
Rectangle { Rectangle {
id: mainItem id: mainItem
anchors.fill: parent width: container.width
height: container.height
property string titleText property string titleText
property var component property var component
property var model
color: 'white' color: 'white'
property var container
Rectangle {
width: parent.width - 2 * 45 * DefaultStyle.dp Control.ScrollView {
id: scrollView
height: parent.height height: parent.height
width: parent.width - 2 * 45 * DefaultStyle.dp
anchors.centerIn: parent anchors.centerIn: parent
contentHeight: content.height + 20 * DefaultStyle.dp
contentWidth: parent.width - 2 * 45 * DefaultStyle.dp
Control.ScrollBar.vertical: ScrollBar {
active: scrollView.contentHeight > container.height
interactive: true
policy: Control.ScrollBar.AsNeeded
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: -15 * DefaultStyle.dp
}
Control.ScrollBar.horizontal: ScrollBar {
active: false
}
ColumnLayout { ColumnLayout {
id: content
width: parent.width width: parent.width
spacing: 10 * DefaultStyle.dp spacing: 10 * DefaultStyle.dp
Text { Text {

View file

@ -0,0 +1,385 @@
import QtCore
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Control
import QtQuick.Dialogs
import Linphone
import SettingsCpp 1.0
import UtilsCpp
AbstractDetailsLayout {
id: mainItem
component: main
property alias account: mainItem.model
Component {
id: main
ColumnLayout {
width: parent.width
spacing: 5 * DefaultStyle.dp
RowLayout {
Layout.topMargin: 16 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
Layout.minimumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
Layout.fillWidth: true
text: qsTr("Détails")
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
}
Text {
text: qsTr("Editer les informations de votre compte.")
font: Typography.p1s
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
}
Item {
Layout.fillHeight: true
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 20 * DefaultStyle.dp
Layout.rightMargin: 44 * DefaultStyle.dp
Layout.topMargin: 20 * DefaultStyle.dp
Layout.leftMargin: 64 * DefaultStyle.dp
Avatar {
account: model
displayPresence: false
Layout.preferredWidth: 100 * DefaultStyle.dp
Layout.preferredHeight: 100 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
}
IconLabelButton {
visible: model.core.pictureUri.length === 0
Layout.preferredWidth: width
Layout.preferredHeight: 17 * DefaultStyle.dp
iconSource: AppIcons.camera
iconSize: 17 * DefaultStyle.dp
text: qsTr("Ajouter une image")
onClicked: fileDialog.open()
Layout.alignment: Qt.AlignHCenter
color: DefaultStyle.main2_600
}
RowLayout {
visible: model.core.pictureUri.length > 0
Layout.alignment: Qt.AlignHCenter
spacing: 5 * DefaultStyle.dp
IconLabelButton {
Layout.preferredWidth: width
Layout.preferredHeight: 17 * DefaultStyle.dp
iconSource: AppIcons.pencil
iconSize: 17 * DefaultStyle.dp
text: qsTr("Modifier l'image")
color: DefaultStyle.main2_600
onClicked: fileDialog.open()
}
IconLabelButton {
Layout.preferredWidth: width
Layout.preferredHeight: 17 * DefaultStyle.dp
iconSource: AppIcons.trashCan
iconSize: 17 * DefaultStyle.dp
text: qsTr("Supprimer l'image")
color: DefaultStyle.main2_600
onClicked: model.core.pictureUri = ""
}
}
FileDialog {
id: fileDialog
currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
onAccepted: {
var avatarPath = UtilsCpp.createAvatar( selectedFile )
if(avatarPath){
model.core.pictureUri = avatarPath
}
}
}
RowLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
Text {
Layout.alignment: Qt.AlignLeft
text: qsTr("Adresse SIP :")
color: DefaultStyle.main2_600
font: Typography.p2l
}
Text {
Layout.alignment: Qt.AlignLeft
text: model.core.identityAddress
color: DefaultStyle.main2_600
font: Typography.p1
}
Item {
Layout.fillWidth: true
}
IconLabelButton {
Layout.alignment: Qt.AlignRight
Layout.preferredWidth: 20 * DefaultStyle.dp
Layout.preferredHeight: 20 * DefaultStyle.dp
iconSize: 24 * DefaultStyle.dp
iconSource: AppIcons.copy
color: DefaultStyle.main2_600
onClicked: UtilsCpp.copyToClipboard(model.core.identityAddress)
}
}
ColumnLayout {
spacing: 5 * DefaultStyle.dp
Layout.alignment: Qt.AlignLeft
Text {
text: qsTr("Nom daffichage")
color: DefaultStyle.main2_600
font: Typography.p2l
}
Text {
text: qsTr("Le nom qui sera affiché à vos correspondants lors de vos échanges.")
color: DefaultStyle.main2_600
font: Typography.p1
}
}
TextField {
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
Layout.preferredHeight: 49 * DefaultStyle.dp
initialText: model.core.displayName
backgroundColor: DefaultStyle.grey_100
onEditingFinished: {
if (text.length != 0) model.core.displayName = text
}
}
Text {
text: qsTr("Indicatif international*")
color: DefaultStyle.main2_600
font: Typography.p2l
}
ComboSetting {
Layout.fillWidth: true
Layout.topMargin: -15 * DefaultStyle.dp
entries: account.core.dialPlans
propertyName: "dialPlan"
propertyOwner: account.core
}
SwitchSetting {
titleText: account.core.humaneReadableRegistrationState
subTitleText: account.core.humaneReadableRegistrationStateExplained
propertyName: "registerEnabled"
propertyOwner: account.core
}
RowLayout {
id:mainItem
spacing : 20 * DefaultStyle.dp
ColumnLayout {
spacing : 5 * DefaultStyle.dp
Text {
text: qsTr("Supprimer mon compte")
font: Typography.p2l
wrapMode: Text.WordWrap
color: DefaultStyle.danger_500main
Layout.fillWidth: true
}
Text {
text: qsTr("Votre compte sera retiré de ce client linphone, mais vous restez connecté sur vos autres clients")
font: Typography.p1
wrapMode: Text.WordWrap
color: DefaultStyle.main2_500main
Layout.fillWidth: true
}
}
Item {
Layout.fillWidth: true
}
Button {
background: Item{}
Layout.alignment: Qt.AlignRight
Layout.rightMargin: 5 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
contentItem: RowLayout {
Layout.alignment: Qt.AlignRight
EffectImage {
imageSource: AppIcons.trashCan
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
fillMode: Image.PreserveAspectFit
colorizationColor: DefaultStyle.danger_500main
}
}
onClicked: {
var mainWin = UtilsCpp.getMainWindow()
mainWin.showConfirmationLambdaPopup(
qsTr("Supprimer ") + (model.core.displayName.length > 0 ? model.core.displayName : qsTr("le compte")) + " ?",
qsTr("Vous pouvez vous reconnecter à tout moment en cliquant sur \"Ajouter un compte\".\nCependant toutes les informations stockées sur ce périphérique seront supprimées."),
function (confirmed) {
if (confirmed) {
account.core.removeAccount()
}
}
)
}
}
}
}
Component.onCompleted: {
}
Component.onDestruction: {
}
}
Rectangle {
Layout.fillWidth: true
Layout.topMargin: 16 * DefaultStyle.dp
height: 1 * DefaultStyle.dp
color: DefaultStyle.main2_500main
}
RowLayout {
Layout.fillWidth: true
Layout.topMargin: 16 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
Layout.minimumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
Layout.fillWidth: true
text: qsTr("Vos appareils")
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
}
Text {
text: qsTr("La liste des appareils connectés à votre compte. Vous pouvez retirer les appareils que vous nutilisez plus. (TODO connecter API SDK quand dispo)")
font: Typography.p1s
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
}
Item {
Layout.fillHeight: true
}
}
Rectangle {
color: DefaultStyle.grey_100
Layout.fillWidth: true
Layout.minimumHeight: account.core.devices.length * 133 * DefaultStyle.dp + (account.core.devices.length - 1) * 15 * DefaultStyle.dp + 2 * 21 * DefaultStyle.dp
radius: 15 * DefaultStyle.dp
Layout.rightMargin: 30 * DefaultStyle.dp
Layout.topMargin: 20 * DefaultStyle.dp
Layout.bottomMargin: 21 * DefaultStyle.dp
Layout.leftMargin: 44 * DefaultStyle.dp
ColumnLayout {
anchors.fill: parent
anchors.bottomMargin: 21 * DefaultStyle.dp
spacing: 15 * DefaultStyle.dp
Repeater {
id: devices
model: account.core.devices
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 133 * DefaultStyle.dp
Layout.topMargin: (index == 0 ? 21 : 0) * DefaultStyle.dp
Layout.leftMargin: 17 * DefaultStyle.dp
Layout.rightMargin: 17 * DefaultStyle.dp
color: 'white'
radius: 10 * DefaultStyle.dp
ColumnLayout {
anchors.topMargin: 26 * DefaultStyle.dp
anchors.bottomMargin: 26 * DefaultStyle.dp
anchors.centerIn: parent
width: parent.width
spacing: 20 * DefaultStyle.dp
RowLayout {
Layout.rightMargin: 36 * DefaultStyle.dp
Layout.leftMargin: 33 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
EffectImage {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
fillMode: Image.PreserveAspectFit
colorizationColor: DefaultStyle.main2_600
imageSource: modelData.core.userAgent.toLowerCase().includes('ios') || modelData.core.userAgent.toLowerCase().includes('android') ? AppIcons.mobile : AppIcons.desktop
}
Text {
text: modelData.core.deviceName
color: DefaultStyle.main2_600
font: Typography.p2
}
Item {
Layout.fillWidth: true
}
MediumButton {
Layout.alignment: Qt.AlignRight
text: qsTr("Supprimer")
icon.source: AppIcons.trashCan
icon.width: 16 * DefaultStyle.dp
icon.height: 16 * DefaultStyle.dp
contentImageColor: DefaultStyle.main1_500_main
onClicked: {
var mainWin = UtilsCpp.getMainWindow()
mainWin.showConfirmationLambdaPopup(
qsTr("Supprimer ") + modelData.core.deviceName + " ?",
function (confirmed) {
if (confirmed) {
modelData.core.removeDevice()
}
}
)
}
}
}
RowLayout {
Layout.rightMargin: 36 * DefaultStyle.dp
Layout.leftMargin: 33 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
text: qsTr("Dernière connexion:")
color: DefaultStyle.main2_600
font: Typography.p2
}
EffectImage {
Layout.preferredWidth: 20 * DefaultStyle.dp
Layout.preferredHeight: 20 * DefaultStyle.dp
imageSource: AppIcons.calendar
colorizationColor: DefaultStyle.main2_600
fillMode: Image.PreserveAspectFit
}
Text {
text: UtilsCpp.formatDate(modelData.core.lastUpdateTimestamp,false)
color: DefaultStyle.main2_600
font: Typography.p1
}
EffectImage {
Layout.preferredWidth: 20 * DefaultStyle.dp
Layout.preferredHeight: 20 * DefaultStyle.dp
imageSource: AppIcons.clock
colorizationColor: DefaultStyle.main2_600
fillMode: Image.PreserveAspectFit
}
Text {
text: UtilsCpp.formatTime(modelData.core.lastUpdateTimestamp)
color: DefaultStyle.main2_600
font: Typography.p1
}
}
}
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,171 @@
import QtCore
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Control
import QtQuick.Dialogs
import Linphone
import SettingsCpp 1.0
import UtilsCpp
AbstractDetailsLayout {
id: mainItem
component: main
property alias account: mainItem.model
Component {
id: main
ColumnLayout {
width: parent.width
spacing: 5 * DefaultStyle.dp
RowLayout {
Layout.topMargin: 16 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
Layout.minimumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
Layout.fillWidth: true
text: qsTr("Paramètres")
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
}
}
Item {
Layout.fillHeight: true
}
}
ColumnLayout {
id: column
Layout.fillWidth: true
spacing: 20 * DefaultStyle.dp
Layout.rightMargin: 44 * DefaultStyle.dp
Layout.leftMargin: 64 * DefaultStyle.dp
Layout.topMargin: 20 * DefaultStyle.dp
ValidatedTextField {
propertyName: "mwiServerAddress"
propertyOwner: account.core
title: qsTr("URI du serveur de messagerie vocale")
isValid: function(text) { return UtilsCpp.isValidSIPAddress(text); }
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.topMargin: 16 * DefaultStyle.dp
height: 1 * DefaultStyle.dp
color: DefaultStyle.main2_500main
}
RowLayout {
Layout.topMargin: 16 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
Layout.minimumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
Layout.fillWidth: true
text: qsTr("Paramètres avancés")
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
}
}
Item {
Layout.fillHeight: true
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 20 * DefaultStyle.dp
Layout.rightMargin: 44 * DefaultStyle.dp
Layout.topMargin: 20 * DefaultStyle.dp
Layout.leftMargin: 64 * DefaultStyle.dp
Text {
text: qsTr("Transport")
color: DefaultStyle.main2_600
font: Typography.p2l
}
ComboSetting {
Layout.fillWidth: true
Layout.topMargin: -15 * DefaultStyle.dp
entries: account.core.transports
propertyName: "transport"
propertyOwner: account.core
}
ValidatedTextField {
title: qsTr("URL du serveur mandataire")
propertyName: "serverAddress"
propertyOwner: account.core
isValid: function(text) { return UtilsCpp.isValidSIPAddress(text); }
}
SwitchSetting {
titleText: qsTr("Serveur mandataire sortant")
propertyName: "outboundProxyEnabled"
propertyOwner: account.core
}
ValidatedTextField {
propertyName: "stunServer"
propertyOwner: account.core
title: qsTr("Adresse du serveur STUN")
isValid: function(text) { return UtilsCpp.isValidIPAddress(text) || UtilsCpp.isValidHostname(text); }
}
SwitchSetting {
titleText: qsTr("Activer ICE")
propertyName: "iceEnabled"
propertyOwner: account.core
}
SwitchSetting {
titleText: qsTr("AVPF")
propertyName: "avpfEnabled"
propertyOwner: account.core
}
SwitchSetting {
titleText: qsTr("Mode bundle")
propertyName: "bundleModeEnabled"
propertyOwner: account.core
}
ValidatedTextField {
propertyName: "expire"
propertyOwner: account.core
title: qsTr("Expiration (en seconde)")
isValid: function(text) { return !isNaN(Number(text)); }
}
ValidatedTextField {
title: qsTr("URI de lusine à conversations")
propertyName: "conferenceFactoryAddress"
propertyOwner: account.core
isValid: function(text) { return UtilsCpp.isValidSIPAddress(text); }
}
ValidatedTextField {
title: qsTr("URI de lusine à réunions")
propertyName: "audioVideoConferenceFactoryAddress"
propertyOwner: account.core
isValid: function(text) { return UtilsCpp.isValidSIPAddress(text); }
}
ValidatedTextField {
title: qsTr("URL du serveur déchange de clés de chiffrement")
propertyName: "limeServerUrl"
propertyOwner: account.core
isValid: function(text) { return UtilsCpp.isValidURL(text); }
}
Item {
Layout.fillHeight: true
}
}
}
}
}
}

View file

@ -15,9 +15,8 @@ import SettingsCpp
Item { Item {
id: mainItem id: mainItem
property var callObj property var callObj
property bool settingsHidden: true property var contextualMenuOpenedComponent: undefined
property bool helpHidden: true
signal addAccountRequest() signal addAccountRequest()
signal openNewCall() signal openNewCall()
signal openCallHistory() signal openCallHistory()
@ -41,6 +40,23 @@ Item {
tabbar.currentIndex = 1 tabbar.currentIndex = 1
mainItem.createContactRequested(name, address) mainItem.createContactRequested(name, address)
} }
function openContextualMenuComponent(component) {
if (mainItem.contextualMenuOpenedComponent && mainItem.contextualMenuOpenedComponent != component) {
mainStackView.pop()
mainItem.contextualMenuOpenedComponent = undefined
}
if (!mainItem.contextualMenuOpenedComponent) {
mainStackView.push(component)
mainItem.contextualMenuOpenedComponent = component
}
settingsButton.popup.close()
}
function closeContextualMenuComponent() {
mainStackView.pop()
mainItem.contextualMenuOpenedComponent = undefined
}
AccountProxy { AccountProxy {
id: accountProxy id: accountProxy
@ -99,13 +115,8 @@ Item {
] ]
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (currentIndex === 0) accountProxy.defaultAccount.core.lResetMissedCalls() if (currentIndex === 0) accountProxy.defaultAccount.core.lResetMissedCalls()
if (!mainItem.settingsHidden) { if (mainItem.contextualMenuOpenedComponent) {
mainStackView.pop() closeContextualMenuComponent()
mainItem.settingsHidden = true
}
if (!mainItem.helpHidden) {
mainStackView.pop()
mainItem.helpHidden = true
} }
} }
} }
@ -302,7 +313,7 @@ Item {
iconSize: 32 * DefaultStyle.dp iconSize: 32 * DefaultStyle.dp
text: qsTr("Mon compte") text: qsTr("Mon compte")
iconSource: AppIcons.manageProfile iconSource: AppIcons.manageProfile
onClicked: console.log("TODO : manage profile") onClicked: openContextualMenuComponent(myAccountSettingsPageComponent)
} }
IconLabelButton { IconLabelButton {
Layout.preferredHeight: 32 * DefaultStyle.dp Layout.preferredHeight: 32 * DefaultStyle.dp
@ -310,19 +321,7 @@ Item {
iconSize: 32 * DefaultStyle.dp iconSize: 32 * DefaultStyle.dp
text: qsTr("Paramètres") text: qsTr("Paramètres")
iconSource: AppIcons.settings iconSource: AppIcons.settings
onClicked: { onClicked: openContextualMenuComponent(settingsPageComponent)
if (!mainItem.helpHidden) {
mainStackView.pop()
mainItem.helpHidden = true
}
if (mainItem.settingsHidden) {
mainStackView.push(settingsPageComponent)
settingsButton.popup.close()
mainItem.settingsHidden = false
} else {
settingsButton.popup.close()
}
}
} }
IconLabelButton { IconLabelButton {
Layout.preferredHeight: 32 * DefaultStyle.dp Layout.preferredHeight: 32 * DefaultStyle.dp
@ -336,19 +335,7 @@ Item {
iconSize: 32 * DefaultStyle.dp iconSize: 32 * DefaultStyle.dp
text: qsTr("Aide") text: qsTr("Aide")
iconSource: AppIcons.question iconSource: AppIcons.question
onClicked: { onClicked: openContextualMenuComponent(helpPageComponent)
if (!mainItem.settingsHidden) {
mainStackView.pop()
mainItem.settingsHidden = true
}
if (mainItem.helpHidden) {
mainStackView.push(helpPageComponent)
settingsButton.popup.close()
mainItem.helpHidden = false
} else {
settingsButton.popup.close()
}
}
} }
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
@ -402,22 +389,23 @@ Item {
MeetingPage{} MeetingPage{}
} }
} }
Component {
id: myAccountSettingsPageComponent
AccountSettingsPage {
account: accountProxy.defaultAccount
onGoBack: closeContextualMenuComponent()
}
}
Component { Component {
id: settingsPageComponent id: settingsPageComponent
SettingsPage { SettingsPage {
onGoBack: { onGoBack: closeContextualMenuComponent()
mainStackView.pop()
mainItem.settingsHidden = true
}
} }
} }
Component { Component {
id: helpPageComponent id: helpPageComponent
HelpPage { HelpPage {
onGoBack: { onGoBack: closeContextualMenuComponent()
mainStackView.pop()
mainItem.helpHidden = true
}
} }
} }
Control.StackView { Control.StackView {

View file

@ -5,7 +5,7 @@ import QtQuick.Controls as Control
import Linphone import Linphone
import SettingsCpp 1.0 import SettingsCpp 1.0
GenericSettingsLayout { AbstractDetailsLayout {
component: settings component: settings
width: parent.width width: parent.width
Component { Component {
@ -29,12 +29,14 @@ GenericSettingsLayout {
titleText: qsTr("Annulateur d'écho") titleText: qsTr("Annulateur d'écho")
subTitleText: qsTr("Évite que de l'écho soit entendu par votre correspondant") subTitleText: qsTr("Évite que de l'écho soit entendu par votre correspondant")
propertyName: "echoCancellationEnabled" propertyName: "echoCancellationEnabled"
propertyOwner: SettingsCpp
} }
SwitchSetting { SwitchSetting {
Layout.fillWidth: true Layout.fillWidth: true
titleText: qsTr("Activer lenregistrement automatique des appels") titleText: qsTr("Activer lenregistrement automatique des appels")
subTitleText: qsTr("Enregistrer tous les appels par défaut") subTitleText: qsTr("Enregistrer tous les appels par défaut")
propertyName: "automaticallyRecordCallsEnabled" propertyName: "automaticallyRecordCallsEnabled"
propertyOwner: SettingsCpp
} }
} }
} }
@ -101,8 +103,9 @@ GenericSettingsLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 12 * DefaultStyle.dp Layout.topMargin: 12 * DefaultStyle.dp
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
model: SettingsCpp.playbackDevices entries: SettingsCpp.playbackDevices
propertyName: "playbackDevice" propertyName: "playbackDevice"
propertyOwner: SettingsCpp
} }
Slider { Slider {
id: speakerVolume id: speakerVolume
@ -145,8 +148,9 @@ GenericSettingsLayout {
Layout.topMargin: 12 * DefaultStyle.dp Layout.topMargin: 12 * DefaultStyle.dp
Layout.bottomMargin: 22 * DefaultStyle.dp Layout.bottomMargin: 22 * DefaultStyle.dp
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
model: SettingsCpp.captureDevices entries: SettingsCpp.captureDevices
propertyName: "captureDevice" propertyName: "captureDevice"
propertyOwner: SettingsCpp
} }
Slider { Slider {
id: microVolume id: microVolume
@ -224,8 +228,9 @@ GenericSettingsLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 12 * DefaultStyle.dp Layout.topMargin: 12 * DefaultStyle.dp
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
model: SettingsCpp.videoDevices entries: SettingsCpp.videoDevices
propertyName: "videoDevice" propertyName: "videoDevice"
propertyOwner: SettingsCpp
} }
Item { Item {
Layout.fillHeight: true Layout.fillHeight: true

View file

@ -7,7 +7,7 @@ import Linphone
import SettingsCpp 1.0 import SettingsCpp 1.0
import UtilsCpp 1.0 import UtilsCpp 1.0
GenericSettingsLayout { AbstractDetailsLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
id: mainItem id: mainItem
@ -50,19 +50,21 @@ GenericSettingsLayout {
SwitchSetting { SwitchSetting {
titleText: qsTr("Activer les traces de débogage") titleText: qsTr("Activer les traces de débogage")
propertyName: "logsEnabled" propertyName: "logsEnabled"
propertyOwner: SettingsCpp
} }
SwitchSetting { SwitchSetting {
titleText: qsTr("Activer les traces de débogage intégrales") titleText: qsTr("Activer les traces de débogage intégrales")
propertyName: "fullLogsEnabled" propertyName: "fullLogsEnabled"
propertyOwner: SettingsCpp
} }
MediumButton { MediumButton {
text: qsTr("Supprimer les traces") text: qsTr("Supprimer les traces")
onClicked: { onClicked: {
deleteLogs.open() deleteLogs.open()
} }
} }
MediumButton { MediumButton {
text: qsTr("Partager les traces") text: qsTr("Partager les traces")
enabled: SettingsCpp.logsEnabled || SettingsCpp.fullLogsEnabled enabled: SettingsCpp.logsEnabled || SettingsCpp.fullLogsEnabled
onClicked: { onClicked: {
UtilsCpp.getMainWindow().showLoadingPopup(qsTr("Téléversement des traces en cours ...")) UtilsCpp.getMainWindow().showLoadingPopup(qsTr("Téléversement des traces en cours ..."))

View file

@ -2,10 +2,10 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls as Control import QtQuick.Controls as Control
import SettingsCpp 1.0
import Linphone import Linphone
GenericSettingsLayout { AbstractDetailsLayout {
Component { Component {
id: settings id: settings
Column { Column {
@ -14,6 +14,7 @@ GenericSettingsLayout {
titleText: qsTr("Chiffrer tous les fichiers") titleText: qsTr("Chiffrer tous les fichiers")
subTitleText: qsTr("Attention, vous ne pourrez pas revenir en arrière !") subTitleText: qsTr("Attention, vous ne pourrez pas revenir en arrière !")
propertyName: "vfsEnabled" propertyName: "vfsEnabled"
propertyOwner: SettingsCpp
} }
} }
} }

View file

@ -49,6 +49,9 @@ AppWindow {
AccountProxy { AccountProxy {
id: accountProxy id: accountProxy
onHaveAccountChanged: {
initStackViewItem()
}
} }
StackView { StackView {
id: mainWindowStackView id: mainWindowStackView

View file

@ -14,14 +14,18 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Layout/Meeting/AddParticipantsLayout.qml view/Layout/Meeting/AddParticipantsLayout.qml
view/Layout/FormItemLayout.qml view/Layout/FormItemLayout.qml
view/Layout/ValidatedTextField.qml
view/Layout/Mosaic.qml view/Layout/Mosaic.qml
view/Layout/RightPanelLayout.qml view/Layout/RightPanelLayout.qml
view/Layout/Section.qml view/Layout/Section.qml
view/App/Layout/Settings/GenericSettingsLayout.qml view/App/Layout/AbstractDetailsLayout.qml
view/App/Layout/Settings/SecuritySettingsLayout.qml view/App/Layout/Settings/SecuritySettingsLayout.qml
view/App/Layout/Settings/CallSettingsLayout.qml view/App/Layout/Settings/CallSettingsLayout.qml
view/App/Layout/Settings/DebugSettingsLayout.qml view/App/Layout/Settings/DebugSettingsLayout.qml
view/App/Layout/Account/AccountSettingsGeneralLayout.qml
view/App/Layout/Account/AccountSettingsParametersLayout.qml
view/Item/Account/Accounts.qml view/Item/Account/Accounts.qml
@ -96,7 +100,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Item/Test/ItemsTest.qml view/Item/Test/ItemsTest.qml
view/Item/Settings/SettingsFamily.qml view/Item/MasterDetailFamily.qml
view/Item/Settings/SwitchSetting.qml view/Item/Settings/SwitchSetting.qml
view/Item/Settings/ComboSetting.qml view/Item/Settings/ComboSetting.qml
@ -114,8 +118,11 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Page/Main/ContactPage.qml view/Page/Main/ContactPage.qml
view/Page/Main/MeetingPage.qml view/Page/Main/MeetingPage.qml
view/Page/Main/AbstractMasterDetailPage.qml
view/Page/Main/SettingsPage.qml view/Page/Main/SettingsPage.qml
view/Page/Main/HelpPage.qml view/Page/Main/HelpPage.qml
view/Page/Main/AccountSettingsPage.qml
view/Tool/utils.js view/Tool/utils.js
# Prototypes # Prototypes

View file

@ -105,6 +105,7 @@ Control.ComboBox {
width: mainItem.width width: mainItem.width
implicitHeight: contentItem.implicitHeight implicitHeight: contentItem.implicitHeight
padding: 1 * DefaultStyle.dp padding: 1 * DefaultStyle.dp
height: Math.min(listView.contentHeight, 300)
contentItem: ListView { contentItem: ListView {
id: listView id: listView

View file

@ -2,23 +2,24 @@ import QtQuick
import QtQuick.Controls.Material import QtQuick.Controls.Material
import QtQuick.Layouts import QtQuick.Layouts
import Linphone import Linphone
import SettingsCpp 1.0
import 'qrc:/Linphone/view/Tool/utils.js' as Utils import 'qrc:/Linphone/view/Tool/utils.js' as Utils
ComboBox { ComboBox {
id: comboBox id: comboBox
Layout.preferredHeight: 49 * DefaultStyle.dp Layout.preferredHeight: 49 * DefaultStyle.dp
property string propertyName property string propertyName
property var propertyOwner
property alias entries: comboBox.model
oneLine: true oneLine: true
currentIndex: Utils.findIndex(model, function (entry) { currentIndex: Utils.findIndex(model, function (entry) {
return entry === SettingsCpp[propertyName] return entry === propertyOwner[propertyName]
}) })
onCurrentTextChanged: { onCurrentTextChanged: {
binding.when = currentText != SettingsCpp[propertyName] binding.when = currentText != propertyOwner[propertyName]
} }
Binding { Binding {
id: binding id: binding
target: SettingsCpp target: propertyOwner
property: propertyName property: propertyName
value: comboBox.currentText value: comboBox.currentText
when: false when: false

View file

@ -2,19 +2,20 @@ import QtQuick
import QtQuick.Controls.Material import QtQuick.Controls.Material
import QtQuick.Layouts import QtQuick.Layouts
import Linphone import Linphone
import SettingsCpp 1.0
RowLayout { RowLayout {
id:mainItem id:mainItem
property string titleText property string titleText
property string subTitleText property string subTitleText
property string propertyName property string propertyName
property var propertyOwner
property bool enabled: true property bool enabled: true
spacing : 20 * DefaultStyle.dp spacing : 20 * DefaultStyle.dp
Layout.minimumHeight: 32 * DefaultStyle.dp
ColumnLayout { ColumnLayout {
Text { Text {
text: titleText text: titleText
font: Typography.p2 font: Typography.p2l
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
color: DefaultStyle.main2_600 color: DefaultStyle.main2_600
Layout.fillWidth: true Layout.fillWidth: true
@ -30,8 +31,8 @@ RowLayout {
} }
SwitchButton { SwitchButton {
id: switchButton id: switchButton
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
checked: SettingsCpp[mainItem.propertyName] checked: propertyOwner[mainItem.propertyName]
enabled: mainItem.enabled enabled: mainItem.enabled
onToggled: { onToggled: {
binding.when = true binding.when = true
@ -39,7 +40,7 @@ RowLayout {
} }
Binding { Binding {
id: binding id: binding
target: SettingsCpp target: propertyOwner
property: mainItem.propertyName property: mainItem.propertyName
value: switchButton.checked value: switchButton.checked
when: false when: false

View file

@ -5,7 +5,8 @@ import Linphone
Control.TextField { Control.TextField {
id: mainItem id: mainItem
width: 360 * DefaultStyle.dp property var customWidth
width: (customWidth ? customWidth - 1 : 360) * DefaultStyle.dp
height: 49 * DefaultStyle.dp height: 49 * DefaultStyle.dp
leftPadding: 15 * DefaultStyle.dp leftPadding: 15 * DefaultStyle.dp
rightPadding: eyeButton.visible ? 5 * DefaultStyle.dp + eyeButton.width + eyeButton.rightMargin : 15 * DefaultStyle.dp rightPadding: eyeButton.visible ? 5 * DefaultStyle.dp + eyeButton.width + eyeButton.rightMargin : 15 * DefaultStyle.dp

View file

@ -48,4 +48,4 @@ ColumnLayout {
} }
} }
} }

View file

@ -0,0 +1,56 @@
import QtQuick
import QtQuick.Controls as Control
import QtQuick.Layouts 1.0
import QtQuick.Effects
import UtilsCpp
import Linphone
FormItemLayout {
id: mainItem
label: title
mandatory: false
enableErrorText: true
property string propertyName
property var propertyOwner
property var title
property var placeHolder
property bool useTitleAsPlaceHolder: true
property int idleTimeOut: 200
property var isValid: function(text) {
return true;
}
contentItem: TextField {
id: textField
property var initialReading: true
placeholderText: useTitleAsPlaceHolder ? mainItem.title : mainItem.placeHolder
initialText: mainItem.propertyOwner[mainItem.propertyName]
customWidth: mainItem.parent.width
Timer {
id: idleTimer
running: false
interval: mainItem.idleTimeOut
repeat: false
onTriggered: textField.editingFinished()
}
onEditingFinished: {
if (initialReading) {
initialReading = false
return
}
if (text.length != 0) {
if (isValid(text)) {
mainItem.errorMessage = ""
if (mainItem.propertyOwner[mainItem.propertyName] != text)
mainItem.propertyOwner[mainItem.propertyName] = text
} else {
mainItem.errorMessage = qsTr("Format non reconnu")
}
} else
mainItem.errorMessage = ""
}
onTextChanged: {
idleTimer.restart()
}
}
}

View file

@ -0,0 +1,83 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import QtQuick.Controls as Control
import Linphone
import UtilsCpp
AbstractMainPage {
id: mainItem
showDefaultItem: false
property var layoutsPath
property var titleText
signal goBack()
function layoutUrl(name) {
return layoutsPath+"/"+name+".qml"
}
property var families
leftPanelContent: ColumnLayout {
id: leftPanel
Layout.fillWidth: true
Layout.fillHeight: true
property int sideMargin: 45 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: leftPanel.sideMargin
Layout.rightMargin: leftPanel.sideMargin
spacing: 5 * DefaultStyle.dp
Button {
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp
icon.source: AppIcons.leftArrow
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
background: Item {
anchors.fill: parent
}
onClicked: {
mainItem.goBack()
}
}
Text {
text: titleText
color: DefaultStyle.main2_700
font: Typography.h3
}
Item {
Layout.fillWidth: true
}
}
ListView {
id: familiesList
Layout.fillWidth: true
Layout.fillHeight: true
model: mainItem.families
Layout.topMargin: 41 * DefaultStyle.dp
Layout.leftMargin: leftPanel.sideMargin
property int selectedIndex: 0
delegate: MasterDetailFamily {
titleText: modelData.title
visible: modelData.visible != undefined ? modelData.visible : true
isSelected: familiesList.selectedIndex == index
onSelected: {
familiesList.selectedIndex = index
rightPanelStackView.clear()
rightPanelStackView.push(layoutUrl(modelData.layout), { titleText: modelData.title, model: modelData.model, container: rightPanelStackView})
}
}
}
Component.onCompleted: {
let initialEntry = mainItem.families[familiesList.selectedIndex]
rightPanelStackView.push(layoutUrl(initialEntry.layout), { titleText: initialEntry.title, model: initialEntry.model, container: rightPanelStackView})
}
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import QtQuick.Controls as Control
import Linphone
import UtilsCpp 1.0
import SettingsCpp 1.0
AbstractMasterDetailPage {
layoutsPath: "qrc:/Linphone/view/App/Layout/Account"
titleText: qsTr("Mon compte")
property AccountProxy accounts: AccountProxy{id: accountProxy}
property AccountGui account: accountProxy.defaultAccount
families: [
{title: qsTr("Général"), layout: "AccountSettingsGeneralLayout", model: account},
{title: qsTr("Paramètres de compte"), layout: "AccountSettingsParametersLayout", model: account}
]
}

View file

@ -18,11 +18,12 @@ AbstractMainPage {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
property int sideMargin: 45 * DefaultStyle.dp property int sideMargin: 45 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: leftPanel.sideMargin Layout.leftMargin: leftPanel.sideMargin
Layout.rightMargin: leftPanel.sideMargin Layout.rightMargin: leftPanel.sideMargin
spacing: 5 * DefaultStyle.dp
Button { Button {
Layout.preferredHeight: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp Layout.preferredWidth: 24 * DefaultStyle.dp

View file

@ -2,22 +2,12 @@ import QtQuick
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls as Control import QtQuick.Controls as Control
import Linphone
import UtilsCpp
import SettingsCpp import SettingsCpp
AbstractMainPage { AbstractMasterDetailPage {
layoutsPath: "qrc:/Linphone/view/App/Layout/Settings"
id: mainItem titleText: qsTr("Paramètres")
showDefaultItem: false families: [
signal goBack()
function layoutUrl(name) {
return "qrc:/Linphone/view/App/Layout/Settings/"+name+".qml"
}
property var settingsFamilies: [
{title: qsTr("Appels"), layout: "CallSettingsLayout"}, {title: qsTr("Appels"), layout: "CallSettingsLayout"},
//{title: qsTr("Sécurité"), layout: "SecuritySettingsLayout"}, //{title: qsTr("Sécurité"), layout: "SecuritySettingsLayout"},
{title: qsTr("Conversations"), layout: "ChatSettingsLayout", visible: !SettingsCpp.disableChatFeature}, {title: qsTr("Conversations"), layout: "ChatSettingsLayout", visible: !SettingsCpp.disableChatFeature},
@ -27,63 +17,4 @@ AbstractMainPage {
{title: qsTr("Réseau"), layout: "NetworkSettingsLayout"}, {title: qsTr("Réseau"), layout: "NetworkSettingsLayout"},
{title: qsTr("Paramètres avancés"), layout: "AdvancedSettingsLayout"} {title: qsTr("Paramètres avancés"), layout: "AdvancedSettingsLayout"}
] ]
leftPanelContent: ColumnLayout {
id: leftPanel
Layout.fillWidth: true
Layout.fillHeight: true
property int sideMargin: 45 * DefaultStyle.dp
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: leftPanel.sideMargin
Layout.rightMargin: leftPanel.sideMargin
Button {
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp
icon.source: AppIcons.leftArrow
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
background: Item {
anchors.fill: parent
}
onClicked: {
mainItem.goBack()
}
}
Text {
text: qsTr("Paramètres")
color: DefaultStyle.main2_700
font: Typography.h3
}
Item {
Layout.fillWidth: true
}
}
ListView {
id: settingsFamiliesList
Layout.fillWidth: true
Layout.fillHeight: true
model: mainItem.settingsFamilies
Layout.topMargin: 41 * DefaultStyle.dp
Layout.leftMargin: leftPanel.sideMargin
property int selectedIndex: 0
delegate: SettingsFamily {
titleText: modelData.title
visible: modelData.visible != undefined ? modelData.visible : true
isSelected: settingsFamiliesList.selectedIndex == index
onSelected: {
settingsFamiliesList.selectedIndex = index
rightPanelStackView.clear()
rightPanelStackView.push(layoutUrl(modelData.layout), { titleText: modelData.title })
}
}
}
Component.onCompleted: {
let initialEntry = mainItem.settingsFamilies[settingsFamiliesList.selectedIndex]
rightPanelStackView.push(layoutUrl(initialEntry.layout), { titleText: initialEntry.title })
}
}
} }

View file

@ -109,4 +109,7 @@ QtObject {
property string cellSignalMedium: "image://internal/cell-signal-medium.svg" property string cellSignalMedium: "image://internal/cell-signal-medium.svg"
property string cellSignalLow: "image://internal/cell-signal-low.svg" property string cellSignalLow: "image://internal/cell-signal-low.svg"
property string cellSignalNone: "image://internal/cell-signal-none.svg" property string cellSignalNone: "image://internal/cell-signal-none.svg"
property string mobile: "image://internal/mobile.svg"
property string desktop: "image://internal/desktop.svg"
property string calendar: "image://internal/calendar.svg"
} }

View file

@ -52,6 +52,13 @@ QtObject {
weight: 400 * DefaultStyle.dp weight: 400 * DefaultStyle.dp
}) })
// Text/P1 - Paratraph text
property font p1s: Qt.font( {
family: DefaultStyle.defaultFont,
pixelSize: 13 * DefaultStyle.dp,
weight: 400 * DefaultStyle.dp
})
// Bouton/B2 - Medium Bouton // Bouton/B2 - Medium Bouton
property font b2: Qt.font( { property font b2: Qt.font( {
family: DefaultStyle.defaultFont, family: DefaultStyle.defaultFont,