mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-20 13:18:06 +00:00
317 lines
10 KiB
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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|