mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-08-01 21:35:42 +02:00

Minor cosmetic changes to the account combo box, search bar, filter tabs, and smartlist. Change-Id: Ie8173504859b325374e42f0dbb4e0ae75f3ed740 Gitlab: #373 Gitlab: #374 Gitlab: #388
627 lines
20 KiB
QML
627 lines
20 KiB
QML
/*
|
|
* 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/>.
|
|
*/
|
|
|
|
import QtQuick 2.14
|
|
import QtQuick.Window 2.14
|
|
import QtQuick.Controls 2.14
|
|
import QtQuick.Layouts 1.14
|
|
import QtQuick.Controls.Universal 2.14
|
|
import QtGraphicalEffects 1.14
|
|
|
|
import net.jami.Models 1.0
|
|
import net.jami.Adapters 1.0
|
|
import net.jami.Constants 1.0
|
|
|
|
// Import qml component files.
|
|
import "components"
|
|
import "../"
|
|
import "../wizardview"
|
|
import "../settingsview"
|
|
import "../settingsview/components"
|
|
|
|
Rectangle {
|
|
id: mainView
|
|
|
|
objectName: "mainView"
|
|
|
|
property int sidePanelViewStackMinimumWidth: 300
|
|
property int mainViewStackPreferredWidth: 425
|
|
property int settingsViewPreferredWidth: 460
|
|
property int onWidthChangedTriggerDistance: 5
|
|
|
|
property bool sidePanelOnly: (!mainViewStack.visible) && sidePanelViewStack.visible
|
|
property int previousWidth: width
|
|
|
|
// To calculate tab bar bottom border hidden rect left margin.
|
|
property int tabBarLeftMargin: 8
|
|
property int tabButtonShrinkSize: 8
|
|
property bool inSettingsView: false
|
|
|
|
// For updating msgWebView
|
|
property string currentConvUID: ""
|
|
|
|
signal loaderSourceChangeRequested(int sourceToLoad)
|
|
|
|
property string currentAccountId: AccountAdapter.currentAccountId
|
|
onCurrentAccountIdChanged: {
|
|
if (inSettingsView) {
|
|
settingsView.accountListChanged()
|
|
settingsView.setSelected(settingsView.selectedMenu, true)
|
|
} else {
|
|
backToMainView(true)
|
|
}
|
|
}
|
|
|
|
function isPageInStack(objectName, stackView) {
|
|
var foundItem = stackView.find(function (item, index) {
|
|
return item.objectName === objectName
|
|
})
|
|
|
|
return foundItem ? true : false
|
|
}
|
|
|
|
function showWelcomeView() {
|
|
currentConvUID = ""
|
|
callStackView.needToCloseInCallConversationAndPotentialWindow()
|
|
LRCInstance.deselectConversation()
|
|
if (isPageInStack("callStackViewObject", sidePanelViewStack) ||
|
|
isPageInStack("communicationPageMessageWebView", sidePanelViewStack) ||
|
|
isPageInStack("communicationPageMessageWebView", mainViewStack) ||
|
|
isPageInStack("callStackViewObject", mainViewStack)) {
|
|
sidePanelViewStack.pop(StackView.Immediate)
|
|
mainViewStack.pop(welcomePage, StackView.Immediate)
|
|
}
|
|
recordBox.visible = false
|
|
}
|
|
|
|
function pushCallStackView() {
|
|
if (sidePanelOnly) {
|
|
sidePanelViewStack.pop(StackView.Immediate)
|
|
sidePanelViewStack.push(callStackView, StackView.Immediate)
|
|
} else {
|
|
sidePanelViewStack.pop(StackView.Immediate)
|
|
mainViewStack.pop(welcomePage, StackView.Immediate)
|
|
mainViewStack.push(callStackView, StackView.Immediate)
|
|
}
|
|
}
|
|
|
|
function pushCommunicationMessageWebView() {
|
|
if (sidePanelOnly) {
|
|
sidePanelViewStack.pop(StackView.Immediate)
|
|
sidePanelViewStack.push(communicationPageMessageWebView, StackView.Immediate)
|
|
} else {
|
|
mainViewStack.pop(welcomePage, StackView.Immediate)
|
|
mainViewStack.push(communicationPageMessageWebView, StackView.Immediate)
|
|
}
|
|
}
|
|
|
|
function startWizard() {
|
|
mainViewStackLayout.currentIndex = 1
|
|
}
|
|
|
|
function currentAccountIsCalling() {
|
|
return UtilsAdapter.hasCall(AccountAdapter.currentAccountId)
|
|
}
|
|
|
|
// Only called onWidthChanged
|
|
function recursionStackViewItemMove(stackOne, stackTwo, depth=1) {
|
|
// Move all items (expect the bottom item) to stacktwo by the same order in stackone.
|
|
if (stackOne.depth === depth) {
|
|
return
|
|
}
|
|
|
|
var tempItem = stackOne.pop(StackView.Immediate)
|
|
recursionStackViewItemMove(stackOne, stackTwo, depth)
|
|
stackTwo.push(tempItem, StackView.Immediate)
|
|
}
|
|
|
|
// Back to WelcomeView required, but can also check, i. e., on account switch or
|
|
// settings exit, if there is need to switch to a current call
|
|
function backToMainView(checkCurrentCall = false) {
|
|
if (inSettingsView)
|
|
return
|
|
if (checkCurrentCall && currentAccountIsCalling()) {
|
|
var callConv = UtilsAdapter.getCallConvForAccount(
|
|
AccountAdapter.currentAccountId)
|
|
LRCInstance.selectConversation(callConv)
|
|
CallAdapter.updateCall(callConv, currentAccountId)
|
|
} else {
|
|
showWelcomeView()
|
|
}
|
|
}
|
|
|
|
function toggleSettingsView() {
|
|
inSettingsView = !inSettingsView
|
|
|
|
if (inSettingsView) {
|
|
if (sidePanelOnly)
|
|
sidePanelViewStack.push(settingsMenu, StackView.Immediate)
|
|
else {
|
|
mainViewStack.pop(welcomePage, StackView.Immediate)
|
|
mainViewStack.push(settingsView, StackView.Immediate)
|
|
sidePanelViewStack.push(settingsMenu, StackView.Immediate)
|
|
|
|
var windowCurrentMinimizedSize = settingsViewPreferredWidth
|
|
+ sidePanelViewStackMinimumWidth + onWidthChangedTriggerDistance
|
|
if (appWindow.width < windowCurrentMinimizedSize)
|
|
appWindow.width = windowCurrentMinimizedSize
|
|
}
|
|
} else {
|
|
sidePanelViewStack.pop(StackView.Immediate)
|
|
mainViewStack.pop(StackView.Immediate)
|
|
backToMainView(true)
|
|
}
|
|
}
|
|
|
|
function setMainView(convId) {
|
|
if (!(communicationPageMessageWebView.jsLoaded)) {
|
|
communicationPageMessageWebView.jsLoadedChanged.connect(
|
|
function(convId) {
|
|
return function() { setMainView(convId) }
|
|
}(convId))
|
|
return
|
|
}
|
|
var item = ConversationsAdapter.getConvInfoMap(convId)
|
|
if (item.convId === undefined)
|
|
return
|
|
communicationPageMessageWebView.headerUserAliasLabelText = item.bestName
|
|
communicationPageMessageWebView.headerUserUserNameLabelText = item.bestId
|
|
if (item.callStackViewShouldShow) {
|
|
if (inSettingsView) {
|
|
toggleSettingsView()
|
|
}
|
|
MessagesAdapter.setupChatView(convId)
|
|
callStackView.setLinkedWebview(communicationPageMessageWebView)
|
|
callStackView.responsibleAccountId = AccountAdapter.currentAccountId
|
|
callStackView.responsibleConvUid = convId
|
|
currentConvUID = convId
|
|
|
|
if (item.callState === Call.Status.IN_PROGRESS ||
|
|
item.callState === Call.Status.PAUSED) {
|
|
CallAdapter.updateCall(convId, AccountAdapter.currentAccountId)
|
|
if (item.isAudioOnly)
|
|
callStackView.showAudioCallPage()
|
|
else
|
|
callStackView.showVideoCallPage()
|
|
} else if (item.callState === Call.Status.INCOMING_RINGING) {
|
|
callStackView.showIncomingCallPage()
|
|
} else {
|
|
callStackView.showOutgoingCallPage(item.callState)
|
|
}
|
|
pushCallStackView()
|
|
|
|
} else if (!inSettingsView) {
|
|
if (currentConvUID !== convId) {
|
|
callStackView.needToCloseInCallConversationAndPotentialWindow()
|
|
MessagesAdapter.setupChatView(convId)
|
|
pushCommunicationMessageWebView()
|
|
communicationPageMessageWebView.focusMessageWebView()
|
|
currentConvUID = convId
|
|
} else if (isPageInStack("callStackViewObject", sidePanelViewStack)
|
|
|| isPageInStack("callStackViewObject", mainViewStack)) {
|
|
callStackView.needToCloseInCallConversationAndPotentialWindow()
|
|
pushCommunicationMessageWebView()
|
|
communicationPageMessageWebView.focusMessageWebView()
|
|
}
|
|
}
|
|
}
|
|
|
|
color: JamiTheme.backgroundColor
|
|
|
|
Connections {
|
|
target: LRCInstance
|
|
|
|
function onSelectedConvUidChanged() {
|
|
mainView.setMainView(LRCInstance.selectedConvUid)
|
|
}
|
|
|
|
function onConversationUpdated(convUid, accountId) {
|
|
if (convUid === LRCInstance.selectedConvUid &&
|
|
accountId === currentAccountId)
|
|
mainView.setMainView(convUid)
|
|
}
|
|
}
|
|
|
|
StackLayout {
|
|
id: mainViewStackLayout
|
|
|
|
anchors.fill: parent
|
|
|
|
currentIndex: 0
|
|
|
|
SplitView {
|
|
id: splitView
|
|
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
width: mainView.width
|
|
height: mainView.height
|
|
|
|
handle: Rectangle {
|
|
implicitWidth: JamiTheme.splitViewHandlePreferredWidth
|
|
implicitHeight: splitView.height
|
|
color: JamiTheme.primaryBackgroundColor
|
|
Rectangle {
|
|
implicitWidth: 1
|
|
implicitHeight: splitView.height
|
|
color: JamiTheme.tabbarBorderColor
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: mainViewSidePanelRect
|
|
|
|
SplitView.minimumWidth: sidePanelViewStackMinimumWidth
|
|
SplitView.maximumWidth: (sidePanelOnly ?
|
|
splitView.width :
|
|
splitView.width - sidePanelViewStackMinimumWidth)
|
|
SplitView.fillHeight: true
|
|
color: JamiTheme.backgroundColor
|
|
|
|
// AccountComboBox is not a ComboBox
|
|
AccountComboBox {
|
|
id: accountComboBox
|
|
|
|
anchors.top: mainViewSidePanelRect.top
|
|
width: mainViewSidePanelRect.width
|
|
height: JamiTheme.accountListItemHeight
|
|
|
|
visible: (mainViewSidePanel.visible || settingsMenu.visible)
|
|
|
|
Connections {
|
|
target: AccountAdapter
|
|
|
|
function onAccountStatusChanged(accountId) {
|
|
accountComboBox.resetAccountListModel(accountId)
|
|
}
|
|
}
|
|
|
|
onSettingBtnClicked: {
|
|
toggleSettingsView()
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
AccountAdapter.setQmlObject(this)
|
|
}
|
|
}
|
|
|
|
StackView {
|
|
id: sidePanelViewStack
|
|
|
|
initialItem: mainViewSidePanel
|
|
|
|
anchors.top: accountComboBox.visible ? accountComboBox.bottom :
|
|
mainViewSidePanelRect.top
|
|
width: mainViewSidePanelRect.width
|
|
height: accountComboBox.visible ? mainViewSidePanelRect.height - accountComboBox.height :
|
|
mainViewSidePanelRect.height
|
|
|
|
clip: true
|
|
}
|
|
}
|
|
|
|
StackView {
|
|
id: mainViewStack
|
|
|
|
initialItem: welcomePage
|
|
|
|
SplitView.maximumWidth: sidePanelOnly ?
|
|
splitView.width :
|
|
splitView.width - sidePanelViewStackMinimumWidth
|
|
SplitView.preferredWidth: mainViewStackPreferredWidth
|
|
SplitView.minimumWidth: sidePanelViewStackMinimumWidth
|
|
SplitView.fillHeight: true
|
|
|
|
clip: true
|
|
}
|
|
}
|
|
|
|
WizardView {
|
|
id: wizardView
|
|
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
onLoaderSourceChangeRequested: {
|
|
mainViewStackLayout.currentIndex = 0
|
|
backToMainView()
|
|
}
|
|
|
|
onWizardViewIsClosed: {
|
|
mainViewStackLayout.currentIndex = 0
|
|
backToMainView()
|
|
}
|
|
}
|
|
}
|
|
|
|
AccountListModel {
|
|
id: accountListModel
|
|
|
|
lrcInstance: LRCInstance
|
|
}
|
|
|
|
SettingsMenu {
|
|
id: settingsMenu
|
|
|
|
objectName: "settingsMenu"
|
|
|
|
visible: false
|
|
|
|
width: mainViewSidePanelRect.width
|
|
height: mainViewSidePanelRect.height
|
|
|
|
onItemSelected: {
|
|
settingsView.setSelected(index)
|
|
if (sidePanelOnly)
|
|
sidePanelViewStack.push(settingsView, StackView.Immediate)
|
|
}
|
|
}
|
|
|
|
SidePanel {
|
|
id: mainViewSidePanel
|
|
|
|
Connections {
|
|
target: ConversationsAdapter
|
|
|
|
function onNavigateToWelcomePageRequested() {
|
|
backToMainView()
|
|
}
|
|
}
|
|
}
|
|
|
|
CallStackView {
|
|
id: callStackView
|
|
|
|
visible: false
|
|
objectName: "callStackViewObject"
|
|
}
|
|
|
|
WelcomePage {
|
|
id: welcomePage
|
|
|
|
visible: false
|
|
}
|
|
|
|
SettingsView {
|
|
id: settingsView
|
|
|
|
visible: false
|
|
|
|
onSettingsViewNeedToShowMainView: {
|
|
AccountAdapter.changeAccount(0)
|
|
toggleSettingsView()
|
|
}
|
|
|
|
onSettingsViewNeedToShowNewWizardWindow: loaderSourceChangeRequested(
|
|
MainApplicationWindow.LoadedSource.WizardView)
|
|
|
|
onSettingsBackArrowClicked: sidePanelViewStack.pop(StackView.Immediate)
|
|
}
|
|
|
|
MessageWebView {
|
|
id: communicationPageMessageWebView
|
|
|
|
objectName: "communicationPageMessageWebView"
|
|
|
|
signal toSendMessageContentSaved(string arg)
|
|
signal toMessagesCleared
|
|
signal toMessagesLoaded
|
|
|
|
visible: false
|
|
|
|
Connections {
|
|
target: MessagesAdapter
|
|
|
|
function onNavigateToWelcomePageRequested() {
|
|
backToMainView()
|
|
}
|
|
|
|
function onInvitationAccepted() {
|
|
mainViewSidePanel.selectTab(SidePanelTabBar.Conversations)
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
recordBox.x = Qt.binding(function() {
|
|
var i = ((mainViewStack.visible && mainViewStack.width > 1000) ?
|
|
Math.round((mainViewStack.width-1000)*0.5) :
|
|
0)
|
|
return mainViewStack.visible ?
|
|
sidePanelViewStack.width + recordBox.x_offset + i :
|
|
recordBox.x_offset + i
|
|
|
|
})
|
|
|
|
recordBox.y = Qt.binding(function() {
|
|
return mainViewStack.visible ? mainViewStack.height + recordBox.y_offset :
|
|
sidePanelViewStack.height + recordBox.y_offset
|
|
})
|
|
|
|
// Set qml MessageWebView object pointer to c++.
|
|
MessagesAdapter.setQmlObject(this)
|
|
}
|
|
}
|
|
|
|
onWidthChanged: {
|
|
// Hide unnecessary stackview when width is changed.
|
|
var widthToCompare = previousWidth < mainView.width ?
|
|
sidePanelViewStackMinimumWidth :
|
|
(sidePanelViewStackMinimumWidth +
|
|
(inSettingsView ? settingsViewPreferredWidth : mainViewStackPreferredWidth))
|
|
|
|
if (mainView.width < widthToCompare - onWidthChangedTriggerDistance
|
|
&& mainViewStack.visible) {
|
|
mainViewStack.visible = false
|
|
|
|
// The find callback function is called for each item in the stack.
|
|
var inWelcomeViewStack = mainViewStack.find(
|
|
function (item, index) {
|
|
return index > 0
|
|
})
|
|
|
|
if (inSettingsView) {
|
|
mainViewStack.pop(StackView.Immediate)
|
|
sidePanelViewStack.push(settingsView, StackView.Immediate)
|
|
}
|
|
else if (inWelcomeViewStack)
|
|
recursionStackViewItemMove(mainViewStack, sidePanelViewStack)
|
|
} else if (mainView.width >= widthToCompare + onWidthChangedTriggerDistance
|
|
&& !mainViewStack.visible) {
|
|
mainViewStack.visible = true
|
|
|
|
var inSidePanelViewStack = sidePanelViewStack.find(
|
|
function (item, index) {
|
|
return index > 0
|
|
})
|
|
|
|
if (inSettingsView) {
|
|
if (sidePanelViewStack.currentItem.objectName !== settingsMenu.objectName)
|
|
sidePanelViewStack.pop(StackView.Immediate)
|
|
mainViewStack.push(settingsView, StackView.Immediate)
|
|
} else if (inSidePanelViewStack) {
|
|
recursionStackViewItemMove(sidePanelViewStack, mainViewStack)
|
|
if (currentAccountIsCalling())
|
|
pushCallStackView()
|
|
}
|
|
}
|
|
|
|
previousWidth = mainView.width
|
|
}
|
|
|
|
AboutPopUp {
|
|
id: aboutPopUpDialog
|
|
|
|
height: Math.min(preferredHeight,
|
|
mainView.height - JamiTheme.preferredMarginSize * 2)
|
|
}
|
|
|
|
WelcomePageQrDialog {
|
|
id: qrDialog
|
|
}
|
|
|
|
RecordBox{
|
|
id: recordBox
|
|
visible: false
|
|
}
|
|
|
|
UserProfile {
|
|
id: userProfile
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Ctrl+M"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: {
|
|
if (!inSettingsView) {
|
|
toggleSettingsView()
|
|
}
|
|
settingsMenu.btnMediaSettings.clicked()
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Ctrl+G"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: {
|
|
if (!inSettingsView) {
|
|
toggleSettingsView()
|
|
}
|
|
settingsMenu.btnGeneralSettings.clicked()
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Ctrl+I"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: {
|
|
if (!inSettingsView) {
|
|
toggleSettingsView()
|
|
}
|
|
settingsMenu.btnAccountSettings.clicked()
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Ctrl+P"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: {
|
|
if (!inSettingsView) {
|
|
toggleSettingsView()
|
|
}
|
|
settingsMenu.btnPluginSettings.clicked()
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "F10"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: {
|
|
shortcutsTable.open()
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "F11"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: {
|
|
// Don't toggle fullscreen mode when we're already
|
|
// in a fullscreen call.
|
|
if (JamiQmlUtils.callIsFullscreen)
|
|
return
|
|
appWindow.toggleFullScreen()
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Ctrl+D"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: CallAdapter.hangUpThisCall()
|
|
onActivatedAmbiguously: CallAdapter.hangUpThisCall()
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Ctrl+Shift+A"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: {
|
|
UtilsAdapter.makePermanentCurrentConv()
|
|
communicationPageMessageWebView.setSendContactRequestButtonVisible(false)
|
|
}
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Ctrl+Shift+N"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: startWizard()
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Escape"
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: {
|
|
if (JamiQmlUtils.callIsFullscreen)
|
|
callStackView.toggleFullScreen()
|
|
else if (appWindow.isFullScreen)
|
|
appWindow.toggleFullScreen()
|
|
}
|
|
}
|
|
|
|
KeyBoardShortcutTable {
|
|
id: shortcutsTable
|
|
}
|
|
}
|