fix slow loading when many friends

This commit is contained in:
gaelle 2025-02-21 15:57:56 +01:00
parent b4b573a027
commit c1013baac5
14 changed files with 384 additions and 384 deletions

View file

@ -59,7 +59,8 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
auto itemCore = item.objectCast<FriendCore>(); auto itemCore = item.objectCast<FriendCore>();
return itemCore->getDefaultAddress().length() > 0 && return itemCore->getDefaultAddress().length() > 0 &&
itemCore->getDefaultAddress() == friendCore->getDefaultAddress() || itemCore->getDefaultAddress() == friendCore->getDefaultAddress() ||
itemCore->getFriendModel()->getFriend() == friendCore->getFriendModel()->getFriend(); itemCore->getFriendModel() && friendCore->getFriendModel() &&
itemCore->getFriendModel()->getFriend() == friendCore->getFriendModel()->getFriend();
}); });
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));
@ -117,8 +118,9 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
address->asString())); // linphone Friend object remove specific address. address->asString())); // linphone Friend object remove specific address.
contacts->append(contact); contacts->append(contact);
} else if (!it->getPhoneNumber().empty()) { } else if (!it->getPhoneNumber().empty()) {
auto phoneNumber = it->getPhoneNumber();
linphoneFriend = CoreModel::getInstance()->getCore()->createFriend(); linphoneFriend = CoreModel::getInstance()->getCore()->createFriend();
linphoneFriend->setAddress(address); linphoneFriend->addPhoneNumber(phoneNumber);
contact = FriendCore::create(linphoneFriend, isStored, it->getSourceFlags()); contact = FriendCore::create(linphoneFriend, isStored, it->getSourceFlags());
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()));
@ -128,6 +130,7 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
mModelConnection->invokeToCore([this, contacts]() { mModelConnection->invokeToCore([this, contacts]() {
setResults(*contacts); setResults(*contacts);
delete contacts; delete contacts;
emit resultsProcessed();
}); });
}); });
qDebug() << log().arg("Initialized"); qDebug() << log().arg("Initialized");

View file

@ -72,6 +72,8 @@ signals:
void friendCreated(int index, FriendGui *data); void friendCreated(int index, FriendGui *data);
void friendStarredChanged(); void friendStarredChanged();
void resultsProcessed();
void initialized(); void initialized();
private: private:

View file

