diff --git a/Linphone/view/Control/Button/PopupButton.qml b/Linphone/view/Control/Button/PopupButton.qml index dfa93b094..7ff4d7b9d 100644 --- a/Linphone/view/Control/Button/PopupButton.qml +++ b/Linphone/view/Control/Button/PopupButton.qml @@ -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 + } + } + } } diff --git a/Linphone/view/Control/Display/Call/CallHistoryListView.qml b/Linphone/view/Control/Display/Call/CallHistoryListView.qml index daad6e8b2..1f06d1405 100644 --- a/Linphone/view/Control/Display/Call/CallHistoryListView.qml +++ b/Linphone/view/Control/Display/Call/CallHistoryListView.qml @@ -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 diff --git a/Linphone/view/Control/Display/Contact/AllContactListView.qml b/Linphone/view/Control/Display/Contact/AllContactListView.qml index 1c0db0156..d0e63967d 100644 --- a/Linphone/view/Control/Display/Contact/AllContactListView.qml +++ b/Linphone/view/Control/Display/Contact/AllContactListView.qml @@ -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 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 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 diff --git a/Linphone/view/Control/Display/Contact/ContactListItem.qml b/Linphone/view/Control/Display/Contact/ContactListItem.qml index 94ffd87ff..f5bb3fbb9 100644 --- a/Linphone/view/Control/Display/Contact/ContactListItem.qml +++ b/Linphone/view/Control/Display/Contact/ContactListItem.qml @@ -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 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 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) + } + } + } } diff --git a/Linphone/view/Page/Layout/Main/MainLayout.qml b/Linphone/view/Page/Layout/Main/MainLayout.qml index b6dec20b5..550f39051 100644 --- a/Linphone/view/Page/Layout/Main/MainLayout.qml +++ b/Linphone/view/Page/Layout/Main/MainLayout.qml @@ -1,7 +1,8 @@ + + /** * Qml template used for welcome and login/register pages **/ - import QtCore import QtQuick import QtQuick.Layouts @@ -11,167 +12,190 @@ import QtQuick.Effects import Linphone import UtilsCpp import SettingsCpp -import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils -import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle +import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils +import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle Item { - id: mainItem - property var callObj - property var contextualMenuOpenedComponent: undefined - - signal addAccountRequest() - signal openNewCallRequest() - signal callCreated() - signal openCallHistory() - signal openNumPadRequest() - signal displayContactRequested(string contactAddress) - signal createContactRequested(string name, string address) - signal accountRemoved() + id: mainItem + property var callObj + property var contextualMenuOpenedComponent: undefined + signal addAccountRequest + signal openNewCallRequest + signal callCreated + signal openCallHistory + signal openNumPadRequest + signal displayContactRequested(string contactAddress) + signal createContactRequested(string name, string address) + signal accountRemoved - function goToNewCall() { - tabbar.currentIndex = 0 - mainItem.openNewCallRequest() - } - function goToCallHistory() { - tabbar.currentIndex = 0 - mainItem.openCallHistory() - } - function displayContactPage(contactAddress) { - tabbar.currentIndex = 1 - mainItem.displayContactRequested(contactAddress) - } + function goToNewCall() { + tabbar.currentIndex = 0 + mainItem.openNewCallRequest() + } + function goToCallHistory() { + tabbar.currentIndex = 0 + mainItem.openCallHistory() + } + function displayContactPage(contactAddress) { + tabbar.currentIndex = 1 + mainItem.displayContactRequested(contactAddress) + } - function createContact(name, address) { - tabbar.currentIndex = 1 - mainItem.createContactRequested(name, address) - } - - function openContextualMenuComponent(component) { - if (mainItem.contextualMenuOpenedComponent && mainItem.contextualMenuOpenedComponent != component) { - mainStackView.pop() - mainItem.contextualMenuOpenedComponent = undefined - } - if (!mainItem.contextualMenuOpenedComponent) { - mainStackView.push(component) - mainItem.contextualMenuOpenedComponent = component - } - settingsMenuButton.popup.close() - } - - function closeContextualMenuComponent() { - mainStackView.pop() - mainItem.contextualMenuOpenedComponent = undefined - } + function createContact(name, address) { + tabbar.currentIndex = 1 + mainItem.createContactRequested(name, address) + } - function openAccountSettings(account: AccountGui) { - var page = accountSettingsPageComponent.createObject(parent, {"account": account}); - openContextualMenuComponent(page) - } + function openContextualMenuComponent(component) { + if (mainItem.contextualMenuOpenedComponent + && mainItem.contextualMenuOpenedComponent != component) { + mainStackView.pop() + mainItem.contextualMenuOpenedComponent = undefined + } + if (!mainItem.contextualMenuOpenedComponent) { + mainStackView.push(component) + mainItem.contextualMenuOpenedComponent = component + } + settingsMenuButton.popup.close() + } - AccountProxy { - id: accountProxy - sourceModel: AppCpp.accounts - onDefaultAccountChanged: if (tabbar.currentIndex === 0 && defaultAccount) defaultAccount.core?.lResetMissedCalls() - } + function closeContextualMenuComponent() { + mainStackView.pop() + mainItem.contextualMenuOpenedComponent = undefined + } - CallProxy { - id: callsModel - sourceModel: AppCpp.calls - } + function openAccountSettings(account) { + var page = accountSettingsPageComponent.createObject(parent, { + "account": account + }) + openContextualMenuComponent(page) + } - Item{ - anchors.fill: parent - - Popup { - id: currentCallNotif - background: Item{} - closePolicy: Control.Popup.NoAutoClose - visible: currentCall - && currentCall.core.state != LinphoneEnums.CallState.Idle - && currentCall.core.state != LinphoneEnums.CallState.IncomingReceived - && currentCall.core.state != LinphoneEnums.CallState.PushIncomingReceived - x: mainItem.width/2 - width/2 - y: contentItem.height/2 - property var currentCall: callsModel.currentCall ? callsModel.currentCall : null - property string remoteName: currentCall ? currentCall.core.remoteName : "" - contentItem: MediumButton { - style: ButtonStyle.toast - 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" - onClicked: { - var callsWindow = UtilsCpp.getCallsWindow(currentCallNotif.currentCall) - UtilsCpp.smartShowWindow(callsWindow) - } - } - } - - RowLayout { - anchors.fill: parent - spacing: 0 - anchors.topMargin: 25 * DefaultStyle.dp - - VerticalTabBar { - id: tabbar - Layout.fillHeight: true - Layout.preferredWidth: 82 * DefaultStyle.dp - defaultAccount: accountProxy.defaultAccount - currentIndex: 0 - Binding on currentIndex { - when: mainItem.contextualMenuOpenedComponent != undefined - value: -1 - } - model: [ - {icon: AppIcons.phone, selectedIcon: AppIcons.phoneSelected, label: qsTr("Appels")}, - {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: { - if (currentIndex == -1) return - if (currentIndex === 0 && accountProxy.defaultAccount) accountProxy.defaultAccount.core?.lResetMissedCalls() - if (mainItem.contextualMenuOpenedComponent) { - closeContextualMenuComponent() - } - } - Keys.onPressed: (event)=>{ - if(event.key == Qt.Key_Right){ - mainStackView.currentItem.forceActiveFocus() - } - } - Component.onCompleted:{ - if(SettingsCpp.shortcutCount > 0){ - var shortcuts = SettingsCpp.shortcuts - shortcuts.forEach((shortcut) => { - model.push({icon: shortcut.icon, selectedIcon: shortcut.icon, label: shortcut.name, colored: true, link:shortcut.link}) - }); - } - initButtons() - currentIndex= SettingsCpp.getLastActiveTabIndex() - } - } - ColumnLayout { - spacing:0 + AccountProxy { + id: accountProxy + sourceModel: AppCpp.accounts + onDefaultAccountChanged: if (tabbar.currentIndex === 0 + && defaultAccount) + defaultAccount.core?.lResetMissedCalls() + } - RowLayout { - id: topRow - Layout.preferredHeight: 50 * DefaultStyle.dp - Layout.leftMargin: 45 * DefaultStyle.dp - Layout.rightMargin: 41 * DefaultStyle.dp - spacing: 25 * DefaultStyle.dp - SearchBar { - id: magicSearchBar - Layout.fillWidth: true - placeholderText: SettingsCpp.disableChatFeature ? qsTr("Rechercher un contact, appeler...") : qsTr("Rechercher un contact, appeler ou envoyer un message...") - focusedBorderColor: DefaultStyle.main1_500_main - numericPadButton.visible: text.length === 0 - numericPadButton.checkable: false - handleNumericPadPopupButtonsPressed: false + CallProxy { + id: callsModel + sourceModel: AppCpp.calls + } + + Item { + anchors.fill: parent + + Popup { + id: currentCallNotif + background: Item {} + closePolicy: Control.Popup.NoAutoClose + visible: currentCall + && currentCall.core.state != LinphoneEnums.CallState.Idle + && currentCall.core.state != LinphoneEnums.CallState.IncomingReceived + && currentCall.core.state != LinphoneEnums.CallState.PushIncomingReceived + x: mainItem.width / 2 - width / 2 + y: contentItem.height / 2 + property var currentCall: callsModel.currentCall ? callsModel.currentCall : null + property string remoteName: currentCall ? currentCall.core.remoteName : "" + contentItem: MediumButton { + style: ButtonStyle.toast + 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" + onClicked: { + var callsWindow = UtilsCpp.getCallsWindow( + currentCallNotif.currentCall) + UtilsCpp.smartShowWindow(callsWindow) + } + } + } + + RowLayout { + anchors.fill: parent + spacing: 0 + anchors.topMargin: 25 * DefaultStyle.dp + + VerticalTabBar { + id: tabbar + Layout.fillHeight: true + Layout.preferredWidth: 82 * DefaultStyle.dp + defaultAccount: accountProxy.defaultAccount + currentIndex: 0 + Binding on currentIndex { + when: mainItem.contextualMenuOpenedComponent != undefined + value: -1 + } + model: [{ + "icon": AppIcons.phone, + "selectedIcon": AppIcons.phoneSelected, + "label": qsTr("Appels") + }, { + "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: { + if (currentIndex == -1) + return + if (currentIndex === 0 && accountProxy.defaultAccount) + accountProxy.defaultAccount.core?.lResetMissedCalls() + if (mainItem.contextualMenuOpenedComponent) { + closeContextualMenuComponent() + } + } + Keys.onPressed: event => { + if (event.key == Qt.Key_Right) { + mainStackView.currentItem.forceActiveFocus() + } + } + Component.onCompleted: { + if (SettingsCpp.shortcutCount > 0) { + var shortcuts = SettingsCpp.shortcuts + shortcuts.forEach(shortcut => { + model.push({ + "icon": shortcut.icon, + "selectedIcon": shortcut.icon, + "label": shortcut.name, + "colored": true, + "link": shortcut.link + }) + }) + } + initButtons() + currentIndex = SettingsCpp.getLastActiveTabIndex() + } + } + ColumnLayout { + spacing: 0 + + RowLayout { + id: topRow + Layout.preferredHeight: 50 * DefaultStyle.dp + Layout.leftMargin: 45 * DefaultStyle.dp + Layout.rightMargin: 41 * DefaultStyle.dp + spacing: 25 * DefaultStyle.dp + SearchBar { + id: magicSearchBar + Layout.fillWidth: true + placeholderText: SettingsCpp.disableChatFeature ? qsTr("Rechercher un contact, appeler...") : qsTr("Rechercher un contact, appeler ou envoyer un message...") + focusedBorderColor: DefaultStyle.main1_500_main + numericPadButton.visible: text.length === 0 + numericPadButton.checkable: false + handleNumericPadPopupButtonsPressed: false + + onOpenNumericPadRequested: mainItem.goToNewCall() - onOpenNumericPadRequested:mainItem.goToNewCall() - Connections { target: mainItem function onCallCreated() { @@ -180,384 +204,451 @@ Item { } } - onTextChanged: { - if (text.length != 0) listPopup.open() - else listPopup.close() - } - 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 + onTextChanged: { + if (text.length != 0) + listPopup.open() + else + listPopup.close() + } + 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 - Popup { - id: listPopup - width: magicSearchBar.width - property int maxHeight: 400 * DefaultStyle.dp + Popup { + id: listPopup + width: magicSearchBar.width + property int maxHeight: 400 * DefaultStyle.dp property bool displayScrollbar: contactList.height > maxHeight - height: Math.min(contactList.contentHeight, maxHeight) + topPadding + bottomPadding - y: magicSearchBar.height - closePolicy: Popup.CloseOnEscape + height: Math.min( + contactList.contentHeight, + maxHeight) + topPadding + bottomPadding + y: magicSearchBar.height + // closePolicy: Popup.CloseOnEscape 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 - leftPadding: 20 * DefaultStyle.dp + leftPadding: 20 * DefaultStyle.dp visible: magicSearchBar.text.length != 0 - background: Item { - anchors.fill: parent - Rectangle { - id: popupBg - radius: 16 * DefaultStyle.dp + background: Item { + anchors.fill: parent + Rectangle { + id: popupBg + radius: 16 * DefaultStyle.dp color: DefaultStyle.grey_0 - anchors.fill: parent - border.color: DefaultStyle.main1_500_main - border.width: contactList.activeFocus ? 2 : 0 - - } - MultiEffect { - source: popupBg - anchors.fill: popupBg - shadowEnabled: true - shadowBlur: 0.1 - shadowColor: DefaultStyle.grey_1000 - shadowOpacity: 0.1 + anchors.fill: parent + border.color: DefaultStyle.main1_500_main + border.width: contactList.activeFocus ? 2 : 0 } - } + MultiEffect { + source: popupBg + anchors.fill: popupBg + shadowEnabled: true + shadowBlur: 0.1 + shadowColor: DefaultStyle.grey_1000 + shadowOpacity: 0.1 + } + } contentItem: AllContactListView { id: contactList - width: listPopup.width - listPopup.leftPadding - listPopup.rightPadding - itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin) - showInitials: false - showContactMenu: false - showActions: true - showFavorites: false - selectionEnabled: false - showDefaultAddress: true - searchOnEmpty: false - - sectionsPixelSize: 13 * DefaultStyle.dp - sectionsWeight: 700 * DefaultStyle.dp - sectionsSpacing: 5 * DefaultStyle.dp - + width: listPopup.width - listPopup.leftPadding + - listPopup.rightPadding + itemsRightMargin: 5 * DefaultStyle.dp //(Actions have already 10 of margin) + showInitials: false + showContactMenu: false + showActions: true + showFavorites: false + selectionEnabled: false + showDefaultAddress: true + searchOnEmpty: false + + sectionsPixelSize: 13 * DefaultStyle.dp + sectionsWeight: 700 * DefaultStyle.dp + sectionsSpacing: 5 * DefaultStyle.dp + searchBarText: magicSearchBar.text - } - } - } - RowLayout { - spacing: 10 * DefaultStyle.dp - PopupButton { - id: deactivateDndButton - Layout.preferredWidth: 32 * DefaultStyle.dp - Layout.preferredHeight: 32 * DefaultStyle.dp - popup.padding: 14 * DefaultStyle.dp - visible: SettingsCpp.dnd - contentItem: EffectImage { - imageSource: AppIcons.bellDnd - width: 32 * DefaultStyle.dp - height: 32 * DefaultStyle.dp - Layout.preferredWidth: 32 * DefaultStyle.dp - Layout.preferredHeight: 32 * DefaultStyle.dp - fillMode: Image.PreserveAspectFit - colorizationColor: DefaultStyle.main1_500_main - } - popup.contentItem: ColumnLayout { - IconLabelButton { - Layout.fillWidth: true - focus: visible - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Désactiver ne pas déranger") - icon.source: AppIcons.bellDnd - onClicked: { - deactivateDndButton.popup.close() - SettingsCpp.dnd = false - } - } - } - } - Voicemail { - id: voicemail - Layout.preferredWidth: 42 * DefaultStyle.dp - Layout.preferredHeight: 36 * DefaultStyle.dp - Repeater { - model: accountProxy - delegate: Item { - Connections { - target: modelData.core - function onShowMwiChanged() {voicemail.updateCumulatedMwi()} - function onVoicemailAddressChanged(){voicemail.updateCumulatedMwi()} - } - } - } + } + } + } + RowLayout { + spacing: 10 * DefaultStyle.dp + PopupButton { + id: deactivateDndButton + Layout.preferredWidth: 32 * DefaultStyle.dp + Layout.preferredHeight: 32 * DefaultStyle.dp + popup.padding: 14 * DefaultStyle.dp + visible: SettingsCpp.dnd + contentItem: EffectImage { + imageSource: AppIcons.bellDnd + width: 32 * DefaultStyle.dp + height: 32 * DefaultStyle.dp + Layout.preferredWidth: 32 * DefaultStyle.dp + Layout.preferredHeight: 32 * DefaultStyle.dp + fillMode: Image.PreserveAspectFit + colorizationColor: DefaultStyle.main1_500_main + } + popup.contentItem: ColumnLayout { + IconLabelButton { + Layout.fillWidth: true + focus: visible + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Désactiver ne pas déranger") + icon.source: AppIcons.bellDnd + onClicked: { + deactivateDndButton.popup.close() + SettingsCpp.dnd = false + } + } + } + } + Voicemail { + id: voicemail + Layout.preferredWidth: 42 * DefaultStyle.dp + Layout.preferredHeight: 36 * DefaultStyle.dp + Repeater { + model: accountProxy + delegate: Item { + Connections { + target: modelData.core + function onShowMwiChanged() { + voicemail.updateCumulatedMwi() + } + function onVoicemailAddressChanged() { + voicemail.updateCumulatedMwi() + } + } + } + } - function updateCumulatedMwi() { - var count = 0 - var showMwi = false - var supportsVoiceMail = false - for (var i=0 ; i < accountProxy.count ; i++ ) { - var core = accountProxy.getAt(i).core - count += core.voicemailCount - showMwi |= core.showMwi - supportsVoiceMail |= core.voicemailAddress.length > 0 - } - voicemail.showMwi = showMwi - voicemail.voicemailCount = count - voicemail.visible = showMwi || supportsVoiceMail - } + function updateCumulatedMwi() { + var count = 0 + var showMwi = false + var supportsVoiceMail = false + for (var i = 0; i < accountProxy.count; i++) { + var core = accountProxy.getAt(i).core + count += core.voicemailCount + showMwi |= core.showMwi + supportsVoiceMail |= core.voicemailAddress.length > 0 + } + voicemail.showMwi = showMwi + voicemail.voicemailCount = count + voicemail.visible = showMwi || supportsVoiceMail + } - Component.onCompleted: { - updateCumulatedMwi() - } - - onClicked: { - if (accountProxy.count > 1) { - avatarButton.popup.open() - } else { - if (accountProxy.defaultAccount.core.voicemailAddress.length > 0) - UtilsCpp.createCall(accountProxy.defaultAccount.core.voicemailAddress) - else - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("L'URI de messagerie vocale n'est pas définie."), false) - } - } - } - PopupButton { - id: avatarButton - Layout.preferredWidth: 54 * DefaultStyle.dp - Layout.preferredHeight: width - popup.padding: 14 * DefaultStyle.dp - contentItem: Avatar { - id: avatar - height: avatarButton.height - width: avatarButton.width - account: accountProxy.defaultAccount - } - popup.contentItem: ColumnLayout { - AccountListView { - id: accounts - onAddAccountRequest: mainItem.addAccountRequest() - onEditAccount: function(account) { - avatarButton.popup.close() - openAccountSettings(account) - } - } - } - } - PopupButton { - id: settingsMenuButton - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - popup.width: 271 * DefaultStyle.dp - popup.padding: 14 * DefaultStyle.dp - popup.contentItem: FocusScope { - id: popupFocus - implicitHeight: settingsButtons.implicitHeight - implicitWidth: settingsButtons.implicitWidth - Keys.onPressed: (event)=> { - if (event.key == Qt.Key_Left || event.key == Qt.Key_Escape) { - settingsMenuButton.popup.close() - event.accepted = true; - } - } - - ColumnLayout { - id: settingsButtons - spacing: 16 * DefaultStyle.dp - anchors.fill: parent - - IconLabelButton { - id: accountButton - Layout.fillWidth: true - visible: !SettingsCpp.hideAccountSettings - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Mon compte") - icon.source: AppIcons.manageProfile - onClicked: openAccountSettings(accountProxy.defaultAccount ? accountProxy.defaultAccount : accountProxy.firstAccount()) - KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(0) : null - KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(0) : null - } - IconLabelButton { - id: dndButton - Layout.fillWidth: true - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: SettingsCpp.dnd ? qsTr("Désactiver ne pas déranger") : qsTr("Activer ne pas déranger") - icon.source: AppIcons.bellDnd - onClicked: { - settingsMenuButton.popup.close() - SettingsCpp.dnd = !SettingsCpp.dnd - } - KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(1) : null - KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(1) : null - } - IconLabelButton { - id: settingsButton - Layout.fillWidth: true - visible: !SettingsCpp.hideSettings - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Paramètres") - icon.source: AppIcons.settings - onClicked: openContextualMenuComponent(settingsPageComponent) - KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(2) : null - KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(2) : null - } - IconLabelButton { - id: recordsButton - Layout.fillWidth: true - visible: !SettingsCpp.disableCallRecordings - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Enregistrements") - icon.source: AppIcons.micro - KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(3) : null - KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(3) : null - } - IconLabelButton { - id: helpButton - Layout.fillWidth: true - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Aide") - icon.source: AppIcons.question - onClicked: openContextualMenuComponent(helpPageComponent) - KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(4) : null - KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(4) : null - } - IconLabelButton { - id: quitButton - Layout.fillWidth: true - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Quitter Linphone") - icon.source: AppIcons.power - onClicked: { - settingsMenuButton.popup.close() - UtilsCpp.getMainWindow().showConfirmationLambdaPopup("", - qsTr("Quitter Linphone ?"), - "", - function (confirmed) { - if (confirmed) { - console.info("Exiting App from Top Menu"); - Qt.quit() - } - } - ) - } - KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(5) : null - KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(5) : null - } - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 1 * DefaultStyle.dp - visible: addAccountButton.visible - color: DefaultStyle.main2_400 - } - IconLabelButton { - id: addAccountButton - Layout.fillWidth: true - visible: SettingsCpp.maxAccount == 0 || SettingsCpp.maxAccount > accountProxy.count - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Ajouter un compte") - icon.source: AppIcons.plusCircle - onClicked: mainItem.addAccountRequest() - KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(7) : null - KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(7) : null - } - } - } - } - } - } - Component { - id: mainStackLayoutComponent - StackLayout { - id: mainStackLayout - objectName: "mainStackLayout" - property int _currentIndex: tabbar.currentIndex - currentIndex: -1 - onActiveFocusChanged: if(activeFocus && currentIndex >= 0) children[currentIndex].forceActiveFocus() - on_CurrentIndexChanged:{ - if (count > 0) { - if(_currentIndex >= count && tabbar.model[_currentIndex].link){ - Qt.openUrlExternally(tabbar.model[_currentIndex].link) - }else if (_currentIndex >= 0){ - currentIndex = _currentIndex - SettingsCpp.setLastActiveTabIndex(currentIndex) - } - } - } - CallPage { - id: callPage - Connections { - target: mainItem - function onOpenNewCallRequest(){ callPage.goToNewCall()} - function onCallCreated(){ callPage.goToCallHistory()} - function onOpenCallHistory(){ callPage.goToCallHistory()} - function onOpenNumPadRequest(){ callPage.openNumPadRequest()} - } - onCreateContactRequested: (name, address) => { - mainItem.createContact(name, address) - } - Component.onCompleted: { - magicSearchBar.numericPadPopup = callPage.numericPadPopup - } - } - ContactPage{ - id: contactPage - Connections { - target: mainItem - function onCreateContactRequested(name, address) { - contactPage.createContact(name, address) - } - function onDisplayContactRequested(contactAddress) { - contactPage.initialFriendToDisplay = contactAddress - } - } - } - Item{} - //ConversationPage{} - MeetingPage{} - } - } - Component { - id: accountSettingsPageComponent - AccountSettingsPage { - onGoBack: closeContextualMenuComponent() - onAccountRemoved: { - closeContextualMenuComponent() - mainItem.accountRemoved() - } - } - } - Component { - id: settingsPageComponent - SettingsPage { - onGoBack: closeContextualMenuComponent() - } - } - Component { - id: helpPageComponent - HelpPage { - onGoBack: closeContextualMenuComponent() - } - } - Control.StackView { - id: mainStackView - property Transition noTransition: Transition { - PropertyAnimation { property: "opacity"; from: 1; to: 1; duration: 0 } - } - pushEnter: noTransition - pushExit: noTransition - popEnter: noTransition - popExit: noTransition - Layout.topMargin: 24 * DefaultStyle.dp - Layout.fillWidth: true - Layout.fillHeight: true - initialItem: mainStackLayoutComponent - } - } - } - } -} - + Component.onCompleted: { + updateCumulatedMwi() + } + + onClicked: { + if (accountProxy.count > 1) { + avatarButton.popup.open() + } else { + if (accountProxy.defaultAccount.core.voicemailAddress.length + > 0) + UtilsCpp.createCall( + accountProxy.defaultAccount.core.voicemailAddress) + else + UtilsCpp.showInformationPopup( + qsTr("Erreur"), qsTr( + "L'URI de messagerie vocale n'est pas définie."), + false) + } + } + } + PopupButton { + id: avatarButton + Layout.preferredWidth: 54 * DefaultStyle.dp + Layout.preferredHeight: width + popup.padding: 14 * DefaultStyle.dp + contentItem: Avatar { + id: avatar + height: avatarButton.height + width: avatarButton.width + account: accountProxy.defaultAccount + } + popup.contentItem: ColumnLayout { + AccountListView { + id: accounts + onAddAccountRequest: mainItem.addAccountRequest() + onEditAccount: function (account) { + avatarButton.popup.close() + openAccountSettings(account) + } + } + } + } + PopupButton { + id: settingsMenuButton + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + popup.width: 271 * DefaultStyle.dp + popup.padding: 14 * DefaultStyle.dp + popup.contentItem: FocusScope { + id: popupFocus + implicitHeight: settingsButtons.implicitHeight + implicitWidth: settingsButtons.implicitWidth + Keys.onPressed: event => { + if (event.key == Qt.Key_Left + || event.key == Qt.Key_Escape) { + settingsMenuButton.popup.close() + event.accepted = true + } + } + + ColumnLayout { + id: settingsButtons + spacing: 16 * DefaultStyle.dp + anchors.fill: parent + + IconLabelButton { + id: accountButton + Layout.fillWidth: true + visible: !SettingsCpp.hideAccountSettings + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Mon compte") + icon.source: AppIcons.manageProfile + onClicked: openAccountSettings( + accountProxy.defaultAccount ? accountProxy.defaultAccount : accountProxy.firstAccount()) + KeyNavigation.up: visibleChildren.length + != 0 ? settingsMenuButton.getPreviousItem( + 0) : null + KeyNavigation.down: visibleChildren.length + != 0 ? settingsMenuButton.getNextItem( + 0) : null + } + IconLabelButton { + id: dndButton + Layout.fillWidth: true + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: SettingsCpp.dnd ? qsTr("Désactiver ne pas déranger") : qsTr( + "Activer ne pas déranger") + icon.source: AppIcons.bellDnd + onClicked: { + settingsMenuButton.popup.close() + SettingsCpp.dnd = !SettingsCpp.dnd + } + KeyNavigation.up: visibleChildren.length + != 0 ? settingsMenuButton.getPreviousItem( + 1) : null + KeyNavigation.down: visibleChildren.length + != 0 ? settingsMenuButton.getNextItem( + 1) : null + } + IconLabelButton { + id: settingsButton + Layout.fillWidth: true + visible: !SettingsCpp.hideSettings + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Paramètres") + icon.source: AppIcons.settings + onClicked: openContextualMenuComponent( + settingsPageComponent) + KeyNavigation.up: visibleChildren.length + != 0 ? settingsMenuButton.getPreviousItem( + 2) : null + KeyNavigation.down: visibleChildren.length + != 0 ? settingsMenuButton.getNextItem( + 2) : null + } + IconLabelButton { + id: recordsButton + Layout.fillWidth: true + visible: !SettingsCpp.disableCallRecordings + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Enregistrements") + icon.source: AppIcons.micro + KeyNavigation.up: visibleChildren.length + != 0 ? settingsMenuButton.getPreviousItem( + 3) : null + KeyNavigation.down: visibleChildren.length + != 0 ? settingsMenuButton.getNextItem( + 3) : null + } + IconLabelButton { + id: helpButton + Layout.fillWidth: true + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Aide") + icon.source: AppIcons.question + onClicked: openContextualMenuComponent( + helpPageComponent) + KeyNavigation.up: visibleChildren.length + != 0 ? settingsMenuButton.getPreviousItem( + 4) : null + KeyNavigation.down: visibleChildren.length + != 0 ? settingsMenuButton.getNextItem( + 4) : null + } + IconLabelButton { + id: quitButton + Layout.fillWidth: true + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Quitter Linphone") + icon.source: AppIcons.power + onClicked: { + settingsMenuButton.popup.close() + UtilsCpp.getMainWindow( + ).showConfirmationLambdaPopup( + "", qsTr( + "Quitter Linphone ?"), + "", + function (confirmed) { + if (confirmed) { + console.info("Exiting App from Top Menu") + Qt.quit() + } + }) + } + KeyNavigation.up: visibleChildren.length + != 0 ? settingsMenuButton.getPreviousItem( + 5) : null + KeyNavigation.down: visibleChildren.length + != 0 ? settingsMenuButton.getNextItem( + 5) : null + } + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 * DefaultStyle.dp + visible: addAccountButton.visible + color: DefaultStyle.main2_400 + } + IconLabelButton { + id: addAccountButton + Layout.fillWidth: true + visible: SettingsCpp.maxAccount == 0 + || SettingsCpp.maxAccount > accountProxy.count + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Ajouter un compte") + icon.source: AppIcons.plusCircle + onClicked: mainItem.addAccountRequest() + KeyNavigation.up: visibleChildren.length + != 0 ? settingsMenuButton.getPreviousItem( + 7) : null + KeyNavigation.down: visibleChildren.length + != 0 ? settingsMenuButton.getNextItem( + 7) : null + } + } + } + } + } + } + Component { + id: mainStackLayoutComponent + StackLayout { + id: mainStackLayout + objectName: "mainStackLayout" + property int _currentIndex: tabbar.currentIndex + currentIndex: -1 + onActiveFocusChanged: if (activeFocus + && currentIndex >= 0) + children[currentIndex].forceActiveFocus() + on_CurrentIndexChanged: { + if (count > 0) { + if (_currentIndex >= count + && tabbar.model[_currentIndex].link) { + Qt.openUrlExternally( + tabbar.model[_currentIndex].link) + } else if (_currentIndex >= 0) { + currentIndex = _currentIndex + SettingsCpp.setLastActiveTabIndex( + currentIndex) + } + } + } + CallPage { + id: callPage + Connections { + target: mainItem + function onOpenNewCallRequest() { + callPage.goToNewCall() + } + function onCallCreated() { + callPage.goToCallHistory() + } + function onOpenCallHistory() { + callPage.goToCallHistory() + } + function onOpenNumPadRequest() { + callPage.openNumPadRequest() + } + } + onCreateContactRequested: (name, address) => { + mainItem.createContact( + name, address) + } + Component.onCompleted: { + magicSearchBar.numericPadPopup = callPage.numericPadPopup + } + } + ContactPage { + id: contactPage + Connections { + target: mainItem + function onCreateContactRequested(name, address) { + contactPage.createContact(name, address) + } + function onDisplayContactRequested(contactAddress) { + contactPage.initialFriendToDisplay = contactAddress + } + } + } + Item {} + //ConversationPage{} + MeetingPage {} + } + } + Component { + id: accountSettingsPageComponent + AccountSettingsPage { + onGoBack: closeContextualMenuComponent() + onAccountRemoved: { + closeContextualMenuComponent() + mainItem.accountRemoved() + } + } + } + Component { + id: settingsPageComponent + SettingsPage { + onGoBack: closeContextualMenuComponent() + } + } + Component { + id: helpPageComponent + HelpPage { + onGoBack: closeContextualMenuComponent() + } + } + Control.StackView { + id: mainStackView + property Transition noTransition: Transition { + PropertyAnimation { + property: "opacity" + from: 1 + to: 1 + duration: 0 + } + } + pushEnter: noTransition + pushExit: noTransition + popEnter: noTransition + popExit: noTransition + Layout.topMargin: 24 * DefaultStyle.dp + Layout.fillWidth: true + Layout.fillHeight: true + initialItem: mainStackLayoutComponent + } + } + } + } +}