asynchronous actions buttons to improve performances

This commit is contained in:
gaelle 2025-02-25 15:55:34 +01:00
parent 586dca5cd0
commit 3629732fde
5 changed files with 1298 additions and 1061 deletions

View file

@ -2,162 +2,191 @@ import QtQuick
import QtQuick.Controls.Basic as Control import QtQuick.Controls.Basic as Control
import QtQuick.Effects import QtQuick.Effects
import Linphone import Linphone
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
Button { Button {
id: mainItem id: mainItem
property alias popup: popup property alias popup: popup
property bool shadowEnabled: mainItem.activeFocus || hovered property bool shadowEnabled: mainItem.activeFocus || hovered
property alias popupBackgroundColor: popupBackground.color property alias popupBackgroundColor: popupBackground.color
property color backgroundColor: checked property color backgroundColor: checked ? pressedColor : hovered ? hoveredColor : color
? pressedColor style: ButtonStyle.popupButton
: hovered checked: popup.visible
? hoveredColor implicitWidth: 24 * DefaultStyle.dp
: color implicitHeight: 24 * DefaultStyle.dp
style: ButtonStyle.popupButton width: 24 * DefaultStyle.dp
checked: popup.visible height: 24 * DefaultStyle.dp
implicitWidth: 24 * DefaultStyle.dp leftPadding: 0
implicitHeight: 24 * DefaultStyle.dp rightPadding: 0
width: 24 * DefaultStyle.dp topPadding: 0
height: 24 * DefaultStyle.dp bottomPadding: 0
leftPadding: 0 icon.source: AppIcons.verticalDots
rightPadding: 0 icon.width: 24 * DefaultStyle.dp
topPadding: 0 icon.height: 24 * DefaultStyle.dp
bottomPadding: 0 function close() {
icon.source: AppIcons.verticalDots popup.close()
icon.width: 24 * DefaultStyle.dp }
icon.height: 24 * DefaultStyle.dp function open() {
function close() { popup.open()
popup.close() }
}
function open() {
popup.open()
}
function isFocusable(item){ function isFocusable(item) {
return item.activeFocusOnTab return item.activeFocusOnTab
} }
function getPreviousItem(index){ function getPreviousItem(index) {
return _getPreviousItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, index) return _getPreviousItem(
} popup.contentItem
function getNextItem(index){ instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem,
return _getNextItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, index) index)
} }
function getNextItem(index) {
return _getNextItem(
popup.contentItem
instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem,
index)
}
function _getPreviousItem(content, index){ function _getPreviousItem(content, index) {
if(content.visibleChildren.length == 0) return null if (content.visibleChildren.length == 0)
--index return null
while(index >= 0){ --index
if( isFocusable(content.children[index]) && content.children[index].visible) return content.children[index] while (index >= 0) {
--index if (isFocusable(content.children[index])
} && content.children[index].visible)
return _getPreviousItem(content, content.children.length) return content.children[index]
} --index
function _getNextItem(content, index){ }
++index return _getPreviousItem(content, content.children.length)
while(index < content.children.length){ }
if( isFocusable(content.children[index]) && content.children[index].visible) return content.children[index] function _getNextItem(content, index) {
++index ++index
} while (index < content.children.length) {
return _getNextItem(content, -1) if (isFocusable(content.children[index])
} && content.children[index].visible)
return content.children[index]
++index
}
return _getNextItem(content, -1)
}
Keys.onPressed: (event) => { Keys.onPressed: event => {
if(mainItem.checked){ if (mainItem.checked) {
if( event.key == Qt.Key_Escape || event.key == Qt.Key_Left || event.key == Qt.Key_Space){ if (event.key == Qt.Key_Escape
mainItem.close() || event.key == Qt.Key_Left
mainItem.forceActiveFocus() || event.key == Qt.Key_Space) {
event.accepted = true mainItem.close()
}else if(event.key == Qt.Key_Up){ mainItem.forceActiveFocus()
getPreviousItem(0).forceActiveFocus() event.accepted = true
event.accepted = true } else if (event.key == Qt.Key_Up) {
}else if(event.key == Qt.Key_Tab || event.key == Qt.Key_Down){ getPreviousItem(0).forceActiveFocus()
getNextItem(-1).forceActiveFocus() event.accepted = true
event.accepted = true } else if (event.key == Qt.Key_Tab
} || event.key == Qt.Key_Down) {
}else if(event.key == Qt.Key_Space){ getNextItem(-1).forceActiveFocus()
mainItem.open() event.accepted = true
event.accepted = true }
} } else if (event.key == Qt.Key_Space) {
} mainItem.open()
event.accepted = true
}
}
background: Item { background: Item {
anchors.fill: mainItem anchors.fill: mainItem
Rectangle { Rectangle {
id: buttonBackground id: buttonBackground
anchors.fill: parent anchors.fill: parent
color: mainItem.backgroundColor color: mainItem.backgroundColor
radius: 40 * DefaultStyle.dp radius: 40 * DefaultStyle.dp
} }
MultiEffect { MultiEffect {
enabled: mainItem.shadowEnabled enabled: mainItem.shadowEnabled
anchors.fill: buttonBackground anchors.fill: buttonBackground
source: buttonBackground source: buttonBackground
visible: mainItem.shadowEnabled visible: mainItem.shadowEnabled
// Crash : https://bugreports.qt.io/browse/QTBUG-124730 // Crash : https://bugreports.qt.io/browse/QTBUG-124730
shadowEnabled: true //mainItem.shadowEnabled shadowEnabled: true //mainItem.shadowEnabled
shadowColor: DefaultStyle.grey_1000 shadowColor: DefaultStyle.grey_1000
shadowBlur: 0.1 shadowBlur: 0.1
shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0
} }
} }
contentItem: EffectImage { contentItem: EffectImage {
imageSource: mainItem.icon.source imageSource: mainItem.icon.source
imageWidth: mainItem.icon.width imageWidth: mainItem.icon.width
imageHeight: mainItem.icon.height imageHeight: mainItem.icon.height
colorizationColor: mainItem.contentImageColor colorizationColor: mainItem.contentImageColor
} }
onPressed: { onPressed: {
if (popup.visible) popup.close() if (popup.visible)
else popup.open() popup.close()
} else
Control.Popup { popup.open()
id: popup }
x: 0 Control.Popup {
y: mainItem.height id: popup
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside | Popup.CloseOnEscape x: 0
padding: 10 * DefaultStyle.dp y: mainItem.height
parent: mainItem // Explicit define for coordinates references. visible: false
function updatePosition(){ closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside
if (!visible) return | Popup.CloseOnEscape
var popupHeight = popup.height + popup.padding padding: 10 * DefaultStyle.dp
var popupWidth = popup.width + popup.padding parent: mainItem // Explicit define for coordinates references.
var winPosition = mainItem.Window.contentItem ? mainItem.Window.contentItem.mapToItem(mainItem,0 , 0) : {x:0,y:0} function updatePosition() {
// Stay inside main window if (!visible)
y = Math.max( Math.min( winPosition.y + mainItem.Window.height - popupHeight, mainItem.height), winPosition.y) return
x = Math.max( Math.min( winPosition.x + mainItem.Window.width - popupWidth, 0), winPosition.x) var popupHeight = popup.height + popup.padding
// Avoid overlapping with popup button by going to the right (todo: check if left is better?) var popupWidth = popup.width + popup.padding
if( y < mainItem.height && y + popupHeight > 0){ var winPosition = mainItem.Window.contentItem ? mainItem.Window.contentItem.mapToItem(
x += mainItem.width mainItem, 0,
} 0) : {
} "x": 0,
"y": 0
}
// Stay inside main window
y = Math.max(Math.min(
winPosition.y + mainItem.Window.height - popupHeight,
mainItem.height), winPosition.y)
x = Math.max(
Math.min(
winPosition.x + mainItem.Window.width - popupWidth,
0), winPosition.x)
// Avoid overlapping with popup button by going to the right (todo: check if left is better?)
if (y < mainItem.height && y + popupHeight > 0) {
x += mainItem.width
}
}
onHeightChanged: Qt.callLater(updatePosition) onHeightChanged: Qt.callLater(updatePosition)
onWidthChanged: Qt.callLater(updatePosition) onWidthChanged: Qt.callLater(updatePosition)
onVisibleChanged: Qt.callLater(updatePosition) onVisibleChanged: Qt.callLater(updatePosition)
Connections{ Connections {
target: mainItem.Window target: mainItem.Window
function onHeightChanged(){ Qt.callLater(popup.updatePosition)} function onHeightChanged() {
function onWidthChanged(){ Qt.callLater(popup.updatePosition)} Qt.callLater(popup.updatePosition)
} }
function onWidthChanged() {
Qt.callLater(popup.updatePosition)
}
}
background: Item { background: Item {
anchors.fill: parent anchors.fill: parent
Rectangle { Rectangle {
id: popupBackground id: popupBackground
anchors.fill: parent anchors.fill: parent
color: DefaultStyle.grey_0 color: DefaultStyle.grey_0
radius: 16 * DefaultStyle.dp radius: 16 * DefaultStyle.dp
} }
MultiEffect { MultiEffect {
source: popupBackground source: popupBackground
anchors.fill: popupBackground anchors.fill: popupBackground
shadowEnabled: true shadowEnabled: true
shadowBlur: 0.1 shadowBlur: 0.1
shadowColor: DefaultStyle.grey_1000 shadowColor: DefaultStyle.grey_1000
shadowOpacity: 0.4 shadowOpacity: 0.4
} }
} }
} }
} }

