fix(StatusMessageReply): Fixed reply text styling and behavior

This commit is contained in:
Igor Sirotin 2022-11-08 20:34:41 +03:00 committed by r4bbit.eth
parent 263b1c01c6
commit a69b3b5928
6 changed files with 161 additions and 109 deletions

View File

@ -80,6 +80,7 @@ Rectangle {
signal profilePictureClicked(var sender, var mouse)
signal senderNameClicked(var sender, var mouse)
signal replyProfileClicked(var sender, var mouse)
signal replyMessageClicked(var mouse)
signal addReactionClicked(var sender, var mouse)
signal toggleReactionClicked(int emojiId)
@ -219,11 +220,9 @@ Rectangle {
sourceComponent: StatusMessageReply {
replyDetails: root.replyDetails
profileClickable: root.profileClickable
onReplyProfileClicked: root.replyProfileClicked(sender, mouse)
audioMessageInfoText: root.audioMessageInfoText
onLinkActivated: {
root.linkActivated(link);
}
onReplyProfileClicked: root.replyProfileClicked(sender, mouse)
onMessageClicked: root.replyMessageClicked(mouse)
}
}

View File

@ -5,6 +5,7 @@ import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Components 0.1
Item {
@ -15,14 +16,18 @@ Item {
property bool profileClickable: true
signal replyProfileClicked(var sender, var mouse)
signal linkActivated(string link)
signal messageClicked(var mouse)
implicitHeight: layout.implicitHeight
implicitWidth: layout.implicitWidth
RowLayout {
id: layout
anchors.fill: parent
anchors.rightMargin: 16
spacing: 8
Shape {
id: replyCorner
Layout.alignment: Qt.AlignTop
@ -32,6 +37,7 @@ Item {
Layout.preferredHeight: messageLayout.height - replyCorner.Layout.topMargin
asynchronous: true
antialiasing: true
ShapePath {
strokeColor: Qt.hsla(Theme.palette.baseColor1.hslHue, Theme.palette.baseColor1.hslSaturation, Theme.palette.baseColor1.hslLightness, 0.4)
strokeWidth: 3
@ -50,86 +56,103 @@ Item {
PathLine { x: 0; y: messageLayout.height}
}
}
ColumnLayout {
id: messageLayout
Item {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
Layout.topMargin: 4
RowLayout {
StatusSmartIdenticon {
id: profileImage
Layout.alignment: Qt.AlignTop
name: replyDetails.sender.displayName
asset: replyDetails.sender.profileImage.assetSettings
ringSettings: replyDetails.sender.profileImage.ringSettings
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
enabled: root.profileClickable
onClicked: replyProfileClicked(this, mouse)
implicitHeight: messageLayout.implicitHeight
implicitWidth: messageLayout.implicitWidth
ColumnLayout {
id: messageLayout
anchors.fill: parent
RowLayout {
StatusSmartIdenticon {
id: profileImage
Layout.alignment: Qt.AlignTop
name: replyDetails.sender.displayName
asset: replyDetails.sender.profileImage.assetSettings
ringSettings: replyDetails.sender.profileImage.ringSettings
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
enabled: root.profileClickable
onClicked: replyProfileClicked(this, mouse)
}
}
TextEdit {
Layout.alignment: Qt.AlignVCenter
color: Theme.palette.baseColor1
selectionColor: Theme.palette.primaryColor3
selectedTextColor: Theme.palette.directColor1
font.pixelSize: Theme.secondaryTextFontSize
font.weight: Font.Medium
selectByMouse: true
readOnly: true
text: replyDetails.amISender ? qsTr("You") : replyDetails.sender.displayName
}
}
TextEdit {
Layout.alignment: Qt.AlignVCenter
color: Theme.palette.baseColor1
selectionColor: Theme.palette.primaryColor3
selectedTextColor: Theme.palette.directColor1
font.pixelSize: Theme.secondaryTextFontSize
font.weight: Font.Medium
selectByMouse: true
readOnly: true
text: replyDetails.amISender ? qsTr("You") : replyDetails.sender.displayName
StatusTextMessage {
Layout.fillWidth: true
textField.font.pixelSize: Theme.secondaryTextFontSize
textField.color: Theme.palette.baseColor1
clip: true
visible: !!replyDetails.messageText && replyDetails.contentType !== StatusMessage.ContentType.Sticker
allowShowMore: false
stripHtmlTags: true
convertToSingleLine: true
messageDetails: root.replyDetails
}
StatusImageMessage {
Layout.fillWidth: true
Layout.preferredHeight: imageAlias.paintedHeight
imageWidth: 56
source: replyDetails.contentType === StatusMessage.ContentType.Image ? replyDetails.messageContent : ""
visible: source
shapeType: StatusImageMessage.ShapeType.ROUNDED
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: 48
Layout.alignment: Qt.AlignLeft
visible: replyDetails.contentType === StatusMessage.ContentType.Sticker
StatusSticker {
asset.width: 48
asset.height: 48
asset.name: replyDetails.messageContent
asset.isImage: true
}
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: 22
visible: replyDetails.contentType === StatusMessage.ContentType.Audio
StatusAudioMessage {
id: audioMessage
anchors.left: parent.left
width: 125
height: 22
isPreview: true
audioSource: replyDetails.messageContent
audioMessageInfoText: root.audioMessageInfoText
}
}
}
StatusTextMessage {
Layout.fillWidth: true
textField.font.pixelSize: Theme.secondaryTextFontSize
textField.color: Theme.palette.baseColor1
convertToSingleLine: true
clip: true
visible: !!replyDetails.messageText && replyDetails.contentType !== StatusMessage.ContentType.Sticker
allowShowMore: false
messageDetails: root.replyDetails
onLinkActivated: {
root.linkActivated(link);
}
}
StatusImageMessage {
Layout.fillWidth: true
Layout.preferredHeight: imageAlias.paintedHeight
imageWidth: 56
source: replyDetails.contentType === StatusMessage.ContentType.Image ? replyDetails.messageContent : ""
visible: source
shapeType: StatusImageMessage.ShapeType.ROUNDED
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: 48
Layout.alignment: Qt.AlignLeft
visible: replyDetails.contentType === StatusMessage.ContentType.Sticker
StatusSticker {
asset.width: 48
asset.height: 48
asset.name: replyDetails.messageContent
asset.isImage: true
}
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: 22
visible: replyDetails.contentType === StatusMessage.ContentType.Audio
StatusAudioMessage {
id: audioMessage
anchors.left: parent.left
width: 125
height: 22
isPreview: true
audioSource: replyDetails.messageContent
audioMessageInfoText: root.audioMessageInfoText
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.messageClicked(mouse)
}
}
}
}
}

View File

@ -12,6 +12,7 @@ Item {
property StatusMessageDetails messageDetails: StatusMessageDetails {}
property bool isEdited: false
property bool convertToSingleLine: false
property bool stripHtmlTags: false
property alias textField: chatText
property bool allowShowMore: true
@ -25,16 +26,16 @@ Item {
id: d
property bool readMore: false
readonly property bool veryLongChatText: chatText.length > 1000
readonly property int showMoreHeight: showMoreLoader.visible ? showMoreLoader.height : 0
readonly property int showMoreHeight: showMoreButtonLoader.visible ? showMoreButtonLoader.height : 0
readonly property string text: {
if (root.messageDetails.contentType === StatusMessage.ContentType.Sticker)
return "";
const formattedMessage = Utils.linkifyAndXSS(root.messageDetails.messageText);
if (root.messageDetails.contentType === StatusMessage.ContentType.Emoji)
return Emoji.parse(formattedMessage, Emoji.size.middle, Emoji.format.png);
return Emoji.parse(root.messageDetails.messageText, Emoji.size.middle, Emoji.format.png);
let formattedMessage = Utils.linkifyAndXSS(root.messageDetails.messageText);
if (root.isEdited) {
const index = formattedMessage.endsWith("code>") ? formattedMessage.length : formattedMessage.length - 4;
@ -44,12 +45,20 @@ Item {
return Utils.getMessageWithStyle(Emoji.parse(editedMessage), chatText.hoveredLink)
}
if (root.convertToSingleLine) {
const singleLineMessage = Utils.convertToSingleLine(formattedMessage)
return Utils.getMessageWithStyle(Emoji.parse(singleLineMessage), chatText.hoveredLink)
}
if (root.convertToSingleLine)
formattedMessage = Utils.convertToSingleLine(formattedMessage)
return Utils.getMessageWithStyle(Emoji.parse(formattedMessage), chatText.hoveredLink)
if (root.stripHtmlTags)
formattedMessage = Utils.stripHtmlTags(formattedMessage)
// add emoji tags even after html striped
formattedMessage = Emoji.parse(formattedMessage)
if (root.stripHtmlTags)
// short return not to add styling when no html
return formattedMessage
return Utils.getMessageWithStyle(formattedMessage, chatText.hoveredLink)
}
}
@ -63,7 +72,7 @@ Item {
width: parent.width
height: effectiveHeight + d.showMoreHeight / 2
opacity: opMask.active ? 0 : 1
opacity: !showMoreOpacityMask.active && !horizontalOpacityMask.active ? 1 : 0
clip: true
text: d.text
selectedTextColor: Theme.palette.directColor1
@ -72,7 +81,7 @@ Item {
font.family: Theme.palette.baseFont.name
font.pixelSize: Theme.primaryTextFontSize
textFormat: Text.RichText
wrapMode: Text.Wrap
wrapMode: root.convertToSingleLine ? Text.NoWrap : Text.Wrap
readOnly: true
selectByMouse: true
onLinkActivated: {
@ -84,10 +93,40 @@ Item {
}
}
// Horizontal crop mask
Loader {
id: mask
id: horizontalClipMask
anchors.fill: chatText
active: showMoreLoader.active && !d.readMore
active: horizontalOpacityMask.active
visible: false
sourceComponent: LinearGradient {
start: Qt.point(0, 0)
end: Qt.point(chatText.width, 0)
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: 0.85; color: "white" }
GradientStop { position: 1; color: "transparent" }
}
}
}
Loader {
id: horizontalOpacityMask
active: root.convertToSingleLine && chatText.implicitWidth > chatText.width
anchors.fill: chatText
sourceComponent: OpacityMask {
source: chatText
maskSource: horizontalClipMask
}
}
// Vertical "show more" mask
Loader {
id: showMoreMaskGradient
anchors.fill: chatText
active: showMoreButtonLoader.active && !d.readMore
visible: false
sourceComponent: LinearGradient {
start: Qt.point(0, 0)
@ -101,17 +140,17 @@ Item {
}
Loader {
id: opMask
active: showMoreLoader.active && !d.readMore
id: showMoreOpacityMask
active: showMoreButtonLoader.active && !d.readMore
anchors.fill: chatText
sourceComponent: OpacityMask {
source: chatText
maskSource: mask
maskSource: showMoreMaskGradient
}
}
Loader {
id: showMoreLoader
id: showMoreButtonLoader
active: root.allowShowMore && d.veryLongChatText
visible: active
anchors.verticalCenter: chatText.bottom

View File

@ -222,6 +222,10 @@ QtObject {
return text.replace(/<br\s*\/>/gm, " ")
}
function stripHtmlTags(text) {
return text.replace(/<[^>]*>?/gm, '')
}
function delegateModelSort(srcGroup, dstGroup, lessThan) {
const insertPosition = (lessThan, item) => {
let lower = 0

View File

@ -539,6 +539,10 @@ Loader {
root.messageClickHandler(sender, Qt.point(mouse.x, mouse.y), true, false, false, null, false, false, true);
}
onReplyMessageClicked: {
root.messageStore.messageModule.jumpToMessage(root.responseToMessageWithId)
}
onSenderNameClicked: {
d.setMessageActive(root.messageId, true);
root.messageClickHandler(sender, Qt.point(mouse.x, mouse.y), true);

View File

@ -58,23 +58,6 @@ QtObject {
return Style.current.accountColors[colorIndex]
}
function getReplyMessageStyle(msg, isCurrentUser) {
return `<style type="text/css">`+
`a {`+
`color: ${Style.current.textColor};`+
`}`+
`a.mention {`+
`color: ${isCurrentUser ? Style.current.mentionColor : Style.current.turquoise};`+
`background-color: ${Style.current.mentionBgColor};` +
`}`+
`</style>`+
`</head>`+
`<body>`+
`${msg}`+
`</body>`+
`</html>`
}
function getLinkStyle(link, hoveredLink, textColor) {
return `<style type="text/css">` +
`a {` +