fix: Pinning messages - tweaks to UI and interactions

... to help align with original design intent

- dropped date breaks before msg groups
- show full date/timestamp in the msg header
- floating "Unpin" button on mouse hover
- no padding/spacing between messages
- some smaller code cleanups and dead code removals

Fixes #9396
This commit is contained in:
Lukáš Tinkl 2023-02-15 12:12:12 +01:00 committed by Lukáš Tinkl
parent 165271dbea
commit 31be818e0e
16 changed files with 109 additions and 103 deletions

View File

@ -60,6 +60,7 @@ Control {
property bool overrideBackground: false property bool overrideBackground: false
property bool profileClickable: true property bool profileClickable: true
property bool hideMessage: false property bool hideMessage: false
property bool isInPinnedPopup
property StatusMessageDetails messageDetails: StatusMessageDetails {} property StatusMessageDetails messageDetails: StatusMessageDetails {}
property StatusMessageDetails replyDetails: StatusMessageDetails {} property StatusMessageDetails replyDetails: StatusMessageDetails {}
@ -76,7 +77,7 @@ Control {
signal stickerClicked() signal stickerClicked()
signal resendClicked() signal resendClicked()
signal editCompleted(var newMsgText) signal editCompleted(string newMsgText)
signal editCancelled() signal editCancelled()
signal stickerLoaded() signal stickerLoaded()
signal linkActivated(string link) signal linkActivated(string link)
@ -242,42 +243,43 @@ Control {
sender: root.messageDetails.sender sender: root.messageDetails.sender
amISender: root.messageDetails.amISender amISender: root.messageDetails.amISender
messageOriginInfo: root.messageDetails.messageOriginInfo messageOriginInfo: root.messageDetails.messageOriginInfo
showResendButton: root.hasExpired && root.messageDetails.amISender && !editMode showResendButton: root.hasExpired && root.messageDetails.amISender && !editMode && !root.isInPinnedPopup
showSendingLoader: root.isSending && root.messageDetails.amISender && !editMode showSendingLoader: root.isSending && root.messageDetails.amISender && !editMode
resendError: root.messageDetails.amISender && !editMode ? root.resendError : "" resendError: root.messageDetails.amISender && !editMode ? root.resendError : ""
onClicked: root.senderNameClicked(sender, mouse) onClicked: root.senderNameClicked(sender, mouse)
onResendClicked: root.resendClicked() onResendClicked: root.resendClicked()
timestamp: root.timestamp timestamp: root.timestamp
showFullTimestamp: root.isInPinnedPopup
displayNameClickable: root.profileClickable displayNameClickable: root.profileClickable
} }
} }
Loader { Loader {
Layout.fillWidth: true Layout.fillWidth: true
active: (!root.editMode && !!root.messageDetails.messageText && !root.hideMessage active: (!root.editMode && !!root.messageDetails.messageText && !root.hideMessage
&& ((root.messageDetails.contentType === StatusMessage.ContentType.Text) && ((root.messageDetails.contentType === StatusMessage.ContentType.Text)
|| (root.messageDetails.contentType === StatusMessage.ContentType.Emoji) || || (root.messageDetails.contentType === StatusMessage.ContentType.Emoji) ||
(root.messageDetails.contentType === StatusMessage.ContentType.DiscordMessage))) (root.messageDetails.contentType === StatusMessage.ContentType.DiscordMessage)))
visible: active visible: active
sourceComponent: StatusTextMessage { sourceComponent: StatusTextMessage {
objectName: "StatusMessage_textMessage" objectName: "StatusMessage_textMessage"
messageDetails: root.messageDetails messageDetails: root.messageDetails
isEdited: root.isEdited isEdited: root.isEdited
allowShowMore: !root.isInPinnedPopup
textField.anchors.rightMargin: root.isInPinnedPopup ? /*Style.current.xlPadding*/ 32 : 0 // margin for the "Unpin" floating button
onLinkActivated: { onLinkActivated: {
root.linkActivated(link); root.linkActivated(link);
} }
} }
} }
Loader { Loader {
active: root.messageDetails.contentType === StatusMessage.ContentType.Image && !editMode active: root.messageDetails.contentType === StatusMessage.ContentType.Image && !editMode
visible: active visible: active
sourceComponent: StatusImageMessage { sourceComponent: StatusImageMessage {
source: root.messageDetails.contentType === StatusMessage.ContentType.Image ? root.messageDetails.messageContent : "" source: root.messageDetails.messageContent
onClicked: root.imageClicked(image, mouse, imageSource) onClicked: root.imageClicked(image, mouse, imageSource)
shapeType: root.messageDetails.amISender ? StatusImageMessage.ShapeType.RIGHT_ROUNDED : StatusImageMessage.ShapeType.LEFT_ROUNDED shapeType: root.messageDetails.amISender ? StatusImageMessage.ShapeType.RIGHT_ROUNDED : StatusImageMessage.ShapeType.LEFT_ROUNDED
} }
} }
Loader { Loader {
active: root.messageAttachments && !editMode active: root.messageAttachments && !editMode
visible: active visible: active
@ -294,18 +296,13 @@ Control {
} }
} }
} }
StatusSticker {
Loader {
active: root.messageDetails.contentType === StatusMessage.ContentType.Sticker && !editMode active: root.messageDetails.contentType === StatusMessage.ContentType.Sticker && !editMode
visible: active visible: active
sourceComponent: StatusSticker { asset.isImage: true
asset.isImage: true asset.name: root.messageDetails.messageContent
asset.name: root.messageDetails.messageContent onStickerLoaded: root.stickerLoaded()
onLoaded: root.stickerLoaded() onClicked: root.stickerClicked()
onClicked: {
root.stickerClicked()
}
}
} }
Loader { Loader {
active: root.messageDetails.contentType === StatusMessage.ContentType.Audio && !editMode active: root.messageDetails.contentType === StatusMessage.ContentType.Audio && !editMode
@ -371,11 +368,8 @@ Control {
anchors.rightMargin: 20 anchors.rightMargin: 20
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: -8 anchors.topMargin: -8
sourceComponent: Component { sourceComponent: StatusMessageQuickActions {
StatusMessageQuickActions { items: root.quickActions
id: quickActionsPanel
items: root.quickActions
}
} }
} }
} }