@ -25,11 +25,13 @@
#include "core/friend/FriendCore.hpp" #include "core/friend/FriendCore.hpp"
MagicSearchProxy::MagicSearchProxy(QObject *parent) : LimitProxy(parent) { MagicSearchProxy::MagicSearchProxy(QObject *parent) : LimitProxy(parent) {
setList(MagicSearchList::create()); auto magicSearchList = MagicSearchList::create();
setList(magicSearchList);
connect(this, &MagicSearchProxy::forceUpdate, [this] { connect(this, &MagicSearchProxy::forceUpdate, [this] {
if (mList) emit mList->lSearch(mSearchText, getSourceFlags(), getAggregationFlag(), getMaxResults()); 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);
connect(magicSearchList.get(), &MagicSearchList::resultsProcessed, this, &MagicSearchProxy::resultsProcessed);
} }
MagicSearchProxy::~MagicSearchProxy() { MagicSearchProxy::~MagicSearchProxy() {

View file

@ -82,6 +82,7 @@ signals:
void parentProxyChanged(); void parentProxyChanged();
void hideListProxyChanged(); void hideListProxyChanged();
void initialized(); void initialized();
void resultsProcessed();
protected: protected:
MagicSearchProxy *mParentProxy = nullptr; MagicSearchProxy *mParentProxy = nullptr;

View file

@ -81,31 +81,23 @@ void MagicSearchModel::onSearchResultsReceived(const std::shared_ptr<linphone::M
auto appFriends = ToolModel::getAppFriendList(); auto appFriends = ToolModel::getAppFriendList();
auto ldapFriends = ToolModel::getLdapFriendList(); auto ldapFriends = ToolModel::getLdapFriendList();
std::list<std::shared_ptr<linphone::SearchResult>> finalResults; std::list<std::shared_ptr<linphone::SearchResult>> finalResults;
emit searchResultsReceived(results);
for (auto result : results) { for (auto result : results) {
auto f = result->getFriend(); auto f = result->getFriend();
auto fList = f ? f->getFriendList() : nullptr; auto fList = f ? f->getFriendList() : nullptr;
qDebug() << log().arg("") << (f ? f->getName().c_str() : "NoFriend") << ", " // qDebug() << log().arg("") << (f ? f->getName().c_str() : "NoFriend") << ", "
<< (result->getAddress() ? result->getAddress()->asString().c_str() : "NoAddr") << " / " // << (result->getAddress() ? result->getAddress()->asString().c_str() : "NoAddr") << " / "
<< (fList ? fList->getDisplayName().c_str() : "NoList") << result->getSourceFlags() << " / " // << (fList ? fList->getDisplayName().c_str() : "NoList") << result->getSourceFlags() << " / "
<< (f ? f.get() : nullptr); // << (f ? f.get() : nullptr);
bool isLdap = (result->getSourceFlags() & (int)linphone::MagicSearch::Source::LdapServers) != 0; bool isLdap = (result->getSourceFlags() & (int)linphone::MagicSearch::Source::LdapServers) != 0;
// Do not add it into ldap_friends if it already exists in app_friends. // Do not add it into ldap_friends if it already exists in app_friends.
if (isLdap && f && (!fList || fList->getDisplayName() != "app_friends") && if (isLdap && f && (!fList || fList->getDisplayName() != "app_friends")) { // Double check because of SDK merging that lead to
!ToolModel::friendIsInFriendList(appFriends, f)) { // Double check because of SDK merging that lead to // use a ldap result as of app_friends/ldap_friends.
// use a ldap result as of app_friends/ldap_friends. updateFriendListWithFriend(f, ldapFriends);
updateFriendListWithFriend(f, ToolModel::getLdapFriendList());
} }
auto resultIt =
std::find_if(finalResults.begin(), finalResults.end(), [result](std::shared_ptr<linphone::SearchResult> 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<linphone::MagicSearch> &magicSearch, void MagicSearchModel::onMoreResultsAvailable(const std::shared_ptr<linphone::MagicSearch> &magicSearch,

View file

@ -296,13 +296,12 @@ std::shared_ptr<linphone::FriendList> ToolModel::getLdapFriendList() {
} }
bool ToolModel::friendIsInFriendList(const std::shared_ptr<linphone::FriendList> &friendList, bool ToolModel::friendIsInFriendList(const std::shared_ptr<linphone::FriendList> &friendList,
const std::shared_ptr<linphone::Friend> &f) { const std::shared_ptr<linphone::Friend> &f) {
for (auto contact : friendList->getFriends()) { auto friends = friendList->getFriends();
if (f == contact) { auto it = std::find_if(friends.begin(), friends.end(), [f] (std::shared_ptr<linphone::Friend> linFriend) {
return true; return linFriend == f;
} });
} return (it != friends.end());
return false;
} }
// Load downloaded codecs like OpenH264 (needs to be after core is created and has loaded its plugins, as // Load downloaded codecs like OpenH264 (needs to be after core is created and has loaded its plugins, as

View file

@ -6,9 +6,9 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Control/Button/CheckBox.qml view/Control/Button/CheckBox.qml
view/Control/Button/ComboBox.qml view/Control/Button/ComboBox.qml
view/Control/Button/HelpIconLabelButton.qml view/Control/Button/HelpIconLabelButton.qml
view/Control/Button/IconButton.qml view/Control/Button/IconButton.qml
view/Control/Button/IconLabelButton.qml view/Control/Button/IconLabelButton.qml
view/Control/Button/BigButton.qml view/Control/Button/BigButton.qml
view/Control/Button/RoundButton.qml view/Control/Button/RoundButton.qml
view/Control/Button/MediumButton.qml view/Control/Button/MediumButton.qml
view/Control/Button/SmallButton.qml view/Control/Button/SmallButton.qml

View file

@ -7,9 +7,10 @@ import Linphone
Control.ScrollBar { Control.ScrollBar {
id: mainItem id: mainItem
padding: 0 padding: 0
property color color: DefaultStyle.grey_850
contentItem: Rectangle { contentItem: Rectangle {
implicitWidth: 6 * DefaultStyle.dp implicitWidth: 6 * DefaultStyle.dp
radius: 32 * DefaultStyle.dp radius: 32 * DefaultStyle.dp
color: DefaultStyle.grey_850 color: mainItem.color
} }
} }

View file

@ -8,328 +8,340 @@ import ConstantsCpp 1.0
import SettingsCpp import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
Flickable{ Flickable {
id: mainItem id: mainItem
property bool showInitials: true // Display Initials of Display name. flickableDirection: Flickable.VerticalFlick
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 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 selectionEnabled: true // Contact can be selected property bool displayNameCapitalization: true // Capitalize display name.
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 FriendGui highlightedContact
property bool searchOnEmpty: true property bool selectionEnabled: true // Contact can be selected
property bool loading: false property bool multiSelectionEnabled: false //Multiple items can be selected.
property bool pauseSearch: false // true = don't search on text change property list<string> selectedContacts // List of default address on selected contacts.
//property FriendGui selectedContact//: model.getAt(currentIndex) || null
property FriendGui highlightedContact
// Model properties property bool searchOnEmpty: true
// set searchBarText without specifying a model to bold property bool loading: false
// matching names property bool pauseSearch: false // true = don't search on text change
property string searchBarText
property string searchText// Binding is done on searchBarTextChanged
property ConferenceInfoGui confInfoGui
property bool haveFavorites: false // Model properties
property bool haveContacts: count > 0 // set searchBarText without specifying a model to bold
property int sectionsPixelSize: 16 * DefaultStyle.dp // matching names
property int sectionsWeight: 800 * DefaultStyle.dp property string searchBarText
property int sectionsSpacing: 18 * DefaultStyle.dp property string searchText// Binding is done on searchBarTextChanged
property ConferenceInfoGui confInfoGui
property int itemsRightMargin: 39 * DefaultStyle.dp property bool haveFavorites: false
property int count: contactsList.count + suggestionsList.count + favoritesList.count 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
signal resultsReceived() property int itemsRightMargin: 39 * DefaultStyle.dp
signal contactStarredChanged() property int count: contactsList.count + suggestionsList.count + favoritesList.count
signal contactDeletionRequested(FriendGui contact)
signal contactAddedToSelection(string address)
signal contactRemovedFromSelection(string address)
signal contactSelected(FriendGui contact)
contentWidth: width contentHeight: contentsLayout.height
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) { function selectContact(address) {
var index = contactsProxy.loadUntil(address)// Be sure to have this address in proxy if it exists var index = contactsProxy.loadUntil(address)// Be sure to have this address in proxy if it exists
if (index != -1) { if (index != -1) {
contactsList.selectIndex(index) contactsList.selectIndex(index)
} }
return index return index
} }
function addContactToSelection(address) { function addContactToSelection(address) {
if (multiSelectionEnabled) { if (multiSelectionEnabled) {
var indexInSelection = selectedContacts.indexOf(address) var indexInSelection = selectedContacts.indexOf(address)
if (indexInSelection == -1) { if (indexInSelection == -1) {
selectedContacts.push(address) selectedContacts.push(address)
contactAddedToSelection(address) contactAddedToSelection(address)
} }
} }
} }
function removeContactFromSelection(indexInSelection) { function removeContactFromSelection(indexInSelection) {
var addressToRemove = selectedContacts[indexInSelection] var addressToRemove = selectedContacts[indexInSelection]
if (indexInSelection != -1) { if (indexInSelection != -1) {
selectedContacts.splice(indexInSelection, 1) selectedContacts.splice(indexInSelection, 1)
contactRemovedFromSelection(addressToRemove) contactRemovedFromSelection(addressToRemove)
} }
} }
function removeSelectedContactByAddress(address) { function removeSelectedContactByAddress(address) {
var index = selectedContacts.indexOf(address) var index = selectedContacts.indexOf(address)
if (index != -1) { if (index != -1) {
selectedContacts.splice(index, 1) selectedContacts.splice(index, 1)
contactRemovedFromSelection(address) contactRemovedFromSelection(address)
} }
} }
function haveAddress(address){ function haveAddress(address){
var index = magicSearchProxy.findFriendIndexByAddress(address) var index = magicSearchProxy.findFriendIndexByAddress(address)
return index != -1 return index != -1
} }
function resetSelections(){ function resetSelections(){
mainItem.highlightedContact = null mainItem.highlightedContact = null
favoritesList.currentIndex = -1 favoritesList.currentIndex = -1
contactsList.currentIndex = -1 contactsList.currentIndex = -1
suggestionsList.currentIndex = -1 suggestionsList.currentIndex = -1
} }
function findNextList(item, count, direction){ function findNextList(item, count, direction){
if(count == 3) return null if(count == 3) return null
var nextItem var nextItem
switch(item){ switch(item){
case suggestionsList:nextItem=(direction > 0 ? favoritesList : contactsList);break; case suggestionsList:nextItem=(direction > 0 ? favoritesList : contactsList);break;
case contactsList:nextItem=(direction > 0 ? suggestionsList : favoritesList);break; case contactsList:nextItem=(direction > 0 ? suggestionsList : favoritesList);break;
case favoritesList:nextItem=(direction > 0 ? contactsList : suggestionsList);break; case favoritesList:nextItem=(direction > 0 ? contactsList : suggestionsList);break;
default: return null default: return null
} }
if( nextItem.model.count > 0) return nextItem if( nextItem.model.count > 0) return nextItem
else return findNextList(nextItem, count+1, direction) else return findNextList(nextItem, count+1, direction)
} }
function updatePosition(list){ function updatePosition(list){
Utils.updatePosition(mainItem, list) Utils.updatePosition(mainItem, list)
} }
onHighlightedContactChanged:{ onHighlightedContactChanged:{
favoritesList.highlightedContact = highlightedContact favoritesList.highlightedContact = highlightedContact
contactsList.highlightedContact = highlightedContact contactsList.highlightedContact = highlightedContact
suggestionsList.highlightedContact = highlightedContact suggestionsList.highlightedContact = highlightedContact
} }
onResultsReceived: { onSearchBarTextChanged: {
loading = false if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) {
mainItem.contentY = 0 console.log("change search text")
} searchText = searchBarText.length === 0 ? "*" : searchBarText
onSearchBarTextChanged: { }
if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) { }
searchText = searchBarText.length === 0 ? "*" : searchBarText onPauseSearchChanged: {
} if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')){
} 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
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 { Keys.onPressed: (event)=> {
target: SettingsCpp if(!event.accepted){
onLdapConfigChanged: { if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){
if (SettingsCpp.syncLdapContacts) var newItem
magicSearchProxy.forceUpdate() 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));
}
}
}
property MagicSearchProxy mainModel: MagicSearchProxy { Connections {
id: magicSearchProxy target: SettingsCpp
searchText: mainItem.searchText onLdapConfigChanged: {
aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend if (SettingsCpp.syncLdapContacts)
sourceFlags: mainItem.sourceFlags magicSearchProxy.forceUpdate()
onModelReset: { }
mainItem.resetSelections() }
mainItem.resultsReceived()
}
onInitialized: { property MagicSearchProxy mainModel: MagicSearchProxy {
if(mainItem.searchOnEmpty || searchText != '' ) { id: magicSearchProxy
mainItem.loading = true searchText: mainItem.searchText
forceUpdate() aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
} sourceFlags: mainItem.sourceFlags
} onModelReset: {
} mainItem.resetSelections()
}
onResultsProcessed: {
console.log("result processed list view")
mainItem.loading = false
mainItem.contentY = 0
}
Control.ScrollBar.vertical: ScrollBar { onInitialized: {
id: scrollbar if(mainItem.searchOnEmpty || searchText != '' ) {
rightPadding: 8 * DefaultStyle.dp mainItem.loading = true
topPadding: mainItem.haveFavorites ? 24 * DefaultStyle.dp : 0 // Avoid to be on top of collapse button forceUpdate()
}
}
}
active: true onAtYEndChanged: if(atYEnd) {
interactive: true if( (contactsProxy.haveMore && contactList.expanded ) || mainItem.hideSuggestions) contactsProxy.displayMore()
policy: mainItem.contentHeight > mainItem.height ? Control.ScrollBar.AlwaysOn : Control.ScrollBar.AlwaysOff 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{ ColumnLayout {
id: contentsLayout id: contentsLayout
width: parent.width width: mainItem.width
spacing: 20 * DefaultStyle.dp spacing: 0//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{ BusyIndicator {
id: favoritesList id: busyIndicator
visible: contentHeight > 0 visible: mainItem.loading
Layout.fillWidth: true width: mainItem.busyIndicatorSize
Layout.preferredHeight: implicitHeight height: mainItem.busyIndicatorSize
interactive: false Layout.preferredWidth: mainItem.busyIndicatorSize
highlightText: mainItem.highlightText Layout.preferredHeight: mainItem.busyIndicatorSize
showActions: mainItem.showActions Layout.alignment: Qt.AlignCenter | Qt.AlignVCenter
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 ContactListView{
onContactSelected: (contactGui) => { id: favoritesList
mainItem.contactSelected(contactGui) visible: contentHeight > 0
} Layout.fillWidth: true
onUpdatePosition: mainItem.updatePosition(favoritesList) Layout.preferredHeight: implicitHeight
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} sectionsWeight: mainItem.sectionsWeight
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} sectionsPixelSize: mainItem.sectionsPixelSize
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} 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
property MagicSearchProxy proxy: MagicSearchProxy { onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact
parentProxy: mainItem.mainModel onContactSelected: (contactGui) => {
filterType: MagicSearchProxy.FilteringTypes.Favorites mainItem.contactSelected(contactGui)
} }
model : mainItem.showFavorites && (mainItem.searchBarText == ''|| mainItem.searchBarText == '*')? proxy : [] onUpdatePosition: mainItem.updatePosition(favoritesList)
} onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)}
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)}
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)}
ContactListView{ property MagicSearchProxy proxy: MagicSearchProxy {
id: contactsList parentProxy: mainItem.mainModel
visible: contentHeight > 0 filterType: MagicSearchProxy.FilteringTypes.Favorites
Layout.fillWidth: true }
Layout.preferredHeight: implicitHeight model : mainItem.showFavorites && (mainItem.searchBarText == ''|| mainItem.searchBarText == '*')? proxy : []
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 ContactListView{
onContactSelected: (contactGui) => { id: contactsList
mainItem.contactSelected(contactGui) visible: contentHeight > 0
} Layout.fillWidth: true
onUpdatePosition: mainItem.updatePosition(contactsList) Layout.preferredHeight: implicitHeight
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} Layout.topMargin: favoritesList.height > 0 ? 4 * DefaultStyle.dp : 0
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} interactive: false
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} 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')
model:MagicSearchProxy { onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact
id: contactsProxy onContactSelected: (contactGui) => {
parentProxy: mainItem.mainModel mainItem.contactSelected(contactGui)
filterType: MagicSearchProxy.FilteringTypes.App }
| (mainItem.searchText != '*' && mainItem.searchText != '' || SettingsCpp.syncLdapContacts ? MagicSearchProxy.FilteringTypes.Ldap | MagicSearchProxy.FilteringTypes.CardDAV: 0) onUpdatePosition: mainItem.updatePosition(contactsList)
initialDisplayItems: Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp)) onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)}
displayItemsStep: 3 * initialDisplayItems / 2 onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)}
onLocalFriendCreated: (index) => { onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(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 model:MagicSearchProxy {
onContactSelected: (contactGui) => { id: contactsProxy
mainItem.contactSelected(contactGui) parentProxy: mainItem.mainModel
} filterType: MagicSearchProxy.FilteringTypes.App
onUpdatePosition: mainItem.updatePosition(suggestionsList) | (mainItem.searchText != '*' && mainItem.searchText != '' || SettingsCpp.syncLdapContacts ? MagicSearchProxy.FilteringTypes.Ldap | MagicSearchProxy.FilteringTypes.CardDAV: 0)
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} initialDisplayItems: Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp))
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} displayItemsStep: 3 * initialDisplayItems / 2
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} onLocalFriendCreated: (index) => {
model:MagicSearchProxy { contactsList.selectIndex(index)
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)) ContactListView{
onInitialDisplayItemsChanged: maxDisplayItems = initialDisplayItems id: suggestionsList
displayItemsStep: 3 * initialDisplayItems / 2 visible: contentHeight > 0
onModelReset: maxDisplayItems = initialDisplayItems 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
}
}
}
} }

