mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-22 22:28:08 +00:00
Fix file message menu and refactoring Chat Menu
This commit is contained in:
parent
144557145f
commit
2f534cc327
6 changed files with 533 additions and 436 deletions
|
|
@ -390,6 +390,8 @@
|
|||
<file>ui/modules/Linphone/Calls/ConferenceControls.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/Chat.js</file>
|
||||
<file>ui/modules/Linphone/Chat/Chat.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/ChatDeliveries.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/ChatMenu.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/Event.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/FileMessage.qml</file>
|
||||
<file>ui/modules/Linphone/Chat/IncomingMessage.qml</file>
|
||||
|
|
|
|||
|
|
@ -61,12 +61,14 @@ ChatMessageModel * ParticipantImdnStateProxyModel::getChatMessageModel(){
|
|||
}
|
||||
|
||||
void ParticipantImdnStateProxyModel::setChatMessageModel(ChatMessageModel * message){
|
||||
ParticipantImdnStateListModel *model = static_cast<ParticipantImdnStateListModel*>(sourceModel());
|
||||
ParticipantImdnStateListModel *messageModel = message->getParticipantImdnStates().get();
|
||||
if( model != messageModel){
|
||||
setSourceModel(messageModel);
|
||||
connect(messageModel, &ParticipantImdnStateListModel::countChanged, this, &ParticipantImdnStateProxyModel::countChanged);
|
||||
sort(0);
|
||||
emit chatMessageModelChanged();
|
||||
if(message){
|
||||
ParticipantImdnStateListModel *model = static_cast<ParticipantImdnStateListModel*>(sourceModel());
|
||||
ParticipantImdnStateListModel *messageModel = message->getParticipantImdnStates().get();
|
||||
if( model != messageModel){
|
||||
setSourceModel(messageModel);
|
||||
connect(messageModel, &ParticipantImdnStateListModel::countChanged, this, &ParticipantImdnStateProxyModel::countChanged);
|
||||
sort(0);
|
||||
emit chatMessageModelChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
62
linphone-app/ui/modules/Linphone/Chat/ChatDeliveries.qml
Normal file
62
linphone-app/ui/modules/Linphone/Chat/ChatDeliveries.qml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
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 'Message.js' as Logic
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
||||
GridView{
|
||||
id: deliveryLayout
|
||||
|
||||
property ChatMessageModel chatMessageModel
|
||||
|
||||
|
||||
//height: visible ? ChatStyle.composingText.height*container.proxyModel.composers.length : 0
|
||||
height: visible ? (ChatStyle.composingText.height-5)*deliveryLayout.model.count : 0
|
||||
cellWidth: parent.width; cellHeight: ChatStyle.composingText.height-5
|
||||
visible:false
|
||||
model: ParticipantImdnStateProxyModel{
|
||||
id: imdnStatesModel
|
||||
chatMessageModel: deliveryLayout.chatMessageModel
|
||||
}
|
||||
function getText(state, displayName, stateChangeTime){
|
||||
if(state == LinphoneEnums.ChatMessageStateDelivered)
|
||||
//: 'Send to %1 - %2' Little message to indicate the state of a message
|
||||
//~ Context %1 is someone, %2 is a date/time. The state is that the message has been sent but not received.
|
||||
return qsTr('deliveryDelivered').arg(displayName).arg(stateChangeTime)
|
||||
else if(state == LinphoneEnums.ChatMessageStateDeliveredToUser)
|
||||
//: 'Retrieved by %1 - %2' Little message to indicate the state of a message
|
||||
//~ Context %1 is someone, %2 is a date/time. The state is that the message has been retrieved
|
||||
return qsTr('deliveryDeliveredToUser').arg(displayName).arg(stateChangeTime)
|
||||
else if(state == LinphoneEnums.ChatMessageStateDisplayed)
|
||||
//: 'Read by %1 - %2' Little message to indicate the state of a message
|
||||
//~ Context %1 is someone, %2 is a date/time. The state that the message has been read.
|
||||
return qsTr('deliveryDisplayed').arg(displayName).arg(stateChangeTime)
|
||||
else if(state == LinphoneEnums.ChatMessageStateNotDelivered)
|
||||
//: "%1 have nothing received" Little message to indicate the state of a message
|
||||
//~ Context %1 is someone. The state is that the message hasn't been delivered.
|
||||
return qsTr('deliveryNotDelivered').arg(displayName)
|
||||
else return ''
|
||||
}
|
||||
delegate:Text{
|
||||
height: ChatStyle.composingText.height-5
|
||||
width: GridView.width
|
||||
text: deliveryLayout.getText(modelData.state, modelData.displayName, UtilsCpp.toDateTimeString(modelData.stateChangeTime))
|
||||
color: "#B1B1B1"
|
||||
font.pointSize: Units.dp * 8
|
||||
elide: Text.ElideMiddle
|
||||
}
|
||||
}
|
||||
93
linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml
Normal file
93
linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
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 'Message.js' as Logic
|
||||
|
||||
// =============================================================================
|
||||
|
||||
Item {
|
||||
id: container
|
||||
property string lastTextSelected
|
||||
property string content
|
||||
property int deliveryCount : 0
|
||||
|
||||
signal deliveryStatusClecked()
|
||||
signal removeEntry()
|
||||
|
||||
|
||||
Menu {
|
||||
id: messageMenu
|
||||
menuStyle : MenuStyle.aux
|
||||
MenuItem {
|
||||
//: 'Copy all' : Text menu to copy all message text into clipboard
|
||||
text: (container.lastTextSelected == '' ? qsTr('menuCopyAll')
|
||||
//: 'Copy' : Text menu to copy selected text in message into clipboard
|
||||
: qsTr('menuCopy'))
|
||||
iconMenu: 'menu_copy_text'
|
||||
iconSizeMenu: 17
|
||||
iconLayoutDirection: Qt.RightToLeft
|
||||
menuItemStyle : MenuItemStyle.aux
|
||||
onTriggered: Clipboard.text = (container.lastTextSelected == '' ? container.content : container.lastTextSelected)
|
||||
visible: content != ''
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
enabled: TextToSpeech.available
|
||||
text: qsTr('menuPlayMe')
|
||||
iconMenu: 'speaker'
|
||||
iconSizeMenu: 17
|
||||
iconLayoutDirection: Qt.RightToLeft
|
||||
menuItemStyle : MenuItemStyle.aux
|
||||
onTriggered: TextToSpeech.say(container.content)
|
||||
visible: content != ''
|
||||
}
|
||||
MenuItem {
|
||||
//: 'Delivery status' : Item menu that lead to IMDN of a message
|
||||
text: qsTr('menuDeliveryStatus')
|
||||
iconMenu: 'menu_imdn_info'
|
||||
iconSizeMenu: 17
|
||||
iconLayoutDirection: Qt.RightToLeft
|
||||
menuItemStyle : MenuItemStyle.aux
|
||||
visible: container.deliveryCount > 0
|
||||
onTriggered: container.deliveryStatusClecked()
|
||||
}
|
||||
MenuItem {
|
||||
//: 'Delete' : Item menu to delete a message
|
||||
text: qsTr('menuDelete')
|
||||
iconMenu: 'menu_delete'
|
||||
iconSizeMenu: 17
|
||||
iconLayoutDirection: Qt.RightToLeft
|
||||
menuItemStyle : MenuItemStyle.auxRed
|
||||
onTriggered: removeEntry()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Handle hovered link.
|
||||
MouseArea {
|
||||
anchors.fill:parent
|
||||
// height: parent.height
|
||||
// width: rectangle.width
|
||||
|
||||
acceptedButtons: Qt.RightButton
|
||||
cursorShape: parent.hoveredLink
|
||||
? Qt.PointingHandCursor
|
||||
: Qt.IBeamCursor
|
||||
|
||||
onClicked: mouse.button === Qt.RightButton && messageMenu.open()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,343 +13,365 @@ import Utils 1.0
|
|||
|
||||
Row {
|
||||
id:mainRow
|
||||
// ---------------------------------------------------------------------------
|
||||
// Avatar if it's an incoming message.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
property bool isOutgoing : $chatEntry.isOutgoing || $chatEntry.state == LinphoneEnums.ChatMessageStateIdle;
|
||||
// ---------------------------------------------------------------------------
|
||||
// Avatar if it's an incoming message.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Item {
|
||||
height: ChatStyle.entry.lineHeight
|
||||
width: ChatStyle.entry.metaWidth
|
||||
|
||||
Component {
|
||||
id: avatar
|
||||
|
||||
Avatar {
|
||||
height: ChatStyle.entry.message.incoming.avatarSize
|
||||
width: ChatStyle.entry.message.incoming.avatarSize
|
||||
|
||||
image: $chatEntry.contactModel? $chatEntry.contactModel.vcard.avatar : '' //chat.sipAddressObserver.contact ? chat.sipAddressObserver.contact.vcard.avatar : ''
|
||||
username: isOutgoing? $chatEntry.toDisplayName : $chatEntry.fromDisplayName
|
||||
|
||||
TooltipArea{
|
||||
delay:0
|
||||
text:parent.username+'\n'+ (isOutgoing ? $chatEntry.toSipAddress : $chatEntry.fromSipAddress)
|
||||
tooltipParent:mainRow
|
||||
property bool isOutgoing : $chatEntry.isOutgoing || $chatEntry.state == LinphoneEnums.ChatMessageStateIdle;
|
||||
|
||||
Item {
|
||||
height: ChatStyle.entry.lineHeight
|
||||
width: ChatStyle.entry.metaWidth
|
||||
|
||||
Component {
|
||||
id: avatar
|
||||
|
||||
Avatar {
|
||||
height: ChatStyle.entry.message.incoming.avatarSize
|
||||
width: ChatStyle.entry.message.incoming.avatarSize
|
||||
|
||||
image: $chatEntry.contactModel? $chatEntry.contactModel.vcard.avatar : '' //chat.sipAddressObserver.contact ? chat.sipAddressObserver.contact.vcard.avatar : ''
|
||||
username: isOutgoing? $chatEntry.toDisplayName : $chatEntry.fromDisplayName
|
||||
|
||||
TooltipArea{
|
||||
delay:0
|
||||
text:parent.username+'\n'+ (isOutgoing ? $chatEntry.toSipAddress : $chatEntry.fromSipAddress)
|
||||
tooltipParent:mainRow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: !isOutgoing? avatar : undefined
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// File message.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Row {
|
||||
spacing: ChatStyle.entry.message.extraContent.leftMargin
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
|
||||
readonly property bool isError: Utils.includes([
|
||||
LinphoneEnums.ChatMessageStateFileTransferError,
|
||||
LinphoneEnums.ChatMessageStateNotDelivered,
|
||||
], $chatEntry.state)
|
||||
readonly property bool isUploaded: $chatEntry.state == LinphoneEnums.ChatMessageStateDelivered
|
||||
readonly property bool isDelivered: $chatEntry.state == LinphoneEnums.ChatMessageStateDeliveredToUser
|
||||
readonly property bool isRead: $chatEntry.state == LinphoneEnums.ChatMessageStateDisplayed
|
||||
|
||||
|
||||
//property ContentModel contentModel : ($chatEntry.getContent(0) ? $chatEntry.getContent(0) : null)
|
||||
property ContentModel contentModel : $chatEntry.fileContentModel
|
||||
property string thumbnail : contentModel.thumbnail
|
||||
color: isOutgoing
|
||||
? ChatStyle.entry.message.outgoing.backgroundColor
|
||||
: ChatStyle.entry.message.incoming.backgroundColor
|
||||
|
||||
height: ChatStyle.entry.message.file.height
|
||||
width: ChatStyle.entry.message.file.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 {
|
||||
mipmap: Qt.platform.os === 'osx'
|
||||
source: rectangle.contentModel.thumbnail
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: extension
|
||||
|
||||
Rectangle {
|
||||
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: (rectangle.contentModel?Utils.getExtension(rectangle.contentModel.name).toUpperCase():'')
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: thumbnailProvider
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: parent.height
|
||||
|
||||
sourceComponent: (rectangle.contentModel ? (rectangle.contentModel.thumbnail ? 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 = ChatStyle.entry.message.file.animation.to
|
||||
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.
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
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: (rectangle.contentModel ? rectangle.contentModel.name : '')
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
ProgressBar {
|
||||
id: progressBar
|
||||
|
||||
height: ChatStyle.entry.message.file.status.bar.height
|
||||
width: parent.width
|
||||
|
||||
to: (rectangle.contentModel ? rectangle.contentModel.fileSize : 0)
|
||||
value: rectangle.contentModel ? rectangle.contentModel.fileOffset || 0 : 0
|
||||
visible: $chatEntry.state == LinphoneEnums.ChatMessageStateInProgress || $chatEntry.state == LinphoneEnums.ChatMessageStateFileTransferInProgress
|
||||
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 {
|
||||
color: fileName.color
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: fileName.font.pointSize
|
||||
text: {
|
||||
if(rectangle.contentModel){
|
||||
var fileSize = Utils.formatSize(rectangle.contentModel.fileSize)
|
||||
return progressBar.visible
|
||||
? Utils.formatSize(rectangle.contentModel.fileOffset) + '/' + fileSize
|
||||
: fileSize
|
||||
}else
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Icon {
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: ChatStyle.entry.message.file.margins
|
||||
right: parent.right
|
||||
rightMargin: ChatStyle.entry.message.file.margins
|
||||
}
|
||||
|
||||
icon: 'download'
|
||||
iconSize: ChatStyle.entry.message.file.iconSize
|
||||
visible: (rectangle.contentModel?!isOutgoing&& !rectangle.contentModel.wasDownloaded : false)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
function handleMouseMove (mouse) {
|
||||
thumbnailProvider.state = Utils.pointIsInItem(this, thumbnailProvider, mouse)
|
||||
? 'hovered'
|
||||
: ''
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
visible: ((rectangle.isUploaded || rectangle.isRead) && !isOutgoing) || isOutgoing
|
||||
|
||||
onClicked: {
|
||||
if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) {
|
||||
rectangle.contentModel.openFile()
|
||||
} else if (rectangle.contentModel && rectangle.contentModel.wasDownloaded) {
|
||||
rectangle.contentModel.openFile(true)// Show directory
|
||||
} else {
|
||||
rectangle.contentModel.downloadFile()
|
||||
}
|
||||
}
|
||||
|
||||
onExited: thumbnailProvider.state = ''
|
||||
onMouseXChanged: handleMouseMove.call(this, mouse)
|
||||
onMouseYChanged: handleMouseMove.call(this, mouse)
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Resend/Remove file message.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Row {
|
||||
spacing: ChatStyle.entry.message.extraContent.spacing
|
||||
|
||||
Component {
|
||||
id: icon
|
||||
|
||||
Icon {
|
||||
anchors.centerIn: parent
|
||||
|
||||
icon: rectangle.isError ? 'chat_error' :
|
||||
(rectangle.isRead ? 'chat_read' :
|
||||
(rectangle.isDelivered ? 'chat_delivered' : ''))
|
||||
|
||||
iconSize: ChatStyle.entry.message.outgoing.sendIconSize
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
visible: (rectangle.isError || $chatEntry.state == LinphoneEnums.ChatMessageStateIdle) && isOutgoing
|
||||
onClicked: proxyModel.resendMessage(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: indicator
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
|
||||
height: ChatStyle.entry.message.outgoing.busyIndicatorSize
|
||||
width: ChatStyle.entry.message.outgoing.busyIndicatorSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
height: ChatStyle.entry.lineHeight
|
||||
width: ChatStyle.entry.message.outgoing.areaSize
|
||||
|
||||
sourceComponent: isOutgoing
|
||||
? (
|
||||
$chatEntry.state == LinphoneEnums.ChatMessageStateInProgress || $chatEntry.state == LinphoneEnums.ChatMessageStateFileTransferInProgress
|
||||
? indicator
|
||||
: icon
|
||||
) : undefined
|
||||
}
|
||||
|
||||
ActionButton {
|
||||
height: ChatStyle.entry.lineHeight
|
||||
icon: 'delete'
|
||||
iconSize: ChatStyle.entry.deleteIconSize
|
||||
visible: isHoverEntry()
|
||||
|
||||
onClicked: removeEntry()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: !isOutgoing? avatar : undefined
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// File message.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Row {
|
||||
spacing: ChatStyle.entry.message.extraContent.leftMargin
|
||||
Item{
|
||||
width: ChatStyle.entry.message.file.width
|
||||
height:rectangle.height + deliveryLayout.height
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
|
||||
readonly property bool isError: Utils.includes([
|
||||
LinphoneEnums.ChatMessageStateFileTransferError,
|
||||
LinphoneEnums.ChatMessageStateNotDelivered,
|
||||
], $chatEntry.state)
|
||||
readonly property bool isUploaded: $chatEntry.state == LinphoneEnums.ChatMessageStateDelivered
|
||||
readonly property bool isDelivered: $chatEntry.state == LinphoneEnums.ChatMessageStateDeliveredToUser
|
||||
readonly property bool isRead: $chatEntry.state == LinphoneEnums.ChatMessageStateDisplayed
|
||||
|
||||
|
||||
//property ContentModel contentModel : ($chatEntry.getContent(0) ? $chatEntry.getContent(0) : null)
|
||||
property ContentModel contentModel : $chatEntry.fileContentModel
|
||||
property string thumbnail : contentModel.thumbnail
|
||||
color: isOutgoing
|
||||
? ChatStyle.entry.message.outgoing.backgroundColor
|
||||
: ChatStyle.entry.message.incoming.backgroundColor
|
||||
|
||||
height: ChatStyle.entry.message.file.height
|
||||
width: ChatStyle.entry.message.file.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 {
|
||||
mipmap: Qt.platform.os === 'osx'
|
||||
source: rectangle.contentModel.thumbnail
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: extension
|
||||
|
||||
Rectangle {
|
||||
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: (rectangle.contentModel?Utils.getExtension(rectangle.contentModel.name).toUpperCase():'')
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: thumbnailProvider
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: parent.height
|
||||
|
||||
sourceComponent: (rectangle.contentModel ? (rectangle.contentModel.thumbnail ? 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 = ChatStyle.entry.message.file.animation.to
|
||||
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.
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
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: (rectangle.contentModel ? rectangle.contentModel.name : '')
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
ProgressBar {
|
||||
id: progressBar
|
||||
|
||||
height: ChatStyle.entry.message.file.status.bar.height
|
||||
width: parent.width
|
||||
|
||||
to: (rectangle.contentModel ? rectangle.contentModel.fileSize : 0)
|
||||
value: rectangle.contentModel ? rectangle.contentModel.fileOffset || 0 : 0
|
||||
visible: $chatEntry.state == LinphoneEnums.ChatMessageStateInProgress || $chatEntry.state == LinphoneEnums.ChatMessageStateFileTransferInProgress
|
||||
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 {
|
||||
color: fileName.color
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: fileName.font.pointSize
|
||||
text: {
|
||||
if(rectangle.contentModel){
|
||||
var fileSize = Utils.formatSize(rectangle.contentModel.fileSize)
|
||||
return progressBar.visible
|
||||
? Utils.formatSize(rectangle.contentModel.fileOffset) + '/' + fileSize
|
||||
: fileSize
|
||||
}else
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Icon {
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: ChatStyle.entry.message.file.margins
|
||||
right: parent.right
|
||||
rightMargin: ChatStyle.entry.message.file.margins
|
||||
}
|
||||
|
||||
icon: 'download'
|
||||
iconSize: ChatStyle.entry.message.file.iconSize
|
||||
visible: (rectangle.contentModel?!isOutgoing&& !rectangle.contentModel.wasDownloaded : false)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
function handleMouseMove (mouse) {
|
||||
thumbnailProvider.state = Utils.pointIsInItem(this, thumbnailProvider, mouse)
|
||||
? 'hovered'
|
||||
: ''
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
visible: ((rectangle.isUploaded || rectangle.isRead) && !isOutgoing) || isOutgoing
|
||||
|
||||
onClicked: {
|
||||
if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) {
|
||||
rectangle.contentModel.openFile()
|
||||
} else if (rectangle.contentModel && rectangle.contentModel.wasDownloaded) {
|
||||
rectangle.contentModel.openFile(true)// Show directory
|
||||
} else {
|
||||
rectangle.contentModel.downloadFile()
|
||||
}
|
||||
}
|
||||
|
||||
onExited: thumbnailProvider.state = ''
|
||||
onMouseXChanged: handleMouseMove.call(this, mouse)
|
||||
onMouseYChanged: handleMouseMove.call(this, mouse)
|
||||
}
|
||||
ChatMenu{
|
||||
height: parent.height
|
||||
width: rectangle.width
|
||||
|
||||
deliveryCount: deliveryLayout.model.count
|
||||
onDeliveryStatusClecked: deliveryLayout.visible = !deliveryLayout.visible
|
||||
}
|
||||
}
|
||||
|
||||
ChatDeliveries{
|
||||
id: deliveryLayout
|
||||
anchors.top:rectangle.bottom
|
||||
anchors.left:parent.left
|
||||
anchors.right:parent.right
|
||||
anchors.rightMargin: 50
|
||||
|
||||
chatMessageModel: $chatEntry
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Resend/Remove file message.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Row {
|
||||
spacing: ChatStyle.entry.message.extraContent.spacing
|
||||
|
||||
Component {
|
||||
id: icon
|
||||
|
||||
Icon {
|
||||
anchors.centerIn: parent
|
||||
|
||||
icon: rectangle.isError ? 'chat_error' :
|
||||
(rectangle.isRead ? 'chat_read' :
|
||||
(rectangle.isDelivered ? 'chat_delivered' : ''))
|
||||
|
||||
iconSize: ChatStyle.entry.message.outgoing.sendIconSize
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
visible: (rectangle.isError || $chatEntry.state == LinphoneEnums.ChatMessageStateIdle) && isOutgoing
|
||||
onClicked: proxyModel.resendMessage(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: indicator
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
|
||||
height: ChatStyle.entry.message.outgoing.busyIndicatorSize
|
||||
width: ChatStyle.entry.message.outgoing.busyIndicatorSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
height: ChatStyle.entry.lineHeight
|
||||
width: ChatStyle.entry.message.outgoing.areaSize
|
||||
|
||||
sourceComponent: isOutgoing
|
||||
? (
|
||||
$chatEntry.state == LinphoneEnums.ChatMessageStateInProgress || $chatEntry.state == LinphoneEnums.ChatMessageStateFileTransferInProgress
|
||||
? indicator
|
||||
: icon
|
||||
) : undefined
|
||||
}
|
||||
|
||||
ActionButton {
|
||||
height: ChatStyle.entry.lineHeight
|
||||
icon: 'delete'
|
||||
iconSize: ChatStyle.entry.deleteIconSize
|
||||
visible: isHoverEntry()
|
||||
|
||||
onClicked: removeEntry()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,65 +109,14 @@ Item {
|
|||
deselect()
|
||||
}
|
||||
|
||||
|
||||
Menu {
|
||||
id: messageMenu
|
||||
menuStyle : MenuStyle.aux
|
||||
MenuItem {
|
||||
//: 'Copy all' : Text menu to copy all message text into clipboard
|
||||
text: (message.lastTextSelected == '' ? qsTr('menuCopyAll')
|
||||
//: 'Copy' : Text menu to copy selected text in message into clipboard
|
||||
: qsTr('menuCopy'))
|
||||
iconMenu: 'menu_copy_text'
|
||||
iconSizeMenu: 17
|
||||
iconLayoutDirection: Qt.RightToLeft
|
||||
menuItemStyle : MenuItemStyle.aux
|
||||
onTriggered: Clipboard.text = (message.lastTextSelected == '' ? $chatEntry.content : message.lastTextSelected)
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
enabled: TextToSpeech.available
|
||||
text: qsTr('menuPlayMe')
|
||||
iconMenu: 'speaker'
|
||||
iconSizeMenu: 17
|
||||
iconLayoutDirection: Qt.RightToLeft
|
||||
menuItemStyle : MenuItemStyle.aux
|
||||
onTriggered: TextToSpeech.say($chatEntry.content)
|
||||
}
|
||||
MenuItem {
|
||||
//: 'Delivery status' : Item menu that lead to IMDN of a message
|
||||
text: qsTr('menuDeliveryStatus')
|
||||
iconMenu: 'menu_imdn_info'
|
||||
iconSizeMenu: 17
|
||||
iconLayoutDirection: Qt.RightToLeft
|
||||
menuItemStyle : MenuItemStyle.aux
|
||||
visible: deliveryLayout.model.count > 0
|
||||
onTriggered: deliveryLayout.visible = !deliveryLayout.visible
|
||||
}
|
||||
MenuItem {
|
||||
//: 'Delete' : Item menu to delete a message
|
||||
text: qsTr('menuDelete')
|
||||
iconMenu: 'menu_delete'
|
||||
iconSizeMenu: 17
|
||||
iconLayoutDirection: Qt.RightToLeft
|
||||
menuItemStyle : MenuItemStyle.auxRed
|
||||
onTriggered: removeEntry()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Handle hovered link.
|
||||
MouseArea {
|
||||
ChatMenu{
|
||||
height: parent.height
|
||||
width: rectangle.width
|
||||
|
||||
acceptedButtons: Qt.RightButton
|
||||
cursorShape: parent.hoveredLink
|
||||
? Qt.PointingHandCursor
|
||||
: Qt.IBeamCursor
|
||||
|
||||
onClicked: mouse.button === Qt.RightButton && messageMenu.open()
|
||||
lastTextSelected: message.lastTextSelected
|
||||
content: $chatEntry.content
|
||||
deliveryCount: deliveryLayout.model.count
|
||||
onDeliveryStatusClecked: deliveryLayout.visible = !deliveryLayout.visible
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -183,46 +132,13 @@ Item {
|
|||
leftMargin: ChatStyle.entry.message.extraContent.leftMargin
|
||||
}
|
||||
}
|
||||
GridView{
|
||||
ChatDeliveries{
|
||||
id: deliveryLayout
|
||||
anchors.top:rectangle.bottom
|
||||
anchors.left:parent.left
|
||||
anchors.right:parent.right
|
||||
anchors.rightMargin: 50
|
||||
//height: visible ? ChatStyle.composingText.height*container.proxyModel.composers.length : 0
|
||||
height: visible ? (ChatStyle.composingText.height-5)*deliveryLayout.model.count : 0
|
||||
cellWidth: parent.width; cellHeight: ChatStyle.composingText.height-5
|
||||
visible:false
|
||||
model: ParticipantImdnStateProxyModel{
|
||||
id: imdnStatesModel
|
||||
chatMessageModel: $chatEntry
|
||||
}
|
||||
function getText(state, displayName, stateChangeTime){
|
||||
if(state == LinphoneEnums.ChatMessageStateDelivered)
|
||||
//: 'Send to %1 - %2' Little message to indicate the state of a message
|
||||
//~ Context %1 is someone, %2 is a date/time. The state is that the message has been sent but not received.
|
||||
return qsTr('deliveryDelivered').arg(displayName).arg(stateChangeTime)
|
||||
else if(state == LinphoneEnums.ChatMessageStateDeliveredToUser)
|
||||
//: 'Retrieved by %1 - %2' Little message to indicate the state of a message
|
||||
//~ Context %1 is someone, %2 is a date/time. The state is that the message has been retrieved
|
||||
return qsTr('deliveryDeliveredToUser').arg(displayName).arg(stateChangeTime)
|
||||
else if(state == LinphoneEnums.ChatMessageStateDisplayed)
|
||||
//: 'Read by %1 - %2' Little message to indicate the state of a message
|
||||
//~ Context %1 is someone, %2 is a date/time. The state that the message has been read.
|
||||
return qsTr('deliveryDisplayed').arg(displayName).arg(stateChangeTime)
|
||||
else if(state == LinphoneEnums.ChatMessageStateNotDelivered)
|
||||
//: "%1 have nothing received" Little message to indicate the state of a message
|
||||
//~ Context %1 is someone. The state is that the message hasn't been delivered.
|
||||
return qsTr('deliveryNotDelivered').arg(displayName)
|
||||
else return ''
|
||||
}
|
||||
delegate:Text{
|
||||
height: ChatStyle.composingText.height-5
|
||||
width: GridView.width
|
||||
text: deliveryLayout.getText(modelData.state, modelData.displayName, UtilsCpp.toDateTimeString(modelData.stateChangeTime))
|
||||
color: "#B1B1B1"
|
||||
font.pointSize: Units.dp * 8
|
||||
elide: Text.ElideMiddle
|
||||
}
|
||||
|
||||
chatMessageModel: $chatEntry
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue