diff --git a/Linphone/core/search/MagicSearchList.cpp b/Linphone/core/search/MagicSearchList.cpp index 09fe5994d..09b1e0b27 100644 --- a/Linphone/core/search/MagicSearchList.cpp +++ b/Linphone/core/search/MagicSearchList.cpp @@ -59,7 +59,8 @@ void MagicSearchList::setSelf(QSharedPointer me) { auto itemCore = item.objectCast(); return itemCore->getDefaultAddress().length() > 0 && itemCore->getDefaultAddress() == friendCore->getDefaultAddress() || - itemCore->getFriendModel()->getFriend() == friendCore->getFriendModel()->getFriend(); + itemCore->getFriendModel() && friendCore->getFriendModel() && + itemCore->getFriendModel()->getFriend() == friendCore->getFriendModel()->getFriend(); }); if (haveContact == mList.end()) { connect(friendCore.get(), &FriendCore::removed, this, qOverload(&MagicSearchList::remove)); @@ -117,8 +118,9 @@ void MagicSearchList::setSelf(QSharedPointer me) { address->asString())); // linphone Friend object remove specific address. contacts->append(contact); } else if (!it->getPhoneNumber().empty()) { + auto phoneNumber = it->getPhoneNumber(); linphoneFriend = CoreModel::getInstance()->getCore()->createFriend(); - linphoneFriend->setAddress(address); + linphoneFriend->addPhoneNumber(phoneNumber); contact = FriendCore::create(linphoneFriend, isStored, it->getSourceFlags()); contact->setGivenName(Utils::coreStringToAppString(it->getPhoneNumber())); contact->appendPhoneNumber(tr("Phone"), Utils::coreStringToAppString(it->getPhoneNumber())); @@ -128,6 +130,7 @@ void MagicSearchList::setSelf(QSharedPointer me) { mModelConnection->invokeToCore([this, contacts]() { setResults(*contacts); delete contacts; + emit resultsProcessed(); }); }); qDebug() << log().arg("Initialized"); diff --git a/Linphone/core/search/MagicSearchList.hpp b/Linphone/core/search/MagicSearchList.hpp index a36215bd6..d546ed212 100644 --- a/Linphone/core/search/MagicSearchList.hpp +++ b/Linphone/core/search/MagicSearchList.hpp @@ -72,6 +72,8 @@ signals: void friendCreated(int index, FriendGui *data); void friendStarredChanged(); + void resultsProcessed(); + void initialized(); private: diff --git a/Linphone/core/search/MagicSearchProxy.cpp b/Linphone/core/search/MagicSearchProxy.cpp index 3c93ba16b..df042f5fb 100644 --- a/Linphone/core/search/MagicSearchProxy.cpp +++ b/Linphone/core/search/MagicSearchProxy.cpp @@ -25,11 +25,13 @@ #include "core/friend/FriendCore.hpp" MagicSearchProxy::MagicSearchProxy(QObject *parent) : LimitProxy(parent) { - setList(MagicSearchList::create()); + auto magicSearchList = MagicSearchList::create(); + setList(magicSearchList); connect(this, &MagicSearchProxy::forceUpdate, [this] { if (mList) emit mList->lSearch(mSearchText, getSourceFlags(), getAggregationFlag(), getMaxResults()); }); connect(App::getInstance(), &App::currentDateChanged, this, &MagicSearchProxy::forceUpdate); + connect(magicSearchList.get(), &MagicSearchList::resultsProcessed, this, &MagicSearchProxy::resultsProcessed); } MagicSearchProxy::~MagicSearchProxy() { diff --git a/Linphone/core/search/MagicSearchProxy.hpp b/Linphone/core/search/MagicSearchProxy.hpp index 8903a3bf4..e6d48d89c 100644 --- a/Linphone/core/search/MagicSearchProxy.hpp +++ b/Linphone/core/search/MagicSearchProxy.hpp @@ -82,6 +82,7 @@ signals: void parentProxyChanged(); void hideListProxyChanged(); void initialized(); + void resultsProcessed(); protected: MagicSearchProxy *mParentProxy = nullptr; diff --git a/Linphone/model/search/MagicSearchModel.cpp b/Linphone/model/search/MagicSearchModel.cpp index 11167be17..cc3a713dc 100644 --- a/Linphone/model/search/MagicSearchModel.cpp +++ b/Linphone/model/search/MagicSearchModel.cpp @@ -81,31 +81,23 @@ void MagicSearchModel::onSearchResultsReceived(const std::shared_ptr> finalResults; + emit searchResultsReceived(results); for (auto result : results) { auto f = result->getFriend(); auto fList = f ? f->getFriendList() : nullptr; - qDebug() << log().arg("") << (f ? f->getName().c_str() : "NoFriend") << ", " - << (result->getAddress() ? result->getAddress()->asString().c_str() : "NoAddr") << " / " - << (fList ? fList->getDisplayName().c_str() : "NoList") << result->getSourceFlags() << " / " - << (f ? f.get() : nullptr); + // qDebug() << log().arg("") << (f ? f->getName().c_str() : "NoFriend") << ", " + // << (result->getAddress() ? result->getAddress()->asString().c_str() : "NoAddr") << " / " + // << (fList ? fList->getDisplayName().c_str() : "NoList") << result->getSourceFlags() << " / " + // << (f ? f.get() : nullptr); bool isLdap = (result->getSourceFlags() & (int)linphone::MagicSearch::Source::LdapServers) != 0; // Do not add it into ldap_friends if it already exists in app_friends. - if (isLdap && f && (!fList || fList->getDisplayName() != "app_friends") && - !ToolModel::friendIsInFriendList(appFriends, f)) { // Double check because of SDK merging that lead to - // use a ldap result as of app_friends/ldap_friends. - updateFriendListWithFriend(f, ToolModel::getLdapFriendList()); + if (isLdap && f && (!fList || fList->getDisplayName() != "app_friends")) { // Double check because of SDK merging that lead to + // use a ldap result as of app_friends/ldap_friends. + updateFriendListWithFriend(f, ldapFriends); } - - auto resultIt = - std::find_if(finalResults.begin(), finalResults.end(), [result](std::shared_ptr r) { - return r->getAddress() && r->getAddress()->weakEqual(result->getAddress()); - }); - if (resultIt == finalResults.end()) finalResults.push_back(result); - else if (fList && fList->getDisplayName() == "app_friends") *resultIt = result; // replace if local friend } - emit searchResultsReceived(finalResults); } void MagicSearchModel::onMoreResultsAvailable(const std::shared_ptr &magicSearch, diff --git a/Linphone/model/tool/ToolModel.cpp b/Linphone/model/tool/ToolModel.cpp index d4215676f..ce64893b9 100644 --- a/Linphone/model/tool/ToolModel.cpp +++ b/Linphone/model/tool/ToolModel.cpp @@ -296,13 +296,12 @@ std::shared_ptr ToolModel::getLdapFriendList() { } bool ToolModel::friendIsInFriendList(const std::shared_ptr &friendList, - const std::shared_ptr &f) { - for (auto contact : friendList->getFriends()) { - if (f == contact) { - return true; - } - } - return false; + const std::shared_ptr &f) { + auto friends = friendList->getFriends(); + auto it = std::find_if(friends.begin(), friends.end(), [f] (std::shared_ptr linFriend) { + return linFriend == f; + }); + return (it != friends.end()); } // Load downloaded codecs like OpenH264 (needs to be after core is created and has loaded its plugins, as diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index 7454c2e16..cae06cce3 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -6,9 +6,9 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Control/Button/CheckBox.qml view/Control/Button/ComboBox.qml view/Control/Button/HelpIconLabelButton.qml - view/Control/Button/IconButton.qml - view/Control/Button/IconLabelButton.qml - view/Control/Button/BigButton.qml + view/Control/Button/IconButton.qml + view/Control/Button/IconLabelButton.qml + view/Control/Button/BigButton.qml view/Control/Button/RoundButton.qml view/Control/Button/MediumButton.qml view/Control/Button/SmallButton.qml diff --git a/Linphone/view/Control/Container/ScrollBar.qml b/Linphone/view/Control/Container/ScrollBar.qml index 8b8428364..4d168f0b3 100644 --- a/Linphone/view/Control/Container/ScrollBar.qml +++ b/Linphone/view/Control/Container/ScrollBar.qml @@ -7,9 +7,10 @@ import Linphone Control.ScrollBar { id: mainItem padding: 0 + property color color: DefaultStyle.grey_850 contentItem: Rectangle { implicitWidth: 6 * DefaultStyle.dp radius: 32 * DefaultStyle.dp - color: DefaultStyle.grey_850 + color: mainItem.color } -} \ No newline at end of file +} diff --git a/Linphone/view/Control/Display/Contact/AllContactListView.qml b/Linphone/view/Control/Display/Contact/AllContactListView.qml index 39867e693..efe3c9b9f 100644 --- a/Linphone/view/Control/Display/Contact/AllContactListView.qml +++ b/Linphone/view/Control/Display/Contact/AllContactListView.qml @@ -8,328 +8,340 @@ import ConstantsCpp 1.0 import SettingsCpp import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils -Flickable{ - id: mainItem - - 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 bool showFavorites: true // Display the favorites in the header - property bool hideSuggestions: false // Hide not stored contacts (not suggestions) - property string highlightText: searchText // Bold characters in Display name. - property var sourceFlags: LinphoneEnums.MagicSearchSource.All - - 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 selectedContacts // List of default address on selected contacts. - //property FriendGui selectedContact//: model.getAt(currentIndex) || null - property FriendGui highlightedContact - - property bool searchOnEmpty: true - property bool loading: false - property bool pauseSearch: false // true = don't search on text change +Flickable { + id: mainItem - // Model properties - // set searchBarText without specifying a model to bold - // matching names - property string searchBarText - property string searchText// Binding is done on searchBarTextChanged - property ConferenceInfoGui confInfoGui - - property bool haveFavorites: false - property bool haveContacts: count > 0 - property int sectionsPixelSize: 16 * DefaultStyle.dp - property int sectionsWeight: 800 * DefaultStyle.dp - property int sectionsSpacing: 18 * DefaultStyle.dp - - property int itemsRightMargin: 39 * DefaultStyle.dp - property int count: contactsList.count + suggestionsList.count + favoritesList.count - - signal resultsReceived() - signal contactStarredChanged() - signal contactDeletionRequested(FriendGui contact) - signal contactAddedToSelection(string address) - signal contactRemovedFromSelection(string address) - signal contactSelected(FriendGui contact) - - contentWidth: width - contentHeight: contentsLayout.height + flickableDirection: Flickable.VerticalFlick - - function selectContact(address) { - var index = contactsProxy.loadUntil(address)// Be sure to have this address in proxy if it exists - if (index != -1) { - contactsList.selectIndex(index) - } - return index - - } - function addContactToSelection(address) { - if (multiSelectionEnabled) { - var indexInSelection = selectedContacts.indexOf(address) - if (indexInSelection == -1) { - selectedContacts.push(address) - contactAddedToSelection(address) - } - } - } - function removeContactFromSelection(indexInSelection) { - var addressToRemove = selectedContacts[indexInSelection] - if (indexInSelection != -1) { - selectedContacts.splice(indexInSelection, 1) - contactRemovedFromSelection(addressToRemove) - } - } - function removeSelectedContactByAddress(address) { - var index = selectedContacts.indexOf(address) - if (index != -1) { - selectedContacts.splice(index, 1) - contactRemovedFromSelection(address) - } - } - function haveAddress(address){ - var index = magicSearchProxy.findFriendIndexByAddress(address) - return index != -1 - } - - function resetSelections(){ - mainItem.highlightedContact = null - favoritesList.currentIndex = -1 - contactsList.currentIndex = -1 - suggestionsList.currentIndex = -1 - } + 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 bool showFavorites: true // Display the favorites in the header + property bool hideSuggestions: false // Hide not stored contacts (not suggestions) + property string highlightText: searchText // Bold characters in Display name. + property var sourceFlags: LinphoneEnums.MagicSearchSource.All - function findNextList(item, count, direction){ - if(count == 3) return null - var nextItem - switch(item){ - case suggestionsList:nextItem=(direction > 0 ? favoritesList : contactsList);break; - case contactsList:nextItem=(direction > 0 ? suggestionsList : favoritesList);break; - case favoritesList:nextItem=(direction > 0 ? contactsList : suggestionsList);break; - default: return null - } - if( nextItem.model.count > 0) return nextItem - else return findNextList(nextItem, count+1, direction) - } - - function updatePosition(list){ - Utils.updatePosition(mainItem, list) - } - - onHighlightedContactChanged:{ - favoritesList.highlightedContact = highlightedContact - contactsList.highlightedContact = highlightedContact - suggestionsList.highlightedContact = highlightedContact - } - - onResultsReceived: { - loading = false - mainItem.contentY = 0 - } - onSearchBarTextChanged: { - if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) { - searchText = searchBarText.length === 0 ? "*" : searchBarText - } - } - onPauseSearchChanged: { - if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')){ - searchText = searchBarText.length === 0 ? "*" : searchBarText - } - } - onSearchTextChanged: loading = true - onAtYEndChanged: if(atYEnd) { - if( (contactsProxy.haveMore && contactList.expanded ) || mainItem.hideSuggestions) contactsProxy.displayMore() - else suggestionsProxy.displayMore() - } - Behavior on contentY{ - NumberAnimation { - duration: 500 - easing.type: Easing.OutExpo - } - } - Keys.onPressed: (event)=> { - if(!event.accepted){ - if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){ - var newItem - var direction = (event.key == Qt.Key_Up ? -1 : 1) - if(suggestionsList.activeFocus) newItem = findNextList(suggestionsList, 0, direction) - else if(contactsList.activeFocus) newItem = findNextList(contactsList, 0, direction) - else if(favoritesList.activeFocus) newItem = findNextList(favoritesList, 0, direction) - else newItem = findNextList(suggestionsList, 0, direction) - if(newItem){ - newItem.selectIndex(direction > 0 ? -1 : newItem.model.count - 1) - event.accepted = true - } - } - } - } - Component.onCompleted: { - if (confInfoGui) { - for(var i = 0; i < confInfoGui.core.participants.length; ++i) { - selectedContacts.push(confInfoGui.core.getParticipantAddressAt(i)); - } - } - } - - Connections { - target: SettingsCpp - onLdapConfigChanged: { - if (SettingsCpp.syncLdapContacts) - magicSearchProxy.forceUpdate() - } - } - - property MagicSearchProxy mainModel: MagicSearchProxy { - id: magicSearchProxy - searchText: mainItem.searchText - aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend - sourceFlags: mainItem.sourceFlags - onModelReset: { - mainItem.resetSelections() - mainItem.resultsReceived() - } - - onInitialized: { - if(mainItem.searchOnEmpty || searchText != '' ) { - mainItem.loading = true - forceUpdate() - } - } - } - + property bool displayNameCapitalization: true // Capitalize display name. - Control.ScrollBar.vertical: ScrollBar { - id: scrollbar - rightPadding: 8 * DefaultStyle.dp - topPadding: mainItem.haveFavorites ? 24 * DefaultStyle.dp : 0 // Avoid to be on top of collapse button - - active: true - interactive: true - policy: mainItem.contentHeight > mainItem.height ? Control.ScrollBar.AlwaysOn : Control.ScrollBar.AlwaysOff - } - - - ColumnLayout{ - id: contentsLayout - width: parent.width - spacing: 20 * DefaultStyle.dp - BusyIndicator { - Layout.alignment: Qt.AlignCenter - Layout.preferredHeight: visible ? 60 * DefaultStyle.dp : 0 - Layout.preferredWidth: 60 * DefaultStyle.dp - indicatorHeight: 60 * DefaultStyle.dp - indicatorWidth: 60 * DefaultStyle.dp - visible: mainItem.loading - indicatorColor: DefaultStyle.main1_500_main - } - - ContactListView{ - id: favoritesList - visible: contentHeight > 0 - Layout.fillWidth: true - Layout.preferredHeight: implicitHeight - interactive: false - highlightText: mainItem.highlightText - showActions: mainItem.showActions - showInitials: mainItem.showInitials - showContactMenu: mainItem.showContactMenu - showDefaultAddress: mainItem.showDefaultAddress - selectionEnabled: mainItem.selectionEnabled - multiSelectionEnabled: mainItem.multiSelectionEnabled - selectedContacts: mainItem.selectedContacts - title: qsTr('Favoris') - - onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact - onContactSelected: (contactGui) => { - mainItem.contactSelected(contactGui) - } - onUpdatePosition: mainItem.updatePosition(favoritesList) - onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} - onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} - onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} - - property MagicSearchProxy proxy: MagicSearchProxy { - parentProxy: mainItem.mainModel - filterType: MagicSearchProxy.FilteringTypes.Favorites - } - model : mainItem.showFavorites && (mainItem.searchBarText == ''|| mainItem.searchBarText == '*')? proxy : [] - } - - ContactListView{ - id: contactsList - visible: contentHeight > 0 - Layout.fillWidth: true - Layout.preferredHeight: implicitHeight - Layout.topMargin: favoritesList.height > 0 ? 4 * DefaultStyle.dp : 0 - interactive: false - highlightText: mainItem.highlightText - showActions: mainItem.showActions - showInitials: mainItem.showInitials - showContactMenu: mainItem.showContactMenu - showDefaultAddress: mainItem.showDefaultAddress - selectionEnabled: mainItem.selectionEnabled - multiSelectionEnabled: mainItem.multiSelectionEnabled - selectedContacts: mainItem.selectedContacts - title: qsTr('Contacts') - - onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact - onContactSelected: (contactGui) => { - mainItem.contactSelected(contactGui) - } - onUpdatePosition: mainItem.updatePosition(contactsList) - onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} - onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} - onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} - - model:MagicSearchProxy { - id: contactsProxy - parentProxy: mainItem.mainModel - filterType: MagicSearchProxy.FilteringTypes.App - | (mainItem.searchText != '*' && mainItem.searchText != '' || SettingsCpp.syncLdapContacts ? MagicSearchProxy.FilteringTypes.Ldap | MagicSearchProxy.FilteringTypes.CardDAV: 0) - initialDisplayItems: Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp)) - displayItemsStep: 3 * initialDisplayItems / 2 - onLocalFriendCreated: (index) => { - contactsList.selectIndex(index) - } - } - } - ContactListView{ - id: suggestionsList - visible: contentHeight > 0 - Layout.fillWidth: true - Layout.preferredHeight: implicitHeight - Layout.topMargin: contactsList.height + favoritesList.height > 0 ? 4 * DefaultStyle.dp : 0 - interactive: false - showInitials: false - highlightText: mainItem.highlightText - showActions: mainItem.showActions - showContactMenu: mainItem.showContactMenu - showDefaultAddress: mainItem.showDefaultAddress - selectionEnabled: mainItem.selectionEnabled - multiSelectionEnabled: mainItem.multiSelectionEnabled - selectedContacts: mainItem.selectedContacts - title: qsTr('Suggestions') - - onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact - onContactSelected: (contactGui) => { - mainItem.contactSelected(contactGui) - } - onUpdatePosition: mainItem.updatePosition(suggestionsList) - onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} - onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} - onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} - model:MagicSearchProxy { - id: suggestionsProxy - parentProxy: mainItem.mainModel - filterType: mainItem.hideSuggestions ? MagicSearchProxy.FilteringTypes.None : MagicSearchProxy.FilteringTypes.Other - initialDisplayItems: contactsProxy.haveMore && contactsList.expanded ? 0 : Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp)) - onInitialDisplayItemsChanged: maxDisplayItems = initialDisplayItems - displayItemsStep: 3 * initialDisplayItems / 2 - onModelReset: maxDisplayItems = initialDisplayItems - } - } - } + property bool selectionEnabled: true // Contact can be selected + property bool multiSelectionEnabled: false //Multiple items can be selected. + property list selectedContacts // List of default address on selected contacts. + //property FriendGui selectedContact//: model.getAt(currentIndex) || null + property FriendGui highlightedContact + + property bool searchOnEmpty: true + property bool loading: false + property bool pauseSearch: false // true = don't search on text change + + // Model properties + // set searchBarText without specifying a model to bold + // matching names + property string searchBarText + property string searchText// Binding is done on searchBarTextChanged + property ConferenceInfoGui confInfoGui + + property bool haveFavorites: false + property bool haveContacts: count > 0 + property int sectionsPixelSize: 16 * DefaultStyle.dp + property int sectionsWeight: 800 * DefaultStyle.dp + property int sectionsSpacing: 18 * DefaultStyle.dp + property int busyIndicatorSize: 40 * DefaultStyle.dp + + property int itemsRightMargin: 39 * DefaultStyle.dp + property int count: contactsList.count + suggestionsList.count + favoritesList.count + + contentHeight: contentsLayout.height + rightMargin: itemsRightMargin + + signal contactStarredChanged() + signal contactDeletionRequested(FriendGui contact) + signal contactAddedToSelection(string address) + signal contactRemovedFromSelection(string address) + signal contactSelected(FriendGui contact) + + function selectContact(address) { + var index = contactsProxy.loadUntil(address)// Be sure to have this address in proxy if it exists + if (index != -1) { + contactsList.selectIndex(index) + } + return index + + } + function addContactToSelection(address) { + if (multiSelectionEnabled) { + var indexInSelection = selectedContacts.indexOf(address) + if (indexInSelection == -1) { + selectedContacts.push(address) + contactAddedToSelection(address) + } + } + } + function removeContactFromSelection(indexInSelection) { + var addressToRemove = selectedContacts[indexInSelection] + if (indexInSelection != -1) { + selectedContacts.splice(indexInSelection, 1) + contactRemovedFromSelection(addressToRemove) + } + } + function removeSelectedContactByAddress(address) { + var index = selectedContacts.indexOf(address) + if (index != -1) { + selectedContacts.splice(index, 1) + contactRemovedFromSelection(address) + } + } + function haveAddress(address){ + var index = magicSearchProxy.findFriendIndexByAddress(address) + return index != -1 + } + + function resetSelections(){ + mainItem.highlightedContact = null + favoritesList.currentIndex = -1 + contactsList.currentIndex = -1 + suggestionsList.currentIndex = -1 + } + + function findNextList(item, count, direction){ + if(count == 3) return null + var nextItem + switch(item){ + case suggestionsList:nextItem=(direction > 0 ? favoritesList : contactsList);break; + case contactsList:nextItem=(direction > 0 ? suggestionsList : favoritesList);break; + case favoritesList:nextItem=(direction > 0 ? contactsList : suggestionsList);break; + default: return null + } + if( nextItem.model.count > 0) return nextItem + else return findNextList(nextItem, count+1, direction) + } + + function updatePosition(list){ + Utils.updatePosition(mainItem, list) + } + + onHighlightedContactChanged:{ + favoritesList.highlightedContact = highlightedContact + contactsList.highlightedContact = highlightedContact + suggestionsList.highlightedContact = highlightedContact + } + + onSearchBarTextChanged: { + if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) { + console.log("change search text") + searchText = searchBarText.length === 0 ? "*" : searchBarText + } + } + onPauseSearchChanged: { + if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')){ + searchText = searchBarText.length === 0 ? "*" : searchBarText + } + } + onSearchTextChanged: { + console.log("search texte changed, loading...") + loading = true + } + + Keys.onPressed: (event)=> { + if(!event.accepted){ + if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){ + var newItem + var direction = (event.key == Qt.Key_Up ? -1 : 1) + if(suggestionsList.activeFocus) newItem = findNextList(suggestionsList, 0, direction) + else if(contactsList.activeFocus) newItem = findNextList(contactsList, 0, direction) + else if(favoritesList.activeFocus) newItem = findNextList(favoritesList, 0, direction) + else newItem = findNextList(suggestionsList, 0, direction) + if(newItem){ + newItem.selectIndex(direction > 0 ? -1 : newItem.model.count - 1) + event.accepted = true + } + } + } + } + Component.onCompleted: { + if (confInfoGui) { + for(var i = 0; i < confInfoGui.core.participants.length; ++i) { + selectedContacts.push(confInfoGui.core.getParticipantAddressAt(i)); + } + } + } + + Connections { + target: SettingsCpp + onLdapConfigChanged: { + if (SettingsCpp.syncLdapContacts) + magicSearchProxy.forceUpdate() + } + } + + property MagicSearchProxy mainModel: MagicSearchProxy { + id: magicSearchProxy + searchText: mainItem.searchText + aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend + sourceFlags: mainItem.sourceFlags + onModelReset: { + mainItem.resetSelections() + + } + onResultsProcessed: { + console.log("result processed list view") + mainItem.loading = false + mainItem.contentY = 0 + } + + onInitialized: { + if(mainItem.searchOnEmpty || searchText != '' ) { + mainItem.loading = true + forceUpdate() + } + } + } + + onAtYEndChanged: if(atYEnd) { + if( (contactsProxy.haveMore && contactList.expanded ) || mainItem.hideSuggestions) contactsProxy.displayMore() + else suggestionsProxy.displayMore() + } + Behavior on contentY{ + NumberAnimation { + duration: 500 + easing.type: Easing.OutExpo + } + } + + Control.ScrollBar.vertical: ScrollBar { + id: scrollbar + z: 1 + topPadding: 24 * DefaultStyle.dp // Avoid to be on top of collapse button + active: true + interactive: true + visible: mainItem.contentHeight > mainItem.height + policy: Control.ScrollBar.AsNeeded + } + + ColumnLayout { + id: contentsLayout + width: mainItem.width + spacing: 0//20 * DefaultStyle.dp + + BusyIndicator { + id: busyIndicator + visible: mainItem.loading + width: mainItem.busyIndicatorSize + height: mainItem.busyIndicatorSize + Layout.preferredWidth: mainItem.busyIndicatorSize + Layout.preferredHeight: mainItem.busyIndicatorSize + Layout.alignment: Qt.AlignCenter | Qt.AlignVCenter + } + + ContactListView{ + id: favoritesList + visible: contentHeight > 0 + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + sectionsWeight: mainItem.sectionsWeight + sectionsPixelSize: mainItem.sectionsPixelSize + interactive: false + highlightText: mainItem.highlightText + showActions: mainItem.showActions + showInitials: mainItem.showInitials + showContactMenu: mainItem.showContactMenu + showDefaultAddress: mainItem.showDefaultAddress + selectionEnabled: mainItem.selectionEnabled + multiSelectionEnabled: mainItem.multiSelectionEnabled + selectedContacts: mainItem.selectedContacts + title: qsTr('Favoris') + itemsRightMargin: mainItem.itemsRightMargin + + onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact + onContactSelected: (contactGui) => { + mainItem.contactSelected(contactGui) + } + onUpdatePosition: mainItem.updatePosition(favoritesList) + onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} + onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} + onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} + + property MagicSearchProxy proxy: MagicSearchProxy { + parentProxy: mainItem.mainModel + filterType: MagicSearchProxy.FilteringTypes.Favorites + } + model : mainItem.showFavorites && (mainItem.searchBarText == ''|| mainItem.searchBarText == '*')? proxy : [] + } + + ContactListView{ + id: contactsList + visible: contentHeight > 0 + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + Layout.topMargin: favoritesList.height > 0 ? 4 * DefaultStyle.dp : 0 + interactive: false + highlightText: mainItem.highlightText + showActions: mainItem.showActions + showInitials: mainItem.showInitials + showContactMenu: mainItem.showContactMenu + showDefaultAddress: mainItem.showDefaultAddress + selectionEnabled: mainItem.selectionEnabled + multiSelectionEnabled: mainItem.multiSelectionEnabled + selectedContacts: mainItem.selectedContacts + itemsRightMargin: mainItem.itemsRightMargin + title: qsTr('Contacts') + + onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact + onContactSelected: (contactGui) => { + mainItem.contactSelected(contactGui) + } + onUpdatePosition: mainItem.updatePosition(contactsList) + onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} + onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} + onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} + + model:MagicSearchProxy { + id: contactsProxy + parentProxy: mainItem.mainModel + filterType: MagicSearchProxy.FilteringTypes.App + | (mainItem.searchText != '*' && mainItem.searchText != '' || SettingsCpp.syncLdapContacts ? MagicSearchProxy.FilteringTypes.Ldap | MagicSearchProxy.FilteringTypes.CardDAV: 0) + initialDisplayItems: Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp)) + displayItemsStep: 3 * initialDisplayItems / 2 + onLocalFriendCreated: (index) => { + contactsList.selectIndex(index) + } + } + } + ContactListView{ + id: suggestionsList + visible: contentHeight > 0 + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + Layout.topMargin: contactsList.height + favoritesList.height > 0 ? 4 * DefaultStyle.dp : 0 + interactive: false + showInitials: false + highlightText: mainItem.highlightText + showActions: mainItem.showActions + showContactMenu: mainItem.showContactMenu + showDefaultAddress: mainItem.showDefaultAddress + selectionEnabled: mainItem.selectionEnabled + multiSelectionEnabled: mainItem.multiSelectionEnabled + selectedContacts: mainItem.selectedContacts + title: qsTr('Suggestions') + itemsRightMargin: mainItem.itemsRightMargin + + onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact + onContactSelected: (contactGui) => { + mainItem.contactSelected(contactGui) + } + onUpdatePosition: mainItem.updatePosition(suggestionsList) + onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} + onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} + onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} + model:MagicSearchProxy { + id: suggestionsProxy + parentProxy: mainItem.mainModel + filterType: mainItem.hideSuggestions ? MagicSearchProxy.FilteringTypes.None : MagicSearchProxy.FilteringTypes.Other + initialDisplayItems: contactsProxy.haveMore && contactsList.expanded ? 0 : Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp)) + onInitialDisplayItemsChanged: maxDisplayItems = initialDisplayItems + displayItemsStep: 3 * initialDisplayItems / 2 + onModelReset: maxDisplayItems = initialDisplayItems + } + } + } } diff --git a/Linphone/view/Control/Display/Contact/ContactListItem.qml b/Linphone/view/Control/Display/Contact/ContactListItem.qml index c8b60e7c0..94ffd87ff 100644 --- a/Linphone/view/Control/Display/Contact/ContactListItem.qml +++ b/Linphone/view/Control/Display/Contact/ContactListItem.qml @@ -114,7 +114,7 @@ FocusScope { id: actionButtons visible: mainItem.showActions spacing: visible ? 10 * DefaultStyle.dp : 0 - Button { + IconButton { id: callButton Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp @@ -128,7 +128,7 @@ FocusScope { KeyNavigation.left: chatButton KeyNavigation.right: videoCallButton } - Button { + IconButton { id: videoCallButton Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp @@ -142,7 +142,7 @@ FocusScope { KeyNavigation.left: callButton KeyNavigation.right: chatButton } - Button { + IconButton { id: chatButton visible: actionButtons.visible && !SettingsCpp.disableChatFeature Layout.preferredWidth: 45 * DefaultStyle.dp diff --git a/Linphone/view/Control/Display/Contact/ContactListView.qml b/Linphone/view/Control/Display/Contact/ContactListView.qml index f07e91d99..8dd69ad25 100644 --- a/Linphone/view/Control/Display/Contact/ContactListView.qml +++ b/Linphone/view/Control/Display/Contact/ContactListView.qml @@ -45,7 +45,6 @@ ListView { property bool expanded: true property int headerHeight: headerItem?.height - signal resultsReceived() signal contactDeletionRequested(FriendGui contact) signal contactSelected(FriendGui contact) // Click/Space/Enter signal addContactToSelection(var address) diff --git a/Linphone/view/Control/Display/EffectImage.qml b/Linphone/view/Control/Display/EffectImage.qml index 2ecd403bf..c05162931 100644 --- a/Linphone/view/Control/Display/EffectImage.qml +++ b/Linphone/view/Control/Display/EffectImage.qml @@ -45,6 +45,7 @@ Loader { MultiEffect { id: effect2 + enabled: effectEnabled visible: mainItem.useColor property bool effectEnabled: mainItem.useColor anchors.fill: effect diff --git a/Linphone/view/Page/Layout/Main/MainLayout.qml b/Linphone/view/Page/Layout/Main/MainLayout.qml index 2104b97b9..b6dec20b5 100644 --- a/Linphone/view/Page/Layout/Main/MainLayout.qml +++ b/Linphone/view/Page/Layout/Main/MainLayout.qml @@ -191,21 +191,22 @@ Item { id: listPopup width: magicSearchBar.width property int maxHeight: 400 * DefaultStyle.dp - property bool displayScrollbar: contactList.contentHeight + topPadding + bottomPadding> maxHeight - height: contactList.haveContacts ? Math.min(contactList.contentHeight + topPadding + bottomPadding, maxHeight) : 0 + property bool displayScrollbar: contactList.height > maxHeight + height: Math.min(contactList.contentHeight, maxHeight) + topPadding + bottomPadding y: magicSearchBar.height - // closePolicy: Popup.NoAutoClose - topPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 0 - bottomPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 0 - rightPadding: 10 * DefaultStyle.dp + closePolicy: Popup.CloseOnEscape + topPadding: 20 * DefaultStyle.dp + bottomPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 10 * DefaultStyle.dp + rightPadding: 8 * DefaultStyle.dp leftPadding: 20 * DefaultStyle.dp - + visible: magicSearchBar.text.length != 0 + background: Item { anchors.fill: parent Rectangle { id: popupBg radius: 16 * DefaultStyle.dp - color: DefaultStyle.grey_0 + color: DefaultStyle.grey_0 anchors.fill: parent border.color: DefaultStyle.main1_500_main border.width: contactList.activeFocus ? 2 : 0 @@ -218,25 +219,12 @@ Item { shadowBlur: 0.1 shadowColor: DefaultStyle.grey_1000 shadowOpacity: 0.1 - } - ScrollBar { - id: scrollbar - Component.onCompleted: x = -10 * DefaultStyle.dp - policy: Control.ScrollBar.AsNeeded// Don't work as expected - visible: listPopup.displayScrollbar - interactive: true - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.margins: 10 * DefaultStyle.dp - - } + } } - contentItem: AllContactListView { - id: contactList - visible: !loading && magicSearchBar.text.length != 0 - Layout.preferredHeight: visible ? contentHeight : 0 - Layout.fillWidth: true + + contentItem: AllContactListView { + id: contactList + width: listPopup.width - listPopup.leftPadding - listPopup.rightPadding itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin) showInitials: false showContactMenu: false @@ -250,8 +238,7 @@ Item { sectionsWeight: 700 * DefaultStyle.dp sectionsSpacing: 5 * DefaultStyle.dp - Control.ScrollBar.vertical: scrollbar - searchBarText: magicSearchBar.text + searchBarText: magicSearchBar.text } } } diff --git a/Linphone/view/Page/Main/Contact/ContactPage.qml b/Linphone/view/Page/Main/Contact/ContactPage.qml index c219d55ee..7375273d5 100644 --- a/Linphone/view/Page/Main/Contact/ContactPage.qml +++ b/Linphone/view/Page/Main/Contact/ContactPage.qml @@ -227,6 +227,7 @@ AbstractMainPage { ColumnLayout { id: content spacing: 15 * DefaultStyle.dp + Layout.leftMargin: 45 * DefaultStyle.dp Text { visible: !contactList.loading && !contactList.haveContacts Layout.alignment: Qt.AlignHCenter @@ -241,7 +242,7 @@ AbstractMainPage { id: contactList Layout.fillWidth: true Layout.fillHeight: true - Layout.leftMargin: 45 * DefaultStyle.dp + Layout.rightMargin: 8 * DefaultStyle.dp searchBarText: searchBar.text hideSuggestions: true showDefaultAddress: false