linphone-desktop/linphone-app/ui/modules/Linphone/Chat/ChatContent.qml
Julien Wadel 4532e278ac New chat layout :
- Split content type to be filtered by proxy lists.
- Add a message in notification when receiving a conference invitation.
- Change chat bubbles colors to match mobile application.
- Change date display on messages to remove sections. It allows to be more coherent when sorting messages.
- Change Chat Layout : outgoing messages to right, incoming messages to left.
- Change bubble design to be squared when grouped.
- Group messages on 1 second away from previous (and same sender).
- Add a background color with radius to files in reply messages.
- Make color corners on reply.
- Fix filename to 2 lines in file download icon.
- Add a background color on conference invitations.
- Change conference title from bold to normal on invitations.
- Rework chat message content layout to be used with grids and lists : files are now displayed in grid.
- Remove cyclic dependencies with reply design (which was recursivly linked with ChatContent).
- Fix center layouts that were not bind to the correct one.
- Align pictures to center.
- Fix hidden admin usernames in participant view.
2023-03-03 17:09:25 +01:00

214 lines
6.5 KiB
QML

import QtQuick 2.7
import QtQuick.Layouts 1.3
import Clipboard 1.0
import Common 1.0
import Linphone 1.0
import Common.Styles 1.0
import Linphone.Styles 1.0
import TextToSpeech 1.0
import Utils 1.0
import Units 1.0
import UtilsCpp 1.0
import LinphoneEnums 1.0
import ColorsList 1.0
// =============================================================================
// Simple content display without reply and forward. These modules need to be splitted because of cyclic dependencies.
// See ChatFullContent
Loader{// Use of Loader because of Repeater (items cannot be loaded dynamically)
id: mainItem
property ChatMessageModel chatMessageModel: null
property int availableWidth //const
property int fileWidth: ChatStyle.entry.message.file.height * 4 / 3 + 2*ChatStyle.entry.message.file.margins
// Readonly
property int bestWidth: Math.min(availableWidth, Math.max(filesBestWidth, conferencesBestWidth, textsBestWidth, voicesBestWidth))
property int filesBestWidth: 0
property int filesCount: 0
property int conferencesCount: 0
property int conferencesBestWidth: 0
property int textsBestWidth: 0
property int textsCount: 0
property int voicesBestWidth: 0
property int voicesCount: 0
signal isFileHoveringChanged(bool isFileHovering)
signal lastTextSelectedChanged(string lastTextSelected)
signal rightClicked()
signal conferenceIcsCopied()
property bool useTextColor: false
property color textColor
property int fileBorderWidth : 0
property color fileBackgroundColor: ChatStyle.entry.message.file.extension.background.colorModel.color
property int fileBackgroundRadius: ChatStyle.entry.message.file.extension.radius
active: chatMessageModel
sourceComponent: Component{
Column{
id: mainComponent
spacing: 0
function updateFilesBestWidth(){
var newBestWidth = 0
var count = 0
for(var child in messageFilesList.children) {
var item = messageFilesList.children[child]
if(item){
var a = item.fitWidth
if(a) {
++count
newBestWidth = Math.max(newBestWidth,a)
}
}
}
if(count > 1){
newBestWidth = Math.max(newBestWidth, mainItem.fileWidth*count)
}
mainItem.filesCount = count
mainItem.filesBestWidth = newBestWidth
}
function updateListBestWidth(listView){
var newBestWidth = 0
var count = 0
for(var child in listView.contentItem.children) {
var a = listView.contentItem.children[child].fitWidth
if(a) {
++count
newBestWidth = Math.max(newBestWidth,a)
}
}
return [count, newBestWidth];
}
ListView {
id: messagesVoicesList
width: parent.width
visible: count > 0
spacing: 0
clip: false
model: ContentProxyModel{
filter: ContentProxyModel.ContentType.Voice
chatMessageModel: mainItem.chatMessageModel
}
height: contentHeight
boundsBehavior: Flickable.StopAtBounds
interactive: false
function updateBestWidth(){
var newWidth = mainComponent.updateListBestWidth(messagesVoicesList)
mainItem.voicesCount = newWidth[0]
mainItem.voicesBestWidth = newWidth[1]
}
delegate: ChatAudioMessage{
id: audioMessage
contentModel: $modelData
visible: contentModel
z: 1
Component.onCompleted: messagesVoicesList.updateBestWidth()
}
Component.onCompleted: messagesVoicesList.updateBestWidth
}
// CONFERENCE
ListView {
id: messagesConferencesList
width: parent.width
visible: count > 0
spacing: 0
clip: false
model: ContentProxyModel{
filter: ContentProxyModel.ContentType.Conference
chatMessageModel: mainItem.chatMessageModel
}
height: contentHeight
boundsBehavior: Flickable.StopAtBounds
interactive: false
function updateBestWidth(){
var newWidth = mainComponent.updateListBestWidth(messagesConferencesList)
mainItem.conferencesCount = newWidth[0]
mainItem.conferencesBestWidth = newWidth[1]
}
Component.onCompleted: messagesConferencesList.updateBestWidth()
delegate: ChatConferenceInvitationMessage{
id: calendarMessage
contentModel: $modelData
width: parent.width
availableWidth: mainItem.availableWidth
gotoButtonMode: 1
onExpandToggle: isExpanded=!isExpanded
height: fitHeight
z: 1
onConferenceIcsCopied:mainItem.conferenceIcsCopied()
onFitWidthChanged: messagesConferencesList.updateBestWidth()
Component.onCompleted: messagesConferencesList.updateBestWidth()
}
}
// FILES
GridLayout {
id: messageFilesList
property alias count: repeater.count
visible: count > 0
clip: false
property int availableSection: mainItem.availableWidth / mainItem.fileWidth
property int bestFitSection: mainItem.bestWidth / mainItem.fileWidth
columns: Math.max(1, Math.min(availableSection , bestFitSection))
columnSpacing: 0
rowSpacing: 0
width: parent.width
Repeater{
id: repeater
model: ContentProxyModel{
filter: ContentProxyModel.ContentType.File
chatMessageModel: mainItem.chatMessageModel
}
ChatFileMessage{
contentModel: $modelData
onIsHoveringChanged: mainItem.isFileHoveringChanged(isHovering)
borderWidth: mainItem.fileBorderWidth
backgroundColor: mainItem.fileBackgroundColor
backgroundRadius: mainItem.fileBackgroundRadius
Component.onCompleted: mainComponent.updateFilesBestWidth()
}
}
}
// TEXTS
ListView {
id: messagesTextsList
width: parent.width
visible: count > 0
spacing: 0
clip: false
model: ContentProxyModel{
filter: ContentProxyModel.ContentType.Text
chatMessageModel: mainItem.chatMessageModel
}
height: contentHeight
boundsBehavior: Flickable.StopAtBounds
interactive: false
function updateBestWidth(){
var newWidth = mainComponent.updateListBestWidth(messagesTextsList)
mainItem.textsCount = newWidth[0]
mainItem.textsBestWidth = newWidth[1]
}
Component.onCompleted: messagesTextsList.updateBestWidth()
delegate:
ChatTextMessage {
contentModel: $modelData
onLastTextSelectedChanged: mainItem.lastTextSelectedChanged(lastTextSelected)
color: mainItem.useTextColor
? mainItem.textColor
: $modelData.isOutgoing
? ChatStyle.entry.message.outgoing.text.colorModel.color
: ChatStyle.entry.message.incoming.text.colorModel.color
onRightClicked: mainItem.rightClicked()
onFitWidthChanged: messagesTextsList.updateBestWidth()
Component.onCompleted: messagesTextsList.updateBestWidth()
}
}
}
}
}