1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-08-01 13:25:46 +02:00

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
This commit is contained in:
Ming Rui Zhang 2020-10-01 12:43:24 -04:00 committed by Andreas Traczyk
parent 695dff3994
commit 4adc59ad5d
7 changed files with 245 additions and 234 deletions

View file

@ -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>

View file

@ -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()
function onShowOnHoldLabel(isPaused) {
audioCallOverlay.showOnHoldImage(isPaused)
audioCallPageRectCentralRect.visible = !isPaused
}
}
CallOverlay {
id: audioCallOverlay
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)
}
}
}
anchors.fill: parent
Rectangle {
id: audioCallPageRectCentralRect
Connections {
target: CallAdapter
anchors.centerIn: parent
function onUpdateTimeText(time) {
audioCallOverlay.timeText = time
audioCallOverlay.setRecording(CallAdapter.isRecordingThisCall())
}
width: audioCallPageRect.width
height: audioCallPageRegisteredNameText.height
+ audioCallPageIdText.height + contactImage.height + 10
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
}
ColumnLayout {
id: audioCallPageRectColumnLayout
Image {
id: contactImage
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 100
Layout.preferredHeight: 100
fillMode: Image.PreserveAspectFit
source: contactImgSource
asynchronous: true
}
Text {
id: audioCallPageRegisteredNameText
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: audioCallPageRectCentralRect.width
Layout.preferredHeight: 50
font.pointSize: JamiTheme.textFontSize + 3
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: textMetricsAudioCallPageRegisteredNameText.elidedText
color: "white"
TextMetrics {
id: textMetricsAudioCallPageRegisteredNameText
font: audioCallPageRegisteredNameText.font
text: bestName
elideWidth: audioCallPageRectCentralRect.width - 50
elide: Qt.ElideMiddle
function onShowOnHoldLabel(isPaused) {
audioCallOverlay.showOnHoldImage(isPaused)
audioCallPageRectCentralRect.visible = !isPaused
}
}
Text {
id: audioCallPageIdText
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: audioCallPageRectCentralRect.width
Layout.preferredHeight: 30
font.pointSize: JamiTheme.textFontSize
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: textMetricsAudioCallPageIdText.elidedText
color: "white"
TextMetrics {
id: textMetricsAudioCallPageIdText
font: audioCallPageIdText.font
text: bestId
elideWidth: audioCallPageRectCentralRect.width - 50
elide: Qt.ElideMiddle
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)
}
}
}
color: "transparent"
}
Rectangle {
id: audioCallPageRectCentralRect
anchors.centerIn: parent
width: audioCallPageRect.width
height: audioCallPageRegisteredNameText.height
+ audioCallPageIdText.height + contactImage.height + 10
ColumnLayout {
id: audioCallPageRectColumnLayout
Image {
id: contactImage
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 100
Layout.preferredHeight: 100
fillMode: Image.PreserveAspectFit
source: contactImgSource
asynchronous: true
}
Text {
id: audioCallPageRegisteredNameText
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: audioCallPageRectCentralRect.width
Layout.preferredHeight: 50
font.pointSize: JamiTheme.textFontSize + 3
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: textMetricsAudioCallPageRegisteredNameText.elidedText
color: "white"
TextMetrics {
id: textMetricsAudioCallPageRegisteredNameText
font: audioCallPageRegisteredNameText.font
text: bestName
elideWidth: audioCallPageRectCentralRect.width - 50
elide: Qt.ElideMiddle
}
}
Text {
id: audioCallPageIdText
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: audioCallPageRectCentralRect.width
Layout.preferredHeight: 30
font.pointSize: JamiTheme.textFontSize
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: textMetricsAudioCallPageIdText.elidedText
color: "white"
TextMetrics {
id: textMetricsAudioCallPageIdText
font: audioCallPageIdText.font
text: bestId
elideWidth: audioCallPageRectCentralRect.width - 50
elide: Qt.ElideMiddle
}
}
}
color: "transparent"
}
}
color: "transparent"
}

View file

@ -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())
}
}

View file

@ -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()

View file

@ -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

View file

@ -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()
}

View file

@ -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()
}