View File

@ -27,6 +27,7 @@ Item {
property bool amISender: false property bool amISender: false
property bool displayNameClickable: true property bool displayNameClickable: true
property string messageOriginInfo: "" property string messageOriginInfo: ""
property bool showFullTimestamp
signal clicked(var sender, var mouse) signal clicked(var sender, var mouse)
signal resendClicked() signal resendClicked()
@ -131,6 +132,7 @@ Item {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
id: timestampText id: timestampText
timestamp: root.timestamp timestamp: root.timestamp
showFullTimestamp: root.showFullTimestamp
} }
Loader { Loader {

View File

@ -14,7 +14,7 @@ Item {
property string messageText: "" property string messageText: ""
signal editCancelled() signal editCancelled()
signal editCompleted(var newMsgText) signal editCompleted(string newMsgText)
implicitHeight: layout.implicitHeight implicitHeight: layout.implicitHeight
implicitWidth: layout.implicitWidth implicitWidth: layout.implicitWidth

View File

@ -1,5 +1,4 @@
import QtQuick 2.3 import QtQuick 2.14
import QtGraphicalEffects 1.13
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
@ -15,11 +14,9 @@ Loader {
height: 140 height: 140
} }
signal loaded() signal stickerLoaded()
signal clicked() signal clicked()
active: visible
sourceComponent: Rectangle { sourceComponent: Rectangle {
id: root id: root
@ -52,12 +49,11 @@ Loader {
anchors.fill: parent anchors.fill: parent
horizontalAlignment: Image.AlignHCenter horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter verticalAlignment: Image.AlignVCenter
cache: true
source: asset.name source: asset.name
onStatusChanged: { onStatusChanged: {
if (status === Image.Ready) { if (status === Image.Ready) {
statusSticker.loaded() statusSticker.stickerLoaded()
} }
} }
MouseArea { MouseArea {

View File

@ -80,10 +80,10 @@ Item {
? 200 ? 200
: chatText.implicitHeight : chatText.implicitHeight
width: parent.width
height: effectiveHeight + d.showMoreHeight / 2 height: effectiveHeight + d.showMoreHeight / 2
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: d.isQuote ? 8 : 0 anchors.leftMargin: d.isQuote ? 8 : 0
anchors.right: parent.right
opacity: !showMoreOpacityMask.active && !horizontalOpacityMask.active ? 1 : 0 opacity: !showMoreOpacityMask.active && !horizontalOpacityMask.active ? 1 : 0
text: d.text text: d.text
selectedTextColor: Theme.palette.directColor1 selectedTextColor: Theme.palette.directColor1

View File

@ -7,11 +7,12 @@ import StatusQ.Core.Theme 0.1
StatusBaseText { StatusBaseText {
id: root id: root
property double timestamp: 0 property double timestamp: 0
property bool showFullTimestamp
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
font.pixelSize: 10 font.pixelSize: 10
visible: !!text visible: !!text
text: LocaleUtils.formatTime(timestamp, Locale.ShortFormat) text: showFullTimestamp ? LocaleUtils.formatDateTime(timestamp) : LocaleUtils.formatTime(timestamp, Locale.ShortFormat)
StatusToolTip { StatusToolTip {
id: tooltip id: tooltip
visible: hhandler.hovered && !!text visible: hhandler.hovered && !!text
@ -19,6 +20,7 @@ StatusBaseText {
} }
HoverHandler { HoverHandler {
id: hhandler id: hhandler
enabled: !root.showFullTimestamp
onHoveredChanged: { onHoveredChanged: {
if(hhandler.hovered && timestamp) { if(hhandler.hovered && timestamp) {
tooltip.text = LocaleUtils.formatDateTime(timestamp) tooltip.text = LocaleUtils.formatDateTime(timestamp)

View File

@ -5,6 +5,7 @@ import QtQml.Models 2.14
import QtGraphicalEffects 1.14 import QtGraphicalEffects 1.14
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
@ -19,7 +20,6 @@ StatusDialog {
property var pinnedMessagesModel //this doesn't belong to the messageStore, it is a part of the ChatContentStore, but we didn't introduce it yet. property var pinnedMessagesModel //this doesn't belong to the messageStore, it is a part of the ChatContentStore, but we didn't introduce it yet.
property string messageToPin property string messageToPin
property string messageToUnpin property string messageToUnpin
property var emojiReactionsModel
width: 800 width: 800
height: 428 height: 428
@ -83,6 +83,8 @@ StatusDialog {
messageContentType: model.contentType messageContentType: model.contentType
pinnedMessage: model.pinned pinnedMessage: model.pinned
messagePinnedBy: model.pinnedBy messagePinnedBy: model.pinnedBy
sticker: model.sticker
stickerPack: model.stickerPack
linkUrls: model.links linkUrls: model.links
transactionParams: model.transactionParameters transactionParams: model.transactionParameters
quotedMessageText: model.quotedMessageParsedText quotedMessageText: model.quotedMessageParsedText
@ -105,12 +107,13 @@ StatusDialog {
// Additional params // Additional params
isInPinnedPopup: true isInPinnedPopup: true
disableHover: !!root.messageToPin
shouldRepeatHeader: true shouldRepeatHeader: true
} }
MouseArea { MouseArea {
id: mouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
z: 55 z: 55
onClicked: { onClicked: {
@ -124,9 +127,27 @@ StatusDialog {
} }
} }
StatusFlatRoundButton {
id: unpinButton
anchors.top: parent.top
anchors.topMargin: Style.current.bigPadding
anchors.right: parent.right
anchors.rightMargin: Style.current.bigPadding
z: mouseArea.z + 1
width: 32
height: 32
visible: !root.messageToPin && (hovered || mouseArea.containsMouse)
icon.name: "unpin"
tooltip.text: qsTr("Unpin")
color: hovered ? Theme.palette.primaryColor2 : Theme.palette.indirectColor1
onClicked: {
root.messageStore.unpinMessage(model.id)
}
}
StatusRadioButton { StatusRadioButton {
id: radio id: radio
visible: !!root.messageToPin visible: root.messageToPin
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Style.current.bigPadding anchors.rightMargin: Style.current.bigPadding
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -140,7 +161,6 @@ StatusDialog {
MessageContextMenuView { MessageContextMenuView {
id: msgContextMenu id: msgContextMenu
reactionModel: root.emojiReactionsModel
store: root.store store: root.store
pinnedPopup: true pinnedPopup: true
pinnedMessage: true pinnedMessage: true
@ -157,7 +177,7 @@ StatusDialog {
} }
} }
layer.enabled: root.visible layer.enabled: root.visible && !root.messageToPin
layer.effect: OpacityMask { layer.effect: OpacityMask {
maskSource: Rectangle { maskSource: Rectangle {
width: column.width width: column.width

View File

@ -174,8 +174,6 @@ Item {
Button { Button {
id: scrollDownButton id: scrollDownButton
readonly property int buttonPadding: 5
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Style.current.padding anchors.rightMargin: Style.current.padding

View File

@ -344,7 +344,6 @@ QtObject {
Component { Component {
id: pinnedMessagesPopup id: pinnedMessagesPopup
PinnedMessagesPopup { PinnedMessagesPopup {
emojiReactionsModel: rootStore.emojiReactionsModel
onClosed: destroy() onClosed: destroy()
} }
}, },

View File

@ -101,6 +101,7 @@ Control {
Layout.maximumHeight: 108 Layout.maximumHeight: 108
Layout.fillWidth: true Layout.fillWidth: true
contentHeight: bioText.height contentHeight: bioText.height
implicitHeight: contentHeight
ScrollBar.vertical: StatusScrollBar { ScrollBar.vertical: StatusScrollBar {
id: scrollBar id: scrollBar

View File

@ -3,7 +3,7 @@ import QtQuick 2.3
StatusChatImageLoader { StatusChatImageLoader {
property int chatVerticalPadding: 12 property int chatVerticalPadding: 12
property int chatHorizontalPadding: 12 property int chatHorizontalPadding: 12
property string imageSource: "data:image/jpeg;base64,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" property string imageSource
id: imageMessage id: imageMessage
verticalPadding: chatVerticalPadding verticalPadding: chatVerticalPadding

View File

@ -15,7 +15,6 @@ Item {
property bool isActiveChannel: false property bool isActiveChannel: false
property bool playing: Global.applicationWindow.active property bool playing: Global.applicationWindow.active
property bool isAnimated: !!source && source.toString().endsWith('.gif') property bool isAnimated: !!source && source.toString().endsWith('.gif')
property var container
property alias imageAlias: imageMessage property alias imageAlias: imageMessage
property bool allCornersRounded: false property bool allCornersRounded: false
property bool isOnline: true // TODO: mark as required when migrating to 5.15 or above property bool isOnline: true // TODO: mark as required when migrating to 5.15 or above

View File

@ -81,7 +81,6 @@ Rectangle {
imageWidth: 64 imageWidth: 64
imageSource: root.image imageSource: root.image
chatHorizontalPadding: 0 chatHorizontalPadding: 0
container: root.container
visible: root.contentType === Constants.messageContentType.imageType visible: root.contentType === Constants.messageContentType.imageType
playing: false playing: false
} }

View File

@ -1,6 +1,6 @@
import QtQuick 2.3 import QtQuick 2.14
import shared.panels 1.0
import shared.panels 1.0
import utils 1.0 import utils 1.0
Loader { Loader {
@ -9,7 +9,8 @@ Loader {
property string stickerData: "" property string stickerData: ""
property int imageHeight: 140 property int imageHeight: 140
property int imageWidth: 140 property int imageWidth: 140
signal loaded()
signal stickerLoaded()
id: root id: root
active: contentType === Constants.messageContentType.stickerType active: contentType === Constants.messageContentType.stickerType
@ -17,7 +18,7 @@ Loader {
sourceComponent: Component { sourceComponent: Component {
ImageLoader { ImageLoader {
color: root.color color: root.color
onLoaded: root.loaded() onLoaded: root.stickerLoaded()
width: imageWidth width: imageWidth
height: this.visible ? imageHeight : 0 height: this.visible ? imageHeight : 0

View File

@ -18,7 +18,6 @@ Column {
property var store property var store
property var messageStore property var messageStore
property var container
//receiving space separated url list //receiving space separated url list
property string links: "" property string links: ""
@ -132,7 +131,6 @@ Column {
property bool localAnimationEnabled: true property bool localAnimationEnabled: true
objectName: "LinksMessageView_unfurledImageComponent_linkImage" objectName: "LinksMessageView_unfurledImageComponent_linkImage"
anchors.centerIn: parent anchors.centerIn: parent
container: root.container
source: result.thumbnailUrl source: result.thumbnailUrl
imageWidth: 300 imageWidth: 300
isCurrentUser: root.isCurrentUser isCurrentUser: root.isCurrentUser
@ -214,7 +212,6 @@ Column {
StatusChatImageLoader { StatusChatImageLoader {
id: linkImage id: linkImage
objectName: "LinksMessageView_unfurledLinkComponent_linkImage" objectName: "LinksMessageView_unfurledLinkComponent_linkImage"
container: root.container
source: result.thumbnailUrl source: result.thumbnailUrl
visible: result.thumbnailUrl.length visible: result.thumbnailUrl.length
readonly property int previewWidth: parseInt(result.width) readonly property int previewWidth: parseInt(result.width)

View File

@ -100,7 +100,7 @@ Loader {
property bool hasMention: false property bool hasMention: false
property bool stickersLoaded: false property bool stickersLoaded: false
property string sticker: "Qme8vJtyrEHxABcSVGPF95PtozDgUyfr1xGjePmFdZgk9v" property string sticker
property int stickerPack: -1 property int stickerPack: -1
property bool isEmoji: messageContentType === Constants.messageContentType.emojiType property bool isEmoji: messageContentType === Constants.messageContentType.emojiType
@ -229,6 +229,15 @@ Loader {
} }
} }
function nextMessageHasHeader() {
if(!root.nextMessageAsJsonObj) {
return false
}
return root.senderId !== root.nextMessageAsJsonObj.senderId ||
d.getShouldRepeatHeader(root.nextMessageAsJsonObj.timeStamp, root.messageTimestamp, root.nextMessageAsJsonObj.outgoingStatus) ||
root.nextMessageAsJsonObj.responseToMessageWithId !== ""
}
function getShouldRepeatHeader(messageTimeStamp, prevMessageTimeStamp, messageOutgoingStatus) { function getShouldRepeatHeader(messageTimeStamp, prevMessageTimeStamp, messageOutgoingStatus) {
return ((messageTimeStamp - prevMessageTimeStamp) / 60 / 1000) > Constants.repeatHeaderInterval return ((messageTimeStamp - prevMessageTimeStamp) / 60 / 1000) > Constants.repeatHeaderInterval
|| d.getIsExpired(messageTimeStamp, messageOutgoingStatus) || d.getIsExpired(messageTimeStamp, messageOutgoingStatus)
@ -237,6 +246,36 @@ Loader {
function getIsExpired(messageTimeStamp, messageOutgoingStatus) { function getIsExpired(messageTimeStamp, messageOutgoingStatus) {
return (messageOutgoingStatus === Constants.sending && (Math.floor(messageTimeStamp) + 180000) < Date.now()) || messageOutgoingStatus === Constants.expired return (messageOutgoingStatus === Constants.sending && (Math.floor(messageTimeStamp) + 180000) < Date.now()) || messageOutgoingStatus === Constants.expired
} }
function convertContentType(value) {
switch (value) {
case Constants.messageContentType.messageType:
return StatusMessage.ContentType.Text;
case Constants.messageContentType.stickerType:
return StatusMessage.ContentType.Sticker;
case Constants.messageContentType.emojiType:
return StatusMessage.ContentType.Emoji;
case Constants.messageContentType.transactionType:
return StatusMessage.ContentType.Transaction;
case Constants.messageContentType.imageType:
return StatusMessage.ContentType.Image;
case Constants.messageContentType.audioType:
return StatusMessage.ContentType.Audio;
case Constants.messageContentType.communityInviteType:
return StatusMessage.ContentType.Invitation;
case Constants.messageContentType.discordMessageType:
return StatusMessage.ContentType.DiscordMessage;
case Constants.messageContentType.fetchMoreMessagesButton:
case Constants.messageContentType.chatIdentifier:
case Constants.messageContentType.unknownContentType:
case Constants.messageContentType.statusType:
case Constants.messageContentType.systemMessagePrivateGroupType:
case Constants.messageContentType.gapType:
case Constants.messageContentType.editType:
default:
return StatusMessage.ContentType.Unknown;
}
}
} }
@ -341,48 +380,16 @@ Loader {
Layout.bottomMargin: 16 Layout.bottomMargin: 16
messageTimestamp: root.messageTimestamp messageTimestamp: root.messageTimestamp
previousMessageTimestamp: root.prevMessageIndex === -1 ? 0 : root.prevMessageTimestamp previousMessageTimestamp: root.prevMessageIndex === -1 ? 0 : root.prevMessageTimestamp
visible: text !== "" visible: text !== "" && !root.isInPinnedPopup
} }
StatusMessage { StatusMessage {
id: delegate id: delegate
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 2 Layout.topMargin: showHeader && !root.isInPinnedPopup ? 2 : 0
Layout.bottomMargin: 2 Layout.bottomMargin: !root.isInPinnedPopup ? 2 : 0
function convertContentType(value) {
switch (value) {
case Constants.messageContentType.messageType:
return StatusMessage.ContentType.Text;
case Constants.messageContentType.stickerType:
return StatusMessage.ContentType.Sticker;
case Constants.messageContentType.emojiType:
return StatusMessage.ContentType.Emoji;
case Constants.messageContentType.transactionType:
return StatusMessage.ContentType.Transaction;
case Constants.messageContentType.imageType:
return StatusMessage.ContentType.Image;
case Constants.messageContentType.audioType:
return StatusMessage.ContentType.Audio;
case Constants.messageContentType.communityInviteType:
return StatusMessage.ContentType.Invitation;
case Constants.messageContentType.discordMessageType:
return StatusMessage.ContentType.DiscordMessage;
case Constants.messageContentType.fetchMoreMessagesButton:
case Constants.messageContentType.chatIdentifier:
case Constants.messageContentType.unknownContentType:
case Constants.messageContentType.statusType:
case Constants.messageContentType.systemMessagePrivateGroupType:
case Constants.messageContentType.gapType:
case Constants.messageContentType.editType:
default:
return StatusMessage.ContentType.Unknown;
}
}
readonly property int contentType: convertContentType(root.messageContentType)
readonly property bool isReply: root.responseToMessageWithId !== ""
readonly property int contentType: d.convertContentType(root.messageContentType)
property string originalMessageText: "" property string originalMessageText: ""
function editCancelledHandler() { function editCancelledHandler() {
@ -406,15 +413,6 @@ Loader {
root.messageStore.editMessage(root.messageId, root.messageContentType, interpretedMessage) root.messageStore.editMessage(root.messageId, root.messageContentType, interpretedMessage)
} }
function nextMessageHasHeader() {
if(!root.nextMessageAsJsonObj) {
return false
}
return root.senderId !== root.nextMessageAsJsonObj.senderId ||
d.getShouldRepeatHeader(root.nextMessageAsJsonObj.timeStamp, root.messageTimestamp, root.nextMessageAsJsonObj.outgoingStatus) ||
root.nextMessageAsJsonObj.responseToMessageWithId !== ""
}
pinnedMsgInfoText: root.isDiscordMessage ? qsTr("Pinned") : qsTr("Pinned by") pinnedMsgInfoText: root.isDiscordMessage ? qsTr("Pinned") : qsTr("Pinned by")
reactionIcons: [ reactionIcons: [
Style.svg("emojiReactions/heart"), Style.svg("emojiReactions/heart"),
@ -427,7 +425,7 @@ Loader {
timestamp: root.messageTimestamp timestamp: root.messageTimestamp
editMode: root.editModeOn editMode: root.editModeOn
isAReply: delegate.isReply isAReply: root.responseToMessageWithId !== ""
isEdited: root.isEdited isEdited: root.isEdited
hasMention: root.hasMention hasMention: root.hasMention
isPinned: root.pinnedMessage isPinned: root.pinnedMessage
@ -438,6 +436,7 @@ Loader {
const ensName = contact.ensVerified ? contact.name : "" const ensName = contact.ensVerified ? contact.name : ""
return ProfileUtils.displayName(contact.localNickname, ensName, contact.displayName, contact.alias) return ProfileUtils.displayName(contact.localNickname, ensName, contact.displayName, contact.alias)
} }
isInPinnedPopup: root.isInPinnedPopup
hasExpired: root.isExpired hasExpired: root.isExpired
isSending: root.isSending isSending: root.isSending
resendError: root.resendError resendError: root.resendError
@ -446,8 +445,8 @@ Loader {
showHeader: root.shouldRepeatHeader || dateGroupLabel.visible || isAReply || showHeader: root.shouldRepeatHeader || dateGroupLabel.visible || isAReply ||
(root.prevMessageContentType !== Constants.messageContentType.systemMessagePrivateGroupType && root.senderId !== root.prevMessageSenderId) (root.prevMessageContentType !== Constants.messageContentType.systemMessagePrivateGroupType && root.senderId !== root.prevMessageSenderId)
isActiveMessage: d.isMessageActive isActiveMessage: d.isMessageActive
topPadding: showHeader ? Style.current.halfPadding : 2 topPadding: showHeader ? Style.current.halfPadding : 0
bottomPadding: showHeader && nextMessageHasHeader() ? Style.current.halfPadding : 2 bottomPadding: showHeader && d.nextMessageHasHeader() ? Style.current.halfPadding : 2
disableHover: root.disableHover || disableHover: root.disableHover ||
(root.chatLogView && root.chatLogView.moving) || (root.chatLogView && root.chatLogView.moving) ||
(root.messageContextMenu && root.messageContextMenu.opened) || (root.messageContextMenu && root.messageContextMenu.opened) ||
@ -572,7 +571,7 @@ Loader {
return root.messageImage; return root.messageImage;
} }
if (root.isDiscordMessage && root.messageImage != "") { if (root.isDiscordMessage && root.messageImage != "") {
return root.messageImage return root.messageImage
} }
return ""; return "";
} }
@ -606,7 +605,7 @@ Loader {
} }
return root.quotedMessageText return root.quotedMessageText
} }
contentType: delegate.convertContentType(root.quotedMessageContentType) contentType: d.convertContentType(root.quotedMessageContentType)
messageContent: { messageContent: {
if (contentType !== StatusMessage.ContentType.Sticker && contentType !== StatusMessage.ContentType.Image) { if (contentType !== StatusMessage.ContentType.Sticker && contentType !== StatusMessage.ContentType.Image) {
return "" return ""
@ -683,7 +682,6 @@ Loader {
LinksMessageView { LinksMessageView {
id: linksMessageView id: linksMessageView
links: root.linkUrls links: root.linkUrls
container: root
messageStore: root.messageStore messageStore: root.messageStore
store: root.rootStore store: root.rootStore
isCurrentUser: root.amISender isCurrentUser: root.amISender