From 4adc59ad5d3d21279a6655b9ead69b7f0faab515 Mon Sep 17 00:00:00 2001 From: Ming Rui Zhang <mingrui.zhang@savoirfairelinux.com> Date: Thu, 1 Oct 2020 12:43:24 -0400 Subject: [PATCH] mainview: add call recording and full screen mode in audio call Call view context menu now should always has menu items in audio call Gitlab: #125 Change-Id: I9bea26d1f95d898c12d8ac2149545273b1494447 --- qml.qrc | 2 +- src/mainview/components/AudioCallPage.qml | 199 ++++++++++-------- src/mainview/components/CallStackView.qml | 37 ++-- .../components/CallViewContextMenu.qml | 23 +- src/mainview/components/VideoCallPage.qml | 6 +- .../callfullscreenwindowcontainercreation.js | 80 +++++++ ...eocallfullscreenwindowcontainercreation.js | 96 --------- 7 files changed, 227 insertions(+), 216 deletions(-) create mode 100644 src/mainview/js/callfullscreenwindowcontainercreation.js delete mode 100644 src/mainview/js/videocallfullscreenwindowcontainercreation.js diff --git a/qml.qrc b/qml.qrc index 06ff49145..0028cdd75 100644 --- a/qml.qrc +++ b/qml.qrc @@ -115,7 +115,7 @@ <file>src/mainview/js/selectscreenwindowcreation.js</file> <file>src/mainview/components/ScreenRubberBand.qml</file> <file>src/mainview/js/screenrubberbandcreation.js</file> - <file>src/mainview/js/videocallfullscreenwindowcontainercreation.js</file> + <file>src/mainview/js/callfullscreenwindowcontainercreation.js</file> <file>src/mainview/components/VideoCallFullScreenWindowContainer.qml</file> <file>src/mainview/components/ContactPicker.qml</file> <file>src/mainview/components/MediaHandlerPicker.qml</file> diff --git a/src/mainview/components/AudioCallPage.qml b/src/mainview/components/AudioCallPage.qml index f751333fa..b944ddb36 100644 --- a/src/mainview/components/AudioCallPage.qml +++ b/src/mainview/components/AudioCallPage.qml @@ -34,6 +34,8 @@ Rectangle { property var linkedWebview: null + signal showFullScreenReqested + function updateUI(accountId, convUid) { contactImgSource = "data:image/png;base64," + UtilsAdapter.getContactImageString( accountId, convUid) @@ -87,135 +89,146 @@ Rectangle { SplitView.minimumHeight: audioCallPageRect.height / 2 + 20 SplitView.fillWidth: true - CallOverlay { - id: audioCallOverlay - + MouseArea { anchors.fill: parent - Connections { - target: CallAdapter + hoverEnabled: true + propagateComposedEvents: true - function onUpdateTimeText(time) { - audioCallOverlay.timeText = time - } + acceptedButtons: Qt.LeftButton - function onUpdateOverlay(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall, bestName) { - audioCallOverlay.showOnHoldImage(isPaused) - audioCallPageRectCentralRect.visible = !isPaused - audioCallOverlay.updateButtonStatus(isPaused, - isAudioOnly, - isAudioMuted, - isVideoMuted, - isRecording, isSIP, - isConferenceCall) - audioCallPageRect.bestName = bestName - } + onDoubleClicked: showFullScreenReqested() + + CallOverlay { + id: audioCallOverlay + + anchors.fill: parent + + Connections { + target: CallAdapter + + function onUpdateTimeText(time) { + audioCallOverlay.timeText = time + audioCallOverlay.setRecording(CallAdapter.isRecordingThisCall()) + } + + function onUpdateOverlay(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall, bestName) { + audioCallOverlay.showOnHoldImage(isPaused) + audioCallPageRectCentralRect.visible = !isPaused + audioCallOverlay.updateButtonStatus(isPaused, + isAudioOnly, + isAudioMuted, + isVideoMuted, + isRecording, isSIP, + isConferenceCall) + audioCallPageRect.bestName = bestName + } - function onShowOnHoldLabel(isPaused) { - audioCallOverlay.showOnHoldImage(isPaused) - audioCallPageRectCentralRect.visible = !isPaused + function onShowOnHoldLabel(isPaused) { + audioCallOverlay.showOnHoldImage(isPaused) + audioCallPageRectCentralRect.visible = !isPaused + } } - } - onOverlayChatButtonClicked: { - if (inAudioCallMessageWebViewStack.visible) { - linkedWebview.resetMessagingHeaderBackButtonSource( - true) - linkedWebview.setMessagingHeaderButtonsVisible( - true) - inAudioCallMessageWebViewStack.visible = false - inAudioCallMessageWebViewStack.clear() - } else { - linkedWebview.resetMessagingHeaderBackButtonSource( - false) - linkedWebview.setMessagingHeaderButtonsVisible( - false) - inAudioCallMessageWebViewStack.visible = true - inAudioCallMessageWebViewStack.push( - linkedWebview) + onOverlayChatButtonClicked: { + if (inAudioCallMessageWebViewStack.visible) { + linkedWebview.resetMessagingHeaderBackButtonSource( + true) + linkedWebview.setMessagingHeaderButtonsVisible( + true) + inAudioCallMessageWebViewStack.visible = false + inAudioCallMessageWebViewStack.clear() + } else { + linkedWebview.resetMessagingHeaderBackButtonSource( + false) + linkedWebview.setMessagingHeaderButtonsVisible( + false) + inAudioCallMessageWebViewStack.visible = true + inAudioCallMessageWebViewStack.push( + linkedWebview) + } } } - } - Rectangle { - id: audioCallPageRectCentralRect + Rectangle { + id: audioCallPageRectCentralRect - anchors.centerIn: parent + anchors.centerIn: parent - width: audioCallPageRect.width - height: audioCallPageRegisteredNameText.height - + audioCallPageIdText.height + contactImage.height + 10 + width: audioCallPageRect.width + height: audioCallPageRegisteredNameText.height + + audioCallPageIdText.height + contactImage.height + 10 - ColumnLayout { - id: audioCallPageRectColumnLayout + ColumnLayout { + id: audioCallPageRectColumnLayout - Image { - id: contactImage + Image { + id: contactImage - Layout.alignment: Qt.AlignCenter + Layout.alignment: Qt.AlignCenter - Layout.preferredWidth: 100 - Layout.preferredHeight: 100 + Layout.preferredWidth: 100 + Layout.preferredHeight: 100 - fillMode: Image.PreserveAspectFit - source: contactImgSource - asynchronous: true - } + fillMode: Image.PreserveAspectFit + source: contactImgSource + asynchronous: true + } - Text { - id: audioCallPageRegisteredNameText + Text { + id: audioCallPageRegisteredNameText - Layout.alignment: Qt.AlignCenter + Layout.alignment: Qt.AlignCenter - Layout.preferredWidth: audioCallPageRectCentralRect.width - Layout.preferredHeight: 50 + Layout.preferredWidth: audioCallPageRectCentralRect.width + Layout.preferredHeight: 50 - font.pointSize: JamiTheme.textFontSize + 3 + font.pointSize: JamiTheme.textFontSize + 3 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter - text: textMetricsAudioCallPageRegisteredNameText.elidedText - color: "white" + text: textMetricsAudioCallPageRegisteredNameText.elidedText + color: "white" - TextMetrics { - id: textMetricsAudioCallPageRegisteredNameText - font: audioCallPageRegisteredNameText.font - text: bestName - elideWidth: audioCallPageRectCentralRect.width - 50 - elide: Qt.ElideMiddle + TextMetrics { + id: textMetricsAudioCallPageRegisteredNameText + font: audioCallPageRegisteredNameText.font + text: bestName + elideWidth: audioCallPageRectCentralRect.width - 50 + elide: Qt.ElideMiddle + } } - } - Text { - id: audioCallPageIdText + Text { + id: audioCallPageIdText - Layout.alignment: Qt.AlignCenter + Layout.alignment: Qt.AlignCenter - Layout.preferredWidth: audioCallPageRectCentralRect.width - Layout.preferredHeight: 30 + Layout.preferredWidth: audioCallPageRectCentralRect.width + Layout.preferredHeight: 30 - font.pointSize: JamiTheme.textFontSize + font.pointSize: JamiTheme.textFontSize - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter - text: textMetricsAudioCallPageIdText.elidedText - color: "white" + text: textMetricsAudioCallPageIdText.elidedText + color: "white" - TextMetrics { - id: textMetricsAudioCallPageIdText - font: audioCallPageIdText.font - text: bestId - elideWidth: audioCallPageRectCentralRect.width - 50 - elide: Qt.ElideMiddle + TextMetrics { + id: textMetricsAudioCallPageIdText + font: audioCallPageIdText.font + text: bestId + elideWidth: audioCallPageRectCentralRect.width - 50 + elide: Qt.ElideMiddle + } } } - } - color: "transparent" + color: "transparent" + } } - color: "transparent" } diff --git a/src/mainview/components/CallStackView.qml b/src/mainview/components/CallStackView.qml index e265e6058..f2f800687 100644 --- a/src/mainview/components/CallStackView.qml +++ b/src/mainview/components/CallStackView.qml @@ -25,7 +25,7 @@ import net.jami.Models 1.0 import net.jami.Adapters 1.0 import "../js/incomingcallpagecreation.js" as IncomingCallPageCreation -import "../js/videocallfullscreenwindowcontainercreation.js" as VideoCallFullScreenWindowContainerCreation +import "../js/callfullscreenwindowcontainercreation.js" as CallFullScreenWindowContainerCreation Rectangle { id: callStackViewWindow @@ -50,7 +50,7 @@ Rectangle { // Close potential window, context menu releated windows. audioCallPage.closeContextMenuAndRelatedWindows() - VideoCallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer() + CallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer() videoCallPage.closeContextMenuAndRelatedWindows() } @@ -120,6 +120,20 @@ Rectangle { videoCallPage.setDistantRendererId(callId) } + function toogleFullScreen(callPage){ + callPage.isFullscreen = !callPage.isFullscreen + CallFullScreenWindowContainerCreation.createvideoCallFullScreenWindowContainerObject() + + if (!CallFullScreenWindowContainerCreation.checkIfVisible()) { + CallFullScreenWindowContainerCreation.setAsContainerChild( + callPage) + CallFullScreenWindowContainerCreation.showVideoCallFullScreenWindowContainer() + } else { + callPage.parent = callStackMainView + CallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer() + } + } + Connections { target: CallAdapter @@ -168,6 +182,9 @@ Rectangle { id: audioCallPage property int stackNumber: 0 + property bool isFullscreen: false + + onShowFullScreenReqested: toogleFullScreen(this) } OutgoingCallPage { @@ -186,20 +203,8 @@ Rectangle { property int stackNumber: 2 property bool isFullscreen: false - onNeedToShowInFullScreen: { - - isFullscreen = !isFullscreen - VideoCallFullScreenWindowContainerCreation.createvideoCallFullScreenWindowContainerObject() - - if (!VideoCallFullScreenWindowContainerCreation.checkIfVisible()) { - VideoCallFullScreenWindowContainerCreation.setAsContainerChild( - videoCallPage) - VideoCallFullScreenWindowContainerCreation.showVideoCallFullScreenWindowContainer() - } else { - videoCallPage.parent = callStackMainView - VideoCallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer() - } - + onShowFullScreenReqested: { + toogleFullScreen(this) videoCallPage.handleParticipantsInfo(CallAdapter.getConferencesInfos()) } } diff --git a/src/mainview/components/CallViewContextMenu.qml b/src/mainview/components/CallViewContextMenu.qml index 2d2aa8ab1..685df52bd 100644 --- a/src/mainview/components/CallViewContextMenu.qml +++ b/src/mainview/components/CallViewContextMenu.qml @@ -65,20 +65,31 @@ Item { ContextMenuGenerator.addMenuSeparator() } - if (!isAudioOnly && !isPaused) { - ContextMenuGenerator.addMenuItem(isRecording ? JamiStrings.stopRec : - JamiStrings.startRec, - "qrc:/images/icons/av_icons/fiber_manual_record-24px.svg", + ContextMenuGenerator.addMenuItem(isRecording ? JamiStrings.stopRec : + JamiStrings.startRec, + "qrc:/images/icons/av_icons/fiber_manual_record-24px.svg", + function (){ + CallAdapter.recordThisCallToggle() + }) + + if (isAudioOnly && !isPaused) + ContextMenuGenerator.addMenuItem(audioCallPage.isFullscreen ? JamiStrings.exitFullScreen : + JamiStrings.fullScreen, + audioCallPage.isFullscreen ? + "qrc:/images/icons/close_fullscreen-24px.svg" : + "qrc:/images/icons/open_in_full-24px.svg", function (){ - CallAdapter.recordThisCallToggle() + audioCallPage.showFullScreenReqested() }) + + if (!isAudioOnly && !isPaused) { ContextMenuGenerator.addMenuItem(videoCallPage.isFullscreen ? JamiStrings.exitFullScreen : JamiStrings.fullScreen, videoCallPage.isFullscreen ? "qrc:/images/icons/close_fullscreen-24px.svg" : "qrc:/images/icons/open_in_full-24px.svg", function (){ - videoCallPageRect.needToShowInFullScreen() + videoCallPage.showFullScreenReqested() }) ContextMenuGenerator.addMenuSeparator() diff --git a/src/mainview/components/VideoCallPage.qml b/src/mainview/components/VideoCallPage.qml index 41e7042f5..a83e4102d 100644 --- a/src/mainview/components/VideoCallPage.qml +++ b/src/mainview/components/VideoCallPage.qml @@ -40,7 +40,7 @@ Rectangle { property var linkedWebview: null - signal needToShowInFullScreen + signal showFullScreenReqested function updateUI(accountId, convUid) { videoCallOverlay.handleParticipantsInfo(CallAdapter.getConferencesInfos()) @@ -155,9 +155,7 @@ Rectangle { acceptedButtons: Qt.LeftButton - onDoubleClicked: { - needToShowInFullScreen() - } + onDoubleClicked: showFullScreenReqested() CallOverlay { id: videoCallOverlay diff --git a/src/mainview/js/callfullscreenwindowcontainercreation.js b/src/mainview/js/callfullscreenwindowcontainercreation.js new file mode 100644 index 000000000..9eba21925 --- /dev/null +++ b/src/mainview/js/callfullscreenwindowcontainercreation.js @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +// Global call full screen window container, object variable for creation. +var callFullScreenWindowContainerComponent +var callFullScreenWindowContainerObject + +function createvideoCallFullScreenWindowContainerObject() { + if (callFullScreenWindowContainerObject) + return + callFullScreenWindowContainerComponent = Qt.createComponent( + "../components/VideoCallFullScreenWindowContainer.qml") + if (callFullScreenWindowContainerComponent.status === Component.Ready) + finishCreation() + else if (callFullScreenWindowContainerComponent.status === Component.Error) + console.log("Error loading component:", + callFullScreenWindowContainerComponent.errorString()) +} + +function finishCreation() { + callFullScreenWindowContainerObject + = callFullScreenWindowContainerComponent.createObject() + if (callFullScreenWindowContainerObject === null) { + // Error Handling. + console.log("Error creating video call full screen window container object") + } + + // Signal connection. + callFullScreenWindowContainerObject.onClosing.connect( + destoryVideoCallFullScreenWindowContainer) +} + +function checkIfVisible() { + if (!callFullScreenWindowContainerObject) + return false + return callFullScreenWindowContainerObject.visible +} + +function setAsContainerChild(obj) { + if (callFullScreenWindowContainerObject) + callFullScreenWindowContainerObject.setAsChild(obj) +} + +// Destroy and reset callFullScreenWindowContainerObject when window is closed. +function destoryVideoCallFullScreenWindowContainer() { + if (!callFullScreenWindowContainerObject) + return + callFullScreenWindowContainerObject.destroy() + callFullScreenWindowContainerObject = false +} + +function showVideoCallFullScreenWindowContainer() { + if (callFullScreenWindowContainerObject) { + + // Hack: show first, then showFullScreen to make sure that the showFullScreen + // display on the correct screen. + callFullScreenWindowContainerObject.show() + callFullScreenWindowContainerObject.showFullScreen() + } +} + +function closeVideoCallFullScreenWindowContainer() { + if (callFullScreenWindowContainerObject) + callFullScreenWindowContainerObject.close() +} diff --git a/src/mainview/js/videocallfullscreenwindowcontainercreation.js b/src/mainview/js/videocallfullscreenwindowcontainercreation.js deleted file mode 100644 index 14c007ce6..000000000 --- a/src/mainview/js/videocallfullscreenwindowcontainercreation.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2020 by Savoir-faire Linux - * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - - -/* - * Global video call full screen window container, object variable for creation. - */ -var videoCallFullScreenWindowContainerComponent -var videoCallFullScreenWindowContainerObject - -function createvideoCallFullScreenWindowContainerObject() { - if (videoCallFullScreenWindowContainerObject) - return - videoCallFullScreenWindowContainerComponent = Qt.createComponent( - "../components/VideoCallFullScreenWindowContainer.qml") - if (videoCallFullScreenWindowContainerComponent.status === Component.Ready) - finishCreation() - else if (videoCallFullScreenWindowContainerComponent.status === Component.Error) - console.log("Error loading component:", - videoCallFullScreenWindowContainerComponent.errorString()) -} - -function finishCreation() { - videoCallFullScreenWindowContainerObject - = videoCallFullScreenWindowContainerComponent.createObject() - if (videoCallFullScreenWindowContainerObject === null) { - - - /* - * Error Handling. - */ - console.log("Error creating video call full screen window container object") - } - - - /* - * Signal connection. - */ - videoCallFullScreenWindowContainerObject.onClosing.connect( - destoryVideoCallFullScreenWindowContainer) -} - -function checkIfVisible() { - if (!videoCallFullScreenWindowContainerObject) - return false - return videoCallFullScreenWindowContainerObject.visible -} - -function setAsContainerChild(obj) { - if (videoCallFullScreenWindowContainerObject) - videoCallFullScreenWindowContainerObject.setAsChild(obj) -} - - -/* - * Destroy and reset videoCallFullScreenWindowContainerObject when window is closed. - */ -function destoryVideoCallFullScreenWindowContainer() { - if (!videoCallFullScreenWindowContainerObject) - return - videoCallFullScreenWindowContainerObject.destroy() - videoCallFullScreenWindowContainerObject = false -} - -function showVideoCallFullScreenWindowContainer() { - if (videoCallFullScreenWindowContainerObject) { - - - /* - * Hack: show first, then showFullScreen to make sure that the showFullScreen - * display on the correct screen. - */ - videoCallFullScreenWindowContainerObject.show() - videoCallFullScreenWindowContainerObject.showFullScreen() - } -} - -function closeVideoCallFullScreenWindowContainer() { - if (videoCallFullScreenWindowContainerObject) - videoCallFullScreenWindowContainerObject.close() -} -- GitLab