Contacts list refactoring + Update SDK for fixing LDAP timeout.

This commit is contained in:
Julien Wadel 2024-11-20 15:47:15 +01:00
parent 213ba75585
commit de2612b40e
16 changed files with 549 additions and 553 deletions

View file

@ -24,6 +24,7 @@ LimitProxy::LimitProxy(QObject *parent) : QSortFilterProxyModel(parent) {
connect(this, &LimitProxy::rowsInserted, this, &LimitProxy::countChanged);
connect(this, &LimitProxy::rowsRemoved, this, &LimitProxy::countChanged);
connect(this, &LimitProxy::modelReset, this, &LimitProxy::countChanged);
connect(this, &LimitProxy::countChanged, this, &LimitProxy::haveMoreChanged);
}
/*
LimitProxy::LimitProxy(QAbstractItemModel *sortFilterProxy, QObject *parent) : QSortFilterProxyModel(parent) {
@ -79,7 +80,7 @@ int LimitProxy::getInitialDisplayItems() const {
}
void LimitProxy::setInitialDisplayItems(int initialItems) {
if (initialItems != 0 && mInitialDisplayItems != initialItems) {
if (mInitialDisplayItems != initialItems) {
mInitialDisplayItems = initialItems;
if (getMaxDisplayItems() <= mInitialDisplayItems) setMaxDisplayItems(initialItems);
if (getDisplayItemsStep() <= 0) setDisplayItemsStep(initialItems);
@ -99,7 +100,7 @@ int LimitProxy::getMaxDisplayItems() const {
return mMaxDisplayItems;
}
void LimitProxy::setMaxDisplayItems(int maxItems) {
if (maxItems != 0 && mMaxDisplayItems != maxItems) {
if (mMaxDisplayItems != maxItems) {
auto model = sourceModel();
int modelCount = model ? model->rowCount() : 0;
int oldCount = getDisplayCount(modelCount);
@ -125,6 +126,12 @@ void LimitProxy::setDisplayItemsStep(int step) {
}
}
bool LimitProxy::getHaveMore() const {
auto model = sourceModel();
int modelCount = model ? model->rowCount() : 0;
return getCount() < modelCount;
}
//--------------------------------------------------------------------------------------------------
QString LimitProxy::getFilterText() const {

View file

@ -32,6 +32,7 @@ public:
initialDisplayItemsChanged)
Q_PROPERTY(int maxDisplayItems READ getMaxDisplayItems WRITE setMaxDisplayItems NOTIFY maxDisplayItemsChanged)
Q_PROPERTY(int displayItemsStep READ getDisplayItemsStep WRITE setDisplayItemsStep NOTIFY displayItemsStepChanged)
Q_PROPERTY(bool haveMore READ getHaveMore NOTIFY haveMoreChanged)
// Propagation
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
@ -72,6 +73,8 @@ public:
int getDisplayItemsStep() const;
void setDisplayItemsStep(int step);
bool getHaveMore() const;
//-------------------------------------------------------------
QString getFilterText() const;
void setFilterText(const QString &filter);
@ -92,6 +95,7 @@ signals:
void initialDisplayItemsChanged();
void maxDisplayItemsChanged();
void displayItemsStepChanged();
void haveMoreChanged();
//-----------------------------------------------------------------
void filterTypeChanged(int filterType);
void filterTextChanged();

View file

@ -71,14 +71,15 @@ public:
Q_INVOKABLE void remove(int index, int count = 1);
void invalidateFilter();
int mFilterType = 0;
QString mFilterText;
signals:
void countChanged();
void filterTypeChanged(int filterType);
void filterTextChanged();
protected:
int mFilterType = 0;
QString mFilterText;
bool mDeleteSourceModel = false;
};

View file

@ -224,3 +224,17 @@ int MagicSearchList::findFriendIndexByAddress(const QString &address) {
}
return -1;
}
QSharedPointer<FriendCore> MagicSearchList::findFriendByAddress(const QString &address) {
for (int i = 0; i < getCount(); ++i) {
auto friendCore = getAt<FriendCore>(i);
if (!friendCore) continue;
for (auto &friendAddress : friendCore->getAllAddresses()) {
auto map = friendAddress.toMap();
if (map["address"].toString() == address) {
return friendCore;
}
}
}
return nullptr;
}

View file

@ -58,6 +58,7 @@ public:
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int findFriendIndexByAddress(const QString &address);
QSharedPointer<FriendCore> findFriendByAddress(const QString &address);
signals:
void

View file

@ -68,9 +68,7 @@ void MagicSearchProxy::setList(QSharedPointer<MagicSearchList> newList) {
}
auto sortFilterList = new SortFilterList(mList.get(), Qt::AscendingOrder);
if (oldModel) {
sortFilterList->mShowFavoritesOnly = oldModel->mShowFavoritesOnly;
sortFilterList->mHideSuggestions = oldModel->mHideSuggestions;
sortFilterList->mShowLdapContacts = oldModel->mShowLdapContacts;
sortFilterList->mFilterType = oldModel->mFilterType;
sortFilterList->mHideListProxy = oldModel->mHideListProxy;
if (sortFilterList->mHideListProxy) {
connect(sortFilterList->mHideListProxy, &MagicSearchProxy::countChanged, sortFilterList,
@ -82,7 +80,7 @@ void MagicSearchProxy::setList(QSharedPointer<MagicSearchList> newList) {
connect(
mList.get(), &MagicSearchList::friendStarredChanged, this,
[this, sortFilterList]() {
if (showFavoritesOnly()) sortFilterList->invalidate();
if ((getFilterType() & (int)FilteringTypes::Favorites) > 0) sortFilterList->invalidate();
},
Qt::QueuedConnection);
setSourceModels(sortFilterList);
@ -98,6 +96,27 @@ int MagicSearchProxy::findFriendIndexByAddress(const QString &address) {
} else return -1;
}
FriendGui *MagicSearchProxy::findFriendByAddress(const QString &address) {
auto magicSearchList = getListModel<MagicSearchList>();
if (magicSearchList) {
auto friendCore = magicSearchList->findFriendByAddress(address);
return friendCore ? new FriendGui(friendCore) : nullptr;
} else return nullptr;
}
int MagicSearchProxy::loadUntil(const QString &address) {
auto magicSearchList = getListModel<MagicSearchList>();
if (magicSearchList) {
auto listIndex = magicSearchList->findFriendIndexByAddress(address);
if (listIndex == -1) return -1;
listIndex =
dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(magicSearchList->index(listIndex, 0)).row();
if (mMaxDisplayItems < listIndex) setMaxDisplayItems(listIndex + 1);
return listIndex;
}
return -1;
}
QString MagicSearchProxy::getSearchText() const {
return mSearchText;
}
@ -125,31 +144,6 @@ void MagicSearchProxy::setMaxResults(int flags) {
mList->setMaxResults(flags);
}
bool MagicSearchProxy::showFavoritesOnly() const {
return dynamic_cast<SortFilterList *>(sourceModel())->mShowFavoritesOnly;
}
void MagicSearchProxy::setShowFavoritesOnly(bool show) {
auto list = dynamic_cast<SortFilterList *>(sourceModel());
if (list->mShowFavoritesOnly != show) {
list->mShowFavoritesOnly = show;
list->invalidate();
emit showFavoriteOnlyChanged();
}
}
bool MagicSearchProxy::getHideSuggestions() const {
return dynamic_cast<SortFilterList *>(sourceModel())->mHideSuggestions;
}
void MagicSearchProxy::setHideSuggestions(bool data) {
auto list = dynamic_cast<SortFilterList *>(sourceModel());
if (list->mHideSuggestions != data) {
list->mHideSuggestions = data;
list->invalidate();
emit hideSuggestionsChanged();
}
}
MagicSearchProxy *MagicSearchProxy::getParentProxy() const {
return mParentProxy;
}
@ -193,9 +187,23 @@ bool MagicSearchProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QMo
auto friendCore = getItemAtSource<MagicSearchList, FriendCore>(sourceRow);
auto toShow = false;
if (friendCore) {
toShow = (!mHideSuggestions || friendCore->getIsStored() || friendCore->isLdap()) &&
(!mShowFavoritesOnly || friendCore->getStarred()) &&
(mShowLdapContacts || (!friendCore->isLdap() || friendCore->getIsStored()));
if (mFilterType == (int)FilteringTypes::None) return false;
if ((mFilterType & (int)FilteringTypes::Favorites) > 0) {
toShow = friendCore->getStarred();
if (!toShow) return false;
}
if ((mFilterType & (int)FilteringTypes::Ldap) > 0) {
toShow = friendCore->isLdap();
// if (!toShow) return false;
}
if (!toShow && (mFilterType & (int)FilteringTypes::App) > 0) {
toShow = friendCore->getIsStored();
// if (!toShow) return false;
}
if (!toShow && (mFilterType & (int)FilteringTypes::Other) > 0) {
toShow = !friendCore->getIsStored() && !friendCore->isLdap();
}
if (toShow && mHideListProxy) {
for (auto &friendAddress : friendCore->getAllAddresses()) {
toShow = mHideListProxy->findFriendIndexByAddress(friendAddress.toMap()["address"].toString()) == -1;
@ -222,15 +230,3 @@ bool MagicSearchProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, c
}
return true;
}
bool MagicSearchProxy::showLdapContacts() const {
return dynamic_cast<SortFilterList *>(sourceModel())->mShowLdapContacts;
}
void MagicSearchProxy::setShowLdapContacts(bool show) {
auto list = dynamic_cast<SortFilterList *>(sourceModel());
if (list->mShowLdapContacts != show) {
list->mShowLdapContacts = show;
list->invalidateFilter();
}
}

View file

@ -22,7 +22,6 @@
#define MAGIC_SEARCH_PROXY_H_
#include "../proxy/LimitProxy.hpp"
#include "core/friend/FriendGui.hpp"
#include "core/search/MagicSearchList.hpp"
#include "tool/LinphoneEnums.hpp"
@ -30,24 +29,22 @@
class MagicSearchProxy : public LimitProxy {
Q_OBJECT
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") // Avoid name clashes
Q_PROPERTY(QString searchText READ getSearchText WRITE setSearchText NOTIFY searchTextChanged)
Q_PROPERTY(int sourceFlags READ getSourceFlags WRITE setSourceFlags NOTIFY sourceFlagsChanged)
Q_PROPERTY(int maxResults READ getMaxResults WRITE setMaxResults NOTIFY maxResultsChanged)
Q_PROPERTY(LinphoneEnums::MagicSearchAggregation aggregationFlag READ getAggregationFlag WRITE setAggregationFlag
NOTIFY aggregationFlagChanged)
Q_PROPERTY(bool showFavoritesOnly READ showFavoritesOnly WRITE setShowFavoritesOnly NOTIFY showFavoriteOnlyChanged)
Q_PROPERTY(MagicSearchProxy *parentProxy READ getParentProxy WRITE setParentProxy NOTIFY parentProxyChanged)
Q_PROPERTY(MagicSearchProxy *hideListProxy READ getHideListProxy WRITE setHideListProxy NOTIFY hideListProxyChanged)
Q_PROPERTY(bool showLdapContacts READ showLdapContacts WRITE setShowLdapContacts CONSTANT)
Q_PROPERTY(bool hideSuggestions READ getHideSuggestions WRITE setHideSuggestions NOTIFY hideSuggestionsChanged)
public:
DECLARE_SORTFILTER_CLASS(bool mShowFavoritesOnly = false; bool mShowLdapContacts = true;
bool mHideSuggestions = false;
MagicSearchProxy *mHideListProxy = nullptr;)
enum class FilteringTypes { None = 0, Favorites = 1, App = 2, Ldap = 4, Other = 8 };
Q_ENUM(FilteringTypes)
DECLARE_SORTFILTER_CLASS(MagicSearchProxy *mHideListProxy = nullptr;)
MagicSearchProxy(QObject *parent = Q_NULLPTR);
~MagicSearchProxy();
@ -63,15 +60,6 @@ public:
int getMaxResults() const;
void setMaxResults(int maxResults);
bool showFavoritesOnly() const;
void setShowFavoritesOnly(bool show);
bool showLdapContacts() const;
void setShowLdapContacts(bool show);
bool getHideSuggestions() const;
void setHideSuggestions(bool data);
MagicSearchProxy *getParentProxy() const;
void setList(QSharedPointer<MagicSearchList> list);
Q_INVOKABLE void setParentProxy(MagicSearchProxy *proxy);
@ -81,6 +69,8 @@ public:
// Q_INVOKABLE forceUpdate();
Q_INVOKABLE int findFriendIndexByAddress(const QString &address);
Q_INVOKABLE FriendGui *findFriendByAddress(const QString &address);
Q_INVOKABLE int loadUntil(const QString &address);
signals:
void searchTextChanged();
@ -89,8 +79,6 @@ signals:
void maxResultsChanged(int maxResults);
void forceUpdate();
void localFriendCreated(int index);
void showFavoriteOnlyChanged();
void hideSuggestionsChanged();
void parentProxyChanged();
void hideListProxyChanged();
void initialized();

View file

@ -49,6 +49,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Control/Display/Contact/Contact.qml
view/Control/Display/Contact/ContactListItem.qml
view/Control/Display/Contact/ContactListView.qml
view/Control/Display/Contact/AllContactListView.qml
view/Control/Display/Contact/Voicemail.qml
view/Control/Display/Meeting/MeetingListView.qml
view/Control/Display/Participant/ParticipantDeviceListView.qml

View file

@ -0,0 +1,332 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls.Basic as Control
import Linphone
import UtilsCpp 1.0
import ConstantsCpp 1.0
import SettingsCpp
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<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 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 itemsRightMargin: 39 * DefaultStyle.dp
property int count: contactsList.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
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
}
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 || mainItem.hideSuggestions) contactsProxy.displayMore()
else suggestionsProxy.displayMore()
}
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){
var item = list.itemAtIndex(list.currentIndex)
var centerPos = list.y - height/2
if( item){
// For debugging just in case
//var listPosition = item.mapToItem(favoriteList, item.x, item.y)
//var newPosition = favoriteList.mapToItem(mainItem, listPosition.x, listPosition.y)
//console.log("item pos: " +item.x + " / " +item.y)
//console.log("fav pos: " +favoriteList.x + " / " +favoriteList.y)
//console.log("fav content: " +favoriteList.contentX + " / " +favoriteList.contentY)
//console.log("main pos: " +mainItem.x + " / " +mainItem.y)
//console.log("main content: " +mainItem.contentX + " / " +mainItem.contentY)
//console.log("list pos: " +listPosition.x + " / " +listPosition.y)
//console.log("new pos: " +newPosition.x + " / " +newPosition.y)
//console.log("header pos: " +headerItem.x + " / " +headerItem.y)
//console.log("Moving to " + (headerItem.y+item.y))
centerPos += item.y
}
mainItem.contentY = Math.max(0, centerPos)
}
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)
if(contactsList.activeFocus) newItem = findNextList(contactsList, 0, direction)
if(favoritesList.activeFocus) newItem = findNextList(favoritesList, 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.resultsReceived()
onInitialized: {
if(mainItem.searchOnEmpty || searchText != '' ) {
mainItem.loading = true
forceUpdate()
}
}
}
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
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
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
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('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 : 0)
initialDisplayItems: 20
displayItemsStep: 5
onLocalFriendCreated: (index) => {
contactsList.selectIndex(index)
}
}
}
ContactListView{
id: suggestionsList
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
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: 0
displayItemsStep: 5
}
}
}
}

View file

@ -8,7 +8,7 @@ import ConstantsCpp 1.0
import SettingsCpp
FocusScope {
id: mainItem
implicitHeight: 56 * DefaultStyle.dp
implicitHeight: visible ? 56 * DefaultStyle.dp : 0
property var searchResultItem
property bool showInitials: true // Display Initials of Display name.
property bool showDefaultAddress: true // Display address below display name.
@ -21,10 +21,8 @@ FocusScope {
property bool selectionEnabled: true // Contact can be selected
property bool multiSelectionEnabled: false //Multiple items can be selected.
property list<string> selectedContacts // List of default address on selected contacts.
property int selectedContactCount: selectedContacts.length
property bool isSelected: false // selected in list => currentIndex == index
property var previousInitial // Use directly previous initial
property int itemsRightMargin: 39 * DefaultStyle.dp
@ -32,15 +30,8 @@ FocusScope {
property string initial: displayName ? displayName[0].toLocaleLowerCase(ConstantsCpp.DefaultLocale) : ''
signal clicked(var mouse)
signal contactStarredChanged()
signal contactDeletionRequested(FriendGui contact)
Connections {
enabled: searchResultItem.core
target: searchResultItem.core
function onStarredChanged() { mainItem.contactStarredChanged()}
}
Text {
id: initial
anchors.left: parent.left
@ -63,7 +54,8 @@ FocusScope {
anchors.left: initial.visible ? initial.right : parent.left
anchors.right: parent.right
anchors.rightMargin: mainItem.itemsRightMargin
anchors.verticalCenter: parent.verticalCenter
anchors.top: parent.top
anchors.bottom: parent.bottom
spacing: 16 * DefaultStyle.dp
z: 1
Avatar {
@ -106,19 +98,11 @@ FocusScope {
spacing: visible ? 16 * DefaultStyle.dp : 0
EffectImage {
id: isSelectedCheck
// visible: mainItem.multiSelectionEnabled && (mainItem.confInfoGui.core.getParticipantIndex(searchResultItem.core.defaultAddress) != -1)
visible: mainItem.multiSelectionEnabled && (mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress) != -1)
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
imageSource: AppIcons.check
colorizationColor: DefaultStyle.main1_500_main
Connections {
target: mainItem
// onParticipantsChanged: isSelectedCheck.visible = mainItem.confInfoGui.core.getParticipantIndex(searchResultItem.core.defaultAddress) != -1
function onSelectedContactCountChanged(){
isSelectedCheck.visible = (mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress) != -1)
}
}
}
RowLayout{
id: actionButtons

View file

@ -11,6 +11,7 @@ import SettingsCpp
ListView {
id: mainItem
property string title
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)
@ -25,141 +26,73 @@ ListView {
property bool selectionEnabled: true // Contact can be selected
property bool multiSelectionEnabled: false //Multiple items can be selected.
property list<string> selectedContacts // List of default address on selected contacts.
property FriendGui selectedContact//: model.getAt(currentIndex) || null
property bool searchOnInitialization: false
property bool loading: false
property bool pauseSearch: false // true = don't search on text change
property FriendGui highlightedContact
// Model properties
// set searchBarText without specifying a model to bold
// matching names
property string searchBarText
property string searchText// Binding is done on searchBarTextChanged
property string searchText
property ConferenceInfoGui confInfoGui
property bool haveFavorites: false
property bool haveContacts: count > 0 || (showFavorites && headerItem.list.count > 0)
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 bool expanded: true
signal resultsReceived()
signal contactStarredChanged()
signal contactDeletionRequested(FriendGui contact)
signal contactAddedToSelection(string address)
signal contactRemovedFromSelection(string address)
signal contactClicked(FriendGui contact)
signal contactSelected(FriendGui contact) // Click/Space/Enter
signal addContactToSelection(var address)
signal removeContactFromSelection(var indexInSelection)
signal updatePosition()
clip: true
highlightFollowsCurrentItem: true
highlightFollowsCurrentItem: false
cacheBuffer: 400
// Binding loop hack
onContentHeightChanged: Qt.callLater(function(){cacheBuffer = Math.max(0,contentHeight)})
function selectContact(address) {
var index = magicSearchProxy.findFriendIndexByAddress(address)
if (index != -1) {
mainItem.currentIndex = 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
}
implicitHeight: contentHeight + headerItem?.height
spacing: 4 * DefaultStyle.dp
property bool _moveToIndex: false
onResultsReceived: {
loading = false
mainItem.positionViewAtBeginning()
}
onSearchBarTextChanged: {
loading = true
if(!pauseSearch) {
searchText = searchBarText.length === 0 ? "*" : searchBarText
function selectIndex(index){
if(mainItem.expanded && index >= 0){
mainItem.currentIndex = index
var item = itemAtIndex(mainItem.currentIndex)
if(item){// Item is ready and available
mainItem.highlightedContact = item.searchResultItem
item.forceActiveFocus()
updatePosition()
}else{// Move on the next items load.
_moveToIndex = true
}
}else{
mainItem.currentIndex = -1
mainItem.highlightedContact = null
if(headerItem) headerItem.forceActiveFocus()
}
}
onPauseSearchChanged: {
if(!pauseSearch){
searchText = searchBarText.length === 0 ? "*" : searchBarText
}
onCountChanged: if(_moveToIndex >= 0 && count > mainItem.currentIndex ){
_moveToIndex = false
selectIndex(mainItem.currentIndex)
}
onAtYEndChanged: if(atYEnd) magicSearchProxy.displayMore()
onContactSelected: updatePosition()
keyNavigationEnabled: false
Keys.onPressed: (event)=> {
if(header.activeFocus) return;
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){
if (currentIndex == 0 && event.key == Qt.Key_Up) {
if( headerItem.list.count > 0) {
mainItem.highlightFollowsCurrentItem = false
currentIndex = -1
headerItem.list.currentIndex = headerItem.list.count -1
var item = headerItem.list.itemAtIndex(headerItem.list.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
headerItem.updatePosition()
event.accepted = true;
}else{
mainItem.currentIndex = mainItem.count - 1
var item = itemAtIndex(mainItem.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
if(event.key == Qt.Key_Up && !headerItem.activeFocus) {
if(currentIndex >= 0 ) {
selectIndex(mainItem.currentIndex-1)
event.accepted = true;
}
}else if(currentIndex >= mainItem.count -1 && event.key == Qt.Key_Down){
if( headerItem.list.count > 0) {
mainItem.highlightFollowsCurrentItem = false
mainItem.currentIndex = -1
headerItem.list.currentIndex = 0
var item = headerItem.list.itemAtIndex(headerItem.list.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
headerItem.updatePosition()
event.accepted = true;
}else{
mainItem.currentIndex = 0
var item = itemAtIndex(mainItem.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
}else if(event.key == Qt.Key_Down && mainItem.expanded){
if(currentIndex < model.count - 1) {
selectIndex(mainItem.currentIndex+1)
event.accepted = true;
}
}else if(event.key == Qt.Key_Up){
mainItem.highlightFollowsCurrentItem = true
var item = itemAtIndex(--mainItem.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
event.accepted = true;
}else if(event.key == Qt.Key_Down){
mainItem.highlightFollowsCurrentItem = true
var item = itemAtIndex(++mainItem.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
event.accepted = true;
}
}
}
@ -178,307 +111,95 @@ ListView {
magicSearchProxy.forceUpdate()
}
}
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
}
model: MagicSearchProxy {
id: magicSearchProxy
searchText: mainItem.searchText
aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
sourceFlags: mainItem.sourceFlags
hideSuggestions: mainItem.hideSuggestions
showLdapContacts: mainItem.searchText != '*' && mainItem.searchText != '' || SettingsCpp.syncLdapContacts
initialDisplayItems: 20
onLocalFriendCreated: (index) => {
var item = itemAtIndex(index)
if(item){
mainItem.currentIndex = index
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
}
}
onInitialized: {
mainItem.loading = true
magicSearchProxy.forceUpdate()
}
onModelReset: mainItem.resultsReceived()
}
section.property: "isStored"
//section.criteria: ViewSection.FirstCharacter
section.delegate: Item{
width: mainItem.width
height: textItem.implicitHeight + sectionsSpacing * 2
required property bool section
Text {
id: textItem
anchors.fill: parent
text: section ? qsTr("Contacts") : qsTr("Suggestions")
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font {
pixelSize: sectionsPixelSize
weight: sectionsWeight
}
}
}
header: FocusScope{
id: headerItem
width: mainItem.width
height: favoritesContents.implicitHeight
property alias list: favoriteList
id: headerItem
width: mainItem.width
height: headerContents.implicitHeight
onActiveFocusChanged: {
if(activeFocus) mainItem.updatePosition()
}
// Hack because changing currentindex change focus.
Timer{
id: focusDelay
interval: 10
onTriggered: {
mainItem.highlightFollowsCurrentItem = !headerItem.activeFocus
ColumnLayout {
id: headerContents
width: parent.width
spacing: mainItem.count > 0 ? sectionsSpacing : 0
Item{// Do not use directly RowLayout : there is an issue where the layout doesn't update on visible
Layout.fillWidth: true
Layout.preferredHeight: mainItem.count > 0 ? headerTitleLayout.implicitHeight : 0
RowLayout {
id: headerTitleLayout
anchors.fill: parent
spacing: 0
// Need this because it can stay at 0 on display without manual relayouting (moving position, resize)
visible: mainItem.count > 0
Text {
text: mainItem.title
font {
pixelSize: sectionsPixelSize
weight: sectionsWeight
}
}
}
onActiveFocusChanged:focusDelay.restart()
//---------------------------------------------------
function updatePosition(){
var item = favoriteList.itemAtIndex(favoriteList.currentIndex)
if( item){
// For debugging just in case
//var listPosition = item.mapToItem(favoriteList, item.x, item.y)
//var newPosition = favoriteList.mapToItem(mainItem, listPosition.x, listPosition.y)
//console.log("item pos: " +item.x + " / " +item.y)
//console.log("fav pos: " +favoriteList.x + " / " +favoriteList.y)
//console.log("fav content: " +favoriteList.contentX + " / " +favoriteList.contentY)
//console.log("main pos: " +mainItem.x + " / " +mainItem.y)
//console.log("main content: " +mainItem.contentX + " / " +mainItem.contentY)
//console.log("list pos: " +listPosition.x + " / " +listPosition.y)
//console.log("new pos: " +newPosition.x + " / " +newPosition.y)
//console.log("header pos: " +headerItem.x + " / " +headerItem.y)
//console.log("Moving to " + (headerItem.y+item.y))
mainItem.contentY = headerItem.y+item.y
}
}
ColumnLayout {
id: favoritesContents
width: parent.width
spacing: mainItem.haveFavorites ? sectionsSpacing : 0
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
}
Item{// Do not use directly RowLayout : there is an issue where the layout doesn't update on visible
Item {
Layout.fillWidth: true
Layout.preferredHeight: mainItem.haveFavorites ? favoriteTitle.implicitHeight : 0
RowLayout {
id: favoriteTitle
anchors.fill: parent
spacing: 0
// Need this because it can stay at 0 on display without manual relayouting (moving position, resize)
visible: mainItem.haveFavorites
onVisibleChanged: if(visible) {
Qt.callLater(mainItem.positionViewAtBeginning)// If not later, the view will not move to favoris at startup
}
Text {
//Layout.fillHeight: true
text: qsTr("Favoris")
font {
pixelSize: sectionsPixelSize
weight: sectionsWeight
}
}
Item {
Layout.fillWidth: true
}
Button {
id: favoriteExpandButton
background: Item{}
icon.source: favoriteList.visible ? AppIcons.upArrow : AppIcons.downArrow
Layout.fillHeight: true
Layout.preferredWidth: height
//Layout.preferredWidth: 24 * DefaultStyle.dp
//Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.rightMargin: 23 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
focus: true
onClicked: favoriteList.visible = !favoriteList.visible
KeyNavigation.down: favoriteList
}
}
}
ListView{
id: favoriteList
Layout.fillWidth: true
Layout.preferredHeight: count > 0 ? contentHeight : 0// Show full and avoid scrolling
onCountChanged: mainItem.haveFavorites = count > 0
Keys.onPressed: (event)=> {
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down) {
if (favoriteList.currentIndex == 0 && event.key == Qt.Key_Up) {
if( mainItem.count > 0) {
mainItem.highlightFollowsCurrentItem = true
favoriteList.currentIndex = -1
mainItem.currentIndex = mainItem.count-1
var item = mainItem.itemAtIndex(mainItem.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
event.accepted = true;
}else{
favoriteList.currentIndex = favoriteList.count - 1
var item = itemAtIndex(favoriteList.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
event.accepted = true;
}
}else if(currentIndex >= favoriteList.count -1 && event.key == Qt.Key_Down) {
if( mainItem.count > 0) {
mainItem.highlightFollowsCurrentItem = true
favoriteList.currentIndex = -1
mainItem.currentIndex = 0
var item = mainItem.itemAtIndex(mainItem.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
event.accepted = true;
}else{
favoriteList.currentIndex = 0
var item = itemAtIndex(favoriteList.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
event.accepted = true;
}
}else if(event.key == Qt.Key_Up){
mainItem.highlightFollowsCurrentItem = false
var item = itemAtIndex(--favoriteList.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
headerItem.updatePosition()
event.accepted = true;
}else if(event.key == Qt.Key_Down){
mainItem.highlightFollowsCurrentItem = false
var item = itemAtIndex(++favoriteList.currentIndex)
mainItem.selectedContact = item.searchResultItem
item.forceActiveFocus()
headerItem.updatePosition()
event.accepted = true;
}
}
}
property MagicSearchProxy proxy: MagicSearchProxy{
parentProxy: mainItem.model
showFavoritesOnly: true
hideSuggestions: mainItem.hideSuggestions
}
model : showFavorites && mainItem.searchBarText == '' ? proxy : []
delegate: ContactListItem{
width: favoriteList.width
focus: true
searchResultItem: $modelData
showInitials: mainItem.showInitials
showDefaultAddress: mainItem.showDefaultAddress
showActions: mainItem.showActions
showContactMenu: mainItem.showContactMenu
highlightText: mainItem.highlightText
displayNameCapitalization: mainItem.displayNameCapitalization
itemsRightMargin: mainItem.itemsRightMargin
selectionEnabled: mainItem.selectionEnabled
multiSelectionEnabled: mainItem.multiSelectionEnabled
selectedContacts: mainItem.selectedContacts
isSelected: mainItem.selectedContact && mainItem.selectedContact.core == searchResultItem.core
previousInitial: ''//favoriteList.count > 0 ? favoriteList.itemAtIndex(index-1)?.initial : '' // Binding on count
initial: '' // Hide initials but keep space
onIsSelectedChanged: if(isSelected) favoriteList.currentIndex = index
onContactStarredChanged: mainItem.contactStarredChanged()
onContactDeletionRequested: (contact) => mainItem.contactDeletionRequested(contact)
onClicked: (mouse) => {
mainItem.highlightFollowsCurrentItem = false
favoriteList.currentIndex = index
mainItem.selectedContact = searchResultItem
forceActiveFocus()
headerItem.updatePosition()
if (mainItem.multiSelectionEnabled) {
var indexInSelection = mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress)
if (indexInSelection == -1) {
mainItem.addContactToSelection(searchResultItem.core.defaultAddress)
}
else {
mainItem.removeContactFromSelection(indexInSelection, 1)
}
}
mainItem.contactClicked(searchResultItem)
}
}
Button {
id: headerExpandButton
background: Item{}
icon.source: mainItem.expanded ? AppIcons.upArrow : AppIcons.downArrow
Layout.fillHeight: true
Layout.preferredWidth: height
Layout.rightMargin: 23 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
focus: true
onClicked: mainItem.expanded = !mainItem.expanded
}
}
}
}
}
delegate: ContactListItem{
id: contactItem
width: mainItem.width
focus: true
visible: mainItem.expanded
searchResultItem: $modelData
showInitials: mainItem.showInitials && isStored
showDefaultAddress: mainItem.showDefaultAddress
showActions: mainItem.showActions
showContactMenu: searchResultItem.core.isStored
highlightText: mainItem.highlightText
displayNameCapitalization: mainItem.displayNameCapitalization
itemsRightMargin: mainItem.itemsRightMargin
selectionEnabled: mainItem.selectionEnabled
multiSelectionEnabled: mainItem.multiSelectionEnabled
selectedContacts: mainItem.selectedContacts
isSelected: mainItem.selectedContact && mainItem.selectedContact.core == searchResultItem.core
isSelected: mainItem.highlightedContact && mainItem.highlightedContact.core == searchResultItem.core
previousInitial: mainItem.itemAtIndex(index-1)?.initial
itemsRightMargin: mainItem.itemsRightMargin
onIsSelectedChanged: if(isSelected) mainItem.currentIndex = index
onContactStarredChanged: mainItem.contactStarredChanged()
onContactDeletionRequested: (contact) => mainItem.contactDeletionRequested(contact)
onClicked: (mouse) => {
mainItem.highlightFollowsCurrentItem = true
if (mouse && mouse.button == Qt.RightButton) {
friendPopup.open()
} else {
forceActiveFocus()
if(mainItem.selectedContact && mainItem.selectedContact.core != contactItem.searchResultItem.core)
headerItem.list.currentIndex = -1
mainItem.selectedContact = contactItem.searchResultItem
if (mainItem.multiSelectionEnabled) {
var indexInSelection = mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress)
if (indexInSelection == -1) {
mainItem.addContactToSelection(searchResultItem.core.defaultAddress)
}
else {
mainItem.removeContactFromSelection(indexInSelection, 1)
}
}
mainItem.contactClicked(searchResultItem)
}
forceActiveFocus()
mainItem.highlightedContact = contactItem.searchResultItem
if (mainItem.multiSelectionEnabled) {
var indexInSelection = mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress)
if (indexInSelection == -1) {
mainItem.addContactToSelection(searchResultItem.core.defaultAddress)
}
else {
mainItem.removeContactFromSelection(indexInSelection)
}
}
mainItem.contactSelected(searchResultItem)
}
}
}
}

View file

@ -88,7 +88,7 @@ FocusScope {
Layout.preferredHeight: 44 * DefaultStyle.dp
padding: 0
KeyNavigation.up: searchBar
KeyNavigation.down: contactLoader.item
KeyNavigation.down: contactList
onClicked: mainItem.groupCallCreationRequested()
background: Rectangle {
anchors.fill: parent
@ -127,23 +127,13 @@ FocusScope {
}
}
}
Loader{
// This is a hack for an incomprehensible behavior on sections title where they doesn't match with their delegate and can be unordered after resetting models.
id: contactLoader
AllContactListView{
id: contactList
Layout.fillWidth: true
Layout.fillHeight: true
property string t: searchBar.text
onTChanged: {
contactLoader.active = false
Qt.callLater(function(){contactLoader.active=true})
}
//-------------------------------------------------------------
sourceComponent: ContactListView{
id: contactList
searchBarText: searchBar.text
onContactClicked: (contact) => {
mainItem.contactClicked(contact)
}
searchBarText: searchBar.text
onContactSelected: (contact) => {
mainItem.contactClicked(contact)
}
}
}

View file

@ -10,7 +10,7 @@ FocusScope{
id: mainItem
property string placeHolderText: qsTr("Rechercher des contacts")
property list<string> selectedParticipants//: contactLoader.item ? contactLoader.item.selectedContacts
property list<string> selectedParticipants
property int selectedParticipantsCount: selectedParticipants.length
property ConferenceInfoGui conferenceInfoGui
property color searchBarColor: DefaultStyle.grey_100
@ -32,7 +32,6 @@ FocusScope{
width: mainItem.width
model: mainItem.selectedParticipants
clip: true
focus: participantList.count > 0
Keys.onPressed: (event) => {
if(currentIndex <=0 && event.key == Qt.Key_Up){
nextItemInFocusChain(false).forceActiveFocus()
@ -67,7 +66,7 @@ FocusScope{
icon.height: 24 * DefaultStyle.dp
focus: true
contentImageColor: DefaultStyle.main1_500_main
onClicked: if(contactLoader.item) contactLoader.item.removeSelectedContactByAddress(modelData)
onClicked: contactList.removeSelectedContactByAddress(modelData)
}
}
}
@ -95,13 +94,13 @@ FocusScope{
KeyNavigation.up: participantList.count > 0
? participantList
: nextItemInFocusChain(false)
KeyNavigation.down: contactLoader.item
KeyNavigation.down: contactList
}
ColumnLayout {
id: content
spacing: 15 * DefaultStyle.dp
Text {
visible: !contactLoader.item?.loading && contactLoader.item?.count === 0
visible: !contactList.loading && contactList.count === 0
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 137 * DefaultStyle.dp
text: qsTr("Aucun contact%1").arg(searchBar.text.length !== 0 ? " correspondant" : "")
@ -110,33 +109,21 @@ FocusScope{
weight: 800 * DefaultStyle.dp
}
}
Loader{
// This is a hack for an incomprehensible behavior on sections title where they doesn't match with their delegate and can be unordered after resetting models.
id: contactLoader
AllContactListView{
id: contactList
Layout.fillWidth: true
Layout.fillHeight: true
property string t: searchBar.text
onTChanged: {
contactLoader.active = false
Qt.callLater(function(){contactLoader.active=true})
}
//-------------------------------------------------------------
sourceComponent: ContactListView{
id: contactList
Layout.fillWidth: true
Layout.fillHeight: true
itemsRightMargin: 28 * DefaultStyle.dp
multiSelectionEnabled: true
showContactMenu: false
confInfoGui: mainItem.conferenceInfoGui
selectedContacts: mainItem.selectedParticipants
onSelectedContactsChanged: Qt.callLater(function(){mainItem.selectedParticipants = selectedContacts})
searchBarText: searchBar.text
onContactAddedToSelection: (address) => {
contactList.addContactToSelection(address)
}
onContactRemovedFromSelection: (address) => contactList.removeSelectedContactByAddress(address)
itemsRightMargin: 28 * DefaultStyle.dp
multiSelectionEnabled: true
showContactMenu: false
confInfoGui: mainItem.conferenceInfoGui
selectedContacts: mainItem.selectedParticipants
onSelectedContactsChanged: Qt.callLater(function(){mainItem.selectedParticipants = selectedContacts})
searchBarText: searchBar.text
onContactAddedToSelection: (address) => {
contactList.addContactToSelection(address)
}
onContactRemovedFromSelection: (address) => contactList.removeSelectedContactByAddress(address)
}
}
}

View file

@ -172,8 +172,8 @@ Item {
if (text.length != 0) listPopup.open()
else listPopup.close()
}
KeyNavigation.down: contactLoader.item?.count > 0 || !contactLoader.item?.footerItem? contactLoader.item : contactLoader.item?.footerItem
KeyNavigation.up: contactLoader.item?.footerItem ? contactLoader.item?.footerItem : contactLoader.item
KeyNavigation.down: contactList //contactLoader.item?.count > 0 || !contactLoader.item?.footerItem? contactLoader.item : contactLoader.item?.footerItem
KeyNavigation.up: contactList//contactLoader.item?.footerItem ? contactLoader.item?.footerItem : contactLoader.item
component MagicSearchButton: Button {
id: button
@ -197,8 +197,8 @@ Item {
id: listPopup
width: magicSearchBar.width
property int maxHeight: 400 * DefaultStyle.dp
property bool displayScrollbar: contactLoader.item?.contentHeight + topPadding + bottomPadding> maxHeight
height: Math.min(contactLoader.item?.contentHeight + topPadding + bottomPadding, maxHeight)
property bool displayScrollbar: contactList.contentHeight + topPadding + bottomPadding> maxHeight
height: Math.min(contactList.contentHeight + topPadding + bottomPadding, maxHeight)
y: magicSearchBar.height
// closePolicy: Popup.NoAutoClose
topPadding: 20 * DefaultStyle.dp
@ -214,7 +214,7 @@ Item {
color: DefaultStyle.grey_0
anchors.fill: parent
border.color: DefaultStyle.main1_500_main
border.width: contactLoader.item?.activeFocus ? 2 : 0
border.width: contactList.activeFocus ? 2 : 0
}
MultiEffect {
@ -238,23 +238,10 @@ Item {
}
}
contentItem: Loader{
// This is a hack for an incomprehensible behavior on sections title where they doesn't match with their delegate and can be unordered after resetting models.
id: contactLoader
Layout.fillWidth: true
Layout.fillHeight: true
property bool deactivate: false
active: !deactivate && magicSearchBar.text != ''
property string t: magicSearchBar.text
onTChanged: {
contactLoader.deactivate = true
Qt.callLater(function(){contactLoader.deactivate=false})
}
//-------------------------------------------------------------
sourceComponent: ContactListView {
contentItem: AllContactListView {
id: contactList
visible: magicSearchBar.text.length != 0
Layout.preferredHeight: item?.contentHeight
Layout.preferredHeight: contentHeight
Layout.fillWidth: true
itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin)
showInitials: false
@ -263,6 +250,7 @@ Item {
showFavorites: false
selectionEnabled: false
showDefaultAddress: true
searchOnEmpty: false
sectionsPixelSize: 13 * DefaultStyle.dp
sectionsWeight: 700 * DefaultStyle.dp
@ -270,24 +258,7 @@ Item {
Control.ScrollBar.vertical: scrollbar
searchBarText: magicSearchBar.text
Keys.onPressed: (event) => {
if(event.key == Qt.Key_Down){
if(contactList.currentIndex == contactList.count -1) {
contactList.currentIndex = -1
contactList.footerItem.forceActiveFocus()
event.accepted = true
}
} else if(event.key == Qt.Key_Up){
if(contactList.currentIndex <= 0) {
contactList.currentIndex = -1
contactList.footerItem.forceActiveFocus()
event.accepted = true
}
}
}
}
}
}
}
RowLayout {

View file

@ -239,22 +239,21 @@ AbstractMainPage {
Qt.callLater(function(){contactLoader.active=true})
}
//-------------------------------------------------------------
sourceComponent: ContactListView{
sourceComponent: AllContactListView{
id: contactList
searchBarText: searchBar.text
hideSuggestions: true
showDefaultAddress: false
sourceFlags: LinphoneEnums.MagicSearchSource.Friends | LinphoneEnums.MagicSearchSource.FavoriteFriends | LinphoneEnums.MagicSearchSource.LdapServers
onSelectedContactChanged: {
mainItem.selectedContact = selectedContact
}
onHighlightedContactChanged: mainItem.selectedContact = highlightedContact
onContactDeletionRequested: (contact) => {
mainItem.deleteContact(contact)
}
onCountChanged: {
if (initialFriendToDisplay.length !== 0) {
if (selectContact(initialFriendToDisplay) != -1) initialFriendToDisplay = ""
onLoadingChanged: {
if(!loading && initialFriendToDisplay.length !== 0) {
Qt.callLater(function(){
if (selectContact(initialFriendToDisplay) != -1) initialFriendToDisplay = ""
})
}
}
}

@ -1 +1 @@
Subproject commit 08d52ccdc63c859f14ffa160b954d1f954a5a272
Subproject commit 4e2af5b435cb7fd6aadc9cd2b7eb45ba547cf5e8