View file

@ -114,7 +114,7 @@ FocusScope {
id: actionButtons id: actionButtons
visible: mainItem.showActions visible: mainItem.showActions
spacing: visible ? 10 * DefaultStyle.dp : 0 spacing: visible ? 10 * DefaultStyle.dp : 0
Button { IconButton {
id: callButton id: callButton
Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp
@ -128,7 +128,7 @@ FocusScope {
KeyNavigation.left: chatButton KeyNavigation.left: chatButton
KeyNavigation.right: videoCallButton KeyNavigation.right: videoCallButton
} }
Button { IconButton {
id: videoCallButton id: videoCallButton
Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp
@ -142,7 +142,7 @@ FocusScope {
KeyNavigation.left: callButton KeyNavigation.left: callButton
KeyNavigation.right: chatButton KeyNavigation.right: chatButton
} }
Button { IconButton {
id: chatButton id: chatButton
visible: actionButtons.visible && !SettingsCpp.disableChatFeature visible: actionButtons.visible && !SettingsCpp.disableChatFeature
Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredWidth: 45 * DefaultStyle.dp

View file

@ -45,7 +45,6 @@ ListView {
property bool expanded: true property bool expanded: true
property int headerHeight: headerItem?.height property int headerHeight: headerItem?.height
signal resultsReceived()
signal contactDeletionRequested(FriendGui contact) signal contactDeletionRequested(FriendGui contact)
signal contactSelected(FriendGui contact) // Click/Space/Enter signal contactSelected(FriendGui contact) // Click/Space/Enter
signal addContactToSelection(var address) signal addContactToSelection(var address)

View file

@ -45,6 +45,7 @@ Loader {
MultiEffect { MultiEffect {
id: effect2 id: effect2
enabled: effectEnabled
visible: mainItem.useColor visible: mainItem.useColor
property bool effectEnabled: mainItem.useColor property bool effectEnabled: mainItem.useColor
anchors.fill: effect anchors.fill: effect

View file

@ -191,21 +191,22 @@ 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: contactList.height > maxHeight
height: contactList.haveContacts ? Math.min(contactList.contentHeight + topPadding + bottomPadding, maxHeight) : 0 height: Math.min(contactList.contentHeight, maxHeight) + topPadding + bottomPadding
y: magicSearchBar.height y: magicSearchBar.height
// closePolicy: Popup.NoAutoClose closePolicy: Popup.CloseOnEscape
topPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 0 topPadding: 20 * DefaultStyle.dp
bottomPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 0 bottomPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 10 * DefaultStyle.dp
rightPadding: 10 * DefaultStyle.dp rightPadding: 8 * DefaultStyle.dp
leftPadding: 20 * DefaultStyle.dp leftPadding: 20 * DefaultStyle.dp
visible: magicSearchBar.text.length != 0
background: Item { background: Item {
anchors.fill: parent anchors.fill: parent
Rectangle { Rectangle {
id: popupBg id: popupBg
radius: 16 * DefaultStyle.dp radius: 16 * DefaultStyle.dp
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: contactList.activeFocus ? 2 : 0
@ -218,25 +219,12 @@ Item {
shadowBlur: 0.1 shadowBlur: 0.1
shadowColor: DefaultStyle.grey_1000 shadowColor: DefaultStyle.grey_1000
shadowOpacity: 0.1 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 contentItem: AllContactListView {
visible: !loading && magicSearchBar.text.length != 0 id: contactList
Layout.preferredHeight: visible ? contentHeight : 0 width: listPopup.width - listPopup.leftPadding - listPopup.rightPadding
Layout.fillWidth: true
itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin) itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin)
showInitials: false showInitials: false
showContactMenu: false showContactMenu: false
@ -250,8 +238,7 @@ Item {
sectionsWeight: 700 * DefaultStyle.dp sectionsWeight: 700 * DefaultStyle.dp
sectionsSpacing: 5 * DefaultStyle.dp sectionsSpacing: 5 * DefaultStyle.dp
Control.ScrollBar.vertical: scrollbar searchBarText: magicSearchBar.text
searchBarText: magicSearchBar.text
} }
} }
} }

View file

@ -227,6 +227,7 @@ AbstractMainPage {
ColumnLayout { ColumnLayout {
id: content id: content
spacing: 15 * DefaultStyle.dp spacing: 15 * DefaultStyle.dp
Layout.leftMargin: 45 * DefaultStyle.dp
Text { Text {
visible: !contactList.loading && !contactList.haveContacts visible: !contactList.loading && !contactList.haveContacts
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
@ -241,7 +242,7 @@ AbstractMainPage {
id: contactList id: contactList
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.leftMargin: 45 * DefaultStyle.dp Layout.rightMargin: 8 * DefaultStyle.dp
searchBarText: searchBar.text searchBarText: searchBar.text
hideSuggestions: true hideSuggestions: true
showDefaultAddress: false showDefaultAddress: false