blob: e948cd0bf5df78e33de410d3c67e30b65b6076e8 [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>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19import QtQuick 2.14
20import QtQuick.Window 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
27
28/*
29 * Import qml component files.
30 */
31import "components"
32import "../settingsview"
33
34Window {
35 id: mainViewWindow
36
37 property int minWidth: sidePanelViewStackPreferedWidth
38 property int minHeight: aboutPopUpDialog.contentHeight
39
40 property int mainViewWindowPreferedWidth: 650
41 property int mainViewWindowPreferedHeight: 600
42 property int sidePanelViewStackPreferedWidth: 250
43 property int welcomePageGroupPreferedWidth: 250
44 property int aboutPopUpPreferedWidth: 250
45
ababidf651a22020-07-30 13:38:57 +020046 property int savedSidePanelViewMinWidth: 0
47 property int savedSidePanelViewMaxWidth: 0
48 property int savedWelcomeViewMinWidth: 0
49 property int savedWelcomeViewMaxWidth: 0
50 property bool hiddenView: false
Sébastien Blin1f915762020-08-03 13:27:42 -040051
52 /*
53 * To calculate tab bar bottom border hidden rect left margin.
54 */
55 property int tabBarLeftMargin: 8
56 property int tabButtonShrinkSize: 8
57
58 signal noAccountIsAvailable
59 signal needToAddNewAccount
60 signal closeApp
61
62 function newAccountAdded(index) {
63 mainViewWindowSidePanel.refreshAccountComboBox(index)
64 }
65
66 function recursionStackViewItemMove(stackOne, stackTwo) {
67
68
69 /*
70 * Move all items (expect the bottom item) to stacktwo by the same order in stackone.
71 */
72 if (stackOne.depth === 1) {
73 return
74 }
75
76 var tempItem = stackOne.pop(StackView.Immediate)
77 recursionStackViewItemMove(stackOne, stackTwo)
78 stackTwo.push(tempItem, StackView.Immediate)
79 }
80
81 title: "Jami"
82 visible: true
83 width: mainViewWindowPreferedWidth
84 height: mainViewWindowPreferedHeight
85 minimumWidth: minWidth
86 minimumHeight: minHeight
87
88 Connections {
89 target: CallAdapter
90
91 function onShowCallStack(accountId, convUid, forceReset) {
92 if (forceReset) {
93 callStackView.responsibleAccountId = accountId
94 callStackView.responsibleConvUid = convUid
95 }
96
97
98 /*
99 * Check if it is coming from the current responsible call,
100 * and push views onto the correct stackview
101 */
102 if (callStackView.responsibleAccountId === accountId
103 && callStackView.responsibleConvUid === convUid) {
104 if (welcomeViewStack.visible) {
105 welcomeViewStack.pop(null, StackView.Immediate)
106 welcomeViewStack.push(callStackView, StackView.Immediate)
107 } else {
108 sidePanelViewStack.pop(null, StackView.Immediate)
109 sidePanelViewStack.push(callStackView, StackView.Immediate)
110 }
111 }
112 }
113
114 function onCloseCallStack(accountId, convUid) {
115
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400116 var responsibleCallId = ClientWrapper.utilsAdaptor.getCallId(
117 callStackView.responsibleAccountId, callStackView.responsibleConvUid)
118 var callId = ClientWrapper.utilsAdaptor.getCallId(
119 callStackView.responsibleAccountId, convUid)
Sébastien Blin1f915762020-08-03 13:27:42 -0400120 /*
121 * Check if call stack view is on any of the stackview.
122 */
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400123 if (responsibleCallId === callId || responsibleCallId.length === 0) {
Sébastien Blin1f915762020-08-03 13:27:42 -0400124 if (welcomeViewStack.find(function (item, index) {
125 return item.objectName === "callStackViewObject"
126 }) || sidePanelViewStack.find(function (item, index) {
127 return item.objectName === "callStackViewObject"
128 })) {
129 callStackView.needToCloseInCallConversationAndPotentialWindow()
130 if (welcomeViewStack.visible) {
131 welcomeViewStack.pop(null, StackView.Immediate)
132 welcomeViewStack.push(communicationPageMessageWebView,
133 StackView.Immediate)
134 } else {
135 sidePanelViewStack.pop(null, StackView.Immediate)
136 sidePanelViewStack.push(
137 communicationPageMessageWebView,
138 StackView.Immediate)
139 }
140 }
141 }
142 }
143
144 function onIncomingCallNeedToSetupMainView(accountId, convUid) {
145
146
147 /*
148 * Set up the call stack view that is needed by call overlay.
149 */
150 welcomeViewStack.pop(null, StackView.Immediate)
151 sidePanelViewStack.pop(null, StackView.Immediate)
152
153 var index = ClientWrapper.utilsAdaptor.getCurrAccList().indexOf(accountId)
154 var name = ClientWrapper.utilsAdaptor.getBestName(accountId, convUid)
155 var id = ClientWrapper.utilsAdaptor.getBestId(accountId, convUid)
156
157 communicationPageMessageWebView.headerUserAliasLabelText = name
158 communicationPageMessageWebView.headerUserUserNameLabelText = (name !== id) ? id : ""
159
160 callStackView.needToCloseInCallConversationAndPotentialWindow()
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400161 callStackView.setLinkedWebview(
Sébastien Blin1f915762020-08-03 13:27:42 -0400162 communicationPageMessageWebView)
163
164 callStackView.responsibleAccountId = accountId
165 callStackView.responsibleConvUid = convUid
166 callStackView.updateCorrspondingUI()
167
168 mainViewWindowSidePanel.needToChangeToAccount(accountId, index)
169 ConversationsAdapter.selectConversation(accountId, convUid)
170
171 MessagesAdapter.setupChatView(convUid)
172 }
173 }
174
175 StackLayout {
176 id: mainViewStackLayout
177
178 anchors.fill: parent
179
180 currentIndex: 0
181
182 SplitView {
183 id: splitView
184
185 Layout.fillWidth: true
186 Layout.fillHeight: true
187
188 width: mainViewWindow.width
189 height: mainViewWindow.height
190
191 handle: Rectangle {
192 implicitWidth: JamiTheme.splitViewHandlePreferedWidth
193 implicitHeight: splitView.height
ababidf651a22020-07-30 13:38:57 +0200194 color:"transparent"
195 Rectangle {
196 implicitWidth: 1
197 implicitHeight: splitView.height
198 color: SplitHandle.pressed ? JamiTheme.pressColor : (SplitHandle.hovered ? JamiTheme.hoverColor : JamiTheme.tabbarBorderColor)
199 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400200 }
201
202 StackView {
203 id: sidePanelViewStack
204
Sébastien Blin1f915762020-08-03 13:27:42 -0400205 initialItem: mainViewWindowSidePanel
206
ababidf651a22020-07-30 13:38:57 +0200207 SplitView.maximumWidth: splitView.width - sidePanelViewStackPreferedWidth
Sébastien Blin1f915762020-08-03 13:27:42 -0400208 SplitView.minimumWidth: sidePanelViewStackPreferedWidth
Sébastien Blin1f915762020-08-03 13:27:42 -0400209 SplitView.fillHeight: true
210
211 clip: true
212 }
213
214 StackView {
215 id: welcomeViewStack
216
217 initialItem: welcomePage
218
ababidf651a22020-07-30 13:38:57 +0200219 SplitView.maximumWidth: hiddenView ? splitView.width : splitView.width - sidePanelViewStackPreferedWidth
220 SplitView.minimumWidth: sidePanelViewStackPreferedWidth
Sébastien Blin1f915762020-08-03 13:27:42 -0400221 SplitView.fillHeight: true
222
223 clip: true
224 }
225 }
226
227 SettingsView {
228 id: settingsView
229
230 Layout.fillWidth: true
231 Layout.fillHeight: true
232
233 onSettingsViewWindowNeedToShowMainViewWindow: {
234 mainViewWindowSidePanel.refreshAccountComboBox(
235 accountDeleted ? 0 : -1)
236 mainViewStackLayout.currentIndex = 0
237 }
238
239 onSettingsViewWindowNeedToShowNewWizardWindow: {
240 mainViewWindow.noAccountIsAvailable()
241 }
242 }
243 }
244
245 AccountListModel {
246 id: accountListModel
247 }
248
249 SidePanel {
250 id: mainViewWindowSidePanel
251
252 onSettingBtnClicked_AccountComboBox: {
253 mainViewStackLayout.currentIndex = 1
254 }
255
256 onConversationSmartListNeedToAccessMessageWebView: {
257
258 communicationPageMessageWebView.headerUserAliasLabelText = currentUserAlias
259 communicationPageMessageWebView.headerUserUserNameLabelText = currentUserDisplayName
260
261 callStackView.needToCloseInCallConversationAndPotentialWindow()
262 callStackView.responsibleAccountId = ClientWrapper.utilsAdaptor.getCurrAccId()
263 callStackView.responsibleConvUid = currentUID
264 callStackView.updateCorrspondingUI()
265
266 if (callStackViewShouldShow) {
267 if (callStateStr == "Talking" || callStateStr == "Hold") {
268 ClientWrapper.utilsAdaptor.setCurrentCall(
269 ClientWrapper.utilsAdaptor.getCurrAccId(),
270 currentUID)
271 if (isAudioOnly)
272 callStackView.showAudioCallPage()
273 else
274 callStackView.showVideoCallPage(
275 ClientWrapper.utilsAdaptor.getCallId(
276 callStackView.responsibleAccountId,
277 callStackView.responsibleConvUid))
278 } else {
279 callStackView.showOutgoingCallPage(callStateStr)
280 }
281 }
282
283
284 /*
285 * Set up chatview.
286 */
287 MessagesAdapter.setupChatView(currentUID)
Sébastien Blin8940f3c2020-07-23 17:03:11 -0400288 callStackView.setLinkedWebview(
Sébastien Blin1f915762020-08-03 13:27:42 -0400289 communicationPageMessageWebView)
290
291 if (welcomeViewStack.find(function (item, index) {
292 return item.objectName === "communicationPageMessageWebView"
293 }) || sidePanelViewStack.find(function (item, index) {
294 return item.objectName === "communicationPageMessageWebView"
295 })) {
296 if (!callStackViewShouldShow)
297 return
298 }
299
300
301 /*
302 * Push messageWebView or callStackView onto the correct stackview
303 */
304 welcomeViewStack.pop(null, StackView.Immediate)
305 sidePanelViewStack.pop(null, StackView.Immediate)
306
307 if (sidePanelViewStack.visible && welcomeViewStack.visible) {
308 if (callStackViewShouldShow) {
309 welcomeViewStack.push(callStackView)
310 } else {
311 welcomeViewStack.push(communicationPageMessageWebView)
312 }
313 } else if (sidePanelViewStack.visible
314 && !welcomeViewStack.visible) {
315 if (callStackViewShouldShow) {
316 sidePanelViewStack.push(callStackView)
317 } else {
318 sidePanelViewStack.push(communicationPageMessageWebView)
319 }
320 } else if (!sidePanelViewStack.visible
321 && !welcomeViewStack.visible) {
322 if (callStackViewShouldShow) {
323 sidePanelViewStack.push(callStackView)
324 } else {
325 sidePanelViewStack.push(communicationPageMessageWebView)
326 }
327 }
328 }
329
330 onAccountComboBoxNeedToShowWelcomePage: {
331
332
333 /*
334 * If the item argument is specified, all items down to (but not including) item will be popped.
335 */
336 welcomeViewStack.pop(welcomePage)
337 welcomePage.currentAccountIndex = index
338 qrDialog.currentAccountIndex = index
339 }
340
341 onConversationSmartListViewNeedToShowWelcomePage: {
342 welcomeViewStack.pop(welcomePage)
343 welcomePage.currentAccountIndex = 0
344 qrDialog.currentAccountIndex = 0
345 }
346
347 onAccountSignalsReconnect: {
348 MessagesAdapter.accountChangedSetUp(accountId)
349 }
350
351 onNeedToUpdateConversationForAddedContact: {
352 MessagesAdapter.updateConversationForAddedContact()
353 mainViewWindowSidePanel.clearContactSearchBar()
354 mainViewWindowSidePanel.forceReselectConversationSmartListCurrentIndex()
355 }
356
357 onNeedToAddNewAccount: {
358 mainViewWindow.needToAddNewAccount()
359 }
360 }
361
362 CallStackView {
363 id: callStackView
364
365 visible: false
366
367 objectName: "callStackViewObject"
Sébastien Blin1f915762020-08-03 13:27:42 -0400368 }
369
370 WelcomePage {
371 id: welcomePage
372 visible: false
373 }
374
375 MessageWebView {
376 id: communicationPageMessageWebView
377
378 objectName: "communicationPageMessageWebView"
379
380 signal toSendMessageContentSaved(string arg)
381 signal toMessagesCleared
382 signal toMessagesLoaded
383
384 visible: false
385
386 Connections {
387 target: MessagesAdapter
388
389 function onNeedToUpdateSmartList() {
390 mainViewWindowSidePanel.forceUpdateConversationSmartListView()
391 }
392 }
393
394 onNeedToGoBackToWelcomeView: {
395 mainViewWindowSidePanel.deselectConversationSmartList()
396 if (communicationPageMessageWebView.visible
397 && !welcomeViewStack.visible) {
398 sidePanelViewStack.pop()
399 } else if (communicationPageMessageWebView.visible
400 && welcomeViewStack.visible) {
401 welcomeViewStack.pop()
402 }
403 }
404
405 Component.onCompleted: {
ababidf651a22020-07-30 13:38:57 +0200406 sidePanelViewStack.SplitView.maximumWidth = Qt.binding(function() {
407 return (hiddenView ? splitView.width : splitView.width - sidePanelViewStackPreferedWidth)
408 })
409
410 recordBox.x = Qt.binding(function() {
411 var i = (welcomeViewStack.width > 1000 ? Math.round((welcomeViewStack.width-1000)*0.5) : 0)
412 return sidePanelViewStack.width + recordBox.x_offset + i
413 })
414
415 recordBox.y = Qt.binding(function() {
416 return sidePanelViewStack.height + recordBox.y_offset
417 })
Sébastien Blin1f915762020-08-03 13:27:42 -0400418
419
420 /*
421 * Set qml MessageWebView object pointer to c++.
422 */
423 MessagesAdapter.setQmlObject(this)
424 }
425 }
426
427 onWidthChanged: {
428
429
430 /*
431 * Hide unnecessary stackview when width is changed.
432 */
433 if (mainViewWindow.width < sidePanelViewStackPreferedWidth
434 + welcomePageGroupPreferedWidth - 5
435 && welcomeViewStack.visible) {
436 welcomeViewStack.visible = false
ababidf651a22020-07-30 13:38:57 +0200437 hiddenView = true
Sébastien Blin1f915762020-08-03 13:27:42 -0400438
439 /*
440 * The find callback function is called for each item in the stack.
441 */
442 var inWelcomeViewStack = welcomeViewStack.find(
443 function (item, index) {
444 return index > 0
445 })
ababidf651a22020-07-30 13:38:57 +0200446
Sébastien Blin1f915762020-08-03 13:27:42 -0400447 if (inWelcomeViewStack) {
448 recursionStackViewItemMove(welcomeViewStack, sidePanelViewStack)
449 }
450
Sébastien Blin1f915762020-08-03 13:27:42 -0400451 mainViewWindow.update()
452 } else if (mainViewWindow.width >= sidePanelViewStackPreferedWidth
453 + welcomePageGroupPreferedWidth + 5
454 && !welcomeViewStack.visible) {
455 welcomeViewStack.visible = true
ababidf651a22020-07-30 13:38:57 +0200456 hiddenView = false
Sébastien Blin1f915762020-08-03 13:27:42 -0400457
458 var inSidePanelViewStack = sidePanelViewStack.find(
459 function (item, index) {
460 return index > 0
461 })
462 if (inSidePanelViewStack) {
463 recursionStackViewItemMove(sidePanelViewStack, welcomeViewStack)
464 }
465
Sébastien Blin1f915762020-08-03 13:27:42 -0400466 mainViewWindow.update()
467 }
468 }
469
470 AboutPopUp {
471 id: aboutPopUpDialog
472
473 x: Math.round((mainViewWindow.width - width) / 2)
474 y: Math.round((mainViewWindow.height - height) / 2)
475 width: Math.max(mainViewWindow.width / 2, aboutPopUpPreferedWidth)
476 height: aboutPopUpDialog.contentHeight
477 }
478
479 WelcomePageQrDialog {
480 id: qrDialog
481
482 x: Math.round((mainViewWindow.width - width) / 2)
483 y: Math.round((mainViewWindow.height - height) / 2)
484 width: qrDialog.contentHeight
485 height: qrDialog.contentHeight
486 }
487
488 RecordBox{
489 id: recordBox
490 visible: false
491 }
492
493 UserProfile {
494 id: userProfile
495
496 x: Math.round((mainViewWindow.width - width) / 2)
497 y: Math.round((mainViewWindow.height - height) / 2)
498 width: Math.max(mainViewWindow.width / 2, aboutPopUpPreferedWidth)
499 height: userProfile.contentHeight
500 }
501
502 Component.onCompleted: {
503 CallAdapter.initQmlObject()
504 }
505
506 onClosing: {
507 close.accepted = false
508 mainViewWindow.hide()
509 mainViewWindow.closeApp()
510 }
511}