diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc
index 0b490187b..f96bda4cc 100644
--- a/linphone-app/resources.qrc
+++ b/linphone-app/resources.qrc
@@ -390,6 +390,8 @@
ui/modules/Linphone/Calls/ConferenceControls.qml
ui/modules/Linphone/Chat/Chat.js
ui/modules/Linphone/Chat/Chat.qml
+ ui/modules/Linphone/Chat/ChatDeliveries.qml
+ ui/modules/Linphone/Chat/ChatMenu.qml
ui/modules/Linphone/Chat/Event.qml
ui/modules/Linphone/Chat/FileMessage.qml
ui/modules/Linphone/Chat/IncomingMessage.qml
diff --git a/linphone-app/src/components/participant-imdn/ParticipantImdnStateProxyModel.cpp b/linphone-app/src/components/participant-imdn/ParticipantImdnStateProxyModel.cpp
index 302a1354f..f6112ad84 100644
--- a/linphone-app/src/components/participant-imdn/ParticipantImdnStateProxyModel.cpp
+++ b/linphone-app/src/components/participant-imdn/ParticipantImdnStateProxyModel.cpp
@@ -61,12 +61,14 @@ ChatMessageModel * ParticipantImdnStateProxyModel::getChatMessageModel(){
}
void ParticipantImdnStateProxyModel::setChatMessageModel(ChatMessageModel * message){
- ParticipantImdnStateListModel *model = static_cast(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(sourceModel());
+ ParticipantImdnStateListModel *messageModel = message->getParticipantImdnStates().get();
+ if( model != messageModel){
+ setSourceModel(messageModel);
+ connect(messageModel, &ParticipantImdnStateListModel::countChanged, this, &ParticipantImdnStateProxyModel::countChanged);
+ sort(0);
+ emit chatMessageModelChanged();
+ }
}
}
\ No newline at end of file
diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatDeliveries.qml b/linphone-app/ui/modules/Linphone/Chat/ChatDeliveries.qml
new file mode 100644
index 000000000..3477ef37a
--- /dev/null
+++ b/linphone-app/ui/modules/Linphone/Chat/ChatDeliveries.qml
@@ -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
+ }
+}
diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml b/linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml
new file mode 100644
index 000000000..c350f7915
--- /dev/null
+++ b/linphone-app/ui/modules/Linphone/Chat/ChatMenu.qml
@@ -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()
+ }
+
+}
diff --git a/linphone-app/ui/modules/Linphone/Chat/FileMessage.qml b/linphone-app/ui/modules/Linphone/Chat/FileMessage.qml
index 8135816e9..da09fccde 100644
--- a/linphone-app/ui/modules/Linphone/Chat/FileMessage.qml
+++ b/linphone-app/ui/modules/Linphone/Chat/FileMessage.qml
@@ -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()
+ }
+ }
+ }
+
}
diff --git a/linphone-app/ui/modules/Linphone/Chat/Message.qml b/linphone-app/ui/modules/Linphone/Chat/Message.qml
index 1bd4853bb..ad7c62c59 100644
--- a/linphone-app/ui/modules/Linphone/Chat/Message.qml
+++ b/linphone-app/ui/modules/Linphone/Chat/Message.qml
@@ -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
}
}