mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
350 lines
14 KiB
QML
350 lines
14 KiB
QML
import QtCore
|
|
import QtQuick
|
|
import QtQuick.Controls.Basic as Control
|
|
import QtQuick.Dialogs
|
|
import QtQuick.Effects
|
|
import QtQuick.Layouts
|
|
import Linphone
|
|
import UtilsCpp
|
|
import SettingsCpp
|
|
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
|
|
|
|
RowLayout {
|
|
id: mainItem
|
|
property ChatGui chat
|
|
property var contactObj: chat ? UtilsCpp.findFriendByAddress(mainItem.chat.core.peerAddress) : null
|
|
property var contact: contactObj?.value || null
|
|
property CallGui call
|
|
property alias callHeaderContent: splitPanel.headerContent
|
|
spacing: 0
|
|
|
|
signal oneOneCall(bool video)
|
|
signal groupCall()
|
|
|
|
onOneOneCall: {
|
|
if (contact)
|
|
mainWindow.startCallWithContact(contact, video, mainItem)
|
|
else
|
|
UtilsCpp.createCall(mainItem.chat?.core.peerAddress, {'localVideoEnabled':video})
|
|
}
|
|
|
|
onGroupCall: {
|
|
mainWindow.showConfirmationLambdaPopup("",
|
|
qsTr("chat_view_group_call_toast_message"),
|
|
"",
|
|
function(confirmed) {
|
|
if (confirmed) {
|
|
const sourceList = mainItem.chat?.core.participants
|
|
let addresses = [];
|
|
for (let i = 0; i < sourceList.length; ++i) {
|
|
const participantGui = sourceList[i]
|
|
const participantCore = participantGui.core
|
|
addresses.push(participantCore.sipAddress)
|
|
}
|
|
UtilsCpp.createGroupCall(mainItem.chat?.core.title, addresses)
|
|
}
|
|
})
|
|
}
|
|
|
|
//onEventChanged: {
|
|
// TODO : call when all messages read after scroll to unread feature available
|
|
// if (chat) chat.core.lMarkAsRead()
|
|
//}
|
|
MainRightPanel {
|
|
id: splitPanel
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
panelColor: DefaultStyle.grey_0
|
|
header.visible: !mainItem.call
|
|
clip: true
|
|
headerContent: [
|
|
RowLayout {
|
|
anchors.left: parent?.left
|
|
anchors.leftMargin: mainItem.call ? 0 : Math.round(31 * DefaultStyle.dp)
|
|
anchors.verticalCenter: parent?.verticalCenter
|
|
spacing: Math.round(12 * DefaultStyle.dp)
|
|
Avatar {
|
|
property var contactObj: mainItem.chat ? UtilsCpp.findFriendByAddress(mainItem.chat?.core.peerAddress) : null
|
|
contact: contactObj?.value || null
|
|
displayNameVal: contact ? "" : mainItem.chat.core.avatarUri
|
|
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
|
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
|
}
|
|
Text {
|
|
text: mainItem.chat?.core.title || ""
|
|
color: DefaultStyle.main2_600
|
|
Layout.fillWidth: true
|
|
maximumLineCount: 1
|
|
font {
|
|
pixelSize: Typography.h4.pixelSize
|
|
weight: Math.round(400 * DefaultStyle.dp)
|
|
capitalization: Font.Capitalize
|
|
}
|
|
}
|
|
EffectImage {
|
|
visible: mainItem.chat?.core.muted
|
|
Layout.preferredWidth: 20 * DefaultStyle.dp
|
|
Layout.alignment: Qt.AlignVCenter
|
|
Layout.preferredHeight: 20 * DefaultStyle.dp
|
|
colorizationColor: DefaultStyle.main1_500_main
|
|
imageSource: AppIcons.bellSlash
|
|
}
|
|
},
|
|
RowLayout {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: Math.round(41 * DefaultStyle.dp)
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
BigButton {
|
|
style: ButtonStyle.noBackground
|
|
icon.source: AppIcons.phone
|
|
onPressed: {
|
|
if (mainItem.chat.core.isGroupChat) {
|
|
mainItem.groupCall()
|
|
} else {
|
|
mainItem.oneOneCall(false)
|
|
}
|
|
}
|
|
}
|
|
BigButton {
|
|
style: ButtonStyle.noBackground
|
|
icon.source: AppIcons.videoCamera
|
|
visible: !mainItem.chat.core.isGroupChat
|
|
onPressed: mainItem.oneOneCall(true)
|
|
}
|
|
BigButton {
|
|
style: ButtonStyle.noBackground
|
|
checkable: true
|
|
checkedImageColor: DefaultStyle.main1_500_main
|
|
icon.source: AppIcons.info
|
|
onCheckedChanged: {
|
|
detailsPanel.visible = !detailsPanel.visible
|
|
}
|
|
}
|
|
}
|
|
]
|
|
|
|
content: Control.SplitView {
|
|
anchors.fill: parent
|
|
orientation: Qt.Vertical
|
|
handle: Rectangle {
|
|
implicitHeight: Math.round(8 * DefaultStyle.dp)
|
|
color: Control.SplitHandle.hovered ? DefaultStyle.grey_200 : DefaultStyle.grey_100
|
|
}
|
|
ColumnLayout {
|
|
spacing: 0
|
|
Control.SplitView.fillHeight: true
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
ChatMessagesListView {
|
|
id: chatMessagesListView
|
|
clip: true
|
|
height: contentHeight
|
|
backgroundColor: splitPanel.panelColor
|
|
width: parent.width - anchors.leftMargin - anchors.rightMargin
|
|
chat: mainItem.chat
|
|
anchors.fill: parent
|
|
anchors.leftMargin: Math.round(18 * DefaultStyle.dp)
|
|
anchors.rightMargin: Math.round(18 * DefaultStyle.dp)
|
|
Control.ScrollBar.vertical: scrollbar
|
|
|
|
Popup {
|
|
id: emojiPickerPopup
|
|
y: Math.round(chatMessagesListView.y + chatMessagesListView.height - height - 8*DefaultStyle.dp)
|
|
x: Math.round(chatMessagesListView.x + 8*DefaultStyle.dp)
|
|
width: Math.round(393 * DefaultStyle.dp)
|
|
height: Math.round(291 * DefaultStyle.dp)
|
|
visible: messageSender.emojiPickerButtonChecked
|
|
closePolicy: Popup.CloseOnPressOutside
|
|
onClosed: messageSender.emojiPickerButtonChecked = false
|
|
padding: 10 * DefaultStyle.dp
|
|
background: Item {
|
|
anchors.fill: parent
|
|
Rectangle {
|
|
id: buttonBackground
|
|
anchors.fill: parent
|
|
color: DefaultStyle.grey_0
|
|
radius: Math.round(20 * DefaultStyle.dp)
|
|
}
|
|
MultiEffect {
|
|
anchors.fill: buttonBackground
|
|
source: buttonBackground
|
|
shadowEnabled: true
|
|
shadowColor: DefaultStyle.grey_1000
|
|
shadowBlur: 0.1
|
|
shadowOpacity: 0.5
|
|
}
|
|
}
|
|
contentItem: EmojiPicker {
|
|
id: emojiPicker
|
|
editor: messageSender.textArea
|
|
}
|
|
}
|
|
}
|
|
ScrollBar {
|
|
id: scrollbar
|
|
visible: chatMessagesListView.contentHeight > parent.height
|
|
active: visible
|
|
anchors.top: chatMessagesListView.top
|
|
anchors.bottom: chatMessagesListView.bottom
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: Math.round(5 * DefaultStyle.dp)
|
|
policy: Control.ScrollBar.AsNeeded
|
|
}
|
|
}
|
|
Control.Control {
|
|
id: selectedFilesArea
|
|
visible: selectedFiles.count > 0
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Math.round(104 * DefaultStyle.dp)
|
|
topPadding: Math.round(12 * DefaultStyle.dp)
|
|
bottomPadding: Math.round(12 * DefaultStyle.dp)
|
|
leftPadding: Math.round(19 * DefaultStyle.dp)
|
|
rightPadding: Math.round(19 * DefaultStyle.dp)
|
|
|
|
Button {
|
|
anchors.top: parent.top
|
|
anchors.right: parent.right
|
|
anchors.topMargin: selectedFilesArea.topPadding
|
|
anchors.rightMargin: selectedFilesArea.rightPadding
|
|
icon.source: AppIcons.closeX
|
|
style: ButtonStyle.noBackground
|
|
onClicked: {
|
|
contents.clear()
|
|
}
|
|
}
|
|
background: Item{
|
|
anchors.fill: parent
|
|
Rectangle {
|
|
color: DefaultStyle.grey_0
|
|
border.color: DefaultStyle.main2_100
|
|
border.width: Math.round(2 * DefaultStyle.dp)
|
|
radius: Math.round(20 * DefaultStyle.dp)
|
|
height: parent.height / 2
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
}
|
|
Rectangle {
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
height: 2 * parent.height / 3
|
|
}
|
|
}
|
|
contentItem: ListView {
|
|
id: selectedFiles
|
|
orientation: ListView.Horizontal
|
|
spacing: Math.round(16 * DefaultStyle.dp)
|
|
model: ChatMessageContentProxy {
|
|
id: contents
|
|
filterType: ChatMessageContentProxy.FilterContentType.File
|
|
}
|
|
delegate: Item {
|
|
width: Math.round(80 * DefaultStyle.dp)
|
|
height: Math.round(80 * DefaultStyle.dp)
|
|
FileView {
|
|
contentGui: modelData
|
|
anchors.left: parent.left
|
|
anchors.bottom: parent.bottom
|
|
width: Math.round(69 * DefaultStyle.dp)
|
|
height: Math.round(69 * DefaultStyle.dp)
|
|
}
|
|
RoundButton {
|
|
icon.source: AppIcons.closeX
|
|
icon.width: Math.round(12 * DefaultStyle.dp)
|
|
icon.height: Math.round(12 * DefaultStyle.dp)
|
|
anchors.top: parent.top
|
|
anchors.right: parent.right
|
|
style: ButtonStyle.numericPad
|
|
shadowEnabled: true
|
|
padding: Math.round(3 * DefaultStyle.dp)
|
|
onClicked: contents.removeContent(modelData)
|
|
}
|
|
}
|
|
Control.ScrollBar.horizontal: selectedFilesScrollbar
|
|
}
|
|
ScrollBar {
|
|
id: selectedFilesScrollbar
|
|
active: true
|
|
anchors.bottom: selectedFilesArea.bottom
|
|
anchors.left: selectedFilesArea.left
|
|
anchors.right: selectedFilesArea.right
|
|
}
|
|
}
|
|
}
|
|
ChatDroppableTextArea {
|
|
id: messageSender
|
|
Control.SplitView.preferredHeight: mainItem.chat.core.isReadOnly ? 0 : Math.round(79 * DefaultStyle.dp)
|
|
Control.SplitView.minimumHeight: mainItem.chat.core.isReadOnly ? 0 : Math.round(79 * DefaultStyle.dp)
|
|
chat: mainItem.chat
|
|
Component.onCompleted: {
|
|
|
|
if (mainItem.chat) text = mainItem.chat.core.sendingText
|
|
}
|
|
onTextChanged: {
|
|
if (text !== "" && mainItem.chat.core.composingName !== "") {
|
|
mainItem.chat.core.lCompose()
|
|
}
|
|
mainItem.chat.core.sendingText = text
|
|
}
|
|
onSendMessage: {
|
|
var filesContents = contents.getAll()
|
|
if (filesContents.length === 0)
|
|
mainItem.chat.core.lSendTextMessage(text)
|
|
else mainItem.chat.core.lSendMessage(text, filesContents)
|
|
contents.clear()
|
|
}
|
|
onDropped: (files) => {
|
|
contents.addFiles(files)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
Rectangle {
|
|
visible: detailsPanel.visible
|
|
color: DefaultStyle.main2_200
|
|
Layout.preferredWidth: Math.round(1 * DefaultStyle.dp)
|
|
Layout.fillHeight: true
|
|
}
|
|
Control.Control {
|
|
id: detailsPanel
|
|
visible: false
|
|
Layout.fillHeight: true
|
|
Layout.preferredWidth: Math.round(387 * DefaultStyle.dp)
|
|
|
|
background: Rectangle {
|
|
color: DefaultStyle.grey_0
|
|
anchors.fill: parent
|
|
}
|
|
|
|
contentItem: Loader {
|
|
id: contentLoader
|
|
anchors.top: parent.top
|
|
anchors.topMargin: Math.round(39 * DefaultStyle.dp)
|
|
sourceComponent: mainItem.chat.core.isGroupChat ? groupInfoComponent : oneToOneInfoComponent
|
|
active: detailsPanel.visible
|
|
onLoaded: {
|
|
if (contentLoader.item) {
|
|
contentLoader.item.parentView = mainItem
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: oneToOneInfoComponent
|
|
OneOneConversationInfos {
|
|
chatGui: mainItem.chat
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: groupInfoComponent
|
|
GroupConversationInfos {
|
|
chatGui: mainItem.chat
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|