blob: 5ec8c82f48b0551e186cfed39d6726a435f446bb [file] [log] [blame]
Sébastien Blin1f915762020-08-03 13:27:42 -04001
2/*
3 * Copyright (C) 2020 by Savoir-faire Linux
4 * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
Sébastien Blin8940f3c2020-07-23 17:03:11 -04005 * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
Sébastien Blin1f915762020-08-03 13:27:42 -04006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20import QtQuick 2.14
21import QtQuick.Controls 2.14
22import QtQuick.Layouts 1.14
23import QtQuick.Controls.Universal 2.12
24import QtGraphicalEffects 1.14
25import net.jami.Models 1.0
26
27import "../../commoncomponents"
28
29Rectangle {
30 id: videoCallPageRect
31
32 property string bestName: "Best Name"
33 property string bestId: "Best Id"
34 property variant clickPos: "1,1"
35 property int previewMargin: 15
Sébastien Blin8940f3c2020-07-23 17:03:11 -040036 property int previewMarginY: previewMargin + 56
Sébastien Blin1f915762020-08-03 13:27:42 -040037 property int previewToX: 0
38 property int previewToY: 0
39
Sébastien Blin8940f3c2020-07-23 17:03:11 -040040 property var linkedWebview: null
Sébastien Blin1f915762020-08-03 13:27:42 -040041
Sébastien Blin1f915762020-08-03 13:27:42 -040042 signal needToShowInFullScreen
43
44 function updateUI(accountId, convUid) {
Sébastien Blin6607e0e2020-07-24 15:15:47 -040045 videoCallOverlay.handleParticipantsInfo(CallAdapter.getConferencesInfos())
46
Sébastien Blin1f915762020-08-03 13:27:42 -040047 bestName = ClientWrapper.utilsAdaptor.getBestName(accountId, convUid)
48
49 var id = ClientWrapper.utilsAdaptor.getBestId(accountId, convUid)
50 bestId = (bestName !== id) ? id : ""
51 }
52
53 function setDistantRendererId(id) {
54 distantRenderer.setRendererId(id)
55 }
56
Sébastien Blin8940f3c2020-07-23 17:03:11 -040057 function setLinkedWebview(webViewId) {
58 linkedWebview = webViewId
59 linkedWebview.needToHideConversationInCall.disconnect(
Sébastien Blin1f915762020-08-03 13:27:42 -040060 closeInCallConversation)
Sébastien Blin8940f3c2020-07-23 17:03:11 -040061 linkedWebview.needToHideConversationInCall.connect(
Sébastien Blin1f915762020-08-03 13:27:42 -040062 closeInCallConversation)
63 }
64
65 function closeInCallConversation() {
66 if (inVideoCallMessageWebViewStack.visible) {
Sébastien Blin8940f3c2020-07-23 17:03:11 -040067 linkedWebview.resetMessagingHeaderBackButtonSource(
Sébastien Blin1f915762020-08-03 13:27:42 -040068 true)
Sébastien Blin8940f3c2020-07-23 17:03:11 -040069 linkedWebview.setMessagingHeaderButtonsVisible(true)
Sébastien Blin1f915762020-08-03 13:27:42 -040070 inVideoCallMessageWebViewStack.visible = false
71 inVideoCallMessageWebViewStack.clear()
72 }
73 }
74
75 function closeContextMenuAndRelatedWindows() {
Sébastien Blin1f915762020-08-03 13:27:42 -040076 videoCallOverlay.closePotentialContactPicker()
77 }
78
Sébastien Blin6607e0e2020-07-24 15:15:47 -040079 function handleParticipantsInfo(infos) {
80 if (infos.length === 0) {
81 bestName = ClientWrapper.utilsAdaptor.getBestName(accountId, convUid)
82 } else {
83 bestName = ""
84 }
85 videoCallOverlay.handleParticipantsInfo(infos)
86 }
87
Sébastien Blin1f915762020-08-03 13:27:42 -040088 function previewMagneticSnap() {
89
90
agsantosc5687502020-09-03 21:19:10 -040091 // Calculate the position where the previewRenderer should attach to.
Sébastien Blin1f915762020-08-03 13:27:42 -040092 var previewRendererCenter = Qt.point(
93 previewRenderer.x + previewRenderer.width / 2,
94 previewRenderer.y + previewRenderer.height / 2)
95 var distantRendererCenter = Qt.point(
96 distantRenderer.x + distantRenderer.width / 2,
97 distantRenderer.y + distantRenderer.height / 2)
98
99 if (previewRendererCenter.x >= distantRendererCenter.x) {
100 if (previewRendererCenter.y >= distantRendererCenter.y) {
101
102
agsantosc5687502020-09-03 21:19:10 -0400103 // Bottom right.
Sébastien Blin1f915762020-08-03 13:27:42 -0400104 previewToX = Qt.binding(function () {
105 return videoCallPageMainRect.width - previewRenderer.width - previewMargin
106 })
107 previewToY = Qt.binding(function () {
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400108 return videoCallPageMainRect.height - previewRenderer.height - previewMarginY
Sébastien Blin1f915762020-08-03 13:27:42 -0400109 })
110 } else {
111
112
agsantosc5687502020-09-03 21:19:10 -0400113 // Top right.
Sébastien Blin1f915762020-08-03 13:27:42 -0400114 previewToX = Qt.binding(function () {
115 return videoCallPageMainRect.width - previewRenderer.width - previewMargin
116 })
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400117 previewToY = previewMarginY
Sébastien Blin1f915762020-08-03 13:27:42 -0400118 }
119 } else {
120 if (previewRendererCenter.y >= distantRendererCenter.y) {
121
122
agsantosc5687502020-09-03 21:19:10 -0400123 // Bottom left.
Sébastien Blin1f915762020-08-03 13:27:42 -0400124 previewToX = previewMargin
125 previewToY = Qt.binding(function () {
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400126 return videoCallPageMainRect.height - previewRenderer.height - previewMarginY
Sébastien Blin1f915762020-08-03 13:27:42 -0400127 })
128 } else {
129
130
agsantosc5687502020-09-03 21:19:10 -0400131 // Top left.
Sébastien Blin1f915762020-08-03 13:27:42 -0400132 previewToX = previewMargin
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400133 previewToY = previewMarginY
Sébastien Blin1f915762020-08-03 13:27:42 -0400134 }
135 }
136 previewRenderer.state = "geoChanging"
137 }
138
Sébastien Blin1f915762020-08-03 13:27:42 -0400139 anchors.fill: parent
140
141 SplitView {
142 id: mainColumnLayout
143
144 anchors.fill: parent
145
146 orientation: Qt.Vertical
147
148 handle: Rectangle {
149 implicitWidth: videoCallPageRect.width
ababia284cae2020-08-10 12:33:34 +0200150 implicitHeight: JamiTheme.splitViewHandlePreferredWidth
Sébastien Blin1f915762020-08-03 13:27:42 -0400151 color: SplitHandle.pressed ? JamiTheme.pressColor : (SplitHandle.hovered ? JamiTheme.hoverColor : JamiTheme.tabbarBorderColor)
152 }
153
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400154
Sébastien Blin1f915762020-08-03 13:27:42 -0400155 Rectangle {
156 id: videoCallPageMainRect
Sébastien Blin1f915762020-08-03 13:27:42 -0400157 SplitView.preferredHeight: (videoCallPageRect.height / 3) * 2
158 SplitView.minimumHeight: videoCallPageRect.height / 2 + 20
159 SplitView.fillWidth: true
160
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400161 MouseArea {
Sébastien Blin1f915762020-08-03 13:27:42 -0400162 anchors.fill: parent
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400163 hoverEnabled: true
164 propagateComposedEvents: true
Sébastien Blin1f915762020-08-03 13:27:42 -0400165
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400166 acceptedButtons: Qt.LeftButton
Sébastien Blin1f915762020-08-03 13:27:42 -0400167
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400168 onDoubleClicked: {
169 needToShowInFullScreen()
Sébastien Blin1f915762020-08-03 13:27:42 -0400170 }
171
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400172 CallOverlay {
173 id: videoCallOverlay
Sébastien Blin1f915762020-08-03 13:27:42 -0400174
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400175 anchors.fill: parent
Sébastien Blin1f915762020-08-03 13:27:42 -0400176
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400177 Connections {
178 target: CallAdapter
Sébastien Blin1f915762020-08-03 13:27:42 -0400179
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400180 function onUpdateTimeText(time) {
181 videoCallOverlay.timeText = time
182 videoCallOverlay.setRecording(CallAdapter.isRecordingThisCall())
183 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400184
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400185 function onUpdateOverlay(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall, bestName) {
186 videoCallOverlay.showOnHoldImage(isPaused)
187 videoCallOverlay.updateButtonStatus(isPaused,
188 isAudioOnly,
189 isAudioMuted,
190 isVideoMuted,
191 isRecording, isSIP,
192 isConferenceCall)
193 videoCallPageRect.bestName = bestName
194 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400195
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400196 function onShowOnHoldLabel(isPaused) {
197 videoCallOverlay.showOnHoldImage(isPaused)
Sébastien Blin1f915762020-08-03 13:27:42 -0400198 }
199 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400200
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400201 onOverlayChatButtonClicked: {
202 if (inVideoCallMessageWebViewStack.visible) {
203 linkedWebview.resetMessagingHeaderBackButtonSource(
204 true)
205 linkedWebview.setMessagingHeaderButtonsVisible(
206 true)
207 inVideoCallMessageWebViewStack.visible = false
208 inVideoCallMessageWebViewStack.clear()
209 } else {
210 linkedWebview.resetMessagingHeaderBackButtonSource(
211 false)
212 linkedWebview.setMessagingHeaderButtonsVisible(
213 false)
214 inVideoCallMessageWebViewStack.visible = true
215 inVideoCallMessageWebViewStack.push(
216 linkedWebview)
217 }
218 }
219 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400220
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400221 DistantRenderer {
222 id: distantRenderer
223
224 anchors.centerIn: videoCallPageMainRect
225 z: -1
226
227 width: videoCallPageMainRect.width
228 height: videoCallPageMainRect.height
Sébastien Blin6607e0e2020-07-24 15:15:47 -0400229
230 onOffsetChanged: {
231 videoCallOverlay.handleParticipantsInfo(CallAdapter.getConferencesInfos())
232 }
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400233 }
234
235 VideoCallPreviewRenderer {
236 id: previewRenderer
237
238
agsantosc5687502020-09-03 21:19:10 -0400239 // Property is used in the {} expression for height (extra dependency),
240 // it will not affect the true height expression, since expression
241 // at last will be taken only, but it will force the height to update
242 // and reevaluate getPreviewImageScalingFactor().
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400243 property int previewImageScalingFactorUpdated: 0
244
245 Connections {
246 target: CallAdapter
247
248 onPreviewVisibilityNeedToChange: previewRenderer.visible = visible
249 }
250
251 width: videoCallPageMainRect.width / 4
252 height: {
253 previewImageScalingFactorUpdated
254 return previewRenderer.width * previewRenderer.getPreviewImageScalingFactor()
255 }
256 x: videoCallPageMainRect.width - previewRenderer.width - previewMargin
agsantosc5687502020-09-03 21:19:10 -0400257 y: videoCallPageMainRect.height - previewRenderer.height - previewMargin - 56 // Avoid overlay
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400258 z: -1
259
260 states: [
261 State {
262 name: "geoChanging"
263 PropertyChanges {
264 target: previewRenderer
265 x: previewToX
266 y: previewToY
267 }
268 }
269 ]
270
271 transitions: Transition {
272 PropertyAnimation {
273 properties: "x,y"
274 easing.type: Easing.OutExpo
275 duration: 250
276
277 onStopped: {
278 previewRenderer.state = ""
279 }
280 }
281 }
282
283 MouseArea {
284 id: dragMouseArea
285
286 anchors.fill: previewRenderer
287
288 onPressed: {
289 clickPos = Qt.point(mouse.x, mouse.y)
290 }
291
292 onReleased: {
Sébastien Blin1f915762020-08-03 13:27:42 -0400293 previewRenderer.state = ""
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400294 previewMagneticSnap()
295 }
296
297 onPositionChanged: {
298
299
agsantosc5687502020-09-03 21:19:10 -0400300 // Calculate mouse position relative change.
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400301 var delta = Qt.point(mouse.x - clickPos.x,
302 mouse.y - clickPos.y)
303 var deltaW = previewRenderer.x + delta.x + previewRenderer.width
304 var deltaH = previewRenderer.y + delta.y + previewRenderer.height
305
306
agsantosc5687502020-09-03 21:19:10 -0400307 // Check if the previewRenderer exceeds the border of videoCallPageMainRect.
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400308 if (deltaW < videoCallPageMainRect.width
309 && previewRenderer.x + delta.x > 1)
310 previewRenderer.x += delta.x
311 if (deltaH < videoCallPageMainRect.height
312 && previewRenderer.y + delta.y > 1)
313 previewRenderer.y += delta.y
Sébastien Blin1f915762020-08-03 13:27:42 -0400314 }
315 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400316
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400317 onPreviewImageAvailable: {
318 previewImageScalingFactorUpdated++
319 previewImageScalingFactorUpdated--
Sébastien Blin1f915762020-08-03 13:27:42 -0400320 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400321 }
322 }
323
324 color: "transparent"
325 }
326
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400327
Sébastien Blin1f915762020-08-03 13:27:42 -0400328 StackView {
329 id: inVideoCallMessageWebViewStack
330
331 SplitView.preferredHeight: videoCallPageRect.height / 3
332 SplitView.fillWidth: true
333
334 visible: false
335
336 clip: true
337 }
338 }
339
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400340 onBestNameChanged: {
341 ContactAdapter.setCalleeDisplayName(bestName)
Sébastien Blin1f915762020-08-03 13:27:42 -0400342 }
343
344 color: "black"
345}