View file

@ -5,8 +5,8 @@ import QtQuick.Controls.Basic as Control
import Linphone import Linphone
import UtilsCpp import UtilsCpp
import SettingsCpp import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
ListView { ListView {
id: mainItem id: mainItem
@ -17,7 +17,7 @@ ListView {
property string searchText: searchBar?.text property string searchText: searchBar?.text
property double busyIndicatorSize: 60 * DefaultStyle.dp property double busyIndicatorSize: 60 * DefaultStyle.dp
signal resultsReceived() signal resultsReceived
onResultsReceived: { onResultsReceived: {
loading = false loading = false
@ -29,7 +29,9 @@ ListView {
id: callHistoryProxy id: callHistoryProxy
filterText: mainItem.searchText filterText: mainItem.searchText
onFilterTextChanged: maxDisplayItems = initialDisplayItems onFilterTextChanged: maxDisplayItems = initialDisplayItems
initialDisplayItems: Math.max(20, 2 * mainItem.height / (56 * DefaultStyle.dp)) initialDisplayItems: Math.max(
20,
2 * mainItem.height / (56 * DefaultStyle.dp))
displayItemsStep: 3 * initialDisplayItems / 2 displayItemsStep: 3 * initialDisplayItems / 2
onModelReset: { onModelReset: {
mainItem.resultsReceived() mainItem.resultsReceived()
@ -38,27 +40,31 @@ ListView {
flickDeceleration: 10000 flickDeceleration: 10000
spacing: 10 * DefaultStyle.dp spacing: 10 * DefaultStyle.dp
Keys.onPressed: (event) => { Keys.onPressed: event => {
if(event.key == Qt.Key_Escape){ if (event.key == Qt.Key_Escape) {
console.log("Back") console.log("Back")
searchBar.forceActiveFocus() searchBar.forceActiveFocus()
event.accepted = true event.accepted = true
} }
} }
Component.onCompleted: cacheBuffer = Math.max(contentHeight,0)//contentHeight>0 ? contentHeight : 0// cache all items Component.onCompleted: cacheBuffer = Math.max(
contentHeight,
0) //contentHeight>0 ? contentHeight : 0// cache all items
// remove binding loop // remove binding loop
onContentHeightChanged: Qt.callLater(function(){ onContentHeightChanged: Qt.callLater(function () {
if (mainItem) mainItem.cacheBuffer = Math?.max(contentHeight,0) || 0 if (mainItem)
mainItem.cacheBuffer = Math?.max(contentHeight, 0) || 0
}) })
onActiveFocusChanged: if(activeFocus && currentIndex < 0 && count > 0) currentIndex = 0 onActiveFocusChanged: if (activeFocus && currentIndex < 0 && count > 0)
currentIndex = 0
onCountChanged: { onCountChanged: {
if(currentIndex < 0 && count > 0){ if (currentIndex < 0 && count > 0) {
mainItem.currentIndex = 0 // Select first item after loading model mainItem.currentIndex = 0 // Select first item after loading model
} }
if(atYBeginning) if (atYBeginning)
positionViewAtBeginning()// Stay at beginning positionViewAtBeginning() // Stay at beginning
} }
Connections { Connections {
target: deleteHistoryPopup target: deleteHistoryPopup
@ -68,13 +74,13 @@ ListView {
} }
onAtYEndChanged: { onAtYEndChanged: {
if(atYEnd && count > 0){ if (atYEnd && count > 0) {
callHistoryProxy.displayMore() callHistoryProxy.displayMore()
} }
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
function moveToCurrentItem(){ function moveToCurrentItem() {
if( mainItem.currentIndex >= 0) if (mainItem.currentIndex >= 0)
Utils.updatePosition(mainItem, mainItem) Utils.updatePosition(mainItem, mainItem)
} }
onCurrentItemChanged: { onCurrentItemChanged: {
@ -82,29 +88,29 @@ ListView {
} }
// Update position only if we are moving to current item and its position is changing. // Update position only if we are moving to current item and its position is changing.
property var _currentItemY: currentItem?.y property var _currentItemY: currentItem?.y
on_CurrentItemYChanged: if(_currentItemY && moveAnimation.running){ on_CurrentItemYChanged: if (_currentItemY && moveAnimation.running) {
moveToCurrentItem() moveToCurrentItem()
} }
Behavior on contentY{ Behavior on contentY {
NumberAnimation { NumberAnimation {
id: moveAnimation id: moveAnimation
duration: 500 duration: 500
easing.type: Easing.OutExpo easing.type: Easing.OutExpo
alwaysRunToEnd: true alwaysRunToEnd: true
} }
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
onVisibleChanged: { onVisibleChanged: {
if (!visible) currentIndex = -1 if (!visible)
currentIndex = -1
} }
// Qt bug: sometimes, containsMouse may not be send and update on each MouseArea. // 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. // So we need to use this variable to switch off all hovered items.
property int lastMouseContainsIndex: -1 property int lastMouseContainsIndex: -1
delegate: FocusScope { delegate: FocusScope {
width:mainItem.width width: mainItem.width
height: 56 * DefaultStyle.dp height: 56 * DefaultStyle.dp
visible: !!modelData visible: !!modelData
@ -115,7 +121,8 @@ ListView {
spacing: 10 * DefaultStyle.dp spacing: 10 * DefaultStyle.dp
Avatar { Avatar {
id: historyAvatar id: historyAvatar
property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.remoteAddress) property var contactObj: UtilsCpp.findFriendByAddress(
modelData.core.remoteAddress)
contact: contactObj?.value || null contact: contactObj?.value || null
displayNameVal: modelData.core.displayName displayNameVal: modelData.core.displayName
secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
@ -144,32 +151,32 @@ ListView {
EffectImage { EffectImage {
id: statusIcon id: statusIcon
imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted || modelData.core.status === LinphoneEnums.CallStatus.Aborted
? AppIcons.arrowElbow || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted ? AppIcons.arrowElbow : modelData.core.isOutgoing ? AppIcons.arrowUpRight : AppIcons.arrowDownLeft
: modelData.core.isOutgoing colorizationColor: modelData.core.status
? AppIcons.arrowUpRight === LinphoneEnums.CallStatus.Declined
: AppIcons.arrowDownLeft || modelData.core.status
colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere || modelData.core.status
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted || modelData.core.status
|| modelData.core.status === LinphoneEnums.CallStatus.Missed === LinphoneEnums.CallStatus.EarlyAborted
? DefaultStyle.danger_500main || modelData.core.status === LinphoneEnums.CallStatus.Missed ? DefaultStyle.danger_500main : modelData.core.isOutgoing ? DefaultStyle.info_500_main : DefaultStyle.success_500main
: modelData.core.isOutgoing
? DefaultStyle.info_500_main
: DefaultStyle.success_500main
Layout.preferredWidth: 12 * DefaultStyle.dp Layout.preferredWidth: 12 * DefaultStyle.dp
Layout.preferredHeight: 12 * DefaultStyle.dp Layout.preferredHeight: 12 * DefaultStyle.dp
transform: Rotation { transform: Rotation {
angle: modelData.core.isOutgoing && (modelData.core.status === LinphoneEnums.CallStatus.Declined angle: modelData.core.isOutgoing
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere && (modelData.core.status === LinphoneEnums.CallStatus.Declined
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0 === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status
=== LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0
origin { origin {
x: statusIcon.width/2 x: statusIcon.width / 2
y: statusIcon.height/2 y: statusIcon.height / 2
} }
} }
} }
@ -191,10 +198,10 @@ ListView {
onClicked: { onClicked: {
if (modelData.core.isConference) { if (modelData.core.isConference) {
var callsWindow = UtilsCpp.getCallsWindow() var callsWindow = UtilsCpp.getCallsWindow()
callsWindow.setupConference(modelData.core.conferenceInfo) callsWindow.setupConference(
modelData.core.conferenceInfo)
UtilsCpp.smartShowWindow(callsWindow) UtilsCpp.smartShowWindow(callsWindow)
} } else {
else {
UtilsCpp.createCall(modelData.core.remoteAddress) UtilsCpp.createCall(modelData.core.remoteAddress)
} }
} }
@ -205,17 +212,19 @@ ListView {
anchors.fill: parent anchors.fill: parent
focus: true focus: true
onContainsMouseChanged: { onContainsMouseChanged: {
if(containsMouse) if (containsMouse)
mainItem.lastMouseContainsIndex = index mainItem.lastMouseContainsIndex = index
else if( mainItem.lastMouseContainsIndex == index) else if (mainItem.lastMouseContainsIndex == index)
mainItem.lastMouseContainsIndex = -1 mainItem.lastMouseContainsIndex = -1
} }
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
opacity: 0.7 opacity: 0.7
radius: 8 * DefaultStyle.dp radius: 8 * DefaultStyle.dp
color: mainItem.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.main2_100 color: mainItem.currentIndex
visible: mainItem.lastMouseContainsIndex === index || mainItem.currentIndex === index === index ? DefaultStyle.main2_200 : DefaultStyle.main2_100
visible: mainItem.lastMouseContainsIndex === index
|| mainItem.currentIndex === index
} }
onPressed: { onPressed: {
mainItem.currentIndex = model.index mainItem.currentIndex = model.index

View file

@ -6,27 +6,28 @@ 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 import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
Flickable { Flickable {
id: mainItem id: mainItem
flickableDirection: Flickable.VerticalFlick flickableDirection: Flickable.VerticalFlick
property bool showInitials: true // Display Initials of Display name. property bool showInitials: true // Display Initials of Display name.
property bool showDefaultAddress: true // Display address below display name. property bool showDefaultAddress: true // Display address below display name.
property bool showActions: false // Display actions layout (call buttons) property bool showActions: false // Display actions layout (call buttons)
property bool showContactMenu: true // Display the dot menu for contacts. property bool showContactMenu: true // Display the dot menu for contacts.
property bool showFavorites: true // Display the favorites in the header property bool showFavorites: true // Display the favorites in the header
property bool hideSuggestions: false // Hide not stored contacts (not suggestions) property bool hideSuggestions: false // Hide not stored contacts (not suggestions)
property string highlightText: searchText // Bold characters in Display name. property string highlightText: searchText // Bold characters in Display name.
property var sourceFlags: LinphoneEnums.MagicSearchSource.All property var sourceFlags: LinphoneEnums.MagicSearchSource.All
property bool displayNameCapitalization: true // Capitalize display name. property bool displayNameCapitalization: true // Capitalize display name.
property bool selectionEnabled: true // Contact can be selected property bool selectionEnabled: true // Contact can be selected
property bool multiSelectionEnabled: false //Multiple items can be selected. property bool multiSelectionEnabled: false //Multiple items can be selected.
property list<string> selectedContacts // List of default address on selected contacts. property list<string> selectedContacts
// List of default address on selected contacts.
//property FriendGui selectedContact//: model.getAt(currentIndex) || null //property FriendGui selectedContact//: model.getAt(currentIndex) || null
property FriendGui highlightedContact property FriendGui highlightedContact
@ -38,7 +39,8 @@ Flickable {
// set searchBarText without specifying a model to bold // set searchBarText without specifying a model to bold
// matching names // matching names
property string searchBarText property string searchBarText
property string searchText// Binding is done on searchBarTextChanged property string searchText
// Binding is done on searchBarTextChanged
property ConferenceInfoGui confInfoGui property ConferenceInfoGui confInfoGui
property bool haveFavorites: false property bool haveFavorites: false
@ -54,19 +56,19 @@ Flickable {
contentHeight: contentsLayout.height contentHeight: contentsLayout.height
rightMargin: itemsRightMargin rightMargin: itemsRightMargin
signal contactStarredChanged() signal contactStarredChanged
signal contactDeletionRequested(FriendGui contact) signal contactDeletionRequested(FriendGui contact)
signal contactAddedToSelection(string address) signal contactAddedToSelection(string address)
signal contactRemovedFromSelection(string address) signal contactRemovedFromSelection(string address)
signal contactSelected(FriendGui contact) signal contactSelected(FriendGui contact)
function selectContact(address) { function selectContact(address) {
var index = contactsProxy.loadUntil(address)// Be sure to have this address in proxy if it exists var index = contactsProxy.loadUntil(
address) // Be sure to have this address in proxy if it exists
if (index != -1) { if (index != -1) {
contactsList.selectIndex(index) contactsList.selectIndex(index)
} }
return index return index
} }
function addContactToSelection(address) { function addContactToSelection(address) {
if (multiSelectionEnabled) { if (multiSelectionEnabled) {
@ -91,49 +93,59 @@ Flickable {
contactRemovedFromSelection(address) contactRemovedFromSelection(address)
} }
} }
function haveAddress(address){ function haveAddress(address) {
var index = magicSearchProxy.findFriendIndexByAddress(address) var index = magicSearchProxy.findFriendIndexByAddress(address)
return index != -1 return index != -1
} }
function resetSelections(){ function resetSelections() {
mainItem.highlightedContact = null mainItem.highlightedContact = null
favoritesList.currentIndex = -1 favoritesList.currentIndex = -1
contactsList.currentIndex = -1 contactsList.currentIndex = -1
suggestionsList.currentIndex = -1 suggestionsList.currentIndex = -1
} }
function findNextList(item, count, direction){ function findNextList(item, count, direction) {
if(count == 3) return null if (count == 3)
return null
var nextItem var nextItem
switch(item){ switch (item) {
case suggestionsList:nextItem=(direction > 0 ? favoritesList : contactsList);break; case suggestionsList:
case contactsList:nextItem=(direction > 0 ? suggestionsList : favoritesList);break; nextItem = (direction > 0 ? favoritesList : contactsList)
case favoritesList:nextItem=(direction > 0 ? contactsList : suggestionsList);break; break
default: return null 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 if (nextItem.model.count > 0)
else return findNextList(nextItem, count+1, direction) return nextItem
else
return findNextList(nextItem, count + 1, direction)
} }
function updatePosition(list){ function updatePosition(list) {
Utils.updatePosition(mainItem, list) Utils.updatePosition(mainItem, list)
} }
onHighlightedContactChanged:{ onHighlightedContactChanged: {
favoritesList.highlightedContact = highlightedContact favoritesList.highlightedContact = highlightedContact
contactsList.highlightedContact = highlightedContact contactsList.highlightedContact = highlightedContact
suggestionsList.highlightedContact = highlightedContact suggestionsList.highlightedContact = highlightedContact
} }
onSearchBarTextChanged: { onSearchBarTextChanged: {
if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) { if (!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) {
console.log("change search text") console.log("change search text")
searchText = searchBarText.length === 0 ? "*" : searchBarText searchText = searchBarText.length === 0 ? "*" : searchBarText
} }
} }
onPauseSearchChanged: { onPauseSearchChanged: {
if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')){ if (!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) {
searchText = searchBarText.length === 0 ? "*" : searchBarText searchText = searchBarText.length === 0 ? "*" : searchBarText
} }
} }
@ -142,26 +154,37 @@ Flickable {
loading = true loading = true
} }
Keys.onPressed: (event)=> { Keys.onPressed: event => {
if(!event.accepted){ if (!event.accepted) {
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){ if (event.key == Qt.Key_Up
var newItem || event.key == Qt.Key_Down) {
var direction = (event.key == Qt.Key_Up ? -1 : 1) var newItem
if(suggestionsList.activeFocus) newItem = findNextList(suggestionsList, 0, direction) var direction = (event.key == Qt.Key_Up ? -1 : 1)
else if(contactsList.activeFocus) newItem = findNextList(contactsList, 0, direction) if (suggestionsList.activeFocus)
else if(favoritesList.activeFocus) newItem = findNextList(favoritesList, 0, direction) newItem = findNextList(suggestionsList, 0,
else newItem = findNextList(suggestionsList, 0, direction) direction)
if(newItem){ else if (contactsList.activeFocus)
newItem.selectIndex(direction > 0 ? -1 : newItem.model.count - 1) newItem = findNextList(contactsList, 0,
event.accepted = true direction)
} else if (favoritesList.activeFocus)
} newItem = findNextList(favoritesList, 0,
} direction)
} else
newItem = findNextList(suggestionsList, 0,
direction)
if (newItem) {
newItem.selectIndex(
direction > 0 ? -1 : newItem.model.count - 1)
event.accepted = true
}
}
}
}
Component.onCompleted: { Component.onCompleted: {
if (confInfoGui) { if (confInfoGui) {
for(var i = 0; i < confInfoGui.core.participants.length; ++i) { for (var i = 0; i < confInfoGui.core.participants.length; ++i) {
selectedContacts.push(confInfoGui.core.getParticipantAddressAt(i)); selectedContacts.push(
confInfoGui.core.getParticipantAddressAt(i))
} }
} }
} }
@ -181,7 +204,6 @@ Flickable {
sourceFlags: mainItem.sourceFlags sourceFlags: mainItem.sourceFlags
onModelReset: { onModelReset: {
mainItem.resetSelections() mainItem.resetSelections()
} }
onResultsProcessed: { onResultsProcessed: {
mainItem.loading = false mainItem.loading = false
@ -189,18 +211,21 @@ Flickable {
} }
onInitialized: { onInitialized: {
if(mainItem.searchOnEmpty || searchText != '' ) { if (mainItem.searchOnEmpty || searchText != '') {
mainItem.loading = true mainItem.loading = true
forceUpdate() forceUpdate()
} }
} }
} }
onAtYEndChanged: if(atYEnd) { onAtYEndChanged: if (atYEnd) {
if( (contactsProxy.haveMore && contactList.expanded ) || mainItem.hideSuggestions) contactsProxy.displayMore() if ((contactsProxy.haveMore && contactList.expanded)
else suggestionsProxy.displayMore() || mainItem.hideSuggestions)
} contactsProxy.displayMore()
Behavior on contentY{ else
suggestionsProxy.displayMore()
}
Behavior on contentY {
NumberAnimation { NumberAnimation {
duration: 500 duration: 500
easing.type: Easing.OutExpo easing.type: Easing.OutExpo
@ -210,7 +235,7 @@ Flickable {
Control.ScrollBar.vertical: ScrollBar { Control.ScrollBar.vertical: ScrollBar {
id: scrollbar id: scrollbar
z: 1 z: 1
topPadding: 24 * DefaultStyle.dp // Avoid to be on top of collapse button topPadding: 24 * DefaultStyle.dp // Avoid to be on top of collapse button
active: true active: true
interactive: true interactive: true
visible: mainItem.contentHeight > mainItem.height visible: mainItem.contentHeight > mainItem.height
@ -220,7 +245,7 @@ Flickable {
ColumnLayout { ColumnLayout {
id: contentsLayout id: contentsLayout
width: mainItem.width width: mainItem.width
spacing: 0//20 * DefaultStyle.dp spacing: 0 //20 * DefaultStyle.dp
BusyIndicator { BusyIndicator {
id: busyIndicator id: busyIndicator
@ -232,7 +257,7 @@ Flickable {
Layout.alignment: Qt.AlignCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignCenter | Qt.AlignVCenter
} }
ContactListView{ ContactListView {
id: favoritesList id: favoritesList
visible: contentHeight > 0 visible: contentHeight > 0
Layout.fillWidth: true Layout.fillWidth: true
@ -252,22 +277,32 @@ Flickable {
itemsRightMargin: mainItem.itemsRightMargin itemsRightMargin: mainItem.itemsRightMargin
onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact
onContactSelected: (contactGui) => { onContactSelected: contactGui => {
mainItem.contactSelected(contactGui) mainItem.contactSelected(contactGui)
} }
onUpdatePosition: mainItem.updatePosition(favoritesList) onUpdatePosition: mainItem.updatePosition(favoritesList)
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} onContactDeletionRequested: contact => {
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} mainItem.contactDeletionRequested(
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} contact)
}
onAddContactToSelection: address => {
mainItem.addContactToSelection(address)
}
onRemoveContactFromSelection: index => {
mainItem.removeContactFromSelection(
index)
}
property MagicSearchProxy proxy: MagicSearchProxy { property MagicSearchProxy proxy: MagicSearchProxy {
parentProxy: mainItem.mainModel parentProxy: mainItem.mainModel
filterType: MagicSearchProxy.FilteringTypes.Favorites filterType: MagicSearchProxy.FilteringTypes.Favorites
} }
model : mainItem.showFavorites && (mainItem.searchBarText == ''|| mainItem.searchBarText == '*')? proxy : [] model: mainItem.showFavorites
&& (mainItem.searchBarText == ''
|| mainItem.searchBarText == '*') ? proxy : []
} }
ContactListView{ ContactListView {
id: contactsList id: contactsList
visible: contentHeight > 0 visible: contentHeight > 0
Layout.fillWidth: true Layout.fillWidth: true
@ -286,32 +321,45 @@ Flickable {
title: qsTr('Contacts') title: qsTr('Contacts')
onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact
onContactSelected: (contactGui) => { onContactSelected: contactGui => {
mainItem.contactSelected(contactGui) mainItem.contactSelected(contactGui)
} }
onUpdatePosition: mainItem.updatePosition(contactsList) onUpdatePosition: mainItem.updatePosition(contactsList)
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} onContactDeletionRequested: contact => {
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} mainItem.contactDeletionRequested(
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} contact)
}
onAddContactToSelection: address => {
mainItem.addContactToSelection(address)
}
onRemoveContactFromSelection: index => {
mainItem.removeContactFromSelection(
index)
}
model:MagicSearchProxy { model: MagicSearchProxy {
id: contactsProxy id: contactsProxy
parentProxy: mainItem.mainModel parentProxy: mainItem.mainModel
filterType: MagicSearchProxy.FilteringTypes.App filterType: MagicSearchProxy.FilteringTypes.App
| (mainItem.searchText != '*' && mainItem.searchText != '' || SettingsCpp.syncLdapContacts ? MagicSearchProxy.FilteringTypes.Ldap | MagicSearchProxy.FilteringTypes.CardDAV: 0) | (mainItem.searchText != '*'
initialDisplayItems: Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp)) && mainItem.searchText != ''
|| SettingsCpp.syncLdapContacts ? MagicSearchProxy.FilteringTypes.Ldap | MagicSearchProxy.FilteringTypes.CardDAV : 0)
initialDisplayItems: Math.max(
20,
2 * mainItem.height / (63 * DefaultStyle.dp))
displayItemsStep: 3 * initialDisplayItems / 2 displayItemsStep: 3 * initialDisplayItems / 2
onLocalFriendCreated: (index) => { onLocalFriendCreated: index => {
contactsList.selectIndex(index) contactsList.selectIndex(index)
} }
} }
} }
ContactListView{ ContactListView {
id: suggestionsList id: suggestionsList
visible: contentHeight > 0 visible: contentHeight > 0
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: implicitHeight Layout.preferredHeight: implicitHeight
Layout.topMargin: contactsList.height + favoritesList.height > 0 ? 4 * DefaultStyle.dp : 0 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
@ -325,18 +373,30 @@ Flickable {
itemsRightMargin: mainItem.itemsRightMargin itemsRightMargin: mainItem.itemsRightMargin
onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact
onContactSelected: (contactGui) => { onContactSelected: contactGui => {
mainItem.contactSelected(contactGui) mainItem.contactSelected(contactGui)
} }
onUpdatePosition: mainItem.updatePosition(suggestionsList) onUpdatePosition: mainItem.updatePosition(suggestionsList)
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)} onContactDeletionRequested: contact => {
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)} mainItem.contactDeletionRequested(
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)} contact)
model:MagicSearchProxy { }
onAddContactToSelection: address => {
mainItem.addContactToSelection(address)
}
onRemoveContactFromSelection: index => {
mainItem.removeContactFromSelection(
index)
}
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: contactsProxy.haveMore && contactsList.expanded ? 0 : Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp)) initialDisplayItems: contactsProxy.haveMore
&& contactsList.expanded ? 0 : Math.max(
20,
2 * mainItem.height
/ (63 * DefaultStyle.dp))
onInitialDisplayItemsChanged: maxDisplayItems = initialDisplayItems onInitialDisplayItemsChanged: maxDisplayItems = initialDisplayItems
displayItemsStep: 3 * initialDisplayItems / 2 displayItemsStep: 3 * initialDisplayItems / 2
onModelReset: maxDisplayItems = initialDisplayItems onModelReset: maxDisplayItems = initialDisplayItems

View file

@ -6,243 +6,291 @@ 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/Style/buttonStyle.js' as ButtonStyle import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
FocusScope { FocusScope {
id: mainItem id: mainItem
implicitHeight: visible ? 56 * DefaultStyle.dp : 0 implicitHeight: visible ? 56 * DefaultStyle.dp : 0
property var searchResultItem property var searchResultItem
property bool showInitials: true // Display Initials of Display name. property bool showInitials: true // Display Initials of Display name.
property bool showDefaultAddress: true // Display address below display name. property bool showDefaultAddress: true // Display address below display name.
property bool showActions: false // Display actions layout (call buttons) property bool showActions: false // Display actions layout (call buttons)
property bool showContactMenu: true // Display the dot menu for contacts. property bool showContactMenu: true // Display the dot menu for contacts.
property string highlightText // Bold characters in Display name. property string highlightText
property bool displayNameCapitalization: true // Capitalize display name. // Bold characters in Display name.
property bool displayNameCapitalization: true // Capitalize display name.
property bool selectionEnabled: true // Contact can be selected property bool selectionEnabled: true // Contact can be selected
property bool multiSelectionEnabled: false //Multiple items can be selected. property bool multiSelectionEnabled: false //Multiple items can be selected.
property list<string> selectedContacts // List of default address on selected contacts. property list<string> selectedContacts
property bool isSelected: false // selected in list => currentIndex == index // List of default address on selected contacts.
property bool isLastHovered: false property bool isSelected: false // selected in list => currentIndex == index
property bool isLastHovered: false
property var previousInitial // Use directly previous initial property var previousInitial
property int itemsRightMargin: 39 * DefaultStyle.dp // Use directly previous initial
property int itemsRightMargin: 39 * DefaultStyle.dp
property var displayName: searchResultItem.core.fullName property var displayName: searchResultItem.core.fullName
property string initial: displayName ? displayName[0].toLocaleLowerCase(ConstantsCpp.DefaultLocale) : '' property string initial: displayName ? displayName[0].toLocaleLowerCase(
ConstantsCpp.DefaultLocale) : ''
signal clicked(var mouse) signal clicked(var mouse)
signal contactDeletionRequested(FriendGui contact) signal contactDeletionRequested(FriendGui contact)
signal containsMouseChanged(bool containsMouse) signal containsMouseChanged(bool containsMouse)
Text { Text {
id: initial id: initial
anchors.left: parent.left anchors.left: parent.left
visible: mainItem.showInitials visible: mainItem.showInitials
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 15 * DefaultStyle.dp anchors.rightMargin: 15 * DefaultStyle.dp
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
width: 20 * DefaultStyle.dp width: 20 * DefaultStyle.dp
opacity: previousInitial != mainItem.initial ? 1 : 0 opacity: previousInitial != mainItem.initial ? 1 : 0
text: mainItem.initial text: mainItem.initial
color: DefaultStyle.main2_400 color: DefaultStyle.main2_400
font { font {
pixelSize: 20 * DefaultStyle.dp pixelSize: 20 * DefaultStyle.dp
weight: 500 * DefaultStyle.dp weight: 500 * DefaultStyle.dp
capitalization: Font.AllUppercase capitalization: Font.AllUppercase
} }
} }
RowLayout { RowLayout {
id: contactDelegate id: contactDelegate
anchors.left: initial.visible ? initial.right : parent.left anchors.left: initial.visible ? initial.right : parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: mainItem.itemsRightMargin anchors.rightMargin: mainItem.itemsRightMargin
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
spacing: 16 * DefaultStyle.dp spacing: 16 * DefaultStyle.dp
z: 1 z: 1
Avatar { Avatar {
Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp
Layout.leftMargin: 5 * DefaultStyle.dp Layout.leftMargin: 5 * DefaultStyle.dp
contact: searchResultItem contact: searchResultItem
shadowEnabled: false shadowEnabled: false
} }
ColumnLayout { ColumnLayout {
spacing: 0 spacing: 0
Text { Text {
text: UtilsCpp.boldTextPart(mainItem.displayName, mainItem.highlightText) text: UtilsCpp.boldTextPart(mainItem.displayName,
font{ mainItem.highlightText)
pixelSize: mainItem.showDefaultAddress ? 16 * DefaultStyle.dp : 14 * DefaultStyle.dp font {
capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase pixelSize: mainItem.showDefaultAddress ? 16 * DefaultStyle.dp : 14
weight: mainItem.showDefaultAddress ? 800 * DefaultStyle.dp : 400 * DefaultStyle.dp * DefaultStyle.dp
} capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase
maximumLineCount: 1 weight: mainItem.showDefaultAddress ? 800 * DefaultStyle.dp : 400
Layout.fillWidth: true * DefaultStyle.dp
} }
Text { maximumLineCount: 1
Layout.topMargin: 2 * DefaultStyle.dp Layout.fillWidth: true
Layout.fillWidth: true }
visible: mainItem.showDefaultAddress Text {
property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(searchResultItem.core.defaultAddress) : searchResultItem.core.defaultAddress Layout.topMargin: 2 * DefaultStyle.dp
text: UtilsCpp.boldTextPart(address, mainItem.highlightText) Layout.fillWidth: true
maximumLineCount: 1 visible: mainItem.showDefaultAddress
elide: Text.ElideRight property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(searchResultItem.core.defaultAddress) : searchResultItem.core.defaultAddress
font { text: UtilsCpp.boldTextPart(address, mainItem.highlightText)
weight: 300 * DefaultStyle.dp maximumLineCount: 1
pixelSize: 12 * DefaultStyle.dp elide: Text.ElideRight
} font {
} weight: 300 * DefaultStyle.dp
} pixelSize: 12 * DefaultStyle.dp
Item{Layout.fillWidth: true} }
RowLayout { }
id: actionsRow }
z: 1 Item {
visible: actionButtons || friendPopup.visible || mainItem.multiSelectionEnabled Layout.fillWidth: true
spacing: visible ? 16 * DefaultStyle.dp : 0 }
Layout.rightMargin: visible ? 10 * DefaultStyle.dp : 0 Loader {
EffectImage { id: buttonsLayoutLoader
id: isSelectedCheck asynchronous: true
visible: mainItem.multiSelectionEnabled && (mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress) != -1) active: mainItem.showActions || mainItem.showContactMenu
Layout.preferredWidth: 24 * DefaultStyle.dp || mainItem.multiSelectionEnabled
Layout.preferredHeight: 24 * DefaultStyle.dp Layout.rightMargin: active ? 10 * DefaultStyle.dp : 0
imageSource: AppIcons.check sourceComponent: RowLayout {
colorizationColor: DefaultStyle.main1_500_main id: actionsRow
} z: 1
RowLayout{ visible: actionButtons.visible || friendPopup.visible
id: actionButtons || mainItem.multiSelectionEnabled
visible: mainItem.showActions spacing: visible ? 16 * DefaultStyle.dp : 0
spacing: visible ? 10 * DefaultStyle.dp : 0 enabled: visible
IconButton { EffectImage {
id: callButton id: isSelectedCheck
Layout.preferredWidth: 45 * DefaultStyle.dp visible: mainItem.multiSelectionEnabled
Layout.preferredHeight: 45 * DefaultStyle.dp && (mainItem.selectedContacts.indexOf(
icon.width: 24 * DefaultStyle.dp searchResultItem.core.defaultAddress) != -1)
icon.height: 24 * DefaultStyle.dp Layout.preferredWidth: 24 * DefaultStyle.dp
icon.source: AppIcons.phone Layout.preferredHeight: 24 * DefaultStyle.dp
focus: visible imageSource: AppIcons.check
radius: 40 * DefaultStyle.dp colorizationColor: DefaultStyle.main1_500_main
style: ButtonStyle.grey }
onClicked: UtilsCpp.createCall(searchResultItem.core.defaultFullAddress) RowLayout {
KeyNavigation.left: chatButton id: actionButtons
KeyNavigation.right: videoCallButton visible: mainItem.showActions
} spacing: visible ? 10 * DefaultStyle.dp : 0
IconButton { IconButton {
id: videoCallButton id: callButton
Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp icon.height: 24 * DefaultStyle.dp
icon.source: AppIcons.videoCamera icon.source: AppIcons.phone
focus: visible && !callButton.visible focus: visible
radius: 40 * DefaultStyle.dp radius: 40 * DefaultStyle.dp
style: ButtonStyle.grey style: ButtonStyle.grey
onClicked: UtilsCpp.createCall(searchResultItem.core.defaultFullAddress, {'localVideoEnabled': true}) onClicked: UtilsCpp.createCall(
KeyNavigation.left: callButton searchResultItem.core.defaultFullAddress)
KeyNavigation.right: chatButton KeyNavigation.left: chatButton
} KeyNavigation.right: videoCallButton
IconButton { }
id: chatButton IconButton {
visible: actionButtons.visible && !SettingsCpp.disableChatFeature id: videoCallButton
Layout.preferredWidth: 45 * DefaultStyle.dp Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp Layout.preferredHeight: 45 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp icon.height: 24 * DefaultStyle.dp
icon.source: AppIcons.chatTeardropText icon.source: AppIcons.videoCamera
focus: visible && !callButton.visible && !videoCallButton.visible focus: visible && !callButton.visible
radius: 40 * DefaultStyle.dp radius: 40 * DefaultStyle.dp
style: ButtonStyle.grey style: ButtonStyle.grey
KeyNavigation.left: videoCallButton onClicked: UtilsCpp.createCall(
KeyNavigation.right: callButton searchResultItem.core.defaultFullAddress,
} {
} "localVideoEnabled": true
PopupButton { })
id: friendPopup KeyNavigation.left: callButton
z: 1 KeyNavigation.right: chatButton
popup.x: 0 }
popup.padding: 10 * DefaultStyle.dp IconButton {
visible: mainItem.showContactMenu && (contactArea.containsMouse || hovered || popup.opened) id: chatButton
visible: actionButtons.visible
&& !SettingsCpp.disableChatFeature
Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
icon.source: AppIcons.chatTeardropText
focus: visible && !callButton.visible
&& !videoCallButton.visible
radius: 40 * DefaultStyle.dp
style: ButtonStyle.grey
KeyNavigation.left: videoCallButton
KeyNavigation.right: callButton
}
}
PopupButton {
id: friendPopup
z: 1
popup.x: 0
popup.padding: 10 * DefaultStyle.dp
visible: mainItem.showContactMenu
&& (contactArea.containsMouse || hovered
|| popup.opened)
enabled: visible
popup.contentItem: ColumnLayout { popup.contentItem: ColumnLayout {
IconLabelButton { IconLabelButton {
visible: searchResultItem.core.isStored && !searchResultItem.core.readOnly visible: searchResultItem.core.isStored
text: searchResultItem.core.starred ? qsTr("Enlever des favoris") : qsTr("Mettre en favori") && !searchResultItem.core.readOnly
icon.source: searchResultItem.core.starred ? AppIcons.heartFill : AppIcons.heart text: searchResultItem.core.starred ? qsTr(
spacing: 10 * DefaultStyle.dp "Enlever des favoris") : qsTr(
textColor: DefaultStyle.main2_500main "Mettre en favori")
hoveredImageColor: searchResultItem.core.starred ? DefaultStyle.main1_700 : DefaultStyle.danger_700 icon.source: searchResultItem.core.starred ? AppIcons.heartFill : AppIcons.heart
contentImageColor: searchResultItem.core.starred ? DefaultStyle.danger_500main : DefaultStyle.main2_600 spacing: 10 * DefaultStyle.dp
onClicked: { textColor: DefaultStyle.main2_500main
searchResultItem.core.lSetStarred(!searchResultItem.core.starred) hoveredImageColor: searchResultItem.core.starred ? DefaultStyle.main1_700 : DefaultStyle.danger_700
friendPopup.close() contentImageColor: searchResultItem.core.starred ? DefaultStyle.danger_500main : DefaultStyle.main2_600
} onClicked: {
style: ButtonStyle.noBackground searchResultItem.core.lSetStarred(
} !searchResultItem.core.starred)
IconLabelButton { friendPopup.close()
text: qsTr("Partager") }
icon.source: AppIcons.shareNetwork style: ButtonStyle.noBackground
spacing: 10 * DefaultStyle.dp }
textColor: DefaultStyle.main2_500main IconLabelButton {
onClicked: { text: qsTr("Partager")
var vcard = searchResultItem.core.getVCard() icon.source: AppIcons.shareNetwork
var username = searchResultItem.core.givenName + searchResultItem.core.familyName spacing: 10 * DefaultStyle.dp
var filepath = UtilsCpp.createVCardFile(username, vcard) textColor: DefaultStyle.main2_500main
if (filepath == "") UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La création du fichier vcard a échoué"), false) onClicked: {
else mainWindow.showInformationPopup(qsTr("VCard créée"), qsTr("VCard du contact enregistrée dans %1").arg(filepath)) var vcard = searchResultItem.core.getVCard()
UtilsCpp.shareByEmail(qsTr("Partage de contact"), vcard, filepath) var username = searchResultItem.core.givenName
} + searchResultItem.core.familyName
style: ButtonStyle.noBackground var filepath = UtilsCpp.createVCardFile(
username, vcard)
if (filepath == "")
UtilsCpp.showInformationPopup(
qsTr("Erreur"), qsTr(
"La création du fichier vcard a échoué"),
false)
else
mainWindow.showInformationPopup(
qsTr("VCard créée"), qsTr(
"VCard du contact enregistrée dans %1").arg(
filepath))
UtilsCpp.shareByEmail(
qsTr("Partage de contact"),
vcard, filepath)
}
style: ButtonStyle.noBackground
}
IconLabelButton {
text: qsTr("Supprimer")
icon.source: AppIcons.trashCan
spacing: 10 * DefaultStyle.dp
visible: !searchResultItem.core.readOnly
onClicked: {
mainItem.contactDeletionRequested(
searchResultItem)
friendPopup.close()
}
style: ButtonStyle.noBackgroundRed
}
}
}
}
}
}
} MouseArea {
IconLabelButton { id: contactArea
text: qsTr("Supprimer") enabled: mainItem.selectionEnabled
icon.source: AppIcons.trashCan anchors.fill: contactDelegate
spacing: 10 * DefaultStyle.dp //height: mainItem.height
visible: !searchResultItem.core.readOnly hoverEnabled: true
onClicked: { acceptedButtons: Qt.AllButtons
mainItem.contactDeletionRequested(searchResultItem) z: -1
friendPopup.close() focus: !buttonsLayoutLoader.active
} onContainsMouseChanged: {
style: ButtonStyle.noBackgroundRed mainItem.containsMouseChanged(containsMouse)
} }
} Rectangle {
} anchors.fill: contactArea
} radius: 8 * DefaultStyle.dp
} opacity: 0.7
color: mainItem.isSelected ? DefaultStyle.main2_200 : DefaultStyle.main2_100
MouseArea { visible: mainItem.isLastHovered || mainItem.isSelected
id: contactArea }
enabled: mainItem.selectionEnabled Keys.onPressed: event => {
anchors.fill: contactDelegate if (event.key == Qt.Key_Space
//height: mainItem.height || event.key == Qt.Key_Enter
hoverEnabled: true || event.key == Qt.Key_Return) {
acceptedButtons: Qt.AllButtons contactArea.clicked(undefined)
z: -1 event.accepted = true
focus: !actionButtons.visible }
onContainsMouseChanged: { }
mainItem.containsMouseChanged(containsMouse) onClicked: mouse => {
} forceActiveFocus()
Rectangle { if (mouse && mouse.button == Qt.RightButton
anchors.fill: contactArea && mainItem.showContactMenu) {
radius: 8 * DefaultStyle.dp friendPopup.open()
opacity: 0.7 } else {
color: mainItem.isSelected ? DefaultStyle.main2_200 : DefaultStyle.main2_100 mainItem.clicked(mouse)
visible: mainItem.isLastHovered || friendPopup.hovered || mainItem.isSelected || friendPopup.visible }
} }
Keys.onPressed: (event)=> { }
if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) {
contactArea.clicked(undefined)
event.accepted = true;
}
}
onClicked: (mouse) => {
forceActiveFocus()
if (mouse && mouse.button == Qt.RightButton && mainItem.showContactMenu) {
friendPopup.open()
} else {
mainItem.clicked(mouse)
}
}
}
} }

File diff suppressed because it is too large Load diff