mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
asynchronous actions buttons to improve performances
This commit is contained in:
parent
586dca5cd0
commit
3629732fde
5 changed files with 1298 additions and 1061 deletions
|
|
@ -2,162 +2,191 @@ import QtQuick
|
|||
import QtQuick.Controls.Basic as Control
|
||||
import QtQuick.Effects
|
||||
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 {
|
||||
id: mainItem
|
||||
property alias popup: popup
|
||||
property bool shadowEnabled: mainItem.activeFocus || hovered
|
||||
property alias popupBackgroundColor: popupBackground.color
|
||||
property color backgroundColor: checked
|
||||
? pressedColor
|
||||
: hovered
|
||||
? hoveredColor
|
||||
: color
|
||||
style: ButtonStyle.popupButton
|
||||
checked: popup.visible
|
||||
implicitWidth: 24 * DefaultStyle.dp
|
||||
implicitHeight: 24 * DefaultStyle.dp
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
icon.source: AppIcons.verticalDots
|
||||
icon.width: 24 * DefaultStyle.dp
|
||||
icon.height: 24 * DefaultStyle.dp
|
||||
function close() {
|
||||
popup.close()
|
||||
}
|
||||
function open() {
|
||||
popup.open()
|
||||
}
|
||||
|
||||
function isFocusable(item){
|
||||
return item.activeFocusOnTab
|
||||
}
|
||||
function getPreviousItem(index){
|
||||
return _getPreviousItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, index)
|
||||
}
|
||||
function getNextItem(index){
|
||||
return _getNextItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, index)
|
||||
}
|
||||
|
||||
function _getPreviousItem(content, index){
|
||||
if(content.visibleChildren.length == 0) return null
|
||||
--index
|
||||
while(index >= 0){
|
||||
if( isFocusable(content.children[index]) && content.children[index].visible) return content.children[index]
|
||||
--index
|
||||
}
|
||||
return _getPreviousItem(content, content.children.length)
|
||||
}
|
||||
function _getNextItem(content, index){
|
||||
++index
|
||||
while(index < content.children.length){
|
||||
if( isFocusable(content.children[index]) && content.children[index].visible) return content.children[index]
|
||||
++index
|
||||
}
|
||||
return _getNextItem(content, -1)
|
||||
}
|
||||
id: mainItem
|
||||
property alias popup: popup
|
||||
property bool shadowEnabled: mainItem.activeFocus || hovered
|
||||
property alias popupBackgroundColor: popupBackground.color
|
||||
property color backgroundColor: checked ? pressedColor : hovered ? hoveredColor : color
|
||||
style: ButtonStyle.popupButton
|
||||
checked: popup.visible
|
||||
implicitWidth: 24 * DefaultStyle.dp
|
||||
implicitHeight: 24 * DefaultStyle.dp
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
icon.source: AppIcons.verticalDots
|
||||
icon.width: 24 * DefaultStyle.dp
|
||||
icon.height: 24 * DefaultStyle.dp
|
||||
function close() {
|
||||
popup.close()
|
||||
}
|
||||
function open() {
|
||||
popup.open()
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if(mainItem.checked){
|
||||
if( event.key == Qt.Key_Escape || event.key == Qt.Key_Left || event.key == Qt.Key_Space){
|
||||
mainItem.close()
|
||||
mainItem.forceActiveFocus()
|
||||
event.accepted = true
|
||||
}else if(event.key == Qt.Key_Up){
|
||||
getPreviousItem(0).forceActiveFocus()
|
||||
event.accepted = true
|
||||
}else if(event.key == Qt.Key_Tab || event.key == Qt.Key_Down){
|
||||
getNextItem(-1).forceActiveFocus()
|
||||
event.accepted = true
|
||||
}
|
||||
}else if(event.key == Qt.Key_Space){
|
||||
mainItem.open()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
background: Item {
|
||||
anchors.fill: mainItem
|
||||
Rectangle {
|
||||
id: buttonBackground
|
||||
anchors.fill: parent
|
||||
color: mainItem.backgroundColor
|
||||
radius: 40 * DefaultStyle.dp
|
||||
}
|
||||
MultiEffect {
|
||||
enabled: mainItem.shadowEnabled
|
||||
anchors.fill: buttonBackground
|
||||
source: buttonBackground
|
||||
visible: mainItem.shadowEnabled
|
||||
// Crash : https://bugreports.qt.io/browse/QTBUG-124730
|
||||
shadowEnabled: true //mainItem.shadowEnabled
|
||||
shadowColor: DefaultStyle.grey_1000
|
||||
shadowBlur: 0.1
|
||||
shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0
|
||||
}
|
||||
}
|
||||
contentItem: EffectImage {
|
||||
imageSource: mainItem.icon.source
|
||||
imageWidth: mainItem.icon.width
|
||||
imageHeight: mainItem.icon.height
|
||||
colorizationColor: mainItem.contentImageColor
|
||||
}
|
||||
onPressed: {
|
||||
if (popup.visible) popup.close()
|
||||
else popup.open()
|
||||
}
|
||||
Control.Popup {
|
||||
id: popup
|
||||
x: 0
|
||||
y: mainItem.height
|
||||
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside | Popup.CloseOnEscape
|
||||
padding: 10 * DefaultStyle.dp
|
||||
parent: mainItem // Explicit define for coordinates references.
|
||||
function updatePosition(){
|
||||
if (!visible) return
|
||||
var popupHeight = popup.height + popup.padding
|
||||
var popupWidth = popup.width + popup.padding
|
||||
var winPosition = mainItem.Window.contentItem ? mainItem.Window.contentItem.mapToItem(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)
|
||||
onWidthChanged: Qt.callLater(updatePosition)
|
||||
onVisibleChanged: Qt.callLater(updatePosition)
|
||||
|
||||
Connections{
|
||||
target: mainItem.Window
|
||||
function onHeightChanged(){ Qt.callLater(popup.updatePosition)}
|
||||
function onWidthChanged(){ Qt.callLater(popup.updatePosition)}
|
||||
}
|
||||
function isFocusable(item) {
|
||||
return item.activeFocusOnTab
|
||||
}
|
||||
function getPreviousItem(index) {
|
||||
return _getPreviousItem(
|
||||
popup.contentItem
|
||||
instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem,
|
||||
index)
|
||||
}
|
||||
function getNextItem(index) {
|
||||
return _getNextItem(
|
||||
popup.contentItem
|
||||
instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem,
|
||||
index)
|
||||
}
|
||||
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
id: popupBackground
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.grey_0
|
||||
radius: 16 * DefaultStyle.dp
|
||||
}
|
||||
MultiEffect {
|
||||
source: popupBackground
|
||||
anchors.fill: popupBackground
|
||||
shadowEnabled: true
|
||||
shadowBlur: 0.1
|
||||
shadowColor: DefaultStyle.grey_1000
|
||||
shadowOpacity: 0.4
|
||||
}
|
||||
}
|
||||
}
|
||||
function _getPreviousItem(content, index) {
|
||||
if (content.visibleChildren.length == 0)
|
||||
return null
|
||||
--index
|
||||
while (index >= 0) {
|
||||
if (isFocusable(content.children[index])
|
||||
&& content.children[index].visible)
|
||||
return content.children[index]
|
||||
--index
|
||||
}
|
||||
return _getPreviousItem(content, content.children.length)
|
||||
}
|
||||
function _getNextItem(content, index) {
|
||||
++index
|
||||
while (index < content.children.length) {
|
||||
if (isFocusable(content.children[index])
|
||||
&& content.children[index].visible)
|
||||
return content.children[index]
|
||||
++index
|
||||
}
|
||||
return _getNextItem(content, -1)
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (mainItem.checked) {
|
||||
if (event.key == Qt.Key_Escape
|
||||
|| event.key == Qt.Key_Left
|
||||
|| event.key == Qt.Key_Space) {
|
||||
mainItem.close()
|
||||
mainItem.forceActiveFocus()
|
||||
event.accepted = true
|
||||
} else if (event.key == Qt.Key_Up) {
|
||||
getPreviousItem(0).forceActiveFocus()
|
||||
event.accepted = true
|
||||
} else if (event.key == Qt.Key_Tab
|
||||
|| event.key == Qt.Key_Down) {
|
||||
getNextItem(-1).forceActiveFocus()
|
||||
event.accepted = true
|
||||
}
|
||||
} else if (event.key == Qt.Key_Space) {
|
||||
mainItem.open()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
background: Item {
|
||||
anchors.fill: mainItem
|
||||
Rectangle {
|
||||
id: buttonBackground
|
||||
anchors.fill: parent
|
||||
color: mainItem.backgroundColor
|
||||
radius: 40 * DefaultStyle.dp
|
||||
}
|
||||
MultiEffect {
|
||||
enabled: mainItem.shadowEnabled
|
||||
anchors.fill: buttonBackground
|
||||
source: buttonBackground
|
||||
visible: mainItem.shadowEnabled
|
||||
// Crash : https://bugreports.qt.io/browse/QTBUG-124730
|
||||
shadowEnabled: true //mainItem.shadowEnabled
|
||||
shadowColor: DefaultStyle.grey_1000
|
||||
shadowBlur: 0.1
|
||||
shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0
|
||||
}
|
||||
}
|
||||
contentItem: EffectImage {
|
||||
imageSource: mainItem.icon.source
|
||||
imageWidth: mainItem.icon.width
|
||||
imageHeight: mainItem.icon.height
|
||||
colorizationColor: mainItem.contentImageColor
|
||||
}
|
||||
onPressed: {
|
||||
if (popup.visible)
|
||||
popup.close()
|
||||
else
|
||||
popup.open()
|
||||
}
|
||||
Control.Popup {
|
||||
id: popup
|
||||
x: 0
|
||||
y: mainItem.height
|
||||
visible: false
|
||||
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside
|
||||
| Popup.CloseOnEscape
|
||||
padding: 10 * DefaultStyle.dp
|
||||
parent: mainItem // Explicit define for coordinates references.
|
||||
function updatePosition() {
|
||||
if (!visible)
|
||||
return
|
||||
var popupHeight = popup.height + popup.padding
|
||||
var popupWidth = popup.width + popup.padding
|
||||
var winPosition = mainItem.Window.contentItem ? mainItem.Window.contentItem.mapToItem(
|
||||
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)
|
||||
onWidthChanged: Qt.callLater(updatePosition)
|
||||
onVisibleChanged: Qt.callLater(updatePosition)
|
||||
|
||||
Connections {
|
||||
target: mainItem.Window
|
||||
function onHeightChanged() {
|
||||
Qt.callLater(popup.updatePosition)
|
||||
}
|
||||
function onWidthChanged() {
|
||||
Qt.callLater(popup.updatePosition)
|
||||
}
|
||||
}
|
||||
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
id: popupBackground
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.grey_0
|
||||
radius: 16 * DefaultStyle.dp
|
||||
}
|
||||
MultiEffect {
|
||||
source: popupBackground
|
||||
anchors.fill: popupBackground
|
||||
shadowEnabled: true
|
||||
shadowBlur: 0.1
|
||||
shadowColor: DefaultStyle.grey_1000
|
||||
shadowOpacity: 0.4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import QtQuick.Controls.Basic as Control
|
|||
import Linphone
|
||||
import UtilsCpp
|
||||
import SettingsCpp
|
||||
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/Style/buttonStyle.js" as ButtonStyle
|
||||
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
|
||||
|
||||
ListView {
|
||||
id: mainItem
|
||||
|
|
@ -17,7 +17,7 @@ ListView {
|
|||
property string searchText: searchBar?.text
|
||||
property double busyIndicatorSize: 60 * DefaultStyle.dp
|
||||
|
||||
signal resultsReceived()
|
||||
signal resultsReceived
|
||||
|
||||
onResultsReceived: {
|
||||
loading = false
|
||||
|
|
@ -29,7 +29,9 @@ ListView {
|
|||
id: callHistoryProxy
|
||||
filterText: mainItem.searchText
|
||||
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
|
||||
onModelReset: {
|
||||
mainItem.resultsReceived()
|
||||
|
|
@ -37,28 +39,32 @@ ListView {
|
|||
}
|
||||
flickDeceleration: 10000
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if(event.key == Qt.Key_Escape){
|
||||
console.log("Back")
|
||||
searchBar.forceActiveFocus()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: cacheBuffer = Math.max(contentHeight,0)//contentHeight>0 ? contentHeight : 0// cache all items
|
||||
Keys.onPressed: event => {
|
||||
if (event.key == Qt.Key_Escape) {
|
||||
console.log("Back")
|
||||
searchBar.forceActiveFocus()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: cacheBuffer = Math.max(
|
||||
contentHeight,
|
||||
0) //contentHeight>0 ? contentHeight : 0// cache all items
|
||||
// remove binding loop
|
||||
onContentHeightChanged: Qt.callLater(function(){
|
||||
if (mainItem) mainItem.cacheBuffer = Math?.max(contentHeight,0) || 0
|
||||
onContentHeightChanged: Qt.callLater(function () {
|
||||
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: {
|
||||
if(currentIndex < 0 && count > 0){
|
||||
mainItem.currentIndex = 0 // Select first item after loading model
|
||||
if (currentIndex < 0 && count > 0) {
|
||||
mainItem.currentIndex = 0 // Select first item after loading model
|
||||
}
|
||||
if(atYBeginning)
|
||||
positionViewAtBeginning()// Stay at beginning
|
||||
if (atYBeginning)
|
||||
positionViewAtBeginning() // Stay at beginning
|
||||
}
|
||||
Connections {
|
||||
target: deleteHistoryPopup
|
||||
|
|
@ -68,13 +74,13 @@ ListView {
|
|||
}
|
||||
|
||||
onAtYEndChanged: {
|
||||
if(atYEnd && count > 0){
|
||||
if (atYEnd && count > 0) {
|
||||
callHistoryProxy.displayMore()
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------
|
||||
function moveToCurrentItem(){
|
||||
if( mainItem.currentIndex >= 0)
|
||||
function moveToCurrentItem() {
|
||||
if (mainItem.currentIndex >= 0)
|
||||
Utils.updatePosition(mainItem, mainItem)
|
||||
}
|
||||
onCurrentItemChanged: {
|
||||
|
|
@ -82,32 +88,32 @@ ListView {
|
|||
}
|
||||
// Update position only if we are moving to current item and its position is changing.
|
||||
property var _currentItemY: currentItem?.y
|
||||
on_CurrentItemYChanged: if(_currentItemY && moveAnimation.running){
|
||||
moveToCurrentItem()
|
||||
}
|
||||
Behavior on contentY{
|
||||
on_CurrentItemYChanged: if (_currentItemY && moveAnimation.running) {
|
||||
moveToCurrentItem()
|
||||
}
|
||||
Behavior on contentY {
|
||||
NumberAnimation {
|
||||
id: moveAnimation
|
||||
id: moveAnimation
|
||||
duration: 500
|
||||
easing.type: Easing.OutExpo
|
||||
alwaysRunToEnd: true
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) currentIndex = -1
|
||||
if (!visible)
|
||||
currentIndex = -1
|
||||
}
|
||||
|
||||
// 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
|
||||
delegate: FocusScope {
|
||||
width:mainItem.width
|
||||
width: mainItem.width
|
||||
height: 56 * DefaultStyle.dp
|
||||
visible: !!modelData
|
||||
|
||||
|
||||
RowLayout {
|
||||
z: 1
|
||||
anchors.fill: parent
|
||||
|
|
@ -115,7 +121,8 @@ ListView {
|
|||
spacing: 10 * DefaultStyle.dp
|
||||
Avatar {
|
||||
id: historyAvatar
|
||||
property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.remoteAddress)
|
||||
property var contactObj: UtilsCpp.findFriendByAddress(
|
||||
modelData.core.remoteAddress)
|
||||
contact: contactObj?.value || null
|
||||
displayNameVal: modelData.core.displayName
|
||||
secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
|
|
@ -144,32 +151,32 @@ ListView {
|
|||
EffectImage {
|
||||
id: statusIcon
|
||||
imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|
||||
? AppIcons.arrowElbow
|
||||
: modelData.core.isOutgoing
|
||||
? AppIcons.arrowUpRight
|
||||
: AppIcons.arrowDownLeft
|
||||
colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Missed
|
||||
? DefaultStyle.danger_500main
|
||||
: modelData.core.isOutgoing
|
||||
? DefaultStyle.info_500_main
|
||||
: DefaultStyle.success_500main
|
||||
|| modelData.core.status
|
||||
=== LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted ? AppIcons.arrowElbow : modelData.core.isOutgoing ? AppIcons.arrowUpRight : AppIcons.arrowDownLeft
|
||||
colorizationColor: modelData.core.status
|
||||
=== LinphoneEnums.CallStatus.Declined
|
||||
|| modelData.core.status
|
||||
=== LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||
|| modelData.core.status
|
||||
=== LinphoneEnums.CallStatus.Aborted
|
||||
|| modelData.core.status
|
||||
=== LinphoneEnums.CallStatus.EarlyAborted
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Missed ? DefaultStyle.danger_500main : modelData.core.isOutgoing ? DefaultStyle.info_500_main : DefaultStyle.success_500main
|
||||
Layout.preferredWidth: 12 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 12 * DefaultStyle.dp
|
||||
transform: Rotation {
|
||||
angle: modelData.core.isOutgoing && (modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0
|
||||
angle: modelData.core.isOutgoing
|
||||
&& (modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||
|| modelData.core.status
|
||||
=== LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||
|| modelData.core.status
|
||||
=== LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0
|
||||
origin {
|
||||
x: statusIcon.width/2
|
||||
y: statusIcon.height/2
|
||||
x: statusIcon.width / 2
|
||||
y: statusIcon.height / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -191,10 +198,10 @@ ListView {
|
|||
onClicked: {
|
||||
if (modelData.core.isConference) {
|
||||
var callsWindow = UtilsCpp.getCallsWindow()
|
||||
callsWindow.setupConference(modelData.core.conferenceInfo)
|
||||
callsWindow.setupConference(
|
||||
modelData.core.conferenceInfo)
|
||||
UtilsCpp.smartShowWindow(callsWindow)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
UtilsCpp.createCall(modelData.core.remoteAddress)
|
||||
}
|
||||
}
|
||||
|
|
@ -205,17 +212,19 @@ ListView {
|
|||
anchors.fill: parent
|
||||
focus: true
|
||||
onContainsMouseChanged: {
|
||||
if(containsMouse)
|
||||
if (containsMouse)
|
||||
mainItem.lastMouseContainsIndex = index
|
||||
else if( mainItem.lastMouseContainsIndex == index)
|
||||
else if (mainItem.lastMouseContainsIndex == index)
|
||||
mainItem.lastMouseContainsIndex = -1
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
opacity: 0.7
|
||||
radius: 8 * DefaultStyle.dp
|
||||
color: mainItem.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
||||
visible: mainItem.lastMouseContainsIndex === index || mainItem.currentIndex === index
|
||||
color: mainItem.currentIndex
|
||||
=== index ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
||||
visible: mainItem.lastMouseContainsIndex === index
|
||||
|| mainItem.currentIndex === index
|
||||
}
|
||||
onPressed: {
|
||||
mainItem.currentIndex = model.index
|
||||
|
|
|
|||
|
|
@ -6,27 +6,28 @@ 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/Control/Tool/Helper/utils.js" as Utils
|
||||
|
||||
Flickable {
|
||||
id: mainItem
|
||||
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
|
||||
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 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 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 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
|
||||
|
||||
|
|
@ -38,7 +39,8 @@ Flickable {
|
|||
// set searchBarText without specifying a model to bold
|
||||
// matching names
|
||||
property string searchBarText
|
||||
property string searchText// Binding is done on searchBarTextChanged
|
||||
property string searchText
|
||||
// Binding is done on searchBarTextChanged
|
||||
property ConferenceInfoGui confInfoGui
|
||||
|
||||
property bool haveFavorites: false
|
||||
|
|
@ -54,19 +56,19 @@ Flickable {
|
|||
contentHeight: contentsLayout.height
|
||||
rightMargin: itemsRightMargin
|
||||
|
||||
signal contactStarredChanged()
|
||||
signal contactStarredChanged
|
||||
signal contactDeletionRequested(FriendGui contact)
|
||||
signal contactAddedToSelection(string address)
|
||||
signal contactRemovedFromSelection(string address)
|
||||
signal contactSelected(FriendGui contact)
|
||||
|
||||
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) {
|
||||
contactsList.selectIndex(index)
|
||||
}
|
||||
return index
|
||||
|
||||
}
|
||||
function addContactToSelection(address) {
|
||||
if (multiSelectionEnabled) {
|
||||
|
|
@ -91,49 +93,59 @@ Flickable {
|
|||
contactRemovedFromSelection(address)
|
||||
}
|
||||
}
|
||||
function haveAddress(address){
|
||||
function haveAddress(address) {
|
||||
var index = magicSearchProxy.findFriendIndexByAddress(address)
|
||||
return index != -1
|
||||
return index != -1
|
||||
}
|
||||
|
||||
function resetSelections(){
|
||||
function resetSelections() {
|
||||
mainItem.highlightedContact = null
|
||||
favoritesList.currentIndex = -1
|
||||
contactsList.currentIndex = -1
|
||||
suggestionsList.currentIndex = -1
|
||||
}
|
||||
|
||||
function findNextList(item, count, direction){
|
||||
if(count == 3) return null
|
||||
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
|
||||
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)
|
||||
if (nextItem.model.count > 0)
|
||||
return nextItem
|
||||
else
|
||||
return findNextList(nextItem, count + 1, direction)
|
||||
}
|
||||
|
||||
function updatePosition(list){
|
||||
function updatePosition(list) {
|
||||
Utils.updatePosition(mainItem, list)
|
||||
}
|
||||
|
||||
onHighlightedContactChanged:{
|
||||
onHighlightedContactChanged: {
|
||||
favoritesList.highlightedContact = highlightedContact
|
||||
contactsList.highlightedContact = highlightedContact
|
||||
suggestionsList.highlightedContact = highlightedContact
|
||||
}
|
||||
|
||||
onSearchBarTextChanged: {
|
||||
if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) {
|
||||
if (!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) {
|
||||
console.log("change search text")
|
||||
searchText = searchBarText.length === 0 ? "*" : searchBarText
|
||||
}
|
||||
}
|
||||
onPauseSearchChanged: {
|
||||
if(!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')){
|
||||
if (!pauseSearch && (mainItem.searchOnEmpty || searchBarText != '')) {
|
||||
searchText = searchBarText.length === 0 ? "*" : searchBarText
|
||||
}
|
||||
}
|
||||
|
|
@ -142,26 +154,37 @@ Flickable {
|
|||
loading = true
|
||||
}
|
||||
|
||||
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)
|
||||
else if(contactsList.activeFocus) newItem = findNextList(contactsList, 0, 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
else if (contactsList.activeFocus)
|
||||
newItem = findNextList(contactsList, 0,
|
||||
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: {
|
||||
if (confInfoGui) {
|
||||
for(var i = 0; i < confInfoGui.core.participants.length; ++i) {
|
||||
selectedContacts.push(confInfoGui.core.getParticipantAddressAt(i));
|
||||
for (var i = 0; i < confInfoGui.core.participants.length; ++i) {
|
||||
selectedContacts.push(
|
||||
confInfoGui.core.getParticipantAddressAt(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -181,7 +204,6 @@ Flickable {
|
|||
sourceFlags: mainItem.sourceFlags
|
||||
onModelReset: {
|
||||
mainItem.resetSelections()
|
||||
|
||||
}
|
||||
onResultsProcessed: {
|
||||
mainItem.loading = false
|
||||
|
|
@ -189,18 +211,21 @@ Flickable {
|
|||
}
|
||||
|
||||
onInitialized: {
|
||||
if(mainItem.searchOnEmpty || searchText != '' ) {
|
||||
if (mainItem.searchOnEmpty || searchText != '') {
|
||||
mainItem.loading = true
|
||||
forceUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onAtYEndChanged: if(atYEnd) {
|
||||
if( (contactsProxy.haveMore && contactList.expanded ) || mainItem.hideSuggestions) contactsProxy.displayMore()
|
||||
else suggestionsProxy.displayMore()
|
||||
}
|
||||
Behavior on contentY{
|
||||
onAtYEndChanged: if (atYEnd) {
|
||||
if ((contactsProxy.haveMore && contactList.expanded)
|
||||
|| mainItem.hideSuggestions)
|
||||
contactsProxy.displayMore()
|
||||
else
|
||||
suggestionsProxy.displayMore()
|
||||
}
|
||||
Behavior on contentY {
|
||||
NumberAnimation {
|
||||
duration: 500
|
||||
easing.type: Easing.OutExpo
|
||||
|
|
@ -210,7 +235,7 @@ Flickable {
|
|||
Control.ScrollBar.vertical: ScrollBar {
|
||||
id: scrollbar
|
||||
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
|
||||
interactive: true
|
||||
visible: mainItem.contentHeight > mainItem.height
|
||||
|
|
@ -220,7 +245,7 @@ Flickable {
|
|||
ColumnLayout {
|
||||
id: contentsLayout
|
||||
width: mainItem.width
|
||||
spacing: 0//20 * DefaultStyle.dp
|
||||
spacing: 0 //20 * DefaultStyle.dp
|
||||
|
||||
BusyIndicator {
|
||||
id: busyIndicator
|
||||
|
|
@ -232,7 +257,7 @@ Flickable {
|
|||
Layout.alignment: Qt.AlignCenter | Qt.AlignVCenter
|
||||
}
|
||||
|
||||
ContactListView{
|
||||
ContactListView {
|
||||
id: favoritesList
|
||||
visible: contentHeight > 0
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -252,22 +277,32 @@ Flickable {
|
|||
itemsRightMargin: mainItem.itemsRightMargin
|
||||
|
||||
onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact
|
||||
onContactSelected: (contactGui) => {
|
||||
mainItem.contactSelected(contactGui)
|
||||
}
|
||||
onContactSelected: contactGui => {
|
||||
mainItem.contactSelected(contactGui)
|
||||
}
|
||||
onUpdatePosition: mainItem.updatePosition(favoritesList)
|
||||
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)}
|
||||
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)}
|
||||
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)}
|
||||
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 : []
|
||||
model: mainItem.showFavorites
|
||||
&& (mainItem.searchBarText == ''
|
||||
|| mainItem.searchBarText == '*') ? proxy : []
|
||||
}
|
||||
|
||||
ContactListView{
|
||||
ContactListView {
|
||||
id: contactsList
|
||||
visible: contentHeight > 0
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -286,32 +321,45 @@ Flickable {
|
|||
title: qsTr('Contacts')
|
||||
|
||||
onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact
|
||||
onContactSelected: (contactGui) => {
|
||||
mainItem.contactSelected(contactGui)
|
||||
}
|
||||
onContactSelected: contactGui => {
|
||||
mainItem.contactSelected(contactGui)
|
||||
}
|
||||
onUpdatePosition: mainItem.updatePosition(contactsList)
|
||||
onContactDeletionRequested: (contact) => {mainItem.contactDeletionRequested(contact)}
|
||||
onAddContactToSelection: (address) => {mainItem.addContactToSelection(address)}
|
||||
onRemoveContactFromSelection: (index) => {mainItem.removeContactFromSelection(index)}
|
||||
onContactDeletionRequested: contact => {
|
||||
mainItem.contactDeletionRequested(
|
||||
contact)
|
||||
}
|
||||
onAddContactToSelection: address => {
|
||||
mainItem.addContactToSelection(address)
|
||||
}
|
||||
onRemoveContactFromSelection: index => {
|
||||
mainItem.removeContactFromSelection(
|
||||
index)
|
||||
}
|
||||
|
||||
model:MagicSearchProxy {
|
||||
model: MagicSearchProxy {
|
||||
id: contactsProxy
|
||||
parentProxy: mainItem.mainModel
|
||||
filterType: MagicSearchProxy.FilteringTypes.App
|
||||
| (mainItem.searchText != '*' && mainItem.searchText != '' || SettingsCpp.syncLdapContacts ? MagicSearchProxy.FilteringTypes.Ldap | MagicSearchProxy.FilteringTypes.CardDAV: 0)
|
||||
initialDisplayItems: Math.max(20, 2 * mainItem.height / (63 * DefaultStyle.dp))
|
||||
| (mainItem.searchText != '*'
|
||||
&& 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
|
||||
onLocalFriendCreated: (index) => {
|
||||
contactsList.selectIndex(index)
|
||||
}
|
||||
onLocalFriendCreated: index => {
|
||||
contactsList.selectIndex(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
ContactListView{
|
||||
ContactListView {
|
||||
id: suggestionsList
|
||||
visible: contentHeight > 0
|
||||
Layout.fillWidth: true
|
||||
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
|
||||
showInitials: false
|
||||
highlightText: mainItem.highlightText
|
||||
|
|
@ -325,18 +373,30 @@ Flickable {
|
|||
itemsRightMargin: mainItem.itemsRightMargin
|
||||
|
||||
onHighlightedContactChanged: mainItem.highlightedContact = highlightedContact
|
||||
onContactSelected: (contactGui) => {
|
||||
mainItem.contactSelected(contactGui)
|
||||
}
|
||||
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 {
|
||||
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: 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
|
||||
displayItemsStep: 3 * initialDisplayItems / 2
|
||||
onModelReset: maxDisplayItems = initialDisplayItems
|
||||
|
|
|
|||
|
|
@ -6,243 +6,291 @@ import Linphone
|
|||
import UtilsCpp 1.0
|
||||
import ConstantsCpp 1.0
|
||||
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 {
|
||||
id: mainItem
|
||||
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.
|
||||
property bool showActions: false // Display actions layout (call buttons)
|
||||
property bool showContactMenu: true // Display the dot menu for contacts.
|
||||
property string highlightText // Bold characters in Display name.
|
||||
|
||||
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 bool isSelected: false // selected in list => currentIndex == index
|
||||
property bool isLastHovered: false
|
||||
|
||||
property var previousInitial // Use directly previous initial
|
||||
property int itemsRightMargin: 39 * DefaultStyle.dp
|
||||
|
||||
property var displayName: searchResultItem.core.fullName
|
||||
property string initial: displayName ? displayName[0].toLocaleLowerCase(ConstantsCpp.DefaultLocale) : ''
|
||||
|
||||
signal clicked(var mouse)
|
||||
signal contactDeletionRequested(FriendGui contact)
|
||||
signal containsMouseChanged(bool containsMouse)
|
||||
id: mainItem
|
||||
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.
|
||||
property bool showActions: false // Display actions layout (call buttons)
|
||||
property bool showContactMenu: true // Display the dot menu for contacts.
|
||||
property string highlightText
|
||||
|
||||
Text {
|
||||
id: initial
|
||||
anchors.left: parent.left
|
||||
visible: mainItem.showInitials
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.rightMargin: 15 * DefaultStyle.dp
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: 20 * DefaultStyle.dp
|
||||
opacity: previousInitial != mainItem.initial ? 1 : 0
|
||||
text: mainItem.initial
|
||||
color: DefaultStyle.main2_400
|
||||
font {
|
||||
pixelSize: 20 * DefaultStyle.dp
|
||||
weight: 500 * DefaultStyle.dp
|
||||
capitalization: Font.AllUppercase
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: contactDelegate
|
||||
anchors.left: initial.visible ? initial.right : parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: mainItem.itemsRightMargin
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
spacing: 16 * DefaultStyle.dp
|
||||
z: 1
|
||||
Avatar {
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
Layout.leftMargin: 5 * DefaultStyle.dp
|
||||
contact: searchResultItem
|
||||
shadowEnabled: false
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
Text {
|
||||
text: UtilsCpp.boldTextPart(mainItem.displayName, mainItem.highlightText)
|
||||
font{
|
||||
pixelSize: mainItem.showDefaultAddress ? 16 * DefaultStyle.dp : 14 * DefaultStyle.dp
|
||||
capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase
|
||||
weight: mainItem.showDefaultAddress ? 800 * DefaultStyle.dp : 400 * DefaultStyle.dp
|
||||
}
|
||||
maximumLineCount: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
Layout.topMargin: 2 * DefaultStyle.dp
|
||||
Layout.fillWidth: true
|
||||
visible: mainItem.showDefaultAddress
|
||||
property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(searchResultItem.core.defaultAddress) : searchResultItem.core.defaultAddress
|
||||
text: UtilsCpp.boldTextPart(address, mainItem.highlightText)
|
||||
maximumLineCount: 1
|
||||
elide: Text.ElideRight
|
||||
font {
|
||||
weight: 300 * DefaultStyle.dp
|
||||
pixelSize: 12 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
Item{Layout.fillWidth: true}
|
||||
RowLayout {
|
||||
id: actionsRow
|
||||
z: 1
|
||||
visible: actionButtons || friendPopup.visible || mainItem.multiSelectionEnabled
|
||||
spacing: visible ? 16 * DefaultStyle.dp : 0
|
||||
Layout.rightMargin: visible ? 10 * DefaultStyle.dp : 0
|
||||
EffectImage {
|
||||
id: isSelectedCheck
|
||||
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
|
||||
}
|
||||
RowLayout{
|
||||
id: actionButtons
|
||||
visible: mainItem.showActions
|
||||
spacing: visible ? 10 * DefaultStyle.dp : 0
|
||||
IconButton {
|
||||
id: callButton
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
icon.width: 24 * DefaultStyle.dp
|
||||
icon.height: 24 * DefaultStyle.dp
|
||||
icon.source: AppIcons.phone
|
||||
focus: visible
|
||||
radius: 40 * DefaultStyle.dp
|
||||
style: ButtonStyle.grey
|
||||
onClicked: UtilsCpp.createCall(searchResultItem.core.defaultFullAddress)
|
||||
KeyNavigation.left: chatButton
|
||||
KeyNavigation.right: videoCallButton
|
||||
}
|
||||
IconButton {
|
||||
id: videoCallButton
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
icon.width: 24 * DefaultStyle.dp
|
||||
icon.height: 24 * DefaultStyle.dp
|
||||
icon.source: AppIcons.videoCamera
|
||||
focus: visible && !callButton.visible
|
||||
radius: 40 * DefaultStyle.dp
|
||||
style: ButtonStyle.grey
|
||||
onClicked: UtilsCpp.createCall(searchResultItem.core.defaultFullAddress, {'localVideoEnabled': true})
|
||||
KeyNavigation.left: callButton
|
||||
KeyNavigation.right: chatButton
|
||||
}
|
||||
IconButton {
|
||||
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)
|
||||
|
||||
popup.contentItem: ColumnLayout {
|
||||
IconLabelButton {
|
||||
visible: searchResultItem.core.isStored && !searchResultItem.core.readOnly
|
||||
text: searchResultItem.core.starred ? qsTr("Enlever des favoris") : qsTr("Mettre en favori")
|
||||
icon.source: searchResultItem.core.starred ? AppIcons.heartFill : AppIcons.heart
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
textColor: DefaultStyle.main2_500main
|
||||
hoveredImageColor: searchResultItem.core.starred ? DefaultStyle.main1_700 : DefaultStyle.danger_700
|
||||
contentImageColor: searchResultItem.core.starred ? DefaultStyle.danger_500main : DefaultStyle.main2_600
|
||||
onClicked: {
|
||||
searchResultItem.core.lSetStarred(!searchResultItem.core.starred)
|
||||
friendPopup.close()
|
||||
}
|
||||
style: ButtonStyle.noBackground
|
||||
}
|
||||
IconLabelButton {
|
||||
text: qsTr("Partager")
|
||||
icon.source: AppIcons.shareNetwork
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
textColor: DefaultStyle.main2_500main
|
||||
onClicked: {
|
||||
var vcard = searchResultItem.core.getVCard()
|
||||
var username = searchResultItem.core.givenName + searchResultItem.core.familyName
|
||||
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
|
||||
// Bold characters in Display name.
|
||||
property bool displayNameCapitalization: true // Capitalize display name.
|
||||
|
||||
}
|
||||
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 {
|
||||
id: contactArea
|
||||
enabled: mainItem.selectionEnabled
|
||||
anchors.fill: contactDelegate
|
||||
//height: mainItem.height
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.AllButtons
|
||||
z: -1
|
||||
focus: !actionButtons.visible
|
||||
onContainsMouseChanged: {
|
||||
mainItem.containsMouseChanged(containsMouse)
|
||||
}
|
||||
Rectangle {
|
||||
anchors.fill: contactArea
|
||||
radius: 8 * DefaultStyle.dp
|
||||
opacity: 0.7
|
||||
color: mainItem.isSelected ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
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 bool isSelected: false // selected in list => currentIndex == index
|
||||
property bool isLastHovered: false
|
||||
|
||||
property var previousInitial
|
||||
// Use directly previous initial
|
||||
property int itemsRightMargin: 39 * DefaultStyle.dp
|
||||
|
||||
property var displayName: searchResultItem.core.fullName
|
||||
property string initial: displayName ? displayName[0].toLocaleLowerCase(
|
||||
ConstantsCpp.DefaultLocale) : ''
|
||||
|
||||
signal clicked(var mouse)
|
||||
signal contactDeletionRequested(FriendGui contact)
|
||||
signal containsMouseChanged(bool containsMouse)
|
||||
|
||||
Text {
|
||||
id: initial
|
||||
anchors.left: parent.left
|
||||
visible: mainItem.showInitials
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.rightMargin: 15 * DefaultStyle.dp
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: 20 * DefaultStyle.dp
|
||||
opacity: previousInitial != mainItem.initial ? 1 : 0
|
||||
text: mainItem.initial
|
||||
color: DefaultStyle.main2_400
|
||||
font {
|
||||
pixelSize: 20 * DefaultStyle.dp
|
||||
weight: 500 * DefaultStyle.dp
|
||||
capitalization: Font.AllUppercase
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: contactDelegate
|
||||
anchors.left: initial.visible ? initial.right : parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: mainItem.itemsRightMargin
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
spacing: 16 * DefaultStyle.dp
|
||||
z: 1
|
||||
Avatar {
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
Layout.leftMargin: 5 * DefaultStyle.dp
|
||||
contact: searchResultItem
|
||||
shadowEnabled: false
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
Text {
|
||||
text: UtilsCpp.boldTextPart(mainItem.displayName,
|
||||
mainItem.highlightText)
|
||||
font {
|
||||
pixelSize: mainItem.showDefaultAddress ? 16 * DefaultStyle.dp : 14
|
||||
* DefaultStyle.dp
|
||||
capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase
|
||||
weight: mainItem.showDefaultAddress ? 800 * DefaultStyle.dp : 400
|
||||
* DefaultStyle.dp
|
||||
}
|
||||
maximumLineCount: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
Layout.topMargin: 2 * DefaultStyle.dp
|
||||
Layout.fillWidth: true
|
||||
visible: mainItem.showDefaultAddress
|
||||
property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(searchResultItem.core.defaultAddress) : searchResultItem.core.defaultAddress
|
||||
text: UtilsCpp.boldTextPart(address, mainItem.highlightText)
|
||||
maximumLineCount: 1
|
||||
elide: Text.ElideRight
|
||||
font {
|
||||
weight: 300 * DefaultStyle.dp
|
||||
pixelSize: 12 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Loader {
|
||||
id: buttonsLayoutLoader
|
||||
asynchronous: true
|
||||
active: mainItem.showActions || mainItem.showContactMenu
|
||||
|| mainItem.multiSelectionEnabled
|
||||
Layout.rightMargin: active ? 10 * DefaultStyle.dp : 0
|
||||
sourceComponent: RowLayout {
|
||||
id: actionsRow
|
||||
z: 1
|
||||
visible: actionButtons.visible || friendPopup.visible
|
||||
|| mainItem.multiSelectionEnabled
|
||||
spacing: visible ? 16 * DefaultStyle.dp : 0
|
||||
enabled: visible
|
||||
EffectImage {
|
||||
id: isSelectedCheck
|
||||
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
|
||||
}
|
||||
RowLayout {
|
||||
id: actionButtons
|
||||
visible: mainItem.showActions
|
||||
spacing: visible ? 10 * DefaultStyle.dp : 0
|
||||
IconButton {
|
||||
id: callButton
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
icon.width: 24 * DefaultStyle.dp
|
||||
icon.height: 24 * DefaultStyle.dp
|
||||
icon.source: AppIcons.phone
|
||||
focus: visible
|
||||
radius: 40 * DefaultStyle.dp
|
||||
style: ButtonStyle.grey
|
||||
onClicked: UtilsCpp.createCall(
|
||||
searchResultItem.core.defaultFullAddress)
|
||||
KeyNavigation.left: chatButton
|
||||
KeyNavigation.right: videoCallButton
|
||||
}
|
||||
IconButton {
|
||||
id: videoCallButton
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
icon.width: 24 * DefaultStyle.dp
|
||||
icon.height: 24 * DefaultStyle.dp
|
||||
icon.source: AppIcons.videoCamera
|
||||
focus: visible && !callButton.visible
|
||||
radius: 40 * DefaultStyle.dp
|
||||
style: ButtonStyle.grey
|
||||
onClicked: UtilsCpp.createCall(
|
||||
searchResultItem.core.defaultFullAddress,
|
||||
{
|
||||
"localVideoEnabled": true
|
||||
})
|
||||
KeyNavigation.left: callButton
|
||||
KeyNavigation.right: chatButton
|
||||
}
|
||||
IconButton {
|
||||
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 {
|
||||
IconLabelButton {
|
||||
visible: searchResultItem.core.isStored
|
||||
&& !searchResultItem.core.readOnly
|
||||
text: searchResultItem.core.starred ? qsTr(
|
||||
"Enlever des favoris") : qsTr(
|
||||
"Mettre en favori")
|
||||
icon.source: searchResultItem.core.starred ? AppIcons.heartFill : AppIcons.heart
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
textColor: DefaultStyle.main2_500main
|
||||
hoveredImageColor: searchResultItem.core.starred ? DefaultStyle.main1_700 : DefaultStyle.danger_700
|
||||
contentImageColor: searchResultItem.core.starred ? DefaultStyle.danger_500main : DefaultStyle.main2_600
|
||||
onClicked: {
|
||||
searchResultItem.core.lSetStarred(
|
||||
!searchResultItem.core.starred)
|
||||
friendPopup.close()
|
||||
}
|
||||
style: ButtonStyle.noBackground
|
||||
}
|
||||
IconLabelButton {
|
||||
text: qsTr("Partager")
|
||||
icon.source: AppIcons.shareNetwork
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
textColor: DefaultStyle.main2_500main
|
||||
onClicked: {
|
||||
var vcard = searchResultItem.core.getVCard()
|
||||
var username = searchResultItem.core.givenName
|
||||
+ searchResultItem.core.familyName
|
||||
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 {
|
||||
id: contactArea
|
||||
enabled: mainItem.selectionEnabled
|
||||
anchors.fill: contactDelegate
|
||||
//height: mainItem.height
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.AllButtons
|
||||
z: -1
|
||||
focus: !buttonsLayoutLoader.active
|
||||
onContainsMouseChanged: {
|
||||
mainItem.containsMouseChanged(containsMouse)
|
||||
}
|
||||
Rectangle {
|
||||
anchors.fill: contactArea
|
||||
radius: 8 * DefaultStyle.dp
|
||||
opacity: 0.7
|
||||
color: mainItem.isSelected ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
||||
visible: mainItem.isLastHovered || mainItem.isSelected
|
||||
}
|
||||
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
Loading…
Add table
Reference in a new issue