From ab64d0479aa29f2bf260dda3c3d88933fcd5fc57 Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Wed, 31 Jul 2024 14:49:36 +0200 Subject: [PATCH] Keyboard shortcuts --- Linphone/data/image/switch-off.svg | 4 - Linphone/data/image/switch-on.svg | 4 - Linphone/view/App/CallsWindow.qml | 65 +- Linphone/view/App/Layout/LoginLayout.qml | 2 + Linphone/view/App/Layout/MainLayout.qml | 360 ++++-- Linphone/view/CMakeLists.txt | 1 - Linphone/view/Item/Button.qml | 24 +- Linphone/view/Item/Calendar.qml | 226 ++-- Linphone/view/Item/CalendarComboBox.qml | 6 +- Linphone/view/Item/Call/CallContactsLists.qml | 19 +- Linphone/view/Item/CheckBox.qml | 44 +- Linphone/view/Item/ComboBox.qml | 55 +- Linphone/view/Item/Contact/ContactEdition.qml | 114 +- Linphone/view/Item/Contact/ContactsList.qml | 39 +- Linphone/view/Item/Dialog.qml | 202 ++-- Linphone/view/Item/EffectImage.qml | 30 + Linphone/view/Item/Form/LoginForm.qml | 8 +- .../view/Item/Help/HelpIconLabelButton.qml | 19 + Linphone/view/Item/IconLabelButton.qml | 88 +- Linphone/view/Item/MasterDetailFamily.qml | 26 +- Linphone/view/Item/Meeting/MeetingList.qml | 9 +- Linphone/view/Item/Meeting/MeetingSetUp.qml | 151 +-- Linphone/view/Item/NumericPad.qml | 257 ++-- Linphone/view/Item/Popup.qml | 1 + Linphone/view/Item/PopupButton.qml | 40 +- Linphone/view/Item/RadioButton.qml | 47 +- Linphone/view/Item/SearchBar.qml | 15 +- Linphone/view/Item/Settings/SwitchSetting.qml | 2 +- Linphone/view/Item/Slider.qml | 58 +- Linphone/view/Item/Switch.qml | 60 +- Linphone/view/Item/SwitchButton.qml | 22 - Linphone/view/Item/TabBar.qml | 22 +- Linphone/view/Item/Text.qml | 4 +- Linphone/view/Item/TextArea.qml | 1 + Linphone/view/Item/TextField.qml | 8 +- Linphone/view/Item/VerticalTabBar.qml | 3 +- Linphone/view/Layout/FormItemLayout.qml | 69 +- .../Layout/Meeting/AddParticipantsLayout.qml | 281 +++-- Linphone/view/Page/Login/LoginPage.qml | 4 +- Linphone/view/Page/Login/RegisterPage.qml | 18 + Linphone/view/Page/Login/SIPLoginPage.qml | 6 +- Linphone/view/Page/Main/AbstractMainPage.qml | 4 +- .../Page/Main/AbstractMasterDetailPage.qml | 12 +- Linphone/view/Page/Main/CallPage.qml | 1066 +++++++++-------- Linphone/view/Page/Main/ContactPage.qml | 6 +- Linphone/view/Page/Main/MeetingPage.qml | 1048 ++++++++-------- 46 files changed, 2696 insertions(+), 1854 deletions(-) delete mode 100644 Linphone/data/image/switch-off.svg delete mode 100644 Linphone/data/image/switch-on.svg delete mode 100644 Linphone/view/Item/SwitchButton.qml diff --git a/Linphone/data/image/switch-off.svg b/Linphone/data/image/switch-off.svg deleted file mode 100644 index 154f9b9d4..000000000 --- a/Linphone/data/image/switch-off.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/Linphone/data/image/switch-on.svg b/Linphone/data/image/switch-on.svg deleted file mode 100644 index c24932e2a..000000000 --- a/Linphone/data/image/switch-on.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/Linphone/view/App/CallsWindow.qml b/Linphone/view/App/CallsWindow.qml index d4559b136..463dda462 100644 --- a/Linphone/view/App/CallsWindow.qml +++ b/Linphone/view/App/CallsWindow.qml @@ -280,9 +280,9 @@ AppWindow { id: callStatusText text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released) ? qsTr("End of the call") - : mainWindow.call && mainWindow.call.core.paused + : mainWindow.call && (mainWindow.call.core.paused || (mainWindow.callState === LinphoneEnums.CallState.Paused - || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) + || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote)) ? (mainWindow.conference ? qsTr('Réunion mise ') : qsTr('Appel mis')) + qsTr(" en pause") : mainWindow.conference ? mainWindow.conference.core.subject @@ -348,8 +348,9 @@ AppWindow { visible: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning imageSource: mainWindow.call ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp + ? AppIcons.lockSimple - : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp + : mainWindow.call && mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified ? AppIcons.warningCircle : AppIcons.lockKey @@ -500,6 +501,12 @@ AppWindow { id: contactsListPanel Item { Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Transfert d'appel") + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Escape) { + rightPanel.visible = false + event.accepted = true; + } + } CallContactsLists { id: callcontactslist anchors.fill: parent @@ -520,6 +527,12 @@ AppWindow { ColumnLayout { Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Dialer") spacing: 0 + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Escape) { + rightPanel.visible = false + event.accepted = true; + } + } Item { Layout.fillWidth: true Layout.fillHeight: true @@ -559,8 +572,14 @@ AppWindow { } Component { id: changeLayoutPanel - Item { + FocusScope { Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Modifier la disposition") + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Escape) { + rightPanel.visible = false + event.accepted = true; + } + } ColumnLayout { anchors.fill: parent anchors.topMargin: 16 * DefaultStyle.dp @@ -631,6 +650,12 @@ AppWindow { rightPanel.headerTitleText = qsTr("Liste d'appel") rightPanel.customHeaderButtons = mergeCallPopupButton.createObject(rightPanel) } + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Escape) { + rightPanel.visible = false + event.accepted = true; + } + } spacing: 0 Component { id: mergeCallPopupButton @@ -725,6 +750,10 @@ AppWindow { popup.contentItem: ColumnLayout { spacing: 0 Button { + id: pausingButton + onClicked: modelData.core.lSetPaused(!modelData.core.paused) + KeyNavigation.up: endCallButton + KeyNavigation.down: endCallButton background: Item {} contentItem: RowLayout { spacing: 5 * DefaultStyle.dp @@ -743,16 +772,18 @@ AppWindow { || modelData.core.state === LinphoneEnums.CallState.PausedByRemote ? qsTr("Reprendre l'appel") : qsTr("Mettre en pause") color: DefaultStyle.main2_500main + font.bold: pausingButton.shadowEnabled } Item { Layout.fillWidth: true } } - onClicked: { - modelData.core.lSetPaused(!modelData.core.paused) - } } Button { + id: endCallButton + onClicked: mainWindow.endCall(modelData) + KeyNavigation.up: pausingButton + KeyNavigation.down: pausingButton background: Item {} contentItem: RowLayout { spacing: 5 * DefaultStyle.dp @@ -765,12 +796,12 @@ AppWindow { Text { color: DefaultStyle.danger_500main text: qsTr("Terminer l'appel") + font.bold: endCallButton.shadowEnabled } Item { Layout.fillWidth: true } } - onClicked: mainWindow.endCall(modelData) } } } @@ -789,6 +820,12 @@ AppWindow { Control.StackView.onActivated: { rightPanel.headerTitleText = qsTr("Paramètres") } + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Escape) { + rightPanel.visible = false + event.accepted = true; + } + } InCallSettingsPanel { id: inSettingsPanel call: mainWindow.call @@ -804,6 +841,12 @@ AppWindow { id: screencastPanel Item { Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Partage de votre écran") + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Escape) { + rightPanel.visible = false + event.accepted = true; + } + } ScreencastPanel { anchors.fill: parent anchors.topMargin: 16 * DefaultStyle.dp @@ -817,6 +860,12 @@ AppWindow { Component { id: participantListPanel Item { + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Escape) { + rightPanel.visible = false + event.accepted = true; + } + } Control.StackView { id: participantsStack anchors.fill: parent diff --git a/Linphone/view/App/Layout/LoginLayout.qml b/Linphone/view/App/Layout/LoginLayout.qml index 4701b6844..07e83cc96 100644 --- a/Linphone/view/App/Layout/LoginLayout.qml +++ b/Linphone/view/App/Layout/LoginLayout.qml @@ -31,6 +31,7 @@ Rectangle { Layout.fillWidth: true } Button { + id: aboutButton Layout.alignment: Qt.AlignRight | Qt.AlignVCenter background: Item{} contentItem: RowLayout { @@ -45,6 +46,7 @@ Rectangle { Layout.alignment: Qt.AlignRight | Qt.AlignVCenter text: qsTr("À propos") font { + underline: aboutButton.underline pixelSize: 14 * DefaultStyle.dp weight: 400 * DefaultStyle.dp } diff --git a/Linphone/view/App/Layout/MainLayout.qml b/Linphone/view/App/Layout/MainLayout.qml index 74948cf19..120b886cb 100644 --- a/Linphone/view/App/Layout/MainLayout.qml +++ b/Linphone/view/App/Layout/MainLayout.qml @@ -119,6 +119,11 @@ Item { closeContextualMenuComponent() } } + Keys.onPressed: (event)=>{ + if(event.key == Qt.Key_Right){ + mainStackView.currentItem.forceActiveFocus() + } + } } ColumnLayout { spacing:0 @@ -138,6 +143,9 @@ Item { if (text.length != 0) listPopup.open() else listPopup.close() } + KeyNavigation.down: contactList.count > 0 ? contactList : contactList.footerItem + KeyNavigation.up: contactList.footerItem + component MagicSearchButton: Button { id: button width: 45 * DefaultStyle.dp @@ -159,7 +167,9 @@ Item { Popup { id: listPopup width: magicSearchBar.width - height: Math.min(magicSearchContent.contentHeight + topPadding + bottomPadding, 400 * DefaultStyle.dp) + property int maxHeight: 400 * DefaultStyle.dp + property bool displayScrollbar: contactList.contentHeight + topPadding + bottomPadding> maxHeight + height: Math.min(contactList.contentHeight + topPadding + bottomPadding, maxHeight) y: magicSearchBar.height // closePolicy: Popup.NoAutoClose topPadding: 20 * DefaultStyle.dp @@ -174,6 +184,9 @@ Item { 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 @@ -183,94 +196,139 @@ Item { shadowColor: DefaultStyle.grey_1000 shadowOpacity: 0.1 } - } - - contentItem: Control.ScrollView { - id: magicSearchContent - contentWidth: width - contentHeight: content.height - Control.ScrollBar.vertical: ScrollBar { + ScrollBar { id: scrollbar - policy: Control.ScrollBar.AsNeeded + Component.onCompleted: x = -10 * DefaultStyle.dp + policy: Control.ScrollBar.AsNeeded// Don't work as expected + visible: listPopup.displayScrollbar interactive: true - height: magicSearchContent.availableHeight - anchors.top: listPopup.top - anchors.bottom: listPopup.bottom + anchors.top: parent.top + anchors.bottom: parent.bottom anchors.right: parent.right + anchors.margins: 10 * DefaultStyle.dp + } - ColumnLayout { - id: content - spacing: 10 * DefaultStyle.dp - width: magicSearchContent.width - scrollbar.width - 5 * DefaultStyle.dp - Text { - visible: contactList.count > 0 - text: qsTr("Contact") - color: DefaultStyle.main2_500main - font { - pixelSize: 13 * DefaultStyle.dp - weight: 700 * DefaultStyle.dp + } + contentItem: ContactsList { + id: contactList + visible: magicSearchBar.text.length != 0 + Layout.preferredHeight: contentHeight + Layout.fillWidth: true + Layout.rightMargin: 5 * DefaultStyle.dp + initialHeadersVisible: false + contactMenuVisible: false + actionLayoutVisible: true + selectionEnabled: false + Control.ScrollBar.vertical: scrollbar + model: MagicSearchProxy { + searchText: magicSearchBar.text.length === 0 ? "*" : magicSearchBar.text + aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend + } + + Keys.onPressed: (event) => { + if(event.key == Qt.Key_Down){ + if(contactList.currentIndex == contactList.count -1) { + contactList.currentIndex = -1 + contactList.footerItem.forceActiveFocus() + event.accepted = true + } + } else if(event.key == Qt.Key_Up){ + if(contactList.currentIndex <= 0) { + contactList.currentIndex = -1 + contactList.footerItem.forceActiveFocus() + event.accepted = true } } - ContactsList { - id: contactList - visible: magicSearchBar.text.length != 0 - Layout.preferredHeight: contentHeight - Layout.fillWidth: true - Layout.rightMargin: 5 * DefaultStyle.dp - initialHeadersVisible: false - contactMenuVisible: false - actionLayoutVisible: true - selectionEnabled: false - Control.ScrollBar.vertical.visible: false - model: MagicSearchProxy { - searchText: magicSearchBar.text.length === 0 ? "*" : magicSearchBar.text - aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend - } + } + header: Text { + visible: contactList.count > 0 + text: qsTr("Contact") + color: DefaultStyle.main2_500main + font { + pixelSize: 13 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp } - Text { - text: qsTr("Suggestion") - color: DefaultStyle.main2_500main - font { - pixelSize: 13 * DefaultStyle.dp - weight: 700 * DefaultStyle.dp - } + } + footer: FocusScope{ + id: suggestionFocusScope + width: contactList.width + height: content.implicitHeight + onActiveFocusChanged: if(activeFocus) contactList.positionViewAtEnd() + Rectangle{ + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: suggestionRow.implicitHeight + color: suggestionFocusScope.activeFocus ? DefaultStyle.numericPadPressedButtonColor : 'transparent' } - RowLayout { - Layout.fillWidth: true - Layout.rightMargin: 5 * DefaultStyle.dp - spacing: 10 * DefaultStyle.dp - Avatar { - Layout.preferredWidth: 45 * DefaultStyle.dp - Layout.preferredHeight: 45 * DefaultStyle.dp - address: magicSearchBar.text + ColumnLayout { + id: content + anchors.fill: parent + anchors.rightMargin: 5 * DefaultStyle.dp + + spacing: 10 * DefaultStyle.dp + Text { + text: qsTr("Suggestion") + color: DefaultStyle.main2_500main + font { + pixelSize: 13 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } } - ColumnLayout { - Text { - text: magicSearchBar.text - font { - pixelSize: 12 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp + + Keys.onPressed: (event) => { + if(contactList.count <= 0) return; + if(event.key == Qt.Key_Down){ + contactList.currentIndex = 0 + event.accepted = true + } else if(event.key == Qt.Key_Up){ + contactList.currentIndex = contactList.count - 1 + event.accepted = true + } + } + RowLayout { + id: suggestionRow + spacing: 10 * DefaultStyle.dp + Avatar { + Layout.preferredWidth: 45 * DefaultStyle.dp + Layout.preferredHeight: 45 * DefaultStyle.dp + address: magicSearchBar.text + } + ColumnLayout { + Text { + text: magicSearchBar.text + font { + pixelSize: 12 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } } } - } - Item { - Layout.fillWidth: true - } - MagicSearchButton { - Layout.preferredWidth: 45 * DefaultStyle.dp - Layout.preferredHeight: 45 * DefaultStyle.dp - icon.source: AppIcons.phone - onClicked: { - UtilsCpp.createCall(magicSearchBar.text) - magicSearchBar.clearText() + Item { + Layout.fillWidth: true + } + MagicSearchButton { + id: callButton + Layout.preferredWidth: 45 * DefaultStyle.dp + Layout.preferredHeight: 45 * DefaultStyle.dp + icon.source: AppIcons.phone + focus: true + onClicked: { + UtilsCpp.createCall(magicSearchBar.text) + magicSearchBar.clearText() + } + KeyNavigation.right: chatButton + KeyNavigation.left: chatButton + } + MagicSearchButton { + id: chatButton + // TODO : visible true when chat available + // visible: false + Layout.preferredWidth: 45 * DefaultStyle.dp + Layout.preferredHeight: 45 * DefaultStyle.dp + icon.source: AppIcons.chatTeardropText + KeyNavigation.right: callButton + KeyNavigation.left: callButton } - } - MagicSearchButton { - // TODO : visible true when chat available - // visible: false - Layout.preferredWidth: 45 * DefaultStyle.dp - Layout.preferredHeight: 45 * DefaultStyle.dp - icon.source: AppIcons.chatTeardropText } } } @@ -281,7 +339,6 @@ Item { spacing: 10 * DefaultStyle.dp PopupButton { id: avatarButton - background.visible: false Layout.preferredWidth: 54 * DefaultStyle.dp Layout.preferredHeight: width popup.padding: 14 * DefaultStyle.dp @@ -300,57 +357,111 @@ Item { } } PopupButton { - id: settingsButton + id: settingsMenuButton Layout.preferredWidth: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp popup.width: 271 * DefaultStyle.dp popup.padding: 14 * DefaultStyle.dp - popup.contentItem: ColumnLayout { - spacing: 20 * DefaultStyle.dp - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - visible: !SettingsCpp.hideAccountSettings - iconSize: 32 * DefaultStyle.dp - text: qsTr("Mon compte") - iconSource: AppIcons.manageProfile - onClicked: openContextualMenuComponent(myAccountSettingsPageComponent) + popup.contentItem: FocusScope { + id: popupFocus + implicitHeight: settingsButtons.implicitHeight + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Left || event.key == Qt.Key_Escape) { + settingsMenuButton.popup.close() + event.accepted = true; + } } - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - visible: !SettingsCpp.hideSettings - iconSize: 32 * DefaultStyle.dp - text: qsTr("Paramètres") - iconSource: AppIcons.settings - onClicked: openContextualMenuComponent(settingsPageComponent) - } - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - visible: !SettingsCpp.disableCallRecordingsFeature - iconSize: 32 * DefaultStyle.dp - text: qsTr("Enregistrements") - iconSource: AppIcons.micro - } - IconLabelButton { - Layout.preferredHeight: 32 * DefaultStyle.dp - iconSize: 32 * DefaultStyle.dp - text: qsTr("Aide") - iconSource: AppIcons.question - onClicked: openContextualMenuComponent(helpPageComponent) - } - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 1 * DefaultStyle.dp - visible: addAccountButton.visible - color: DefaultStyle.main2_400 - } - IconLabelButton { - id: addAccountButton - Layout.preferredHeight: 32 * DefaultStyle.dp - visible: SettingsCpp.maxAccount == 0 || SettingsCpp.maxAccount > accountProxy.count - iconSize: 32 * DefaultStyle.dp - text: qsTr("Ajouter un compte") - iconSource: AppIcons.plusCircle - onClicked: mainItem.addAccountRequest() + ColumnLayout { + id: settingsButtons + anchors.fill: parent + spacing: 20 * DefaultStyle.dp + + function getPreviousItem(index){ + if(visibleChildren.length == 0) return null + --index + while(index >= 0){ + if( index!= 4 && children[index].visible) return children[index] + --index + } + return getPreviousItem(children.length) + } + function getNextItem(index){ + ++index + while(index < children.length){ + if( index!= 4 && children[index].visible) return children[index] + ++index + } + return getNextItem(-1) + } + + IconLabelButton { + id: accountButton + Layout.preferredHeight: 32 * DefaultStyle.dp + Layout.fillWidth: true + visible: !SettingsCpp.hideAccountSettings + focus: visible + iconSize: 32 * DefaultStyle.dp + text: qsTr("Mon compte") + iconSource: AppIcons.manageProfile + onClicked: openContextualMenuComponent(myAccountSettingsPageComponent) + KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(0) : null + KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(0) : null + } + IconLabelButton { + id: settingsButton + Layout.preferredHeight: 32 * DefaultStyle.dp + Layout.fillWidth: true + visible: !SettingsCpp.hideSettings + focus: !accountButton.visible && visible + iconSize: 32 * DefaultStyle.dp + text: qsTr("Paramètres") + iconSource: AppIcons.settings + onClicked: openContextualMenuComponent(settingsPageComponent) + KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(1) : null + KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(1) : null + } + IconLabelButton { + id: recordsButton + Layout.preferredHeight: 32 * DefaultStyle.dp + Layout.fillWidth: true + visible: !SettingsCpp.disableCallRecordingsFeature + focus: !accountButton.visible && !settingsButton.visible && visible + iconSize: 32 * DefaultStyle.dp + text: qsTr("Enregistrements") + iconSource: AppIcons.micro + KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(2) : null + KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(2) : null + } + IconLabelButton { + id: helpButton + Layout.preferredHeight: 32 * DefaultStyle.dp + Layout.fillWidth: true + iconSize: 32 * DefaultStyle.dp + focus: !accountButton.visible && !settingsButton.visible && !recordsButton.visible + text: qsTr("Aide") + iconSource: AppIcons.question + onClicked: openContextualMenuComponent(helpPageComponent) + KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(3) : null + KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(3) : null + } + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 * DefaultStyle.dp + visible: addAccountButton.visible + color: DefaultStyle.main2_400 + } + IconLabelButton { + id: addAccountButton + Layout.preferredHeight: 32 * DefaultStyle.dp + Layout.fillWidth: true + visible: SettingsCpp.maxAccount == 0 || SettingsCpp.maxAccount > accountProxy.count + iconSize: 32 * DefaultStyle.dp + text: qsTr("Ajouter un compte") + iconSource: AppIcons.plusCircle + onClicked: mainItem.addAccountRequest() + KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(5) : null + KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(5) : null + } } } } @@ -361,6 +472,7 @@ Item { StackLayout { id: mainStackLayout currentIndex: tabbar.currentIndex + onActiveFocusChanged: if(activeFocus) children[currentIndex].forceActiveFocus() CallPage { id: callPage Connections { diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index aefd210cf..cbc52a43e 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -62,7 +62,6 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Item/Carousel.qml view/Item/CheckableButton.qml view/Item/CheckBox.qml - view/Item/SwitchButton.qml view/Item/ComboBox.qml view/Item/DesktopPopup.qml view/Item/Dialog.qml diff --git a/Linphone/view/Item/Button.qml b/Linphone/view/Item/Button.qml index 29d75040a..c2dd35949 100644 --- a/Linphone/view/Item/Button.qml +++ b/Linphone/view/Item/Button.qml @@ -1,5 +1,5 @@ -import QtQuick 2.7 -import QtQuick.Controls.Basic 2.2 as Control +import QtQuick +import QtQuick.Controls.Basic as Control import QtQuick.Effects import QtQuick.Layouts import Linphone @@ -16,17 +16,19 @@ Control.Button { property int textWeight: 600 * DefaultStyle.dp property int radius: 48 * DefaultStyle.dp property color textColor: DefaultStyle.grey_0 - property bool underline: false - property bool shadowEnabled: false + property bool underline: mainItem.activeFocus || containsMouse + property bool shadowEnabled: mainItem.activeFocus || containsMouse property var contentImageColor + property alias containsMouse: mouseArea.containsMouse hoverEnabled: true - + activeFocusOnTab: true // leftPadding: 20 * DefaultStyle.dp // rightPadding: 20 * DefaultStyle.dp // topPadding: 11 * DefaultStyle.dp // bottomPadding: 11 * DefaultStyle.dp MouseArea { + id: mouseArea anchors.fill: parent hoverEnabled: true cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor @@ -39,10 +41,10 @@ Control.Button { id: buttonBackground color: mainItem.enabled ? inversedColors - ? mainItem.pressed + ? mainItem.pressed || mainItem.shadowEnabled ? DefaultStyle.grey_100 : mainItem.borderColor - : mainItem.pressed + : mainItem.pressed || mainItem.shadowEnabled ? mainItem.pressedColor : mainItem.color : mainItem.disabledColor @@ -59,10 +61,12 @@ Control.Button { enabled: mainItem.shadowEnabled anchors.fill: buttonBackground source: buttonBackground - shadowEnabled: mainItem.shadowEnabled + visible: mainItem.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730 + shadowEnabled: true //mainItem.shadowEnabled shadowColor: DefaultStyle.grey_1000 shadowBlur: 1 - shadowOpacity: 0.1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 } } @@ -83,6 +87,7 @@ Control.Button { family: DefaultStyle.defaultFont capitalization: mainItem.capitalization underline: mainItem.underline + bold: mainItem.font.bold } } @@ -93,6 +98,7 @@ Control.Button { imageWidth: mainItem.icon.width imageHeight: mainItem.icon.height colorizationColor: mainItem.contentImageColor + shadowEnabled: mainItem.shadowEnabled } contentItem: StackLayout { diff --git a/Linphone/view/Item/Calendar.qml b/Linphone/view/Item/Calendar.qml index 7202b9e73..47e9598b7 100644 --- a/Linphone/view/Item/Calendar.qml +++ b/Linphone/view/Item/Calendar.qml @@ -1,5 +1,5 @@ -import QtQuick 2.7 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Layouts import QtQuick.Controls as Control import QtQuick.Effects @@ -23,6 +23,8 @@ ListView { property int currentYear: calendarModel.yearAt(currentIndex) onCurrentYearChanged: console.log("currentyear", currentYear) onCurrentMonthChanged: console.log("current month", currentMonth) + currentIndex: 0 + keyNavigationEnabled: false model: Control.CalendarModel { id: calendarModel @@ -30,104 +32,156 @@ ListView { to: UtilsCpp.addYears(new Date(), 5) } - delegate: ColumnLayout { + delegate: FocusScope{ width: mainItem.width height: mainItem.height - property int currentMonth: model.month - spacing: 18 * DefaultStyle.dp - RowLayout { - Layout.fillWidth: true - spacing: 38 * DefaultStyle.dp - Text { - text: UtilsCpp.toDateMonthAndYearString(new Date(model.year, model.month, 15))// 15 because of timezones that can change the date for localeString - font { - pixelSize: 14 * DefaultStyle.dp - weight: 700 * DefaultStyle.dp - capitalization: Font.Capitalize - } - } - Item { - Layout.fillWidth: true - } - Button { - Layout.preferredWidth: 20 * DefaultStyle.dp - Layout.preferredHeight: 20 * DefaultStyle.dp - icon.width: width - icon.height: height - background: Item{} - icon.source: AppIcons.leftArrow - onClicked: if (mainItem.currentIndex > 0) mainItem.currentIndex = mainItem.currentIndex - 1 - } - Button { - Layout.preferredWidth: 20 * DefaultStyle.dp - Layout.preferredHeight: 20 * DefaultStyle.dp - icon.width: width - icon.height: height - background: Item{} - icon.source: AppIcons.rightArrow - onClicked: if (mainItem.currentIndex < mainItem.count) mainItem.currentIndex = mainItem.currentIndex + 1 - } - } - + property bool isCurrentIndex: index == mainItem.currentIndex + onIsCurrentIndexChanged: if( isCurrentIndex) monthGrid.forceActiveFocus() ColumnLayout { - spacing: 12 * DefaultStyle.dp - Control.DayOfWeekRow { - locale: monthGrid.locale - Layout.column: 1 + anchors.fill: parent + property int currentMonth: model.month + spacing: 18 * DefaultStyle.dp + RowLayout { Layout.fillWidth: true - delegate: Text { - text: model.shortName - color: DefaultStyle.main2_400 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + spacing: 38 * DefaultStyle.dp + Text { + text: UtilsCpp.toDateMonthAndYearString(new Date(model.year, model.month, 15))// 15 because of timezones that can change the date for localeString font { - pixelSize: 12 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp + pixelSize: 14 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + capitalization: Font.Capitalize } } + Item { + Layout.fillWidth: true + } + Button { + id: previousButton + Layout.preferredWidth: 20 * DefaultStyle.dp + Layout.preferredHeight: 20 * DefaultStyle.dp + icon.width: width + icon.height: height + background: Item{} + icon.source: AppIcons.leftArrow + onClicked: if (mainItem.currentIndex > 0) mainItem.currentIndex = mainItem.currentIndex - 1 + } + Button { + id: nextButton + Layout.preferredWidth: 20 * DefaultStyle.dp + Layout.preferredHeight: 20 * DefaultStyle.dp + icon.width: width + icon.height: height + background: Item{} + icon.source: AppIcons.rightArrow + onClicked: if (mainItem.currentIndex < mainItem.count) mainItem.currentIndex = mainItem.currentIndex + 1 + } } - - Control.MonthGrid { - id: monthGrid - Layout.fillWidth: true - Layout.fillHeight: true - year: model.year - month: model.month - property var curDate: model.date - onMonthChanged: console.log("cur date changed", month) - locale: Qt.locale(ConstantsCpp.DefaultLocale) - delegate: Item { - property bool isSelectedDay: mainItem.selectedDate ? UtilsCpp.datesAreEqual(mainItem.selectedDate, model.date) : false - // width: 30 * DefaultStyle.dp - // height: 30 * DefaultStyle.dp - Rectangle { - anchors.centerIn: parent - width: 30 * DefaultStyle.dp - height: 30 * DefaultStyle.dp - radius: 50 * DefaultStyle.dp - color: isSelectedDay ? DefaultStyle.main1_500_main : "transparent" - } - Text { - anchors.centerIn: parent - text: UtilsCpp.toDateDayString(model.date) - color: isSelectedDay - ? DefaultStyle.grey_0 - : UtilsCpp.isCurrentDay(model.date) - ? DefaultStyle.main1_500_main - : UtilsCpp.dateisInMonth(model.date, mainItem.currentMonth, mainItem.currentYear) - ? DefaultStyle.main2_700 - : DefaultStyle.main2_400 + + ColumnLayout { + spacing: 12 * DefaultStyle.dp + Control.DayOfWeekRow { + locale: monthGrid.locale + Layout.column: 1 + Layout.fillWidth: true + delegate: Text { + text: model.shortName + color: DefaultStyle.main2_400 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter font { pixelSize: 12 * DefaultStyle.dp weight: 300 * DefaultStyle.dp } } } - onClicked: (date) => { - if (UtilsCpp.isBeforeToday(date)) return; - mainItem.selectedDate = date + + Control.MonthGrid { + id: monthGrid + Layout.fillWidth: true + Layout.fillHeight: true + year: model.year + month: model.month + property var curDate: model.date + onMonthChanged: { + console.log("cur date changed", month) + } + locale: Qt.locale(ConstantsCpp.DefaultLocale) + delegate: FocusScope { + id: focusDay + property bool isSelectedDay: mainItem.selectedDate ? UtilsCpp.datesAreEqual(mainItem.selectedDate, model.date) : false + property var d: model.date + objectName: 'focusDay' + // width: 30 * DefaultStyle.dp + // height: 30 * DefaultStyle.dp + activeFocusOnTab: true + focus: index == 0 + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + monthGrid.clicked(model.date) + event.accepted = true; + }else if(event.key == Qt.Key_Left){ + var previous = nextItemInFocusChain(false) + if( previous.objectName != 'focusDay'){ + previousButton.clicked(undefined) + }else{ + previous.forceActiveFocus() + } + }else if(event.key == Qt.Key_Right){ + var next = nextItemInFocusChain() + console.log(next.objectName) + if( next.objectName != 'focusDay'){ + nextButton.clicked(undefined) + } else { + next.forceActiveFocus() + + } + } + } + + MouseArea{ + id: hoveringArea + anchors.fill: parent + hoverEnabled: true + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + acceptedButtons: Qt.LeftButton + onPressed: (event) =>{ + focusDay.forceActiveFocus() + event.accepted = false + } + } + + Rectangle { + anchors.centerIn: parent + width: 30 * DefaultStyle.dp + height: 30 * DefaultStyle.dp + radius: 50 * DefaultStyle.dp + color: isSelectedDay ? DefaultStyle.main1_500_main : "transparent" + border.color: DefaultStyle.main1_500_main_darker + border.width: focusDay.activeFocus || hoveringArea.containsMouse ? 1 : 0 + + } + Text { + anchors.centerIn: parent + text: UtilsCpp.toDateDayString(model.date) + color: isSelectedDay + ? DefaultStyle.grey_0 + : UtilsCpp.isCurrentDay(model.date) + ? DefaultStyle.main1_500_main + : UtilsCpp.dateisInMonth(model.date, mainItem.currentMonth, mainItem.currentYear) + ? DefaultStyle.main2_700 + : DefaultStyle.main2_400 + font { + pixelSize: 12 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + } + } + onClicked: (date) => { + if (UtilsCpp.isBeforeToday(date)) return; + mainItem.selectedDate = date + } } - } + } } } -} \ No newline at end of file +} diff --git a/Linphone/view/Item/CalendarComboBox.qml b/Linphone/view/Item/CalendarComboBox.qml index 5b2768f27..38755d82d 100644 --- a/Linphone/view/Item/CalendarComboBox.qml +++ b/Linphone/view/Item/CalendarComboBox.qml @@ -22,6 +22,7 @@ ComboBox { } } popup: Control.Popup { + id: popupItem y: mainItem.height width: 321 * DefaultStyle.dp height: 270 * DefaultStyle.dp @@ -30,6 +31,7 @@ ComboBox { bottomPadding: 24 * DefaultStyle.dp leftPadding: 21 * DefaultStyle.dp rightPadding: 19 * DefaultStyle.dp + onOpened: calendar.forceActiveFocus() background: Item { anchors.fill: parent Rectangle { @@ -37,6 +39,8 @@ ComboBox { anchors.fill: parent color: DefaultStyle.grey_0 radius: 16 * DefaultStyle.dp + border.color: DefaultStyle.main1_500_main + border.width: calendar.activeFocus? 1 : 0 } MultiEffect { anchors.fill: calendarBg @@ -50,4 +54,4 @@ ComboBox { id: calendar } } -} \ No newline at end of file +} diff --git a/Linphone/view/Item/Call/CallContactsLists.qml b/Linphone/view/Item/Call/CallContactsLists.qml index 708077c08..1a89d3e26 100644 --- a/Linphone/view/Item/Call/CallContactsLists.qml +++ b/Linphone/view/Item/Call/CallContactsLists.qml @@ -7,16 +7,18 @@ import Linphone import UtilsCpp import SettingsCpp -Item { +FocusScope { id: mainItem property bool groupCallVisible property color searchBarColor: DefaultStyle.grey_100 property color searchBarBorderColor: "transparent" property alias searchBar: searchBar - signal callButtonPressed(string address) - signal groupCallCreationRequested() property FriendGui selectedContact property NumericPad numPad + signal callButtonPressed(string address) + signal callSelectedContact() + signal groupCallCreationRequested() + clip: true Control.Control { @@ -33,10 +35,12 @@ Item { Layout.alignment: Qt.AlignTop Layout.fillWidth: true Layout.maximumWidth: mainItem.width + focus: true color: mainItem.searchBarColor borderColor: mainItem.searchBarBorderColor placeholderText: qsTr("Rechercher un contact") numericPad: mainItem.numPad + KeyNavigation.down: grouCallButton } Control.ScrollView { Layout.fillWidth: true @@ -60,9 +64,13 @@ Item { width: parent.width spacing: 32 * DefaultStyle.dp Button { + id: grouCallButton visible: mainItem.groupCallVisible && !SettingsCpp.disableMeetingsFeature Layout.preferredWidth: 320 * DefaultStyle.dp padding: 0 + KeyNavigation.up: searchBar + KeyNavigation.down: contactList.count >0 ? contactList : searchList + onClicked: mainItem.groupCallCreationRequested() background: Rectangle { gradient: Gradient { orientation: Gradient.Horizontal @@ -87,6 +95,7 @@ Item { font { pixelSize: 16 * DefaultStyle.dp weight: 800 * DefaultStyle.dp + underline: grouCallButton.shadowEnabled } } Item { @@ -98,7 +107,6 @@ Item { Layout.preferredHeight: 24 * DefaultStyle.dp } } - onClicked: mainItem.groupCallCreationRequested() } ColumnLayout { spacing: 18 * DefaultStyle.dp @@ -120,6 +128,7 @@ Item { searchText: searchBar.text.length === 0 ? "*" : searchBar.text } onSelectedContactChanged: mainItem.selectedContact = selectedContact + onClicked: mainItem.callSelectedContact() } } ColumnLayout { @@ -132,6 +141,7 @@ Item { } } ContactsList{ + id: searchList contactMenuVisible: false Layout.fillWidth: true Layout.fillHeight: true @@ -145,6 +155,7 @@ Item { aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend } onSelectedContactChanged: mainItem.selectedContact = selectedContact + onClicked: mainItem.callSelectedContact() } } Item { diff --git a/Linphone/view/Item/CheckBox.qml b/Linphone/view/Item/CheckBox.qml index 835752bf4..4155c8a66 100644 --- a/Linphone/view/Item/CheckBox.qml +++ b/Linphone/view/Item/CheckBox.qml @@ -1,24 +1,40 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 as Control +import QtQuick +import QtQuick.Controls as Control import Linphone - +import QtQuick.Effects + Control.CheckBox { id: mainItem - - indicator: Rectangle { + property bool shadowEnabled: mainItem.activeFocus || mainItem.hovered + indicator: Item{ implicitWidth: 20 * DefaultStyle.dp implicitHeight: 20 * DefaultStyle.dp x: (parent.width - width) / 2 y: (parent.height - height) / 2 - radius: 3 * DefaultStyle.dp - border.color: DefaultStyle.main1_500_main - border.width: 2.2 * DefaultStyle.dp - // color: mainItem.checked ? DefaultStyle.main1_500_main : "transparent" - EffectImage { - visible: mainItem.checked - imageSource: AppIcons.check - colorizationColor: DefaultStyle.main1_500_main - anchors.fill: parent + Rectangle { + id: backgroundArea + anchors.fill: parent + radius: 3 * DefaultStyle.dp + border.color: DefaultStyle.main1_500_main + border.width: 2.2 * DefaultStyle.dp + // color: mainItem.checked ? DefaultStyle.main1_500_main : "transparent" + EffectImage { + visible: mainItem.checked + imageSource: AppIcons.check + colorizationColor: DefaultStyle.main1_500_main + anchors.fill: parent + } + } + MultiEffect { + enabled: mainItem.shadowEnabled + anchors.fill: backgroundArea + source: backgroundArea + visible: mainItem.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730 + shadowEnabled: true //mainItem.shadowEnabled + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 } } } diff --git a/Linphone/view/Item/ComboBox.qml b/Linphone/view/Item/ComboBox.qml index 8d568634e..34548d83c 100644 --- a/Linphone/view/Item/ComboBox.qml +++ b/Linphone/view/Item/ComboBox.qml @@ -17,6 +17,7 @@ Control.ComboBox { property int weight: 400 * DefaultStyle.dp property int leftMargin: 10 * DefaultStyle.dp property bool oneLine: false + property bool shadowEnabled: mainItem.activeFocus || mainItem.hovered onConstantImageSourceChanged: if (constantImageSource) selectedItemImg.source = constantImageSource onCurrentIndexChanged: { @@ -33,12 +34,37 @@ Control.ComboBox { ? item.img : "" } + + Keys.onPressed: (event)=>{ + if(!mainItem.contentItem.activeFocus && (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return)){ + mainItem.popup.open() + event.accepted = true + } + } - background: Rectangle { - anchors.fill: mainItem - radius: 63 * DefaultStyle.dp - color: mainItem.enabled ? DefaultStyle.grey_100 : DefaultStyle.grey_200 - border.color: mainItem.enabled ? DefaultStyle.grey_200 : DefaultStyle.grey_400 + background: Item{ + Rectangle { + id: buttonBackground + anchors.fill: parent + radius: 63 * DefaultStyle.dp + color: mainItem.enabled ? DefaultStyle.grey_100 : DefaultStyle.grey_200 + border.color: mainItem.enabled + ? mainItem.activeFocus + ? DefaultStyle.main1_500_main + : DefaultStyle.grey_200 + : DefaultStyle.grey_400 + } + 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.5 + shadowOpacity: mainItem.shadowEnabled ? 0.1 : 0.0 + } } contentItem: Item { anchors.fill: parent @@ -105,8 +131,12 @@ Control.ComboBox { width: mainItem.width implicitHeight: contentItem.implicitHeight padding: 1 * DefaultStyle.dp - height: Math.min(listView.contentHeight, 300) + //height: Math.min(implicitHeight, 300) + onOpened: { + listView.positionViewAtIndex(listView.currentIndex, ListView.Center) + listView.forceActiveFocus() + } contentItem: ListView { id: listView clip: true @@ -123,6 +153,14 @@ Control.ComboBox { radius: 15 * DefaultStyle.dp y: listView.currentItem? listView.currentItem.y : 0 } + + Keys.onPressed: (event)=>{ + if(event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return){ + event.accepted = true + mainItem.currentIndex = listView.currentIndex + popup.close() + } + } delegate: Item { width:mainItem.width @@ -163,6 +201,7 @@ Control.ComboBox { } MouseArea { + id: mouseArea anchors.fill: parent hoverEnabled: true Rectangle { @@ -182,9 +221,7 @@ Control.ComboBox { Control.ScrollIndicator.vertical: Control.ScrollIndicator { } } - onOpened: { - listView.positionViewAtIndex(listView.currentIndex, ListView.Center) - } + background: Item { implicitWidth: mainItem.width diff --git a/Linphone/view/Item/Contact/ContactEdition.qml b/Linphone/view/Item/Contact/ContactEdition.qml index 6f278d3c5..3a12c9520 100644 --- a/Linphone/view/Item/Contact/ContactEdition.qml +++ b/Linphone/view/Item/Contact/ContactEdition.qml @@ -66,7 +66,7 @@ RightPanelLayout { content: ColumnLayout { anchors.fill: parent - spacing: 63 * DefaultStyle.dp + spacing : 0 ColumnLayout { spacing: 8 * DefaultStyle.dp Layout.alignment: Qt.AlignHCenter @@ -78,23 +78,27 @@ RightPanelLayout { Layout.alignment: Qt.AlignHCenter } IconLabelButton { + id: addPictureButton visible: !mainItem.contact || mainItem.contact.core.pictureUri.length === 0 Layout.preferredWidth: width Layout.preferredHeight: 17 * DefaultStyle.dp iconSource: AppIcons.camera iconSize: 17 * DefaultStyle.dp text: qsTr("Ajouter une image") + KeyNavigation.down: editButton.visible ? editButton : givenNameEdit onClicked: fileDialog.open() } RowLayout { visible: mainItem.contact && mainItem.contact.core.pictureUri.length != 0 Layout.alignment: Qt.AlignHCenter IconLabelButton { + id: editButton Layout.preferredWidth: width Layout.preferredHeight: 17 * DefaultStyle.dp iconSource: AppIcons.pencil iconSize: 17 * DefaultStyle.dp text: qsTr("Modifier") + KeyNavigation.down: givenNameEdit onClicked: fileDialog.open() } FileDialog { @@ -109,11 +113,13 @@ RightPanelLayout { } } IconLabelButton { + id: removeButton Layout.preferredHeight: 17 * DefaultStyle.dp Layout.preferredWidth: width iconSize: 17 * DefaultStyle.dp iconSource: AppIcons.trashCan text: qsTr("Supprimer") + KeyNavigation.down: givenNameEdit onClicked: mainItem.contact.core.pictureUri = "" } } @@ -122,8 +128,8 @@ RightPanelLayout { Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 50 * DefaultStyle.dp - Layout.bottomMargin: 50 * DefaultStyle.dp + Layout.topMargin: 63 * DefaultStyle.dp + Layout.bottomMargin: 78 * DefaultStyle.dp spacing: 100 * DefaultStyle.dp Flickable { Layout.preferredWidth: contentWidth @@ -146,30 +152,49 @@ RightPanelLayout { onTextEdited: contact.core.givenName = text backgroundColor: DefaultStyle.grey_0 backgroundBorderColor: givenName.errorTextItem.opacity != 0 ? DefaultStyle.danger_500main : DefaultStyle.grey_200 + KeyNavigation.up: editButton.visible ? editButton : addPictureButton + KeyNavigation.down: nameTextField } } FormItemLayout { label: qsTr("Nom") contentItem: TextField { + id: nameTextField initialText: contact.core.familyName onTextEdited: contact.core.familyName = text backgroundColor: DefaultStyle.grey_0 + KeyNavigation.up: givenNameEdit + KeyNavigation.down: companyTextField } } FormItemLayout { label: qsTr("Entreprise") contentItem: TextField { + id: companyTextField initialText: contact.core.organization onTextEdited: contact.core.organization = text backgroundColor: DefaultStyle.grey_0 + KeyNavigation.up: nameTextField + KeyNavigation.down: jobTextField } } FormItemLayout { label: qsTr("Fonction") contentItem: TextField { + id: jobTextField initialText: contact.core.job onTextEdited: contact.core.job = text backgroundColor: DefaultStyle.grey_0 + KeyNavigation.up: companyTextField + Keys.onPressed: (event) => { + if(event.key == Qt.Key_Down){ + if(addressesList.count > 0) + addressesList.itemAt(0).forceActiveFocus() + else + newAddressTextField.forceActiveFocus() + event.accepted = true + } + } } } Item{Layout.fillHeight: true} @@ -218,8 +243,25 @@ RightPanelLayout { delegate: FormItemLayout { label: modelData.label contentItem: RowLayout { + id: addressLayout spacing: 10 * DefaultStyle.dp + function updateFocus(event){ + if(event.key == Qt.Key_Up){ + if(index - 1 >=0 ) + addressesList.itemAt(index - 1).forceActiveFocus() + else + jobTextField.forceActiveFocus() + event.accepted = true + }else if(event.key == Qt.Key_Down){ + if(index + 1 < addressesList.count) + addressesList.itemAt(index+1).forceActiveFocus() + else + newAddressTextField.forceActiveFocus() + event.accepted = true + } + } TextField { + id: addressTextField onTextEdited: { if (text.length != 0) mainItem.contact.core.setAddressAt(index, qsTr("Adresse SIP"), text) } @@ -228,8 +270,12 @@ RightPanelLayout { backgroundColor: DefaultStyle.grey_0 Layout.preferredWidth: width Layout.preferredHeight: height + focus: true + KeyNavigation.right: removeAddressButton + Keys.onPressed: (event) => addressLayout.updateFocus(event) } Button { + id: removeAddressButton Layout.preferredWidth: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp Layout.alignment: Qt.AlignVCenter @@ -239,6 +285,8 @@ RightPanelLayout { height: 24 * DefaultStyle.dp icon.width: 24 * DefaultStyle.dp icon.height: 24 * DefaultStyle.dp + KeyNavigation.left: addressTextField + Keys.onPressed: (event) => addressLayout.updateFocus(event) onClicked: mainItem.contact.core.removeAddress(index) } } @@ -250,12 +298,28 @@ RightPanelLayout { FormItemLayout { label: qsTr("Adresse SIP") contentItem: TextField { + id: newAddressTextField backgroundColor: DefaultStyle.grey_0 - Component.onCompleted: text = "sip:" + Keys.onPressed: (event) => { + if(event.key == Qt.Key_Up){ + if(addressesList.count > 0 ) + addressesList.itemAt(addressesList.count - 1).forceActiveFocus() + else + jobTextField.forceActiveFocus() + event.accepted = true + }else if(event.key == Qt.Key_Down){ + if(phoneNumberList.count > 0) + phoneNumberList.itemAt(0).forceActiveFocus() + else + phoneNumberInputTextField.forceActiveFocus() + event.accepted = true + } + } onEditingFinished: { if (text.length != 0) mainItem.contact.core.appendAddress(text) text = "sip:" } + Component.onCompleted: text = "sip:" } } Item { @@ -272,8 +336,25 @@ RightPanelLayout { delegate: FormItemLayout { label: modelData.label contentItem: RowLayout { + id: phoneNumberLayout spacing: 10 * DefaultStyle.dp + function updateFocus(event){ + if(event.key == Qt.Key_Up){ + if(index - 1 >=0 ) + phoneNumberList.itemAt(index - 1).forceActiveFocus() + else + newAddressTextField.forceActiveFocus() + event.accepted = true + }else if(event.key == Qt.Key_Down){ + if(index + 1 < phoneNumberList.count) + addressesList.phoneNumberList(index+1).forceActiveFocus() + else + phoneNumberInputTextField.forceActiveFocus() + event.accepted = true + } + } TextField { + id: phoneTextField initialText: modelData.address onTextEdited: { if (text.length != 0) mainItem.contact.core.setPhoneNumberAt(index, qsTr("Téléphone"), text) @@ -281,8 +362,12 @@ RightPanelLayout { backgroundColor: DefaultStyle.grey_0 Layout.preferredWidth: width Layout.preferredHeight: height + focus: true + KeyNavigation.right: removePhoneButton + Keys.onPressed: (event) => phoneNumberLayout.updateFocus(event) } Button { + id: removePhoneButton Layout.preferredWidth: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp Layout.alignment: Qt.AlignVCenter @@ -292,6 +377,8 @@ RightPanelLayout { height: 24 * DefaultStyle.dp icon.width: 24 * DefaultStyle.dp icon.height: 24 * DefaultStyle.dp + KeyNavigation.left: phoneTextField + Keys.onPressed: (event) => phoneNumberLayout.updateFocus(event) onClicked: mainItem.contact.core.removePhoneNumber(index) } } @@ -304,7 +391,23 @@ RightPanelLayout { id: phoneNumberInput label: qsTr("Phone") contentItem: TextField { + id: phoneNumberInputTextField backgroundColor: DefaultStyle.grey_0 + Keys.onPressed: (event) => { + if(event.key == Qt.Key_Up){ + if(phoneNumberList.count > 0 ) + phoneNumberList.itemAt(phoneNumberList.count - 1).forceActiveFocus() + else + newAddressTextField.forceActiveFocus() + event.accepted = true + }else if(event.key == Qt.Key_Down){ + if(saveButton.enabled) + saveButton.forceActiveFocus() + else + givenNameEdit.forceActiveFocus() + event.accepted = true + } + } onEditingFinished: { if (text.length != 0) mainItem.contact.core.appendPhoneNumber(phoneNumberInput.label, text) text = "" @@ -328,6 +431,7 @@ RightPanelLayout { } Button { + id: saveButton Layout.bottomMargin: 100 * DefaultStyle.dp Layout.preferredWidth: 165 * DefaultStyle.dp Layout.alignment: Qt.AlignHCenter @@ -337,6 +441,8 @@ RightPanelLayout { rightPadding: 20 * DefaultStyle.dp topPadding: 11 * DefaultStyle.dp bottomPadding: 11 * DefaultStyle.dp + KeyNavigation.up: phoneNumberInputTextField + KeyNavigation.down: givenNameEdit onClicked: { if (givenNameEdit.text.length === 0 || (addressesList.count === 0 && phoneNumberList.count === 0)) { if (givenNameEdit.text.length === 0) givenName.errorMessage = qsTr("Veuillez saisir un prénom") diff --git a/Linphone/view/Item/Contact/ContactsList.qml b/Linphone/view/Item/Contact/ContactsList.qml index 7d3b6cba1..ad5795ec9 100644 --- a/Linphone/view/Item/Contact/ContactsList.qml +++ b/Linphone/view/Item/Contact/ContactsList.qml @@ -11,6 +11,7 @@ ListView { height: contentHeight visible: contentHeight > 0 clip: true + //keyNavigationWraps: true // rightMargin: 5 * DefaultStyle.dp property string searchBarText @@ -47,6 +48,7 @@ ListView { signal contactStarredChanged() signal contactDeletionRequested(FriendGui contact) signal contactAddedToSelection() + signal clicked() function selectContact(address) { var index = magicSearchProxy.findFriendIndexByAddress(address) @@ -69,9 +71,11 @@ ListView { selectedContacts.splice(indexInSelection, 1) } } - - - + onActiveFocusChanged: if(activeFocus && (!footerItem || !footerItem.activeFocus)) { + currentIndex = 0 + }else { + currentIndex = -1 + } model: MagicSearchProxy { id: magicSearchProxy searchText: searchBarText.length === 0 ? "*" : searchBarText @@ -88,8 +92,12 @@ ListView { // anchors.bottom: parent.bottom // anchors.right: parent.right } - - delegate: Item { + Keys.onPressed: (event)=>{ + if(event.key == Qt.Key_Tab && !mainItem.itemAtIndex(mainItem.currentIndex).activeFocus){ + mainItem.itemAtIndex(mainItem.currentIndex).forceActiveFocus() + } + } + delegate: FocusScope { id: itemDelegate height: display ? 56 * DefaultStyle.dp : 0 width: mainItem.width @@ -163,14 +171,17 @@ ListView { anchors.verticalCenter: parent.verticalCenter spacing: 10 * DefaultStyle.dp // TODO : change when mockup ready RowLayout{ + id: actionButtons visible: mainItem.actionLayoutVisible spacing: 10 * DefaultStyle.dp Button { + 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 contentImageColor: DefaultStyle.main2_500main background: Rectangle { anchors.fill: parent @@ -178,19 +189,25 @@ ListView { color: DefaultStyle.main2_200 } onClicked: UtilsCpp.createCall(modelData.core.defaultAddress) + KeyNavigation.right: chatButton + KeyNavigation.left: chatButton } Button { + id: chatButton 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 contentImageColor: DefaultStyle.main2_500main background: Rectangle { anchors.fill: parent radius: 40 * DefaultStyle.dp color: DefaultStyle.main2_200 } + KeyNavigation.right: callButton + KeyNavigation.left: callButton } } PopupButton { @@ -268,14 +285,21 @@ ListView { height: mainItem.height acceptedButtons: Qt.AllButtons z: -1 + focus: !actionButtons.visible Rectangle { anchors.fill: contactArea opacity: 0.7 color: DefaultStyle.main2_100 - visible: contactArea.containsMouse || friendPopup.hovered || (!mainItem.multiSelectionEnabled && mainItem.currentIndex === index) + visible: contactArea.containsMouse || friendPopup.hovered || mainItem.currentIndex === index + } + 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) => { - if (mouse.button == Qt.RightButton) { + if (mouse && mouse.button == Qt.RightButton) { friendPopup.open() } else { mainItem.currentIndex = -1 @@ -289,6 +313,7 @@ ListView { mainItem.removeContactFromSelection(indexInSelection, 1) } } + mainItem.clicked() } } } diff --git a/Linphone/view/Item/Dialog.qml b/Linphone/view/Item/Dialog.qml index ba68b6ff6..6eb0cd3d7 100644 --- a/Linphone/view/Item/Dialog.qml +++ b/Linphone/view/Item/Dialog.qml @@ -27,7 +27,7 @@ Popup { signal accepted() signal rejected() - + background: Item { anchors.fill: parent Rectangle { @@ -58,101 +58,121 @@ Popup { } } - contentItem: ColumnLayout { - spacing: 20 * DefaultStyle.dp - Text{ - id: titleText - Layout.fillWidth: true - visible: text.length != 0 - text: mainItem.title - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp + contentItem: FocusScope{ + height: contentLayout.implicitHeight + width: contentLayout.implicitWidth + onVisibleChanged: { + if(visible) forceActiveFocus() + } + Keys.onPressed: (event) => { + if(visible && event.key == Qt.Key_Escape){ + mainItem.close() + event.accepted = true } - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignLeft } - Rectangle{ - Layout.fillWidth: true - Layout.preferredHeight: 1 - color: DefaultStyle.main2_400 - visible: titleText.visible - } - - Text { - id: defaultText - visible: text.length != 0 - Layout.fillWidth: true - //Layout.preferredWidth: 278 * DefaultStyle.dp - Layout.alignment: Qt.AlignCenter - text: mainItem.text - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } - wrapMode: Text.Wrap - horizontalAlignment: titleText.visible ? Text.AlignLeft : Text.AlignHCenter - } - Text { - id: detailsText - visible: text.length != 0 - Layout.fillWidth: true - //Layout.preferredWidth: 278 * DefaultStyle.dp - Layout.alignment: Qt.AlignCenter - text: mainItem.details - font { - pixelSize: 13 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - italic: true - } - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - } - ColumnLayout { - id: contentLayout - Layout.fillWidth: true - Layout.fillHeight: true - Layout.alignment: Qt.AlignHCenter - } - - RowLayout { - id: buttonsLayout - Layout.alignment: Qt.AlignBottom | ( titleText.visible ? Qt.AlignRight : Qt.AlignHCenter) - spacing: 10 * DefaultStyle.dp - - // Default buttons only visible if no other children - // have been set - Button { - id:firstButtonId - visible: mainItem.buttons.length === 2 - text: qsTr("Oui") - leftPadding: 20 * DefaultStyle.dp - rightPadding: 20 * DefaultStyle.dp - topPadding: 11 * DefaultStyle.dp - bottomPadding: 11 * DefaultStyle.dp - onClicked: { - if(firstButtonAccept) - mainItem.accepted() - else - mainItem.rejected() - mainItem.close() + anchors.fill: parent + spacing: 20 * DefaultStyle.dp + Text{ + id: titleText + Layout.fillWidth: true + visible: text.length != 0 + text: mainItem.title + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp } + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignLeft } - Button { - id: secondButtonId - visible: mainItem.buttons.length === 2 - text: qsTr("Non") - leftPadding: 20 * DefaultStyle.dp - rightPadding: 20 * DefaultStyle.dp - topPadding: 11 * DefaultStyle.dp - bottomPadding: 11 * DefaultStyle.dp - onClicked: { - if(secondButtonAccept) - mainItem.accepted() - else - mainItem.rejected() - mainItem.close() + Rectangle{ + Layout.fillWidth: true + Layout.preferredHeight: 1 + color: DefaultStyle.main2_400 + visible: titleText.visible + } + + Text { + id: defaultText + visible: text.length != 0 + Layout.fillWidth: true + //Layout.preferredWidth: 278 * DefaultStyle.dp + Layout.alignment: Qt.AlignCenter + text: mainItem.text + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + wrapMode: Text.Wrap + horizontalAlignment: titleText.visible ? Text.AlignLeft : Text.AlignHCenter + } + Text { + id: detailsText + visible: text.length != 0 + Layout.fillWidth: true + //Layout.preferredWidth: 278 * DefaultStyle.dp + Layout.alignment: Qt.AlignCenter + text: mainItem.details + font { + pixelSize: 13 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + italic: true + } + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + } + + ColumnLayout { + id: contentLayout + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + } + + RowLayout { + id: buttonsLayout + Layout.alignment: Qt.AlignBottom | ( titleText.visible ? Qt.AlignRight : Qt.AlignHCenter) + spacing: 10 * DefaultStyle.dp + + // Default buttons only visible if no other children + // have been set + Button { + id:firstButtonId + visible: mainItem.buttons.length === 2 + text: qsTr("Oui") + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + topPadding: 11 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + focus: !firstButtonAccept + onClicked: { + if(firstButtonAccept) + mainItem.accepted() + else + mainItem.rejected() + mainItem.close() + } + KeyNavigation.left: secondButtonId + KeyNavigation.right: secondButtonId + } + Button { + id: secondButtonId + visible: mainItem.buttons.length === 2 + text: qsTr("Non") + leftPadding: 20 * DefaultStyle.dp + rightPadding: 20 * DefaultStyle.dp + topPadding: 11 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + focus: !secondButtonAccept + onClicked: { + if(secondButtonAccept) + mainItem.accepted() + else + mainItem.rejected() + mainItem.close() + } + KeyNavigation.left: firstButtonId + KeyNavigation.right: firstButtonId } } } diff --git a/Linphone/view/Item/EffectImage.qml b/Linphone/view/Item/EffectImage.qml index ae5d18423..f657f29bb 100644 --- a/Linphone/view/Item/EffectImage.qml +++ b/Linphone/view/Item/EffectImage.qml @@ -16,6 +16,7 @@ Loader { property int imageWidth: width property int imageHeight: height property bool useColor: colorizationColor != undefined + property bool shadowEnabled: false sourceComponent: Item { Image { id: image @@ -49,5 +50,34 @@ Loader { colorizationColor: effectEnabled && mainItem.colorizationColor ? mainItem.colorizationColor : 'black' colorization: effectEnabled ? 1.0: 0.0 } + /* Alernative to shadow for no blackcolors + MultiEffect { + visible: mainItem.shadowEnabled + source: image + width: image.width + height: image.height + x: image.x + y: image.y + 6 + z: -1 + blurEnabled: true + blurMax: 12 + blur: 1.0 + contrast: -1.0 + brightness: 1.0 + colorizationColor: DefaultStyle.grey_400 + colorization: 1.0 + }*/ + MultiEffect { + id: shadow + enabled: mainItem.shadowEnabled + anchors.fill: image + source: image + visible: mainItem.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730? + shadowEnabled: true //mainItem.shadowEnabled + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 0 + shadowOpacity: mainItem.shadowEnabled ? 0.7 : 0.0 + } } } diff --git a/Linphone/view/Item/Form/LoginForm.qml b/Linphone/view/Item/Form/LoginForm.qml index ab6d641b4..be1cd6b1d 100644 --- a/Linphone/view/Item/Form/LoginForm.qml +++ b/Linphone/view/Item/Form/LoginForm.qml @@ -139,11 +139,13 @@ ColumnLayout { Shortcut { sequences: ["Return", "Enter"] - onActivated: connectionButton.trigger() + onActivated: if(passwordEdit.activeFocus) connectionButton.trigger() + else if( usernameEdit.activeFocus) passwordEdit.forceActiveFocus() } onPressed: connectionButton.trigger() } Button { + id: forgottenButton background: Item { visible: false } @@ -151,7 +153,7 @@ ColumnLayout { color: DefaultStyle.main2_500main text: qsTr("Mot de passe oublié ?") font{ - underline: true + underline: forgottenButton.underline pixelSize: 13 * DefaultStyle.dp weight: 600 * DefaultStyle.dp } @@ -160,4 +162,4 @@ ColumnLayout { } } -} \ No newline at end of file +} diff --git a/Linphone/view/Item/Help/HelpIconLabelButton.qml b/Linphone/view/Item/Help/HelpIconLabelButton.qml index 4b2e054cf..7755cde9d 100644 --- a/Linphone/view/Item/Help/HelpIconLabelButton.qml +++ b/Linphone/view/Item/Help/HelpIconLabelButton.qml @@ -9,10 +9,18 @@ MouseArea { property string title property string subTitle property int iconSize: 32 * DefaultStyle.dp + property bool shadowEnabled: containsMouse || activeFocus hoverEnabled: true width: content.implicitWidth height: content.implicitHeight cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + activeFocusOnTab: true + Keys.onPressed: (event) => { + if(event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return){ + mainItem.clicked(undefined) + event.accepted = true + } + } RowLayout { id: content anchors.verticalCenter: parent.verticalCenter @@ -48,4 +56,15 @@ MouseArea { } } } + MultiEffect { + enabled: mainItem.shadowEnabled + anchors.fill: content + source: content + visible: mainItem.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730 + shadowEnabled: true //mainItem.shadowEnabled + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 + } } diff --git a/Linphone/view/Item/IconLabelButton.qml b/Linphone/view/Item/IconLabelButton.qml index 345becda7..a6760cebb 100644 --- a/Linphone/view/Item/IconLabelButton.qml +++ b/Linphone/view/Item/IconLabelButton.qml @@ -1,9 +1,9 @@ -import QtQuick 2.15 +import QtQuick import QtQuick.Effects import QtQuick.Layouts import Linphone -MouseArea { +Item{ id: mainItem property string iconSource property string text @@ -11,28 +11,70 @@ MouseArea { property int iconSize: 17 * DefaultStyle.dp property int textSize: 14 * DefaultStyle.dp property int textWeight: 400 * DefaultStyle.dp - hoverEnabled: true - cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor - width: content.implicitWidth - RowLayout { - id: content - anchors.verticalCenter: parent.verticalCenter - EffectImage { - Layout.preferredWidth: mainItem.iconSize - Layout.preferredHeight: mainItem.iconSize - width: mainItem.iconSize - height: mainItem.iconSize - imageSource: mainItem.iconSource - colorizationColor: mainItem.color + property color backgroundColor: DefaultStyle.grey_0 + property color backgroundPressedColor: DefaultStyle.main2_100 + property int radius: 5 * DefaultStyle.dp + property bool shadowEnabled: mainItem.activeFocus// || containsMouse + property alias containsMouse: mouseArea.containsMouse + + signal clicked(var mouse) + + implicitWidth: content.implicitWidth + activeFocusOnTab: true + + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + mainItem.clicked(undefined) + event.accepted = true; } - Text { - width: implicitWidth - Layout.fillWidth: true - text: mainItem.text - color: mainItem.color - font { - pixelSize: mainItem.textSize - weight: mainItem.textWeight + } + Rectangle{ + anchors.fill: parent + id: buttonBackground + color: mainItem.shadowEnabled ? mainItem.backgroundPressedColor : mainItem.backgroundColor + radius: mainItem.radius + }/* + 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: 1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 + }*/ + + MouseArea { + id: mouseArea + anchors.verticalCenter: parent.verticalCenter + width: content.implicitWidth + height: mainItem.height + hoverEnabled: true + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + + onClicked: function(mouse){mainItem.clicked(mouse)} + RowLayout { + id: content + anchors.verticalCenter: parent.verticalCenter + EffectImage { + Layout.preferredWidth: mainItem.iconSize + Layout.preferredHeight: mainItem.iconSize + width: mainItem.iconSize + height: mainItem.iconSize + imageSource: mainItem.iconSource + colorizationColor: mainItem.color + } + Text { + width: implicitWidth + Layout.fillWidth: true + text: mainItem.text + color: mainItem.color + font { + pixelSize: mainItem.textSize + weight: mainItem.textWeight + } } } } diff --git a/Linphone/view/Item/MasterDetailFamily.qml b/Linphone/view/Item/MasterDetailFamily.qml index df27f8af7..7c97a4c7c 100644 --- a/Linphone/view/Item/MasterDetailFamily.qml +++ b/Linphone/view/Item/MasterDetailFamily.qml @@ -1,10 +1,10 @@ import QtQuick import QtQuick.Controls as Control -import QtQuick.Layouts 1.0 +import QtQuick.Layouts +import QtQuick.Effects import Linphone -Rectangle { - +Item { id: mainItem height: visible ? 50 * DefaultStyle.dp : 0 @@ -13,10 +13,17 @@ Rectangle { property string titleText property bool isSelected: false + property bool shadowEnabled: mainItem.activeFocus || mouseArea.containsMouse signal selected() + Keys.onPressed: (event)=>{ + if(event.key == Qt.Key_Space || event.key == Qt.Key_Return || event.key == Qt.Key_Enter){ + mainItem.selected() + } + } MouseArea { + id: mouseArea hoverEnabled: true anchors.fill: parent Rectangle { @@ -24,7 +31,7 @@ Rectangle { anchors.fill: parent color: DefaultStyle.main2_200 radius: 35 * DefaultStyle.dp - visible: parent.containsMouse || isSelected + visible: parent.containsMouse || isSelected || mainItem.shadowEnabled } Rectangle { id: backgroundRightFiller @@ -34,6 +41,17 @@ Rectangle { height: 50 * DefaultStyle.dp visible: parent.containsMouse || isSelected } + MultiEffect { + enabled: mainItem.shadowEnabled + anchors.fill: background + source: background + visible: mainItem.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730 + shadowEnabled: true //mainItem.shadowEnabled + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 + } onClicked: { mainItem.selected() } diff --git a/Linphone/view/Item/Meeting/MeetingList.qml b/Linphone/view/Item/Meeting/MeetingList.qml index 748e1881f..a40298f10 100644 --- a/Linphone/view/Item/Meeting/MeetingList.qml +++ b/Linphone/view/Item/Meeting/MeetingList.qml @@ -15,7 +15,7 @@ ListView { property bool hoverEnabled: true property var delegateButtons property ConferenceInfoGui selectedConference: model && currentIndex != -1 ? model.getAt(currentIndex) : null - + spacing: 8 * DefaultStyle.dp currentIndex: confInfoProxy.currentDateIndex @@ -60,7 +60,7 @@ ListView { property: '$sectionMonth' } - delegate: Item { + delegate: FocusScope { id: itemDelegate height: 63 * DefaultStyle.dp + topOffset width: mainItem.width @@ -75,6 +75,7 @@ ListView { property var haveModel: $modelData && $modelData.core.haveModel || false + RowLayout{ anchors.fill: parent anchors.topMargin:parent.topOffset @@ -138,13 +139,14 @@ ListView { anchors.fill: parent anchors.rightMargin: 5 // margin to avoid clipping shadows at right radius: 10 * DefaultStyle.dp - visible: itemDelegate.haveModel + visible: itemDelegate.haveModel || itemDelegate.activeFocus color: mainItem.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.grey_0 ColumnLayout { anchors.fill: parent anchors.left: parent.left anchors.leftMargin: 15 * DefaultStyle.dp spacing: 2 * DefaultStyle.dp + visible: itemDelegate.haveModel RowLayout { spacing: 8 * DefaultStyle.dp Image { @@ -200,6 +202,7 @@ ListView { onClicked: { mainItem.currentIndex = index mainItem.conferenceSelected($modelData) + itemDelegate.forceActiveFocus() } } } diff --git a/Linphone/view/Item/Meeting/MeetingSetUp.qml b/Linphone/view/Item/Meeting/MeetingSetUp.qml index 040e096cf..7033bf0fe 100644 --- a/Linphone/view/Item/Meeting/MeetingSetUp.qml +++ b/Linphone/view/Item/Meeting/MeetingSetUp.qml @@ -6,9 +6,8 @@ import Linphone import UtilsCpp import SettingsCpp -ColumnLayout { +FocusScope{ id: mainItem - spacing: 8 * DefaultStyle.dp property bool isCreation property ConferenceInfoGui conferenceInfoGui signal addParticipantsRequested() @@ -59,6 +58,7 @@ ColumnLayout { } } } + RowLayout { visible: mainItem.isCreation && !SettingsCpp.disableBroadcastFeature Layout.topMargin: 20 * DefaultStyle.dp @@ -100,8 +100,10 @@ ColumnLayout { pixelSize: 20 * DefaultStyle.dp weight: 800 * DefaultStyle.dp } - onActiveFocusChanged: if(activeFocus==true) selectAll() + focus: true + onActiveFocusChanged: if(activeFocus) selectAll() onEditingFinished: mainItem.conferenceInfoGui.core.subject = text + KeyNavigation.down: allDaySwitch } } } @@ -127,11 +129,13 @@ ColumnLayout { Switch { id: allDaySwitch readonly property bool isAllDay: position === 1 - Component.onCompleted: if (mainItem.conferenceInfoGui.core.isAllDayConf()) toggle + KeyNavigation.up: confTitle + KeyNavigation.down: startDate onPositionChanged: if (position === 1) { mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(startDate.selectedDate, 0, 0) mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(endDate.selectedDate, 23, 59) } + Component.onCompleted: if (mainItem.conferenceInfoGui.core.isAllDayConf()) toggle } }, RowLayout { @@ -143,6 +147,10 @@ ColumnLayout { contentText.font.weight: (isCreation ? 700 : 400) * DefaultStyle.dp Layout.preferredWidth: 200 * DefaultStyle.dp Layout.preferredHeight: 30 * DefaultStyle.dp + KeyNavigation.up: allDaySwitch + KeyNavigation.down: endDate + KeyNavigation.left: startHour + KeyNavigation.right: startHour onSelectedDateChanged: { if (!selectedDate || selectedDate == mainItem.conferenceInfoGui.core.dateTime) return mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(selectedDate, allDaySwitch.isAllDay ? 0 : startHour.selectedHour, allDaySwitch.isAllDay ? 0 : startHour.selectedMin) @@ -163,6 +171,10 @@ ColumnLayout { Layout.preferredHeight: 30 * DefaultStyle.dp background.visible: mainItem.isCreation contentText.font.weight: (isCreation ? 700 : 400) * DefaultStyle.dp + KeyNavigation.up: allDaySwitch + KeyNavigation.down: endDate + KeyNavigation.left: startDate + KeyNavigation.right: startDate onSelectedHourChanged: { mainItem.conferenceInfoGui.core.dateTime = selectedDateTime//UtilsCpp.createDateTime(startDate.selectedDate, selectedHour, selectedMin) endDate.calendar.selectedDate = UtilsCpp.addSecs(selectedDateTime, 3600) @@ -200,99 +212,6 @@ ColumnLayout { onSelectedMinChanged: mainItem.conferenceInfoGui.core.endDateTime = selectedDateTime//UtilsCpp.createDateTime(startDate.selectedDate, selectedHour, selectedMin) } }, - // RowLayout { - // EffectImage { - // imageSource: AppIcons.clock - // colorizationColor: DefaultStyle.main2_600 - // Layout.preferredWidth: 24 * DefaultStyle.dp - // Layout.preferredHeight: 24 * DefaultStyle.dp - // } - // CalendarComboBox { - // id: startDate - // Layout.fillWidth: true - // Layout.preferredHeight: 30 * DefaultStyle.dp - // background.visible: mainItem.isCreation - // contentText.font.weight: (mainItem.isCreation ? 700 : 400) * DefaultStyle.dp - // onSelectedDateChanged: { - // mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(selectedDate, allDaySwitch.position === 1 ? 0 : startHour.selectedHour, allDaySwitch.position === 1 ? 0 : startHour.selectedMin) - // if (allDaySwitch.position === 0) endDate.calendar.selectedDate = UtilsCpp.addSecs(selectedDate, 3600) - // } - // } - // }, - // RowLayout { - // Item { - // Layout.preferredWidth: 24 * DefaultStyle.dp - // Layout.preferredHeight: 24 * DefaultStyle.dp - // } - // RowLayout { - // visible: allDaySwitch.position === 0 - // TimeComboBox { - // id: startHour - // onSelectedHourChanged: { - // mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(startDate.selectedDate, selectedHour, selectedMin) - // endHour.selectedTimeString = Qt.formatDateTime(UtilsCpp.createDateTime(new Date(), selectedHour == 23 ? 23 : selectedHour + 1, selectedHour == 23 ? 59 : selectedMin), "hh:mm") - // } - // onSelectedMinChanged: { - // mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(startDate.selectedDate, selectedHour, selectedMin) - // endHour.selectedTimeString = Qt.formatDateTime(UtilsCpp.createDateTime(new Date(), selectedHour == 23 ? 23 : selectedHour + 1, selectedHour == 23 ? 59 : selectedMin), "hh:mm") - // } - // Layout.preferredWidth: 94 * DefaultStyle.dp - // Layout.preferredHeight: 30 * DefaultStyle.dp - // } - // TimeComboBox { - // id: endHour - // // property date startTime: new Date() - // onSelectedHourChanged: mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(endDate.selectedDate, selectedHour, selectedMin) - // onSelectedMinChanged: mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(endDate.selectedDate, selectedHour, selectedMin) - // Layout.preferredWidth: 94 * DefaultStyle.dp - // Layout.preferredHeight: 30 * DefaultStyle.dp - // } - // Item { - // Layout.fillWidth: true - // } - // Text { - // property int durationSec: UtilsCpp.secsTo(startHour.selectedTime, endHour.selectedTime) - // property int hour: durationSec/3600 - // property int min: (durationSec - hour*3600)/60 - // text: (hour > 0 ? hour + "h" : "") + (min > 0 ? min + "mn" : "") - // font { - // pixelSize: 14 * DefaultStyle.dp - // weight: 700 * DefaultStyle.dp - // } - // } - // } - // CalendarComboBox { - // id: endDate - // visible: allDaySwitch.position === 1 - // Layout.fillWidth: true - // // Layout.fillHeight: false - // contentText.font.weight: (mainItem.isCreation ? 700 : 400) * DefaultStyle.dp - // Layout.preferredHeight: 30 * DefaultStyle.dp - // onSelectedDateChanged: mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(selectedDate, allDaySwitch.position === 1 ? 23 : endHour.selectedHour, allDaySwitch.position === 1 ? 59 : endHour.selectedMin) - // } - // }, - // RowLayout { - // Item { - // Layout.preferredWidth: 24 * DefaultStyle.dp - // Layout.preferredHeight: 24 * DefaultStyle.dp - // } - // RowLayout { - // Switch { - // id: allDaySwitch - // text: qsTr("Toute la journée") - // onPositionChanged: { - // if (position == 1) { - // mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(startDate.selectedDate, 0, 0) - // mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(endDate.selectedDate, 23, 59) - // } else { - // mainItem.conferenceInfoGui.core.dateTime = UtilsCpp.createDateTime(startDate.selectedDate, startHour.selectedHour, startHour.selectedMin) - // mainItem.conferenceInfoGui.core.endDateTime = UtilsCpp.createDateTime(endDate.selectedDate, endHour.selectedHour, endHour.selectedMin) - // } - // } - // } - // } - // }, - ComboBox { id: timeZoneCbox @@ -316,33 +235,6 @@ ColumnLayout { mainItem.conferenceInfoGui.core.timeZoneModel = timeZoneCbox.model.data(modelIndex, Qt.DisplayRole + 1) } } - - // ComboBox { - // id: repeaterCbox - // enabled: false - // Component.onCompleted: console.log("TODO : handle conf repetition") - // constantImageSource: AppIcons.reloadArrow - // Layout.fillWidth: true - // Layout.preferredHeight: height - // height: 30 * DefaultStyle.dp - // width: 307 * DefaultStyle.dp - // weight: 700 * DefaultStyle.dp - // leftMargin: 0 - // currentIndex: 0 - // background: Rectangle { - // visible: parent.hovered || parent.down - // anchors.fill: parent - // color: DefaultStyle.grey_100 - // } - // model: [ - // {text: qsTr("Une fois")}, - // {text: qsTr("Tous les jours")}, - // {text: qsTr("Tous les jours de la semaine (Lun-Ven)")}, - // {text: qsTr("Toutes les semaines")}, - // {text: qsTr("Tous les mois")} - // ] - // } - ] } @@ -370,12 +262,19 @@ ColumnLayout { pixelSize: 14 * DefaultStyle.dp weight: 400 * DefaultStyle.dp } + onEditingFinished: mainItem.conferenceInfoGui.core.description = text + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Escape) { + text = mainItem.conferenceInfoGui.core.description + nextItemInFocusChain().forceActiveFocus() + event.accepted = true; + } + } background: Rectangle { anchors.fill: parent color: descriptionEdit.hovered || descriptionEdit.activeFocus ? DefaultStyle.grey_100 : "transparent" radius: 4 * DefaultStyle.dp } - onEditingFinished: mainItem.conferenceInfoGui.core.description = text } } } @@ -387,7 +286,7 @@ ColumnLayout { Layout.preferredHeight: 30 * DefaultStyle.dp background: Rectangle { anchors.fill: parent - color: addParticipantsButton.hovered ? DefaultStyle.grey_100 : "transparent" + color: addParticipantsButton.hovered || addParticipantsButton.activeFocus ? DefaultStyle.grey_100 : "transparent" radius: 4 * DefaultStyle.dp } contentItem: RowLayout { diff --git a/Linphone/view/Item/NumericPad.qml b/Linphone/view/Item/NumericPad.qml index 391e3c5c2..cf65cf349 100644 --- a/Linphone/view/Item/NumericPad.qml +++ b/Linphone/view/Item/NumericPad.qml @@ -1,5 +1,5 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 as Control +import QtQuick +import QtQuick.Controls as Control import QtQuick.Layouts as Layout import QtQuick.Effects import Linphone @@ -16,6 +16,7 @@ Control.Popup { rightPadding: 72 * DefaultStyle.dp topPadding: 41 * DefaultStyle.dp bottomPadding: 18 * DefaultStyle.dp + onOpened: numPad.forceActiveFocus() background: Item { anchors.fill: parent Rectangle { @@ -61,117 +62,169 @@ Control.Popup { onClicked: mainItem.close() } } - contentItem: Layout.GridLayout { - columns: 3 - columnSpacing: 40 * DefaultStyle.dp - rowSpacing: 10 * DefaultStyle.dp - Repeater { - model: 9 + contentItem: FocusScope{ + id: numPad + anchors.fill: parent + anchors.topMargin: 41 * DefaultStyle.dp + anchors.bottomMargin: 18 * DefaultStyle.dp + anchors.rightMargin: 72 * DefaultStyle.dp + anchors.leftMargin: 72 * DefaultStyle.dp + + Layout.GridLayout { + id: numPadGrid + anchors.fill: parent + columns: 3 + columnSpacing: 40 * DefaultStyle.dp + rowSpacing: 10 * DefaultStyle.dp + function getButtonAt(index){ + index = (index+15) % 15 + if(index >= 0){ + if( index < 9){ + return numPadRepeater.itemAt(index) + }else if( index < 12){ + return digitRepeater.itemAt(index-9) + }else if (index < 14){ + return launchCallButton + }else if( index < 15){ + return eraseButton + } + } + } + Repeater { + id: numPadRepeater + model: 9 + Button { + id: numPadButton + Layout.Layout.alignment: Qt.AlignHCenter + required property int index + implicitWidth: 60 * DefaultStyle.dp + implicitHeight: 60 * DefaultStyle.dp + focus: index == 4 + onClicked: { + mainItem.buttonPressed(innerText.text) + } + KeyNavigation.left: numPadGrid.getButtonAt(index - 1) + KeyNavigation.right: numPadGrid.getButtonAt(index + 1) + KeyNavigation.up: numPadGrid.getButtonAt(index - 3) + KeyNavigation.down: numPadGrid.getButtonAt(index + 3) + background: Rectangle { + anchors.fill: parent + color: numPadButton.down || numPadButton.shadowEnabled? DefaultStyle.numericPadPressedButtonColor : DefaultStyle.grey_0 + radius: 71 * DefaultStyle.dp + } + contentItem: Text { + id: innerText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.centerIn: parent + text: index + 1 + font { + pixelSize: 32 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + } + } + Repeater { + id: digitRepeater + model: [ + {pressText: "*"}, + {pressText: "0", longPressText: "+"}, + {pressText: "#"} + ] + Button { + id: digitButton + Layout.Layout.alignment: Qt.AlignHCenter + implicitWidth: 60 * DefaultStyle.dp + implicitHeight: 60 * DefaultStyle.dp + + onClicked: mainItem.buttonPressed(pressText.text) + onPressAndHold: mainItem.buttonPressed(longPressText.text) + + KeyNavigation.left: numPadGrid.getButtonAt((index - 1)+9) + KeyNavigation.right: numPadGrid.getButtonAt((index + 1)+9) + KeyNavigation.up: numPadGrid.getButtonAt((index - 3)+9) + KeyNavigation.down: numPadGrid.getButtonAt((index + 3)+9) + + background: Rectangle { + anchors.fill: parent + color: digitButton.down || digitButton.shadowEnabled? DefaultStyle.numericPadPressedButtonColor : DefaultStyle.grey_0 + radius: 71 * DefaultStyle.dp + } + contentItem: Item { + anchors.fill: parent + Text { + id: pressText + height: contentHeight + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + Component.onCompleted: {if (modelData.longPressText === undefined) anchors.centerIn= parent} + text: modelData.pressText + font.pixelSize: 32 * DefaultStyle.dp + } + Text { + id: longPressText + height: contentHeight + anchors.left: parent.left + anchors.right: parent.right + y: digitButton.height/2 + horizontalAlignment: Text.AlignHCenter + visible: modelData.longPressText ? modelData.longPressText.length > 0 : false + text: modelData.longPressText ? modelData.longPressText : "" + font.pixelSize: 22 * DefaultStyle.dp + } + } + } + } + Item { + // Invisible item to move the last two buttons to the right + } Button { - id: numPadButton + id: launchCallButton + implicitWidth: 75 * DefaultStyle.dp + implicitHeight: 55 * DefaultStyle.dp Layout.Layout.alignment: Qt.AlignHCenter - required property int index - implicitWidth: 60 * DefaultStyle.dp - implicitHeight: 60 * DefaultStyle.dp + icon.source: AppIcons.phone + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + contentImageColor: DefaultStyle.grey_0 + + onClicked: mainItem.launchCall() + + KeyNavigation.left: eraseButton + KeyNavigation.right: eraseButton + KeyNavigation.up: numPadGrid.getButtonAt(10) + KeyNavigation.down: numPadGrid.getButtonAt(1) + background: Rectangle { anchors.fill: parent - color: numPadButton.down ? DefaultStyle.numericPadPressedButtonColor : DefaultStyle.grey_0 + color: DefaultStyle.success_500main radius: 71 * DefaultStyle.dp } - contentItem: Text { - id: innerText - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - anchors.centerIn: parent - text: index + 1 - font { - pixelSize: 32 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } - } - onClicked: { - mainItem.buttonPressed(innerText.text) - } } - } - Repeater { - model: [ - {pressText: "*"}, - {pressText: "0", longPressText: "+"}, - {pressText: "#"} - ] Button { - id: digitButton + id: eraseButton + leftPadding: 5 * DefaultStyle.dp + rightPadding: 5 * DefaultStyle.dp + topPadding: 5 * DefaultStyle.dp + bottomPadding: 5 * DefaultStyle.dp Layout.Layout.alignment: Qt.AlignHCenter - shadowEnabled: true - implicitWidth: 60 * DefaultStyle.dp - implicitHeight: 60 * DefaultStyle.dp - - background: Rectangle { - anchors.fill: parent - color: digitButton.down ? DefaultStyle.numericPadPressedButtonColor : DefaultStyle.grey_0 - radius: 71 * DefaultStyle.dp + icon.source: AppIcons.backspaceFill + icon.width: 38 * DefaultStyle.dp + icon.height: 38 * DefaultStyle.dp + + onClicked: mainItem.wipe() + + KeyNavigation.left: launchCallButton + KeyNavigation.right: launchCallButton + KeyNavigation.up: numPadGrid.getButtonAt(11) + KeyNavigation.down: numPadGrid.getButtonAt(1) + + background: Item { + visible: false } - contentItem: Item { - anchors.fill: parent - Text { - id: pressText - height: contentHeight - anchors.left: parent.left - anchors.right: parent.right - horizontalAlignment: Text.AlignHCenter - Component.onCompleted: {if (modelData.longPressText === undefined) anchors.centerIn= parent} - text: modelData.pressText - font.pixelSize: 32 * DefaultStyle.dp - } - Text { - id: longPressText - height: contentHeight - anchors.left: parent.left - anchors.right: parent.right - y: digitButton.height/2 - horizontalAlignment: Text.AlignHCenter - visible: modelData.longPressText ? modelData.longPressText.length > 0 : false - text: modelData.longPressText ? modelData.longPressText : "" - font.pixelSize: 22 * DefaultStyle.dp - } - } - onClicked: mainItem.buttonPressed(pressText.text) - onPressAndHold: mainItem.buttonPressed(longPressText.text) } } - Item { - // Invisible item to move the last two buttons to the right - } - Button { - id: launchCallButton - implicitWidth: 75 * DefaultStyle.dp - implicitHeight: 55 * DefaultStyle.dp - Layout.Layout.alignment: Qt.AlignHCenter - background: Rectangle { - anchors.fill: parent - color: DefaultStyle.success_500main - radius: 71 * DefaultStyle.dp - } - icon.source: AppIcons.phone - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - contentImageColor: DefaultStyle.grey_0 - onClicked: mainItem.launchCall() - } - Button { - leftPadding: 5 * DefaultStyle.dp - rightPadding: 5 * DefaultStyle.dp - topPadding: 5 * DefaultStyle.dp - bottomPadding: 5 * DefaultStyle.dp - Layout.Layout.alignment: Qt.AlignHCenter - background: Item { - visible: false - } - icon.source: AppIcons.backspaceFill - icon.width: 38 * DefaultStyle.dp - icon.height: 38 * DefaultStyle.dp - onClicked: mainItem.wipe() - } } } diff --git a/Linphone/view/Item/Popup.qml b/Linphone/view/Item/Popup.qml index 71d36f635..85349fbab 100644 --- a/Linphone/view/Item/Popup.qml +++ b/Linphone/view/Item/Popup.qml @@ -9,6 +9,7 @@ Control.Popup{ property color underlineColor : DefaultStyle.main1_500_main property int radius: 16 * DefaultStyle.dp property bool hovered: mouseArea.containsMouse + background: Item{ Rectangle { visible: mainItem.underlineColor != undefined diff --git a/Linphone/view/Item/PopupButton.qml b/Linphone/view/Item/PopupButton.qml index 4db746961..dd30f822f 100644 --- a/Linphone/view/Item/PopupButton.qml +++ b/Linphone/view/Item/PopupButton.qml @@ -7,6 +7,8 @@ Button { id: mainItem property alias popup: popup property var contentImageColor + property bool shadowEnabled: mainItem.activeFocus || hovered + property alias popupBackgroundColor: popupBackground.color checked: popup.visible implicitWidth: 24 * DefaultStyle.dp implicitHeight: 24 * DefaultStyle.dp @@ -26,11 +28,32 @@ Button { popup.open() } - background: Rectangle { + Keys.onPressed: (event) => { + if(popup.checked && event.key == Qt.Key_Escape){ + mainItem.close() + event.accepted = true + } + } + background: Item { anchors.fill: mainItem - visible: mainItem.checked - color: DefaultStyle.main2_300 - radius: 40 * DefaultStyle.dp + Rectangle { + id: buttonBackground + anchors.fill: parent + visible: mainItem.checked || mainItem.shadowEnabled + color: mainItem.checked ? DefaultStyle.main2_300 : DefaultStyle.grey_100 + 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: 1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 + } } contentItem: EffectImage { imageSource: mainItem.icon.source @@ -46,7 +69,7 @@ Button { id: popup x: 0 y: mainItem.height - closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside + closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside | Popup.CloseOnEscape padding: 10 * DefaultStyle.dp parent: mainItem // Explicit define for coordinates references. @@ -64,19 +87,20 @@ Button { } else { x = 0 } + popup.contentItem.forceActiveFocus() } background: Item { anchors.fill: parent Rectangle { - id: callOptionsMenuPopup + id: popupBackground anchors.fill: parent color: DefaultStyle.grey_0 radius: 16 * DefaultStyle.dp } MultiEffect { - source: callOptionsMenuPopup - anchors.fill: callOptionsMenuPopup + source: popupBackground + anchors.fill: popupBackground shadowEnabled: true shadowBlur: 1 shadowColor: DefaultStyle.grey_900 diff --git a/Linphone/view/Item/RadioButton.qml b/Linphone/view/Item/RadioButton.qml index c49026b7d..4ea7ceafe 100644 --- a/Linphone/view/Item/RadioButton.qml +++ b/Linphone/view/Item/RadioButton.qml @@ -1,6 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 as Control +import QtQuick +import QtQuick.Controls as Control import QtQuick.Layouts +import QtQuick.Effects import Linphone Control.RadioButton { @@ -11,32 +12,48 @@ Control.RadioButton { property bool checkOnClick: true property color color property int indicatorSize: 16 * DefaultStyle.dp + property bool shadowEnabled: mainItem.activeFocus || mainItem.hovered //onClicked: if (checkOnClick && !mainItem.checked) mainItem.toggle() MouseArea{ + id: mouseArea anchors.fill:parent hoverEnabled: true acceptedButtons: Qt.NoButton cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor } - indicator: Rectangle { + indicator: Item{ implicitWidth: mainItem.indicatorSize implicitHeight: mainItem.indicatorSize - radius: implicitWidth/2 - color: "transparent" - border.color: mainItem.color - border.width: 2 * DefaultStyle.dp anchors.verticalCenter: mainItem.verticalCenter - Rectangle { - width: parent.width/2 - height: parent.height/2 - x: parent.width/4 - y: parent.width/4 - radius: width/2 - color: mainItem.color - visible: mainItem.checked + id: backgroundArea + anchors.fill: parent + radius: mainItem.indicatorSize/2 + color: "transparent" + border.color: mainItem.color + border.width: 2 * DefaultStyle.dp + Rectangle { + width: parent.width/2 + height: parent.height/2 + x: parent.width/4 + y: parent.width/4 + radius: width/2 + color: mainItem.color + visible: mainItem.checked + } + } + MultiEffect { + enabled: mainItem.shadowEnabled + anchors.fill: backgroundArea + source: backgroundArea + visible: mainItem.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730 + shadowEnabled: true //mainItem.shadowEnabled + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 } } } diff --git a/Linphone/view/Item/SearchBar.qml b/Linphone/view/Item/SearchBar.qml index 03e53fd60..7e1acbe71 100644 --- a/Linphone/view/Item/SearchBar.qml +++ b/Linphone/view/Item/SearchBar.qml @@ -4,7 +4,7 @@ import QtQuick.Layouts 1.0 import Linphone -Rectangle { +FocusScope { id: mainItem property string placeholderText: "" property color placeholderTextColor: DefaultStyle.main2_400 @@ -17,6 +17,7 @@ Rectangle { property Control.Popup numericPad property alias numericPadButton: dialerButton readonly property bool hasActiveFocus: textField.activeFocus + property alias color: backgroundItem.color onVisibleChanged: if (!visible && numericPad) numericPad.close() @@ -38,9 +39,14 @@ Rectangle { implicitWidth: mainItem.textInputWidth implicitHeight: 50 * DefaultStyle.dp - radius: 28 * DefaultStyle.dp - color: DefaultStyle.grey_100 - border.color: textField.activeFocus ? mainItem.focusedBorderColor : mainItem.borderColor + + Rectangle{ + id: backgroundItem + anchors.fill: parent + radius: 28 * DefaultStyle.dp + color: DefaultStyle.grey_100 + border.color: textField.activeFocus ? mainItem.focusedBorderColor : mainItem.borderColor + } Image { id: magnifier visible: mainItem.magnifierVisible @@ -57,6 +63,7 @@ Rectangle { anchors.leftMargin: magnifier.visible ? 0 : 10 * DefaultStyle.dp anchors.right: clearTextButton.left anchors.verticalCenter: parent.verticalCenter + focus: true placeholderText: mainItem.placeholderText placeholderTextColor: mainItem.placeholderTextColor width: mainItem.width - dialerButton.width diff --git a/Linphone/view/Item/Settings/SwitchSetting.qml b/Linphone/view/Item/Settings/SwitchSetting.qml index c85a913de..530d9bfd5 100644 --- a/Linphone/view/Item/Settings/SwitchSetting.qml +++ b/Linphone/view/Item/Settings/SwitchSetting.qml @@ -29,7 +29,7 @@ RowLayout { Layout.fillWidth: true } } - SwitchButton { + Switch { id: switchButton Layout.alignment: Qt.AlignRight | Qt.AlignVCenter checked: propertyOwner[mainItem.propertyName] diff --git a/Linphone/view/Item/Slider.qml b/Linphone/view/Item/Slider.qml index a1cb16dd6..730e23c25 100644 --- a/Linphone/view/Item/Slider.qml +++ b/Linphone/view/Item/Slider.qml @@ -6,28 +6,44 @@ import Linphone Control.Slider { id: mainItem - - background: Rectangle { - x: mainItem.leftPadding - y: mainItem.topPadding + mainItem.availableHeight / 2 - height / 2 - implicitWidth: 200 * DefaultStyle.dp - implicitHeight: 4 * DefaultStyle.dp - width: mainItem.availableWidth - height: implicitHeight - radius: 30 * DefaultStyle.dp - // TODO : change the colors when mockup indicates their names - color: DefaultStyle.grey_850 - - Rectangle { - width: mainItem.visualPosition * parent.width - height: parent.height - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { position: 0.0; color: "#FF9E79" } - GradientStop { position: 1.0; color: "#FE5E00" } + property bool shadowEnabled: mainItem.hovered || mainItem.activeFocus + hoverEnabled: true + background: Item{ + x: mainItem.leftPadding + y: mainItem.topPadding + mainItem.availableHeight / 2 - height / 2 + implicitWidth: 200 * DefaultStyle.dp + implicitHeight: 4 * DefaultStyle.dp + width: mainItem.availableWidth + height: implicitHeight + Rectangle { + id: sliderBackground + anchors.fill: parent + radius: 30 * DefaultStyle.dp + // TODO : change the colors when mockup indicates their names + color: DefaultStyle.grey_850 + + Rectangle { + width: mainItem.visualPosition * parent.width + height: parent.height + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { position: 0.0; color: "#FF9E79" } + GradientStop { position: 1.0; color: "#FE5E00" } + } + radius: 40 * DefaultStyle.dp } - radius: 40 * DefaultStyle.dp - } + } + MultiEffect { + enabled: mainItem.shadowEnabled + anchors.fill: sliderBackground + source: sliderBackground + visible: mainItem.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730 + shadowEnabled: true //mainItem.shadowEnabled + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 + } } handle: Item { diff --git a/Linphone/view/Item/Switch.qml b/Linphone/view/Item/Switch.qml index 0abda7a8b..08400fee0 100644 --- a/Linphone/view/Item/Switch.qml +++ b/Linphone/view/Item/Switch.qml @@ -1,34 +1,52 @@ -import QtQuick 2.12 +import QtQuick import QtQuick.Controls as Control +import QtQuick.Effects import Linphone Control.Switch { id: mainItem + property bool shadowEnabled: mainItem.hovered || mainItem.activeFocus + hoverEnabled: true font { pixelSize: 14 * DefaultStyle.dp weight: 400 * DefaultStyle.dp } - indicator: Rectangle { - implicitWidth: 32 * DefaultStyle.dp - implicitHeight: 20 * DefaultStyle.dp - x: mainItem.leftPadding - y: parent.height / 2 - height / 2 - radius: 10 * DefaultStyle.dp - color: mainItem.checked ? DefaultStyle.success_500main : DefaultStyle.main2_400 - - Rectangle { - anchors.verticalCenter: parent.verticalCenter - property int margin: 4 * DefaultStyle.dp - x: mainItem.checked ? parent.width - width - margin : margin - width: 12 * DefaultStyle.dp - height: 12 * DefaultStyle.dp - radius: 10 * DefaultStyle.dp - color: DefaultStyle.grey_0 - Behavior on x { - NumberAnimation{duration: 100} + indicator: Item{ + implicitWidth: 32 * DefaultStyle.dp + implicitHeight: 20 * DefaultStyle.dp + x: mainItem.leftPadding + y: parent.height / 2 - height / 2 + Rectangle { + id: indicatorBackground + anchors.fill: parent + radius: 10 * DefaultStyle.dp + color: mainItem.checked? DefaultStyle.success_500main : DefaultStyle.main2_400 + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + property int margin: 4 * DefaultStyle.dp + x: mainItem.checked ? parent.width - width - margin : margin + width: 12 * DefaultStyle.dp + height: 12 * DefaultStyle.dp + radius: 10 * DefaultStyle.dp + color: DefaultStyle.grey_0 + Behavior on x { + NumberAnimation{duration: 100} + } } - } + } + MultiEffect { + enabled: mainItem.shadowEnabled + anchors.fill: indicatorBackground + source: indicatorBackground + visible: mainItem.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730 + shadowEnabled: true //mainItem.shadowEnabled + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 1 + shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0 + } } contentItem: Text { @@ -38,4 +56,4 @@ Control.Switch { verticalAlignment: Text.AlignVCenter leftPadding: mainItem.indicator.width + mainItem.spacing } -} \ No newline at end of file +} diff --git a/Linphone/view/Item/SwitchButton.qml b/Linphone/view/Item/SwitchButton.qml deleted file mode 100644 index f27c05da9..000000000 --- a/Linphone/view/Item/SwitchButton.qml +++ /dev/null @@ -1,22 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 as Control -import Linphone - -Control.AbstractButton { - id: mainItem - checkable: true - width: 32 * DefaultStyle.dp - height: 20 * DefaultStyle.dp - EffectImage { - visible: mainItem.checked - imageSource: AppIcons.switchOn - //colorizationColor: DefaultStyle.success_500main - not working on this icon. - anchors.fill: parent - } - EffectImage { - visible: !mainItem.checked - imageSource: AppIcons.switchOff - //colorizationColor: DefaultStyle.main2_400 - not working on this icon. - anchors.fill: parent - } -} diff --git a/Linphone/view/Item/TabBar.qml b/Linphone/view/Item/TabBar.qml index 310a83d40..9dcb03039 100644 --- a/Linphone/view/Item/TabBar.qml +++ b/Linphone/view/Item/TabBar.qml @@ -1,6 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 as Control +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Control +import QtQuick.Effects import Linphone Control.TabBar { @@ -44,9 +45,12 @@ Control.TabBar { Repeater { model: mainItem.model Control.TabButton { + id: tabButton required property string modelData required property int index + property bool shadowEnabled: activeFocus || hovered width: implicitWidth + activeFocusOnTab: true hoverEnabled: true ToolTip { visible: tabText.truncated && hovered @@ -58,6 +62,7 @@ Control.TabBar { anchors.fill: parent Rectangle { + id: tabBackground visible: mainItem.currentIndex === index height: 5 * DefaultStyle.dp color: DefaultStyle.main1_500_main @@ -65,6 +70,17 @@ Control.TabBar { anchors.left: parent.left anchors.right: parent.right } + MultiEffect { + enabled: tabButton.shadowEnabled + anchors.fill: tabBackground + source: tabBackground + visible: tabButton.shadowEnabled + // Crash : https://bugreports.qt.io/browse/QTBUG-124730 + shadowEnabled: true //mainItem.shadowEnabled + shadowColor: DefaultStyle.grey_1000 + shadowBlur: 1 + shadowOpacity: tabButton.shadowEnabled ? 0.5 : 0.0 + } } contentItem: Text { diff --git a/Linphone/view/Item/Text.qml b/Linphone/view/Item/Text.qml index 69d41c785..82bbdae0e 100644 --- a/Linphone/view/Item/Text.qml +++ b/Linphone/view/Item/Text.qml @@ -1,4 +1,4 @@ -import QtQuick 2.7 as Quick +import QtQuick as Quick import QtQuick.Layouts import Linphone @@ -24,4 +24,4 @@ Quick.Text { text: mainItem.text font: mainItem.font } -} \ No newline at end of file +} diff --git a/Linphone/view/Item/TextArea.qml b/Linphone/view/Item/TextArea.qml index de6221137..0115afade 100644 --- a/Linphone/view/Item/TextArea.qml +++ b/Linphone/view/Item/TextArea.qml @@ -15,6 +15,7 @@ TextEdit { property bool hovered: mouseArea.hoverEnabled && mouseArea.containsMouse topPadding: 5 * DefaultStyle.dp bottomPadding: 5 * DefaultStyle.dp + activeFocusOnTab: true MouseArea { id: mouseArea diff --git a/Linphone/view/Item/TextField.qml b/Linphone/view/Item/TextField.qml index 3e8b2f986..ad12502fe 100644 --- a/Linphone/view/Item/TextField.qml +++ b/Linphone/view/Item/TextField.qml @@ -20,6 +20,7 @@ Control.TextField { weight: 400 * DefaultStyle.dp } selectByMouse: true + activeFocusOnTab: true property bool controlIsDown: false property bool hidden: false @@ -111,10 +112,9 @@ Control.TextField { icon.source: eyeButton.checked ? AppIcons.eyeShow : AppIcons.eyeHide width: 20 * DefaultStyle.dp height: 20 * DefaultStyle.dp - icon.width: 20 * DefaultStyle.dp - icon.height: 20 * DefaultStyle.dp - anchors.top: parent.top - anchors.bottom: parent.bottom + icon.width: width + icon.height: height + anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: rightMargin } diff --git a/Linphone/view/Item/VerticalTabBar.qml b/Linphone/view/Item/VerticalTabBar.qml index f9855d98e..201e4c0cf 100644 --- a/Linphone/view/Item/VerticalTabBar.qml +++ b/Linphone/view/Item/VerticalTabBar.qml @@ -107,7 +107,7 @@ Control.TabBar { Layout.preferredHeight: buttonSize Layout.alignment: Qt.AlignHCenter fillMode: Image.PreserveAspectFit - colorizationColor: DefaultStyle.grey_0 + colorizationColor: DefaultStyle.grey_0 } Text { id: buttonText @@ -115,6 +115,7 @@ Control.TabBar { font { weight: mainItem.currentIndex === index ? 800 * DefaultStyle.dp : 400 * DefaultStyle.dp pixelSize: 9 * DefaultStyle.dp + underline: tabButton.activeFocus || tabButton.hovered } color: DefaultStyle.grey_0 Layout.fillWidth: true diff --git a/Linphone/view/Layout/FormItemLayout.qml b/Linphone/view/Layout/FormItemLayout.qml index ce3383057..5c5ccb646 100644 --- a/Linphone/view/Layout/FormItemLayout.qml +++ b/Linphone/view/Layout/FormItemLayout.qml @@ -1,10 +1,10 @@ import QtQuick import QtQuick.Controls as Control -import QtQuick.Layouts 1.0 +import QtQuick.Layouts import QtQuick.Effects import Linphone -ColumnLayout { +FocusScope{ id: mainItem property alias contentItem: contentItem.data property string label: "" @@ -14,38 +14,43 @@ ColumnLayout { property alias errorMessage: errorText.text property bool enableErrorText: false property bool errorTextVisible: errorText.opacity > 0 - spacing: 5 * DefaultStyle.dp - - Text { - visible: label.length > 0 - verticalAlignment: Text.AlignVCenter - text: mainItem.label + (mainItem.mandatory ? "*" : "") - color: contentItem.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.main2_600 - elide: Text.ElideRight - wrapMode: Text.Wrap - maximumLineCount: 1 - textFormat: Text.RichText - - font { - pixelSize: 13 * DefaultStyle.dp - weight: 700 * DefaultStyle.dp + implicitHeight: layout.implicitHeight + implicitWidth: layout.implicitWidth + ColumnLayout { + id: layout + spacing: 5 * DefaultStyle.dp + + Text { + visible: label.length > 0 + verticalAlignment: Text.AlignVCenter + text: mainItem.label + (mainItem.mandatory ? "*" : "") + color: contentItem.activeFocus ? DefaultStyle.main1_500_main : DefaultStyle.main2_600 + elide: Text.ElideRight + wrapMode: Text.Wrap + maximumLineCount: 1 + textFormat: Text.RichText + + font { + pixelSize: 13 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } } - } - - Item { - Layout.preferredHeight: contentItem.height - Layout.preferredWidth: contentItem.width + Item { - id: contentItem - height: childrenRect.height - width: childrenRect.width - } - ErrorText { - id: errorText - anchors.top: contentItem.bottom - color: DefaultStyle.danger_500main - Layout.preferredWidth: implicitWidth + Layout.preferredHeight: contentItem.height + Layout.preferredWidth: contentItem.width + Item { + id: contentItem + height: childrenRect.height + width: childrenRect.width + } + ErrorText { + id: errorText + anchors.top: contentItem.bottom + color: DefaultStyle.danger_500main + Layout.preferredWidth: implicitWidth + } } + } - } diff --git a/Linphone/view/Layout/Meeting/AddParticipantsLayout.qml b/Linphone/view/Layout/Meeting/AddParticipantsLayout.qml index 4d8a71354..b50c72dde 100644 --- a/Linphone/view/Layout/Meeting/AddParticipantsLayout.qml +++ b/Linphone/view/Layout/Meeting/AddParticipantsLayout.qml @@ -6,9 +6,9 @@ import Linphone import UtilsCpp import SettingsCpp -ColumnLayout { +FocusScope{ id: mainItem - spacing: 15 * DefaultStyle.dp + property string placeHolderText: qsTr("Rechercher des contacts") property list selectedParticipants: contactList.selectedContacts property int selectedParticipantsCount: selectedParticipants.length @@ -24,141 +24,166 @@ ColumnLayout { } ColumnLayout { - visible: mainItem.nameGroupCall - spacing: 5 * DefaultStyle.dp - Layout.rightMargin: 38 * DefaultStyle.dp - RowLayout { - spacing: 0 - Text { - font.pixelSize: 13 * DefaultStyle.dp - font.weight: 700 * DefaultStyle.dp - text: qsTr("Nom du groupe") - } - Item{Layout.fillWidth: true} - Text { - font.pixelSize: 12 * DefaultStyle.dp - font.weight: 300 * DefaultStyle.dp - text: qsTr("Requis") - } - } - TextField { - id: groupCallName - Layout.fillWidth: true - Layout.preferredHeight: 49 * DefaultStyle.dp - } - } - ListView { - id: participantList - Layout.fillWidth: true - Layout.preferredHeight: contentHeight - Layout.maximumHeight: mainItem.height / 3 - width: mainItem.width - model: contactList.selectedContacts - clip: true - delegate: Item { - height: 56 * DefaultStyle.dp - width: participantList.width - scrollbar.implicitWidth - 12 * DefaultStyle.dp + anchors.fill: parent + spacing: 15 * DefaultStyle.dp + ColumnLayout { + visible: mainItem.nameGroupCall + spacing: 5 * DefaultStyle.dp + Layout.rightMargin: 38 * DefaultStyle.dp RowLayout { - anchors.fill: parent - spacing: 10 * DefaultStyle.dp - Avatar { - Layout.preferredWidth: 45 * DefaultStyle.dp - Layout.preferredHeight: 45 * DefaultStyle.dp - address: modelData - } + spacing: 0 Text { - property var nameObj: UtilsCpp.getDisplayName(modelData) - text: nameObj ? nameObj.value : "" - font.pixelSize: 14 * DefaultStyle.dp - font.capitalization: Font.Capitalize + font.pixelSize: 13 * DefaultStyle.dp + font.weight: 700 * DefaultStyle.dp + text: qsTr("Nom du groupe") } - Item { - Layout.fillWidth: true - } - Button { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - background: Item{} - icon.source: AppIcons.closeX - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - contentImageColor: DefaultStyle.main1_500_main - onClicked: contactList.selectedContacts.splice(index, 1) + Item{Layout.fillWidth: true} + Text { + font.pixelSize: 12 * DefaultStyle.dp + font.weight: 300 * DefaultStyle.dp + text: qsTr("Requis") } } - } - Control.ScrollBar.vertical: ScrollBar { - id: scrollbar - active: true - interactive: true - policy: Control.ScrollBar.AsNeeded - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.rightMargin: 8 * DefaultStyle.dp - } - } - SearchBar { - id: searchbar - Layout.fillWidth: true - Layout.topMargin: 6 * DefaultStyle.dp - Layout.rightMargin: 28 * DefaultStyle.dp - placeholderText: mainItem.placeHolderText - color: mainItem.searchBarColor - borderColor: mainItem.searchBarColor - } - Text { - Layout.topMargin: 6 * DefaultStyle.dp - text: qsTr("Contacts") - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - } - ContactsList { - id: contactList - visible: contentHeight > 0 || searchbar.text.length > 0 - Layout.fillWidth: true - Layout.fillHeight: true - Layout.topMargin: 8 * DefaultStyle.dp - Layout.rightMargin: 8 * DefaultStyle.dp - Layout.preferredHeight: contentHeight - multiSelectionEnabled: true - contactMenuVisible: false - confInfoGui: mainItem.conferenceInfoGui - searchBarText: searchbar.text - onContactAddedToSelection: participantList.positionViewAtEnd() - headerPositioning: ListView.InlineHeader - header: MouseArea { - onClicked: contactList.addContactToSelection(sipAddr.text) - visible: searchbar.text.length > 0 - height: searchbar.text.length > 0 ? 56 * DefaultStyle.dp : 0 - width: contactList.width - RowLayout { + TextField { + id: groupCallName Layout.fillWidth: true - spacing: 10 * DefaultStyle.dp - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: 30 * DefaultStyle.dp - anchors.left: parent.left - Avatar { - Layout.preferredWidth: 45 * DefaultStyle.dp - Layout.preferredHeight: 45 * DefaultStyle.dp - address: sipAddr.text - } - ColumnLayout { - spacing: 0 - Text { - id: sipAddr - property string _text: UtilsCpp.interpretUrl(searchbar.text) - text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_text) : _text - font.pixelSize: 14 * DefaultStyle.dp + Layout.preferredHeight: 49 * DefaultStyle.dp + focus: mainItem.nameGroupCall + KeyNavigation.down: participantList.count > 0 ? participantList : searchbar + Keys.onPressed: (event) => { + if(currentIndex <=0 && event.key == Qt.Key_Up){ + nextItemInFocusChain(false).forceActiveFocus() } } } } - - } - Item { - Layout.fillHeight: true + ListView { + id: participantList + Layout.fillWidth: true + Layout.preferredHeight: contentHeight + Layout.maximumHeight: mainItem.height / 3 + width: mainItem.width + model: contactList.selectedContacts + clip: true + focus: !groupCallName.visible && participantList.count > 0 + Keys.onPressed: (event) => { + if(currentIndex <=0 && event.key == Qt.Key_Up){ + nextItemInFocusChain(false).forceActiveFocus() + } + } + delegate: FocusScope { + height: 56 * DefaultStyle.dp + width: participantList.width - scrollbar.implicitWidth - 12 * DefaultStyle.dp + RowLayout { + anchors.fill: parent + spacing: 10 * DefaultStyle.dp + Avatar { + Layout.preferredWidth: 45 * DefaultStyle.dp + Layout.preferredHeight: 45 * DefaultStyle.dp + address: modelData + } + Text { + property var nameObj: UtilsCpp.getDisplayName(modelData) + text: nameObj ? nameObj.value : "" + font.pixelSize: 14 * DefaultStyle.dp + font.capitalization: Font.Capitalize + } + Item { + Layout.fillWidth: true + } + Button { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + background: Item{} + icon.source: AppIcons.closeX + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + focus: true + contentImageColor: DefaultStyle.main1_500_main + onClicked: contactList.selectedContacts.splice(index, 1) + } + } + } + Control.ScrollBar.vertical: ScrollBar { + id: scrollbar + active: true + interactive: true + policy: Control.ScrollBar.AsNeeded + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.rightMargin: 8 * DefaultStyle.dp + } + } + SearchBar { + id: searchbar + Layout.fillWidth: true + Layout.topMargin: 6 * DefaultStyle.dp + Layout.rightMargin: 28 * DefaultStyle.dp + placeholderText: mainItem.placeHolderText + focus: !groupCallName.visible && participantList.count == 0 + color: mainItem.searchBarColor + borderColor: mainItem.searchBarColor + KeyNavigation.up: participantList.count > 0 + ? participantList + : groupCallName.visible + ? groupCallName + : nextItemInFocusChain(false) + KeyNavigation.down: contactList + } + Text { + Layout.topMargin: 6 * DefaultStyle.dp + text: qsTr("Contacts") + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + ContactsList { + id: contactList + visible: contentHeight > 0 || searchbar.text.length > 0 + Layout.fillWidth: true + Layout.fillHeight: true + Layout.topMargin: 8 * DefaultStyle.dp + Layout.rightMargin: 8 * DefaultStyle.dp + Layout.preferredHeight: contentHeight + multiSelectionEnabled: true + contactMenuVisible: false + confInfoGui: mainItem.conferenceInfoGui + searchBarText: searchbar.text + onContactAddedToSelection: participantList.positionViewAtEnd() + headerPositioning: ListView.InlineHeader + header: MouseArea { + onClicked: contactList.addContactToSelection(sipAddr.text) + visible: searchbar.text.length > 0 + height: searchbar.text.length > 0 ? 56 * DefaultStyle.dp : 0 + width: contactList.width + RowLayout { + Layout.fillWidth: true + spacing: 10 * DefaultStyle.dp + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 30 * DefaultStyle.dp + anchors.left: parent.left + Avatar { + Layout.preferredWidth: 45 * DefaultStyle.dp + Layout.preferredHeight: 45 * DefaultStyle.dp + address: sipAddr.text + } + ColumnLayout { + spacing: 0 + Text { + id: sipAddr + property string _text: UtilsCpp.interpretUrl(searchbar.text) + text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_text) : _text + font.pixelSize: 14 * DefaultStyle.dp + } + } + } + } + + } + Item { + Layout.fillHeight: true + } } } diff --git a/Linphone/view/Page/Login/LoginPage.qml b/Linphone/view/Page/Login/LoginPage.qml index e163791ed..ad7b42453 100644 --- a/Linphone/view/Page/Login/LoginPage.qml +++ b/Linphone/view/Page/Login/LoginPage.qml @@ -23,8 +23,8 @@ LoginLayout { Layout.preferredWidth: 27 * DefaultStyle.dp Layout.leftMargin: 79 * DefaultStyle.dp icon.source: AppIcons.leftArrow - icon.width: 27 * DefaultStyle.dp - icon.height: 27 * DefaultStyle.dp + icon.width: width + icon.height: height background: Rectangle { color: "transparent" } diff --git a/Linphone/view/Page/Login/RegisterPage.qml b/Linphone/view/Page/Login/RegisterPage.qml index 5411c3aae..40ee4f181 100644 --- a/Linphone/view/Page/Login/RegisterPage.qml +++ b/Linphone/view/Page/Login/RegisterPage.qml @@ -214,13 +214,22 @@ LoginLayout { } } Text { + activeFocusOnTab: true font { underline: true pixelSize: 14 * DefaultStyle.dp weight: 400 * DefaultStyle.dp + bold: activeFocus } text: qsTr("conditions d’utilisation") + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + cguMouseArea.clicked(undefined) + event.accepted = true; + } + } MouseArea { + id: cguMouseArea anchors.fill: parent hoverEnabled: true cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor @@ -235,13 +244,22 @@ LoginLayout { } } Text { + activeFocusOnTab: true font { underline: true pixelSize: 14 * DefaultStyle.dp weight: 400 * DefaultStyle.dp + bold: activeFocus } text: qsTr("politique de confidentialité.") + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + privateMouseArea.clicked(undefined) + event.accepted = true; + } + } MouseArea { + id: privateMouseArea anchors.fill: parent hoverEnabled: true cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor diff --git a/Linphone/view/Page/Login/SIPLoginPage.qml b/Linphone/view/Page/Login/SIPLoginPage.qml index 7d56b4c76..ba66097e8 100644 --- a/Linphone/view/Page/Login/SIPLoginPage.qml +++ b/Linphone/view/Page/Login/SIPLoginPage.qml @@ -95,6 +95,7 @@ LoginLayout {

To enable it in a commercial projet, please contact us.

" } Button { + Layout.alignment: Qt.AlignCenter Layout.topMargin: 18 * DefaultStyle.dp text: "linphone.org/contact" textSize: 13 * DefaultStyle.dp @@ -109,7 +110,7 @@ LoginLayout { } Button { Layout.topMargin: 85 * DefaultStyle.dp - Layout.preferredWidth: 360 * DefaultStyle.dp + Layout.fillWidth: true inversedColors: true text: qsTr("I prefer creating an account") leftPadding: 20 * DefaultStyle.dp @@ -123,7 +124,7 @@ LoginLayout { } Button { Layout.topMargin: 20 * DefaultStyle.dp - Layout.preferredWidth: 360 * DefaultStyle.dp + Layout.fillWidth: true text: qsTr("I understand") leftPadding: 20 * DefaultStyle.dp rightPadding: 20 * DefaultStyle.dp @@ -229,7 +230,6 @@ LoginLayout { anchors.topMargin: 70 * DefaultStyle.dp anchors.leftMargin: 127 * DefaultStyle.dp width: 361 * DefaultStyle.dp - clip: true }, Image { z: -1 diff --git a/Linphone/view/Page/Main/AbstractMainPage.qml b/Linphone/view/Page/Main/AbstractMainPage.qml index e2a720c50..104410a16 100644 --- a/Linphone/view/Page/Main/AbstractMainPage.qml +++ b/Linphone/view/Page/Main/AbstractMainPage.qml @@ -9,7 +9,7 @@ import QtQuick.Controls as Control import Linphone import UtilsCpp -Item { +FocusScope { id: mainItem property string noItemButtonText property string newItemIconSource @@ -209,6 +209,8 @@ Item { } Control.StackView { id: rightPanelStackView + Layout.fillWidth: true + Layout.fillHeight: true } } } diff --git a/Linphone/view/Page/Main/AbstractMasterDetailPage.qml b/Linphone/view/Page/Main/AbstractMasterDetailPage.qml index 2866940d1..4033f09c2 100644 --- a/Linphone/view/Page/Main/AbstractMasterDetailPage.qml +++ b/Linphone/view/Page/Main/AbstractMasterDetailPage.qml @@ -33,17 +33,19 @@ AbstractMainPage { Layout.rightMargin: leftPanel.sideMargin spacing: 5 * DefaultStyle.dp Button { + id: backButton Layout.preferredHeight: 24 * DefaultStyle.dp Layout.preferredWidth: 24 * DefaultStyle.dp icon.source: AppIcons.leftArrow width: 24 * DefaultStyle.dp height: 24 * DefaultStyle.dp - background: Item { - anchors.fill: parent - } + focus: true onClicked: { mainItem.goBack() } + background: Item { + anchors.fill: parent + } } Text { text: titleText @@ -63,11 +65,13 @@ AbstractMainPage { Layout.topMargin: 41 * DefaultStyle.dp Layout.leftMargin: leftPanel.sideMargin property int selectedIndex: 0 + activeFocusOnTab: true delegate: MasterDetailFamily { titleText: modelData.title visible: modelData.visible != undefined ? modelData.visible : true isSelected: familiesList.selectedIndex == index + focus: index == 0 onSelected: { familiesList.selectedIndex = index rightPanelStackView.clear() @@ -78,6 +82,8 @@ AbstractMainPage { Component.onCompleted: { let initialEntry = mainItem.families[familiesList.selectedIndex] rightPanelStackView.push(layoutUrl(initialEntry.layout), { titleText: initialEntry.title, model: initialEntry.model, container: rightPanelStackView}) + familiesList.currentIndex = familiesList.selectedIndex + backButton.forceActiveFocus() } } } diff --git a/Linphone/view/Page/Main/CallPage.qml b/Linphone/view/Page/Main/CallPage.qml index a4eab2c80..3057f70bc 100644 --- a/Linphone/view/Page/Main/CallPage.qml +++ b/Linphone/view/Page/Main/CallPage.qml @@ -69,23 +69,32 @@ AbstractMainPage { id: leftPanel Layout.fillWidth: true Layout.fillHeight: true - Loader { id: titleLoader anchors.left: parent.left anchors.right: parent.right + asynchronous: false + onActiveFocusChanged:{ + if(activeFocus && item){ + item.forceActiveFocus() + } + } } Control.StackView { id: listStackView - clip: true - initialItem: historyListItem anchors.top: titleLoader.bottom anchors.topMargin: 18 * DefaultStyle.dp anchors.left: parent.left anchors.leftMargin: 45 * DefaultStyle.dp anchors.right: parent.right anchors.bottom: parent.bottom + clip: true + initialItem: historyListItem + focus: true + onActiveFocusChanged: if(activeFocus){ + currentItem.forceActiveFocus() + } } Item { @@ -107,42 +116,53 @@ AbstractMainPage { Component { id: historyListTitle - RowLayout { - spacing: 16 * DefaultStyle.dp - Text { - text: qsTr("Appels") - Layout.leftMargin: 45 * DefaultStyle.dp - color: DefaultStyle.main2_700 - font.pixelSize: 29 * DefaultStyle.dp - font.weight: 800 * DefaultStyle.dp - } - Item { - Layout.fillWidth: true - } - PopupButton { - id: removeHistory - width: 24 * DefaultStyle.dp - height: 24 * DefaultStyle.dp - popup.x: 0 - popup.padding: 10 * DefaultStyle.dp - popup.contentItem: Button { - background: Item{} - contentItem: RowLayout { - EffectImage { - imageSource: AppIcons.trashCan - width: 24 * DefaultStyle.dp - height: 24 * DefaultStyle.dp - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - fillMode: Image.PreserveAspectFit - colorizationColor: DefaultStyle.danger_500main - } - Text { - text: qsTr("Supprimer l’historique") - color: DefaultStyle.danger_500main - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp + FocusScope{ + width: parent.width + height: titleCallLayout.implicitHeight + RowLayout { + id: titleCallLayout + anchors.fill: parent + spacing: 16 * DefaultStyle.dp + Text { + text: qsTr("Appels") + Layout.leftMargin: 45 * DefaultStyle.dp + color: DefaultStyle.main2_700 + font.pixelSize: 29 * DefaultStyle.dp + font.weight: 800 * DefaultStyle.dp + } + Item { + Layout.fillWidth: true + } + PopupButton { + id: removeHistory + width: 24 * DefaultStyle.dp + height: 24 * DefaultStyle.dp + focus: true + popup.x: 0 + popup.padding: 10 * DefaultStyle.dp + KeyNavigation.right: newCallButton + KeyNavigation.down: listStackView + popup.contentItem: Button { + color: removeHistory.popupBackgroundColor + borderColor: removeHistory.popupBackgroundColor + inversedColors: true + contentItem: RowLayout { + EffectImage { + imageSource: AppIcons.trashCan + width: 24 * DefaultStyle.dp + height: 24 * DefaultStyle.dp + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + fillMode: Image.PreserveAspectFit + colorizationColor: DefaultStyle.danger_500main + } + Text { + text: qsTr("Supprimer l’historique") + color: DefaultStyle.danger_500main + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } } } } @@ -151,235 +171,262 @@ AbstractMainPage { deleteHistoryPopup.open() } } - } - Button { - background: Item {} - icon.source: AppIcons.newCall - Layout.preferredWidth: 28 * DefaultStyle.dp - Layout.preferredHeight: 28 * DefaultStyle.dp - Layout.rightMargin: 39 * DefaultStyle.dp - icon.width: 28 * DefaultStyle.dp - icon.height: 28 * DefaultStyle.dp - onClicked: { - console.debug("[CallPage]User: create new call") - listStackView.push(newCallItem) + Button { + id: newCallButton + background: Item {} + icon.source: AppIcons.newCall + Layout.preferredWidth: 28 * DefaultStyle.dp + Layout.preferredHeight: 28 * DefaultStyle.dp + Layout.rightMargin: 39 * DefaultStyle.dp + icon.width: 28 * DefaultStyle.dp + icon.height: 28 * DefaultStyle.dp + KeyNavigation.left: removeHistory + KeyNavigation.down: listStackView + onClicked: { + console.debug("[CallPage]User: create new call") + listStackView.push(newCallItem) + } } } } } Component { id: historyListItem - ColumnLayout { + FocusScope{ + width: parent.width + height: parent.height Control.StackView.onActivated: titleLoader.sourceComponent = historyListTitle - property alias listView: historyListView - SearchBar { - id: searchBar - Layout.fillWidth: true - Layout.rightMargin: 39 * DefaultStyle.dp - placeholderText: qsTr("Rechercher un appel") - } - Item { - Layout.topMargin: 38 * DefaultStyle.dp - Layout.fillWidth: true - Layout.fillHeight: true - Control.Control { - id: listLayout - anchors.fill: parent - anchors.rightMargin: 39 * DefaultStyle.dp - - background: Item{} - ColumnLayout { + ColumnLayout { + anchors.fill: parent + SearchBar { + id: searchBar + Layout.fillWidth: true + Layout.rightMargin: 39 * DefaultStyle.dp + placeholderText: qsTr("Rechercher un appel") + focus: true + KeyNavigation.up: titleLoader + KeyNavigation.down: historyListView + } + Item { + Layout.topMargin: 38 * DefaultStyle.dp + Layout.fillWidth: true + Layout.fillHeight: true + Control.Control { + id: listLayout anchors.fill: parent + anchors.rightMargin: 39 * DefaultStyle.dp + + background: Item{} ColumnLayout { - Text { - text: qsTr("Aucun appel") - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - visible: historyListView.count === 0 - Layout.alignment: Qt.AlignHCenter - Binding on text { - when: searchBar.text.length !== 0 - value: qsTr("Aucun appel correspondant") - restoreMode: Binding.RestoreBindingOrValue - } - } - ListView { - id: historyListView - clip: true - Layout.fillWidth: true - Layout.fillHeight: true - model: CallHistoryProxy { - filterText: searchBar.text - } - - currentIndex: -1 - flickDeceleration: 10000 - spacing: 10 * DefaultStyle.dp - - Connections { - target: deleteHistoryPopup - function onAccepted() { - historyListView.model.removeAllEntries() + anchors.fill: parent + ColumnLayout { + Text { + visible: historyListView.count === 0 + Layout.alignment: Qt.AlignHCenter + text: qsTr("Aucun appel") + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + Binding on text { + when: searchBar.text.length !== 0 + value: qsTr("Aucun appel correspondant") + restoreMode: Binding.RestoreBindingOrValue } } - - delegate: Item { - width:historyListView.width - height: 56 * DefaultStyle.dp - anchors.topMargin: 5 * DefaultStyle.dp - anchors.bottomMargin: 5 * DefaultStyle.dp - RowLayout { - z: 1 - anchors.fill: parent - Item { - Layout.preferredWidth: historyAvatar.width - Layout.preferredHeight: historyAvatar.height - Layout.leftMargin: 5 * DefaultStyle.dp - MultiEffect { - source: historyAvatar - anchors.fill: historyAvatar - shadowEnabled: true - shadowBlur: 1 - shadowColor: DefaultStyle.grey_900 - shadowOpacity: 0.1 - } - Avatar { - id: historyAvatar - address: modelData.core.remoteAddress - width: 45 * DefaultStyle.dp - height: 45 * DefaultStyle.dp - } + ListView { + id: historyListView + clip: true + Layout.fillWidth: true + Layout.fillHeight: true + model: CallHistoryProxy { + filterText: searchBar.text + } + + currentIndex: -1 + flickDeceleration: 10000 + spacing: 10 * DefaultStyle.dp + highlightFollowsCurrentItem: true + preferredHighlightBegin: height/2 - 10 + preferredHighlightEnd: height/2 + 10 + highlightRangeMode: ListView.ApplyRange + Keys.onPressed: (event) => { + if(event.key == Qt.Key_Escape){ + console.log("Back") + searchBar.forceActiveFocus() + event.accepted = true } - ColumnLayout { - Layout.fillHeight: true - Layout.fillWidth: true - spacing: 5 * DefaultStyle.dp - Text { - id: friendAddress - Layout.fillWidth: true - maximumLineCount: 1 - text: modelData.core.displayName - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp + } + onActiveFocusChanged: if(activeFocus && currentIndex <0) currentIndex = 0 + + Connections { + target: deleteHistoryPopup + function onAccepted() { + historyListView.model.removeAllEntries() + } + } + + delegate: FocusScope { + width:historyListView.width + height: 56 * DefaultStyle.dp + anchors.topMargin: 5 * DefaultStyle.dp + anchors.bottomMargin: 5 * DefaultStyle.dp + RowLayout { + z: 1 + anchors.fill: parent + Item { + Layout.preferredWidth: historyAvatar.width + Layout.preferredHeight: historyAvatar.height + Layout.leftMargin: 5 * DefaultStyle.dp + MultiEffect { + source: historyAvatar + anchors.fill: historyAvatar + shadowEnabled: true + shadowBlur: 1 + shadowColor: DefaultStyle.grey_900 + shadowOpacity: 0.1 + } + Avatar { + id: historyAvatar + address: modelData.core.remoteAddress + width: 45 * DefaultStyle.dp + height: 45 * DefaultStyle.dp } } - RowLayout { - spacing: 3 * DefaultStyle.dp - 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 - 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 - origin { - x: statusIcon.width/2 - y: statusIcon.height/2 + ColumnLayout { + Layout.fillHeight: true + Layout.fillWidth: true + spacing: 5 * DefaultStyle.dp + Text { + id: friendAddress + Layout.fillWidth: true + maximumLineCount: 1 + text: modelData.core.displayName + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + RowLayout { + spacing: 3 * DefaultStyle.dp + 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 + 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 + origin { + x: statusIcon.width/2 + y: statusIcon.height/2 + } + } + } + Text { + // text: modelData.core.date + text: UtilsCpp.formatDateElapsedTime(modelData.core.date) + font { + pixelSize: 12 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp } } } - Text { - // text: modelData.core.date - text: UtilsCpp.formatDateElapsedTime(modelData.core.date) - font { - pixelSize: 12 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp + } + Button { + Layout.rightMargin: 5 * DefaultStyle.dp + padding: 0 + background: Item { + visible: false + } + icon.source: AppIcons.phone + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + focus: true + activeFocusOnTab: false + onClicked: { + if (modelData.core.isConference) { + var callsWindow = UtilsCpp.getCallsWindow() + callsWindow.setupConference(modelData.core.conferenceInfo) + callsWindow.show() + } + else { + UtilsCpp.createCall(modelData.core.remoteAddress) } } } } - Button { - Layout.rightMargin: 5 * DefaultStyle.dp - padding: 0 - background: Item { - visible: false + MouseArea { + hoverEnabled: true + anchors.fill: parent + focus: true + Rectangle { + anchors.fill: parent + opacity: 0.1 + color: DefaultStyle.main2_500main + visible: parent.containsMouse } - icon.source: AppIcons.phone - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - onClicked: { - if (modelData.core.isConference) { - var callsWindow = UtilsCpp.getCallsWindow() - callsWindow.setupConference(modelData.core.conferenceInfo) - callsWindow.show() - } - else { - UtilsCpp.createCall(modelData.core.remoteAddress) - } + Rectangle { + anchors.fill: parent + visible: historyListView.currentIndex === model.index + color: DefaultStyle.main2_100 + } + onPressed: { + historyListView.currentIndex = model.index + historyListView.forceActiveFocus() + } } } - MouseArea { - hoverEnabled: true - anchors.fill: parent - Rectangle { - anchors.fill: parent - opacity: 0.1 - color: DefaultStyle.main2_500main - visible: parent.containsMouse - } - Rectangle { - anchors.fill: parent - visible: historyListView.currentIndex === model.index - color: DefaultStyle.main2_100 - } - onPressed: { - historyListView.currentIndex = model.index + onCurrentIndexChanged: { + positionViewAtIndex(currentIndex, ListView.Visible) + mainItem.selectedRowHistoryGui = model.getAt(currentIndex) + } + onCountChanged: mainItem.selectedRowHistoryGui = model.getAt(currentIndex) + onVisibleChanged: { + if (!visible) currentIndex = -1 + } + + Connections { + target: mainItem + function onListViewUpdated() { + historyListView.model.updateView() } } + Control.ScrollBar.vertical: scrollbar } - onCurrentIndexChanged: { - positionViewAtIndex(currentIndex, ListView.Visible) - mainItem.selectedRowHistoryGui = model.getAt(currentIndex) - } - onCountChanged: mainItem.selectedRowHistoryGui = model.getAt(currentIndex) - onVisibleChanged: { - if (!visible) currentIndex = -1 - } - - Connections { - target: mainItem - function onListViewUpdated() { - historyListView.model.updateView() - } - } - Control.ScrollBar.vertical: scrollbar } } } - } - ScrollBar { - id: scrollbar - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.rightMargin: 8 * DefaultStyle.dp - active: true - policy: Control.ScrollBar.AsNeeded + ScrollBar { + id: scrollbar + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.rightMargin: 8 * DefaultStyle.dp + active: true + policy: Control.ScrollBar.AsNeeded + } } } } @@ -387,51 +434,71 @@ AbstractMainPage { Component { id: newCallTitle - RowLayout { - Button { - Layout.leftMargin: 45 * DefaultStyle.dp - background: Item { + FocusScope{ + width: parent.width + height: parent.height + RowLayout { + anchors.fill: parent + Button { + Layout.leftMargin: 45 * DefaultStyle.dp + background: Item { + } + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.source: AppIcons.leftArrow + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + focus: true + KeyNavigation.down: listStackView + onClicked: { + console.debug("[CallPage]User: return to call history") + listStackView.pop() + listStackView.forceActiveFocus() + } } - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.source: AppIcons.leftArrow - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - onClicked: { - console.debug("[CallPage]User: return to call history") - listStackView.pop() + Text { + text: qsTr("Nouvel appel") + color: DefaultStyle.main2_700 + font.pixelSize: 29 * DefaultStyle.dp + font.weight: 800 * DefaultStyle.dp + } + Item { + Layout.fillWidth: true } - } - Text { - text: qsTr("Nouvel appel") - color: DefaultStyle.main2_700 - font.pixelSize: 29 * DefaultStyle.dp - font.weight: 800 * DefaultStyle.dp - } - Item { - Layout.fillWidth: true } } } Component { id: newCallItem - ColumnLayout { - Control.StackView.onActivated: titleLoader.sourceComponent = newCallTitle - CallContactsLists { - id: callContactsList - Layout.fillWidth: true - Layout.fillHeight: true - numPad: numericPad - groupCallVisible: true - searchBarColor: DefaultStyle.grey_100 - onSelectedContactChanged: mainWindow.startCallWithContact(selectedContact, false, callContactsList) - onGroupCallCreationRequested: { - console.log("groupe call requetsed") - listStackView.push(groupCallItem) - } - Connections { - target: mainItem - function onCreateCallFromSearchBarRequested(){ UtilsCpp.createCall(callContactsList.searchBar.text)} + FocusScope{ + width: parent?.width + height: parent?.height + Control.StackView.onActivated:{ + titleLoader.sourceComponent = newCallTitle + callContactsList.forceActiveFocus() + } + + ColumnLayout { + anchors.fill: parent + CallContactsLists { + id: callContactsList + Layout.fillWidth: true + Layout.fillHeight: true + focus: true + numPad: numericPad + groupCallVisible: true + searchBarColor: DefaultStyle.grey_100 + //onSelectedContactChanged: mainWindow.startCallWithContact(selectedContact, false, callContactsList) + onCallSelectedContact: mainWindow.startCallWithContact(selectedContact, false, callContactsList) + onCallButtonPressed: mainItem.createCallFromSearchBarRequested() + onGroupCallCreationRequested: { + console.log("groupe call requetsed") + listStackView.push(groupCallItem) + } + Connections { + target: mainItem + function onCreateCallFromSearchBarRequested(){ UtilsCpp.createCall(callContactsList.searchBar.text)} + } } } } @@ -439,54 +506,70 @@ AbstractMainPage { Component { id: groupCallTitle - RowLayout { - spacing: 10 * DefaultStyle.dp - visible: !SettingsCpp.disableMeetingsFeature - Button { - background: Item{} - icon.source: AppIcons.leftArrow - contentImageColor: DefaultStyle.main1_500_main - Layout.leftMargin: 21 * DefaultStyle.dp - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - onClicked: listStackView.pop() - } - ColumnLayout { - spacing: 3 * DefaultStyle.dp - Text { - text: qsTr("Appel de groupe") - color: DefaultStyle.main1_500_main - maximumLineCount: 1 - font { - pixelSize: 18 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp + FocusScope{ + width: parent.width + height: parent.height + RowLayout { + anchors.fill: parent + spacing: 10 * DefaultStyle.dp + visible: !SettingsCpp.disableMeetingsFeature + Button { + id: backGroupCallButton + background: Item{} + icon.source: AppIcons.leftArrow + contentImageColor: DefaultStyle.main1_500_main + Layout.leftMargin: 21 * DefaultStyle.dp + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + KeyNavigation.down: listStackView + KeyNavigation.right: groupCallButton + KeyNavigation.left: groupCallButton + onClicked: { + listStackView.pop() + titleLoader.item.forceActiveFocus() } - Layout.fillWidth: true } - Text { - text: qsTr("%1 participant%2 sélectionné").arg(mainItem.selectedParticipantsCount).arg(mainItem.selectedParticipantsCount > 1 ? "s" : "") - color: DefaultStyle.main2_500main - maximumLineCount: 1 - font { - pixelSize: 12 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp + ColumnLayout { + spacing: 3 * DefaultStyle.dp + Text { + text: qsTr("Appel de groupe") + color: DefaultStyle.main1_500_main + maximumLineCount: 1 + font { + pixelSize: 18 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + Layout.fillWidth: true + } + Text { + text: qsTr("%1 participant%2 sélectionné").arg(mainItem.selectedParticipantsCount).arg(mainItem.selectedParticipantsCount > 1 ? "s" : "") + color: DefaultStyle.main2_500main + maximumLineCount: 1 + font { + pixelSize: 12 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + Layout.fillWidth: true } - Layout.fillWidth: true } - } - Button { - enabled: mainItem.selectedParticipantsCount.length != 0 - Layout.rightMargin: 21 * DefaultStyle.dp - topPadding: 6 * DefaultStyle.dp - bottomPadding: 6 * DefaultStyle.dp - leftPadding: 12 * DefaultStyle.dp - rightPadding: 12 * DefaultStyle.dp - text: qsTr("Lancer") - textSize: 13 * DefaultStyle.dp - onClicked: { - mainItem.startGroupCallRequested() + Button { + id: groupCallButton + enabled: mainItem.selectedParticipantsCount.length != 0 + Layout.rightMargin: 21 * DefaultStyle.dp + topPadding: 6 * DefaultStyle.dp + bottomPadding: 6 * DefaultStyle.dp + leftPadding: 12 * DefaultStyle.dp + rightPadding: 12 * DefaultStyle.dp + text: qsTr("Lancer") + textSize: 13 * DefaultStyle.dp + KeyNavigation.down: listStackView + KeyNavigation.left: backGroupCallButton + KeyNavigation.right: backGroupCallButton + onClicked: { + mainItem.startGroupCallRequested() + } } } } @@ -494,12 +577,19 @@ AbstractMainPage { Component { id: groupCallItem - // RowLayout { + FocusScope{ + width: parent?.width + height: parent?.height + Control.StackView.onActivated: { + titleLoader.sourceComponent = groupCallTitle + addParticipantsLayout.forceActiveFocus() + } AddParticipantsLayout { - Control.StackView.onActivated: titleLoader.sourceComponent = groupCallTitle id: addParticipantsLayout + anchors.fill: parent onSelectedParticipantsCountChanged: mainItem.selectedParticipantsCount = selectedParticipantsCount nameGroupCall: true + focus: true Connections { target: mainItem function onStartGroupCallRequested() { @@ -519,7 +609,7 @@ AbstractMainPage { } } } - // } + } } Component{ @@ -528,194 +618,198 @@ AbstractMainPage { } Component { id: contactDetailComp - ContactLayout { - id: contactDetail - visible: mainItem.selectedRowHistoryGui != undefined - property var contactObj: UtilsCpp.findFriendByAddress(contactAddress) - contact: contactObj && contactObj.value || null - conferenceInfo: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.conferenceInfo || null - contactAddress: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress || "" - contactName: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.displayName : "" - anchors.top: rightPanelStackView.top - anchors.bottom: rightPanelStackView.bottom - anchors.topMargin: 45 * DefaultStyle.dp - anchors.bottomMargin: 45 * DefaultStyle.dp - buttonContent: PopupButton { - id: detailOptions - anchors.right: parent.right - anchors.rightMargin: 30 * DefaultStyle.dp - anchors.verticalCenter: parent.verticalCenter - popup.x: width - property var friendGuiObj: UtilsCpp.findFriendByAddress(contactDetail.contactAddress) - property var friendGui: friendGuiObj ? friendGuiObj.value : null - popup.contentItem: ColumnLayout { - Button { - background: Item {} - contentItem: IconLabel { - text: detailOptions.friendGui ? qsTr("Voir le contact") : qsTr("Ajouter aux contacts") - iconSource: AppIcons.plusCircle - } - onClicked: { - detailOptions.close() - if (detailOptions.friendGui) mainWindow.displayContactPage(contactDetail.contactAddress) - else mainItem.createContactRequested(contactDetail.contactName, contactDetail.contactAddress) - } - } - Button { - background: Item {} - contentItem: IconLabel { - text: qsTr("Copier l'adresse SIP") - iconSource: AppIcons.copy - } - onClicked: { - detailOptions.close() - var success = UtilsCpp.copyToClipboard(mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress) - if (success) UtilsCpp.showInformationPopup(qsTr("Copié"), qsTr("L'adresse a été copiée dans le presse-papier"), true) - else UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Erreur lors de la copie de l'adresse"), false) - } - } - // Button { - // background: Item {} - // enabled: false - // contentItem: IconLabel { - // text: qsTr("Bloquer") - // iconSource: AppIcons.empty - // } - // onClicked: console.debug("[CallPage.qml] TODO : block user") - // } - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 2 * DefaultStyle.dp - color: DefaultStyle.main2_400 - } - Button { - background: Item {} - contentItem: IconLabel { - text: qsTr("Supprimer l'historique") - iconSource: AppIcons.trashCan - colorizationColor: DefaultStyle.danger_500main - } - Connections { - target: deleteForUserPopup - function onAccepted() { - detailListView.model.removeEntriesWithFilter() - mainItem.listViewUpdated() + FocusScope{ + width: parent?.width + height: parent?.height + ContactLayout { + id: contactDetail + anchors.fill: parent + anchors.topMargin: 45 * DefaultStyle.dp + anchors.bottomMargin: 45 * DefaultStyle.dp + visible: mainItem.selectedRowHistoryGui != undefined + property var contactObj: UtilsCpp.findFriendByAddress(contactAddress) + contact: contactObj && contactObj.value || null + conferenceInfo: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.conferenceInfo || null + contactAddress: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress || "" + contactName: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.displayName : "" + + buttonContent: PopupButton { + id: detailOptions + anchors.right: parent.right + anchors.rightMargin: 30 * DefaultStyle.dp + anchors.verticalCenter: parent.verticalCenter + popup.x: width + property var friendGuiObj: UtilsCpp.findFriendByAddress(contactDetail.contactAddress) + property var friendGui: friendGuiObj ? friendGuiObj.value : null + popup.contentItem: ColumnLayout { + Button { + background: Item {} + contentItem: IconLabel { + text: detailOptions.friendGui ? qsTr("Voir le contact") : qsTr("Ajouter aux contacts") + iconSource: AppIcons.plusCircle + } + onClicked: { + detailOptions.close() + if (detailOptions.friendGui) mainWindow.displayContactPage(contactDetail.contactAddress) + else mainItem.createContactRequested(contactDetail.contactName, contactDetail.contactAddress) } } - onClicked: { - detailOptions.close() - deleteForUserPopup.open() + Button { + background: Item {} + contentItem: IconLabel { + text: qsTr("Copier l'adresse SIP") + iconSource: AppIcons.copy + } + onClicked: { + detailOptions.close() + var success = UtilsCpp.copyToClipboard(mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress) + if (success) UtilsCpp.showInformationPopup(qsTr("Copié"), qsTr("L'adresse a été copiée dans le presse-papier"), true) + else UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Erreur lors de la copie de l'adresse"), false) + } + } + // Button { + // background: Item {} + // enabled: false + // contentItem: IconLabel { + // text: qsTr("Bloquer") + // iconSource: AppIcons.empty + // } + // onClicked: console.debug("[CallPage.qml] TODO : block user") + // } + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 2 * DefaultStyle.dp + color: DefaultStyle.main2_400 + } + + Button { + background: Item {} + contentItem: IconLabel { + text: qsTr("Supprimer l'historique") + iconSource: AppIcons.trashCan + colorizationColor: DefaultStyle.danger_500main + } + Connections { + target: deleteForUserPopup + function onAccepted() { + detailListView.model.removeEntriesWithFilter() + mainItem.listViewUpdated() + } + } + onClicked: { + detailOptions.close() + deleteForUserPopup.open() + } } } } - } - detailContent: RoundedBackgroundControl { - id: detailControl - Layout.preferredWidth: 360 * DefaultStyle.dp - implicitHeight: 430 * DefaultStyle.dp + topPadding + bottomPadding - - background: Rectangle { - id: detailListBackground - width: parent.width - height: detailListView.height - color: DefaultStyle.grey_0 - radius: 15 * DefaultStyle.dp - } - - ListView { - id: detailListView - width: parent.width - height: Math.min(detailControl.implicitHeight, contentHeight) - - - spacing: 20 * DefaultStyle.dp - clip: true - - model: CallHistoryProxy { - filterText: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : "" + detailContent: RoundedBackgroundControl { + id: detailControl + Layout.preferredWidth: 360 * DefaultStyle.dp + implicitHeight: 430 * DefaultStyle.dp + topPadding + bottomPadding + + background: Rectangle { + id: detailListBackground + width: parent.width + height: detailListView.height + color: DefaultStyle.grey_0 + radius: 15 * DefaultStyle.dp } - - delegate: Item { - width:detailListView.width - height: 56 * DefaultStyle.dp - RowLayout { - anchors.fill: parent - anchors.leftMargin: 20 * DefaultStyle.dp - anchors.rightMargin: 20 * DefaultStyle.dp - anchors.verticalCenter: parent.verticalCenter - ColumnLayout { - Layout.alignment: Qt.AlignVCenter - RowLayout { - 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 - Layout.preferredWidth: 16 * DefaultStyle.dp - Layout.preferredHeight: 16 * 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 - origin { - x: statusIcon.width/2 - y: statusIcon.height/2 + + ListView { + id: detailListView + width: parent.width + height: Math.min(detailControl.implicitHeight, contentHeight) + + spacing: 20 * DefaultStyle.dp + clip: true + + model: CallHistoryProxy { + filterText: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : "" + } + + delegate: Item { + width:detailListView.width + height: 56 * DefaultStyle.dp + RowLayout { + anchors.fill: parent + anchors.leftMargin: 20 * DefaultStyle.dp + anchors.rightMargin: 20 * DefaultStyle.dp + anchors.verticalCenter: parent.verticalCenter + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + RowLayout { + 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 + Layout.preferredWidth: 16 * DefaultStyle.dp + Layout.preferredHeight: 16 * 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 + origin { + x: statusIcon.width/2 + y: statusIcon.height/2 + } + } + } + Text { + text: modelData.core.status === LinphoneEnums.CallStatus.Missed + ? qsTr("Appel manqué") + : modelData.core.isOutgoing + ? qsTr("Appel sortant") + : qsTr("Appel entrant") + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp } } } Text { - text: modelData.core.status === LinphoneEnums.CallStatus.Missed - ? qsTr("Appel manqué") - : modelData.core.isOutgoing - ? qsTr("Appel sortant") - : qsTr("Appel entrant") + text: UtilsCpp.formatDate(modelData.core.date) + color: modelData.core.status === LinphoneEnums.CallStatus.Missed? DefaultStyle.danger_500main : DefaultStyle.main2_500main font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp + pixelSize: 12 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp } } } + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } Text { - text: UtilsCpp.formatDate(modelData.core.date) - color: modelData.core.status === LinphoneEnums.CallStatus.Missed? DefaultStyle.danger_500main : DefaultStyle.main2_500main + text: UtilsCpp.formatElapsedTime(modelData.core.duration, false) font { pixelSize: 12 * DefaultStyle.dp weight: 300 * DefaultStyle.dp } } } - Item { - Layout.fillHeight: true - Layout.fillWidth: true - } - Text { - text: UtilsCpp.formatElapsedTime(modelData.core.duration, false) - font { - pixelSize: 12 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp - } - } } } } - } - Item{ - Layout.fillHeight: true + Item{ + Layout.fillHeight: true + } } } } diff --git a/Linphone/view/Page/Main/ContactPage.qml b/Linphone/view/Page/Main/ContactPage.qml index 0fe2c9ae9..42b8b8f82 100644 --- a/Linphone/view/Page/Main/ContactPage.qml +++ b/Linphone/view/Page/Main/ContactPage.qml @@ -363,6 +363,8 @@ AbstractMainPage { Component { id: contactDetail Item { + width: parent?.width + height: parent?.height property string objectName: "contactDetail" Control.StackView.onActivated: mainItem.leftPanelEnabled = true Control.StackView.onDeactivated: mainItem.leftPanelEnabled = false @@ -791,6 +793,8 @@ AbstractMainPage { Component { id: contactEdition ContactEdition { + width: rightPanelStackView.width + height: rightPanelStackView.height property string objectName: "contactEdition" onCloseEdition: { if (rightPanelStackView.depth <= 1) rightPanelStackView.clear() @@ -798,4 +802,4 @@ AbstractMainPage { } } } -} \ No newline at end of file +} diff --git a/Linphone/view/Page/Main/MeetingPage.qml b/Linphone/view/Page/Main/MeetingPage.qml index 8c14fe872..6ca5974d6 100644 --- a/Linphone/view/Page/Main/MeetingPage.qml +++ b/Linphone/view/Page/Main/MeetingPage.qml @@ -28,19 +28,22 @@ AbstractMainPage { } } - onNoItemButtonPressed: editConference() + onNoItemButtonPressed: editConference() function editConference(confInfoGui = null) { var isCreation = !confInfoGui + var item if (isCreation) { confInfoGui = Qt.createQmlObject('import Linphone ConferenceInfoGui{ }', mainItem) mainItem.selectedConference = confInfoGui - leftPanelStackView.push(createConf, {"conferenceInfoGui": mainItem.selectedConference, "isCreation": isCreation}) + item = leftPanelStackView.push(createConf, {"conferenceInfoGui": mainItem.selectedConference, "isCreation": isCreation}) + item.forceActiveFocus() } else { mainItem.selectedConference = confInfoGui - overridenRightPanelStackView.push(editConf, {"conferenceInfoGui": mainItem.selectedConference, "isCreation": isCreation}) + item = overridenRightPanelStackView.push(editConf, {"conferenceInfoGui": mainItem.selectedConference, "isCreation": isCreation}) + item.forceActiveFocus() } } @@ -120,9 +123,9 @@ AbstractMainPage { Component { id: listLayout - ColumnLayout { - id: listLayoutIn - spacing: 0 + FocusScope{ + width: parent.width + height: listLayoutIn.implicitHeight property string objectName: "listLayout" Control.StackView.onDeactivated: { mainItem.selectedConference = null @@ -137,80 +140,97 @@ AbstractMainPage { value: conferenceList.count === 0 restoreMode: Binding.RestoreBindingOrValue } - RowLayout { - enabled: mainItem.leftPanelEnabled - Layout.rightMargin: 39 * DefaultStyle.dp + ColumnLayout { + id: listLayoutIn + anchors.fill: parent spacing: 0 + RowLayout { + enabled: mainItem.leftPanelEnabled + Layout.rightMargin: 39 * DefaultStyle.dp + spacing: 0 + Text { + Layout.fillWidth: true + text: qsTr("Réunions") + color: DefaultStyle.main2_700 + font.pixelSize: 29 * DefaultStyle.dp + font.weight: 800 * DefaultStyle.dp + } + Item{Layout.fillWidth: true} + Button { + background: Item { + } + icon.source: AppIcons.plusCircle + Layout.preferredWidth: 28 * DefaultStyle.dp + Layout.preferredHeight: 28 * DefaultStyle.dp + icon.width: 28 * DefaultStyle.dp + icon.height: 28 * DefaultStyle.dp + onClicked: { + mainItem.editConference() + } + } + } + SearchBar { + id: searchBar + Layout.topMargin: 18 * DefaultStyle.dp + // Layout.fillWidth: true + //Layout.topMargin: 18 * DefaultStyle.dp + placeholderText: qsTr("Rechercher une réunion") + Layout.preferredWidth: 331 * DefaultStyle.dp + KeyNavigation.up: conferenceList + KeyNavigation.down: conferenceList + } Text { - Layout.fillWidth: true - text: qsTr("Réunions") - color: DefaultStyle.main2_700 - font.pixelSize: 29 * DefaultStyle.dp - font.weight: 800 * DefaultStyle.dp - } - Item{Layout.fillWidth: true} - Button { - background: Item { - } - icon.source: AppIcons.plusCircle - Layout.preferredWidth: 28 * DefaultStyle.dp - Layout.preferredHeight: 28 * DefaultStyle.dp - icon.width: 28 * DefaultStyle.dp - icon.height: 28 * DefaultStyle.dp - onClicked: { - mainItem.editConference() - } - } - } - SearchBar { - id: searchBar - Layout.topMargin: 18 * DefaultStyle.dp - // Layout.fillWidth: true - //Layout.topMargin: 18 * DefaultStyle.dp - placeholderText: qsTr("Rechercher une réunion") - focusedBorderColor: DefaultStyle.main1_500_main - Layout.preferredWidth: 331 * DefaultStyle.dp - } - - Text { - Layout.topMargin: 38 * DefaultStyle.dp - Layout.fillHeight: true - Layout.alignment: Qt.AlignHCenter - text: mainItem.emptyListText - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - visible: mainItem.showDefaultItem - Binding on text { - when: searchBar.text.length !== 0 - value: qsTr("Aucune réunion correspondante") - restoreMode: Binding.RestoreBindingOrValue - } - } - - RowLayout { - // Remove 24 from first section padding because we cannot know that it is the first section. 24 is the margins between sections. - Layout.topMargin: 38 * DefaultStyle.dp - 24 * DefaultStyle.dp - spacing: 0 - MeetingList { - id: conferenceList - Layout.fillWidth: true + Layout.topMargin: 38 * DefaultStyle.dp Layout.fillHeight: true - visible: count != 0 - hoverEnabled: mainItem.leftPanelEnabled - searchBarText: searchBar.text - onSelectedConferenceChanged: { - mainItem.selectedConference = selectedConference + Layout.alignment: Qt.AlignHCenter + text: mainItem.emptyListText + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp } - Control.ScrollBar.vertical: ScrollBar { - id: meetingsScrollbar - anchors.right: parent.right - anchors.rightMargin: 8 * DefaultStyle.dp - active: true - interactive: true - policy: Control.ScrollBar.AsNeeded - + visible: mainItem.showDefaultItem + Binding on text { + when: searchBar.text.length !== 0 + value: qsTr("Aucune réunion correspondante") + restoreMode: Binding.RestoreBindingOrValue + } + } + RowLayout { + // Remove 24 from first section padding because we cannot know that it is the first section. 24 is the margins between sections. + Layout.topMargin: 38 * DefaultStyle.dp - 24 * DefaultStyle.dp + spacing: 0 + MeetingList { + id: conferenceList + Layout.fillWidth: true + Layout.fillHeight: true + visible: count != 0 + hoverEnabled: mainItem.leftPanelEnabled + highlightFollowsCurrentItem: true + preferredHighlightBegin: height/2 - 10 + preferredHighlightEnd: height/2 + 10 + highlightRangeMode: ListView.ApplyRange + searchBarText: searchBar.text + Keys.onPressed: (event) => { + if(event.key == Qt.Key_Escape){ + searchBar.forceActiveFocus() + event.accepted = true + }else if(event.key == Qt.Key_Right){ + overridenRightPanelStackView.currentItem.forceActiveFocus() + event.accepted = true + } + } + onSelectedConferenceChanged: { + mainItem.selectedConference = selectedConference + } + Control.ScrollBar.vertical: ScrollBar { + id: meetingsScrollbar + anchors.right: parent.right + anchors.rightMargin: 8 * DefaultStyle.dp + active: true + interactive: true + policy: Control.ScrollBar.AsNeeded + + } } } } @@ -219,101 +239,113 @@ AbstractMainPage { Component { id: createConf - ColumnLayout { + FocusScope{ id: createConfLayout property ConferenceInfoGui conferenceInfoGui property bool isCreation - spacing: 33 * DefaultStyle.dp - - RowLayout { - width: 320 * DefaultStyle.dp - Layout.rightMargin: 35 * DefaultStyle.dp - Button { - background: Item{} - icon.source: AppIcons.leftArrow - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - topPadding: 6 * DefaultStyle.dp - bottomPadding: 6 * DefaultStyle.dp - onClicked: { - meetingSetup.conferenceInfoGui.core.undo() - leftPanelStackView.pop() + ColumnLayout { + spacing: 33 * DefaultStyle.dp + + RowLayout { + width: 320 * DefaultStyle.dp + Layout.rightMargin: 35 * DefaultStyle.dp + spacing: 5 * DefaultStyle.dp + Button { + id: backButton + background: Item{} + icon.source: AppIcons.leftArrow + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + topPadding: 6 * DefaultStyle.dp + bottomPadding: 6 * DefaultStyle.dp + focus: true + KeyNavigation.right: createButton + KeyNavigation.down: meetingSetup + onClicked: { + meetingSetup.conferenceInfoGui.core.undo() + leftPanelStackView.pop() + } } - } - Text { - text: qsTr("Nouvelle réunion") - color: DefaultStyle.main2_700 - font { - pixelSize: 22 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - Layout.fillWidth: true - } - Button { - Layout.preferredWidth: 57 * DefaultStyle.dp - topPadding: 6 * DefaultStyle.dp - bottomPadding: 6 * DefaultStyle.dp - contentItem: Text { - text: qsTr("Créer") - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - + Text { + text: qsTr("Nouvelle réunion") + color: DefaultStyle.main2_700 font { - pixelSize: 13 * DefaultStyle.dp - weight: 600 * DefaultStyle.dp + pixelSize: 22 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp } - color: DefaultStyle.grey_0 + Layout.fillWidth: true } - onClicked: { - if (meetingSetup.conferenceInfoGui.core.subject.length === 0) { - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir un sujet"), false) - } else if (meetingSetup.conferenceInfoGui.core.duration <= 0) { - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La fin de la conférence doit être plus récente que son début"), false) - } else if (meetingSetup.conferenceInfoGui.core.participantCount === 0) { - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir au moins un participant"), false) - } else { - meetingSetup.conferenceInfoGui.core.save() - mainWindow.showLoadingPopup(qsTr("Création de la réunion en cours ..."), true) - } - } - } - } - MeetingSetUp { - id: meetingSetup - conferenceInfoGui: parent.conferenceInfoGui - isCreation: parent.isCreation - Layout.rightMargin: 35 * DefaultStyle.dp - Connections { - target: meetingSetup.conferenceInfoGui ? meetingSetup.conferenceInfoGui.core : null - function onConferenceSchedulerStateChanged() { - var mainWin = UtilsCpp.getMainWindow() - if (meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.AllocationPending - || meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Updating) { - mainWin.showLoadingPopup(qsTr("Création de la réunion en cours...")) - } else { - if (meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Error) { - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La création de la conférence a échoué"), false) + Button { + id: createButton + Layout.preferredWidth: 57 * DefaultStyle.dp + topPadding: 6 * DefaultStyle.dp + bottomPadding: 6 * DefaultStyle.dp + KeyNavigation.left: backButton + KeyNavigation.down: meetingSetup + contentItem: Text { + text: qsTr("Créer") + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + font { + pixelSize: 13 * DefaultStyle.dp + weight: 600 * DefaultStyle.dp + } + color: DefaultStyle.grey_0 + } + onClicked: { + if (meetingSetup.conferenceInfoGui.core.subject.length === 0) { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir un sujet"), false) + } else if (meetingSetup.conferenceInfoGui.core.duration <= 0) { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La fin de la conférence doit être plus récente que son début"), false) + } else if (meetingSetup.conferenceInfoGui.core.participantCount === 0) { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir au moins un participant"), false) + } else { + meetingSetup.conferenceInfoGui.core.save() + mainWindow.showLoadingPopup(qsTr("Création de la réunion en cours ..."), true) } - mainWin.closeLoadingPopup() } - createConfLayout.enabled = meetingSetup.conferenceInfoGui.core.schedulerState != LinphoneEnums.ConferenceSchedulerState.AllocationPending } } - onSaveSucceed: { - leftPanelStackView.pop() - UtilsCpp.showInformationPopup(qsTr("Nouvelle réunion"), qsTr("Réunion planifiée avec succès"), true) - mainWindow.closeLoadingPopup() - } - onAddParticipantsRequested: { - leftPanelStackView.push(addParticipants, {"conferenceInfoGui": conferenceInfoGui, "container": leftPanelStackView}) - } - Connections { - target: mainItem - function onAddParticipantsValidated(selectedParticipants) { - meetingSetup.conferenceInfoGui.core.resetParticipants(selectedParticipants) + MeetingSetUp { + id: meetingSetup + conferenceInfoGui: createConfLayout.conferenceInfoGui + isCreation: createConfLayout.isCreation + Layout.fillHeight: true + Layout.fillWidth: true + Layout.rightMargin: 35 * DefaultStyle.dp + Connections { + target: meetingSetup.conferenceInfoGui ? meetingSetup.conferenceInfoGui.core : null + function onConferenceSchedulerStateChanged() { + var mainWin = UtilsCpp.getMainWindow() + if (meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.AllocationPending + || meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Updating) { + mainWin.showLoadingPopup(qsTr("Création de la réunion en cours...")) + } else { + if (meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Error) { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La création de la conférence a échoué"), false) + } + mainWin.closeLoadingPopup() + } + createConfLayout.enabled = meetingSetup.conferenceInfoGui.core.schedulerState != LinphoneEnums.ConferenceSchedulerState.AllocationPending + } + } + onSaveSucceed: { leftPanelStackView.pop() + UtilsCpp.showInformationPopup(qsTr("Nouvelle réunion"), qsTr("Réunion planifiée avec succès"), true) + mainWindow.closeLoadingPopup() + } + onAddParticipantsRequested: { + leftPanelStackView.push(addParticipants, {"conferenceInfoGui": conferenceInfoGui, "container": leftPanelStackView}) + } + Connections { + target: mainItem + onAddParticipantsValidated: (selectedParticipants) => { + meetingSetup.conferenceInfoGui.core.resetParticipants(selectedParticipants) + leftPanelStackView.pop() + } } } } @@ -322,83 +354,107 @@ AbstractMainPage { Component { id: editConf - ColumnLayout { + FocusScope{ + id: editFocusScope property bool isCreation property ConferenceInfoGui conferenceInfoGui - Section { - content: RowLayout { - spacing: 10 * DefaultStyle.dp - Button { - background: Item{} - icon.source: AppIcons.leftArrow - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - onClicked: { - conferenceEdit.conferenceInfoGui.core.undo() - overridenRightPanelStackView.pop() + width : parent.width + height: editLayout.implicitHeight + ColumnLayout { + id: editLayout + anchors.fill: parent + spacing: 0 + Section { + content: RowLayout { + spacing: 10 * DefaultStyle.dp + Button { + id: backButton + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + icon.source: AppIcons.leftArrow + KeyNavigation.left: saveButton + KeyNavigation.right: titleText + KeyNavigation.down: conferenceEdit + KeyNavigation.up: conferenceEdit + onClicked: { + conferenceEdit.conferenceInfoGui.core.undo() + overridenRightPanelStackView.pop() + } + background: Item{} } - } - - TextField { - Component.onCompleted: text = mainItem.selectedConference.core.subject - color: DefaultStyle.main2_600 - font { - pixelSize: 20 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp + + TextField { + id: titleText + Layout.fillWidth: true + color: DefaultStyle.main2_600 + font { + pixelSize: 20 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + KeyNavigation.left: backButton + KeyNavigation.right: saveButton + KeyNavigation.down: conferenceEdit + KeyNavigation.up: conferenceEdit + onActiveFocusChanged: if(activeFocus==true) selectAll() + onEditingFinished: mainItem.selectedConference.core.subject = text + Component.onCompleted: text = mainItem.selectedConference.core.subject + background: Item{} } - background: Item{} - Layout.fillWidth: true - onActiveFocusChanged: if(activeFocus==true) selectAll() - onEditingFinished: mainItem.selectedConference.core.subject = text - } - Button { - topPadding: 6 * DefaultStyle.dp - bottomPadding: 6 * DefaultStyle.dp - leftPadding: 12 * DefaultStyle.dp - rightPadding: 12 * DefaultStyle.dp - text: qsTr("Save") - textSize: 13 * DefaultStyle.dp - onClicked: { - if (mainItem.selectedConference.core.subject.length === 0) { - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir un sujet"), false) - } else if (mainItem.selectedConference.core.duration <= 0) { - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La fin de la conférence doit être plus récente que son début"), false) - } else if (mainItem.selectedConference.core.participantCount === 0) { - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir au moins un participant"), false) - } else { - mainItem.selectedConference.core.save() + Button { + id: saveButton + topPadding: 6 * DefaultStyle.dp + bottomPadding: 6 * DefaultStyle.dp + leftPadding: 12 * DefaultStyle.dp + rightPadding: 12 * DefaultStyle.dp + focus: true + text: qsTr("Save") + textSize: 13 * DefaultStyle.dp + KeyNavigation.left: titleText + KeyNavigation.right: backButton + KeyNavigation.down: conferenceEdit + KeyNavigation.up: conferenceEdit + onClicked: { + if (mainItem.selectedConference.core.subject.length === 0) { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir un sujet"), false) + } else if (mainItem.selectedConference.core.duration <= 0) { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La fin de la conférence doit être plus récente que son début"), false) + } else if (mainItem.selectedConference.core.participantCount === 0) { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir au moins un participant"), false) + } else { + mainItem.selectedConference.core.save() + } } } } } - } - MeetingSetUp { - id: conferenceEdit - property bool isCreation - isCreation: parent.isCreation - conferenceInfoGui: parent.conferenceInfoGui - onSaveSucceed: { - overridenRightPanelStackView.pop() - UtilsCpp.showInformationPopup(qsTr("Enregistré"), qsTr("Réunion modifiée avec succès"), true) - } - onAddParticipantsRequested: { - overridenRightPanelStackView.push(addParticipants, {"conferenceInfoGui": conferenceInfoGui, "container": overridenRightPanelStackView}) - } - Connections { - target: mainItem - function onAddParticipantsValidated(selectedParticipants) { - conferenceEdit.conferenceInfoGui.core.resetParticipants(selectedParticipants) + MeetingSetUp { + id: conferenceEdit + property bool isCreation + isCreation: editFocusScope.isCreation + conferenceInfoGui: editFocusScope.conferenceInfoGui + onSaveSucceed: { overridenRightPanelStackView.pop() + UtilsCpp.showInformationPopup(qsTr("Enregistré"), qsTr("Réunion modifiée avec succès"), true) } - } - Connections { - target: conferenceEdit.conferenceInfoGui ? conferenceEdit.conferenceInfoGui.core : null - function onConferenceSchedulerStateChanged() { - var mainWin = UtilsCpp.getMainWindow() - if (conferenceEdit.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Error) { - UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("L'édition de la conférence a échoué"), false) + onAddParticipantsRequested: { + overridenRightPanelStackView.push(addParticipants, {"conferenceInfoGui": conferenceInfoGui, "container": overridenRightPanelStackView}) + } + Connections { + target: mainItem + function onAddParticipantsValidated(selectedParticipants) { + conferenceEdit.conferenceInfoGui.core.resetParticipants(selectedParticipants) + overridenRightPanelStackView.pop() + } + } + Connections { + target: conferenceEdit.conferenceInfoGui ? conferenceEdit.conferenceInfoGui.core : null + function onConferenceSchedulerStateChanged() { + var mainWin = UtilsCpp.getMainWindow() + if (conferenceEdit.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Error) { + UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("L'édition de la conférence a échoué"), false) + } } } } @@ -411,56 +467,71 @@ AbstractMainPage { ColumnLayout { property Control.StackView container property ConferenceInfoGui conferenceInfoGui - RowLayout { - Button { - background: Item{} - icon.source: AppIcons.leftArrow - contentImageColor: DefaultStyle.main1_500_main - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - onClicked: container.pop() - } - ColumnLayout { - spacing: 3 * DefaultStyle.dp - Text { - text: qsTr("Ajouter des participants") - color: DefaultStyle.main1_500_main - maximumLineCount: 1 - font { - pixelSize: 18 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - Layout.fillWidth: true + FocusScope{ + Layout.fillWidth: true + Layout.preferredHeight: addParticipantsButtons.implicitHeight + RowLayout { + id: addParticipantsButtons + spacing: 5 * DefaultStyle.dp + Button { + id: removeButton + background: Item{} + icon.source: AppIcons.leftArrow + contentImageColor: DefaultStyle.main1_500_main + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + KeyNavigation.right: addButton + KeyNavigation.down: addParticipantLayout + onClicked: container.pop() } - Text { - text: qsTr("%1 participant%2 sélectionné%2").arg(addParticipantLayout.selectedParticipantsCount).arg(addParticipantLayout.selectedParticipantsCount > 1 ? "s" : "") - color: DefaultStyle.main2_500main - maximumLineCount: 1 - font { - pixelSize: 12 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp + ColumnLayout { + spacing: 3 * DefaultStyle.dp + Text { + text: qsTr("Ajouter des participants") + color: DefaultStyle.main1_500_main + maximumLineCount: 1 + font { + pixelSize: 18 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + Layout.fillWidth: true + } + Text { + text: qsTr("%1 participant%2 sélectionné%2").arg(addParticipantLayout.selectedParticipantsCount).arg(addParticipantLayout.selectedParticipantsCount > 1 ? "s" : "") + color: DefaultStyle.main2_500main + maximumLineCount: 1 + font { + pixelSize: 12 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + Layout.fillWidth: true } - Layout.fillWidth: true } - } - Button { - enabled: addParticipantLayout.selectedParticipantsCount.length != 0 - Layout.rightMargin: 21 * DefaultStyle.dp - topPadding: 6 * DefaultStyle.dp - bottomPadding: 6 * DefaultStyle.dp - leftPadding: 12 * DefaultStyle.dp - rightPadding: 12 * DefaultStyle.dp - text: qsTr("Ajouter") - textSize: 13 * DefaultStyle.dp - onClicked: { - mainItem.addParticipantsValidated(addParticipantLayout.selectedParticipants) + Button { + id: addButton + enabled: addParticipantLayout.selectedParticipantsCount.length != 0 + Layout.rightMargin: 21 * DefaultStyle.dp + topPadding: 6 * DefaultStyle.dp + bottomPadding: 6 * DefaultStyle.dp + leftPadding: 12 * DefaultStyle.dp + rightPadding: 12 * DefaultStyle.dp + focus: enabled + text: qsTr("Ajouter") + textSize: 13 * DefaultStyle.dp + KeyNavigation.left: removeButton + KeyNavigation.down: addParticipantLayout + onClicked: { + mainItem.addParticipantsValidated(addParticipantLayout.selectedParticipants) + } } } } AddParticipantsLayout { id: addParticipantLayout + Layout.fillWidth: true + Layout.fillHeight: true conferenceInfoGui: parent.conferenceInfoGui } } @@ -468,48 +539,64 @@ AbstractMainPage { Component { id: meetingDetail - ColumnLayout { - visible: mainItem.selectedConference - spacing: 25 * DefaultStyle.dp - Section { - Layout.topMargin: 58 * DefaultStyle.dp + FocusScope{ + width: overridenRightPanelStackView.width + height: meetingDetailsLayout.implicitHeight + ColumnLayout { + id: meetingDetailsLayout + anchors.fill: parent visible: mainItem.selectedConference - content: RowLayout { - spacing: 8 * DefaultStyle.dp - Image { - source: AppIcons.usersThree - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - } - Text { - text: mainItem.selectedConference ? mainItem.selectedConference.core.subject : "" - font { - pixelSize: 20 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp + spacing: 25 * DefaultStyle.dp + Section { + Layout.topMargin: 58 * DefaultStyle.dp + visible: mainItem.selectedConference + content: RowLayout { + spacing: 8 * DefaultStyle.dp + Image { + source: AppIcons.usersThree + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp } - } - Item { - Layout.fillWidth: true - } - Button { - visible: mainItem.selectedConference && UtilsCpp.isMe(mainItem.selectedConference.core.organizerAddress) - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - icon.source: AppIcons.pencil - contentImageColor: DefaultStyle.main1_500_main - background: Item{} - onClicked: mainItem.editConference(mainItem.selectedConference) - } - PopupButton { - id: deletePopup - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - contentImageColor: DefaultStyle.main1_500_main - popup.contentItem: RowLayout { - Button { - background: Item{} + Text { + text: mainItem.selectedConference ? mainItem.selectedConference.core.subject : "" + font { + pixelSize: 20 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + Item { + Layout.fillWidth: true + } + Button { + id: editButton + visible: mainItem.selectedConference && UtilsCpp.isMe(mainItem.selectedConference.core.organizerAddress) + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + icon.source: AppIcons.pencil + contentImageColor: DefaultStyle.main1_500_main + KeyNavigation.left: leftPanelStackView.currentItem + KeyNavigation.right: deletePopup + KeyNavigation.up: joinButton + KeyNavigation.down: shareNetworkButton + background: Item{} + onClicked: mainItem.editConference(mainItem.selectedConference) + } + PopupButton { + id: deletePopup + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + contentImageColor: DefaultStyle.main1_500_main + KeyNavigation.left: editButton.visible ? editButton : leftPanelStackView.currentItem + KeyNavigation.right: leftPanelStackView.currentItem + KeyNavigation.up: joinButton + KeyNavigation.down: shareNetworkButton + + popup.contentItem: Button { + color: deletePopup.popupBackgroundColor + borderColor: deletePopup.popupBackgroundColor + inversedColors: true contentItem: RowLayout { EffectImage { imageSource: AppIcons.trashCan @@ -550,186 +637,209 @@ AbstractMainPage { } } } - } - Section { - content: ColumnLayout { - spacing: 15 * DefaultStyle.dp - width: parent.width - RowLayout { - spacing: 8 * DefaultStyle.dp - Layout.fillWidth: true - Image { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - source: AppIcons.videoCamera - } - Button { + Section { + content: ColumnLayout { + spacing: 15 * DefaultStyle.dp + width: parent.width + RowLayout { + spacing: 8 * DefaultStyle.dp Layout.fillWidth: true - text: mainItem.selectedConference ? mainItem.selectedConference.core.uri : "" - textSize: 14 * DefaultStyle.dp - textWeight: 400 * DefaultStyle.dp - underline: true - inversedColors: true - color: DefaultStyle.main2_600 - background: Item{} - onClicked: { - // TODO : voir si c'est en audio only quand on clique sur le lien - UtilsCpp.createCall(mainItem.selectedConference.core.uri) + Image { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + source: AppIcons.videoCamera + } + Button { + id: linkButton + Layout.fillWidth: true + font.bold: shadowEnabled + text: mainItem.selectedConference ? mainItem.selectedConference.core.uri : "" + textSize: 14 * DefaultStyle.dp + textWeight: 400 * DefaultStyle.dp + underline: true + inversedColors: true + color: DefaultStyle.main2_600 + background: Item{} + Keys.onPressed: (event)=> { + if (event.key == Qt.Key_Space || event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + clicked(undefined) + event.accepted = true; + } + } + KeyNavigation.left: shareNetworkButton + KeyNavigation.right: shareNetworkButton + KeyNavigation.up: deletePopup + KeyNavigation.down: joinButton + onClicked: { + // TODO : voir si c'est en audio only quand on clique sur le lien + UtilsCpp.createCall(mainItem.selectedConference.core.uri) + } + } + Button { + id: shareNetworkButton + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + icon.width: 24 * DefaultStyle.dp + icon.height: 24 * DefaultStyle.dp + background: Item{} + icon.source: AppIcons.shareNetwork + KeyNavigation.left: linkButton + KeyNavigation.right: linkButton + KeyNavigation.up: deletePopup + KeyNavigation.down: joinButton + onClicked: { + UtilsCpp.copyToClipboard(mainItem.selectedConference.core.uri) + UtilsCpp.showInformationPopup(qsTr("Enregistré"), qsTr("Le lien de la réunion a été copié dans le presse-papiers")) + } } } - Button { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - icon.width: 24 * DefaultStyle.dp - icon.height: 24 * DefaultStyle.dp - background: Item{} - icon.source: AppIcons.shareNetwork - onClicked: { - UtilsCpp.copyToClipboard(mainItem.selectedConference.core.uri) - UtilsCpp.showInformationPopup(qsTr("Enregistré"), qsTr("Le lien de la réunion a été copié dans le presse-papiers")) - } - } - } - RowLayout { - spacing: 8 * DefaultStyle.dp - Image { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - source: AppIcons.clock - } - Text { - text: mainItem.selectedConference - ? UtilsCpp.toDateString(mainItem.selectedConference.core.dateTimeUtc) - + " | " + UtilsCpp.toDateHourString(mainItem.selectedConference.core.dateTimeUtc) - + " - " - + UtilsCpp.toDateHourString(mainItem.selectedConference.core.endDateTime) - : '' - font { - pixelSize: 14 * DefaultStyle.dp - capitalization: Font.Capitalize - } - } - } - RowLayout { - spacing: 8 * DefaultStyle.dp - Image { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - source: AppIcons.globe - } - Text { - text: qsTr("Time zone: ") + (mainItem.selectedConference ? (mainItem.selectedConference.core.timeZoneModel.displayName + ", " + mainItem.selectedConference.core.timeZoneModel.countryName) : "") - font { - pixelSize: 14 * DefaultStyle.dp - capitalization: Font.Capitalize - } - } - } - } - } - Section { - visible: mainItem.selectedConference && mainItem.selectedConference.core.description.length != 0 - content: RowLayout { - spacing: 8 * DefaultStyle.dp - EffectImage { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - imageSource: AppIcons.note - colorizationColor: DefaultStyle.main2_600 - } - Text { - text: mainItem.selectedConference ? mainItem.selectedConference.core.description : "" - Layout.fillWidth: true - font { - pixelSize: 14 * DefaultStyle.dp - capitalization: Font.Capitalize - } - } - } - } - Section { - content: RowLayout { - spacing: 8 * DefaultStyle.dp - EffectImage { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - imageSource: AppIcons.userRectangle - colorizationColor: DefaultStyle.main2_600 - } - Avatar { - Layout.preferredWidth: 45 * DefaultStyle.dp - Layout.preferredHeight: 45 * DefaultStyle.dp - address: mainItem.selectedConference ? mainItem.selectedConference.core.organizerAddress : "" - } - Text { - text: mainItem.selectedConference ? mainItem.selectedConference.core.organizerName : "" - font { - pixelSize: 14 * DefaultStyle.dp - capitalization: Font.Capitalize - } - } - } - } - Section { - content: RowLayout { - Layout.preferredHeight: participantList.height - width: 393 * DefaultStyle.dp - spacing: 8 * DefaultStyle.dp - Image { - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - Layout.alignment: Qt.AlignLeft | Qt.AlignTop - Layout.topMargin: 20 * DefaultStyle.dp - source: AppIcons.usersTwo - } - ListView { - id: participantList - Layout.preferredHeight: Math.min(184 * DefaultStyle.dp, contentHeight) - Layout.fillWidth: true - model: mainItem.selectedConference ? mainItem.selectedConference.core.participants : [] - clip: true - delegate: RowLayout { - height: 56 * DefaultStyle.dp - width: participantList.width - Avatar { - Layout.preferredWidth: 45 * DefaultStyle.dp - Layout.preferredHeight: 45 * DefaultStyle.dp - address: modelData.address + RowLayout { + spacing: 8 * DefaultStyle.dp + Image { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + source: AppIcons.clock } Text { - text: modelData.displayName - Layout.fillWidth: true + text: mainItem.selectedConference + ? UtilsCpp.toDateString(mainItem.selectedConference.core.dateTimeUtc) + + " | " + UtilsCpp.toDateHourString(mainItem.selectedConference.core.dateTimeUtc) + + " - " + + UtilsCpp.toDateHourString(mainItem.selectedConference.core.endDateTime) + : '' font { pixelSize: 14 * DefaultStyle.dp capitalization: Font.Capitalize } } + } + RowLayout { + spacing: 8 * DefaultStyle.dp + Image { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + source: AppIcons.globe + } Text { - text: qsTr("Organizer") - visible: mainItem.selectedConference && mainItem.selectedConference.core.organizerAddress === modelData.address - color: DefaultStyle.main2_400 + text: qsTr("Time zone: ") + (mainItem.selectedConference ? (mainItem.selectedConference.core.timeZoneModel.displayName + ", " + mainItem.selectedConference.core.timeZoneModel.countryName) : "") font { - pixelSize: 12 * DefaultStyle.dp - weight: 300 * DefaultStyle.dp + pixelSize: 14 * DefaultStyle.dp + capitalization: Font.Capitalize } } } } } - } - Button { - Layout.fillWidth: true - text: qsTr("Rejoindre la réunion") - topPadding: 11 * DefaultStyle.dp - bottomPadding: 11 * DefaultStyle.dp - onClicked: { - console.log(mainItem.selectedConference.core.uri) - var callsWindow = UtilsCpp.getCallsWindow() - callsWindow.setupConference(mainItem.selectedConference) - callsWindow.show() + Section { + visible: mainItem.selectedConference && mainItem.selectedConference.core.description.length != 0 + content: RowLayout { + spacing: 8 * DefaultStyle.dp + EffectImage { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + imageSource: AppIcons.note + colorizationColor: DefaultStyle.main2_600 + } + Text { + text: mainItem.selectedConference ? mainItem.selectedConference.core.description : "" + Layout.fillWidth: true + font { + pixelSize: 14 * DefaultStyle.dp + capitalization: Font.Capitalize + } + } + } } + Section { + content: RowLayout { + spacing: 8 * DefaultStyle.dp + EffectImage { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + imageSource: AppIcons.userRectangle + colorizationColor: DefaultStyle.main2_600 + } + Avatar { + Layout.preferredWidth: 45 * DefaultStyle.dp + Layout.preferredHeight: 45 * DefaultStyle.dp + address: mainItem.selectedConference ? mainItem.selectedConference.core.organizerAddress : "" + } + Text { + text: mainItem.selectedConference ? mainItem.selectedConference.core.organizerName : "" + font { + pixelSize: 14 * DefaultStyle.dp + capitalization: Font.Capitalize + } + } + } + } + Section { + content: RowLayout { + Layout.preferredHeight: participantList.height + width: 393 * DefaultStyle.dp + spacing: 8 * DefaultStyle.dp + Image { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.topMargin: 20 * DefaultStyle.dp + source: AppIcons.usersTwo + } + ListView { + id: participantList + Layout.preferredHeight: Math.min(184 * DefaultStyle.dp, contentHeight) + Layout.fillWidth: true + model: mainItem.selectedConference ? mainItem.selectedConference.core.participants : [] + clip: true + delegate: RowLayout { + height: 56 * DefaultStyle.dp + width: participantList.width + Avatar { + Layout.preferredWidth: 45 * DefaultStyle.dp + Layout.preferredHeight: 45 * DefaultStyle.dp + address: modelData.address + } + Text { + text: modelData.displayName + Layout.fillWidth: true + font { + pixelSize: 14 * DefaultStyle.dp + capitalization: Font.Capitalize + } + } + Text { + text: qsTr("Organizer") + visible: mainItem.selectedConference && mainItem.selectedConference.core.organizerAddress === modelData.address + color: DefaultStyle.main2_400 + font { + pixelSize: 12 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } + } + } + } + } + } + Button { + id: joinButton + Layout.fillWidth: true + text: qsTr("Rejoindre la réunion") + topPadding: 11 * DefaultStyle.dp + bottomPadding: 11 * DefaultStyle.dp + focus: true + KeyNavigation.up: shareNetworkButton + KeyNavigation.down: deletePopup + KeyNavigation.left: leftPanelStackView.currentItem + KeyNavigation.right: leftPanelStackView.currentItem + onClicked: { + console.log(mainItem.selectedConference.core.uri) + var callsWindow = UtilsCpp.getCallsWindow() + callsWindow.setupConference(mainItem.selectedConference) + callsWindow.show() + } + } + Item { Layout.fillHeight: true} } - Item { Layout.fillHeight: true} } } }