linphone-desktop/linphone-app/ui/modules/Linphone/Chat/ChatFileMessage.qml

317 lines
10 KiB
QML

import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import LinphoneEnums 1.0
import Linphone.Styles 1.0
import Utils 1.0
import Units 1.0
import ColorsList 1.0
import UtilsCpp 1.0
// =============================================================================
// TODO : into Loader
Row {
id:mainRow
property ChatMessageModel chatMessageModel: contentModel && contentModel.chatMessageModel
property ContentModel contentModel
property bool isOutgoing : chatMessageModel && ( chatMessageModel.isOutgoing || chatMessageModel.state == LinphoneEnums.ChatMessageStateIdle);
property int fitWidth: visible ? Math.max( (fileName.visible ? fileName.implicitWidth : 0)
+ thumbnailProvider.width + 3*ChatStyle.entry.message.file.margins
, Math.max(ChatStyle.entry.message.file.width, ChatStyle.entry.message.outgoing.areaSize)) : 0
property int fitHeight: visible ? rectangle.height : 0
property bool isAnimatedImage : mainRow.contentModel && mainRow.contentModel.wasDownloaded && UtilsCpp.isAnimatedImage(mainRow.contentModel.filePath)
property bool haveThumbnail: mainRow.contentModel && mainRow.contentModel.thumbnail
signal copyAllDone()
signal copySelectionDone()
signal forwardClicked()
height: fitHeight
visible: contentModel && !contentModel.isIcalendar() && (contentModel.isFile() || contentModel.isFileTransfer()) && !contentModel.isVoiceRecording()
// ---------------------------------------------------------------------------
// File message.
// ---------------------------------------------------------------------------
Row {
spacing: ChatStyle.entry.message.extraContent.leftMargin
Item{
width: mainRow.width
height:rectangle.height
Rectangle {
id: rectangle
readonly property bool isError: chatMessageModel && Utils.includes([
LinphoneEnums.ChatMessageStateFileTransferError,
LinphoneEnums.ChatMessageStateNotDelivered,
], chatMessageModel.state)
readonly property bool isUploaded: chatMessageModel && chatMessageModel.state == LinphoneEnums.ChatMessageStateDelivered
readonly property bool isDelivered: chatMessageModel && chatMessageModel.state == LinphoneEnums.ChatMessageStateDeliveredToUser
readonly property bool isRead: chatMessageModel && chatMessageModel.state == LinphoneEnums.ChatMessageStateDisplayed
property string thumbnail : mainRow.contentModel ? mainRow.contentModel.thumbnail : ''
color: 'transparent'
height: mainRow.isAnimatedImage ? ChatStyle.entry.message.file.heightbetter : ChatStyle.entry.message.file.height
width: mainRow.width
radius: ChatStyle.entry.message.radius
RowLayout {
anchors {
fill: parent
margins: ChatStyle.entry.message.file.margins
}
spacing: ChatStyle.entry.message.file.spacing
// ---------------------------------------------------------------------
// Thumbnail or extension.
// ---------------------------------------------------------------------
Component {
id: thumbnailImage
Image {
id: thumbnailImageSource
property real scaleAnimatorTo : ChatStyle.entry.message.file.animation.thumbnailTo
mipmap: SettingsModel.mipmapEnabled
source: mainRow.contentModel.thumbnail
fillMode: Image.PreserveAspectFit
Loader{
anchors.fill: parent
sourceComponent: Image{// Better quality on zoom
mipmap: SettingsModel.mipmapEnabled
source:'file:/'+mainRow.contentModel.filePath
fillMode: Image.PreserveAspectFit
visible: status == Image.Ready
}
asynchronous: true
active: thumbnailProvider.state == 'hovered'
}
}
}
Component {
id: animatedImage
AnimatedImage {
id: animatedImageSource
property real scaleAnimatorTo : ChatStyle.entry.message.file.animation.to
mipmap: SettingsModel.mipmapEnabled
source: 'file:/'+mainRow.contentModel.filePath
fillMode: Image.PreserveAspectFit
//width: 200
//height: 100
}
}
Component {
id: extension
Rectangle {
property real scaleAnimatorTo : ChatStyle.entry.message.file.animation.to
color: ChatStyle.entry.message.file.extension.background.color
Text {
anchors.fill: parent
color: ChatStyle.entry.message.file.extension.text.color
font.bold: true
elide: Text.ElideRight
text: (mainRow.contentModel?Utils.getExtension(mainRow.contentModel.name).toUpperCase():'')
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}
Loader {
id: thumbnailProvider
Layout.fillHeight: true
Layout.preferredWidth: parent.height*4/3
sourceComponent: (mainRow.contentModel ?
(mainRow.isAnimatedImage ? animatedImage
: (mainRow.haveThumbnail ? thumbnailImage : extension )
) : undefined)
ScaleAnimator {
id: thumbnailProviderAnimator
target: thumbnailProvider
duration: ChatStyle.entry.message.file.animation.duration
easing.type: Easing.InOutQuad
from: 1.0
}
states: State {
name: 'hovered'
}
transitions: [
Transition {
from: ''
to: 'hovered'
ScriptAction {
script: {
if (thumbnailProviderAnimator.running) {
thumbnailProviderAnimator.running = false
}
thumbnailProvider.z = Constants.zPopup
thumbnailProviderAnimator.to = thumbnailProvider.item.scaleAnimatorTo
thumbnailProviderAnimator.running = true
}
}
},
Transition {
from: 'hovered'
to: ''
ScriptAction {
script: {
if (thumbnailProviderAnimator.running) {
thumbnailProviderAnimator.running = false
}
thumbnailProviderAnimator.to = 1.0
thumbnailProviderAnimator.running = true
thumbnailProvider.z = 0
}
}
}
]
}
// ---------------------------------------------------------------------
// Upload or file status.
// ---------------------------------------------------------------------
Item{
Layout.fillWidth: true
Layout.fillHeight: true
Column {
anchors.fill: parent
spacing: ChatStyle.entry.message.file.status.spacing
Text {
id: fileName
color: isOutgoing
? ChatStyle.entry.message.outgoing.text.color
: ChatStyle.entry.message.incoming.text.color
elide: Text.ElideRight
font {
bold: true
pointSize: isOutgoing
? ChatStyle.entry.message.outgoing.text.pointSize
: ChatStyle.entry.message.incoming.text.pointSize
}
text: (mainRow.contentModel ? mainRow.contentModel.name : '')
width: visible ? parent.width : 0
visible: mainRow.contentModel && !mainRow.isAnimatedImage && !mainRow.haveThumbnail
}
ProgressBar {
id: progressBar
height: ChatStyle.entry.message.file.status.bar.height
width: visible ? parent.width : 0
to: (mainRow.contentModel ? mainRow.contentModel.fileSize : 0)
value: mainRow.contentModel ? mainRow.contentModel.fileOffset || to : to
visible: value != to
background: Rectangle {
color: ChatStyle.entry.message.file.status.bar.background.color
radius: ChatStyle.entry.message.file.status.bar.radius
}
contentItem: Item {
Rectangle {
color: ChatStyle.entry.message.file.status.bar.contentItem.color
height: parent.height
width: progressBar.visualPosition * parent.width
radius: ChatStyle.entry.message.file.status.bar.radius
}
}
}
Text {
visible: progressBar.value != progressBar.to
color: fileName.color
elide: Text.ElideRight
font.pointSize: fileName.font.pointSize
text: {
if(mainRow.contentModel){
var fileSize = Utils.formatSize(mainRow.contentModel.fileSize)
return progressBar.visible
? Utils.formatSize(mainRow.contentModel.fileOffset) + '/' + fileSize
: fileSize
}else
return ''
}
}
}
}
}
Icon {
id:downloadButton
anchors {
bottom: parent.bottom
bottomMargin: ChatStyle.entry.message.file.margins
right: parent.right
rightMargin: ChatStyle.entry.message.file.margins
}
icon: ChatStyle.entry.message.file.download.icon
iconSize: ChatStyle.entry.message.file.download.iconSize
overwriteColor: isOutgoing ? ChatStyle.entry.message.file.download.outgoingColor : ChatStyle.entry.message.file.download.incomingColor
visible: !progressBar.visible && (mainRow.contentModel? !mainRow.contentModel.wasDownloaded : false)
}
MouseArea {
function handleMouseMove (mouse) {
thumbnailProvider.state = Utils.pointIsInItem(this, thumbnailProvider, mouse)
? 'hovered'
: ''
}
anchors.fill: parent
visible: true
//downloadButton.visible || ((rectangle.isUploaded || rectangle.isRead) && !isOutgoing) || isOutgoing
//onVisibleChanged: console.log("Mouse of "+mainRow.contentModel.name+" / "+downloadButton.visible
// +"/"+rectangle.isUploaded +"/"+rectangle.isRead)
onClicked: {
if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) {
mainRow.contentModel.openFile()
} else if (mainRow.contentModel && mainRow.contentModel.wasDownloaded) {
mainRow.contentModel.openFile(true)// Show directory
thumbnailProvider.state = ''
} else {
mainRow.contentModel.downloadFile()
thumbnailProvider.state = ''
}
}
onExited: thumbnailProvider.state = ''
onMouseXChanged: handleMouseMove.call(this, mouse)
onMouseYChanged: handleMouseMove.call(this, mouse)
}
}
}
}
}