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,18 +2,14 @@ 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
: hovered
? hoveredColor
: color
style: ButtonStyle.popupButton style: ButtonStyle.popupButton
checked: popup.visible checked: popup.visible
implicitWidth: 24 * DefaultStyle.dp implicitWidth: 24 * DefaultStyle.dp
@ -34,48 +30,62 @@ Button {
popup.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
instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem,
index)
} }
function getNextItem(index){ function getNextItem(index) {
return _getNextItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, 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)
return null
--index --index
while(index >= 0){ while (index >= 0) {
if( isFocusable(content.children[index]) && content.children[index].visible) return content.children[index] if (isFocusable(content.children[index])
&& content.children[index].visible)
return content.children[index]
--index --index
} }
return _getPreviousItem(content, content.children.length) return _getPreviousItem(content, content.children.length)
} }
function _getNextItem(content, index){ function _getNextItem(content, index) {
++index ++index
while(index < content.children.length){ while (index < content.children.length) {
if( isFocusable(content.children[index]) && content.children[index].visible) return content.children[index] if (isFocusable(content.children[index])
&& content.children[index].visible)
return content.children[index]
++index ++index
} }
return _getNextItem(content, -1) 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
|| event.key == Qt.Key_Left
|| event.key == Qt.Key_Space) {
mainItem.close() mainItem.close()
mainItem.forceActiveFocus() mainItem.forceActiveFocus()
event.accepted = true event.accepted = true
}else if(event.key == Qt.Key_Up){ } else if (event.key == Qt.Key_Up) {
getPreviousItem(0).forceActiveFocus() getPreviousItem(0).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_Tab
|| event.key == Qt.Key_Down) {
getNextItem(-1).forceActiveFocus() getNextItem(-1).forceActiveFocus()
event.accepted = true event.accepted = true
} }
}else if(event.key == Qt.Key_Space){ } else if (event.key == Qt.Key_Space) {
mainItem.open() mainItem.open()
event.accepted = true event.accepted = true
} }
@ -108,26 +118,41 @@ Button {
colorizationColor: mainItem.contentImageColor colorizationColor: mainItem.contentImageColor
} }
onPressed: { onPressed: {
if (popup.visible) popup.close() if (popup.visible)
else popup.open() popup.close()
else
popup.open()
} }
Control.Popup { Control.Popup {
id: popup id: popup
x: 0 x: 0
y: mainItem.height y: mainItem.height
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside | Popup.CloseOnEscape visible: false
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside
| Popup.CloseOnEscape
padding: 10 * DefaultStyle.dp padding: 10 * DefaultStyle.dp
parent: mainItem // Explicit define for coordinates references. parent: mainItem // Explicit define for coordinates references.
function updatePosition(){ function updatePosition() {
if (!visible) return if (!visible)
return
var popupHeight = popup.height + popup.padding var popupHeight = popup.height + popup.padding
var popupWidth = popup.width + popup.padding var popupWidth = popup.width + popup.padding
var winPosition = mainItem.Window.contentItem ? mainItem.Window.contentItem.mapToItem(mainItem,0 , 0) : {x:0,y:0} var winPosition = mainItem.Window.contentItem ? mainItem.Window.contentItem.mapToItem(
// Stay inside main window mainItem, 0,
y = Math.max( Math.min( winPosition.y + mainItem.Window.height - popupHeight, mainItem.height), winPosition.y) 0) : {
x = Math.max( Math.min( winPosition.x + mainItem.Window.width - popupWidth, 0), winPosition.x) "x": 0,
// Avoid overlapping with popup button by going to the right (todo: check if left is better?) "y": 0
if( y < mainItem.height && y + popupHeight > 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 x += mainItem.width
} }
} }
@ -136,10 +161,14 @@ Button {
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 {

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,10 +88,10 @@ 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
@ -93,18 +99,18 @@ ListView {
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
=== LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted || modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted ? AppIcons.arrowElbow : modelData.core.isOutgoing ? AppIcons.arrowUpRight : AppIcons.arrowDownLeft
? AppIcons.arrowElbow colorizationColor: modelData.core.status
: modelData.core.isOutgoing === LinphoneEnums.CallStatus.Declined
? AppIcons.arrowUpRight || modelData.core.status
: AppIcons.arrowDownLeft === LinphoneEnums.CallStatus.DeclinedElsewhere
colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined || modelData.core.status
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted === LinphoneEnums.CallStatus.EarlyAborted
|| modelData.core.status === LinphoneEnums.CallStatus.Missed || modelData.core.status === LinphoneEnums.CallStatus.Missed ? DefaultStyle.danger_500main : modelData.core.isOutgoing ? DefaultStyle.info_500_main : DefaultStyle.success_500main
? DefaultStyle.danger_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.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted || modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0 || 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,7 +6,7 @@ import Linphone
import UtilsCpp 1.0 import UtilsCpp 1.0
import ConstantsCpp 1.0 import ConstantsCpp 1.0
import SettingsCpp import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
Flickable { Flickable {
id: mainItem id: mainItem
@ -26,7 +26,8 @@ Flickable {
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,17 +154,27 @@ 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
|| event.key == Qt.Key_Down) {
var newItem var newItem
var direction = (event.key == Qt.Key_Up ? -1 : 1) var direction = (event.key == Qt.Key_Up ? -1 : 1)
if(suggestionsList.activeFocus) newItem = findNextList(suggestionsList, 0, direction) if (suggestionsList.activeFocus)
else if(contactsList.activeFocus) newItem = findNextList(contactsList, 0, direction) newItem = findNextList(suggestionsList, 0,
else if(favoritesList.activeFocus) newItem = findNextList(favoritesList, 0, direction) direction)
else newItem = findNextList(suggestionsList, 0, direction) else if (contactsList.activeFocus)
if(newItem){ newItem = findNextList(contactsList, 0,
newItem.selectIndex(direction > 0 ? -1 : newItem.model.count - 1) 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 event.accepted = true
} }
} }
@ -160,8 +182,9 @@ Flickable {
} }
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()
else
suggestionsProxy.displayMore()
} }
Behavior on contentY{ Behavior on contentY {
NumberAnimation { NumberAnimation {
duration: 500 duration: 500
easing.type: Easing.OutExpo easing.type: Easing.OutExpo
@ -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,7 +6,7 @@ import Linphone
import UtilsCpp 1.0 import UtilsCpp 1.0
import ConstantsCpp 1.0 import ConstantsCpp 1.0
import SettingsCpp import SettingsCpp
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
FocusScope { FocusScope {
id: mainItem id: mainItem
@ -16,21 +16,25 @@ FocusScope {
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
// Bold characters in Display name.
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 bool isSelected: false // selected in list => currentIndex == index property bool isSelected: false // selected in list => currentIndex == index
property bool isLastHovered: false property bool isLastHovered: false
property var previousInitial // Use directly previous initial property var previousInitial
// Use directly previous initial
property int itemsRightMargin: 39 * DefaultStyle.dp 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)
@ -72,11 +76,14 @@ FocusScope {
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 {
pixelSize: mainItem.showDefaultAddress ? 16 * DefaultStyle.dp : 14
* DefaultStyle.dp
capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase capitalization: mainItem.displayNameCapitalization ? Font.Capitalize : Font.MixedCase
weight: mainItem.showDefaultAddress ? 800 * DefaultStyle.dp : 400 * DefaultStyle.dp weight: mainItem.showDefaultAddress ? 800 * DefaultStyle.dp : 400
* DefaultStyle.dp
} }
maximumLineCount: 1 maximumLineCount: 1
Layout.fillWidth: true Layout.fillWidth: true
@ -95,22 +102,33 @@ FocusScope {
} }
} }
} }
Item{Layout.fillWidth: true} Item {
RowLayout { 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 id: actionsRow
z: 1 z: 1
visible: actionButtons || friendPopup.visible || mainItem.multiSelectionEnabled visible: actionButtons.visible || friendPopup.visible
|| mainItem.multiSelectionEnabled
spacing: visible ? 16 * DefaultStyle.dp : 0 spacing: visible ? 16 * DefaultStyle.dp : 0
Layout.rightMargin: visible ? 10 * DefaultStyle.dp : 0 enabled: visible
EffectImage { EffectImage {
id: isSelectedCheck id: isSelectedCheck
visible: mainItem.multiSelectionEnabled && (mainItem.selectedContacts.indexOf(searchResultItem.core.defaultAddress) != -1) visible: mainItem.multiSelectionEnabled
&& (mainItem.selectedContacts.indexOf(
searchResultItem.core.defaultAddress) != -1)
Layout.preferredWidth: 24 * DefaultStyle.dp Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp
imageSource: AppIcons.check imageSource: AppIcons.check
colorizationColor: DefaultStyle.main1_500_main colorizationColor: DefaultStyle.main1_500_main
} }
RowLayout{ RowLayout {
id: actionButtons id: actionButtons
visible: mainItem.showActions visible: mainItem.showActions
spacing: visible ? 10 * DefaultStyle.dp : 0 spacing: visible ? 10 * DefaultStyle.dp : 0
@ -124,7 +142,8 @@ FocusScope {
focus: visible focus: visible
radius: 40 * DefaultStyle.dp radius: 40 * DefaultStyle.dp
style: ButtonStyle.grey style: ButtonStyle.grey
onClicked: UtilsCpp.createCall(searchResultItem.core.defaultFullAddress) onClicked: UtilsCpp.createCall(
searchResultItem.core.defaultFullAddress)
KeyNavigation.left: chatButton KeyNavigation.left: chatButton
KeyNavigation.right: videoCallButton KeyNavigation.right: videoCallButton
} }
@ -138,19 +157,25 @@ FocusScope {
focus: visible && !callButton.visible focus: visible && !callButton.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(
searchResultItem.core.defaultFullAddress,
{
"localVideoEnabled": true
})
KeyNavigation.left: callButton KeyNavigation.left: callButton
KeyNavigation.right: chatButton KeyNavigation.right: chatButton
} }
IconButton { IconButton {
id: chatButton id: chatButton
visible: actionButtons.visible && !SettingsCpp.disableChatFeature visible: actionButtons.visible
&& !SettingsCpp.disableChatFeature
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.chatTeardropText
focus: visible && !callButton.visible && !videoCallButton.visible focus: visible && !callButton.visible
&& !videoCallButton.visible
radius: 40 * DefaultStyle.dp radius: 40 * DefaultStyle.dp
style: ButtonStyle.grey style: ButtonStyle.grey
KeyNavigation.left: videoCallButton KeyNavigation.left: videoCallButton
@ -162,19 +187,26 @@ FocusScope {
z: 1 z: 1
popup.x: 0 popup.x: 0
popup.padding: 10 * DefaultStyle.dp popup.padding: 10 * DefaultStyle.dp
visible: mainItem.showContactMenu && (contactArea.containsMouse || hovered || popup.opened) 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
text: searchResultItem.core.starred ? qsTr(
"Enlever des favoris") : qsTr(
"Mettre en favori")
icon.source: searchResultItem.core.starred ? AppIcons.heartFill : AppIcons.heart icon.source: searchResultItem.core.starred ? AppIcons.heartFill : AppIcons.heart
spacing: 10 * DefaultStyle.dp spacing: 10 * DefaultStyle.dp
textColor: DefaultStyle.main2_500main textColor: DefaultStyle.main2_500main
hoveredImageColor: searchResultItem.core.starred ? DefaultStyle.main1_700 : DefaultStyle.danger_700 hoveredImageColor: searchResultItem.core.starred ? DefaultStyle.main1_700 : DefaultStyle.danger_700
contentImageColor: searchResultItem.core.starred ? DefaultStyle.danger_500main : DefaultStyle.main2_600 contentImageColor: searchResultItem.core.starred ? DefaultStyle.danger_500main : DefaultStyle.main2_600
onClicked: { onClicked: {
searchResultItem.core.lSetStarred(!searchResultItem.core.starred) searchResultItem.core.lSetStarred(
!searchResultItem.core.starred)
friendPopup.close() friendPopup.close()
} }
style: ButtonStyle.noBackground style: ButtonStyle.noBackground
@ -186,14 +218,25 @@ FocusScope {
textColor: DefaultStyle.main2_500main textColor: DefaultStyle.main2_500main
onClicked: { onClicked: {
var vcard = searchResultItem.core.getVCard() var vcard = searchResultItem.core.getVCard()
var username = searchResultItem.core.givenName + searchResultItem.core.familyName var username = searchResultItem.core.givenName
var filepath = UtilsCpp.createVCardFile(username, vcard) + searchResultItem.core.familyName
if (filepath == "") UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La création du fichier vcard a échoué"), false) var filepath = UtilsCpp.createVCardFile(
else mainWindow.showInformationPopup(qsTr("VCard créée"), qsTr("VCard du contact enregistrée dans %1").arg(filepath)) username, vcard)
UtilsCpp.shareByEmail(qsTr("Partage de contact"), vcard, filepath) 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 style: ButtonStyle.noBackground
} }
IconLabelButton { IconLabelButton {
text: qsTr("Supprimer") text: qsTr("Supprimer")
@ -201,7 +244,8 @@ FocusScope {
spacing: 10 * DefaultStyle.dp spacing: 10 * DefaultStyle.dp
visible: !searchResultItem.core.readOnly visible: !searchResultItem.core.readOnly
onClicked: { onClicked: {
mainItem.contactDeletionRequested(searchResultItem) mainItem.contactDeletionRequested(
searchResultItem)
friendPopup.close() friendPopup.close()
} }
style: ButtonStyle.noBackgroundRed style: ButtonStyle.noBackgroundRed
@ -210,6 +254,7 @@ FocusScope {
} }
} }
} }
}
MouseArea { MouseArea {
id: contactArea id: contactArea
@ -219,7 +264,7 @@ FocusScope {
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.AllButtons acceptedButtons: Qt.AllButtons
z: -1 z: -1
focus: !actionButtons.visible focus: !buttonsLayoutLoader.active
onContainsMouseChanged: { onContainsMouseChanged: {
mainItem.containsMouseChanged(containsMouse) mainItem.containsMouseChanged(containsMouse)
} }
@ -228,17 +273,20 @@ FocusScope {
radius: 8 * DefaultStyle.dp radius: 8 * DefaultStyle.dp
opacity: 0.7 opacity: 0.7
color: mainItem.isSelected ? DefaultStyle.main2_200 : DefaultStyle.main2_100 color: mainItem.isSelected ? DefaultStyle.main2_200 : DefaultStyle.main2_100
visible: mainItem.isLastHovered || friendPopup.hovered || mainItem.isSelected || friendPopup.visible visible: mainItem.isLastHovered || mainItem.isSelected
} }
Keys.onPressed: (event)=> { Keys.onPressed: event => {
if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { if (event.key == Qt.Key_Space
|| event.key == Qt.Key_Enter
|| event.key == Qt.Key_Return) {
contactArea.clicked(undefined) contactArea.clicked(undefined)
event.accepted = true; event.accepted = true
} }
} }
onClicked: (mouse) => { onClicked: mouse => {
forceActiveFocus() forceActiveFocus()
if (mouse && mouse.button == Qt.RightButton && mainItem.showContactMenu) { if (mouse && mouse.button == Qt.RightButton
&& mainItem.showContactMenu) {
friendPopup.open() friendPopup.open()
} else { } else {
mainItem.clicked(mouse) mainItem.clicked(mouse)

View file

@ -1,7 +1,8 @@
/** /**
* Qml template used for welcome and login/register pages * Qml template used for welcome and login/register pages
**/ **/
import QtCore import QtCore
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
@ -11,23 +12,22 @@ import QtQuick.Effects
import Linphone import Linphone
import UtilsCpp import UtilsCpp
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
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
Item { Item {
id: mainItem id: mainItem
property var callObj property var callObj
property var contextualMenuOpenedComponent: undefined property var contextualMenuOpenedComponent: undefined
signal addAccountRequest() signal addAccountRequest
signal openNewCallRequest() signal openNewCallRequest
signal callCreated() signal callCreated
signal openCallHistory() signal openCallHistory
signal openNumPadRequest() signal openNumPadRequest
signal displayContactRequested(string contactAddress) signal displayContactRequested(string contactAddress)
signal createContactRequested(string name, string address) signal createContactRequested(string name, string address)
signal accountRemoved() signal accountRemoved
function goToNewCall() { function goToNewCall() {
tabbar.currentIndex = 0 tabbar.currentIndex = 0
@ -48,7 +48,8 @@ Item {
} }
function openContextualMenuComponent(component) { function openContextualMenuComponent(component) {
if (mainItem.contextualMenuOpenedComponent && mainItem.contextualMenuOpenedComponent != component) { if (mainItem.contextualMenuOpenedComponent
&& mainItem.contextualMenuOpenedComponent != component) {
mainStackView.pop() mainStackView.pop()
mainItem.contextualMenuOpenedComponent = undefined mainItem.contextualMenuOpenedComponent = undefined
} }
@ -64,15 +65,19 @@ Item {
mainItem.contextualMenuOpenedComponent = undefined mainItem.contextualMenuOpenedComponent = undefined
} }
function openAccountSettings(account: AccountGui) { function openAccountSettings(account) {
var page = accountSettingsPageComponent.createObject(parent, {"account": account}); var page = accountSettingsPageComponent.createObject(parent, {
"account": account
})
openContextualMenuComponent(page) openContextualMenuComponent(page)
} }
AccountProxy { AccountProxy {
id: accountProxy id: accountProxy
sourceModel: AppCpp.accounts sourceModel: AppCpp.accounts
onDefaultAccountChanged: if (tabbar.currentIndex === 0 && defaultAccount) defaultAccount.core?.lResetMissedCalls() onDefaultAccountChanged: if (tabbar.currentIndex === 0
&& defaultAccount)
defaultAccount.core?.lResetMissedCalls()
} }
CallProxy { CallProxy {
@ -80,29 +85,27 @@ Item {
sourceModel: AppCpp.calls sourceModel: AppCpp.calls
} }
Item{ Item {
anchors.fill: parent anchors.fill: parent
Popup { Popup {
id: currentCallNotif id: currentCallNotif
background: Item{} background: Item {}
closePolicy: Control.Popup.NoAutoClose closePolicy: Control.Popup.NoAutoClose
visible: currentCall visible: currentCall
&& currentCall.core.state != LinphoneEnums.CallState.Idle && currentCall.core.state != LinphoneEnums.CallState.Idle
&& currentCall.core.state != LinphoneEnums.CallState.IncomingReceived && currentCall.core.state != LinphoneEnums.CallState.IncomingReceived
&& currentCall.core.state != LinphoneEnums.CallState.PushIncomingReceived && currentCall.core.state != LinphoneEnums.CallState.PushIncomingReceived
x: mainItem.width/2 - width/2 x: mainItem.width / 2 - width / 2
y: contentItem.height/2 y: contentItem.height / 2
property var currentCall: callsModel.currentCall ? callsModel.currentCall : null property var currentCall: callsModel.currentCall ? callsModel.currentCall : null
property string remoteName: currentCall ? currentCall.core.remoteName : "" property string remoteName: currentCall ? currentCall.core.remoteName : ""
contentItem: MediumButton { contentItem: MediumButton {
style: ButtonStyle.toast style: ButtonStyle.toast
text: currentCallNotif.currentCall text: currentCallNotif.currentCall ? currentCallNotif.currentCall.core.conference ? ("Réunion en cours : ") + currentCallNotif.currentCall.core.conference.core.subject : (("Appel en cours : ") + currentCallNotif.remoteName) : "appel en cours"
? currentCallNotif.currentCall.core.conference
? ("Réunion en cours : ") + currentCallNotif.currentCall.core.conference.core.subject
: (("Appel en cours : ") + currentCallNotif.remoteName) : "appel en cours"
onClicked: { onClicked: {
var callsWindow = UtilsCpp.getCallsWindow(currentCallNotif.currentCall) var callsWindow = UtilsCpp.getCallsWindow(
currentCallNotif.currentCall)
UtilsCpp.smartShowWindow(callsWindow) UtilsCpp.smartShowWindow(callsWindow)
} }
} }
@ -123,37 +126,58 @@ Item {
when: mainItem.contextualMenuOpenedComponent != undefined when: mainItem.contextualMenuOpenedComponent != undefined
value: -1 value: -1
} }
model: [ model: [{
{icon: AppIcons.phone, selectedIcon: AppIcons.phoneSelected, label: qsTr("Appels")}, "icon": AppIcons.phone,
{icon: AppIcons.adressBook, selectedIcon: AppIcons.adressBookSelected, label: qsTr("Contacts")}, "selectedIcon": AppIcons.phoneSelected,
{icon: AppIcons.chatTeardropText, selectedIcon: AppIcons.chatTeardropTextSelected, label: qsTr("Conversations"), visible: !SettingsCpp.disableChatFeature}, "label": qsTr("Appels")
{icon: AppIcons.videoconference, selectedIcon: AppIcons.videoconferenceSelected, label: qsTr("Réunions"), visible: !SettingsCpp.disableMeetingsFeature} }, {
] "icon": AppIcons.adressBook,
"selectedIcon": AppIcons.adressBookSelected,
"label": qsTr("Contacts")
}, {
"icon": AppIcons.chatTeardropText,
"selectedIcon": AppIcons.chatTeardropTextSelected,
"label": qsTr("Conversations"),
"visible": !SettingsCpp.disableChatFeature
}, {
"icon": AppIcons.videoconference,
"selectedIcon": AppIcons.videoconferenceSelected,
"label": qsTr("Réunions"),
"visible": !SettingsCpp.disableMeetingsFeature
}]
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (currentIndex == -1) return if (currentIndex == -1)
if (currentIndex === 0 && accountProxy.defaultAccount) accountProxy.defaultAccount.core?.lResetMissedCalls() return
if (currentIndex === 0 && accountProxy.defaultAccount)
accountProxy.defaultAccount.core?.lResetMissedCalls()
if (mainItem.contextualMenuOpenedComponent) { if (mainItem.contextualMenuOpenedComponent) {
closeContextualMenuComponent() closeContextualMenuComponent()
} }
} }
Keys.onPressed: (event)=>{ Keys.onPressed: event => {
if(event.key == Qt.Key_Right){ if (event.key == Qt.Key_Right) {
mainStackView.currentItem.forceActiveFocus() mainStackView.currentItem.forceActiveFocus()
} }
} }
Component.onCompleted:{ Component.onCompleted: {
if(SettingsCpp.shortcutCount > 0){ if (SettingsCpp.shortcutCount > 0) {
var shortcuts = SettingsCpp.shortcuts var shortcuts = SettingsCpp.shortcuts
shortcuts.forEach((shortcut) => { shortcuts.forEach(shortcut => {
model.push({icon: shortcut.icon, selectedIcon: shortcut.icon, label: shortcut.name, colored: true, link:shortcut.link}) model.push({
}); "icon": shortcut.icon,
"selectedIcon": shortcut.icon,
"label": shortcut.name,
"colored": true,
"link": shortcut.link
})
})
} }
initButtons() initButtons()
currentIndex= SettingsCpp.getLastActiveTabIndex() currentIndex = SettingsCpp.getLastActiveTabIndex()
} }
} }
ColumnLayout { ColumnLayout {
spacing:0 spacing: 0
RowLayout { RowLayout {
id: topRow id: topRow
@ -170,7 +194,7 @@ Item {
numericPadButton.checkable: false numericPadButton.checkable: false
handleNumericPadPopupButtonsPressed: false handleNumericPadPopupButtonsPressed: false
onOpenNumericPadRequested:mainItem.goToNewCall() onOpenNumericPadRequested: mainItem.goToNewCall()
Connections { Connections {
target: mainItem target: mainItem
@ -181,22 +205,27 @@ Item {
} }
onTextChanged: { onTextChanged: {
if (text.length != 0) listPopup.open() if (text.length != 0)
else listPopup.close() listPopup.open()
else
listPopup.close()
} }
KeyNavigation.down: contactList //contactLoader.item?.count > 0 || !contactLoader.item?.footerItem? contactLoader.item : contactLoader.item?.footerItem KeyNavigation.down: contactList //contactLoader.item?.count > 0 || !contactLoader.item?.footerItem? contactLoader.item : contactLoader.item?.footerItem
KeyNavigation.up: contactList//contactLoader.item?.footerItem ? contactLoader.item?.footerItem : contactLoader.item KeyNavigation.up: contactList //contactLoader.item?.footerItem ? contactLoader.item?.footerItem : contactLoader.item
Popup { Popup {
id: listPopup id: listPopup
width: magicSearchBar.width width: magicSearchBar.width
property int maxHeight: 400 * DefaultStyle.dp property int maxHeight: 400 * DefaultStyle.dp
property bool displayScrollbar: contactList.height > maxHeight property bool displayScrollbar: contactList.height > maxHeight
height: Math.min(contactList.contentHeight, maxHeight) + topPadding + bottomPadding height: Math.min(
contactList.contentHeight,
maxHeight) + topPadding + bottomPadding
y: magicSearchBar.height y: magicSearchBar.height
closePolicy: Popup.CloseOnEscape // closePolicy: Popup.CloseOnEscape
topPadding: 20 * DefaultStyle.dp topPadding: 20 * DefaultStyle.dp
bottomPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 10 * DefaultStyle.dp bottomPadding: contactList.haveContacts ? 20 * DefaultStyle.dp : 10
* DefaultStyle.dp
rightPadding: 8 * DefaultStyle.dp rightPadding: 8 * DefaultStyle.dp
leftPadding: 20 * DefaultStyle.dp leftPadding: 20 * DefaultStyle.dp
visible: magicSearchBar.text.length != 0 visible: magicSearchBar.text.length != 0
@ -210,7 +239,6 @@ Item {
anchors.fill: parent anchors.fill: parent
border.color: DefaultStyle.main1_500_main border.color: DefaultStyle.main1_500_main
border.width: contactList.activeFocus ? 2 : 0 border.width: contactList.activeFocus ? 2 : 0
} }
MultiEffect { MultiEffect {
source: popupBg source: popupBg
@ -224,7 +252,8 @@ Item {
contentItem: AllContactListView { contentItem: AllContactListView {
id: contactList id: contactList
width: listPopup.width - listPopup.leftPadding - listPopup.rightPadding width: listPopup.width - listPopup.leftPadding
- listPopup.rightPadding
itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin) itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin)
showInitials: false showInitials: false
showContactMenu: false showContactMenu: false
@ -283,8 +312,12 @@ Item {
delegate: Item { delegate: Item {
Connections { Connections {
target: modelData.core target: modelData.core
function onShowMwiChanged() {voicemail.updateCumulatedMwi()} function onShowMwiChanged() {
function onVoicemailAddressChanged(){voicemail.updateCumulatedMwi()} voicemail.updateCumulatedMwi()
}
function onVoicemailAddressChanged() {
voicemail.updateCumulatedMwi()
}
} }
} }
} }
@ -293,7 +326,7 @@ Item {
var count = 0 var count = 0
var showMwi = false var showMwi = false
var supportsVoiceMail = false var supportsVoiceMail = false
for (var i=0 ; i < accountProxy.count ; i++ ) { for (var i = 0; i < accountProxy.count; i++) {
var core = accountProxy.getAt(i).core var core = accountProxy.getAt(i).core
count += core.voicemailCount count += core.voicemailCount
showMwi |= core.showMwi showMwi |= core.showMwi
@ -312,10 +345,15 @@ Item {
if (accountProxy.count > 1) { if (accountProxy.count > 1) {
avatarButton.popup.open() avatarButton.popup.open()
} else { } else {
if (accountProxy.defaultAccount.core.voicemailAddress.length > 0) if (accountProxy.defaultAccount.core.voicemailAddress.length
UtilsCpp.createCall(accountProxy.defaultAccount.core.voicemailAddress) > 0)
UtilsCpp.createCall(
accountProxy.defaultAccount.core.voicemailAddress)
else else
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("L'URI de messagerie vocale n'est pas définie."), false) UtilsCpp.showInformationPopup(
qsTr("Erreur"), qsTr(
"L'URI de messagerie vocale n'est pas définie."),
false)
} }
} }
} }
@ -334,7 +372,7 @@ Item {
AccountListView { AccountListView {
id: accounts id: accounts
onAddAccountRequest: mainItem.addAccountRequest() onAddAccountRequest: mainItem.addAccountRequest()
onEditAccount: function(account) { onEditAccount: function (account) {
avatarButton.popup.close() avatarButton.popup.close()
openAccountSettings(account) openAccountSettings(account)
} }
@ -351,10 +389,11 @@ Item {
id: popupFocus id: popupFocus
implicitHeight: settingsButtons.implicitHeight implicitHeight: settingsButtons.implicitHeight
implicitWidth: settingsButtons.implicitWidth implicitWidth: settingsButtons.implicitWidth
Keys.onPressed: (event)=> { Keys.onPressed: event => {
if (event.key == Qt.Key_Left || event.key == Qt.Key_Escape) { if (event.key == Qt.Key_Left
|| event.key == Qt.Key_Escape) {
settingsMenuButton.popup.close() settingsMenuButton.popup.close()
event.accepted = true; event.accepted = true
} }
} }
@ -371,23 +410,33 @@ Item {
icon.height: 32 * DefaultStyle.dp icon.height: 32 * DefaultStyle.dp
text: qsTr("Mon compte") text: qsTr("Mon compte")
icon.source: AppIcons.manageProfile icon.source: AppIcons.manageProfile
onClicked: openAccountSettings(accountProxy.defaultAccount ? accountProxy.defaultAccount : accountProxy.firstAccount()) onClicked: openAccountSettings(
KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(0) : null accountProxy.defaultAccount ? accountProxy.defaultAccount : accountProxy.firstAccount())
KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(0) : null KeyNavigation.up: visibleChildren.length
!= 0 ? settingsMenuButton.getPreviousItem(
0) : null
KeyNavigation.down: visibleChildren.length
!= 0 ? settingsMenuButton.getNextItem(
0) : null
} }
IconLabelButton { IconLabelButton {
id: dndButton id: dndButton
Layout.fillWidth: true Layout.fillWidth: true
icon.width: 32 * DefaultStyle.dp icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp icon.height: 32 * DefaultStyle.dp
text: SettingsCpp.dnd ? qsTr("Désactiver ne pas déranger") : qsTr("Activer ne pas déranger") text: SettingsCpp.dnd ? qsTr("Désactiver ne pas déranger") : qsTr(
"Activer ne pas déranger")
icon.source: AppIcons.bellDnd icon.source: AppIcons.bellDnd
onClicked: { onClicked: {
settingsMenuButton.popup.close() settingsMenuButton.popup.close()
SettingsCpp.dnd = !SettingsCpp.dnd SettingsCpp.dnd = !SettingsCpp.dnd
} }
KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(1) : null KeyNavigation.up: visibleChildren.length
KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(1) : null != 0 ? settingsMenuButton.getPreviousItem(
1) : null
KeyNavigation.down: visibleChildren.length
!= 0 ? settingsMenuButton.getNextItem(
1) : null
} }
IconLabelButton { IconLabelButton {
id: settingsButton id: settingsButton
@ -397,9 +446,14 @@ Item {
icon.height: 32 * DefaultStyle.dp icon.height: 32 * DefaultStyle.dp
text: qsTr("Paramètres") text: qsTr("Paramètres")
icon.source: AppIcons.settings icon.source: AppIcons.settings
onClicked: openContextualMenuComponent(settingsPageComponent) onClicked: openContextualMenuComponent(
KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(2) : null settingsPageComponent)
KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(2) : null KeyNavigation.up: visibleChildren.length
!= 0 ? settingsMenuButton.getPreviousItem(
2) : null
KeyNavigation.down: visibleChildren.length
!= 0 ? settingsMenuButton.getNextItem(
2) : null
} }
IconLabelButton { IconLabelButton {
id: recordsButton id: recordsButton
@ -409,8 +463,12 @@ Item {
icon.height: 32 * DefaultStyle.dp icon.height: 32 * DefaultStyle.dp
text: qsTr("Enregistrements") text: qsTr("Enregistrements")
icon.source: AppIcons.micro icon.source: AppIcons.micro
KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(3) : null KeyNavigation.up: visibleChildren.length
KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(3) : null != 0 ? settingsMenuButton.getPreviousItem(
3) : null
KeyNavigation.down: visibleChildren.length
!= 0 ? settingsMenuButton.getNextItem(
3) : null
} }
IconLabelButton { IconLabelButton {
id: helpButton id: helpButton
@ -419,9 +477,14 @@ Item {
icon.height: 32 * DefaultStyle.dp icon.height: 32 * DefaultStyle.dp
text: qsTr("Aide") text: qsTr("Aide")
icon.source: AppIcons.question icon.source: AppIcons.question
onClicked: openContextualMenuComponent(helpPageComponent) onClicked: openContextualMenuComponent(
KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(4) : null helpPageComponent)
KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(4) : null KeyNavigation.up: visibleChildren.length
!= 0 ? settingsMenuButton.getPreviousItem(
4) : null
KeyNavigation.down: visibleChildren.length
!= 0 ? settingsMenuButton.getNextItem(
4) : null
} }
IconLabelButton { IconLabelButton {
id: quitButton id: quitButton
@ -432,19 +495,24 @@ Item {
icon.source: AppIcons.power icon.source: AppIcons.power
onClicked: { onClicked: {
settingsMenuButton.popup.close() settingsMenuButton.popup.close()
UtilsCpp.getMainWindow().showConfirmationLambdaPopup("", UtilsCpp.getMainWindow(
qsTr("Quitter Linphone ?"), ).showConfirmationLambdaPopup(
"", qsTr(
"Quitter Linphone ?"),
"", "",
function (confirmed) { function (confirmed) {
if (confirmed) { if (confirmed) {
console.info("Exiting App from Top Menu"); console.info("Exiting App from Top Menu")
Qt.quit() Qt.quit()
} }
})
} }
) KeyNavigation.up: visibleChildren.length
} != 0 ? settingsMenuButton.getPreviousItem(
KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(5) : null 5) : null
KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(5) : null KeyNavigation.down: visibleChildren.length
!= 0 ? settingsMenuButton.getNextItem(
5) : null
} }
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
@ -455,14 +523,19 @@ Item {
IconLabelButton { IconLabelButton {
id: addAccountButton id: addAccountButton
Layout.fillWidth: true Layout.fillWidth: true
visible: SettingsCpp.maxAccount == 0 || SettingsCpp.maxAccount > accountProxy.count visible: SettingsCpp.maxAccount == 0
|| SettingsCpp.maxAccount > accountProxy.count
icon.width: 32 * DefaultStyle.dp icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp icon.height: 32 * DefaultStyle.dp
text: qsTr("Ajouter un compte") text: qsTr("Ajouter un compte")
icon.source: AppIcons.plusCircle icon.source: AppIcons.plusCircle
onClicked: mainItem.addAccountRequest() onClicked: mainItem.addAccountRequest()
KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(7) : null KeyNavigation.up: visibleChildren.length
KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(7) : null != 0 ? settingsMenuButton.getPreviousItem(
7) : null
KeyNavigation.down: visibleChildren.length
!= 0 ? settingsMenuButton.getNextItem(
7) : null
} }
} }
} }
@ -476,14 +549,19 @@ Item {
objectName: "mainStackLayout" objectName: "mainStackLayout"
property int _currentIndex: tabbar.currentIndex property int _currentIndex: tabbar.currentIndex
currentIndex: -1 currentIndex: -1
onActiveFocusChanged: if(activeFocus && currentIndex >= 0) children[currentIndex].forceActiveFocus() onActiveFocusChanged: if (activeFocus
on_CurrentIndexChanged:{ && currentIndex >= 0)
children[currentIndex].forceActiveFocus()
on_CurrentIndexChanged: {
if (count > 0) { if (count > 0) {
if(_currentIndex >= count && tabbar.model[_currentIndex].link){ if (_currentIndex >= count
Qt.openUrlExternally(tabbar.model[_currentIndex].link) && tabbar.model[_currentIndex].link) {
}else if (_currentIndex >= 0){ Qt.openUrlExternally(
tabbar.model[_currentIndex].link)
} else if (_currentIndex >= 0) {
currentIndex = _currentIndex currentIndex = _currentIndex
SettingsCpp.setLastActiveTabIndex(currentIndex) SettingsCpp.setLastActiveTabIndex(
currentIndex)
} }
} }
} }
@ -491,19 +569,28 @@ Item {
id: callPage id: callPage
Connections { Connections {
target: mainItem target: mainItem
function onOpenNewCallRequest(){ callPage.goToNewCall()} function onOpenNewCallRequest() {
function onCallCreated(){ callPage.goToCallHistory()} callPage.goToNewCall()
function onOpenCallHistory(){ callPage.goToCallHistory()} }
function onOpenNumPadRequest(){ callPage.openNumPadRequest()} function onCallCreated() {
callPage.goToCallHistory()
}
function onOpenCallHistory() {
callPage.goToCallHistory()
}
function onOpenNumPadRequest() {
callPage.openNumPadRequest()
}
} }
onCreateContactRequested: (name, address) => { onCreateContactRequested: (name, address) => {
mainItem.createContact(name, address) mainItem.createContact(
name, address)
} }
Component.onCompleted: { Component.onCompleted: {
magicSearchBar.numericPadPopup = callPage.numericPadPopup magicSearchBar.numericPadPopup = callPage.numericPadPopup
} }
} }
ContactPage{ ContactPage {
id: contactPage id: contactPage
Connections { Connections {
target: mainItem target: mainItem
@ -515,9 +602,9 @@ Item {
} }
} }
} }
Item{} Item {}
//ConversationPage{} //ConversationPage{}
MeetingPage{} MeetingPage {}
} }
} }
Component { Component {
@ -545,7 +632,12 @@ Item {
Control.StackView { Control.StackView {
id: mainStackView id: mainStackView
property Transition noTransition: Transition { property Transition noTransition: Transition {
PropertyAnimation { property: "opacity"; from: 1; to: 1; duration: 0 } PropertyAnimation {
property: "opacity"
from: 1
to: 1
duration: 0
}
} }
pushEnter: noTransition pushEnter: noTransition
pushExit: noTransition pushExit: noTransition
@ -560,4 +652,3 @@ Item {
} }
} }
} }