linphone-desktop/Linphone/view/Control/Display/Contact/ContactListView.qml

232 lines
7.5 KiB
QML

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls.Basic as Control
import Linphone
import UtilsCpp 1.0
import ConstantsCpp 1.0
import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
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 showDisplayName: true // Display name above address.
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 highlightedContact
// Model properties
// set searchBarText without specifying a model to bold
// matching names
property string searchText
property ConferenceInfoGui confInfoGui
property bool haveFavorites: false
property bool haveContacts: count > 0
property real sectionsPixelSize: Typography.h4.pixelSize
property real sectionsWeight: Typography.h4.weight
property real sectionsSpacing: Math.round(18 * DefaultStyle.dp)
property real itemsRightMargin: Math.round(39 * DefaultStyle.dp)
property bool expanded: true
property real headerHeight: headerItem?.height
signal contactDeletionRequested(FriendGui contact)
signal contactSelected(FriendGui contact) // Click/Space/Enter
signal addContactToSelection(var address)
signal removeContactFromSelection(var indexInSelection)
signal updatePosition()
clip: true
highlightFollowsCurrentItem: false
cacheBuffer: 400
implicitHeight: contentHeight
spacing: expanded ? Math.round(4 * DefaultStyle.dp) : 0
onVisibleChanged: if (visible && !expanded) expanded = true
onYChanged: updatePosition()
// Qt bug: sometimes, containsMouse may not be send and update on each MouseArea.
// So we need to use this variable to switch off all hovered items.
property int lastMouseContainsIndex: -1
property bool _moveToIndex: false
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()
_moveToIndex = false
}else{// Move on the next items load.
// If visible, try to wait loading
_moveToIndex = visible
}
}else{
mainItem.currentIndex = -1
mainItem.highlightedContact = null
if(headerItem) {
headerItem.forceActiveFocus()
}
_moveToIndex = false
}
}
onContactSelected: updatePosition()
onExpandedChanged: if(!expanded) updatePosition()
keyNavigationEnabled: false
Keys.onPressed: (event)=> {
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){
if(event.key == Qt.Key_Up && !headerItem.activeFocus) {
if(currentIndex >= 0 ) {
selectIndex(mainItem.currentIndex-1)
event.accepted = true;
}
}else if(event.key == Qt.Key_Down && mainItem.expanded){
if(currentIndex < model.count - 1) {
selectIndex(mainItem.currentIndex+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()
}
}
// Workaround: itemAtIndex and count are decorellated and are not enough to know when the ListView has load all its children.
// So when itemAtIndex is not available, start this timer along count changed signal.
Timer{
id: delaySelection
interval: 100
running: _moveToIndex
onTriggered: {
_moveToIndex = false
if(count > mainItem.currentIndex) selectIndex(mainItem.currentIndex)
else{
_moveToIndex = true
}
}
}
header: FocusScope{
id: headerItem
width: mainItem.width
height: headerContents.implicitHeight
ColumnLayout {
id: headerContents
width: parent.width
spacing: 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
Layout.bottomMargin: Math.round(4 * DefaultStyle.dp)
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
}
}
Item {
Layout.fillWidth: true
}
RoundButton {
id: headerExpandButton
style: ButtonStyle.noBackground
icon.source: mainItem.expanded ? AppIcons.upArrow : AppIcons.downArrow
Layout.rightMargin: mainItem.itemsRightMargin
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: mainItem.showContactMenu && searchResultItem.core.isStored
highlightText: mainItem.highlightText
displayNameCapitalization: mainItem.displayNameCapitalization
selectionEnabled: mainItem.selectionEnabled
multiSelectionEnabled: mainItem.multiSelectionEnabled
selectedContacts: mainItem.selectedContacts
isSelected: mainItem.highlightedContact && mainItem.highlightedContact.core == searchResultItem.core
isLastHovered: mainItem.lastMouseContainsIndex == index
previousInitial: mainItem.itemAtIndex(index-1)?.initial
itemsRightMargin: mainItem.itemsRightMargin
onIsSelectedChanged: if(isSelected) mainItem.currentIndex = index
onContactDeletionRequested: (contact) => mainItem.contactDeletionRequested(contact)
onClicked: (mouse) => {
if (mouse && mouse.button == Qt.RightButton) {
friendPopup.open()
} else {
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)
}
}
onContainsMouseChanged: (containsMouse) => {
if(containsMouse)
mainItem.lastMouseContainsIndex = index
else if( mainItem.lastMouseContainsIndex == index)
mainItem.lastMouseContainsIndex = -1
}
}
}