Quickfixes Contacts.

- losing focus after search.
- sections margins.
- hide magic search popup on loading instead of showing spinner.
- Display complete suggestions in participants/calls/magicBar.
- Limit adaptation with suggestions/contacts.
- Empty list when only suggestions.
- Avoid autoscroll outside lists.
- ResetSelection after contact deletion.
This commit is contained in:
Julien Wadel 2024-11-21 09:49:01 +01:00
parent ea2612acbb
commit f847054385
7 changed files with 71 additions and 57 deletions

View file

@ -87,6 +87,12 @@ public:
AbstractListProxy<QSharedPointer<QObject>>::prepend(items); AbstractListProxy<QSharedPointer<QObject>>::prepend(items);
} }
virtual void resetData() {
beginResetModel();
mList.clear();
endResetModel();
}
template <class T> template <class T>
void resetData(QList<QSharedPointer<T>> items) { void resetData(QList<QSharedPointer<T>> items) {
beginResetModel(); beginResetModel();

View file

@ -79,6 +79,7 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
&MagicSearchList::lSearch, &MagicSearchList::lSearch,
[this](QString filter, int sourceFlags, LinphoneEnums::MagicSearchAggregation aggregationFlag, [this](QString filter, int sourceFlags, LinphoneEnums::MagicSearchAggregation aggregationFlag,
int maxResults) { int maxResults) {
resetData();
mModelConnection->invokeToModel([this, filter, sourceFlags, aggregationFlag, maxResults]() { mModelConnection->invokeToModel([this, filter, sourceFlags, aggregationFlag, maxResults]() {
mMagicSearch->search(filter, sourceFlags, aggregationFlag, maxResults); mMagicSearch->search(filter, sourceFlags, aggregationFlag, maxResults);
}); });

View file

@ -50,9 +50,9 @@ void MagicSearchModel::search(QString filter,
!SettingsModel::getInstance()->getSyncLdapContacts()) !SettingsModel::getInstance()->getSyncLdapContacts())
sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::LdapServers; sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::LdapServers;
// For complete search, we search only on local contacts. // For complete search, we search only on local contacts.
sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::CallLogs; // sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::CallLogs;
sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::ChatRooms; // sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::ChatRooms;
sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::ConferencesInfo; // sourceFlags &= ~(int)LinphoneEnums::MagicSearchSource::ConferencesInfo;
} }
qInfo() << log().arg("Searching ") << filter << " from " << sourceFlags << " with limit " << maxResults; qInfo() << log().arg("Searching ") << filter << " from " << sourceFlags << " with limit " << maxResults;
mMonitor->getContactsListAsync(filter != "*" ? Utils::appStringToCoreString(filter) : "", "", sourceFlags, mMonitor->getContactsListAsync(filter != "*" ? Utils::appStringToCoreString(filter) : "", "", sourceFlags,

View file

@ -45,7 +45,7 @@ Flickable{
property int sectionsSpacing: 18 * DefaultStyle.dp property int sectionsSpacing: 18 * DefaultStyle.dp
property int itemsRightMargin: 39 * DefaultStyle.dp property int itemsRightMargin: 39 * DefaultStyle.dp
property int count: contactsList.count property int count: contactsList.count + suggestionsList.count + favoritesList.count
signal resultsReceived() signal resultsReceived()
signal contactStarredChanged() signal contactStarredChanged()
@ -94,6 +94,13 @@ Flickable{
return index != -1 return index != -1
} }
function resetSelections(){
mainItem.highlightedContact = null
favoritesList.currentIndex = -1
contactsList.currentIndex = -1
suggestionsList.currentIndex = -1
}
onHighlightedContactChanged:{ onHighlightedContactChanged:{
favoritesList.highlightedContact = highlightedContact favoritesList.highlightedContact = highlightedContact
contactsList.highlightedContact = highlightedContact contactsList.highlightedContact = highlightedContact
@ -116,7 +123,7 @@ Flickable{
} }
onSearchTextChanged: loading = true onSearchTextChanged: loading = true
onAtYEndChanged: if(atYEnd) { onAtYEndChanged: if(atYEnd) {
if( contactsProxy.haveMore || mainItem.hideSuggestions) contactsProxy.displayMore() if( (contactsProxy.haveMore && contactList.expanded ) || mainItem.hideSuggestions) contactsProxy.displayMore()
else suggestionsProxy.displayMore() else suggestionsProxy.displayMore()
} }
function findNextList(item, count, direction){ function findNextList(item, count, direction){
@ -134,7 +141,7 @@ Flickable{
function updatePosition(list){ function updatePosition(list){
var item = list.itemAtIndex(list.currentIndex) var item = list.itemAtIndex(list.currentIndex)
var centerPos = list.y - height/2 var centerPos = list.y - height/2
if( item){ if( item && list.expanded){
// For debugging just in case // For debugging just in case
//var listPosition = item.mapToItem(favoriteList, item.x, item.y) //var listPosition = item.mapToItem(favoriteList, item.x, item.y)
//var newPosition = favoriteList.mapToItem(mainItem, listPosition.x, listPosition.y) //var newPosition = favoriteList.mapToItem(mainItem, listPosition.x, listPosition.y)
@ -149,7 +156,7 @@ Flickable{
//console.log("Moving to " + (headerItem.y+item.y)) //console.log("Moving to " + (headerItem.y+item.y))
centerPos += item.y centerPos += item.y
} }
mainItem.contentY = Math.max(0, centerPos) mainItem.contentY = Math.min(Math.max(0, centerPos), mainItem.contentHeight - mainItem.height)
} }
Behavior on contentY{ Behavior on contentY{
NumberAnimation { NumberAnimation {
@ -163,9 +170,9 @@ Flickable{
var newItem var newItem
var direction = (event.key == Qt.Key_Up ? -1 : 1) var direction = (event.key == Qt.Key_Up ? -1 : 1)
if(suggestionsList.activeFocus) newItem = findNextList(suggestionsList, 0, direction) if(suggestionsList.activeFocus) newItem = findNextList(suggestionsList, 0, direction)
if(contactsList.activeFocus) newItem = findNextList(contactsList, 0, direction) else if(contactsList.activeFocus) newItem = findNextList(contactsList, 0, direction)
if(favoritesList.activeFocus) newItem = findNextList(favoritesList, 0, direction) else if(favoritesList.activeFocus) newItem = findNextList(favoritesList, 0, direction)
else newItem = findNextList(suggestionsList, 0, direction)
if(newItem){ if(newItem){
newItem.selectIndex(direction > 0 ? -1 : newItem.model.count - 1) newItem.selectIndex(direction > 0 ? -1 : newItem.model.count - 1)
event.accepted = true event.accepted = true
@ -194,7 +201,10 @@ Flickable{
searchText: mainItem.searchText searchText: mainItem.searchText
aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
sourceFlags: mainItem.sourceFlags sourceFlags: mainItem.sourceFlags
onModelReset: mainItem.resultsReceived() onModelReset: {
mainItem.resetSelections()
mainItem.resultsReceived()
}
onInitialized: { onInitialized: {
if(mainItem.searchOnEmpty || searchText != '' ) { if(mainItem.searchOnEmpty || searchText != '' ) {
@ -219,7 +229,7 @@ Flickable{
ColumnLayout{ ColumnLayout{
id: contentsLayout id: contentsLayout
width: parent.width width: parent.width
spacing: 0
BusyIndicator { BusyIndicator {
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
Layout.preferredHeight: visible ? 60 * DefaultStyle.dp : 0 Layout.preferredHeight: visible ? 60 * DefaultStyle.dp : 0
@ -265,6 +275,7 @@ Flickable{
id: contactsList id: contactsList
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: implicitHeight Layout.preferredHeight: implicitHeight
Layout.topMargin: favoritesList.height > 0 ? 4 * DefaultStyle.dp : 0
interactive: false interactive: false
highlightText: mainItem.highlightText highlightText: mainItem.highlightText
showActions: mainItem.showActions showActions: mainItem.showActions
@ -300,6 +311,7 @@ Flickable{
id: suggestionsList id: suggestionsList
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: implicitHeight Layout.preferredHeight: implicitHeight
Layout.topMargin: contactsList.height + favoritesList.height > 0 ? 4 * DefaultStyle.dp : 0
interactive: false interactive: false
showInitials: false showInitials: false
highlightText: mainItem.highlightText highlightText: mainItem.highlightText
@ -319,13 +331,14 @@ Flickable{
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)}
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)}
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)}
model:MagicSearchProxy { model:MagicSearchProxy {
id: suggestionsProxy id: suggestionsProxy
parentProxy: mainItem.mainModel parentProxy: mainItem.mainModel
filterType: mainItem.hideSuggestions ? MagicSearchProxy.FilteringTypes.None : MagicSearchProxy.FilteringTypes.Other filterType: mainItem.hideSuggestions ? MagicSearchProxy.FilteringTypes.None : MagicSearchProxy.FilteringTypes.Other
initialDisplayItems: 0 initialDisplayItems: contactsProxy.haveMore && contactsList.expanded ? 0 : 20
onInitialDisplayItemsChanged: maxDisplayItems = initialDisplayItems
displayItemsStep: 5 displayItemsStep: 5
onModelReset: maxDisplayItems = initialDisplayItems
} }
} }
} }

View file

@ -6,7 +6,7 @@ import Linphone
import UtilsCpp 1.0 import UtilsCpp 1.0
import ConstantsCpp 1.0 import ConstantsCpp 1.0
import SettingsCpp import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
ListView { ListView {
id: mainItem id: mainItem
@ -53,8 +53,8 @@ ListView {
clip: true clip: true
highlightFollowsCurrentItem: false highlightFollowsCurrentItem: false
cacheBuffer: 400 cacheBuffer: 400
implicitHeight: contentHeight + headerItem?.height implicitHeight: contentHeight
spacing: 4 * DefaultStyle.dp spacing: expanded ? 4 * DefaultStyle.dp : 0
property bool _moveToIndex: false property bool _moveToIndex: false
@ -72,14 +72,17 @@ ListView {
}else{ }else{
mainItem.currentIndex = -1 mainItem.currentIndex = -1
mainItem.highlightedContact = null mainItem.highlightedContact = null
if(headerItem) headerItem.forceActiveFocus() if(headerItem) {
headerItem.forceActiveFocus()
}
} }
} }
onCountChanged: if(_moveToIndex >= 0 && count > mainItem.currentIndex ){ onCountChanged: if(_moveToIndex && count > mainItem.currentIndex ){
_moveToIndex = false _moveToIndex = false
selectIndex(mainItem.currentIndex) selectIndex(mainItem.currentIndex)
} }
onContactSelected: updatePosition() onContactSelected: updatePosition()
onExpandedChanged: if(!expanded) updatePosition()
keyNavigationEnabled: false keyNavigationEnabled: false
Keys.onPressed: (event)=> { Keys.onPressed: (event)=> {
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){ if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){
@ -123,10 +126,11 @@ ListView {
ColumnLayout { ColumnLayout {
id: headerContents id: headerContents
width: parent.width width: parent.width
spacing: mainItem.count > 0 ? sectionsSpacing : 0 spacing: 0
Item{// Do not use directly RowLayout : there is an issue where the layout doesn't update on visible Item{// Do not use directly RowLayout : there is an issue where the layout doesn't update on visible
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: mainItem.count > 0 ? headerTitleLayout.implicitHeight : 0 Layout.preferredHeight: mainItem.count > 0 ? headerTitleLayout.implicitHeight : 0
Layout.bottomMargin: 4 * DefaultStyle.dp
RowLayout { RowLayout {
id: headerTitleLayout id: headerTitleLayout
anchors.fill: parent anchors.fill: parent

View file

@ -198,11 +198,11 @@ Item {
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.contentHeight + topPadding + bottomPadding> maxHeight
height: Math.min(contactList.contentHeight + topPadding + bottomPadding, maxHeight) height: contactList.haveContacts ? Math.min(contactList.contentHeight + topPadding + bottomPadding, maxHeight) : 0
y: magicSearchBar.height y: magicSearchBar.height
// closePolicy: Popup.NoAutoClose // closePolicy: Popup.NoAutoClose
topPadding: 20 * DefaultStyle.dp topPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 0
bottomPadding: 20 * DefaultStyle.dp bottomPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 0
rightPadding: 10 * DefaultStyle.dp rightPadding: 10 * DefaultStyle.dp
leftPadding: 20 * DefaultStyle.dp leftPadding: 20 * DefaultStyle.dp
@ -240,8 +240,8 @@ Item {
} }
contentItem: AllContactListView { contentItem: AllContactListView {
id: contactList id: contactList
visible: magicSearchBar.text.length != 0 visible: !loading && magicSearchBar.text.length != 0
Layout.preferredHeight: contentHeight Layout.preferredHeight: visible ? contentHeight : 0
Layout.fillWidth: true 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

View file

@ -20,7 +20,7 @@ AbstractMainPage {
onVisibleChanged: if (!visible) { onVisibleChanged: if (!visible) {
rightPanelStackView.clear() rightPanelStackView.clear()
if(contactLoader.item) contactLoader.item.currentIndex = -1 contactList.resetSelections()
} }
onSelectedContactChanged: { onSelectedContactChanged: {
@ -51,7 +51,7 @@ AbstractMainPage {
// rightPanelStackView.initialItem: contactDetail // rightPanelStackView.initialItem: contactDetail
showDefaultItem: rightPanelStackView.depth == 0 && contactLoader.item?.count === 0 && searchBar.text.length === 0 showDefaultItem: rightPanelStackView.depth == 0 && !contactList.haveContacts && searchBar.text.length === 0
function deleteContact(contact) { function deleteContact(contact) {
if (!contact) return if (!contact) return
@ -63,6 +63,7 @@ AbstractMainPage {
if (confirmed) { if (confirmed) {
var name = contact.core.fullName var name = contact.core.fullName
contact.core.remove() contact.core.remove()
contactList.resetSelections()
UtilsCpp.showInformationPopup(qsTr("Supprimé"), qsTr("%1 a été supprimé").arg(name)) } UtilsCpp.showInformationPopup(qsTr("Supprimé"), qsTr("%1 a été supprimé").arg(name)) }
} }
) )
@ -211,13 +212,13 @@ AbstractMainPage {
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: qsTr("Rechercher un contact") placeholderText: qsTr("Rechercher un contact")
KeyNavigation.up: createContactButton KeyNavigation.up: createContactButton
KeyNavigation.down: contactLoader.item KeyNavigation.down: contactList
} }
ColumnLayout { ColumnLayout {
id: content id: content
spacing: 15 * DefaultStyle.dp spacing: 15 * DefaultStyle.dp
Text { Text {
visible: contactLoader.item && !contactLoader.item.loading && !contactLoader.item.haveContacts visible: !contactList.loading && !contactList.haveContacts
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 137 * DefaultStyle.dp Layout.topMargin: 137 * DefaultStyle.dp
text: qsTr("Aucun contact%1").arg(searchBar.text.length !== 0 ? " correspondant" : "") text: qsTr("Aucun contact%1").arg(searchBar.text.length !== 0 ? " correspondant" : "")
@ -226,35 +227,24 @@ AbstractMainPage {
weight: 800 * DefaultStyle.dp weight: 800 * DefaultStyle.dp
} }
} }
Loader{ AllContactListView{
// 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: contactList
id: contactLoader
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.leftMargin: 45 * DefaultStyle.dp Layout.leftMargin: 45 * DefaultStyle.dp
property string t: searchBar.text searchBarText: searchBar.text
active: leftPanel.visible hideSuggestions: true
onTChanged: { showDefaultAddress: false
contactLoader.active = false sourceFlags: LinphoneEnums.MagicSearchSource.Friends | LinphoneEnums.MagicSearchSource.FavoriteFriends | LinphoneEnums.MagicSearchSource.LdapServers
Qt.callLater(function(){contactLoader.active=true}) onHighlightedContactChanged: mainItem.selectedContact = highlightedContact
onContactDeletionRequested: (contact) => {
mainItem.deleteContact(contact)
} }
//------------------------------------------------------------- onLoadingChanged: {
sourceComponent: AllContactListView{ if(!loading && initialFriendToDisplay.length !== 0) {
id: contactList Qt.callLater(function(){
searchBarText: searchBar.text if (selectContact(initialFriendToDisplay) != -1) initialFriendToDisplay = ""
hideSuggestions: true })
showDefaultAddress: false
sourceFlags: LinphoneEnums.MagicSearchSource.Friends | LinphoneEnums.MagicSearchSource.FavoriteFriends | LinphoneEnums.MagicSearchSource.LdapServers
onHighlightedContactChanged: mainItem.selectedContact = highlightedContact
onContactDeletionRequested: (contact) => {
mainItem.deleteContact(contact)
}
onLoadingChanged: {
if(!loading && initialFriendToDisplay.length !== 0) {
Qt.callLater(function(){
if (selectContact(initialFriendToDisplay) != -1) initialFriendToDisplay = ""
})
}
} }
} }
} }