Fix reentrency issues with magic search :
- store search parameters into Core. - add search limitation to avoid 300 useless items. - retrieve old parameters on proxy when changing list. - store parent proxy to avoid MOC warnings. Fix contacts search views: - add a loading state for buzy indicators. - limit results on suggestions. - avoid to create MagicSearchProxy if not needed. - add a status to know if friend is stored or not. - propagate invalidateFilter. - delay search while typing. Fix margins and participants selection. Do not search contacts when contact panel is not shown. Avoid search on empty magicbar. Avoid repeating section on object that disappeared from cache. Focus on new contact after creation. Avoid changing maxresult if not needed. Redirect only if friend is not ldap Fix empty display name on making favorite a ldap contact. Fix focus and positions on favorites.
This commit is contained in:
parent
97c2c1e214
commit
a6561ccb19
22 changed files with 1158 additions and 883 deletions
|
|
@ -824,8 +824,6 @@ void CallCore::findRemoteLdapFriend(QSharedPointer<CallCore> me) {
|
||||||
auto linphoneSearch = CoreModel::getInstance()->getCore()->createMagicSearch();
|
auto linphoneSearch = CoreModel::getInstance()->getCore()->createMagicSearch();
|
||||||
linphoneSearch->setLimitedSearch(true);
|
linphoneSearch->setLimitedSearch(true);
|
||||||
mLdapMagicSearchModel = Utils::makeQObject_ptr<MagicSearchModel>(linphoneSearch);
|
mLdapMagicSearchModel = Utils::makeQObject_ptr<MagicSearchModel>(linphoneSearch);
|
||||||
mLdapMagicSearchModel->setSourceFlags((int)LinphoneEnums::MagicSearchSource::LdapServers);
|
|
||||||
mLdapMagicSearchModel->setAggregationFlag(LinphoneEnums::MagicSearchAggregation::Friend);
|
|
||||||
mLdapMagicSearchModel->setSelf(mLdapMagicSearchModel);
|
mLdapMagicSearchModel->setSelf(mLdapMagicSearchModel);
|
||||||
mLdapMagicSearchModelConnection = QSharedPointer<SafeConnection<CallCore, MagicSearchModel>>(
|
mLdapMagicSearchModelConnection = QSharedPointer<SafeConnection<CallCore, MagicSearchModel>>(
|
||||||
new SafeConnection<CallCore, MagicSearchModel>(me, mLdapMagicSearchModel), &QObject::deleteLater);
|
new SafeConnection<CallCore, MagicSearchModel>(me, mLdapMagicSearchModel), &QObject::deleteLater);
|
||||||
|
|
@ -845,5 +843,6 @@ void CallCore::findRemoteLdapFriend(QSharedPointer<CallCore> me) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mLdapMagicSearchModel->search(mRemoteUsername);
|
mLdapMagicSearchModel->search(mRemoteAddress, (int)LinphoneEnums::MagicSearchSource::LdapServers,
|
||||||
|
LinphoneEnums::MagicSearchAggregation::Friend, -1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,14 +44,14 @@ QVariant createFriendDevice(const QString &name, const QString &address, Linphon
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<FriendCore> FriendCore::create(const std::shared_ptr<linphone::Friend> &contact) {
|
QSharedPointer<FriendCore> FriendCore::create(const std::shared_ptr<linphone::Friend> &contact, bool isStored) {
|
||||||
auto sharedPointer = QSharedPointer<FriendCore>(new FriendCore(contact), &QObject::deleteLater);
|
auto sharedPointer = QSharedPointer<FriendCore>(new FriendCore(contact, isStored), &QObject::deleteLater);
|
||||||
sharedPointer->setSelf(sharedPointer);
|
sharedPointer->setSelf(sharedPointer);
|
||||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||||
return sharedPointer;
|
return sharedPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObject(nullptr) {
|
FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool isStored) : QObject(nullptr) {
|
||||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||||
if (contact) {
|
if (contact) {
|
||||||
mustBeInLinphoneThread(getClassName());
|
mustBeInLinphoneThread(getClassName());
|
||||||
|
|
@ -60,6 +60,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
|
||||||
mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence());
|
mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence());
|
||||||
mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
|
mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
|
||||||
mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
|
mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
|
||||||
|
auto defaultAddress = contact->getAddress();
|
||||||
auto vcard = contact->getVcard();
|
auto vcard = contact->getVcard();
|
||||||
if (vcard) {
|
if (vcard) {
|
||||||
mOrganization = Utils::coreStringToAppString(vcard->getOrganization());
|
mOrganization = Utils::coreStringToAppString(vcard->getOrganization());
|
||||||
|
|
@ -69,13 +70,16 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
|
||||||
mFullName = Utils::coreStringToAppString(vcard->getFullName());
|
mFullName = Utils::coreStringToAppString(vcard->getFullName());
|
||||||
mVCardString = Utils::coreStringToAppString(vcard->asVcard4String());
|
mVCardString = Utils::coreStringToAppString(vcard->asVcard4String());
|
||||||
}
|
}
|
||||||
|
if (defaultAddress) {
|
||||||
|
if (mGivenName.isEmpty()) mGivenName = Utils::coreStringToAppString(defaultAddress->getUsername());
|
||||||
|
}
|
||||||
auto addresses = contact->getAddresses();
|
auto addresses = contact->getAddresses();
|
||||||
for (auto &address : addresses) {
|
for (auto &address : addresses) {
|
||||||
mAddressList.append(
|
mAddressList.append(
|
||||||
createFriendAddressVariant(_addressLabel, Utils::coreStringToAppString(address->asStringUriOnly())));
|
createFriendAddressVariant(_addressLabel, Utils::coreStringToAppString(address->asStringUriOnly())));
|
||||||
}
|
}
|
||||||
mDefaultAddress =
|
mDefaultAddress =
|
||||||
contact->getAddress() ? Utils::coreStringToAppString(contact->getAddress()->asStringUriOnly()) : QString();
|
defaultAddress ? Utils::coreStringToAppString(contact->getAddress()->asStringUriOnly()) : QString();
|
||||||
auto phoneNumbers = contact->getPhoneNumbersWithLabel();
|
auto phoneNumbers = contact->getPhoneNumbersWithLabel();
|
||||||
for (auto &phoneNumber : phoneNumbers) {
|
for (auto &phoneNumber : phoneNumbers) {
|
||||||
mPhoneNumberList.append(
|
mPhoneNumberList.append(
|
||||||
|
|
@ -94,9 +98,11 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
|
||||||
|
|
||||||
mStarred = contact->getStarred();
|
mStarred = contact->getStarred();
|
||||||
mIsSaved = true;
|
mIsSaved = true;
|
||||||
|
mIsStored = isStored;
|
||||||
} else {
|
} else {
|
||||||
mIsSaved = false;
|
mIsSaved = false;
|
||||||
mStarred = false;
|
mStarred = false;
|
||||||
|
mIsStored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mIsLdap = ToolModel::friendIsInFriendList(ToolModel::getLdapFriendList(), contact);
|
mIsLdap = ToolModel::friendIsInFriendList(ToolModel::getLdapFriendList(), contact);
|
||||||
|
|
@ -502,15 +508,28 @@ bool FriendCore::getIsSaved() const {
|
||||||
void FriendCore::setIsSaved(bool data) {
|
void FriendCore::setIsSaved(bool data) {
|
||||||
if (mIsSaved != data) {
|
if (mIsSaved != data) {
|
||||||
mIsSaved = data;
|
mIsSaved = data;
|
||||||
|
if (mIsSaved) setIsStored(true);
|
||||||
emit isSavedChanged(mIsSaved);
|
emit isSavedChanged(mIsSaved);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FriendCore::getIsStored() const {
|
||||||
|
return mIsStored;
|
||||||
|
}
|
||||||
|
void FriendCore::setIsStored(bool data) {
|
||||||
|
if (mIsStored != data) {
|
||||||
|
mIsStored = data;
|
||||||
|
emit isStoredChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FriendCore::writeIntoModel(std::shared_ptr<FriendModel> model) const {
|
void FriendCore::writeIntoModel(std::shared_ptr<FriendModel> model) const {
|
||||||
mustBeInLinphoneThread(QString("[") + gClassName + "] " + Q_FUNC_INFO);
|
mustBeInLinphoneThread(QString("[") + gClassName + "] " + Q_FUNC_INFO);
|
||||||
model->getFriend()->edit();
|
model->getFriend()->edit();
|
||||||
// needed to create the vcard if not created yet
|
// needed to create the vcard if not created yet
|
||||||
model->setName(mGivenName + (mFamilyName.isEmpty() || mGivenName.isEmpty() ? "" : " ") + mFamilyName);
|
model->setName(mFullName.isEmpty()
|
||||||
|
? mGivenName + (mFamilyName.isEmpty() || mGivenName.isEmpty() ? "" : " ") + mFamilyName
|
||||||
|
: mFullName);
|
||||||
auto core = CoreModel::getInstance()->getCore();
|
auto core = CoreModel::getInstance()->getCore();
|
||||||
|
|
||||||
std::list<std::shared_ptr<linphone::Address>> addresses;
|
std::list<std::shared_ptr<linphone::Address>> addresses;
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ class FriendCore : public QObject, public AbstractObject {
|
||||||
Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY
|
Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY
|
||||||
consolidatedPresenceChanged)
|
consolidatedPresenceChanged)
|
||||||
Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged)
|
Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged)
|
||||||
|
Q_PROPERTY(bool isStored READ getIsStored NOTIFY isStoredChanged)
|
||||||
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
|
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
|
||||||
Q_PROPERTY(bool starred READ getStarred WRITE lSetStarred NOTIFY starredChanged)
|
Q_PROPERTY(bool starred READ getStarred WRITE lSetStarred NOTIFY starredChanged)
|
||||||
Q_PROPERTY(bool readOnly READ getReadOnly CONSTANT)
|
Q_PROPERTY(bool readOnly READ getReadOnly CONSTANT)
|
||||||
|
|
@ -72,8 +73,8 @@ class FriendCore : public QObject, public AbstractObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Should be call from model Thread. Will be automatically in App thread after initialization
|
// Should be call from model Thread. Will be automatically in App thread after initialization
|
||||||
static QSharedPointer<FriendCore> create(const std::shared_ptr<linphone::Friend> &contact);
|
static QSharedPointer<FriendCore> create(const std::shared_ptr<linphone::Friend> &contact, bool isStored = true);
|
||||||
FriendCore(const std::shared_ptr<linphone::Friend> &contact);
|
FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool isStored = true);
|
||||||
FriendCore(const FriendCore &friendCore);
|
FriendCore(const FriendCore &friendCore);
|
||||||
~FriendCore();
|
~FriendCore();
|
||||||
void setSelf(QSharedPointer<FriendCore> me);
|
void setSelf(QSharedPointer<FriendCore> me);
|
||||||
|
|
@ -81,7 +82,6 @@ public:
|
||||||
void reset(const FriendCore &contact);
|
void reset(const FriendCore &contact);
|
||||||
|
|
||||||
QString getDisplayName() const;
|
QString getDisplayName() const;
|
||||||
void setDisplayName(const QString &name);
|
|
||||||
|
|
||||||
QString getFamilyName() const;
|
QString getFamilyName() const;
|
||||||
void setFamilyName(const QString &name);
|
void setFamilyName(const QString &name);
|
||||||
|
|
@ -131,6 +131,9 @@ public:
|
||||||
bool getIsSaved() const;
|
bool getIsSaved() const;
|
||||||
void setIsSaved(bool isSaved);
|
void setIsSaved(bool isSaved);
|
||||||
|
|
||||||
|
bool getIsStored() const; // Exist in DB
|
||||||
|
void setIsStored(bool isStored);
|
||||||
|
|
||||||
QString getPictureUri() const;
|
QString getPictureUri() const;
|
||||||
void setPictureUri(const QString &uri);
|
void setPictureUri(const QString &uri);
|
||||||
void onPictureUriChanged(QString uri);
|
void onPictureUriChanged(QString uri);
|
||||||
|
|
@ -163,6 +166,7 @@ signals:
|
||||||
void pictureUriChanged();
|
void pictureUriChanged();
|
||||||
void saved();
|
void saved();
|
||||||
void isSavedChanged(bool isSaved);
|
void isSavedChanged(bool isSaved);
|
||||||
|
void isStoredChanged();
|
||||||
void removed(FriendCore *contact);
|
void removed(FriendCore *contact);
|
||||||
void defaultAddressChanged();
|
void defaultAddressChanged();
|
||||||
void allAddressesChanged();
|
void allAddressesChanged();
|
||||||
|
|
@ -189,6 +193,7 @@ protected:
|
||||||
QString mDefaultAddress;
|
QString mDefaultAddress;
|
||||||
QString mPictureUri;
|
QString mPictureUri;
|
||||||
bool mIsSaved;
|
bool mIsSaved;
|
||||||
|
bool mIsStored;
|
||||||
QString mVCardString;
|
QString mVCardString;
|
||||||
bool mIsLdap;
|
bool mIsLdap;
|
||||||
std::shared_ptr<FriendModel> mFriendModel;
|
std::shared_ptr<FriendModel> mFriendModel;
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,13 @@ DEFINE_ABSTRACT_OBJECT(FriendGui)
|
||||||
FriendGui::FriendGui(QObject *parent) : QObject(parent) {
|
FriendGui::FriendGui(QObject *parent) : QObject(parent) {
|
||||||
mustBeInMainThread(getClassName());
|
mustBeInMainThread(getClassName());
|
||||||
mCore = FriendCore::create(nullptr);
|
mCore = FriendCore::create(nullptr);
|
||||||
|
connect(mCore.get(), &FriendCore::isStoredChanged, this, &FriendGui::isStoredChanged);
|
||||||
}
|
}
|
||||||
FriendGui::FriendGui(QSharedPointer<FriendCore> core) {
|
FriendGui::FriendGui(QSharedPointer<FriendCore> core) {
|
||||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||||
mCore = core;
|
mCore = core;
|
||||||
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
||||||
|
connect(mCore.get(), &FriendCore::isStoredChanged, this, &FriendGui::isStoredChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
FriendGui::~FriendGui() {
|
FriendGui::~FriendGui() {
|
||||||
|
|
@ -43,3 +45,7 @@ void FriendGui::createContact(const QString &address) {
|
||||||
FriendCore *FriendGui::getCore() const {
|
FriendCore *FriendGui::getCore() const {
|
||||||
return mCore.get();
|
return mCore.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FriendGui::getIsStored() {
|
||||||
|
return mCore ? mCore->getIsStored() : false;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ class FriendGui : public QObject, public AbstractObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(FriendCore *core READ getCore CONSTANT)
|
Q_PROPERTY(FriendCore *core READ getCore CONSTANT)
|
||||||
|
Q_PROPERTY(bool isStored READ getIsStored NOTIFY isStoredChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FriendGui(QObject *parent = nullptr);
|
FriendGui(QObject *parent = nullptr);
|
||||||
|
|
@ -37,6 +38,12 @@ public:
|
||||||
FriendCore *getCore() const;
|
FriendCore *getCore() const;
|
||||||
Q_INVOKABLE void createContact(const QString &address);
|
Q_INVOKABLE void createContact(const QString &address);
|
||||||
QSharedPointer<FriendCore> mCore;
|
QSharedPointer<FriendCore> mCore;
|
||||||
|
|
||||||
|
bool getIsStored();
|
||||||
|
signals:
|
||||||
|
void isStoredChanged();
|
||||||
|
|
||||||
|
public:
|
||||||
DECLARE_ABSTRACT_OBJECT
|
DECLARE_ABSTRACT_OBJECT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,3 +88,7 @@ void SortFilterProxy::setSortOrder(const Qt::SortOrder &order) {
|
||||||
void SortFilterProxy::remove(int index, int count) {
|
void SortFilterProxy::remove(int index, int count) {
|
||||||
QSortFilterProxyModel::removeRows(index, count);
|
QSortFilterProxyModel::removeRows(index, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SortFilterProxy::invalidateFilter() {
|
||||||
|
QSortFilterProxyModel::invalidateFilter();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ public:
|
||||||
void setFilterText(const QString &filter);
|
void setFilterText(const QString &filter);
|
||||||
|
|
||||||
Q_INVOKABLE void remove(int index, int count = 1);
|
Q_INVOKABLE void remove(int index, int count = 1);
|
||||||
|
void invalidateFilter();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void countChanged();
|
void countChanged();
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
#include "MagicSearchList.hpp"
|
#include "MagicSearchList.hpp"
|
||||||
#include "core/App.hpp"
|
#include "core/App.hpp"
|
||||||
#include "core/friend/FriendCore.hpp"
|
#include "core/friend/FriendCore.hpp"
|
||||||
#include "core/friend/FriendGui.hpp"
|
|
||||||
#include "tool/Utils.hpp"
|
#include "tool/Utils.hpp"
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <linphone++/linphone.hh>
|
#include <linphone++/linphone.hh>
|
||||||
|
|
@ -62,7 +61,7 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
|
||||||
if (haveContact == mList.end()) {
|
if (haveContact == mList.end()) {
|
||||||
connect(friendCore.get(), &FriendCore::removed, this, qOverload<QObject *>(&MagicSearchList::remove));
|
connect(friendCore.get(), &FriendCore::removed, this, qOverload<QObject *>(&MagicSearchList::remove));
|
||||||
add(friendCore);
|
add(friendCore);
|
||||||
emit friendCreated(getCount() - 1);
|
emit friendCreated(getCount() - 1, new FriendGui(friendCore));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mCoreModelConnection->invokeToModel([this] {
|
mCoreModelConnection->invokeToModel([this] {
|
||||||
|
|
@ -71,34 +70,17 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
|
||||||
auto magicSearch = Utils::makeQObject_ptr<MagicSearchModel>(linphoneSearch);
|
auto magicSearch = Utils::makeQObject_ptr<MagicSearchModel>(linphoneSearch);
|
||||||
mCoreModelConnection->invokeToCore([this, magicSearch] {
|
mCoreModelConnection->invokeToCore([this, magicSearch] {
|
||||||
mMagicSearch = magicSearch;
|
mMagicSearch = magicSearch;
|
||||||
mMagicSearch->mSourceFlags = mSourceFlags;
|
|
||||||
mMagicSearch->mAggregationFlag = mAggregationFlag;
|
|
||||||
mMagicSearch->setSelf(mMagicSearch);
|
mMagicSearch->setSelf(mMagicSearch);
|
||||||
mModelConnection = QSharedPointer<SafeConnection<MagicSearchList, MagicSearchModel>>(
|
mModelConnection = QSharedPointer<SafeConnection<MagicSearchList, MagicSearchModel>>(
|
||||||
new SafeConnection<MagicSearchList, MagicSearchModel>(mCoreModelConnection->mCore.mQData, mMagicSearch),
|
new SafeConnection<MagicSearchList, MagicSearchModel>(mCoreModelConnection->mCore.mQData, mMagicSearch),
|
||||||
&QObject::deleteLater);
|
&QObject::deleteLater);
|
||||||
mModelConnection->makeConnectToCore(&MagicSearchList::lSearch, [this](QString filter) {
|
|
||||||
mModelConnection->invokeToModel([this, filter]() { mMagicSearch->search(filter); });
|
|
||||||
});
|
|
||||||
mModelConnection->makeConnectToCore(&MagicSearchList::lSetSourceFlags, [this](int flags) {
|
|
||||||
mModelConnection->invokeToModel([this, flags]() { mMagicSearch->setSourceFlags(flags); });
|
|
||||||
});
|
|
||||||
mModelConnection->makeConnectToCore(&MagicSearchList::lSetAggregationFlag,
|
|
||||||
[this](LinphoneEnums::MagicSearchAggregation aggregation) {
|
|
||||||
mModelConnection->invokeToModel([this, aggregation]() {
|
|
||||||
mMagicSearch->setAggregationFlag(aggregation);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
mModelConnection->makeConnectToCore(
|
mModelConnection->makeConnectToCore(
|
||||||
&MagicSearchList::lSetAggregationFlag, [this](LinphoneEnums::MagicSearchAggregation flag) {
|
&MagicSearchList::lSearch,
|
||||||
mModelConnection->invokeToModel([this, flag]() { mMagicSearch->setAggregationFlag(flag); });
|
[this](QString filter, int sourceFlags, LinphoneEnums::MagicSearchAggregation aggregationFlag,
|
||||||
});
|
int maxResults) {
|
||||||
mModelConnection->makeConnectToModel(&MagicSearchModel::sourceFlagsChanged, [this](int flags) {
|
mModelConnection->invokeToModel([this, filter, sourceFlags, aggregationFlag, maxResults]() {
|
||||||
mModelConnection->invokeToCore([this, flags]() { setSourceFlags(flags); });
|
mMagicSearch->search(filter, sourceFlags, aggregationFlag, maxResults);
|
||||||
});
|
});
|
||||||
mModelConnection->makeConnectToModel(
|
|
||||||
&MagicSearchModel::aggregationFlagChanged, [this](LinphoneEnums::MagicSearchAggregation flag) {
|
|
||||||
mModelConnection->invokeToCore([this, flag]() { setAggregationFlag(flag); });
|
|
||||||
});
|
});
|
||||||
mModelConnection->makeConnectToModel(
|
mModelConnection->makeConnectToModel(
|
||||||
&MagicSearchModel::searchResultsReceived,
|
&MagicSearchModel::searchResultsReceived,
|
||||||
|
|
@ -106,26 +88,30 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
|
||||||
auto *contacts = new QList<QSharedPointer<FriendCore>>();
|
auto *contacts = new QList<QSharedPointer<FriendCore>>();
|
||||||
for (auto it : results) {
|
for (auto it : results) {
|
||||||
QSharedPointer<FriendCore> contact;
|
QSharedPointer<FriendCore> contact;
|
||||||
if (it->getFriend()) {
|
auto linphoneFriend = it->getFriend();
|
||||||
contact = FriendCore::create(it->getFriend());
|
// Considered LDAP results as stored.
|
||||||
|
bool isStored = (it->getSourceFlags() & (int)linphone::MagicSearch::Source::LdapServers) > 0;
|
||||||
|
if (linphoneFriend) {
|
||||||
|
contact = FriendCore::create(linphoneFriend);
|
||||||
contacts->append(contact);
|
contacts->append(contact);
|
||||||
} else if (auto address = it->getAddress()) {
|
} else if (auto address = it->getAddress()) {
|
||||||
auto linphoneFriend = CoreModel::getInstance()->getCore()->createFriend();
|
auto linphoneFriend = CoreModel::getInstance()->getCore()->createFriend();
|
||||||
contact = FriendCore::create(linphoneFriend);
|
linphoneFriend->setAddress(address);
|
||||||
auto displayname = Utils::coreStringToAppString(address->getDisplayName());
|
contact = FriendCore::create(linphoneFriend, isStored);
|
||||||
auto splitted = displayname.split(" ");
|
auto displayName = Utils::coreStringToAppString(address->getDisplayName());
|
||||||
if (splitted.size() > 0) {
|
auto splitted = displayName.split(" ");
|
||||||
|
if (!displayName.isEmpty() && splitted.size() > 0) {
|
||||||
contact->setGivenName(splitted[0]);
|
contact->setGivenName(splitted[0]);
|
||||||
splitted.removeFirst();
|
splitted.removeFirst();
|
||||||
contact->setFamilyName(splitted.join(" "));
|
contact->setFamilyName(splitted.join(" "));
|
||||||
} else {
|
} else {
|
||||||
contact->setGivenName(Utils::coreStringToAppString(address->getUsername()));
|
contact->setGivenName(Utils::coreStringToAppString(address->getUsername()));
|
||||||
}
|
}
|
||||||
contact->appendAddress(Utils::coreStringToAppString(address->asStringUriOnly()));
|
|
||||||
contacts->append(contact);
|
contacts->append(contact);
|
||||||
} else if (!it->getPhoneNumber().empty()) {
|
} else if (!it->getPhoneNumber().empty()) {
|
||||||
auto linphoneFriend = CoreModel::getInstance()->getCore()->createFriend();
|
linphoneFriend = CoreModel::getInstance()->getCore()->createFriend();
|
||||||
contact = FriendCore::create(linphoneFriend);
|
linphoneFriend->setAddress(address);
|
||||||
|
contact = FriendCore::create(linphoneFriend, isStored);
|
||||||
contact->setGivenName(Utils::coreStringToAppString(it->getPhoneNumber()));
|
contact->setGivenName(Utils::coreStringToAppString(it->getPhoneNumber()));
|
||||||
contact->appendPhoneNumber(tr("Phone"), Utils::coreStringToAppString(it->getPhoneNumber()));
|
contact->appendPhoneNumber(tr("Phone"), Utils::coreStringToAppString(it->getPhoneNumber()));
|
||||||
contacts->append(contact);
|
contacts->append(contact);
|
||||||
|
|
@ -148,10 +134,11 @@ void MagicSearchList::setResults(const QList<QSharedPointer<FriendCore>> &contac
|
||||||
if (!isFriendCore) continue;
|
if (!isFriendCore) continue;
|
||||||
disconnect(isFriendCore.get());
|
disconnect(isFriendCore.get());
|
||||||
}
|
}
|
||||||
|
qDebug() << log().arg("SetResults: %1").arg(contacts.size());
|
||||||
resetData<FriendCore>(contacts);
|
resetData<FriendCore>(contacts);
|
||||||
for (auto it : contacts) {
|
for (auto it : contacts) {
|
||||||
connect(it.get(), &FriendCore::removed, this, qOverload<QObject *>(&MagicSearchList::remove));
|
connect(it.get(), &FriendCore::removed, this, qOverload<QObject *>(&MagicSearchList::remove));
|
||||||
connect(it.get(), &FriendCore::starredChanged, this, [this] { lSearch(mSearchFilter); });
|
connect(it.get(), &FriendCore::starredChanged, this, &MagicSearchList::friendStarredChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,7 +148,7 @@ void MagicSearchList::addResult(const QSharedPointer<FriendCore> &contact) {
|
||||||
void MagicSearchList::setSearch(const QString &search) {
|
void MagicSearchList::setSearch(const QString &search) {
|
||||||
mSearchFilter = search;
|
mSearchFilter = search;
|
||||||
if (!search.isEmpty()) {
|
if (!search.isEmpty()) {
|
||||||
lSearch(search);
|
emit lSearch(search, mSourceFlags, mAggregationFlag, mMaxResults);
|
||||||
} else {
|
} else {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
mList.clear();
|
mList.clear();
|
||||||
|
|
@ -180,6 +167,17 @@ void MagicSearchList::setSourceFlags(int flags) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MagicSearchList::getMaxResults() const {
|
||||||
|
return mMaxResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MagicSearchList::setMaxResults(int maxResults) {
|
||||||
|
if (mMaxResults != maxResults) {
|
||||||
|
mMaxResults = maxResults;
|
||||||
|
emit maxResultsChanged(mMaxResults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LinphoneEnums::MagicSearchAggregation MagicSearchList::getAggregationFlag() const {
|
LinphoneEnums::MagicSearchAggregation MagicSearchList::getAggregationFlag() const {
|
||||||
return mAggregationFlag;
|
return mAggregationFlag;
|
||||||
}
|
}
|
||||||
|
|
@ -191,11 +189,20 @@ void MagicSearchList::setAggregationFlag(LinphoneEnums::MagicSearchAggregation f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> MagicSearchList::roleNames() const {
|
||||||
|
QHash<int, QByteArray> roles;
|
||||||
|
roles[Qt::DisplayRole] = "$modelData";
|
||||||
|
roles[Qt::DisplayRole + 1] = "isStored";
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant MagicSearchList::data(const QModelIndex &index, int role) const {
|
QVariant MagicSearchList::data(const QModelIndex &index, int role) const {
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
return QVariant::fromValue(new FriendGui(mList[row].objectCast<FriendCore>()));
|
return QVariant::fromValue(new FriendGui(mList[row].objectCast<FriendCore>()));
|
||||||
|
} else if (role == Qt::DisplayRole + 1) {
|
||||||
|
return mList[row].objectCast<FriendCore>()->getIsStored();
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#define MAGIC_SEARCH_LIST_H_
|
#define MAGIC_SEARCH_LIST_H_
|
||||||
|
|
||||||
#include "../proxy/ListProxy.hpp"
|
#include "../proxy/ListProxy.hpp"
|
||||||
|
#include "core/friend/FriendGui.hpp"
|
||||||
#include "model/search/MagicSearchModel.hpp"
|
#include "model/search/MagicSearchModel.hpp"
|
||||||
#include "tool/AbstractObject.hpp"
|
#include "tool/AbstractObject.hpp"
|
||||||
#include "tool/thread/SafeConnection.hpp"
|
#include "tool/thread/SafeConnection.hpp"
|
||||||
|
|
@ -50,19 +51,24 @@ public:
|
||||||
LinphoneEnums::MagicSearchAggregation getAggregationFlag() const;
|
LinphoneEnums::MagicSearchAggregation getAggregationFlag() const;
|
||||||
void setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag);
|
void setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag);
|
||||||
|
|
||||||
|
int getMaxResults() const;
|
||||||
|
void setMaxResults(int maxResults);
|
||||||
|
|
||||||
|
virtual QHash<int, QByteArray> roleNames() const override;
|
||||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
int findFriendIndexByAddress(const QString &address);
|
int findFriendIndexByAddress(const QString &address);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void lSearch(QString filter);
|
void
|
||||||
void lSetSourceFlags(int sourceFlags);
|
lSearch(QString filter, int sourceFlags, LinphoneEnums::MagicSearchAggregation aggregationFlag, int maxResults);
|
||||||
void lSetAggregationFlag(LinphoneEnums::MagicSearchAggregation aggregationFlag);
|
|
||||||
|
|
||||||
void sourceFlagsChanged(int sourceFlags);
|
void sourceFlagsChanged(int sourceFlags);
|
||||||
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation flag);
|
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation flag);
|
||||||
|
void maxResultsChanged(int maxResults);
|
||||||
|
|
||||||
void friendCreated(int index);
|
void friendCreated(int index, FriendGui *data);
|
||||||
|
void friendStarredChanged();
|
||||||
|
|
||||||
void initialized();
|
void initialized();
|
||||||
|
|
||||||
|
|
@ -70,6 +76,7 @@ private:
|
||||||
int mSourceFlags;
|
int mSourceFlags;
|
||||||
LinphoneEnums::MagicSearchAggregation mAggregationFlag;
|
LinphoneEnums::MagicSearchAggregation mAggregationFlag;
|
||||||
QString mSearchFilter;
|
QString mSearchFilter;
|
||||||
|
int mMaxResults = -1;
|
||||||
|
|
||||||
std::shared_ptr<MagicSearchModel> mMagicSearch;
|
std::shared_ptr<MagicSearchModel> mMagicSearch;
|
||||||
QSharedPointer<SafeConnection<MagicSearchList, MagicSearchModel>> mModelConnection;
|
QSharedPointer<SafeConnection<MagicSearchList, MagicSearchModel>> mModelConnection;
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,14 @@
|
||||||
|
|
||||||
#include "MagicSearchProxy.hpp"
|
#include "MagicSearchProxy.hpp"
|
||||||
#include "MagicSearchList.hpp"
|
#include "MagicSearchList.hpp"
|
||||||
|
|
||||||
#include "core/App.hpp"
|
#include "core/App.hpp"
|
||||||
#include "core/friend/FriendGui.hpp"
|
#include "core/friend/FriendCore.hpp"
|
||||||
|
|
||||||
MagicSearchProxy::MagicSearchProxy(QObject *parent) : LimitProxy(parent) {
|
MagicSearchProxy::MagicSearchProxy(QObject *parent) : LimitProxy(parent) {
|
||||||
mSourceFlags = (int)LinphoneEnums::MagicSearchSource::Friends | (int)LinphoneEnums::MagicSearchSource::LdapServers;
|
|
||||||
mAggregationFlag = LinphoneEnums::MagicSearchAggregation::Friend;
|
|
||||||
setList(MagicSearchList::create());
|
setList(MagicSearchList::create());
|
||||||
sort(0);
|
|
||||||
connect(this, &MagicSearchProxy::forceUpdate, [this] {
|
connect(this, &MagicSearchProxy::forceUpdate, [this] {
|
||||||
if (mList) emit mList->lSearch(mSearchText);
|
if (mList) emit mList->lSearch(mSearchText, getSourceFlags(), getAggregationFlag(), getMaxResults());
|
||||||
});
|
});
|
||||||
connect(App::getInstance(), &App::currentDateChanged, this, &MagicSearchProxy::forceUpdate);
|
connect(App::getInstance(), &App::currentDateChanged, this, &MagicSearchProxy::forceUpdate);
|
||||||
}
|
}
|
||||||
|
|
@ -50,28 +48,28 @@ void MagicSearchProxy::setList(QSharedPointer<MagicSearchList> newList) {
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(mList.get(), &MagicSearchList::aggregationFlagChanged, this, &MagicSearchProxy::aggregationFlagChanged,
|
connect(mList.get(), &MagicSearchList::aggregationFlagChanged, this, &MagicSearchProxy::aggregationFlagChanged,
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
mList.get(), &MagicSearchList::friendCreated, this,
|
mList.get(), &MagicSearchList::friendCreated, this,
|
||||||
[this](int index) {
|
[this](int index, FriendGui *data) {
|
||||||
auto proxyIndex =
|
auto sortModel = dynamic_cast<SortFilterList *>(sourceModel());
|
||||||
dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(mList->index(index, 0)).row();
|
sortModel->invalidate();
|
||||||
// auto proxyIndex = mapFromSource(sourceModel()->index(index, 0)); // OLD (keep for checking new proxy
|
if (!data->mCore->isLdap()) {
|
||||||
// behavior)
|
auto proxyIndex = sortModel->mapFromSource(mList->index(index, 0)).row();
|
||||||
emit friendCreated(proxyIndex);
|
// auto proxyIndex = mapFromSource(sourceModel()->index(index, 0)); // OLD (keep for checking new
|
||||||
|
// proxy behavior)
|
||||||
|
emit localFriendCreated(proxyIndex);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(
|
connect(
|
||||||
mList.get(), &MagicSearchList::initialized, this,
|
mList.get(), &MagicSearchList::initialized, this, [this, newList = mList.get()] { emit initialized(); },
|
||||||
[this, newList = mList.get()] {
|
|
||||||
emit newList->lSetSourceFlags(mSourceFlags);
|
|
||||||
emit newList->lSetAggregationFlag(mAggregationFlag);
|
|
||||||
emit initialized();
|
|
||||||
},
|
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
auto sortFilterList = new SortFilterList(mList.get(), Qt::AscendingOrder);
|
auto sortFilterList = new SortFilterList(mList.get(), Qt::AscendingOrder);
|
||||||
if (oldModel) {
|
if (oldModel) {
|
||||||
sortFilterList->mShowFavoritesOnly = oldModel->mShowFavoritesOnly;
|
sortFilterList->mShowFavoritesOnly = oldModel->mShowFavoritesOnly;
|
||||||
|
sortFilterList->mHideSuggestions = oldModel->mHideSuggestions;
|
||||||
sortFilterList->mShowLdapContacts = oldModel->mShowLdapContacts;
|
sortFilterList->mShowLdapContacts = oldModel->mShowLdapContacts;
|
||||||
sortFilterList->mHideListProxy = oldModel->mHideListProxy;
|
sortFilterList->mHideListProxy = oldModel->mHideListProxy;
|
||||||
if (sortFilterList->mHideListProxy) {
|
if (sortFilterList->mHideListProxy) {
|
||||||
|
|
@ -81,7 +79,14 @@ void MagicSearchProxy::setList(QSharedPointer<MagicSearchList> newList) {
|
||||||
[this, sortFilterList]() { sortFilterList->invalidate(); });
|
[this, sortFilterList]() { sortFilterList->invalidate(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
connect(
|
||||||
|
mList.get(), &MagicSearchList::friendStarredChanged, this,
|
||||||
|
[this, sortFilterList]() {
|
||||||
|
if (showFavoritesOnly()) sortFilterList->invalidate();
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
setSourceModels(sortFilterList);
|
setSourceModels(sortFilterList);
|
||||||
|
sort(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MagicSearchProxy::findFriendIndexByAddress(const QString &address) {
|
int MagicSearchProxy::findFriendIndexByAddress(const QString &address) {
|
||||||
|
|
@ -105,14 +110,19 @@ void MagicSearchProxy::setSearchText(const QString &search) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int MagicSearchProxy::getSourceFlags() const {
|
int MagicSearchProxy::getSourceFlags() const {
|
||||||
return mSourceFlags;
|
return mList->getSourceFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicSearchProxy::setSourceFlags(int flags) {
|
void MagicSearchProxy::setSourceFlags(int flags) {
|
||||||
if (flags != mSourceFlags) {
|
mList->setSourceFlags(flags);
|
||||||
mSourceFlags = flags;
|
}
|
||||||
emit mList->lSetSourceFlags(flags);
|
|
||||||
}
|
int MagicSearchProxy::getMaxResults() const {
|
||||||
|
return mList->getMaxResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MagicSearchProxy::setMaxResults(int flags) {
|
||||||
|
mList->setMaxResults(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagicSearchProxy::showFavoritesOnly() const {
|
bool MagicSearchProxy::showFavoritesOnly() const {
|
||||||
|
|
@ -128,9 +138,28 @@ void MagicSearchProxy::setShowFavoritesOnly(bool show) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicSearchProxy::setParentProxy(MagicSearchProxy *proxy) {
|
bool MagicSearchProxy::getHideSuggestions() const {
|
||||||
setList(proxy->mList);
|
return dynamic_cast<SortFilterList *>(sourceModel())->mHideSuggestions;
|
||||||
emit parentProxyChanged();
|
}
|
||||||
|
void MagicSearchProxy::setHideSuggestions(bool data) {
|
||||||
|
auto list = dynamic_cast<SortFilterList *>(sourceModel());
|
||||||
|
if (list->mHideSuggestions != data) {
|
||||||
|
list->mHideSuggestions = data;
|
||||||
|
list->invalidate();
|
||||||
|
emit hideSuggestionsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MagicSearchProxy *MagicSearchProxy::getParentProxy() const {
|
||||||
|
return mParentProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MagicSearchProxy::setParentProxy(MagicSearchProxy *parentProxy) {
|
||||||
|
if (parentProxy && parentProxy->mList) {
|
||||||
|
mParentProxy = parentProxy;
|
||||||
|
setList(parentProxy->mList);
|
||||||
|
emit parentProxyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MagicSearchProxy *MagicSearchProxy::getHideListProxy() const {
|
MagicSearchProxy *MagicSearchProxy::getHideListProxy() const {
|
||||||
|
|
@ -138,36 +167,34 @@ MagicSearchProxy *MagicSearchProxy::getHideListProxy() const {
|
||||||
return list ? list->mHideListProxy : nullptr;
|
return list ? list->mHideListProxy : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicSearchProxy::setHideListProxy(MagicSearchProxy *proxy) {
|
void MagicSearchProxy::setHideListProxy(MagicSearchProxy *hideListProxy) {
|
||||||
auto list = dynamic_cast<SortFilterList *>(sourceModel());
|
auto list = dynamic_cast<SortFilterList *>(sourceModel());
|
||||||
if (list && list->mHideListProxy != proxy) {
|
if (list && list->mHideListProxy != hideListProxy) {
|
||||||
if (list->mHideListProxy) list->disconnect(list->mHideListProxy);
|
if (list->mHideListProxy) list->disconnect(list->mHideListProxy);
|
||||||
list->mHideListProxy = proxy;
|
list->mHideListProxy = hideListProxy;
|
||||||
list->invalidate();
|
list->invalidate();
|
||||||
if (proxy) {
|
if (hideListProxy) {
|
||||||
connect(proxy, &MagicSearchProxy::countChanged, list, [this, list]() { list->invalidate(); });
|
connect(hideListProxy, &MagicSearchProxy::countChanged, list, [this, list]() { list->invalidateFilter(); });
|
||||||
connect(proxy, &MagicSearchProxy::modelReset, list, [this, list]() { list->invalidate(); });
|
connect(hideListProxy, &MagicSearchProxy::modelReset, list, [this, list]() { list->invalidateFilter(); });
|
||||||
}
|
}
|
||||||
emit hideListProxyChanged();
|
emit hideListProxyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LinphoneEnums::MagicSearchAggregation MagicSearchProxy::getAggregationFlag() const {
|
LinphoneEnums::MagicSearchAggregation MagicSearchProxy::getAggregationFlag() const {
|
||||||
return mAggregationFlag;
|
return mList->getAggregationFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicSearchProxy::setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag) {
|
void MagicSearchProxy::setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag) {
|
||||||
if (flag != mAggregationFlag) {
|
mList->setAggregationFlag(flag);
|
||||||
mAggregationFlag = flag;
|
|
||||||
emit mList->lSetAggregationFlag(flag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagicSearchProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
bool MagicSearchProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||||
auto friendCore = getItemAtSource<MagicSearchList, FriendCore>(sourceRow);
|
auto friendCore = getItemAtSource<MagicSearchList, FriendCore>(sourceRow);
|
||||||
auto toShow = false;
|
auto toShow = false;
|
||||||
if (friendCore) {
|
if (friendCore) {
|
||||||
toShow = (!mShowFavoritesOnly || friendCore->getStarred()) && (mShowLdapContacts || !friendCore->isLdap());
|
toShow = (!mHideSuggestions || friendCore->getIsStored()) &&
|
||||||
|
(!mShowFavoritesOnly || friendCore->getStarred()) && (mShowLdapContacts || !friendCore->isLdap());
|
||||||
if (toShow && mHideListProxy) {
|
if (toShow && mHideListProxy) {
|
||||||
for (auto &friendAddress : friendCore->getAllAddresses()) {
|
for (auto &friendAddress : friendCore->getAllAddresses()) {
|
||||||
toShow = mHideListProxy->findFriendIndexByAddress(friendAddress.toMap()["address"].toString()) == -1;
|
toShow = mHideListProxy->findFriendIndexByAddress(friendAddress.toMap()["address"].toString()) == -1;
|
||||||
|
|
@ -184,6 +211,10 @@ bool MagicSearchProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, c
|
||||||
auto r = getItemAtSource<MagicSearchList, FriendCore>(sourceRight.row());
|
auto r = getItemAtSource<MagicSearchList, FriendCore>(sourceRight.row());
|
||||||
|
|
||||||
if (l && r) {
|
if (l && r) {
|
||||||
|
bool lIsStored = l->getIsStored();
|
||||||
|
bool rIsStored = r->getIsStored();
|
||||||
|
if (lIsStored && !rIsStored) return true;
|
||||||
|
else if (!lIsStored && rIsStored) return false;
|
||||||
auto lName = l->getDisplayName().toLower();
|
auto lName = l->getDisplayName().toLower();
|
||||||
auto rName = r->getDisplayName().toLower();
|
auto rName = r->getDisplayName().toLower();
|
||||||
return lName < rName;
|
return lName < rName;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#define MAGIC_SEARCH_PROXY_H_
|
#define MAGIC_SEARCH_PROXY_H_
|
||||||
|
|
||||||
#include "../proxy/LimitProxy.hpp"
|
#include "../proxy/LimitProxy.hpp"
|
||||||
|
#include "core/friend/FriendGui.hpp"
|
||||||
#include "core/search/MagicSearchList.hpp"
|
#include "core/search/MagicSearchList.hpp"
|
||||||
#include "tool/LinphoneEnums.hpp"
|
#include "tool/LinphoneEnums.hpp"
|
||||||
|
|
||||||
|
|
@ -32,18 +33,21 @@ class MagicSearchProxy : public LimitProxy {
|
||||||
|
|
||||||
Q_PROPERTY(QString searchText READ getSearchText WRITE setSearchText NOTIFY searchTextChanged)
|
Q_PROPERTY(QString searchText READ getSearchText WRITE setSearchText NOTIFY searchTextChanged)
|
||||||
Q_PROPERTY(int sourceFlags READ getSourceFlags WRITE setSourceFlags NOTIFY sourceFlagsChanged)
|
Q_PROPERTY(int sourceFlags READ getSourceFlags WRITE setSourceFlags NOTIFY sourceFlagsChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(int maxResults READ getMaxResults WRITE setMaxResults NOTIFY maxResultsChanged)
|
||||||
Q_PROPERTY(LinphoneEnums::MagicSearchAggregation aggregationFlag READ getAggregationFlag WRITE setAggregationFlag
|
Q_PROPERTY(LinphoneEnums::MagicSearchAggregation aggregationFlag READ getAggregationFlag WRITE setAggregationFlag
|
||||||
NOTIFY aggregationFlagChanged)
|
NOTIFY aggregationFlagChanged)
|
||||||
Q_PROPERTY(bool showFavoritesOnly READ showFavoritesOnly WRITE setShowFavoritesOnly NOTIFY showFavoriteOnlyChanged)
|
Q_PROPERTY(bool showFavoritesOnly READ showFavoritesOnly WRITE setShowFavoritesOnly NOTIFY showFavoriteOnlyChanged)
|
||||||
Q_PROPERTY(MagicSearchProxy *parentProxy WRITE setParentProxy NOTIFY parentProxyChanged)
|
Q_PROPERTY(MagicSearchProxy *parentProxy READ getParentProxy WRITE setParentProxy NOTIFY parentProxyChanged)
|
||||||
Q_PROPERTY(MagicSearchProxy *hideListProxy READ getHideListProxy WRITE setHideListProxy NOTIFY hideListProxyChanged)
|
Q_PROPERTY(MagicSearchProxy *hideListProxy READ getHideListProxy WRITE setHideListProxy NOTIFY hideListProxyChanged)
|
||||||
|
|
||||||
Q_PROPERTY(bool showLdapContacts READ showLdapContacts WRITE setShowLdapContacts CONSTANT)
|
Q_PROPERTY(bool showLdapContacts READ showLdapContacts WRITE setShowLdapContacts CONSTANT)
|
||||||
|
Q_PROPERTY(bool hideSuggestions READ getHideSuggestions WRITE setHideSuggestions NOTIFY hideSuggestionsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DECLARE_SORTFILTER_CLASS(bool mShowFavoritesOnly = false; bool mShowLdapContacts = false;
|
DECLARE_SORTFILTER_CLASS(bool mShowFavoritesOnly = false; bool mShowLdapContacts = true;
|
||||||
|
bool mHideSuggestions = false;
|
||||||
MagicSearchProxy *mHideListProxy = nullptr;)
|
MagicSearchProxy *mHideListProxy = nullptr;)
|
||||||
|
|
||||||
MagicSearchProxy(QObject *parent = Q_NULLPTR);
|
MagicSearchProxy(QObject *parent = Q_NULLPTR);
|
||||||
~MagicSearchProxy();
|
~MagicSearchProxy();
|
||||||
|
|
||||||
|
|
@ -56,12 +60,19 @@ public:
|
||||||
LinphoneEnums::MagicSearchAggregation getAggregationFlag() const;
|
LinphoneEnums::MagicSearchAggregation getAggregationFlag() const;
|
||||||
void setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag);
|
void setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag);
|
||||||
|
|
||||||
|
int getMaxResults() const;
|
||||||
|
void setMaxResults(int maxResults);
|
||||||
|
|
||||||
bool showFavoritesOnly() const;
|
bool showFavoritesOnly() const;
|
||||||
void setShowFavoritesOnly(bool show);
|
void setShowFavoritesOnly(bool show);
|
||||||
|
|
||||||
bool showLdapContacts() const;
|
bool showLdapContacts() const;
|
||||||
void setShowLdapContacts(bool show);
|
void setShowLdapContacts(bool show);
|
||||||
|
|
||||||
|
bool getHideSuggestions() const;
|
||||||
|
void setHideSuggestions(bool data);
|
||||||
|
|
||||||
|
MagicSearchProxy *getParentProxy() const;
|
||||||
void setList(QSharedPointer<MagicSearchList> list);
|
void setList(QSharedPointer<MagicSearchList> list);
|
||||||
Q_INVOKABLE void setParentProxy(MagicSearchProxy *proxy);
|
Q_INVOKABLE void setParentProxy(MagicSearchProxy *proxy);
|
||||||
|
|
||||||
|
|
@ -75,17 +86,18 @@ signals:
|
||||||
void searchTextChanged();
|
void searchTextChanged();
|
||||||
void sourceFlagsChanged(int sourceFlags);
|
void sourceFlagsChanged(int sourceFlags);
|
||||||
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation aggregationFlag);
|
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation aggregationFlag);
|
||||||
|
void maxResultsChanged(int maxResults);
|
||||||
void forceUpdate();
|
void forceUpdate();
|
||||||
void friendCreated(int index);
|
void localFriendCreated(int index);
|
||||||
void showFavoriteOnlyChanged();
|
void showFavoriteOnlyChanged();
|
||||||
|
void hideSuggestionsChanged();
|
||||||
void parentProxyChanged();
|
void parentProxyChanged();
|
||||||
void hideListProxyChanged();
|
void hideListProxyChanged();
|
||||||
void initialized();
|
void initialized();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
MagicSearchProxy *mParentProxy = nullptr;
|
||||||
QString mSearchText;
|
QString mSearchText;
|
||||||
int mSourceFlags;
|
|
||||||
LinphoneEnums::MagicSearchAggregation mAggregationFlag;
|
|
||||||
QSharedPointer<MagicSearchList> mList;
|
QSharedPointer<MagicSearchList> mList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "model/core/CoreModel.hpp"
|
#include "model/core/CoreModel.hpp"
|
||||||
|
#include "model/setting/SettingsModel.hpp"
|
||||||
#include "model/tool/ToolModel.hpp"
|
#include "model/tool/ToolModel.hpp"
|
||||||
#include "tool/Utils.hpp"
|
#include "tool/Utils.hpp"
|
||||||
|
|
||||||
|
|
@ -37,35 +38,43 @@ MagicSearchModel::~MagicSearchModel() {
|
||||||
mustBeInLinphoneThread("~" + getClassName());
|
mustBeInLinphoneThread("~" + getClassName());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicSearchModel::search(QString filter) {
|
void MagicSearchModel::search(QString filter,
|
||||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
int sourceFlags,
|
||||||
|
LinphoneEnums::MagicSearchAggregation aggregation,
|
||||||
|
int maxResults) {
|
||||||
mLastSearch = filter;
|
mLastSearch = filter;
|
||||||
mMonitor->getContactsListAsync(filter != "*" ? Utils::appStringToCoreString(filter) : "", "", mSourceFlags,
|
setMaxResults(maxResults);
|
||||||
LinphoneEnums::toLinphone(mAggregationFlag));
|
if ((filter == "" || filter == "*") && ((sourceFlags & (int)LinphoneEnums::MagicSearchSource::LdapServers) > 0) &&
|
||||||
}
|
!SettingsModel::getInstance()->getSyncLdapContacts()) {
|
||||||
|
sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::LdapServers;
|
||||||
void MagicSearchModel::setSourceFlags(int flags) {
|
|
||||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
|
||||||
if (mSourceFlags != flags) {
|
|
||||||
mSourceFlags = flags;
|
|
||||||
emit sourceFlagsChanged(mSourceFlags);
|
|
||||||
}
|
}
|
||||||
|
qInfo() << log().arg("Searching ") << filter << " from " << sourceFlags << " with limit " << maxResults;
|
||||||
|
mMonitor->getContactsListAsync(filter != "*" ? Utils::appStringToCoreString(filter) : "", "", sourceFlags,
|
||||||
|
LinphoneEnums::toLinphone(aggregation));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicSearchModel::setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag) {
|
int MagicSearchModel::getMaxResults() const {
|
||||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
if (!mMonitor->getLimitedSearch()) return -1;
|
||||||
if (mAggregationFlag != flag) {
|
else return mMonitor->getSearchLimit();
|
||||||
mAggregationFlag = flag;
|
}
|
||||||
emit aggregationFlagChanged(mAggregationFlag);
|
|
||||||
|
void MagicSearchModel::setMaxResults(int maxResults) {
|
||||||
|
if (maxResults <= 0 && mMonitor->getLimitedSearch() ||
|
||||||
|
maxResults > 0 && (!mMonitor->getLimitedSearch() || maxResults != mMonitor->getSearchLimit())) {
|
||||||
|
mMonitor->setLimitedSearch(maxResults > 0);
|
||||||
|
if (maxResults > 0) mMonitor->setSearchLimit(maxResults);
|
||||||
|
emit maxResultsChanged(maxResults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicSearchModel::onSearchResultsReceived(const std::shared_ptr<linphone::MagicSearch> &magicSearch) {
|
void MagicSearchModel::onSearchResultsReceived(const std::shared_ptr<linphone::MagicSearch> &magicSearch) {
|
||||||
for (auto it : magicSearch->getLastSearch()) {
|
qDebug() << log().arg("SDK send callback: onSearchResultsReceived");
|
||||||
|
auto results = magicSearch->getLastSearch();
|
||||||
|
for (auto it : results) {
|
||||||
bool isLdap = (it->getSourceFlags() & (int)LinphoneEnums::MagicSearchSource::LdapServers) != 0;
|
bool isLdap = (it->getSourceFlags() & (int)LinphoneEnums::MagicSearchSource::LdapServers) != 0;
|
||||||
if (isLdap && it->getFriend()) updateLdapFriendListWithFriend(it->getFriend());
|
if (isLdap && it->getFriend()) updateLdapFriendListWithFriend(it->getFriend());
|
||||||
}
|
}
|
||||||
emit searchResultsReceived(magicSearch->getLastSearch());
|
emit searchResultsReceived(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicSearchModel::onLdapHaveMoreResults(const std::shared_ptr<linphone::MagicSearch> &magicSearch,
|
void MagicSearchModel::onLdapHaveMoreResults(const std::shared_ptr<linphone::MagicSearch> &magicSearch,
|
||||||
|
|
|
||||||
|
|
@ -37,17 +37,14 @@ public:
|
||||||
MagicSearchModel(const std::shared_ptr<linphone::MagicSearch> &data, QObject *parent = nullptr);
|
MagicSearchModel(const std::shared_ptr<linphone::MagicSearch> &data, QObject *parent = nullptr);
|
||||||
~MagicSearchModel();
|
~MagicSearchModel();
|
||||||
|
|
||||||
void search(QString filter);
|
void search(QString filter, int sourceFlags, LinphoneEnums::MagicSearchAggregation aggregation, int maxResults);
|
||||||
void setSourceFlags(int flags);
|
|
||||||
void setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag);
|
|
||||||
|
|
||||||
int mSourceFlags = (int)linphone::MagicSearch::Source::All;
|
int getMaxResults() const;
|
||||||
LinphoneEnums::MagicSearchAggregation mAggregationFlag = LinphoneEnums::MagicSearchAggregation::None;
|
void setMaxResults(int maxResults);
|
||||||
QString mLastSearch;
|
QString mLastSearch;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sourceFlagsChanged(int sourceFlags);
|
void maxResultsChanged(int maxResults);
|
||||||
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation aggregationFlag);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_ABSTRACT_OBJECT
|
DECLARE_ABSTRACT_OBJECT
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
||||||
view/Control/Display/Call/CallStatistics.qml
|
view/Control/Display/Call/CallStatistics.qml
|
||||||
view/Control/Display/Contact/Avatar.qml
|
view/Control/Display/Contact/Avatar.qml
|
||||||
view/Control/Display/Contact/Contact.qml
|
view/Control/Display/Contact/Contact.qml
|
||||||
|
view/Control/Display/Contact/ContactListItem.qml
|
||||||
view/Control/Display/Contact/ContactListView.qml
|
view/Control/Display/Contact/ContactListView.qml
|
||||||
view/Control/Display/Contact/Voicemail.qml
|
view/Control/Display/Contact/Voicemail.qml
|
||||||
view/Control/Display/Meeting/MeetingListView.qml
|
view/Control/Display/Meeting/MeetingListView.qml
|
||||||
|
|
|
||||||
264
Linphone/view/Control/Display/Contact/ContactListItem.qml
Normal file
264
Linphone/view/Control/Display/Contact/ContactListItem.qml
Normal file
|
|
@ -0,0 +1,264 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls.Basic as Control
|
||||||
|
|
||||||
|
import Linphone
|
||||||
|
import UtilsCpp 1.0
|
||||||
|
import ConstantsCpp 1.0
|
||||||
|
import SettingsCpp
|
||||||
|
FocusScope {
|
||||||
|
id: mainItem
|
||||||
|
implicitHeight: 56 * DefaultStyle.dp
|
||||||
|
property var searchResultItem
|
||||||
|
property bool showInitials: true // Display Initials of Display name.
|
||||||
|
property bool showDefaultAddress: true // Display address below display name.
|
||||||
|
property bool showActions: false // Display actions layout (call buttons)
|
||||||
|
property bool showContactMenu: true // Display the dot menu for contacts.
|
||||||
|
property string highlightText // Bold characters in Display name.
|
||||||
|
|
||||||
|
property bool displayNameCapitalization: true // Capitalize display name.
|
||||||
|
|
||||||
|
property bool selectionEnabled: true // Contact can be selected
|
||||||
|
property bool multiSelectionEnabled: false //Multiple items can be selected.
|
||||||
|
property list<string> selectedContacts // List of default address on selected contacts.
|
||||||
|
property int selectedContactCount: selectedContacts.length
|
||||||
|
property bool isSelected: false // selected in list => currentIndex == index
|
||||||
|
|
||||||
|
|
||||||
|
property var previousInitial // Use directly previous initial
|
||||||
|
property int itemsRightMargin: 39 * DefaultStyle.dp
|
||||||
|
|
||||||
|
property var displayName: searchResultItem.core.displayName
|
||||||
|
property string initial: displayName ? displayName[0].toLocaleLowerCase(ConstantsCpp.DefaultLocale) : ''
|
||||||
|
|
||||||
|
signal clicked(var mouse)
|
||||||
|
signal contactStarredChanged()
|
||||||
|
signal contactDeletionRequested(FriendGui contact)
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
enabled: searchResultItem.core
|
||||||
|
target: searchResultItem.core
|
||||||
|
function onStarredChanged() { mainItem.contactStarredChanged()}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: initial
|
||||||
|
anchors.left: parent.left
|
||||||
|
visible: mainItem.showInitials
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.rightMargin: 15 * DefaultStyle.dp
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
width: 20 * DefaultStyle.dp
|
||||||
|
opacity: previousInitial != mainItem.initial ? 1 : 0
|
||||||
|
text: mainItem.initial
|
||||||
|
color: DefaultStyle.main2_400
|
||||||
|
font {
|
||||||
|
pixelSize: 20 * DefaultStyle.dp
|
||||||
|
weight: 500 * DefaultStyle.dp
|
||||||
|
capitalization: Font.AllUppercase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
id: contactDelegate
|
||||||
|
anchors.left: initial.visible ? initial.right : parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: mainItem.itemsRightMargin
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 16 * DefaultStyle.dp
|
||||||
|
z: 1
|
||||||
|
Avatar {
|
||||||
|
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
|
Layout.leftMargin: 5 * DefaultStyle.dp
|
||||||
|
contact: searchResultItem
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 0
|
||||||
|
Text {
|
||||||
|
text: UtilsCpp.boldTextPart(mainItem.displayName, mainItem.highlightText)
|
||||||
|
font{
|
||||||
|
pixelSize: mainItem.showDefaultAddress ? 16 * DefaultStyle.dp : 14 * DefaultStyle.dp
|
||||||
|
capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase
|
||||||
|
weight: mainItem.showDefaultAddress ? 800 * DefaultStyle.dp : 400 * DefaultStyle.dp
|
||||||
|
}
|
||||||
|
maximumLineCount: 1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
Layout.topMargin: 2 * DefaultStyle.dp
|
||||||
|
Layout.fillWidth: true
|
||||||
|
visible: mainItem.showDefaultAddress
|
||||||
|
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(searchResultItem.core.defaultAddress) : searchResultItem.core.defaultAddress
|
||||||
|
maximumLineCount: 1
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font {
|
||||||
|
weight: 300 * DefaultStyle.dp
|
||||||
|
pixelSize: 12 * DefaultStyle.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item{Layout.fillWidth: true}
|
||||||
|
RowLayout {
|
||||||
|
id: actionsRow
|
||||||
|
z: 1
|
||||||
|
visible: actionButtons || friendPopup.visible || mainItem.multiSelectionEnabled
|
||||||
|
spacing: visible ? 16 * DefaultStyle.dp : 0
|
||||||
|
EffectImage {
|
||||||
|
id: isSelectedCheck
|
||||||
|
// visible: mainItem.multiSelectionEnabled && (mainItem.confInfoGui.core.getParticipantIndex(searchResultItem.core.defaultAddress) != -1)
|
||||||
|
visible: mainItem.multiSelectionEnabled && (mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress) != -1)
|
||||||
|
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||||
|
imageSource: AppIcons.check
|
||||||
|
colorizationColor: DefaultStyle.main1_500_main
|
||||||
|
Connections {
|
||||||
|
target: mainItem
|
||||||
|
// onParticipantsChanged: isSelectedCheck.visible = mainItem.confInfoGui.core.getParticipantIndex(searchResultItem.core.defaultAddress) != -1
|
||||||
|
function onSelectedContactCountChanged(){
|
||||||
|
isSelectedCheck.visible = (mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress) != -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout{
|
||||||
|
id: actionButtons
|
||||||
|
Layout.rightMargin: 10 * DefaultStyle.dp
|
||||||
|
visible: mainItem.showActions
|
||||||
|
spacing: visible ? 10 * DefaultStyle.dp : 0
|
||||||
|
Button {
|
||||||
|
id: callButton
|
||||||
|
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
|
icon.width: 24 * DefaultStyle.dp
|
||||||
|
icon.height: 24 * DefaultStyle.dp
|
||||||
|
icon.source: AppIcons.phone
|
||||||
|
focus: visible
|
||||||
|
contentImageColor: DefaultStyle.main2_500main
|
||||||
|
background: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 40 * DefaultStyle.dp
|
||||||
|
color: DefaultStyle.main2_200
|
||||||
|
}
|
||||||
|
onClicked: UtilsCpp.createCall(searchResultItem.core.defaultAddress)
|
||||||
|
KeyNavigation.right: chatButton
|
||||||
|
KeyNavigation.left: chatButton
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
id: chatButton
|
||||||
|
visible: actionButtons.visible && !SettingsCpp.disableChatFeature
|
||||||
|
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
|
icon.width: 24 * DefaultStyle.dp
|
||||||
|
icon.height: 24 * DefaultStyle.dp
|
||||||
|
icon.source: AppIcons.chatTeardropText
|
||||||
|
focus: visible && !callButton.visible
|
||||||
|
contentImageColor: DefaultStyle.main2_500main
|
||||||
|
background: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 40 * DefaultStyle.dp
|
||||||
|
color: DefaultStyle.main2_200
|
||||||
|
}
|
||||||
|
KeyNavigation.right: callButton
|
||||||
|
KeyNavigation.left: callButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PopupButton {
|
||||||
|
id: friendPopup
|
||||||
|
z: 1
|
||||||
|
// Layout.rightMargin: 13 * DefaultStyle.dp
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.rightMargin: 8 * DefaultStyle.dp
|
||||||
|
popup.x: 0
|
||||||
|
popup.padding: 10 * DefaultStyle.dp
|
||||||
|
visible: mainItem.showContactMenu && (contactArea.containsMouse || hovered || popup.opened)
|
||||||
|
|
||||||
|
popup.contentItem: ColumnLayout {
|
||||||
|
Button {
|
||||||
|
visible: searchResultItem.core.isStored
|
||||||
|
text: searchResultItem.core.starred ? qsTr("Enlever des favoris") : qsTr("Mettre en favori")
|
||||||
|
icon.source: searchResultItem.core.starred ? AppIcons.heartFill : AppIcons.heart
|
||||||
|
icon.width: 24 * DefaultStyle.dp
|
||||||
|
icon.height: 24 * DefaultStyle.dp
|
||||||
|
spacing: 10 * DefaultStyle.dp
|
||||||
|
textSize: 14 * DefaultStyle.dp
|
||||||
|
textWeight: 400 * DefaultStyle.dp
|
||||||
|
textColor: DefaultStyle.main2_500main
|
||||||
|
contentImageColor: searchResultItem.core.starred ? DefaultStyle.danger_500main : DefaultStyle.main2_600
|
||||||
|
onClicked: {
|
||||||
|
searchResultItem.core.lSetStarred(!searchResultItem.core.starred)
|
||||||
|
friendPopup.close()
|
||||||
|
}
|
||||||
|
background: Item{}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: qsTr("Partager")
|
||||||
|
icon.source: AppIcons.shareNetwork
|
||||||
|
icon.width: 24 * DefaultStyle.dp
|
||||||
|
icon.height: 24 * DefaultStyle.dp
|
||||||
|
spacing: 10 * DefaultStyle.dp
|
||||||
|
textSize: 14 * DefaultStyle.dp
|
||||||
|
textWeight: 400 * DefaultStyle.dp
|
||||||
|
textColor: DefaultStyle.main2_500main
|
||||||
|
onClicked: {
|
||||||
|
var vcard = searchResultItem.core.getVCard()
|
||||||
|
var username = searchResultItem.core.givenName + searchResultItem.core.familyName
|
||||||
|
var filepath = UtilsCpp.createVCardFile(username, vcard)
|
||||||
|
if (filepath == "") UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La création du fichier vcard a échoué"), false)
|
||||||
|
else mainWindow.showInformationPopup(qsTr("VCard créée"), qsTr("VCard du contact enregistrée dans %1").arg(filepath))
|
||||||
|
UtilsCpp.shareByEmail(qsTr("Partage de contact"), vcard, filepath)
|
||||||
|
}
|
||||||
|
background: Item{}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: qsTr("Supprimer")
|
||||||
|
icon.source: AppIcons.trashCan
|
||||||
|
icon.width: 24 * DefaultStyle.dp
|
||||||
|
icon.height: 24 * DefaultStyle.dp
|
||||||
|
spacing: 10 * DefaultStyle.dp
|
||||||
|
textSize: 14 * DefaultStyle.dp
|
||||||
|
textWeight: 400 * DefaultStyle.dp
|
||||||
|
textColor: DefaultStyle.danger_500main
|
||||||
|
contentImageColor: DefaultStyle.danger_500main
|
||||||
|
visible: !searchResultItem.core.readOnly
|
||||||
|
onClicked: {
|
||||||
|
mainItem.contactDeletionRequested(searchResultItem)
|
||||||
|
friendPopup.close()
|
||||||
|
}
|
||||||
|
background: Item{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: contactArea
|
||||||
|
enabled: mainItem.selectionEnabled
|
||||||
|
anchors.fill: contactDelegate
|
||||||
|
//height: mainItem.height
|
||||||
|
hoverEnabled: true
|
||||||
|
acceptedButtons: Qt.AllButtons
|
||||||
|
z: -1
|
||||||
|
focus: !actionButtons.visible
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: contactArea
|
||||||
|
radius: 8 * DefaultStyle.dp
|
||||||
|
opacity: 0.7
|
||||||
|
color: mainItem.isSelected ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
||||||
|
visible: contactArea.containsMouse || friendPopup.hovered || mainItem.isSelected || friendPopup.visible
|
||||||
|
}
|
||||||
|
Keys.onPressed: (event)=> {
|
||||||
|
if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) {
|
||||||
|
contactArea.clicked(undefined)
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
forceActiveFocus()
|
||||||
|
if (mouse && mouse.button == Qt.RightButton && mainItem.showContactMenu) {
|
||||||
|
friendPopup.open()
|
||||||
|
} else {
|
||||||
|
mainItem.clicked(mouse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,52 +7,56 @@ import UtilsCpp 1.0
|
||||||
import ConstantsCpp 1.0
|
import ConstantsCpp 1.0
|
||||||
import SettingsCpp
|
import SettingsCpp
|
||||||
|
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: mainItem
|
id: mainItem
|
||||||
height: contentHeight
|
|
||||||
visible: contentHeight > 0
|
|
||||||
clip: true
|
|
||||||
currentIndex: -1
|
|
||||||
//keyNavigationWraps: true
|
|
||||||
// rightMargin: 5 * DefaultStyle.dp
|
|
||||||
|
|
||||||
property bool selectionEnabled: true
|
property bool showInitials: true // Display Initials of Display name.
|
||||||
property bool hoverEnabled: true
|
property bool showDefaultAddress: true // Display address below display name.
|
||||||
// dots popup menu
|
property bool showActions: false // Display actions layout (call buttons)
|
||||||
property bool contactMenuVisible: true
|
property bool showContactMenu: true // Display the dot menu for contacts.
|
||||||
// call, video call etc menu
|
property bool showFavorites: true // Display the favorites in the header
|
||||||
property bool actionLayoutVisible: false
|
property bool hideSuggestions: false // Hide not stored contacts (not suggestions)
|
||||||
property bool initialHeadersVisible: true
|
property string highlightText // Bold characters in Display name.
|
||||||
property bool displayNameCapitalization: true
|
property var sourceFlags: LinphoneEnums.MagicSearchSource.All
|
||||||
property bool showFavoritesOnly: false
|
|
||||||
property bool showDefaultAddress: false
|
property bool displayNameCapitalization: true // Capitalize display name.
|
||||||
property bool showLdapContacts: false
|
|
||||||
|
property bool selectionEnabled: true // Contact can be selected
|
||||||
|
property bool multiSelectionEnabled: false //Multiple items can be selected.
|
||||||
|
property list<string> selectedContacts // List of default address on selected contacts.
|
||||||
|
property FriendGui selectedContact//: model.getAt(currentIndex) || null
|
||||||
|
|
||||||
property bool searchOnInitialization: false
|
property bool searchOnInitialization: false
|
||||||
|
property bool loading: false
|
||||||
property var listProxy: MagicSearchProxy{}
|
property bool pauseSearch: false // true = don't search on text change
|
||||||
property alias hideListProxy: magicSearchProxy.hideListProxy
|
|
||||||
|
|
||||||
// Model properties
|
// Model properties
|
||||||
// set searchBarText without specifying a model to bold
|
// set searchBarText without specifying a model to bold
|
||||||
// matching names
|
// matching names
|
||||||
property string searchBarText
|
property string searchBarText
|
||||||
property string searchText: searchBarText.length === 0 ? "*" : searchBarText
|
property string searchText// Binding is done on searchBarTextChanged
|
||||||
property var aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
|
|
||||||
property var sourceFlags: LinphoneEnums.MagicSearchSource.Friends | ((searchText.length > 0 && searchText != "*") || SettingsCpp.syncLdapContacts ? LinphoneEnums.MagicSearchSource.LdapServers : 0)
|
|
||||||
|
|
||||||
property ConferenceInfoGui confInfoGui
|
property ConferenceInfoGui confInfoGui
|
||||||
|
|
||||||
property bool multiSelectionEnabled: false
|
property bool haveFavorites: false
|
||||||
property list<string> selectedContacts
|
property int sectionsPixelSize: 16 * DefaultStyle.dp
|
||||||
property int selectedContactCount: selectedContacts.length
|
property int sectionsWeight: 800 * DefaultStyle.dp
|
||||||
|
property int sectionsSpacing: 18 * DefaultStyle.dp
|
||||||
property FriendGui selectedContact: model.getAt(currentIndex) || null
|
|
||||||
|
property int itemsRightMargin: 39 * DefaultStyle.dp
|
||||||
|
|
||||||
|
signal resultsReceived()
|
||||||
signal contactStarredChanged()
|
signal contactStarredChanged()
|
||||||
signal contactDeletionRequested(FriendGui contact)
|
signal contactDeletionRequested(FriendGui contact)
|
||||||
signal contactAddedToSelection(string address)
|
signal contactAddedToSelection(string address)
|
||||||
signal contactRemovedFromSelection(string address)
|
signal contactRemovedFromSelection(string address)
|
||||||
signal contactClicked(FriendGui contact)
|
signal contactClicked(FriendGui contact)
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
highlightFollowsCurrentItem: true
|
||||||
|
cacheBuffer: 400
|
||||||
|
// Binding loop hack
|
||||||
|
onContentHeightChanged: Qt.callLater(function(){cacheBuffer = Math.max(0,contentHeight)})
|
||||||
|
|
||||||
function selectContact(address) {
|
function selectContact(address) {
|
||||||
var index = magicSearchProxy.findFriendIndexByAddress(address)
|
var index = magicSearchProxy.findFriendIndexByAddress(address)
|
||||||
|
|
@ -89,9 +93,75 @@ ListView {
|
||||||
return index != -1
|
return index != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
onCurrentIndexChanged: selectedContact = model.getAt(currentIndex) || null
|
onResultsReceived: {
|
||||||
onCountChanged: selectedContact = model.getAt(currentIndex) || null
|
loading = false
|
||||||
|
mainItem.positionViewAtBeginning()
|
||||||
|
}
|
||||||
|
onSearchBarTextChanged: {
|
||||||
|
loading = true
|
||||||
|
if(!pauseSearch) {
|
||||||
|
searchText = searchBarText.length === 0 ? "*" : searchBarText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onPauseSearchChanged: {
|
||||||
|
if(!pauseSearch){
|
||||||
|
searchText = searchBarText.length === 0 ? "*" : searchBarText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onAtYEndChanged: if(atYEnd) magicSearchProxy.displayMore()
|
||||||
|
keyNavigationEnabled: false
|
||||||
|
Keys.onPressed: (event)=> {
|
||||||
|
if(header.activeFocus) return;
|
||||||
|
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){
|
||||||
|
if (currentIndex == 0 && event.key == Qt.Key_Up) {
|
||||||
|
if( headerItem.list.count > 0) {
|
||||||
|
mainItem.highlightFollowsCurrentItem = false
|
||||||
|
currentIndex = -1
|
||||||
|
headerItem.list.currentIndex = headerItem.list.count -1
|
||||||
|
var item = headerItem.list.itemAtIndex(headerItem.list.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
headerItem.updatePosition()
|
||||||
|
event.accepted = true;
|
||||||
|
}else{
|
||||||
|
mainItem.currentIndex = mainItem.count - 1
|
||||||
|
var item = itemAtIndex(mainItem.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}else if(currentIndex >= mainItem.count -1 && event.key == Qt.Key_Down){
|
||||||
|
if( headerItem.list.count > 0) {
|
||||||
|
mainItem.highlightFollowsCurrentItem = false
|
||||||
|
mainItem.currentIndex = -1
|
||||||
|
headerItem.list.currentIndex = 0
|
||||||
|
var item = headerItem.list.itemAtIndex(headerItem.list.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
headerItem.updatePosition()
|
||||||
|
event.accepted = true;
|
||||||
|
}else{
|
||||||
|
mainItem.currentIndex = 0
|
||||||
|
var item = itemAtIndex(mainItem.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}else if(event.key == Qt.Key_Up){
|
||||||
|
mainItem.highlightFollowsCurrentItem = true
|
||||||
|
var item = itemAtIndex(--mainItem.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
event.accepted = true;
|
||||||
|
}else if(event.key == Qt.Key_Down){
|
||||||
|
mainItem.highlightFollowsCurrentItem = true
|
||||||
|
var item = itemAtIndex(++mainItem.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (confInfoGui) {
|
if (confInfoGui) {
|
||||||
for(var i = 0; i < confInfoGui.core.participants.length; ++i) {
|
for(var i = 0; i < confInfoGui.core.participants.length; ++i) {
|
||||||
|
|
@ -99,33 +169,7 @@ ListView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// strange behaviour with this lines
|
|
||||||
// When a popup opens after clicking on a contact, the selected contact
|
|
||||||
// changes because we lose focus on the list
|
|
||||||
// onActiveFocusChanged: if(activeFocus && (!footerItem || !footerItem.activeFocus)) {
|
|
||||||
// currentIndex = 0
|
|
||||||
// }
|
|
||||||
|
|
||||||
model: MagicSearchProxy {
|
|
||||||
id: magicSearchProxy
|
|
||||||
searchText: mainItem.searchText
|
|
||||||
// This property is needed instead of playing on the delegate visibility
|
|
||||||
// considering its starred status. Otherwise, the row in the list still
|
|
||||||
// exists even if its delegate is not visible, and creates navigation issues
|
|
||||||
showFavoritesOnly: mainItem.showFavoritesOnly
|
|
||||||
aggregationFlag: mainItem.aggregationFlag
|
|
||||||
parentProxy: mainItem.listProxy
|
|
||||||
showLdapContacts: mainItem.showLdapContacts
|
|
||||||
sourceFlags: mainItem.sourceFlags
|
|
||||||
onFriendCreated: (index) => {
|
|
||||||
mainItem.currentIndex = index
|
|
||||||
}
|
|
||||||
onInitialized: {
|
|
||||||
if(mainItem.searchOnInitialization) magicSearchProxy.forceUpdate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SettingsCpp
|
target: SettingsCpp
|
||||||
onLdapConfigChanged: {
|
onLdapConfigChanged: {
|
||||||
|
|
@ -136,255 +180,302 @@ ListView {
|
||||||
|
|
||||||
Control.ScrollBar.vertical: ScrollBar {
|
Control.ScrollBar.vertical: ScrollBar {
|
||||||
id: scrollbar
|
id: scrollbar
|
||||||
|
rightPadding: 8 * DefaultStyle.dp
|
||||||
|
topPadding: mainItem.haveFavorites ? 24 * DefaultStyle.dp : 0 // Avoid to be on top of collapse button
|
||||||
|
|
||||||
active: true
|
active: true
|
||||||
interactive: true
|
interactive: true
|
||||||
// anchors.top: parent.top
|
policy: mainItem.contentHeight > mainItem.height ? Control.ScrollBar.AlwaysOn : Control.ScrollBar.AlwaysOff
|
||||||
// anchors.bottom: parent.bottom
|
|
||||||
// anchors.right: parent.right
|
|
||||||
}
|
}
|
||||||
Keys.onPressed: (event)=>{
|
|
||||||
if(event.key == Qt.Key_Tab && !mainItem.itemAtIndex(mainItem.currentIndex).activeFocus){
|
model: MagicSearchProxy {
|
||||||
mainItem.itemAtIndex(mainItem.currentIndex).forceActiveFocus()
|
id: magicSearchProxy
|
||||||
|
searchText: mainItem.searchText
|
||||||
|
aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
|
||||||
|
sourceFlags: mainItem.sourceFlags
|
||||||
|
|
||||||
|
hideSuggestions: mainItem.hideSuggestions
|
||||||
|
initialDisplayItems: 20
|
||||||
|
onLocalFriendCreated: (index) => {
|
||||||
|
var item = itemAtIndex(index)
|
||||||
|
if(item){
|
||||||
|
mainItem.currentIndex = index
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
onInitialized: {
|
||||||
|
mainItem.loading = true
|
||||||
|
magicSearchProxy.forceUpdate()
|
||||||
|
}
|
||||||
|
onModelReset: mainItem.resultsReceived()
|
||||||
}
|
}
|
||||||
delegate: FocusScope {
|
|
||||||
id: itemDelegate
|
section.property: "isStored"
|
||||||
height: 56 * DefaultStyle.dp
|
//section.criteria: ViewSection.FirstCharacter
|
||||||
width: mainItem.width
|
section.delegate: Item{
|
||||||
property var previousItem : mainItem.model.count > 0 && index > 0 ? mainItem.model.getAt(index-1) : null
|
width: mainItem.width
|
||||||
property var previousDisplayName: previousItem ? previousItem.core.displayName : ""
|
height: textItem.implicitHeight + sectionsSpacing * 2
|
||||||
property var displayName: modelData.core.displayName
|
required property bool section
|
||||||
|
Text {
|
||||||
Connections {
|
id: textItem
|
||||||
enabled: modelData.core
|
anchors.fill: parent
|
||||||
target: modelData.core
|
text: section ? qsTr("Contacts") : qsTr("Suggestions")
|
||||||
function onStarredChanged() { mainItem.contactStarredChanged()}
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
font {
|
||||||
|
pixelSize: sectionsPixelSize
|
||||||
|
weight: sectionsWeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Text {
|
header: FocusScope{
|
||||||
id: initial
|
id: headerItem
|
||||||
anchors.left: parent.left
|
width: mainItem.width
|
||||||
visible: mainItem.initialHeadersVisible && mainItem.model.sourceFlags != LinphoneEnums.MagicSearchSource.All
|
height: favoritesContents.implicitHeight
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
property alias list: favoriteList
|
||||||
anchors.rightMargin: 15 * DefaultStyle.dp
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
// Hack because changing currentindex change focus.
|
||||||
width: 20 * DefaultStyle.dp
|
Timer{
|
||||||
opacity: (!previousItem || !previousDisplayName.toLocaleLowerCase(ConstantsCpp.DefaultLocale).startsWith(displayName[0].toLocaleLowerCase(ConstantsCpp.DefaultLocale))) ? 1 : 0
|
id: focusDelay
|
||||||
text: displayName[0]
|
interval: 10
|
||||||
color: DefaultStyle.main2_400
|
onTriggered: {
|
||||||
font {
|
mainItem.highlightFollowsCurrentItem = !headerItem.activeFocus
|
||||||
pixelSize: 20 * DefaultStyle.dp
|
|
||||||
weight: 500 * DefaultStyle.dp
|
|
||||||
capitalization: Font.AllUppercase
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RowLayout {
|
|
||||||
id: contactDelegate
|
|
||||||
anchors.left: initial.visible ? initial.right : parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
spacing: 16 * DefaultStyle.dp
|
|
||||||
z: 1
|
|
||||||
Avatar {
|
|
||||||
Layout.leftMargin: 5 * DefaultStyle.dp
|
|
||||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
|
||||||
contact: modelData
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
|
||||||
spacing: 0
|
|
||||||
Text {
|
|
||||||
text: UtilsCpp.boldTextPart(itemDelegate.displayName, mainItem.searchBarText)
|
|
||||||
font{
|
|
||||||
pixelSize: mainItem.showDefaultAddress ? 16 * DefaultStyle.dp : 14 * DefaultStyle.dp
|
|
||||||
capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase
|
|
||||||
weight: mainItem.showDefaultAddress ? 800 * DefaultStyle.dp : 400 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
maximumLineCount: 1
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
maximumLineCount: 1
|
|
||||||
visible: mainItem.showDefaultAddress
|
|
||||||
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(modelData.core.defaultAddress) : modelData.core.defaultAddress
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 2 * DefaultStyle.dp
|
|
||||||
font {
|
|
||||||
weight: 300 * DefaultStyle.dp
|
|
||||||
pixelSize: 12 * DefaultStyle.dp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
onActiveFocusChanged:focusDelay.restart()
|
||||||
Item{Layout.fillWidth: true}
|
//---------------------------------------------------
|
||||||
RowLayout {
|
|
||||||
id: actionsRow
|
function updatePosition(){
|
||||||
z: 1
|
var item = favoriteList.itemAtIndex(favoriteList.currentIndex)
|
||||||
visible: actionButtons || friendPopup.visible || mainItem.multiSelectionEnabled
|
if( item){
|
||||||
spacing: visible ? 16 * DefaultStyle.dp : 0
|
// For debugging just in case
|
||||||
EffectImage {
|
//var listPosition = item.mapToItem(favoriteList, item.x, item.y)
|
||||||
id: isSelectedCheck
|
//var newPosition = favoriteList.mapToItem(mainItem, listPosition.x, listPosition.y)
|
||||||
// visible: mainItem.multiSelectionEnabled && (mainItem.confInfoGui.core.getParticipantIndex(modelData.core.defaultAddress) != -1)
|
//console.log("item pos: " +item.x + " / " +item.y)
|
||||||
visible: mainItem.multiSelectionEnabled && (mainItem.selectedContacts.indexOf(modelData.core.defaultAddress) != -1)
|
//console.log("fav pos: " +favoriteList.x + " / " +favoriteList.y)
|
||||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
//console.log("fav content: " +favoriteList.contentX + " / " +favoriteList.contentY)
|
||||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
//console.log("main pos: " +mainItem.x + " / " +mainItem.y)
|
||||||
imageSource: AppIcons.check
|
//console.log("main content: " +mainItem.contentX + " / " +mainItem.contentY)
|
||||||
colorizationColor: DefaultStyle.main1_500_main
|
//console.log("list pos: " +listPosition.x + " / " +listPosition.y)
|
||||||
Connections {
|
//console.log("new pos: " +newPosition.x + " / " +newPosition.y)
|
||||||
target: mainItem
|
//console.log("header pos: " +headerItem.x + " / " +headerItem.y)
|
||||||
// onParticipantsChanged: isSelectedCheck.visible = mainItem.confInfoGui.core.getParticipantIndex(modelData.core.defaultAddress) != -1
|
//console.log("Moving to " + (headerItem.y+item.y))
|
||||||
function onSelectedContactCountChanged(){ isSelectedCheck.visible = (mainItem.selectedContacts.indexOf(modelData.core.defaultAddress) != -1)}
|
mainItem.contentY = headerItem.y+item.y
|
||||||
}
|
}
|
||||||
}
|
|
||||||
RowLayout{
|
|
||||||
id: actionButtons
|
|
||||||
visible: mainItem.actionLayoutVisible
|
|
||||||
spacing: visible ? 10 * DefaultStyle.dp : 0
|
|
||||||
Button {
|
|
||||||
id: callButton
|
|
||||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
|
||||||
icon.width: 24 * DefaultStyle.dp
|
|
||||||
icon.height: 24 * DefaultStyle.dp
|
|
||||||
icon.source: AppIcons.phone
|
|
||||||
contentImageColor: DefaultStyle.main2_600
|
|
||||||
focus: visible
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: 40 * DefaultStyle.dp
|
|
||||||
color: DefaultStyle.main2_200
|
|
||||||
}
|
|
||||||
onClicked: UtilsCpp.createCall(modelData.core.defaultAddress)
|
|
||||||
KeyNavigation.right: chatButton
|
|
||||||
KeyNavigation.left: chatButton
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
id: chatButton
|
|
||||||
visible: actionButtons.visible && !SettingsCpp.disableChatFeature
|
|
||||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
|
||||||
icon.width: 24 * DefaultStyle.dp
|
|
||||||
icon.height: 24 * DefaultStyle.dp
|
|
||||||
icon.source: AppIcons.chatTeardropText
|
|
||||||
focus: visible && !callButton.visible
|
|
||||||
contentImageColor: DefaultStyle.main2_500main
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: 40 * DefaultStyle.dp
|
|
||||||
color: DefaultStyle.main2_200
|
|
||||||
}
|
|
||||||
KeyNavigation.right: callButton
|
|
||||||
KeyNavigation.left: callButton
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PopupButton {
|
|
||||||
id: friendPopup
|
|
||||||
z: 1
|
|
||||||
// Layout.rightMargin: 13 * DefaultStyle.dp
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
Layout.rightMargin: 8 * DefaultStyle.dp
|
|
||||||
popup.x: 0
|
|
||||||
popup.padding: 10 * DefaultStyle.dp
|
|
||||||
hoverEnabled: mainItem.hoverEnabled
|
|
||||||
visible: mainItem.contactMenuVisible && (contactArea.containsMouse || hovered || popup.opened) && (!mainItem.delegateButtons || mainItem.delegateButtons.length === 0)
|
|
||||||
|
|
||||||
popup.contentItem: ColumnLayout {
|
}
|
||||||
Button {
|
|
||||||
text: $modelData.core.starred ? qsTr("Enlever des favoris") : qsTr("Mettre en favori")
|
ColumnLayout {
|
||||||
background: Item{}
|
id: favoritesContents
|
||||||
icon.source: modelData.core.starred ? AppIcons.heartFill : AppIcons.heart
|
width: parent.width
|
||||||
icon.width: 24 * DefaultStyle.dp
|
spacing: mainItem.haveFavorites ? sectionsSpacing : 0
|
||||||
icon.height: 24 * DefaultStyle.dp
|
BusyIndicator {
|
||||||
spacing: 10 * DefaultStyle.dp
|
Layout.alignment: Qt.AlignCenter
|
||||||
textSize: 14 * DefaultStyle.dp
|
Layout.preferredHeight: visible ? 60 * DefaultStyle.dp : 0
|
||||||
textWeight: 400 * DefaultStyle.dp
|
Layout.preferredWidth: 60 * DefaultStyle.dp
|
||||||
textColor: DefaultStyle.main2_500main
|
indicatorHeight: 60 * DefaultStyle.dp
|
||||||
contentImageColor: modelData.core.starred ? DefaultStyle.danger_500main : DefaultStyle.main2_600
|
indicatorWidth: 60 * DefaultStyle.dp
|
||||||
onClicked: {
|
visible: mainItem.loading
|
||||||
modelData.core.lSetStarred(!modelData.core.starred)
|
indicatorColor: DefaultStyle.main1_500_main
|
||||||
friendPopup.close()
|
|
||||||
|
}
|
||||||
|
Item{// Do not use directly RowLayout : there is an issue where the layout doesn't update on visible
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: mainItem.haveFavorites ? favoriteTitle.implicitHeight : 0
|
||||||
|
RowLayout {
|
||||||
|
id: favoriteTitle
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
// Need this because it can stay at 0 on display without manual relayouting (moving position, resize)
|
||||||
|
visible: mainItem.haveFavorites
|
||||||
|
onVisibleChanged: if(visible) {
|
||||||
|
Qt.callLater(mainItem.positionViewAtBeginning)// If not later, the view will not move to favoris at startup
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
//Layout.fillHeight: true
|
||||||
|
text: qsTr("Favoris")
|
||||||
|
font {
|
||||||
|
pixelSize: sectionsPixelSize
|
||||||
|
weight: sectionsWeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
id: favoriteExpandButton
|
||||||
|
background: Item{}
|
||||||
|
icon.source: favoriteList.visible ? AppIcons.upArrow : AppIcons.downArrow
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: height
|
||||||
|
//Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||||
|
//Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||||
|
Layout.rightMargin: 23 * DefaultStyle.dp
|
||||||
|
icon.width: 24 * DefaultStyle.dp
|
||||||
|
icon.height: 24 * DefaultStyle.dp
|
||||||
|
focus: true
|
||||||
|
onClicked: favoriteList.visible = !favoriteList.visible
|
||||||
|
KeyNavigation.down: favoriteList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Button {
|
}
|
||||||
text: qsTr("Partager")
|
ListView{
|
||||||
background: Item{}
|
id: favoriteList
|
||||||
icon.source: AppIcons.shareNetwork
|
Layout.fillWidth: true
|
||||||
icon.width: 24 * DefaultStyle.dp
|
Layout.preferredHeight: count > 0 ? contentHeight : 0// Show full and avoid scrolling
|
||||||
icon.height: 24 * DefaultStyle.dp
|
|
||||||
spacing: 10 * DefaultStyle.dp
|
|
||||||
textSize: 14 * DefaultStyle.dp
|
|
||||||
textWeight: 400 * DefaultStyle.dp
|
onCountChanged: mainItem.haveFavorites = count > 0
|
||||||
textColor: DefaultStyle.main2_500main
|
Keys.onPressed: (event)=> {
|
||||||
onClicked: {
|
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down) {
|
||||||
var vcard = modelData.core.getVCard()
|
if (favoriteList.currentIndex == 0 && event.key == Qt.Key_Up) {
|
||||||
var username = modelData.core.givenName + modelData.core.familyName
|
if( mainItem.count > 0) {
|
||||||
var filepath = UtilsCpp.createVCardFile(username, vcard)
|
mainItem.highlightFollowsCurrentItem = true
|
||||||
if (filepath == "") UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La création du fichier vcard a échoué"), false)
|
favoriteList.currentIndex = -1
|
||||||
else mainWindow.showInformationPopup(qsTr("VCard créée"), qsTr("VCard du contact enregistrée dans %1").arg(filepath))
|
mainItem.currentIndex = mainItem.count-1
|
||||||
UtilsCpp.shareByEmail(qsTr("Partage de contact"), vcard, filepath)
|
var item = mainItem.itemAtIndex(mainItem.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
event.accepted = true;
|
||||||
|
}else{
|
||||||
|
favoriteList.currentIndex = favoriteList.count - 1
|
||||||
|
var item = itemAtIndex(favoriteList.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}else if(currentIndex >= favoriteList.count -1 && event.key == Qt.Key_Down) {
|
||||||
|
if( mainItem.count > 0) {
|
||||||
|
mainItem.highlightFollowsCurrentItem = true
|
||||||
|
favoriteList.currentIndex = -1
|
||||||
|
mainItem.currentIndex = 0
|
||||||
|
var item = mainItem.itemAtIndex(mainItem.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
event.accepted = true;
|
||||||
|
}else{
|
||||||
|
favoriteList.currentIndex = 0
|
||||||
|
var item = itemAtIndex(favoriteList.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}else if(event.key == Qt.Key_Up){
|
||||||
|
mainItem.highlightFollowsCurrentItem = false
|
||||||
|
var item = itemAtIndex(--favoriteList.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
headerItem.updatePosition()
|
||||||
|
event.accepted = true;
|
||||||
|
}else if(event.key == Qt.Key_Down){
|
||||||
|
mainItem.highlightFollowsCurrentItem = false
|
||||||
|
var item = itemAtIndex(++favoriteList.currentIndex)
|
||||||
|
mainItem.selectedContact = item.searchResultItem
|
||||||
|
item.forceActiveFocus()
|
||||||
|
headerItem.updatePosition()
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Button {
|
property MagicSearchProxy proxy: MagicSearchProxy{
|
||||||
text: qsTr("Supprimer")
|
parentProxy: mainItem.model
|
||||||
background: Item{}
|
showFavoritesOnly: true
|
||||||
icon.source: AppIcons.trashCan
|
hideSuggestions: mainItem.hideSuggestions
|
||||||
icon.width: 24 * DefaultStyle.dp
|
}
|
||||||
icon.height: 24 * DefaultStyle.dp
|
model : showFavorites && mainItem.searchBarText == '' ? proxy : []
|
||||||
spacing: 10 * DefaultStyle.dp
|
delegate: ContactListItem{
|
||||||
textSize: 14 * DefaultStyle.dp
|
width: favoriteList.width
|
||||||
textWeight: 400 * DefaultStyle.dp
|
focus: true
|
||||||
textColor: DefaultStyle.danger_500main
|
|
||||||
contentImageColor: DefaultStyle.danger_500main
|
searchResultItem: $modelData
|
||||||
visible: !modelData.core.readOnly
|
showInitials: mainItem.showInitials
|
||||||
onClicked: {
|
showDefaultAddress: mainItem.showDefaultAddress
|
||||||
mainItem.contactDeletionRequested(modelData)
|
showActions: mainItem.showActions
|
||||||
friendPopup.close()
|
showContactMenu: mainItem.showContactMenu
|
||||||
|
highlightText: mainItem.highlightText
|
||||||
|
|
||||||
|
displayNameCapitalization: mainItem.displayNameCapitalization
|
||||||
|
itemsRightMargin: mainItem.itemsRightMargin
|
||||||
|
selectionEnabled: mainItem.selectionEnabled
|
||||||
|
multiSelectionEnabled: mainItem.multiSelectionEnabled
|
||||||
|
selectedContacts: mainItem.selectedContacts
|
||||||
|
isSelected: mainItem.selectedContact && mainItem.selectedContact.core == searchResultItem.core
|
||||||
|
previousInitial: ''//favoriteList.count > 0 ? favoriteList.itemAtIndex(index-1)?.initial : '' // Binding on count
|
||||||
|
initial: '' // Hide initials but keep space
|
||||||
|
|
||||||
|
onIsSelectedChanged: if(isSelected) favoriteList.currentIndex = index
|
||||||
|
onContactStarredChanged: mainItem.contactStarredChanged()
|
||||||
|
onContactDeletionRequested: (contact) => mainItem.contactDeletionRequested(contact)
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
mainItem.highlightFollowsCurrentItem = false
|
||||||
|
favoriteList.currentIndex = index
|
||||||
|
mainItem.selectedContact = searchResultItem
|
||||||
|
forceActiveFocus()
|
||||||
|
headerItem.updatePosition()
|
||||||
|
if (mainItem.multiSelectionEnabled) {
|
||||||
|
var indexInSelection = mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress)
|
||||||
|
if (indexInSelection == -1) {
|
||||||
|
mainItem.addContactToSelection(searchResultItem.core.defaultAddress)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mainItem.removeContactFromSelection(indexInSelection, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mainItem.contactClicked(searchResultItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
delegate: ContactListItem{
|
||||||
|
id: contactItem
|
||||||
|
width: mainItem.width
|
||||||
|
focus: true
|
||||||
|
|
||||||
MouseArea {
|
searchResultItem: $modelData
|
||||||
id: contactArea
|
showInitials: mainItem.showInitials && searchResultItem.core.isStored
|
||||||
enabled: mainItem.selectionEnabled
|
showDefaultAddress: mainItem.showDefaultAddress
|
||||||
hoverEnabled: mainItem.hoverEnabled
|
showActions: mainItem.showActions
|
||||||
anchors.fill: contactDelegate
|
showContactMenu: searchResultItem.core.isStored
|
||||||
height: mainItem.height
|
highlightText: mainItem.highlightText
|
||||||
acceptedButtons: Qt.AllButtons
|
|
||||||
z: -1
|
displayNameCapitalization: mainItem.displayNameCapitalization
|
||||||
focus: !actionButtons.visible
|
itemsRightMargin: mainItem.itemsRightMargin
|
||||||
Rectangle {
|
|
||||||
anchors.fill: contactArea
|
selectionEnabled: mainItem.selectionEnabled
|
||||||
opacity: 0.7
|
multiSelectionEnabled: mainItem.multiSelectionEnabled
|
||||||
radius: 8 * DefaultStyle.dp
|
selectedContacts: mainItem.selectedContacts
|
||||||
color: mainItem.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
isSelected: mainItem.selectedContact && mainItem.selectedContact.core == searchResultItem.core
|
||||||
visible: contactArea.containsMouse || friendPopup.hovered || mainItem.currentIndex === index
|
previousInitial: mainItem.itemAtIndex(index-1)?.initial
|
||||||
}
|
|
||||||
Keys.onPressed: (event)=> {
|
onIsSelectedChanged: if(isSelected) mainItem.currentIndex = index
|
||||||
if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) {
|
onContactStarredChanged: mainItem.contactStarredChanged()
|
||||||
contactArea.clicked(undefined)
|
onContactDeletionRequested: (contact) => mainItem.contactDeletionRequested(contact)
|
||||||
event.accepted = true;
|
onClicked: (mouse) => {
|
||||||
}
|
mainItem.highlightFollowsCurrentItem = true
|
||||||
}
|
if (mouse && mouse.button == Qt.RightButton) {
|
||||||
onClicked: (mouse) => {
|
friendPopup.open()
|
||||||
if (mouse && mouse.button == Qt.RightButton) {
|
} else {
|
||||||
friendPopup.open()
|
forceActiveFocus()
|
||||||
} else {
|
if(mainItem.selectedContact && mainItem.selectedContact.core != contactItem.searchResultItem.core)
|
||||||
mainItem.forceActiveFocus()
|
headerItem.list.currentIndex = -1
|
||||||
mainItem.currentIndex = index
|
mainItem.selectedContact = contactItem.searchResultItem
|
||||||
if (mainItem.multiSelectionEnabled) {
|
if (mainItem.multiSelectionEnabled) {
|
||||||
var indexInSelection = mainItem.selectedContacts.indexOf(modelData.core.defaultAddress)
|
var indexInSelection = mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress)
|
||||||
if (indexInSelection == -1) {
|
if (indexInSelection == -1) {
|
||||||
mainItem.addContactToSelection(modelData.core.defaultAddress)
|
mainItem.addContactToSelection(searchResultItem.core.defaultAddress)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mainItem.removeContactFromSelection(indexInSelection, 1)
|
mainItem.removeContactFromSelection(indexInSelection, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mainItem.contactClicked(modelData)
|
mainItem.contactClicked(searchResultItem)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,14 @@ FocusScope {
|
||||||
property int textInputWidth: 350 * DefaultStyle.dp
|
property int textInputWidth: 350 * DefaultStyle.dp
|
||||||
property color borderColor: "transparent"
|
property color borderColor: "transparent"
|
||||||
property color focusedBorderColor: DefaultStyle.main2_500main
|
property color focusedBorderColor: DefaultStyle.main2_500main
|
||||||
property string text: textField.text
|
property string text: textField.searchText
|
||||||
property bool magnifierVisible: true
|
property bool magnifierVisible: true
|
||||||
property var validator: RegularExpressionValidator{}
|
property var validator: RegularExpressionValidator{}
|
||||||
property Control.Popup numericPadPopup
|
property Control.Popup numericPadPopup
|
||||||
property alias numericPadButton: dialerButton
|
property alias numericPadButton: dialerButton
|
||||||
readonly property bool hasActiveFocus: textField.activeFocus
|
readonly property bool hasActiveFocus: textField.activeFocus
|
||||||
property alias color: backgroundItem.color
|
property alias color: backgroundItem.color
|
||||||
|
property bool delaySearch: true // Wait some idle time after typing to start searching
|
||||||
|
|
||||||
signal openNumericPadRequested()// Useful for redirection before displaying numeric pad.
|
signal openNumericPadRequested()// Useful for redirection before displaying numeric pad.
|
||||||
|
|
||||||
|
|
@ -62,6 +63,9 @@ FocusScope {
|
||||||
anchors.leftMargin: magnifier.visible ? 0 : 10 * DefaultStyle.dp
|
anchors.leftMargin: magnifier.visible ? 0 : 10 * DefaultStyle.dp
|
||||||
anchors.right: clearTextButton.left
|
anchors.right: clearTextButton.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
property string searchText
|
||||||
|
|
||||||
focus: true
|
focus: true
|
||||||
placeholderText: mainItem.placeholderText
|
placeholderText: mainItem.placeholderText
|
||||||
placeholderTextColor: mainItem.placeholderTextColor
|
placeholderTextColor: mainItem.placeholderTextColor
|
||||||
|
|
@ -75,6 +79,7 @@ FocusScope {
|
||||||
color: DefaultStyle.main2_600
|
color: DefaultStyle.main2_600
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
validator: mainItem.validator
|
validator: mainItem.validator
|
||||||
|
onTextChanged: mainItem.delaySearch ? delayTimer.restart() : searchText = text
|
||||||
background: Item {
|
background: Item {
|
||||||
opacity: 0.
|
opacity: 0.
|
||||||
}
|
}
|
||||||
|
|
@ -83,6 +88,12 @@ FocusScope {
|
||||||
color: DefaultStyle.main2_500main
|
color: DefaultStyle.main2_500main
|
||||||
width: 1 * DefaultStyle.dp
|
width: 1 * DefaultStyle.dp
|
||||||
}
|
}
|
||||||
|
Timer{
|
||||||
|
id: delayTimer
|
||||||
|
interval: 300
|
||||||
|
repeat: false
|
||||||
|
onTriggered: textField.searchText = textField.text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
id: dialerButton
|
id: dialerButton
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ FocusScope {
|
||||||
signal transferCallToAnotherRequested(CallGui dest)
|
signal transferCallToAnotherRequested(CallGui dest)
|
||||||
signal contactClicked(FriendGui contact)
|
signal contactClicked(FriendGui contact)
|
||||||
clip: true
|
clip: true
|
||||||
onVisibleChanged: if (numPadPopup.opened) numPadPopup.close()
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -71,7 +70,7 @@ FocusScope {
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 39 * DefaultStyle.dp
|
Layout.rightMargin: 39 * DefaultStyle.dp
|
||||||
Layout.maximumWidth: mainItem.width
|
//Layout.maximumWidth: mainItem.width
|
||||||
focus: true
|
focus: true
|
||||||
color: mainItem.searchBarColor
|
color: mainItem.searchBarColor
|
||||||
borderColor: mainItem.searchBarBorderColor
|
borderColor: mainItem.searchBarBorderColor
|
||||||
|
|
@ -79,127 +78,72 @@ FocusScope {
|
||||||
numericPadPopup: mainItem.numPadPopup
|
numericPadPopup: mainItem.numPadPopup
|
||||||
KeyNavigation.down: grouCallButton
|
KeyNavigation.down: grouCallButton
|
||||||
}
|
}
|
||||||
Flickable {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
id: content
|
||||||
Layout.fillHeight: true
|
spacing: 32 * DefaultStyle.dp
|
||||||
Layout.topMargin: 25 * DefaultStyle.dp
|
Button {
|
||||||
contentWidth: width
|
id: grouCallButton
|
||||||
contentHeight: content.height
|
visible: mainItem.groupCallVisible && !SettingsCpp.disableMeetingsFeature
|
||||||
clip: true
|
Layout.preferredWidth: 320 * DefaultStyle.dp
|
||||||
Control.ScrollBar.vertical: ScrollBar {
|
Layout.preferredHeight: 44 * DefaultStyle.dp
|
||||||
active: true
|
padding: 0
|
||||||
interactive: true
|
KeyNavigation.up: searchBar
|
||||||
policy: Control.ScrollBar.AsNeeded
|
KeyNavigation.down: contactLoader.item
|
||||||
anchors.top: parent.top
|
onClicked: mainItem.groupCallCreationRequested()
|
||||||
anchors.bottom: parent.bottom
|
background: Rectangle {
|
||||||
anchors.right: parent.right
|
anchors.fill: parent
|
||||||
anchors.rightMargin: 8 * DefaultStyle.dp
|
radius: 50 * DefaultStyle.dp
|
||||||
|
gradient: Gradient {
|
||||||
|
orientation: Gradient.Horizontal
|
||||||
|
GradientStop { position: 0.0; color: DefaultStyle.main2_100}
|
||||||
|
GradientStop { position: 1.0; color: DefaultStyle.grey_0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contentItem: RowLayout {
|
||||||
|
spacing: 16 * DefaultStyle.dp
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
Image {
|
||||||
|
source: AppIcons.groupCall
|
||||||
|
Layout.preferredWidth: 44 * DefaultStyle.dp
|
||||||
|
sourceSize.width: 44 * DefaultStyle.dp
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: "Appel de groupe"
|
||||||
|
color: DefaultStyle.grey_1000
|
||||||
|
font {
|
||||||
|
pixelSize: 16 * DefaultStyle.dp
|
||||||
|
weight: 800 * DefaultStyle.dp
|
||||||
|
underline: grouCallButton.shadowEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
source: AppIcons.rightArrow
|
||||||
|
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loader{
|
||||||
ColumnLayout {
|
// This is a hack for an incomprehensible behavior on sections title where they doesn't match with their delegate and can be unordered after resetting models.
|
||||||
id: content
|
id: contactLoader
|
||||||
spacing: 32 * DefaultStyle.dp
|
Layout.fillWidth: true
|
||||||
anchors.left: parent.left
|
Layout.fillHeight: true
|
||||||
anchors.right: parent.right
|
property string t: searchBar.text
|
||||||
anchors.rightMargin: 39 * DefaultStyle.dp
|
onTChanged: {
|
||||||
Button {
|
contactLoader.active = false
|
||||||
id: grouCallButton
|
Qt.callLater(function(){contactLoader.active=true})
|
||||||
visible: mainItem.groupCallVisible && !SettingsCpp.disableMeetingsFeature
|
|
||||||
Layout.preferredWidth: 320 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 44 * DefaultStyle.dp
|
|
||||||
padding: 0
|
|
||||||
KeyNavigation.up: searchBar
|
|
||||||
KeyNavigation.down: contactList.count >0 ? contactList : searchList
|
|
||||||
onClicked: mainItem.groupCallCreationRequested()
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: 50 * DefaultStyle.dp
|
|
||||||
gradient: Gradient {
|
|
||||||
orientation: Gradient.Horizontal
|
|
||||||
GradientStop { position: 0.0; color: DefaultStyle.main2_100}
|
|
||||||
GradientStop { position: 1.0; color: DefaultStyle.grey_0}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contentItem: RowLayout {
|
|
||||||
spacing: 16 * DefaultStyle.dp
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
Image {
|
|
||||||
source: AppIcons.groupCall
|
|
||||||
Layout.preferredWidth: 44 * DefaultStyle.dp
|
|
||||||
sourceSize.width: 44 * DefaultStyle.dp
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
text: "Appel de groupe"
|
|
||||||
color: DefaultStyle.grey_1000
|
|
||||||
font {
|
|
||||||
pixelSize: 16 * DefaultStyle.dp
|
|
||||||
weight: 800 * DefaultStyle.dp
|
|
||||||
underline: grouCallButton.shadowEnabled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
Image {
|
|
||||||
source: AppIcons.rightArrow
|
|
||||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ColumnLayout {
|
//-------------------------------------------------------------
|
||||||
spacing: 18 * DefaultStyle.dp
|
sourceComponent: ContactListView{
|
||||||
visible: contactList.contentHeight > 0
|
id: contactList
|
||||||
Text {
|
searchBarText: searchBar.text
|
||||||
text: qsTr("Contacts")
|
onContactClicked: (contact) => {
|
||||||
font {
|
mainItem.contactClicked(contact)
|
||||||
pixelSize: 16 * DefaultStyle.dp
|
|
||||||
weight: 800 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ContactListView{
|
|
||||||
id: contactList
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: contentHeight
|
|
||||||
Control.ScrollBar.vertical.visible: false
|
|
||||||
contactMenuVisible: false
|
|
||||||
searchOnInitialization: true
|
|
||||||
searchBarText: searchBar.text
|
|
||||||
onContactClicked: (contact) => {
|
|
||||||
mainItem.contactClicked(contact)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
|
||||||
spacing: 18 * DefaultStyle.dp
|
|
||||||
visible: searchList.count > 0
|
|
||||||
Text {
|
|
||||||
text: qsTr("Suggestions")
|
|
||||||
font {
|
|
||||||
pixelSize: 16 * DefaultStyle.dp
|
|
||||||
weight: 800 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ContactListView{
|
|
||||||
id: searchList
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.preferredHeight: contentHeight
|
|
||||||
contactMenuVisible: false
|
|
||||||
Control.ScrollBar.vertical.visible: false
|
|
||||||
initialHeadersVisible: false
|
|
||||||
displayNameCapitalization: false
|
|
||||||
searchBarText: searchBar.text
|
|
||||||
sourceFlags: LinphoneEnums.MagicSearchSource.All
|
|
||||||
hideListProxy: contactList.model
|
|
||||||
onContactClicked: (contact) => {
|
|
||||||
mainItem.contactClicked(contact)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ FocusScope{
|
||||||
id: mainItem
|
id: mainItem
|
||||||
|
|
||||||
property string placeHolderText: qsTr("Rechercher des contacts")
|
property string placeHolderText: qsTr("Rechercher des contacts")
|
||||||
property list<string> selectedParticipants: suggestionList.selectedContacts
|
property list<string> selectedParticipants//: contactLoader.item ? contactLoader.item.selectedContacts
|
||||||
property int selectedParticipantsCount: selectedParticipants.length
|
property int selectedParticipantsCount: selectedParticipants.length
|
||||||
property ConferenceInfoGui conferenceInfoGui
|
property ConferenceInfoGui conferenceInfoGui
|
||||||
property color searchBarColor: DefaultStyle.grey_100
|
property color searchBarColor: DefaultStyle.grey_100
|
||||||
|
|
@ -30,7 +30,7 @@ FocusScope{
|
||||||
Layout.preferredHeight: contentHeight
|
Layout.preferredHeight: contentHeight
|
||||||
Layout.maximumHeight: mainItem.height / 3
|
Layout.maximumHeight: mainItem.height / 3
|
||||||
width: mainItem.width
|
width: mainItem.width
|
||||||
model: suggestionList.selectedContacts
|
model: mainItem.selectedParticipants
|
||||||
clip: true
|
clip: true
|
||||||
focus: participantList.count > 0
|
focus: participantList.count > 0
|
||||||
Keys.onPressed: (event) => {
|
Keys.onPressed: (event) => {
|
||||||
|
|
@ -40,7 +40,7 @@ FocusScope{
|
||||||
}
|
}
|
||||||
delegate: FocusScope {
|
delegate: FocusScope {
|
||||||
height: 56 * DefaultStyle.dp
|
height: 56 * DefaultStyle.dp
|
||||||
width: participantList.width - scrollbar.implicitWidth - 12 * DefaultStyle.dp
|
width: participantList.width - scrollbar.implicitWidth - 28 * DefaultStyle.dp
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 10 * DefaultStyle.dp
|
spacing: 10 * DefaultStyle.dp
|
||||||
|
|
@ -67,7 +67,7 @@ FocusScope{
|
||||||
icon.height: 24 * DefaultStyle.dp
|
icon.height: 24 * DefaultStyle.dp
|
||||||
focus: true
|
focus: true
|
||||||
contentImageColor: DefaultStyle.main1_500_main
|
contentImageColor: DefaultStyle.main1_500_main
|
||||||
onClicked: suggestionList.removeSelectedContactByAddress(modelData)
|
onClicked: if(contactLoader.item) contactLoader.item.removeSelectedContactByAddress(modelData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +83,7 @@ FocusScope{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SearchBar {
|
SearchBar {
|
||||||
id: searchbar
|
id: searchBar
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 6 * DefaultStyle.dp
|
Layout.topMargin: 6 * DefaultStyle.dp
|
||||||
Layout.rightMargin: 28 * DefaultStyle.dp
|
Layout.rightMargin: 28 * DefaultStyle.dp
|
||||||
|
|
@ -95,86 +95,49 @@ FocusScope{
|
||||||
KeyNavigation.up: participantList.count > 0
|
KeyNavigation.up: participantList.count > 0
|
||||||
? participantList
|
? participantList
|
||||||
: nextItemInFocusChain(false)
|
: nextItemInFocusChain(false)
|
||||||
KeyNavigation.down: contactList
|
KeyNavigation.down: contactLoader.item
|
||||||
}
|
}
|
||||||
Flickable {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
id: content
|
||||||
Layout.fillHeight: true
|
spacing: 15 * DefaultStyle.dp
|
||||||
contentWidth: width
|
Text {
|
||||||
contentHeight: content.height
|
visible: !contactLoader.item?.loading && contactLoader.item?.count === 0
|
||||||
clip: true
|
Layout.alignment: Qt.AlignHCenter
|
||||||
Control.ScrollBar.vertical: ScrollBar {
|
Layout.topMargin: 137 * DefaultStyle.dp
|
||||||
id: contactsScrollBar
|
text: qsTr("Aucun contact%1").arg(searchBar.text.length !== 0 ? " correspondant" : "")
|
||||||
active: true
|
font {
|
||||||
interactive: true
|
pixelSize: 16 * DefaultStyle.dp
|
||||||
policy: Control.ScrollBar.AsNeeded
|
weight: 800 * DefaultStyle.dp
|
||||||
anchors.top: parent.top
|
}
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 8 * DefaultStyle.dp
|
|
||||||
}
|
}
|
||||||
ColumnLayout {
|
Loader{
|
||||||
id: content
|
// This is a hack for an incomprehensible behavior on sections title where they doesn't match with their delegate and can be unordered after resetting models.
|
||||||
anchors.left: parent.left
|
id: contactLoader
|
||||||
anchors.right: parent.right
|
Layout.fillWidth: true
|
||||||
anchors.rightMargin: contactsScrollBar.implicitWidth + 12 * DefaultStyle.dp
|
Layout.fillHeight: true
|
||||||
Text {
|
property string t: searchBar.text
|
||||||
Layout.topMargin: 6 * DefaultStyle.dp
|
onTChanged: {
|
||||||
text: qsTr("Contacts")
|
contactLoader.active = false
|
||||||
font {
|
Qt.callLater(function(){contactLoader.active=true})
|
||||||
pixelSize: 16 * DefaultStyle.dp
|
|
||||||
weight: 800 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ContactListView {
|
//-------------------------------------------------------------
|
||||||
|
sourceComponent: ContactListView{
|
||||||
id: contactList
|
id: contactList
|
||||||
visible: contentHeight > 0 || searchbar.text.length > 0
|
|
||||||
Layout.fillWidth: true
|
|
||||||
// Layout.fillHeight: true
|
|
||||||
Layout.topMargin: 8 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: contentHeight
|
|
||||||
multiSelectionEnabled: true
|
|
||||||
contactMenuVisible: false
|
|
||||||
confInfoGui: mainItem.conferenceInfoGui
|
|
||||||
searchBarText: searchbar.text
|
|
||||||
searchOnInitialization: true
|
|
||||||
onContactAddedToSelection: (address) => {
|
|
||||||
suggestionList.addContactToSelection(address)
|
|
||||||
}
|
|
||||||
onContactRemovedFromSelection: (address) => suggestionList.removeSelectedContactByAddress(address)
|
|
||||||
Control.ScrollBar.vertical.visible: false
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
Layout.topMargin: 6 * DefaultStyle.dp
|
|
||||||
text: qsTr("Suggestions")
|
|
||||||
font {
|
|
||||||
pixelSize: 16 * DefaultStyle.dp
|
|
||||||
weight: 800 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ContactListView {
|
|
||||||
id: suggestionList
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.preferredHeight: contentHeight
|
itemsRightMargin: 28 * DefaultStyle.dp
|
||||||
Control.ScrollBar.vertical.visible: false
|
|
||||||
contactMenuVisible: false
|
|
||||||
searchBarText: searchbar.text
|
|
||||||
sourceFlags: LinphoneEnums.MagicSearchSource.All
|
|
||||||
multiSelectionEnabled: true
|
multiSelectionEnabled: true
|
||||||
displayNameCapitalization: false
|
showContactMenu: false
|
||||||
hideListProxy: contactList.model
|
confInfoGui: mainItem.conferenceInfoGui
|
||||||
|
selectedContacts: mainItem.selectedParticipants
|
||||||
|
onSelectedContactsChanged: Qt.callLater(function(){mainItem.selectedParticipants = selectedContacts})
|
||||||
|
searchBarText: searchBar.text
|
||||||
onContactAddedToSelection: (address) => {
|
onContactAddedToSelection: (address) => {
|
||||||
contactList.addContactToSelection(address)
|
contactList.addContactToSelection(address)
|
||||||
participantList.positionViewAtEnd()
|
|
||||||
}
|
}
|
||||||
onContactRemovedFromSelection: (address) => contactList.removeSelectedContactByAddress(address)
|
onContactRemovedFromSelection: (address) => contactList.removeSelectedContactByAddress(address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Item {
|
|
||||||
// Layout.fillHeight: true
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,8 +171,8 @@ Item {
|
||||||
if (text.length != 0) listPopup.open()
|
if (text.length != 0) listPopup.open()
|
||||||
else listPopup.close()
|
else listPopup.close()
|
||||||
}
|
}
|
||||||
KeyNavigation.down: contactList.count > 0 ? contactList : contactList.footerItem
|
KeyNavigation.down: contactLoader.item?.count > 0 || !contactLoader.item?.footerItem? contactLoader.item : contactLoader.item?.footerItem
|
||||||
KeyNavigation.up: contactList.footerItem
|
KeyNavigation.up: contactLoader.item?.footerItem ? contactLoader.item?.footerItem : contactLoader.item
|
||||||
|
|
||||||
component MagicSearchButton: Button {
|
component MagicSearchButton: Button {
|
||||||
id: button
|
id: button
|
||||||
|
|
@ -196,13 +196,13 @@ Item {
|
||||||
id: listPopup
|
id: listPopup
|
||||||
width: magicSearchBar.width
|
width: magicSearchBar.width
|
||||||
property int maxHeight: 400 * DefaultStyle.dp
|
property int maxHeight: 400 * DefaultStyle.dp
|
||||||
property bool displayScrollbar: contactList.contentHeight + topPadding + bottomPadding> maxHeight
|
property bool displayScrollbar: contactLoader.item?.contentHeight + topPadding + bottomPadding> maxHeight
|
||||||
height: Math.min(contactList.contentHeight + topPadding + bottomPadding, maxHeight)
|
height: Math.min(contactLoader.item?.contentHeight + topPadding + bottomPadding, maxHeight)
|
||||||
y: magicSearchBar.height
|
y: magicSearchBar.height
|
||||||
// closePolicy: Popup.NoAutoClose
|
// closePolicy: Popup.NoAutoClose
|
||||||
topPadding: 20 * DefaultStyle.dp
|
topPadding: 20 * DefaultStyle.dp
|
||||||
bottomPadding: 20 * DefaultStyle.dp
|
bottomPadding: 20 * DefaultStyle.dp
|
||||||
rightPadding: 20 * DefaultStyle.dp
|
rightPadding: 10 * DefaultStyle.dp
|
||||||
leftPadding: 20 * DefaultStyle.dp
|
leftPadding: 20 * DefaultStyle.dp
|
||||||
|
|
||||||
background: Item {
|
background: Item {
|
||||||
|
|
@ -213,7 +213,7 @@ Item {
|
||||||
color: DefaultStyle.grey_0
|
color: DefaultStyle.grey_0
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
border.color: DefaultStyle.main1_500_main
|
border.color: DefaultStyle.main1_500_main
|
||||||
border.width: contactList.activeFocus ? 2 : 0
|
border.width: contactLoader.item?.activeFocus ? 2 : 0
|
||||||
|
|
||||||
}
|
}
|
||||||
MultiEffect {
|
MultiEffect {
|
||||||
|
|
@ -237,125 +237,138 @@ Item {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contentItem: ContactListView {
|
contentItem: Loader{
|
||||||
id: contactList
|
// This is a hack for an incomprehensible behavior on sections title where they doesn't match with their delegate and can be unordered after resetting models.
|
||||||
visible: magicSearchBar.text.length != 0
|
id: contactLoader
|
||||||
Layout.preferredHeight: contentHeight
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 5 * DefaultStyle.dp
|
Layout.fillHeight: true
|
||||||
initialHeadersVisible: false
|
property bool deactivate: false
|
||||||
contactMenuVisible: false
|
active: !deactivate && magicSearchBar.text != ''
|
||||||
actionLayoutVisible: true
|
property string t: magicSearchBar.text
|
||||||
selectionEnabled: false
|
onTChanged: {
|
||||||
showDefaultAddress: true
|
contactLoader.deactivate = true
|
||||||
showLdapContacts: true
|
Qt.callLater(function(){contactLoader.deactivate=false})
|
||||||
Control.ScrollBar.vertical: scrollbar
|
|
||||||
searchText: magicSearchBar.text
|
|
||||||
|
|
||||||
Keys.onPressed: (event) => {
|
|
||||||
if(event.key == Qt.Key_Down){
|
|
||||||
if(contactList.currentIndex == contactList.count -1) {
|
|
||||||
contactList.currentIndex = -1
|
|
||||||
contactList.footerItem.forceActiveFocus()
|
|
||||||
event.accepted = true
|
|
||||||
}
|
|
||||||
} else if(event.key == Qt.Key_Up){
|
|
||||||
if(contactList.currentIndex <= 0) {
|
|
||||||
contactList.currentIndex = -1
|
|
||||||
contactList.footerItem.forceActiveFocus()
|
|
||||||
event.accepted = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
header: Text {
|
//-------------------------------------------------------------
|
||||||
visible: contactList.count > 0
|
sourceComponent: ContactListView {
|
||||||
text: qsTr("Contact")
|
id: contactList
|
||||||
color: DefaultStyle.main2_500main
|
visible: magicSearchBar.text.length != 0
|
||||||
font {
|
Layout.preferredHeight: item?.contentHeight
|
||||||
pixelSize: 13 * DefaultStyle.dp
|
Layout.fillWidth: true
|
||||||
weight: 700 * DefaultStyle.dp
|
itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin)
|
||||||
}
|
showInitials: false
|
||||||
}
|
showContactMenu: false
|
||||||
footer: FocusScope{
|
showActions: true
|
||||||
id: suggestionFocusScope
|
showFavorites: false
|
||||||
width: contactList.width
|
selectionEnabled: false
|
||||||
height: visible ? content.implicitHeight : 0
|
showDefaultAddress: true
|
||||||
onActiveFocusChanged: if(activeFocus) contactList.positionViewAtEnd()
|
hideSuggestions: true
|
||||||
visible: !contactList.haveAddress(suggestionText.text)
|
|
||||||
Rectangle{
|
sectionsPixelSize: 13 * DefaultStyle.dp
|
||||||
anchors.left: parent.left
|
sectionsWeight: 700 * DefaultStyle.dp
|
||||||
anchors.right: parent.right
|
sectionsSpacing: 5 * DefaultStyle.dp
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
height: suggestionRow.implicitHeight
|
Control.ScrollBar.vertical: scrollbar
|
||||||
color: suggestionFocusScope.activeFocus ? DefaultStyle.numericPadPressedButtonColor : 'transparent'
|
searchBarText: magicSearchBar.text
|
||||||
}
|
|
||||||
ColumnLayout {
|
Keys.onPressed: (event) => {
|
||||||
id: content
|
if(event.key == Qt.Key_Down){
|
||||||
anchors.fill: parent
|
if(contactList.currentIndex == contactList.count -1) {
|
||||||
anchors.rightMargin: 5 * DefaultStyle.dp
|
contactList.currentIndex = -1
|
||||||
|
contactList.footerItem.forceActiveFocus()
|
||||||
spacing: 10 * DefaultStyle.dp
|
|
||||||
Text {
|
|
||||||
text: qsTr("Suggestion")
|
|
||||||
color: DefaultStyle.main2_500main
|
|
||||||
font {
|
|
||||||
pixelSize: 13 * DefaultStyle.dp
|
|
||||||
weight: 700 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: (event) => {
|
|
||||||
if(contactList.count <= 0) return;
|
|
||||||
if(event.key == Qt.Key_Down){
|
|
||||||
contactList.currentIndex = 0
|
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
} else if(event.key == Qt.Key_Up){
|
}
|
||||||
contactList.currentIndex = contactList.count - 1
|
} else if(event.key == Qt.Key_Up){
|
||||||
|
if(contactList.currentIndex <= 0) {
|
||||||
|
contactList.currentIndex = -1
|
||||||
|
contactList.footerItem.forceActiveFocus()
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RowLayout {
|
}
|
||||||
id: suggestionRow
|
|
||||||
spacing: 10 * DefaultStyle.dp
|
footer: FocusScope{
|
||||||
|
id: suggestionFocusScope
|
||||||
|
width: contactList.width
|
||||||
|
height: visible ? content.implicitHeight : 0
|
||||||
|
onActiveFocusChanged: if(activeFocus) contactList.positionViewAtEnd()
|
||||||
|
visible: !contactList.haveAddress(suggestionText.text)
|
||||||
|
Rectangle{
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
height: suggestionRow.implicitHeight
|
||||||
|
color: suggestionFocusScope.activeFocus ? DefaultStyle.numericPadPressedButtonColor : 'transparent'
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 5 * DefaultStyle.dp
|
||||||
|
anchors.rightMargin: 15 * DefaultStyle.dp
|
||||||
|
|
||||||
Avatar {
|
spacing: 10 * DefaultStyle.dp
|
||||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
|
||||||
_address: magicSearchBar.text
|
|
||||||
}
|
|
||||||
Text {
|
Text {
|
||||||
id: suggestionText
|
text: qsTr("Suggestion")
|
||||||
property var urlObj: UtilsCpp.interpretUrl(magicSearchBar.text)
|
color: DefaultStyle.main2_500main
|
||||||
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(urlObj?.value) : urlObj?.value
|
|
||||||
font {
|
font {
|
||||||
pixelSize: 12 * DefaultStyle.dp
|
pixelSize: 13 * DefaultStyle.dp
|
||||||
weight: 300 * DefaultStyle.dp
|
weight: 700 * DefaultStyle.dp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
Keys.onPressed: (event) => {
|
||||||
}
|
if(contactList.count <= 0) return;
|
||||||
MagicSearchButton {
|
if(event.key == Qt.Key_Down){
|
||||||
id: callButton
|
contactList.currentIndex = 0
|
||||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
event.accepted = true
|
||||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
} else if(event.key == Qt.Key_Up){
|
||||||
icon.source: AppIcons.phone
|
contactList.currentIndex = contactList.count - 1
|
||||||
focus: true
|
event.accepted = true
|
||||||
onClicked: {
|
|
||||||
UtilsCpp.createCall(magicSearchBar.text)
|
|
||||||
magicSearchBar.clearText()
|
|
||||||
}
|
}
|
||||||
KeyNavigation.right: chatButton
|
|
||||||
KeyNavigation.left: chatButton
|
|
||||||
}
|
}
|
||||||
MagicSearchButton {
|
RowLayout {
|
||||||
id: chatButton
|
id: suggestionRow
|
||||||
visible: !SettingsCpp.disableChatFeature
|
spacing: 10 * DefaultStyle.dp
|
||||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
Avatar {
|
||||||
icon.source: AppIcons.chatTeardropText
|
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||||
KeyNavigation.right: callButton
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
KeyNavigation.left: callButton
|
_address: magicSearchBar.text
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id: suggestionText
|
||||||
|
property var urlObj: UtilsCpp.interpretUrl(magicSearchBar.text)
|
||||||
|
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(urlObj?.value) : urlObj?.value
|
||||||
|
font {
|
||||||
|
pixelSize: 12 * DefaultStyle.dp
|
||||||
|
weight: 300 * DefaultStyle.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
MagicSearchButton {
|
||||||
|
id: callButton
|
||||||
|
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
|
icon.source: AppIcons.phone
|
||||||
|
focus: true
|
||||||
|
onClicked: {
|
||||||
|
UtilsCpp.createCall(magicSearchBar.text)
|
||||||
|
magicSearchBar.clearText()
|
||||||
|
}
|
||||||
|
KeyNavigation.right: chatButton
|
||||||
|
KeyNavigation.left: chatButton
|
||||||
|
}
|
||||||
|
MagicSearchButton {
|
||||||
|
id: chatButton
|
||||||
|
visible: !SettingsCpp.disableChatFeature
|
||||||
|
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||||
|
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||||
|
icon.source: AppIcons.chatTeardropText
|
||||||
|
KeyNavigation.right: callButton
|
||||||
|
KeyNavigation.left: callButton
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ AbstractMainPage {
|
||||||
|
|
||||||
onNoItemButtonPressed: goToNewCall()
|
onNoItemButtonPressed: goToNewCall()
|
||||||
|
|
||||||
showDefaultItem: listStackView.currentItem && listStackView.currentItem.objectName == "historyListItem" && listStackView.currentItem.listView.count === 0
|
showDefaultItem: listStackView.currentItem && listStackView.currentItem.objectName == "historyListItem" && listStackView.currentItem.listView.count === 0 || false
|
||||||
|
|
||||||
function goToNewCall() {
|
function goToNewCall() {
|
||||||
if (listStackView.currentItem && listStackView.currentItem.objectName != "newCallItem") listStackView.push(newCallItem)
|
if (listStackView.currentItem && listStackView.currentItem.objectName != "newCallItem") listStackView.push(newCallItem)
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ AbstractMainPage {
|
||||||
|
|
||||||
onVisibleChanged: if (!visible) {
|
onVisibleChanged: if (!visible) {
|
||||||
rightPanelStackView.clear()
|
rightPanelStackView.clear()
|
||||||
contactList.currentIndex = -1
|
if(contactLoader.item) contactLoader.item.currentIndex = -1
|
||||||
favoriteList.currentIndex = -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectedContactChanged: {
|
onSelectedContactChanged: {
|
||||||
|
|
@ -52,13 +51,8 @@ AbstractMainPage {
|
||||||
|
|
||||||
// rightPanelStackView.initialItem: contactDetail
|
// rightPanelStackView.initialItem: contactDetail
|
||||||
|
|
||||||
showDefaultItem: rightPanelStackView.depth == 0 && leftPanelNoItemText.visible && searchBar.text.length === 0
|
showDefaultItem: rightPanelStackView.depth == 0 && contactLoader.item?.count === 0 && searchBar.text.length === 0
|
||||||
|
|
||||||
MagicSearchProxy {
|
|
||||||
id: allFriends
|
|
||||||
showLdapContacts: SettingsCpp.syncLdapContacts
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteContact(contact) {
|
function deleteContact(contact) {
|
||||||
if (!contact) return
|
if (!contact) return
|
||||||
var mainWin = UtilsCpp.getMainWindow()
|
var mainWin = UtilsCpp.getMainWindow()
|
||||||
|
|
@ -211,170 +205,60 @@ AbstractMainPage {
|
||||||
spacing: 38 * DefaultStyle.dp
|
spacing: 38 * DefaultStyle.dp
|
||||||
SearchBar {
|
SearchBar {
|
||||||
id: searchBar
|
id: searchBar
|
||||||
visible: contactList.count != 0 || text.length !== 0
|
visible: !contactLoader.item || contactLoader.item.loading || contactLoader.item.count != 0 || text.length !== 0
|
||||||
Layout.leftMargin: leftPanel.leftMargin
|
Layout.leftMargin: leftPanel.leftMargin
|
||||||
Layout.rightMargin: leftPanel.rightMargin
|
Layout.rightMargin: leftPanel.rightMargin
|
||||||
Layout.topMargin: 18 * DefaultStyle.dp
|
Layout.topMargin: 18 * DefaultStyle.dp
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
placeholderText: qsTr("Rechercher un contact")
|
placeholderText: qsTr("Rechercher un contact")
|
||||||
KeyNavigation.up: createContactButton
|
KeyNavigation.up: createContactButton
|
||||||
KeyNavigation.down: favoriteList.contentHeight > 0 ? favoriteExpandButton : contactExpandButton
|
KeyNavigation.down: contactLoader.item
|
||||||
}
|
}
|
||||||
|
ColumnLayout {
|
||||||
RowLayout {
|
id: content
|
||||||
Flickable {
|
spacing: 15 * DefaultStyle.dp
|
||||||
id: listLayout
|
Text {
|
||||||
contentWidth: width
|
visible: contactLoader.item && !contactLoader.item.loading && contactLoader.item.count === 0
|
||||||
contentHeight: content.height
|
Layout.alignment: Qt.AlignHCenter
|
||||||
clip: true
|
Layout.topMargin: 137 * DefaultStyle.dp
|
||||||
Control.ScrollBar.vertical: contactsScrollbar
|
text: qsTr("Aucun contact%1").arg(searchBar.text.length !== 0 ? " correspondant" : "")
|
||||||
|
font {
|
||||||
|
pixelSize: 16 * DefaultStyle.dp
|
||||||
|
weight: 800 * DefaultStyle.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loader{
|
||||||
|
// This is a hack for an incomprehensible behavior on sections title where they doesn't match with their delegate and can be unordered after resetting models.
|
||||||
|
id: contactLoader
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
Layout.leftMargin: 45 * DefaultStyle.dp
|
||||||
ColumnLayout {
|
property string t: searchBar.text
|
||||||
id: content
|
active: leftPanel.visible
|
||||||
width: parent.width
|
onTChanged: {
|
||||||
spacing: 15 * DefaultStyle.dp
|
contactLoader.active = false
|
||||||
Text {
|
Qt.callLater(function(){contactLoader.active=true})
|
||||||
id: leftPanelNoItemText
|
}
|
||||||
visible: contactList.count === 0
|
//-------------------------------------------------------------
|
||||||
Layout.alignment: Qt.AlignHCenter
|
sourceComponent: ContactListView{
|
||||||
Layout.topMargin: 137 * DefaultStyle.dp
|
id: contactList
|
||||||
text: qsTr("Aucun contact%1").arg(searchBar.text.length !== 0 ? " correspondant" : "")
|
searchBarText: searchBar.text
|
||||||
font {
|
hideSuggestions: true
|
||||||
pixelSize: 16 * DefaultStyle.dp
|
sourceFlags: LinphoneEnums.MagicSearchSource.Friends | LinphoneEnums.MagicSearchSource.FavoriteFriends | LinphoneEnums.MagicSearchSource.LdapServers
|
||||||
weight: 800 * DefaultStyle.dp
|
|
||||||
}
|
onSelectedContactChanged: {
|
||||||
|
mainItem.selectedContact = selectedContact
|
||||||
}
|
}
|
||||||
ColumnLayout {
|
onContactDeletionRequested: (contact) => {
|
||||||
visible: favoriteList.contentHeight > 0
|
mainItem.deleteContact(contact)
|
||||||
onVisibleChanged: if (visible && !favoriteList.visible) favoriteList.visible = true
|
|
||||||
Layout.leftMargin: leftPanel.leftMargin
|
|
||||||
Layout.rightMargin: leftPanel.rightMargin
|
|
||||||
spacing: 18 * DefaultStyle.dp
|
|
||||||
RowLayout {
|
|
||||||
spacing: 0
|
|
||||||
Text {
|
|
||||||
text: qsTr("Favoris")
|
|
||||||
font {
|
|
||||||
pixelSize: 16 * DefaultStyle.dp
|
|
||||||
weight: 800 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
id: favoriteExpandButton
|
|
||||||
background: Item{}
|
|
||||||
icon.source: favoriteList.visible ? AppIcons.upArrow : AppIcons.downArrow
|
|
||||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
|
||||||
icon.width: 24 * DefaultStyle.dp
|
|
||||||
icon.height: 24 * DefaultStyle.dp
|
|
||||||
onClicked: favoriteList.visible = !favoriteList.visible
|
|
||||||
KeyNavigation.up: searchBar
|
|
||||||
KeyNavigation.down: favoriteList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ContactListView{
|
|
||||||
id: favoriteList
|
|
||||||
hoverEnabled: mainItem.leftPanelEnabled
|
|
||||||
highlightFollowsCurrentItem: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: contentHeight
|
|
||||||
Control.ScrollBar.vertical.visible: false
|
|
||||||
showFavoritesOnly: true
|
|
||||||
searchOnInitialization: true
|
|
||||||
contactMenuVisible: true
|
|
||||||
searchBarText: searchBar.text
|
|
||||||
listProxy: allFriends
|
|
||||||
onSelectedContactChanged: {
|
|
||||||
if (selectedContact) {
|
|
||||||
contactList.currentIndex = -1
|
|
||||||
}
|
|
||||||
mainItem.selectedContact = selectedContact
|
|
||||||
}
|
|
||||||
onContactDeletionRequested: (contact) => {
|
|
||||||
mainItem.deleteContact(contact)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ColumnLayout {
|
onCountChanged: {
|
||||||
visible: contactList.contentHeight > 0
|
if (initialFriendToDisplay.length !== 0) {
|
||||||
onVisibleChanged: if (visible && !contactList.visible) contactList.visible = true
|
if (selectContact(initialFriendToDisplay) != -1) initialFriendToDisplay = ""
|
||||||
Layout.leftMargin: leftPanel.leftMargin
|
|
||||||
Layout.rightMargin: leftPanel.rightMargin
|
|
||||||
spacing: 16 * DefaultStyle.dp
|
|
||||||
RowLayout {
|
|
||||||
spacing: 0
|
|
||||||
Text {
|
|
||||||
text: qsTr("Contacts")
|
|
||||||
font {
|
|
||||||
pixelSize: 16 * DefaultStyle.dp
|
|
||||||
weight: 800 * DefaultStyle.dp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
id: contactExpandButton
|
|
||||||
background: Item{}
|
|
||||||
icon.source: contactList.visible ? AppIcons.upArrow : AppIcons.downArrow
|
|
||||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
|
||||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
|
||||||
icon.width: 24 * DefaultStyle.dp
|
|
||||||
icon.height: 24 * DefaultStyle.dp
|
|
||||||
onClicked: contactList.visible = !contactList.visible
|
|
||||||
KeyNavigation.up: favoriteList.visible ? favoriteList : searchBar
|
|
||||||
KeyNavigation.down: contactList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ContactListView{
|
|
||||||
id: contactList
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: contentHeight
|
|
||||||
Control.ScrollBar.vertical.visible: false
|
|
||||||
hoverEnabled: mainItem.leftPanelEnabled
|
|
||||||
contactMenuVisible: true
|
|
||||||
searchOnInitialization: true
|
|
||||||
highlightFollowsCurrentItem: true
|
|
||||||
searchBarText: searchBar.text
|
|
||||||
listProxy: allFriends
|
|
||||||
onCountChanged: {
|
|
||||||
if (initialFriendToDisplay.length !== 0) {
|
|
||||||
if (selectContact(initialFriendToDisplay) != -1) initialFriendToDisplay = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onSelectedContactChanged: {
|
|
||||||
if (selectedContact) {
|
|
||||||
favoriteList.currentIndex = -1
|
|
||||||
}
|
|
||||||
mainItem.selectedContact = selectedContact
|
|
||||||
}
|
|
||||||
onContactDeletionRequested: (contact) => {
|
|
||||||
mainItem.deleteContact(contact)
|
|
||||||
}
|
|
||||||
Connections {
|
|
||||||
target: contactList.model
|
|
||||||
function onFriendCreated(index) {
|
|
||||||
contactList.currentIndex = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ScrollBar {
|
|
||||||
id: contactsScrollbar
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.rightMargin: 8 * DefaultStyle.dp
|
|
||||||
height: listLayout.height
|
|
||||||
active: true
|
|
||||||
interactive: true
|
|
||||||
policy: Control.ScrollBar.AsNeeded
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -493,8 +377,6 @@ AbstractMainPage {
|
||||||
spacing: 0
|
spacing: 0
|
||||||
Text {
|
Text {
|
||||||
text: contactDetail.contactName
|
text: contactDetail.contactName
|
||||||
Layout.fillWidth: true
|
|
||||||
maximumLineCount: 1
|
|
||||||
font {
|
font {
|
||||||
pixelSize: 29 * DefaultStyle.dp
|
pixelSize: 29 * DefaultStyle.dp
|
||||||
weight: 800 * DefaultStyle.dp
|
weight: 800 * DefaultStyle.dp
|
||||||
|
|
@ -579,6 +461,7 @@ AbstractMainPage {
|
||||||
model: mainItem.selectedContact ? mainItem.selectedContact.core.allAddresses : []
|
model: mainItem.selectedContact ? mainItem.selectedContact.core.allAddresses : []
|
||||||
}
|
}
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
|
property var listViewModelData: modelData
|
||||||
width: addrList.width
|
width: addrList.width
|
||||||
height: 46 * DefaultStyle.dp
|
height: 46 * DefaultStyle.dp
|
||||||
|
|
||||||
|
|
@ -595,7 +478,7 @@ AbstractMainPage {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Text {
|
Text {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: modelData.label
|
text: listViewModelData.label
|
||||||
font {
|
font {
|
||||||
pixelSize: 13 * DefaultStyle.dp
|
pixelSize: 13 * DefaultStyle.dp
|
||||||
weight: 700 * DefaultStyle.dp
|
weight: 700 * DefaultStyle.dp
|
||||||
|
|
@ -603,7 +486,7 @@ AbstractMainPage {
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
property string _text: modelData.address
|
property string _text: listViewModelData.address
|
||||||
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_text) : _text
|
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_text) : _text
|
||||||
font {
|
font {
|
||||||
pixelSize: 14 * DefaultStyle.dp
|
pixelSize: 14 * DefaultStyle.dp
|
||||||
|
|
@ -624,7 +507,7 @@ AbstractMainPage {
|
||||||
icon.width: 24 * DefaultStyle.dp
|
icon.width: 24 * DefaultStyle.dp
|
||||||
icon.height: 24 * DefaultStyle.dp
|
icon.height: 24 * DefaultStyle.dp
|
||||||
onClicked: {
|
onClicked: {
|
||||||
UtilsCpp.createCall(modelData.address)
|
UtilsCpp.createCall(listViewModelData.address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -761,16 +644,17 @@ AbstractMainPage {
|
||||||
id: deviceDelegate
|
id: deviceDelegate
|
||||||
width: deviceList.width
|
width: deviceList.width
|
||||||
height: 30 * DefaultStyle.dp
|
height: 30 * DefaultStyle.dp
|
||||||
|
property var listViewModelData: modelData
|
||||||
property var callObj
|
property var callObj
|
||||||
property CallGui deviceCall: callObj ? callObj.value : null
|
property CallGui deviceCall: callObj ? callObj.value : null
|
||||||
property string deviceName: modelData.name.length != 0 ? modelData.name : qsTr("Appareil sans nom")
|
property string deviceName: listViewModelData.name.length != 0 ? listViewModelData.name : qsTr("Appareil sans nom")
|
||||||
Text {
|
Text {
|
||||||
text: deviceDelegate.deviceName
|
text: deviceDelegate.deviceName
|
||||||
font.pixelSize: 14 * DefaultStyle.dp
|
font.pixelSize: 14 * DefaultStyle.dp
|
||||||
}
|
}
|
||||||
Item{Layout.fillWidth: true}
|
Item{Layout.fillWidth: true}
|
||||||
Image{
|
Image{
|
||||||
visible: modelData.securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
visible: listViewModelData.securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||||
source: AppIcons.trusted
|
source: AppIcons.trusted
|
||||||
width: 22 * DefaultStyle.dp
|
width: 22 * DefaultStyle.dp
|
||||||
height: 22 * DefaultStyle.dp
|
height: 22 * DefaultStyle.dp
|
||||||
|
|
@ -778,7 +662,7 @@ AbstractMainPage {
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
Layout.preferredHeight: 30 * DefaultStyle.dp
|
Layout.preferredHeight: 30 * DefaultStyle.dp
|
||||||
visible: modelData.securityLevel != LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
visible: listViewModelData.securityLevel != LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||||
color: DefaultStyle.main1_100
|
color: DefaultStyle.main1_100
|
||||||
icon.source: AppIcons.warningCircle
|
icon.source: AppIcons.warningCircle
|
||||||
icon.height: 14 * DefaultStyle.dp
|
icon.height: 14 * DefaultStyle.dp
|
||||||
|
|
@ -794,12 +678,12 @@ AbstractMainPage {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (SettingsCpp.getDisplayDeviceCheckConfirmation()) {
|
if (SettingsCpp.getDisplayDeviceCheckConfirmation()) {
|
||||||
verifyDevicePopup.deviceName = deviceDelegate.deviceName
|
verifyDevicePopup.deviceName = deviceDelegate.deviceName
|
||||||
verifyDevicePopup.deviceAddress = modelData.address
|
verifyDevicePopup.deviceAddress = listViewModelData.address
|
||||||
verifyDevicePopup.open()
|
verifyDevicePopup.open()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
UtilsCpp.createCall(modelData.address, {}, LinphoneEnums.MediaEncryption.Zrtp)
|
UtilsCpp.createCall(listViewModelData.address, {}, LinphoneEnums.MediaEncryption.Zrtp)
|
||||||
parent.callObj = UtilsCpp.getCallByAddress(modelData.address)
|
parent.callObj = UtilsCpp.getCallByAddress(listViewModelData.address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue