blob: 4657a7ed3c99a9cc2ee08c3c3381688262b674f4 [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) {
45 bestName = ClientWrapper.utilsAdaptor.getBestName(accountId, convUid)
46
47 var id = ClientWrapper.utilsAdaptor.getBestId(accountId, convUid)
48 bestId = (bestName !== id) ? id : ""
49 }
50
51 function setDistantRendererId(id) {
52 distantRenderer.setRendererId(id)
53 }
54
Sébastien Blin8940f3c2020-07-23 17:03:11 -040055 function setLinkedWebview(webViewId) {
56 linkedWebview = webViewId
57 linkedWebview.needToHideConversationInCall.disconnect(
Sébastien Blin1f915762020-08-03 13:27:42 -040058 closeInCallConversation)
Sébastien Blin8940f3c2020-07-23 17:03:11 -040059 linkedWebview.needToHideConversationInCall.connect(
Sébastien Blin1f915762020-08-03 13:27:42 -040060 closeInCallConversation)
61 }
62
63 function closeInCallConversation() {
64 if (inVideoCallMessageWebViewStack.visible) {
Sébastien Blin8940f3c2020-07-23 17:03:11 -040065 linkedWebview.resetMessagingHeaderBackButtonSource(
Sébastien Blin1f915762020-08-03 13:27:42 -040066 true)
Sébastien Blin8940f3c2020-07-23 17:03:11 -040067 linkedWebview.setMessagingHeaderButtonsVisible(true)
Sébastien Blin1f915762020-08-03 13:27:42 -040068 inVideoCallMessageWebViewStack.visible = false
69 inVideoCallMessageWebViewStack.clear()
70 }
71 }
72
73 function closeContextMenuAndRelatedWindows() {
Sébastien Blin1f915762020-08-03 13:27:42 -040074 videoCallOverlay.closePotentialContactPicker()
75 }
76
77 function previewMagneticSnap() {
78
79
80 /*
81 * Calculate the position where the previewRenderer should attach to.
82 */
83 var previewRendererCenter = Qt.point(
84 previewRenderer.x + previewRenderer.width / 2,
85 previewRenderer.y + previewRenderer.height / 2)
86 var distantRendererCenter = Qt.point(
87 distantRenderer.x + distantRenderer.width / 2,
88 distantRenderer.y + distantRenderer.height / 2)
89
90 if (previewRendererCenter.x >= distantRendererCenter.x) {
91 if (previewRendererCenter.y >= distantRendererCenter.y) {
92
93
94 /*
95 * Bottom right.
96 */
97 previewToX = Qt.binding(function () {
98 return videoCallPageMainRect.width - previewRenderer.width - previewMargin
99 })
100 previewToY = Qt.binding(function () {
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400101 return videoCallPageMainRect.height - previewRenderer.height - previewMarginY
Sébastien Blin1f915762020-08-03 13:27:42 -0400102 })
103 } else {
104
105
106 /*
107 * Top right.
108 */
109 previewToX = Qt.binding(function () {
110 return videoCallPageMainRect.width - previewRenderer.width - previewMargin
111 })
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400112 previewToY = previewMarginY
Sébastien Blin1f915762020-08-03 13:27:42 -0400113 }
114 } else {
115 if (previewRendererCenter.y >= distantRendererCenter.y) {
116
117
118 /*
119 * Bottom left.
120 */
121 previewToX = previewMargin
122 previewToY = Qt.binding(function () {
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400123 return videoCallPageMainRect.height - previewRenderer.height - previewMarginY
Sébastien Blin1f915762020-08-03 13:27:42 -0400124 })
125 } else {
126
127
128 /*
129 * Top left.
130 */
131 previewToX = previewMargin
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400132 previewToY = previewMarginY
Sébastien Blin1f915762020-08-03 13:27:42 -0400133 }
134 }
135 previewRenderer.state = "geoChanging"
136 }
137
Sébastien Blin1f915762020-08-03 13:27:42 -0400138 anchors.fill: parent
139
140 SplitView {
141 id: mainColumnLayout
142
143 anchors.fill: parent
144
145 orientation: Qt.Vertical
146
147 handle: Rectangle {
148 implicitWidth: videoCallPageRect.width
149 implicitHeight: JamiTheme.splitViewHandlePreferedWidth
150 color: SplitHandle.pressed ? JamiTheme.pressColor : (SplitHandle.hovered ? JamiTheme.hoverColor : JamiTheme.tabbarBorderColor)
151 }
152
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400153
Sébastien Blin1f915762020-08-03 13:27:42 -0400154 Rectangle {
155 id: videoCallPageMainRect
Sébastien Blin1f915762020-08-03 13:27:42 -0400156 SplitView.preferredHeight: (videoCallPageRect.height / 3) * 2
157 SplitView.minimumHeight: videoCallPageRect.height / 2 + 20
158 SplitView.fillWidth: true
159
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400160 MouseArea {
Sébastien Blin1f915762020-08-03 13:27:42 -0400161 anchors.fill: parent
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400162 hoverEnabled: true
163 propagateComposedEvents: true
Sébastien Blin1f915762020-08-03 13:27:42 -0400164
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400165 acceptedButtons: Qt.LeftButton
Sébastien Blin1f915762020-08-03 13:27:42 -0400166
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400167 onDoubleClicked: {
168 needToShowInFullScreen()
Sébastien Blin1f915762020-08-03 13:27:42 -0400169 }
170
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400171 CallOverlay {
172 id: videoCallOverlay
Sébastien Blin1f915762020-08-03 13:27:42 -0400173
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400174 anchors.fill: parent
Sébastien Blin1f915762020-08-03 13:27:42 -0400175
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400176 Connections {
177 target: CallAdapter
Sébastien Blin1f915762020-08-03 13:27:42 -0400178
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400179 function onUpdateTimeText(time) {
180 videoCallOverlay.timeText = time
181 videoCallOverlay.setRecording(CallAdapter.isRecordingThisCall())
182 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400183
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400184 function onUpdateOverlay(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall, bestName) {
185 videoCallOverlay.showOnHoldImage(isPaused)
186 videoCallOverlay.updateButtonStatus(isPaused,
187 isAudioOnly,
188 isAudioMuted,
189 isVideoMuted,
190 isRecording, isSIP,
191 isConferenceCall)
192 videoCallPageRect.bestName = bestName
193 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400194
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400195 function onShowOnHoldLabel(isPaused) {
196 videoCallOverlay.showOnHoldImage(isPaused)
Sébastien Blin1f915762020-08-03 13:27:42 -0400197 }
198 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400199
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400200 onOverlayChatButtonClicked: {
201 if (inVideoCallMessageWebViewStack.visible) {
202 linkedWebview.resetMessagingHeaderBackButtonSource(
203 true)
204 linkedWebview.setMessagingHeaderButtonsVisible(
205 true)
206 inVideoCallMessageWebViewStack.visible = false
207 inVideoCallMessageWebViewStack.clear()
208 } else {
209 linkedWebview.resetMessagingHeaderBackButtonSource(
210 false)
211 linkedWebview.setMessagingHeaderButtonsVisible(
212 false)
213 inVideoCallMessageWebViewStack.visible = true
214 inVideoCallMessageWebViewStack.push(
215 linkedWebview)
216 }
217 }
218 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400219
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400220 DistantRenderer {
221 id: distantRenderer
222
223 anchors.centerIn: videoCallPageMainRect
224 z: -1
225
226 width: videoCallPageMainRect.width
227 height: videoCallPageMainRect.height
228 }
229
230 VideoCallPreviewRenderer {
231 id: previewRenderer
232
233
234 /*
235 * Property is used in the {} expression for height (extra dependency),
236 * it will not affect the true height expression, since expression
237 * at last will be taken only, but it will force the height to update
238 * and reevaluate getPreviewImageScalingFactor().
239 */
240 property int previewImageScalingFactorUpdated: 0
241
242 Connections {
243 target: CallAdapter
244
245 onPreviewVisibilityNeedToChange: previewRenderer.visible = visible
246 }
247
248 width: videoCallPageMainRect.width / 4
249 height: {
250 previewImageScalingFactorUpdated
251 return previewRenderer.width * previewRenderer.getPreviewImageScalingFactor()
252 }
253 x: videoCallPageMainRect.width - previewRenderer.width - previewMargin
254 y: videoCallPageMainRect.height - previewRenderer.height - previewMargin - 56 /* Avoid overlay */
255 z: -1
256
257 states: [
258 State {
259 name: "geoChanging"
260 PropertyChanges {
261 target: previewRenderer
262 x: previewToX
263 y: previewToY
264 }
265 }
266 ]
267
268 transitions: Transition {
269 PropertyAnimation {
270 properties: "x,y"
271 easing.type: Easing.OutExpo
272 duration: 250
273
274 onStopped: {
275 previewRenderer.state = ""
276 }
277 }
278 }
279
280 MouseArea {
281 id: dragMouseArea
282
283 anchors.fill: previewRenderer
284
285 onPressed: {
286 clickPos = Qt.point(mouse.x, mouse.y)
287 }
288
289 onReleased: {
Sébastien Blin1f915762020-08-03 13:27:42 -0400290 previewRenderer.state = ""
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400291 previewMagneticSnap()
292 }
293
294 onPositionChanged: {
295
296
297 /*
298 * Calculate mouse position relative change.
299 */
300 var delta = Qt.point(mouse.x - clickPos.x,
301 mouse.y - clickPos.y)
302 var deltaW = previewRenderer.x + delta.x + previewRenderer.width
303 var deltaH = previewRenderer.y + delta.y + previewRenderer.height
304
305
306 /*
307 * Check if the previewRenderer exceeds the border of videoCallPageMainRect.
308 */
309 if (deltaW < videoCallPageMainRect.width
310 && previewRenderer.x + delta.x > 1)
311 previewRenderer.x += delta.x
312 if (deltaH < videoCallPageMainRect.height
313 && previewRenderer.y + delta.y > 1)
314 previewRenderer.y += delta.y
Sébastien Blin1f915762020-08-03 13:27:42 -0400315 }
316 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400317
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400318 onPreviewImageAvailable: {
319 previewImageScalingFactorUpdated++
320 previewImageScalingFactorUpdated--
Sébastien Blin1f915762020-08-03 13:27:42 -0400321 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400322 }
323 }
324
325 color: "transparent"
326 }
327
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400328
Sébastien Blin1f915762020-08-03 13:27:42 -0400329 StackView {
330 id: inVideoCallMessageWebViewStack
331
332 SplitView.preferredHeight: videoCallPageRect.height / 3
333 SplitView.fillWidth: true
334
335 visible: false
336
337 clip: true
338 }
339 }
340
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400341 onBestNameChanged: {
342 ContactAdapter.setCalleeDisplayName(bestName)
Sébastien Blin1f915762020-08-03 13:27:42 -0400343 }
344
345 color: "black"
346}