Fix file message menu and refactoring Chat Menu

This commit is contained in:
Julien Wadel 2021-08-16 17:06:11 +02:00
parent 144557145f
commit 2f534cc327
6 changed files with 533 additions and 436 deletions

View file

@ -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>

View 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();
}
}
}

View 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
}
}

View 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()
}
}

View file

@ -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()
}
}
}
}

View file

@ -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
}
}