From b6ac70d6275de855098afbcc5bdb158c47582aee Mon Sep 17 00:00:00 2001 From: gaelle <gaelle.braud@belledonne-communications.com> Date: Tue, 25 Feb 2025 17:19:56 +0100 Subject: [PATCH] fix close calls window on last call finished --- .../view/Page/Window/Call/CallsWindow.qml | 2731 +++++++++-------- 1 file changed, 1397 insertions(+), 1334 deletions(-) diff --git a/Linphone/view/Page/Window/Call/CallsWindow.qml b/Linphone/view/Page/Window/Call/CallsWindow.qml index 9f050daf5..847396666 100644 --- a/Linphone/view/Page/Window/Call/CallsWindow.qml +++ b/Linphone/view/Page/Window/Call/CallsWindow.qml @@ -7,1366 +7,1429 @@ import EnumsToStringCpp import UtilsCpp import SettingsCpp import DesktopToolsCpp -import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle +import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle AbstractWindow { id: mainWindow - flags: Qt.Window - // modality: Qt.WindowModal + flags: Qt.Window - property CallGui call + // modality: Qt.WindowModal + property CallGui call - property ConferenceGui conference: call && call.core.conference || null - property bool isConference: call ? call.core.isConference : false + property ConferenceGui conference: call && call.core.conference || null + property bool isConference: call ? call.core.isConference : false - property int conferenceLayout: call && call.core.conferenceVideoLayout || 0 - property bool localVideoEnabled: call && call.core.localVideoEnabled - property bool remoteVideoEnabled: call && call.core.remoteVideoEnabled + property int conferenceLayout: call && call.core.conferenceVideoLayout || 0 + property bool localVideoEnabled: call && call.core.localVideoEnabled + property bool remoteVideoEnabled: call && call.core.remoteVideoEnabled - property bool callTerminatedByUser: false - property var callState: call ? call.core.state : LinphoneEnums.CallState.Idle - property var transferState: call && call.core.transferState + property bool callTerminatedByUser: false + property var callState: call ? call.core.state : LinphoneEnums.CallState.Idle + property var transferState: call && call.core.transferState - onCallStateChanged: { - if (callState === LinphoneEnums.CallState.Connected) { - if (middleItemStackView.currentItem.objectName != "inCallItem") { - middleItemStackView.replace(inCallItem) - bottomButtonsLayout.visible = true - } - if(call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp && !mainWindow.isConference && (!call.core.tokenVerified || call.core.isMismatch)) { - zrtpValidation.open() - } - } - else if (callState === LinphoneEnums.CallState.Error || callState === LinphoneEnums.CallState.End) { - zrtpValidation.close() - callEnded(call) - } - } + onCallStateChanged: { + if (callState === LinphoneEnums.CallState.Connected) { + if (middleItemStackView.currentItem.objectName != "inCallItem") { + middleItemStackView.replace(inCallItem) + bottomButtonsLayout.visible = true + } + if (call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp + && !mainWindow.isConference && (!call.core.tokenVerified + || call.core.isMismatch)) { + zrtpValidation.open() + } + } else if (callState === LinphoneEnums.CallState.Error + || callState === LinphoneEnums.CallState.End) { + zrtpValidation.close() + callEnded(call) + } + } - onTransferStateChanged: { - console.log("Transfer state:", transferState) - if (mainWindow.transferState === LinphoneEnums.CallState.OutgoingInit) { - var callsWin = UtilsCpp.getCallsWindow() - if (!callsWin) return - callsWin.showLoadingPopup(qsTr("Transfert en cours, veuillez patienter")) - } - else if (mainWindow.transferState === LinphoneEnums.CallState.Error - || mainWindow.transferState === LinphoneEnums.CallState.End - || mainWindow.transferState === LinphoneEnums.CallState.Released - || mainWindow.transferState === LinphoneEnums.CallState.Connected) { - var callsWin = UtilsCpp.getCallsWindow() - callsWin.closeLoadingPopup() - if (transferState === LinphoneEnums.CallState.Error) UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Le transfert d'appel a échoué"), false, mainWindow) - else if (transferState === LinphoneEnums.CallState.Connected){ - var mainWin = UtilsCpp.getMainWindow() - UtilsCpp.smartShowWindow(mainWin) - mainWin.transferCallSucceed() - } - } - } - onClosing: (close) => { - DesktopToolsCpp.screenSaverStatus = true - if (callsModel.haveCall) { - close.accepted = false - terminateAllCallsDialog.open() - } - if (middleItemStackView.currentItem.objectName === "waitingRoom") middleItemStackView.replace(inCallItem) - } + onTransferStateChanged: { + console.log("Transfer state:", transferState) + if (mainWindow.transferState === LinphoneEnums.CallState.OutgoingInit) { + var callsWin = UtilsCpp.getCallsWindow() + if (!callsWin) + return + callsWin.showLoadingPopup( + qsTr("Transfert en cours, veuillez patienter")) + } else if (mainWindow.transferState === LinphoneEnums.CallState.Error + || mainWindow.transferState === LinphoneEnums.CallState.End + || mainWindow.transferState === LinphoneEnums.CallState.Released + || mainWindow.transferState === LinphoneEnums.CallState.Connected) { + var callsWin = UtilsCpp.getCallsWindow() + callsWin.closeLoadingPopup() + if (transferState === LinphoneEnums.CallState.Error) + UtilsCpp.showInformationPopup( + qsTr("Erreur"), + qsTr("Le transfert d'appel a échoué"), false, + mainWindow) + else if (transferState === LinphoneEnums.CallState.Connected) { + var mainWin = UtilsCpp.getMainWindow() + UtilsCpp.smartShowWindow(mainWin) + mainWin.transferCallSucceed() + } + } + } + onClosing: close => { + DesktopToolsCpp.screenSaverStatus = true + if (callsModel.haveCall) { + close.accepted = false + terminateAllCallsDialog.open() + } + if (middleItemStackView.currentItem.objectName === "waitingRoom") + middleItemStackView.replace(inCallItem) + } - function changeLayout(layoutIndex) { - if (layoutIndex == 0) { - console.log("Set Grid layout") - call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.Grid) - } else if (layoutIndex == 1) { - console.log("Set AS layout") - call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.ActiveSpeaker) - } else { - console.log("Set audio-only layout") - call.core.lSetConferenceVideoLayout(LinphoneEnums.ConferenceLayout.AudioOnly) - } - } - - function endCall(callToFinish) { - if (callToFinish) callToFinish.core.lTerminate() - // var mainWin = UtilsCpp.getMainWindow() - // mainWin.goToCallHistory() - } - function callEnded(call){ - if (call.core.state === LinphoneEnums.CallState.Error) { - middleItemStackView.replace(inCallItem) - } - if (!callsModel.haveCall) { - if (call && call.core.isConference) UtilsCpp.closeCallsWindow() - else { - bottomButtonsLayout.setButtonsEnabled(false) - autoCloseWindow.restart() - } - } else { - if (middleItemStackView.currentItem.objectName === "waitingRoom") { - middleItemStackView.replace(inCallItem) - } - mainWindow.call = callsModel.currentCall - } - } + function changeLayout(layoutIndex) { + if (layoutIndex == 0) { + console.log("Set Grid layout") + call.core.lSetConferenceVideoLayout( + LinphoneEnums.ConferenceLayout.Grid) + } else if (layoutIndex == 1) { + console.log("Set AS layout") + call.core.lSetConferenceVideoLayout( + LinphoneEnums.ConferenceLayout.ActiveSpeaker) + } else { + console.log("Set audio-only layout") + call.core.lSetConferenceVideoLayout( + LinphoneEnums.ConferenceLayout.AudioOnly) + } + } - signal setUpConferenceRequested(ConferenceInfoGui conferenceInfo) - function setupConference(conferenceInfo) { - middleItemStackView.replace(waitingRoom) - setUpConferenceRequested(conferenceInfo) - } + function endCall(callToFinish) { + if (callToFinish) + callToFinish.core.lTerminate() + // var mainWin = UtilsCpp.getMainWindow() + // mainWin.goToCallHistory() + } + function callEnded(call) { + if (call.core.state === LinphoneEnums.CallState.Error) { + middleItemStackView.replace(inCallItem) + } + if (!callsModel.haveCall) { + if (call && call.core.isConference) + UtilsCpp.closeCallsWindow() + else { + bottomButtonsLayout.setButtonsEnabled(false) + autoCloseWindow.restart() + } + } else { + if (middleItemStackView.currentItem.objectName === "waitingRoom") { + middleItemStackView.replace(inCallItem) + } + mainWindow.call = callsModel.currentCall + } + } - function joinConference(uri, options) { - if (uri.length === 0) UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence n'a pas pu démarrer en raison d'une erreur d'uri."), mainWindow) - else { - UtilsCpp.createCall(uri, options) - } - } - function cancelJoinConference() { - if (!callsModel.haveCall) { - UtilsCpp.closeCallsWindow() - } else { - mainWindow.call = callsModel.currentCall - } - middleItemStackView.replace(inCallItem) - } - function cancelAfterJoin() { - endCall(mainWindow.call) - } - - Connections { - enabled: !!mainWindow.call - target: mainWindow.call && mainWindow.call.core - function onSecurityUpdated() { - if (mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) { - if (call.core.tokenVerified) { - zrtpValidation.close() - zrtpValidationToast.open() - } else { - zrtpValidation.open() - } - } else { - zrtpValidation.close() - } - } - function onTokenVerified() { - if (!zrtpValidation.isTokenVerified) { - zrtpValidation.securityError = true - } else zrtpValidation.close() - } - } - - Timer { - id: autoCloseWindow - interval: mainWindow.callTerminatedByUser ? 1000 : 2000 - onTriggered: { - UtilsCpp.closeCallsWindow() - } - } + signal setUpConferenceRequested(ConferenceInfoGui conferenceInfo) + function setupConference(conferenceInfo) { + middleItemStackView.replace(waitingRoom) + setUpConferenceRequested(conferenceInfo) + } - Dialog { - id: terminateAllCallsDialog - onAccepted: { - mainWindow.callTerminatedByUser = true - call.core.lTerminateAllCalls() - } - width: 278 * DefaultStyle.dp - text: qsTr("La fenêtre est sur le point d'être fermée. Cela terminera tous les appels en cours. Souhaitez vous continuer ?") - } + function joinConference(uri, options) { + if (uri.length === 0) + UtilsCpp.showInformationPopup( + qsTr("Erreur"), qsTr( + "La conférence n'a pas pu démarrer en raison d'une erreur d'uri."), + mainWindow) + else { + UtilsCpp.createCall(uri, options) + } + } + function cancelJoinConference() { + if (!callsModel.haveCall) { + UtilsCpp.closeCallsWindow() + } else { + mainWindow.call = callsModel.currentCall + } + middleItemStackView.replace(inCallItem) + } + function cancelAfterJoin() { + endCall(mainWindow.call) + } - CallProxy{ - id: callsModel - sourceModel: AppCpp.calls - onCurrentCallChanged: { - if(currentCall) { - mainWindow.call = currentCall - } - } - onHaveCallChanged: { - if (!haveCall) { - mainWindow.endCall() - } - } - } + Connections { + enabled: !!mainWindow.call + target: mainWindow.call && mainWindow.call.core + function onSecurityUpdated() { + if (mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) { + if (call.core.tokenVerified) { + zrtpValidation.close() + zrtpValidationToast.open() + } else { + zrtpValidation.open() + } + } else { + zrtpValidation.close() + } + } + function onTokenVerified() { + if (!zrtpValidation.isTokenVerified) { + zrtpValidation.securityError = true + } else + zrtpValidation.close() + } + } - component BottomButton : Button { - id: bottomButton - required property string enabledIcon - property string disabledIcon - enabled: call != undefined - leftPadding: 0 - rightPadding: 0 - topPadding: 0 - bottomPadding: 0 - checkable: true - background: Rectangle { - anchors.fill: parent - color: bottomButton.enabled - ? disabledIcon - ? DefaultStyle.grey_500 - : bottomButton.pressed || bottomButton.checked - ? DefaultStyle.main2_400 - : DefaultStyle.grey_500 - : DefaultStyle.grey_600 - radius: 71 * DefaultStyle.dp - } - icon.source: disabledIcon && bottomButton.checked ? disabledIcon : enabledIcon - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - contentImageColor: DefaultStyle.grey_0 - } - ZrtpAuthenticationDialog { - id: zrtpValidation - call: mainWindow.call - modal: true - closePolicy: Popup.NoAutoClose - } - Timer { - id: autoCloseZrtpToast - interval: 4000 - onTriggered: { - zrtpValidationToast.y = -zrtpValidationToast.height*2 - } - } - Control.Control { - id: zrtpValidationToast - // width: 269 * DefaultStyle.dp - y: -height*2 - z: 1 - topPadding: 8 * DefaultStyle.dp - bottomPadding: 8 * DefaultStyle.dp - leftPadding: 50 * DefaultStyle.dp - rightPadding: 50 * DefaultStyle.dp - anchors.horizontalCenter: parent.horizontalCenter - clip: true - function open() { - if (mainWindow.isConference) return - y = headerItem.height/2 - autoCloseZrtpToast.restart() - } - Behavior on y {NumberAnimation {duration: 1000}} - background: Rectangle { - anchors.fill: parent - color: DefaultStyle.grey_0 - border.color: DefaultStyle.info_500_main - border.width: 1 * DefaultStyle.dp - radius: 50 * DefaultStyle.dp - } - contentItem: RowLayout { - // anchors.centerIn: parent - Image { - source: AppIcons.trusted - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - fillMode: Image.PreserveAspectFit - Layout.fillWidth: true - } - Text { - color: DefaultStyle.info_500_main - text: qsTr("Appareil vérifié") - Layout.fillWidth: true - font { - pixelSize: 14 * DefaultStyle.dp - } - } - } - } + Timer { + id: autoCloseWindow + interval: mainWindow.callTerminatedByUser ? 1000 : 2000 + onTriggered: { + UtilsCpp.closeCallsWindow() + } + } -/************************* CONTENT ********************************/ - - Rectangle { - anchors.fill: parent - color: DefaultStyle.grey_900 - Keys.onEscapePressed: { - if(mainWindow.visibility == Window.FullScreen) mainWindow.showNormal() - } - - ColumnLayout { - anchors.fill: parent - spacing: 10 * DefaultStyle.dp - anchors.bottomMargin: 10 * DefaultStyle.dp - anchors.topMargin: 10 * DefaultStyle.dp - Item { - id: headerItem - Layout.margins: 10 * DefaultStyle.dp - Layout.leftMargin: 20 * DefaultStyle.dp - Layout.fillWidth: true - Layout.minimumHeight: 25 * DefaultStyle.dp - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: 10 * DefaultStyle.dp - RowLayout { - spacing: 10 * DefaultStyle.dp - EffectImage { - id: callStatusIcon - Layout.preferredWidth: 30 * DefaultStyle.dp - Layout.preferredHeight: 30 * DefaultStyle.dp - // TODO : change with broadcast or meeting icon when available - imageSource: !mainWindow.call - ? AppIcons.meeting - : (mainWindow.callState === LinphoneEnums.CallState.End - || mainWindow.callState === LinphoneEnums.CallState.Released) - ? AppIcons.endCall - : (mainWindow.callState === LinphoneEnums.CallState.Paused - || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) - ? AppIcons.pause - : mainWindow.conference - ? AppIcons.usersThree - : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing - ? AppIcons.arrowUpRight - : AppIcons.arrowDownLeft - colorizationColor: !mainWindow.call || mainWindow.call.core.paused || mainWindow.callState === LinphoneEnums.CallState.Paused - || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote || mainWindow.callState === LinphoneEnums.CallState.End - || mainWindow.callState === LinphoneEnums.CallState.Released || mainWindow.conference - ? DefaultStyle.danger_500main - : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing - ? DefaultStyle.info_500_main - : DefaultStyle.success_500main - onColorizationColorChanged: { - callStatusIcon.active = !callStatusIcon.active - callStatusIcon.active = !callStatusIcon.active - } - } - ColumnLayout { - spacing: 6 * DefaultStyle.dp - RowLayout { - spacing: 10 * DefaultStyle.dp - Text { - id: callStatusText - property string remoteName: mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning - ? mainWindow.call.core.remoteName - : qsTr("Appel %1").arg(mainWindow.call ? EnumsToStringCpp.dirToString(mainWindow.call.core.dir) : "") - text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released) - ? qsTr("Fin d'appel") - : mainWindow.call && (mainWindow.call.core.paused - || (mainWindow.callState === LinphoneEnums.CallState.Paused - || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote)) - ? (mainWindow.conference ? qsTr('Réunion mise ') : qsTr('Appel mis')) + qsTr(" en pause") - : mainWindow.conference - ? mainWindow.conference.core.subject - : remoteName - color: DefaultStyle.grey_0 - font { - pixelSize: 22 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - } - Rectangle { - visible: mainWindow.call && (mainWindow.callState === LinphoneEnums.CallState.Connected - || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) - Layout.fillHeight: true - Layout.topMargin: 10 * DefaultStyle.dp - Layout.bottomMargin: 2 * DefaultStyle.dp - Layout.preferredWidth: 2 * DefaultStyle.dp - color: DefaultStyle.grey_0 - } - Text { - text: mainWindow.call ? UtilsCpp.formatElapsedTime(mainWindow.call.core.duration) : "" - color: DefaultStyle.grey_0 - font { - pixelSize: 22 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - visible: mainWindow.callState === LinphoneEnums.CallState.Connected - || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning - } - Text { - Layout.leftMargin: 14 * DefaultStyle.dp - id: conferenceDate - text: mainWindow.conferenceInfo ? mainWindow.conferenceInfo.core.getStartEndDateString() : "" - color: DefaultStyle.grey_0 - font { - pixelSize: 14 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - capitalization: Font.Capitalize - } - } - } - RowLayout { - id: securityStateLayout - spacing: 5 * DefaultStyle.dp - visible: false - Connections { - target: mainWindow - function onCallStateChanged() { - if (mainWindow.callState === LinphoneEnums.CallState.Connected) securityStateLayout.visible = true - else if (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released) securityStateLayout.visible = false - } - } - BusyIndicator { - visible: mainWindow.call && mainWindow.callState != LinphoneEnums.CallState.Connected && mainWindow.callState != LinphoneEnums.CallState.StreamsRunning - Layout.preferredWidth: 15 * DefaultStyle.dp - Layout.preferredHeight: 15 * DefaultStyle.dp - indicatorColor: DefaultStyle.grey_0 - } - EffectImage { - Layout.preferredWidth: 15 * DefaultStyle.dp - Layout.preferredHeight: 15 * DefaultStyle.dp - colorizationColor: mainWindow.call - ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp - ? DefaultStyle.info_500_main - : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp - ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified - ? DefaultStyle.warning_600 - : DefaultStyle.info_500_main - : DefaultStyle.grey_0 - : "transparent" - visible: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning - imageSource: mainWindow.call - ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp + Dialog { + id: terminateAllCallsDialog + onAccepted: { + mainWindow.callTerminatedByUser = true + call.core.lTerminateAllCalls() + } + width: 278 * DefaultStyle.dp + text: qsTr("La fenêtre est sur le point d'être fermée. Cela terminera tous les appels en cours. Souhaitez vous continuer ?") + } - ? AppIcons.lockSimple - : mainWindow.call && mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp - ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified - ? AppIcons.warningCircle - : AppIcons.lockKey - : AppIcons.lockSimpleOpen - : "" - } - Text { - text: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning - ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp - ? qsTr("Appel chiffré de point à point") - : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp - ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified - ? qsTr("Vérification nécessaire") - : qsTr("Appel chiffré de bout en bout") - : qsTr("Appel non chiffré") - : qsTr("En attente de chiffrement") - color: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning - ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp - ? DefaultStyle.info_500_main - : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp - ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified - ? DefaultStyle.warning_600 - : DefaultStyle.info_500_main - : DefaultStyle.grey_0 - : DefaultStyle.grey_0 - font { - pixelSize: 12 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: { - rightPanel.visible = true - rightPanel.replace(encryptionPanel) - } - } - } - Item { - Layout.fillWidth: true - } - } - } - - } - Item { - Layout.fillWidth: true - } - EffectImage { - Layout.preferredWidth: 32 * DefaultStyle.dp - Layout.preferredHeight: 32 * DefaultStyle.dp - Layout.rightMargin: 30 * DefaultStyle.dp - property int quality: mainWindow.call ? mainWindow.call.core.quality : 0 - imageSource: quality >= 4 - ? AppIcons.cellSignalFull - : quality >= 3 - ? AppIcons.cellSignalMedium - : quality >= 2 - ? AppIcons.cellSignalLow - : AppIcons.cellSignalNone - colorizationColor: DefaultStyle.grey_0 - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: { - if (rightPanel.visible && rightPanel.contentStackView.currentItem.objectName === "statsPanel") rightPanel.visible = false - else { - rightPanel.visible = true - rightPanel.replace(statsPanel) - } - } - } - } - } + CallProxy { + id: callsModel + sourceModel: AppCpp.calls + onCurrentCallChanged: { + if (currentCall) { + mainWindow.call = currentCall + } + } + onHaveCallChanged: { + if (!haveCall) { + mainWindow.callEnded() + } + } + } - Control.Control { - visible: mainWindow.call - ? !!mainWindow.conference - ? mainWindow.conference.core.isRecording - : (mainWindow.call.core.recording || mainWindow.call.core.remoteRecording) - : false - anchors.centerIn: parent - leftPadding: 14 * DefaultStyle.dp - rightPadding: 14 * DefaultStyle.dp - topPadding: 6 * DefaultStyle.dp - bottomPadding: 6 * DefaultStyle.dp - background: Rectangle { - anchors.fill: parent - color: DefaultStyle.grey_500 - radius: 10 * DefaultStyle.dp - } - contentItem: RowLayout { - spacing: 85 * DefaultStyle.dp - RowLayout { - spacing: 15 * DefaultStyle.dp - EffectImage { - imageSource: AppIcons.recordFill - colorizationColor: DefaultStyle.danger_500main - Layout.preferredWidth: 24 * DefaultStyle.dp - Layout.preferredHeight: 24 * DefaultStyle.dp - } - Text { - color: DefaultStyle.danger_500main - font.pixelSize: 14 * DefaultStyle.dp - text: mainWindow.call - ? mainWindow.call.core.recording - ? mainWindow.conference ? qsTr("Vous enregistrez la réunion") : qsTr("Vous enregistrez l'appel") - : mainWindow.conference ? qsTr("Un participant enregistre la réunion") : qsTr("Votre correspondant enregistre l'appel") - : "" - } - } - BigButton { - visible: mainWindow.call && mainWindow.call.core.recording - text: qsTr("Arrêter l'enregistrement") - style: ButtonStyle.main - onPressed: mainWindow.call.core.lStopRecording() - } - } - } - - } - - RowLayout { - Layout.fillWidth: true - Layout.fillHeight: true - spacing: 23 * DefaultStyle.dp - Control.StackView { - id: middleItemStackView - initialItem: inCallItem - Layout.fillWidth: true - Layout.fillHeight: true - } - CallSettingsPanel { - id: rightPanel - Layout.fillHeight: true - Layout.rightMargin: 20 * DefaultStyle.dp - Layout.preferredWidth: 393 * DefaultStyle.dp - Layout.topMargin: 10 * DefaultStyle.dp - property int currentIndex: 0 - visible: false - function replace(id) { - rightPanel.customHeaderButtons = null - contentStackView.replace(id, Control.StackView.Immediate) - } - headerStack.currentIndex: 0 - contentStackView.initialItem: callListPanel - headerValidateButtonText: qsTr("Ajouter") + component BottomButton: Button { + id: bottomButton + required property string enabledIcon + property string disabledIcon + enabled: call != undefined + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + checkable: true + background: Rectangle { + anchors.fill: parent + color: bottomButton.enabled ? disabledIcon ? DefaultStyle.grey_500 : bottomButton.pressed || bottomButton.checked ? DefaultStyle.main2_400 : DefaultStyle.grey_500 : DefaultStyle.grey_600 + radius: 71 * DefaultStyle.dp + } + icon.source: disabledIcon + && bottomButton.checked ? disabledIcon : enabledIcon + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + contentImageColor: DefaultStyle.grey_0 + } + ZrtpAuthenticationDialog { + id: zrtpValidation + call: mainWindow.call + modal: true + closePolicy: Popup.NoAutoClose + } + Timer { + id: autoCloseZrtpToast + interval: 4000 + onTriggered: { + zrtpValidationToast.y = -zrtpValidationToast.height * 2 + } + } + Control.Control { + id: zrtpValidationToast + // width: 269 * DefaultStyle.dp + y: -height * 2 + z: 1 + topPadding: 8 * DefaultStyle.dp + bottomPadding: 8 * DefaultStyle.dp + leftPadding: 50 * DefaultStyle.dp + rightPadding: 50 * DefaultStyle.dp + anchors.horizontalCenter: parent.horizontalCenter + clip: true + function open() { + if (mainWindow.isConference) + return + y = headerItem.height / 2 + autoCloseZrtpToast.restart() + } + Behavior on y { + NumberAnimation { + duration: 1000 + } + } + background: Rectangle { + anchors.fill: parent + color: DefaultStyle.grey_0 + border.color: DefaultStyle.info_500_main + border.width: 1 * DefaultStyle.dp + radius: 50 * DefaultStyle.dp + } + contentItem: RowLayout { + // anchors.centerIn: parent + Image { + source: AppIcons.trusted + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + fillMode: Image.PreserveAspectFit + Layout.fillWidth: true + } + Text { + color: DefaultStyle.info_500_main + text: qsTr("Appareil vérifié") + Layout.fillWidth: true + font { + pixelSize: 14 * DefaultStyle.dp + } + } + } + } - Item { - id: numericPadContainer - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - height: childrenRect.height - } - } - } - - - Component { - id: callTransferPanel - NewCallForm { - id: newCallForm - Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Transférer %1 à :").arg(mainWindow.call.core.remoteName) - Keys.onEscapePressed: (event) => { - rightPanel.visible = false - event.accepted = true - } - groupCallVisible: false - displayCurrentCalls: true - searchBarColor: DefaultStyle.grey_0 - searchBarBorderColor: DefaultStyle.grey_200 - onContactClicked: (contact) => { - var callsWin = UtilsCpp.getCallsWindow() - if (contact) callsWin.showConfirmationLambdaPopup( - qsTr("Confirmer le transfert ?"), - qsTr("Vous allez transférer %1 à %2.").arg(mainWindow.call.core.remoteName).arg(contact.core.fullName), - "", - function (confirmed) { - if (confirmed) { - mainWindow.transferCallToContact(mainWindow.call, contact, newCallForm) - } - } - ) - } - onTransferCallToAnotherRequested: (dest) => { - var callsWin = UtilsCpp.getCallsWindow() - console.log("transfer to", dest) - callsWin.showConfirmationLambdaPopup( - qsTr("Confirmer le transfert ?"), - qsTr("Vous allez transférer %1 à %2.").arg(mainWindow.call.core.remoteName).arg(dest.core.remoteName), - "", - function (confirmed) { - if (confirmed) { - mainWindow.call.core.lTransferCallToAnother(dest.core.remoteAddress) - } - } - ) - } - numPadPopup: numPadPopup + /************************* CONTENT ********************************/ + Rectangle { + anchors.fill: parent + color: DefaultStyle.grey_900 + Keys.onEscapePressed: { + if (mainWindow.visibility == Window.FullScreen) + mainWindow.showNormal() + } - NumericPadPopup { - id: numPadPopup - parent: numericPadContainer - width: parent.width - roundedBottom: true - lastRowVisible: false - visible: false - leftPadding: 40 * DefaultStyle.dp - rightPadding: 40 * DefaultStyle.dp - topPadding: 41 * DefaultStyle.dp - bottomPadding: 18 * DefaultStyle.dp - Component.onCompleted: parent.height = height - } - } - } - Component { - id: newCallPanel - NewCallForm { - id: newCallForm - objectName: "newCallPanel" - Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Nouvel appel") - groupCallVisible: false - searchBarColor: DefaultStyle.grey_0 - searchBarBorderColor: DefaultStyle.grey_200 - numPadPopup: numericPad - onContactClicked: (contact) => { - mainWindow.startCallWithContact(contact, false, rightPanel) - } - Connections { - target: mainWindow - function onCallChanged(){ if (newCallForm.Control.StackView.status === Control.StackView.Active) rightPanel.visible = false} - } - - NumericPadPopup { - id: numericPad - width: parent.width - parent: numericPadContainer - roundedBottom: true - visible: newCallForm.searchBar.numericPadButton.checked - leftPadding: 40 * DefaultStyle.dp - rightPadding: 40 * DefaultStyle.dp - topPadding: 41 * DefaultStyle.dp - bottomPadding: 18 * DefaultStyle.dp - onLaunchCall: { - rightPanel.visible = false - UtilsCpp.createCall(newCallForm.searchBar.text) - } - Component.onCompleted: parent.height = height - } - } - } - Component { - id: dialerPanel - Item { - id: dialerPanelContent - Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Dialer") - anchors.top: parent.top - anchors.bottom: parent.bottom - Keys.onEscapePressed: (event) => { - rightPanel.visible = false - event.accepted = true - } - SearchBar { - anchors.leftMargin: 10 * DefaultStyle.dp - anchors.rightMargin: 10 * DefaultStyle.dp - anchors.bottom: numPad.top - anchors.bottomMargin: 41 * DefaultStyle.dp - magnifierVisible: false - color: DefaultStyle.grey_0 - borderColor: DefaultStyle.grey_200 - placeholderText: "" - numericPadPopup: numPad - numericPadButton.visible: false - enabled: false - } - NumericPad { - id: numPad - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - currentCall: callsModel.currentCall - lastRowVisible: false - anchors.bottomMargin: 18 * DefaultStyle.dp - onLaunchCall: { - UtilsCpp.createCall(dialerTextInput.text) - } - Component.onCompleted: parent.height = height - } - } - } - Component { - id: changeLayoutPanel - ChangeLayoutForm { - Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Modifier la disposition") - Keys.onEscapePressed: (event) => { - rightPanel.visible = false - event.accepted = true - } - call: mainWindow.call - onChangeLayoutRequested: (index) => { - mainWindow.changeLayout(index) - } - } - } - Component { - id: callListPanel - ColumnLayout { - Control.StackView.onActivated: { - rightPanel.headerTitleText = qsTr("Liste d'appel") - rightPanel.customHeaderButtons = mergeCallPopupButton.createObject(rightPanel) - } - Keys.onEscapePressed: (event) => { - rightPanel.visible = false - event.accepted = true - } - spacing: 0 - Component { - id: mergeCallPopupButton - PopupButton { - visible: callsModel.count >= 2 - id: popupbutton - popup.contentItem: IconLabelButton { - icon.source: AppIcons.arrowsMerge - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Merger tous les appels") - textSize: 14 * DefaultStyle.dp - onClicked: { - callsModel.lMergeAll() - popupbutton.close() - } - } - } - } - RoundedPane { - Layout.fillWidth: true - Layout.maximumHeight: rightPanel.height - visible: callList.contentHeight > 0 - leftPadding: 16 * DefaultStyle.dp - rightPadding: 6 * DefaultStyle.dp - topPadding: 15 * DefaultStyle.dp - bottomPadding: 16 * DefaultStyle.dp + ColumnLayout { + anchors.fill: parent + spacing: 10 * DefaultStyle.dp + anchors.bottomMargin: 10 * DefaultStyle.dp + anchors.topMargin: 10 * DefaultStyle.dp + Item { + id: headerItem + Layout.margins: 10 * DefaultStyle.dp + Layout.leftMargin: 20 * DefaultStyle.dp + Layout.fillWidth: true + Layout.minimumHeight: 25 * DefaultStyle.dp + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + spacing: 10 * DefaultStyle.dp + RowLayout { + spacing: 10 * DefaultStyle.dp + EffectImage { + id: callStatusIcon + Layout.preferredWidth: 30 * DefaultStyle.dp + Layout.preferredHeight: 30 * DefaultStyle.dp + // TODO : change with broadcast or meeting icon when available + imageSource: !mainWindow.call ? AppIcons.meeting : (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released) ? AppIcons.endCall : (mainWindow.callState === LinphoneEnums.CallState.Paused || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) ? AppIcons.pause : mainWindow.conference ? AppIcons.usersThree : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing ? AppIcons.arrowUpRight : AppIcons.arrowDownLeft + colorizationColor: !mainWindow.call + || mainWindow.call.core.paused + || mainWindow.callState + === LinphoneEnums.CallState.Paused + || mainWindow.callState + === LinphoneEnums.CallState.PausedByRemote + || mainWindow.callState + === LinphoneEnums.CallState.End + || mainWindow.callState + === LinphoneEnums.CallState.Released + || mainWindow.conference ? DefaultStyle.danger_500main : mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing ? DefaultStyle.info_500_main : DefaultStyle.success_500main + onColorizationColorChanged: { + callStatusIcon.active = !callStatusIcon.active + callStatusIcon.active = !callStatusIcon.active + } + } + ColumnLayout { + spacing: 6 * DefaultStyle.dp + RowLayout { + spacing: 10 * DefaultStyle.dp + Text { + id: callStatusText + property string remoteName: mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning ? mainWindow.call.core.remoteName : qsTr("Appel %1").arg(mainWindow.call ? EnumsToStringCpp.dirToString(mainWindow.call.core.dir) : "") + text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released) ? qsTr("Fin d'appel") : mainWindow.call && (mainWindow.call.core.paused || (mainWindow.callState === LinphoneEnums.CallState.Paused || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote)) ? (mainWindow.conference ? qsTr('Réunion mise ') : qsTr('Appel mis')) + qsTr(" en pause") : mainWindow.conference ? mainWindow.conference.core.subject : remoteName + color: DefaultStyle.grey_0 + font { + pixelSize: 22 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + Rectangle { + visible: mainWindow.call + && (mainWindow.callState + === LinphoneEnums.CallState.Connected + || mainWindow.callState + === LinphoneEnums.CallState.StreamsRunning) + Layout.fillHeight: true + Layout.topMargin: 10 * DefaultStyle.dp + Layout.bottomMargin: 2 * DefaultStyle.dp + Layout.preferredWidth: 2 * DefaultStyle.dp + color: DefaultStyle.grey_0 + } + Text { + text: mainWindow.call ? UtilsCpp.formatElapsedTime( + mainWindow.call.core.duration) : "" + color: DefaultStyle.grey_0 + font { + pixelSize: 22 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + visible: mainWindow.callState + === LinphoneEnums.CallState.Connected + || mainWindow.callState + === LinphoneEnums.CallState.StreamsRunning + } + Text { + Layout.leftMargin: 14 * DefaultStyle.dp + id: conferenceDate + text: mainWindow.conferenceInfo ? mainWindow.conferenceInfo.core.getStartEndDateString( + ) : "" + color: DefaultStyle.grey_0 + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + capitalization: Font.Capitalize + } + } + } + RowLayout { + id: securityStateLayout + spacing: 5 * DefaultStyle.dp + visible: false + Connections { + target: mainWindow + function onCallStateChanged() { + if (mainWindow.callState + === LinphoneEnums.CallState.Connected) + securityStateLayout.visible = true + else if (mainWindow.callState + === LinphoneEnums.CallState.End + || mainWindow.callState + === LinphoneEnums.CallState.Released) + securityStateLayout.visible = false + } + } + BusyIndicator { + visible: mainWindow.call + && mainWindow.callState + != LinphoneEnums.CallState.Connected + && mainWindow.callState + != LinphoneEnums.CallState.StreamsRunning + Layout.preferredWidth: 15 * DefaultStyle.dp + Layout.preferredHeight: 15 * DefaultStyle.dp + indicatorColor: DefaultStyle.grey_0 + } + EffectImage { + Layout.preferredWidth: 15 * DefaultStyle.dp + Layout.preferredHeight: 15 * DefaultStyle.dp + colorizationColor: mainWindow.call ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp ? DefaultStyle.info_500_main : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified ? DefaultStyle.warning_600 : DefaultStyle.info_500_main : DefaultStyle.grey_0 : "transparent" + 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 && mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified ? AppIcons.warningCircle : AppIcons.lockKey : AppIcons.lockSimpleOpen : "" + } + Text { + text: mainWindow.call + && mainWindow.callState + === LinphoneEnums.CallState.Connected + || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp ? qsTr("Appel chiffré de point à point") : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified ? qsTr("Vérification nécessaire") : qsTr("Appel chiffré de bout en bout") : qsTr("Appel non chiffré") : qsTr("En attente de chiffrement") + color: mainWindow.call + && mainWindow.callState + === LinphoneEnums.CallState.Connected + || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp ? DefaultStyle.info_500_main : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified ? DefaultStyle.warning_600 : DefaultStyle.info_500_main : DefaultStyle.grey_0 : DefaultStyle.grey_0 + font { + pixelSize: 12 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + onClicked: { + rightPanel.visible = true + rightPanel.replace(encryptionPanel) + } + } + } + Item { + Layout.fillWidth: true + } + } + } + } + Item { + Layout.fillWidth: true + } + EffectImage { + Layout.preferredWidth: 32 * DefaultStyle.dp + Layout.preferredHeight: 32 * DefaultStyle.dp + Layout.rightMargin: 30 * DefaultStyle.dp + property int quality: mainWindow.call ? mainWindow.call.core.quality : 0 + imageSource: quality >= 4 ? AppIcons.cellSignalFull : quality >= 3 ? AppIcons.cellSignalMedium : quality >= 2 ? AppIcons.cellSignalLow : AppIcons.cellSignalNone + colorizationColor: DefaultStyle.grey_0 + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + onClicked: { + if (rightPanel.visible + && rightPanel.contentStackView.currentItem.objectName + === "statsPanel") + rightPanel.visible = false + else { + rightPanel.visible = true + rightPanel.replace(statsPanel) + } + } + } + } + } - Layout.topMargin: 15 * DefaultStyle.dp - Layout.bottomMargin: 16 * DefaultStyle.dp - Layout.leftMargin: 16 * DefaultStyle.dp - Layout.rightMargin: 16 * DefaultStyle.dp - - contentItem: CallListView { - id: callList - } - } - Item { - Layout.fillHeight: true - } - } - } - Component { - id: settingsPanel - Item { - Control.StackView.onActivated: { - rightPanel.headerTitleText = qsTr("Paramètres") - } - Keys.onEscapePressed: (event) => { - rightPanel.visible = false - event.accepted = true - } - MultimediaSettings { - id: inSettingsPanel - call: mainWindow.call - anchors.fill: parent - anchors.topMargin: 16 * DefaultStyle.dp - anchors.bottomMargin: 16 * DefaultStyle.dp - anchors.leftMargin: 17 * DefaultStyle.dp - anchors.rightMargin: 17 * DefaultStyle.dp - } - } - } - Component { - id: screencastPanel - Item { - Control.StackView.onActivated: rightPanel.headerTitleText = qsTr("Partage de votre écran") - Keys.onEscapePressed: (event) => { - rightPanel.visible = false - event.accepted = true - } - ScreencastSettings { - anchors.fill: parent - anchors.topMargin: 16 * DefaultStyle.dp - anchors.bottomMargin: 16 * DefaultStyle.dp - anchors.leftMargin: 17 * DefaultStyle.dp - anchors.rightMargin: 17 * DefaultStyle.dp - call: mainWindow.call - } - } - } - Component { - id: participantListPanel - Item { - objectName: "participantListPanel" - Keys.onEscapePressed: (event) => { - rightPanel.visible = false - event.accepted = true - } - Control.StackView { - id: participantsStack - anchors.fill: parent - anchors.bottomMargin: 16 * DefaultStyle.dp - anchors.leftMargin: 17 * DefaultStyle.dp - anchors.rightMargin: 17 * DefaultStyle.dp - initialItem: participantListComp - onCurrentItemChanged: rightPanel.headerStack.currentIndex = currentItem.Control.StackView.index - property list<string> selectedParticipants + Control.Control { + visible: mainWindow.call ? !!mainWindow.conference ? mainWindow.conference.core.isRecording : (mainWindow.call.core.recording || mainWindow.call.core.remoteRecording) : false + anchors.centerIn: parent + leftPadding: 14 * DefaultStyle.dp + rightPadding: 14 * DefaultStyle.dp + topPadding: 6 * DefaultStyle.dp + bottomPadding: 6 * DefaultStyle.dp + background: Rectangle { + anchors.fill: parent + color: DefaultStyle.grey_500 + radius: 10 * DefaultStyle.dp + } + contentItem: RowLayout { + spacing: 85 * DefaultStyle.dp + RowLayout { + spacing: 15 * DefaultStyle.dp + EffectImage { + imageSource: AppIcons.recordFill + colorizationColor: DefaultStyle.danger_500main + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + } + Text { + color: DefaultStyle.danger_500main + font.pixelSize: 14 * DefaultStyle.dp + text: mainWindow.call ? mainWindow.call.core.recording ? mainWindow.conference ? qsTr("Vous enregistrez la réunion") : qsTr("Vous enregistrez l'appel") : mainWindow.conference ? qsTr("Un participant enregistre la réunion") : qsTr("Votre correspondant enregistre l'appel") : "" + } + } + BigButton { + visible: mainWindow.call + && mainWindow.call.core.recording + text: qsTr("Arrêter l'enregistrement") + style: ButtonStyle.main + onPressed: mainWindow.call.core.lStopRecording() + } + } + } + } - Connections { - target: rightPanel - function onReturnRequested(){ participantsStack.pop()} - } + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + spacing: 23 * DefaultStyle.dp + Control.StackView { + id: middleItemStackView + initialItem: inCallItem + Layout.fillWidth: true + Layout.fillHeight: true + } + CallSettingsPanel { + id: rightPanel + Layout.fillHeight: true + Layout.rightMargin: 20 * DefaultStyle.dp + Layout.preferredWidth: 393 * DefaultStyle.dp + Layout.topMargin: 10 * DefaultStyle.dp + property int currentIndex: 0 + visible: false + function replace(id) { + rightPanel.customHeaderButtons = null + contentStackView.replace(id, + Control.StackView.Immediate) + } + headerStack.currentIndex: 0 + contentStackView.initialItem: callListPanel + headerValidateButtonText: qsTr("Ajouter") - Component { - id: participantListComp - ParticipantListView { - id: participantList - Component { - id: headerbutton - PopupButton { - popup.contentItem: IconLabelButton { - icon.source: AppIcons.shareNetwork - text: qsTr("Partager le lien de la réunion") - onClicked: { - UtilsCpp.copyToClipboard(mainWindow.call.core.remoteAddress) - showInformationPopup(qsTr("Copié"), qsTr("Le lien de la réunion a été copié dans le presse-papier"), true) - } - } - } - } - Control.StackView.onActivated: { - rightPanel.customHeaderButtons = headerbutton.createObject(rightPanel) - rightPanel.headerTitleText = qsTr("Participants (%1)").arg(count) - } - call: mainWindow.call - onAddParticipantRequested: participantsStack.push(addParticipantComp) - onCountChanged: { - rightPanel.headerTitleText = qsTr("Participants (%1)").arg(count) - } - Connections { - target: participantsStack - function onCurrentItemChanged() { - if (participantsStack.currentItem == participantList) rightPanel.headerTitleText = qsTr("Participants (%1)").arg(participantList.count) - } - } - Connections { - target: rightPanel - function onValidateRequested() { - participantList.model.addAddresses(participantsStack.selectedParticipants) - participantsStack.pop() - } - } - } - } - Component { - id: addParticipantComp - AddParticipantsForm { - id: addParticipantLayout - searchBarColor: DefaultStyle.grey_0 - searchBarBorderColor: DefaultStyle.grey_200 - onSelectedParticipantsCountChanged: { - rightPanel.headerSubtitleText = qsTr("%1 participant%2 sélectionné%2").arg(selectedParticipantsCount).arg(selectedParticipantsCount > 1 ? "s" : "") - participantsStack.selectedParticipants = selectedParticipants - } - Connections { - target: participantsStack - function onCurrentItemChanged() { - if (participantsStack.currentItem == addParticipantLayout) { - rightPanel.headerTitleText = qsTr("Ajouter des participants") - rightPanel.headerSubtitleText = qsTr("%1 participant%2 sélectionné%2").arg(addParticipantLayout.selectedParticipants.length).arg(addParticipantLayout.selectedParticipants.length > 1 ? "s" : "") - } - } - } - } - } - } - } - } - Component { - id: encryptionPanel - EncryptionSettings { - call: mainWindow.call - Control.StackView.onActivated: { - rightPanel.headerTitleText = qsTr("Chiffrement") - } - onEncryptionValidationRequested: zrtpValidation.open() - } - } - Component { - id: statsPanel - CallStatistics { - Control.StackView.onActivated: { - rightPanel.headerTitleText = qsTr("Statistiques") - } - call: mainWindow.call - } - } - Component { - id: waitingRoom - WaitingRoom { - id: waitingRoomIn - objectName: "waitingRoom" - Layout.alignment: Qt.AlignCenter - onSettingsButtonCheckedChanged: { - if (settingsButtonChecked) { - rightPanel.visible = true - rightPanel.replace(settingsPanel) - } else { - rightPanel.visible = false - } - } - Binding { - target: callStatusIcon - when: middleItemStackView.currentItem.objectName === "waitingRoom" - property: "imageSource" - value: AppIcons.usersThree - } - Binding { - target: callStatusText - when: middleItemStackView.currentItem.objectName === "waitingRoom" - property: "text" - value: waitingRoomIn.conferenceInfo ? waitingRoomIn.conferenceInfo.core.subject : '' - } - Binding { - target: conferenceDate - when: middleItemStackView.currentItem.objectName === "waitingRoom" - property: "text" - value: waitingRoomIn.conferenceInfo ? waitingRoomIn.conferenceInfo.core.startEndDateString : '' - } - Connections { - target: rightPanel - function onVisibleChanged(){ if (!visible) waitingRoomIn.settingsButtonChecked = false} - } - Connections { - target:mainWindow - function onSetUpConferenceRequested(conferenceInfo) { - waitingRoomIn.conferenceInfo = conferenceInfo - } - } - onJoinConfRequested: (uri) => { - mainWindow.joinConference(uri, {'microEnabled':microEnabled, 'localVideoEnabled':localVideoEnabled}) - } - onCancelJoiningRequested: mainWindow.cancelJoinConference() - onCancelAfterJoinRequested: mainWindow.cancelAfterJoin() - - } - } - Component { - id: inCallItem - Loader{ - property string objectName: "inCallItem" - asynchronous: true - sourceComponent: Item { - CallLayout{ - anchors.fill: parent - anchors.leftMargin: 20 * DefaultStyle.dp - anchors.rightMargin: (rightPanel.visible ? 0 : 10) * DefaultStyle.dp // Grid and AS have 10 in right margin (so apply -10 here) - anchors.topMargin: 10 * DefaultStyle.dp - call: mainWindow.call - callTerminatedByUser: mainWindow.callTerminatedByUser - } - } - } - } - - - - RowLayout { - id: bottomButtonsLayout - Layout.alignment: Qt.AlignHCenter - spacing: 58 * DefaultStyle.dp - visible: middleItemStackView.currentItem.objectName == "inCallItem" + Item { + id: numericPadContainer + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + height: childrenRect.height + } + } + } - function refreshLayout() { - if (mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning - || mainWindow.callState === LinphoneEnums.CallState.Paused || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) { - connectedCallButtons.visible = bottomButtonsLayout.visible - moreOptionsButton.visible = bottomButtonsLayout.visible - bottomButtonsLayout.layoutDirection = Qt.RightToLeft - } - else if (mainWindow.callState === LinphoneEnums.CallState.OutgoingInit) { - connectedCallButtons.visible = false - bottomButtonsLayout.layoutDirection = Qt.LeftToRight - moreOptionsButton.visible = false - } - } + Component { + id: callTransferPanel + NewCallForm { + id: newCallForm + Control.StackView.onActivated: rightPanel.headerTitleText = qsTr( + "Transférer %1 à :").arg( + mainWindow.call.core.remoteName) + Keys.onEscapePressed: event => { + rightPanel.visible = false + event.accepted = true + } + groupCallVisible: false + displayCurrentCalls: true + searchBarColor: DefaultStyle.grey_0 + searchBarBorderColor: DefaultStyle.grey_200 + onContactClicked: contact => { + var callsWin = UtilsCpp.getCallsWindow() + if (contact) + callsWin.showConfirmationLambdaPopup( + qsTr("Confirmer le transfert ?"), + qsTr("Vous allez transférer %1 à %2.").arg( + mainWindow.call.core.remoteName).arg( + contact.core.fullName), "", + function (confirmed) { + if (confirmed) { + mainWindow.transferCallToContact( + mainWindow.call, + contact, + newCallForm) + } + }) + } + onTransferCallToAnotherRequested: dest => { + var callsWin = UtilsCpp.getCallsWindow() + console.log( + "transfer to", + dest) + callsWin.showConfirmationLambdaPopup( + qsTr("Confirmer le transfert ?"), + qsTr("Vous allez transférer %1 à %2.").arg(mainWindow.call.core.remoteName).arg( + dest.core.remoteName), + "", + function (confirmed) { + if (confirmed) { + mainWindow.call.core.lTransferCallToAnother(dest.core.remoteAddress) + } + }) + } + numPadPopup: numPadPopup - Connections { - target: mainWindow - function onCallStateChanged(){ bottomButtonsLayout.refreshLayout()} - function onCallChanged(){ bottomButtonsLayout.refreshLayout()} - } - function setButtonsEnabled(enabled) { - for(var i=0; i < children.length; ++i) { - children[i].enabled = false - } - } - BigButton { - Layout.row: 0 - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - ToolTip.text: qsTr("Terminer l'appel") - Layout.preferredWidth: 75 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - radius: 71 * DefaultStyle.dp - style: ButtonStyle.phoneRed - Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit - || mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress - || mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging - || mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia - || mainWindow.callState == LinphoneEnums.CallState.IncomingReceived - ? 0 : bottomButtonsLayout.columns - 1 - onClicked: { - mainWindow.callTerminatedByUser = true - mainWindow.endCall(mainWindow.call) - } - } - RowLayout { - id: connectedCallButtons - visible: false - Layout.row: 0 - Layout.column: 1 - spacing: 10 * DefaultStyle.dp - CheckableButton { - id: pauseButton - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - ToolTip.text: checked ? qsTr("Reprendre l'appel") : qsTr("Mettre l'appel en pause") - background: Rectangle { - anchors.fill: parent - radius: 71 * DefaultStyle.dp - color: parent.enabled - ? parent.checked - ? DefaultStyle.success_500main - : parent.pressed - ? DefaultStyle.main2_400 - : DefaultStyle.grey_500 - : DefaultStyle.grey_600 - } - enabled: mainWindow.conference || mainWindow.callState != LinphoneEnums.CallState.PausedByRemote - icon.source: enabled && checked ? AppIcons.play : AppIcons.phonePause - checked: mainWindow.call && mainWindow.callState == LinphoneEnums.CallState.Paused || mainWindow.callState == LinphoneEnums.CallState.Pausing || (!mainWindow.conference && mainWindow.callState == LinphoneEnums.CallState.PausedByRemote) - onClicked: { - mainWindow.call.core.lSetPaused(!mainWindow.call.core.paused) - } - } - CheckableButton { - id: transferCallButton - visible: !mainWindow.conference - icon.source: AppIcons.transferCall - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - contentImageColor: DefaultStyle.grey_0 - ToolTip.text: qsTr("Transférer l'appel") - onCheckedChanged: { - console.log("checked transfer changed", checked) - if (checked) { - rightPanel.visible = true - rightPanel.replace(callTransferPanel) - } else { - rightPanel.visible = false - } - } - Connections { - target: rightPanel - function onVisibleChanged(){ if(!rightPanel.visible) transferCallButton.checked = false} - } - } - CheckableButton { - id: newCallButton - checkable: true - icon.source: AppIcons.newCall - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - ToolTip.text: qsTr("Initier un nouvel appel") - onCheckedChanged: { - console.log("checked newcall changed", checked) - if (checked) { - rightPanel.visible = true - rightPanel.replace(newCallPanel) - } else { - rightPanel.visible = false - } - } - Connections { - target: rightPanel - function onVisibleChanged() { if(!rightPanel.visible) newCallButton.checked = false} - } - } - CheckableButton { - id: callListButton - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - checkable: true - icon.source: AppIcons.callList - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - ToolTip.text: qsTr("Afficher la liste d'appels") - onCheckedChanged: { - if (checked) { - rightPanel.visible = true - rightPanel.replace(callListPanel) - } else { - rightPanel.visible = false - } - } - Connections { - target: rightPanel - function onVisibleChanged() { if(!rightPanel.visible) newCallButton.checked = false} - } - } - } - RowLayout { - Layout.row: 0 - Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit - || mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress - || mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging - || mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia - || mainWindow.callState == LinphoneEnums.CallState.IncomingReceived - ? bottomButtonsLayout.columns - 1 : 0 - spacing: 10 * DefaultStyle.dp - CheckableButton { - id: videoCameraButton - enabled: mainWindow.conferenceInfo || (mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) - iconUrl: AppIcons.videoCamera - checkedIconUrl: AppIcons.videoCameraSlash - ToolTip.text: mainWindow.localVideoEnabled ? qsTr("Désactiver la vidéo") :qsTr("Activer la vidéo") - checked: !mainWindow.localVideoEnabled - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - onClicked: mainWindow.call.core.lSetLocalVideoEnabled(!mainWindow.call.core.localVideoEnabled) - } - CheckableButton { - iconUrl: AppIcons.microphone - ToolTip.text: mainWindow.call && mainWindow.call.core.microphoneMuted ? qsTr("Activer le son") :qsTr("Désactiver le son") - checkedIconUrl: AppIcons.microphoneSlash - checked: mainWindow.call && mainWindow.call.core.microphoneMuted - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - onClicked: mainWindow.call.core.lSetMicrophoneMuted(!mainWindow.call.core.microphoneMuted) - } - CheckableButton { - iconUrl: AppIcons.screencast - visible: !!mainWindow.conference - ToolTip.text: qsTr("Partager l'écran...") - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - onCheckedChanged: { - if (checked) { - rightPanel.visible = true - rightPanel.replace(screencastPanel) - } else { - rightPanel.visible = false - } - } - } - CheckableButton { - visible: false - checkable: false - iconUrl: AppIcons.handWaving - ToolTip.text: qsTr("Lever la main") - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - } - CheckableButton { - visible: false - iconUrl: AppIcons.smiley - ToolTip.text: qsTr("Envoyer une réaction") - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - } - CheckableButton { - id: participantListButton - ToolTip.text: qsTr("Gérer les participants") - visible: mainWindow.conference - iconUrl: AppIcons.usersTwo - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - onCheckedChanged: { - if (checked) { - rightPanel.visible = true - rightPanel.replace(participantListPanel) - } else { - rightPanel.visible = false - } - } - Connections { - target: rightPanel - onVisibleChanged: if (!rightPanel.visible) participantListButton.checked = false - } - } - PopupButton { - id: moreOptionsButton - ToolTip.text: qsTr("Plus d'options...") - Layout.preferredWidth: 55 * DefaultStyle.dp - Layout.preferredHeight: 55 * DefaultStyle.dp - popup.topPadding: 20 * DefaultStyle.dp - popup.bottomPadding: 20 * DefaultStyle.dp - popup.leftPadding: 10 * DefaultStyle.dp - popup.rightPadding: 10 * DefaultStyle.dp - style: ButtonStyle.checkable - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp + NumericPadPopup { + id: numPadPopup + parent: numericPadContainer + width: parent.width + roundedBottom: true + lastRowVisible: false + visible: false + leftPadding: 40 * DefaultStyle.dp + rightPadding: 40 * DefaultStyle.dp + topPadding: 41 * DefaultStyle.dp + bottomPadding: 18 * DefaultStyle.dp + Component.onCompleted: parent.height = height + } + } + } + Component { + id: newCallPanel + NewCallForm { + id: newCallForm + objectName: "newCallPanel" + Control.StackView.onActivated: rightPanel.headerTitleText = qsTr( + "Nouvel appel") + groupCallVisible: false + searchBarColor: DefaultStyle.grey_0 + searchBarBorderColor: DefaultStyle.grey_200 + numPadPopup: numericPad + onContactClicked: contact => { + mainWindow.startCallWithContact( + contact, false, rightPanel) + } + Connections { + target: mainWindow + function onCallChanged() { + if (newCallForm.Control.StackView.status === Control.StackView.Active) + rightPanel.visible = false + } + } + + NumericPadPopup { + id: numericPad + width: parent.width + parent: numericPadContainer + roundedBottom: true + visible: newCallForm.searchBar.numericPadButton.checked + leftPadding: 40 * DefaultStyle.dp + rightPadding: 40 * DefaultStyle.dp + topPadding: 41 * DefaultStyle.dp + bottomPadding: 18 * DefaultStyle.dp + onLaunchCall: { + rightPanel.visible = false + UtilsCpp.createCall(newCallForm.searchBar.text) + } + Component.onCompleted: parent.height = height + } + } + } + Component { + id: dialerPanel + Item { + id: dialerPanelContent + Control.StackView.onActivated: rightPanel.headerTitleText = qsTr( + "Dialer") + anchors.top: parent.top + anchors.bottom: parent.bottom + Keys.onEscapePressed: event => { + rightPanel.visible = false + event.accepted = true + } + SearchBar { + anchors.leftMargin: 10 * DefaultStyle.dp + anchors.rightMargin: 10 * DefaultStyle.dp + anchors.bottom: numPad.top + anchors.bottomMargin: 41 * DefaultStyle.dp + magnifierVisible: false + color: DefaultStyle.grey_0 + borderColor: DefaultStyle.grey_200 + placeholderText: "" + numericPadPopup: numPad + numericPadButton.visible: false + enabled: false + } + NumericPad { + id: numPad + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + currentCall: callsModel.currentCall + lastRowVisible: false + anchors.bottomMargin: 18 * DefaultStyle.dp + onLaunchCall: { + UtilsCpp.createCall(dialerTextInput.text) + } + Component.onCompleted: parent.height = height + } + } + } + Component { + id: changeLayoutPanel + ChangeLayoutForm { + Control.StackView.onActivated: rightPanel.headerTitleText = qsTr( + "Modifier la disposition") + Keys.onEscapePressed: event => { + rightPanel.visible = false + event.accepted = true + } + call: mainWindow.call + onChangeLayoutRequested: index => { + mainWindow.changeLayout(index) + } + } + } + Component { + id: callListPanel + ColumnLayout { + Control.StackView.onActivated: { + rightPanel.headerTitleText = qsTr("Liste d'appel") + rightPanel.customHeaderButtons = mergeCallPopupButton.createObject( + rightPanel) + } + Keys.onEscapePressed: event => { + rightPanel.visible = false + event.accepted = true + } + spacing: 0 + Component { + id: mergeCallPopupButton + PopupButton { + visible: callsModel.count >= 2 + id: popupbutton + popup.contentItem: IconLabelButton { + icon.source: AppIcons.arrowsMerge + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Merger tous les appels") + textSize: 14 * DefaultStyle.dp + onClicked: { + callsModel.lMergeAll() + popupbutton.close() + } + } + } + } + RoundedPane { + Layout.fillWidth: true + Layout.maximumHeight: rightPanel.height + visible: callList.contentHeight > 0 + leftPadding: 16 * DefaultStyle.dp + rightPadding: 6 * DefaultStyle.dp + topPadding: 15 * DefaultStyle.dp + bottomPadding: 16 * DefaultStyle.dp + + Layout.topMargin: 15 * DefaultStyle.dp + Layout.bottomMargin: 16 * DefaultStyle.dp + Layout.leftMargin: 16 * DefaultStyle.dp + Layout.rightMargin: 16 * DefaultStyle.dp + + contentItem: CallListView { + id: callList + } + } + Item { + Layout.fillHeight: true + } + } + } + Component { + id: settingsPanel + Item { + Control.StackView.onActivated: { + rightPanel.headerTitleText = qsTr("Paramètres") + } + Keys.onEscapePressed: event => { + rightPanel.visible = false + event.accepted = true + } + MultimediaSettings { + id: inSettingsPanel + call: mainWindow.call + anchors.fill: parent + anchors.topMargin: 16 * DefaultStyle.dp + anchors.bottomMargin: 16 * DefaultStyle.dp + anchors.leftMargin: 17 * DefaultStyle.dp + anchors.rightMargin: 17 * DefaultStyle.dp + } + } + } + Component { + id: screencastPanel + Item { + Control.StackView.onActivated: rightPanel.headerTitleText = qsTr( + "Partage de votre écran") + Keys.onEscapePressed: event => { + rightPanel.visible = false + event.accepted = true + } + ScreencastSettings { + anchors.fill: parent + anchors.topMargin: 16 * DefaultStyle.dp + anchors.bottomMargin: 16 * DefaultStyle.dp + anchors.leftMargin: 17 * DefaultStyle.dp + anchors.rightMargin: 17 * DefaultStyle.dp + call: mainWindow.call + } + } + } + Component { + id: participantListPanel + Item { + objectName: "participantListPanel" + Keys.onEscapePressed: event => { + rightPanel.visible = false + event.accepted = true + } + Control.StackView { + id: participantsStack + anchors.fill: parent + anchors.bottomMargin: 16 * DefaultStyle.dp + anchors.leftMargin: 17 * DefaultStyle.dp + anchors.rightMargin: 17 * DefaultStyle.dp + initialItem: participantListComp + onCurrentItemChanged: rightPanel.headerStack.currentIndex + = currentItem.Control.StackView.index + property list<string> selectedParticipants + + Connections { + target: rightPanel + function onReturnRequested() { + participantsStack.pop() + } + } - Connections { - target: moreOptionsButton.popup - function onOpened() { - moreOptionsButton.popup.y = - moreOptionsButton.popup.height - moreOptionsButton.popup.padding - } - } - popup.contentItem: ColumnLayout { - id: optionsList - spacing: 5 * DefaultStyle.dp + Component { + id: participantListComp + ParticipantListView { + id: participantList + Component { + id: headerbutton + PopupButton { + popup.contentItem: IconLabelButton { + icon.source: AppIcons.shareNetwork + text: qsTr("Partager le lien de la réunion") + onClicked: { + UtilsCpp.copyToClipboard( + mainWindow.call.core.remoteAddress) + showInformationPopup( + qsTr("Copié"), qsTr( + "Le lien de la réunion a été copié dans le presse-papier"), + true) + } + } + } + } + Control.StackView.onActivated: { + rightPanel.customHeaderButtons = headerbutton.createObject( + rightPanel) + rightPanel.headerTitleText = qsTr( + "Participants (%1)").arg(count) + } + call: mainWindow.call + onAddParticipantRequested: participantsStack.push( + addParticipantComp) + onCountChanged: { + rightPanel.headerTitleText = qsTr( + "Participants (%1)").arg(count) + } + Connections { + target: participantsStack + function onCurrentItemChanged() { + if (participantsStack.currentItem == participantList) + rightPanel.headerTitleText = qsTr( + "Participants (%1)").arg( + participantList.count) + } + } + Connections { + target: rightPanel + function onValidateRequested() { + participantList.model.addAddresses( + participantsStack.selectedParticipants) + participantsStack.pop() + } + } + } + } + Component { + id: addParticipantComp + AddParticipantsForm { + id: addParticipantLayout + searchBarColor: DefaultStyle.grey_0 + searchBarBorderColor: DefaultStyle.grey_200 + onSelectedParticipantsCountChanged: { + rightPanel.headerSubtitleText = qsTr( + "%1 participant%2 sélectionné%2").arg( + selectedParticipantsCount).arg( + selectedParticipantsCount > 1 ? "s" : "") + participantsStack.selectedParticipants = selectedParticipants + } + Connections { + target: participantsStack + function onCurrentItemChanged() { + if (participantsStack.currentItem == addParticipantLayout) { + rightPanel.headerTitleText = qsTr( + "Ajouter des participants") + rightPanel.headerSubtitleText = qsTr( + "%1 participant%2 sélectionné%2").arg( + addParticipantLayout.selectedParticipants.length).arg(addParticipantLayout.selectedParticipants.length > 1 ? "s" : "") + } + } + } + } + } + } + } + } + Component { + id: encryptionPanel + EncryptionSettings { + call: mainWindow.call + Control.StackView.onActivated: { + rightPanel.headerTitleText = qsTr("Chiffrement") + } + onEncryptionValidationRequested: zrtpValidation.open() + } + } + Component { + id: statsPanel + CallStatistics { + Control.StackView.onActivated: { + rightPanel.headerTitleText = qsTr("Statistiques") + } + call: mainWindow.call + } + } + Component { + id: waitingRoom + WaitingRoom { + id: waitingRoomIn + objectName: "waitingRoom" + Layout.alignment: Qt.AlignCenter + onSettingsButtonCheckedChanged: { + if (settingsButtonChecked) { + rightPanel.visible = true + rightPanel.replace(settingsPanel) + } else { + rightPanel.visible = false + } + } + Binding { + target: callStatusIcon + when: middleItemStackView.currentItem.objectName === "waitingRoom" + property: "imageSource" + value: AppIcons.usersThree + } + Binding { + target: callStatusText + when: middleItemStackView.currentItem.objectName === "waitingRoom" + property: "text" + value: waitingRoomIn.conferenceInfo ? waitingRoomIn.conferenceInfo.core.subject : '' + } + Binding { + target: conferenceDate + when: middleItemStackView.currentItem.objectName === "waitingRoom" + property: "text" + value: waitingRoomIn.conferenceInfo ? waitingRoomIn.conferenceInfo.core.startEndDateString : '' + } + Connections { + target: rightPanel + function onVisibleChanged() { + if (!visible) + waitingRoomIn.settingsButtonChecked = false + } + } + Connections { + target: mainWindow + function onSetUpConferenceRequested(conferenceInfo) { + waitingRoomIn.conferenceInfo = conferenceInfo + } + } + onJoinConfRequested: uri => { + mainWindow.joinConference(uri, { + "microEnabled": microEnabled, + "localVideoEnabled": localVideoEnabled + }) + } + onCancelJoiningRequested: mainWindow.cancelJoinConference() + onCancelAfterJoinRequested: mainWindow.cancelAfterJoin() + } + } + Component { + id: inCallItem + Loader { + property string objectName: "inCallItem" + asynchronous: true + sourceComponent: Item { + CallLayout { + anchors.fill: parent + anchors.leftMargin: 20 * DefaultStyle.dp + anchors.rightMargin: (rightPanel.visible ? 0 : 10) * DefaultStyle.dp // Grid and AS have 10 in right margin (so apply -10 here) + anchors.topMargin: 10 * DefaultStyle.dp + call: mainWindow.call + callTerminatedByUser: mainWindow.callTerminatedByUser + } + } + } + } + + RowLayout { + id: bottomButtonsLayout + Layout.alignment: Qt.AlignHCenter + spacing: 58 * DefaultStyle.dp + visible: middleItemStackView.currentItem.objectName == "inCallItem" + + function refreshLayout() { + if (mainWindow.callState === LinphoneEnums.CallState.Connected + || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning + || mainWindow.callState === LinphoneEnums.CallState.Paused + || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote) { + connectedCallButtons.visible = bottomButtonsLayout.visible + moreOptionsButton.visible = bottomButtonsLayout.visible + bottomButtonsLayout.layoutDirection = Qt.RightToLeft + } else if (mainWindow.callState === LinphoneEnums.CallState.OutgoingInit) { + connectedCallButtons.visible = false + bottomButtonsLayout.layoutDirection = Qt.LeftToRight + moreOptionsButton.visible = false + } + } + + Connections { + target: mainWindow + function onCallStateChanged() { + bottomButtonsLayout.refreshLayout() + } + function onCallChanged() { + bottomButtonsLayout.refreshLayout() + } + } + function setButtonsEnabled(enabled) { + for (var i = 0; i < children.length; ++i) { + children[i].enabled = false + } + } + BigButton { + Layout.row: 0 + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + ToolTip.text: qsTr("Terminer l'appel") + Layout.preferredWidth: 75 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + radius: 71 * DefaultStyle.dp + style: ButtonStyle.phoneRed + Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit + || mainWindow.callState + == LinphoneEnums.CallState.OutgoingProgress + || mainWindow.callState + == LinphoneEnums.CallState.OutgoingRinging + || mainWindow.callState + == LinphoneEnums.CallState.OutgoingEarlyMedia + || mainWindow.callState == LinphoneEnums.CallState.IncomingReceived ? 0 : bottomButtonsLayout.columns - 1 + onClicked: { + mainWindow.callTerminatedByUser = true + mainWindow.endCall(mainWindow.call) + } + } + RowLayout { + id: connectedCallButtons + visible: false + Layout.row: 0 + Layout.column: 1 + spacing: 10 * DefaultStyle.dp + CheckableButton { + id: pauseButton + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + ToolTip.text: checked ? qsTr( + "Reprendre l'appel") : qsTr( + "Mettre l'appel en pause") + background: Rectangle { + anchors.fill: parent + radius: 71 * DefaultStyle.dp + color: parent.enabled ? parent.checked ? DefaultStyle.success_500main : parent.pressed ? DefaultStyle.main2_400 : DefaultStyle.grey_500 : DefaultStyle.grey_600 + } + enabled: mainWindow.conference + || mainWindow.callState != LinphoneEnums.CallState.PausedByRemote + icon.source: enabled + && checked ? AppIcons.play : AppIcons.phonePause + checked: mainWindow.call + && mainWindow.callState == LinphoneEnums.CallState.Paused + || mainWindow.callState == LinphoneEnums.CallState.Pausing + || (!mainWindow.conference + && mainWindow.callState + == LinphoneEnums.CallState.PausedByRemote) + onClicked: { + mainWindow.call.core.lSetPaused( + !mainWindow.call.core.paused) + } + } + CheckableButton { + id: transferCallButton + visible: !mainWindow.conference + icon.source: AppIcons.transferCall + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + contentImageColor: DefaultStyle.grey_0 + ToolTip.text: qsTr("Transférer l'appel") + onCheckedChanged: { + console.log("checked transfer changed", checked) + if (checked) { + rightPanel.visible = true + rightPanel.replace(callTransferPanel) + } else { + rightPanel.visible = false + } + } + Connections { + target: rightPanel + function onVisibleChanged() { + if (!rightPanel.visible) + transferCallButton.checked = false + } + } + } + CheckableButton { + id: newCallButton + checkable: true + icon.source: AppIcons.newCall + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + ToolTip.text: qsTr("Initier un nouvel appel") + onCheckedChanged: { + console.log("checked newcall changed", checked) + if (checked) { + rightPanel.visible = true + rightPanel.replace(newCallPanel) + } else { + rightPanel.visible = false + } + } + Connections { + target: rightPanel + function onVisibleChanged() { + if (!rightPanel.visible) + newCallButton.checked = false + } + } + } + CheckableButton { + id: callListButton + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + checkable: true + icon.source: AppIcons.callList + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + ToolTip.text: qsTr("Afficher la liste d'appels") + onCheckedChanged: { + if (checked) { + rightPanel.visible = true + rightPanel.replace(callListPanel) + } else { + rightPanel.visible = false + } + } + Connections { + target: rightPanel + function onVisibleChanged() { + if (!rightPanel.visible) + newCallButton.checked = false + } + } + } + } + RowLayout { + Layout.row: 0 + Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit + || mainWindow.callState + == LinphoneEnums.CallState.OutgoingProgress + || mainWindow.callState + == LinphoneEnums.CallState.OutgoingRinging + || mainWindow.callState + == LinphoneEnums.CallState.OutgoingEarlyMedia + || mainWindow.callState == LinphoneEnums.CallState.IncomingReceived ? bottomButtonsLayout.columns - 1 : 0 + spacing: 10 * DefaultStyle.dp + CheckableButton { + id: videoCameraButton + enabled: mainWindow.conferenceInfo + || (mainWindow.callState === LinphoneEnums.CallState.Connected + || mainWindow.callState + === LinphoneEnums.CallState.StreamsRunning) + iconUrl: AppIcons.videoCamera + checkedIconUrl: AppIcons.videoCameraSlash + ToolTip.text: mainWindow.localVideoEnabled ? qsTr("Désactiver la vidéo") : qsTr( + "Activer la vidéo") + checked: !mainWindow.localVideoEnabled + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + onClicked: mainWindow.call.core.lSetLocalVideoEnabled( + !mainWindow.call.core.localVideoEnabled) + } + CheckableButton { + iconUrl: AppIcons.microphone + ToolTip.text: mainWindow.call + && mainWindow.call.core.microphoneMuted ? qsTr("Activer le son") : qsTr("Désactiver le son") + checkedIconUrl: AppIcons.microphoneSlash + checked: mainWindow.call + && mainWindow.call.core.microphoneMuted + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + onClicked: mainWindow.call.core.lSetMicrophoneMuted( + !mainWindow.call.core.microphoneMuted) + } + CheckableButton { + iconUrl: AppIcons.screencast + visible: !!mainWindow.conference + ToolTip.text: qsTr("Partager l'écran...") + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + onCheckedChanged: { + if (checked) { + rightPanel.visible = true + rightPanel.replace(screencastPanel) + } else { + rightPanel.visible = false + } + } + } + CheckableButton { + visible: false + checkable: false + iconUrl: AppIcons.handWaving + ToolTip.text: qsTr("Lever la main") + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + } + CheckableButton { + visible: false + iconUrl: AppIcons.smiley + ToolTip.text: qsTr("Envoyer une réaction") + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + } + CheckableButton { + id: participantListButton + ToolTip.text: qsTr("Gérer les participants") + visible: mainWindow.conference + iconUrl: AppIcons.usersTwo + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + onCheckedChanged: { + if (checked) { + rightPanel.visible = true + rightPanel.replace(participantListPanel) + } else { + rightPanel.visible = false + } + } + Connections { + target: rightPanel + onVisibleChanged: if (!rightPanel.visible) + participantListButton.checked = false + } + } + PopupButton { + id: moreOptionsButton + ToolTip.text: qsTr("Plus d'options...") + Layout.preferredWidth: 55 * DefaultStyle.dp + Layout.preferredHeight: 55 * DefaultStyle.dp + popup.topPadding: 20 * DefaultStyle.dp + popup.bottomPadding: 20 * DefaultStyle.dp + popup.leftPadding: 10 * DefaultStyle.dp + popup.rightPadding: 10 * DefaultStyle.dp + style: ButtonStyle.checkable + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp - IconLabelButton { - Layout.fillWidth: true - visible: mainWindow.conference - icon.source: AppIcons.squaresFour - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Modifier la disposition") - style: ButtonStyle.noBackground - onClicked: { - rightPanel.visible = true - rightPanel.replace(changeLayoutPanel) - moreOptionsButton.close() - } - } - IconLabelButton { - Layout.fillWidth: true - icon.source: AppIcons.fullscreen - text: qsTr("Mode Plein écran") - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - checkable: true - style: ButtonStyle.noBackground - Binding on checked { value: mainWindow.visibility === Window.FullScreen } - onToggled: { - if(checked) { - mainWindow.showFullScreen() - }else{ - mainWindow.showNormal() - } - moreOptionsButton.close() - } - } - IconLabelButton { - Layout.fillWidth: true - icon.source: AppIcons.dialer - text: qsTr("Dialer") - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - style: ButtonStyle.noBackground - onClicked: { - rightPanel.visible = true - rightPanel.replace(dialerPanel) - moreOptionsButton.close() - } - } - IconLabelButton { - Layout.fillWidth: true - checkable: true - style: ButtonStyle.noBackground - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - visible: mainWindow.call && !mainWindow.conference && !SettingsCpp.disableCallRecordings - enabled: mainWindow.call && mainWindow.call.core.recordable - icon.source: AppIcons.recordFill - checked: mainWindow.call && mainWindow.call.core.recording - hoveredImageColor: contentImageColor - contentImageColor: mainWindow.call && mainWindow.call.core.recording - ? DefaultStyle.danger_500main - : DefaultStyle.main2_500main - text: mainWindow.call && mainWindow.call.core.recording ? qsTr("Terminer l'enregistrement") : qsTr("Enregistrer l'appel") - textColor: mainWindow.call && mainWindow.call.core.recording - ? DefaultStyle.danger_500main - : DefaultStyle.main2_500main - hoveredTextColor : textColor - onToggled: { - if (mainWindow.call) - if (mainWindow.call.core.recording) mainWindow.call.core.lStopRecording() - else mainWindow.call.core.lStartRecording() - } - } - IconLabelButton { - Layout.fillWidth: true - checkable: true - style: ButtonStyle.noBackground - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - icon.source: !mainWindow.call || mainWindow.call.core.speakerMuted ? AppIcons.speakerSlash : AppIcons.speaker - contentImageColor: mainWindow.call && mainWindow.call.core.speakerMuted - ? DefaultStyle.danger_500main - : DefaultStyle.main2_500main - hoveredImageColor: contentImageColor - text: mainWindow.call && mainWindow.call.core.speakerMuted ? qsTr("Activer le son") : qsTr("Désactiver le son") - textColor: mainWindow.call && mainWindow.call.core.speakerMuted - ? DefaultStyle.danger_500main - : DefaultStyle.main2_500main - hoveredTextColor: textColor - onCheckedChanged: { - if (mainWindow.call) mainWindow.call.core.lSetSpeakerMuted(!mainWindow.call.core.speakerMuted) - } - } - IconLabelButton { - Layout.fillWidth: true - icon.source: AppIcons.settings - icon.width: 32 * DefaultStyle.dp - icon.height: 32 * DefaultStyle.dp - text: qsTr("Paramètres") - style: ButtonStyle.noBackground - onClicked: { - rightPanel.visible = true - rightPanel.replace(settingsPanel) - moreOptionsButton.close() - } - } - } - } - } - } - - } - } + Connections { + target: moreOptionsButton.popup + function onOpened() { + moreOptionsButton.popup.y = -moreOptionsButton.popup.height + - moreOptionsButton.popup.padding + } + } + popup.contentItem: ColumnLayout { + id: optionsList + spacing: 5 * DefaultStyle.dp + IconLabelButton { + Layout.fillWidth: true + visible: mainWindow.conference + icon.source: AppIcons.squaresFour + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Modifier la disposition") + style: ButtonStyle.noBackground + onClicked: { + rightPanel.visible = true + rightPanel.replace(changeLayoutPanel) + moreOptionsButton.close() + } + } + IconLabelButton { + Layout.fillWidth: true + icon.source: AppIcons.fullscreen + text: qsTr("Mode Plein écran") + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + checkable: true + style: ButtonStyle.noBackground + Binding on checked { + value: mainWindow.visibility === Window.FullScreen + } + onToggled: { + if (checked) { + mainWindow.showFullScreen() + } else { + mainWindow.showNormal() + } + moreOptionsButton.close() + } + } + IconLabelButton { + Layout.fillWidth: true + icon.source: AppIcons.dialer + text: qsTr("Dialer") + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + style: ButtonStyle.noBackground + onClicked: { + rightPanel.visible = true + rightPanel.replace(dialerPanel) + moreOptionsButton.close() + } + } + IconLabelButton { + Layout.fillWidth: true + checkable: true + style: ButtonStyle.noBackground + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + visible: mainWindow.call + && !mainWindow.conference + && !SettingsCpp.disableCallRecordings + enabled: mainWindow.call + && mainWindow.call.core.recordable + icon.source: AppIcons.recordFill + checked: mainWindow.call + && mainWindow.call.core.recording + hoveredImageColor: contentImageColor + contentImageColor: mainWindow.call + && mainWindow.call.core.recording ? DefaultStyle.danger_500main : DefaultStyle.main2_500main + text: mainWindow.call + && mainWindow.call.core.recording ? qsTr("Terminer l'enregistrement") : qsTr("Enregistrer l'appel") + textColor: mainWindow.call + && mainWindow.call.core.recording ? DefaultStyle.danger_500main : DefaultStyle.main2_500main + hoveredTextColor: textColor + onToggled: { + if (mainWindow.call) + if (mainWindow.call.core.recording) + mainWindow.call.core.lStopRecording( + ) + else + mainWindow.call.core.lStartRecording() + } + } + IconLabelButton { + Layout.fillWidth: true + checkable: true + style: ButtonStyle.noBackground + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + icon.source: !mainWindow.call + || mainWindow.call.core.speakerMuted ? AppIcons.speakerSlash : AppIcons.speaker + contentImageColor: mainWindow.call + && mainWindow.call.core.speakerMuted ? DefaultStyle.danger_500main : DefaultStyle.main2_500main + hoveredImageColor: contentImageColor + text: mainWindow.call + && mainWindow.call.core.speakerMuted ? qsTr("Activer le son") : qsTr("Désactiver le son") + textColor: mainWindow.call + && mainWindow.call.core.speakerMuted ? DefaultStyle.danger_500main : DefaultStyle.main2_500main + hoveredTextColor: textColor + onCheckedChanged: { + if (mainWindow.call) + mainWindow.call.core.lSetSpeakerMuted( + !mainWindow.call.core.speakerMuted) + } + } + IconLabelButton { + Layout.fillWidth: true + icon.source: AppIcons.settings + icon.width: 32 * DefaultStyle.dp + icon.height: 32 * DefaultStyle.dp + text: qsTr("Paramètres") + style: ButtonStyle.noBackground + onClicked: { + rightPanel.visible = true + rightPanel.replace(settingsPanel) + moreOptionsButton.close() + } + } + } + } + } + } + } + } } -- GitLab