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:
parent
ea2612acbb
commit
f847054385
7 changed files with 71 additions and 57 deletions
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,21 +227,11 @@ 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
|
|
||||||
active: leftPanel.visible
|
|
||||||
onTChanged: {
|
|
||||||
contactLoader.active = false
|
|
||||||
Qt.callLater(function(){contactLoader.active=true})
|
|
||||||
}
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
sourceComponent: AllContactListView{
|
|
||||||
id: contactList
|
|
||||||
searchBarText: searchBar.text
|
searchBarText: searchBar.text
|
||||||
hideSuggestions: true
|
hideSuggestions: true
|
||||||
showDefaultAddress: false
|
showDefaultAddress: false
|
||||||
|
|
@ -260,7 +251,6 @@ AbstractMainPage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: contactDetail
|
id: contactDetail
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue