feat: implement redesign of message replies

Fixes #2303
This commit is contained in:
Jonathan Rainville 2021-04-23 11:49:05 -04:00 committed by Iuri Matias
parent 7def4b8630
commit 3a7c95967a
8 changed files with 146 additions and 45 deletions

View File

@ -225,6 +225,7 @@ QtObject:
of "timestamp": result = $(message.timestamp)
of "image": result = $(message.image)
of "contentType": result = $(message.contentType.int)
of "sticker": result = $(message.stickerHash.decodeContentHash())
else: result = ("")
proc add*(self: ChatMessageList, message: Message) =

View File

@ -44,14 +44,18 @@ Item {
property bool isMessage: isEmoji || isImage || isSticker || isText || isAudio
|| contentType === Constants.communityInviteType || contentType === Constants.transactionType
property bool isExpired: (outgoingStatus == "sending" && (Math.floor(timestamp) + 180000) < Date.now())
property bool isExpired: (outgoingStatus === "sending" && (Math.floor(timestamp) + 180000) < Date.now())
property bool isStatusUpdate: false
property int replyMessageIndex: chatsModel.messageList.getMessageIndex(responseTo);
property string repliedMessageAuthor: replyMessageIndex > -1 ? chatsModel.messageList.getMessageData(replyMessageIndex, "userName") : "";
property string repliedMessageAuthorPubkey: replyMessageIndex > -1 ? chatsModel.messageList.getMessageData(replyMessageIndex, "publicKey") : "";
property bool repliedMessageAuthorIsCurrentUser: replyMessageIndex > -1 ? repliedMessageAuthorPubkey === profileModel.profile.pubKey : "";
property string repliedMessageContent: replyMessageIndex > -1 ? chatsModel.messageList.getMessageData(replyMessageIndex, "message") : "";
property int repliedMessageType: replyMessageIndex > -1 ? parseInt(chatsModel.messageList.getMessageData(replyMessageIndex, "contentType")) : 0;
property string repliedMessageImage: replyMessageIndex > -1 ? chatsModel.messageList.getMessageData(replyMessageIndex, "image") : "";
property string repliedMessageUserIdenticon: replyMessageIndex > -1 ? chatsModel.messageList.getMessageData(replyMessageIndex, "identicon") : "";
property string repliedMessageUserImage: replyMessageIndex > -1 ? appMain.getProfileImage(repliedMessageAuthorPubkey, repliedMessageAuthorIsCurrentUser , false) || "" : "";
property var imageClick: function () {}
property var scrollToBottom: function () {}
@ -106,6 +110,11 @@ Item {
if (img) {
profileImageSource = img
}
} else if (replyMessageIndex > -1 && pubkey === repliedMessageAuthorPubkey) {
const imgReply = appMain.getProfileImage(repliedMessageAuthorPubkey, repliedMessageAuthorIsCurrentUser, false)
if (imgReply) {
repliedMessageUserImage = imgReply
}
}
}
}

View File

@ -1,4 +1,6 @@
import QtQuick 2.14
import QtQuick.Shapes 1.13
import QtGraphicalEffects 1.13
import "../../../../../shared"
import "../../../../../imports"
@ -12,6 +14,8 @@ Loader {
property var container
property int chatHorizontalPadding
property int nameMargin: 6
id: root
active: responseTo != "" && replyMessageIndex > -1
@ -22,7 +26,18 @@ Loader {
id: chatReply
// childrenRect.height shows a binding loop for some reason, so we use heights instead
height: lblReplyAuthor.height + ((repliedMessageType === Constants.imageType ? imgReplyImage.height : lblReplyMessage.height) + 5 + 8)
height: {
const h = userImage.height + 2
if (repliedMessageType === Constants.imageType) {
return h + imgReplyImage.height
}
if (repliedMessageType === Constants.stickerType) {
return h + stickerLoader.height
}
return h + lblReplyMessage.height
}
width: parent.width
clip: true
TextMetrics {
id: txtAuthorMetrics
@ -30,35 +45,102 @@ Loader {
text: lblReplyAuthor.text
}
Shape {
id: replyCorner
anchors.left: parent.left
anchors.leftMargin: 20 - 1
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
width: 20
height: parent.height - anchors.topMargin
asynchronous: true
antialiasing: true
ShapePath {
id: capTest
strokeColor: Utils.setColorAlpha(root.elementsColor, 0.4)
strokeWidth: 3
fillColor: "transparent"
capStyle: ShapePath.RoundCap
joinStyle: ShapePath.RoundJoin
startX: 20
startY: 0
PathLine { x: 10; y: 0 }
PathArc {
x: 0; y: 10
radiusX: 13
radiusY: 13
direction: PathArc.Counterclockwise
}
PathLine { x: 0; y: chatReply.height - replyCorner.anchors.topMargin }
}
}
UserImage {
id: userImage
imageHeight: 20
imageWidth: 20
active: true
anchors.left: replyCorner.right
anchors.leftMargin: Style.current.halfPadding
identiconImageSource: repliedMessageUserIdenticon
isReplyImage: true
profileImage: repliedMessageUserImage
}
StyledTextEdit {
id: lblReplyAuthor
text: "↳" + repliedMessageAuthor
text: repliedMessageAuthor
color: root.elementsColor
readOnly: true
font.pixelSize: Style.current.secondaryTextFontSize
selectByMouse: true
wrapMode: Text.Wrap
anchors.left: parent.left
anchors.right: parent.right
font.weight: Font.Medium
anchors.verticalCenter: userImage.verticalCenter
anchors.left: userImage.right
anchors.leftMargin: 5
}
ChatImage {
id: imgReplyImage
visible: repliedMessageType == Constants.imageType
visible: repliedMessageType === Constants.imageType
imageWidth: 50
imageSource: repliedMessageImage
anchors.top: lblReplyAuthor.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.topMargin: nameMargin
anchors.left: userImage.left
chatHorizontalPadding: 0
container: root.container
allCornersRounded: true
}
Loader {
id: stickerLoader
active: repliedMessageType === Constants.stickerType
anchors.top: lblReplyAuthor.bottom
anchors.topMargin: nameMargin
anchors.left: userImage.left
sourceComponent: Component {
Sticker {
id: stickerId
imageHeight: 56
imageWidth: 56
stickerData: chatsModel.messageList.getMessageData(replyMessageIndex, "sticker")
contentType: repliedMessageType
container: root.container
}
}
}
StyledTextEdit {
id: lblReplyMessage
visible: repliedMessageType != Constants.imageType
visible: repliedMessageType !== Constants.imageType && repliedMessageType !== Constants.stickerType
Component.onCompleted: textFieldImplicitWidth = implicitWidth
anchors.top: lblReplyAuthor.bottom
anchors.topMargin: 5
anchors.topMargin: nameMargin
text: `<style type="text/css">`+
`a {`+
`color: ${isCurrentUser && !appSettings.useCompactMode ? Style.current.white : Style.current.textColor};`+
@ -76,21 +158,13 @@ Loader {
color: root.elementsColor
readOnly: true
selectByMouse: true
wrapMode: Text.Wrap
font.pixelSize: Style.current.secondaryTextFontSize
anchors.left: parent.left
anchors.left: userImage.left
width: root.longReply ? parent.width : implicitWidth
height: 18
clip: true
z: 51
}
Separator {
anchors.top: repliedMessageType == Constants.imageType ? imgReplyImage.bottom : lblReplyMessage.bottom
anchors.topMargin: Style.current.halfPadding
anchors.left: lblReplyMessage.left
anchors.right: lblReplyMessage.right
anchors.rightMargin: root.chatHorizontalPadding
color: root.elementsColor
}
}
}
}

View File

@ -14,7 +14,7 @@ Item {
property bool isCurrentUser: false
property bool isHovered: typeof hoveredMessage !== "undefined" && hoveredMessage === messageId
property bool isMessageActive: typeof activeMessage !== "undefined" && activeMessage === messageId
property bool headerRepeatCondition: (authorCurrentMsg !== authorPrevMsg || shouldRepeatHeader || dateGroupLbl.visible)
property bool headerRepeatCondition: (authorCurrentMsg !== authorPrevMsg || shouldRepeatHeader || dateGroupLbl.visible || chatReply.active)
id: root
@ -71,12 +71,22 @@ Item {
color: root.isHovered || isMessageActive ? (hasMention ? Style.current.mentionMessageHoverColor : Style.current.backgroundHoverLight) :
(hasMention ? Style.current.mentionMessageColor : Style.current.transparent)
ChatReply {
id: chatReply
anchors.left: chatImage.left
longReply: active && textFieldImplicitWidth > width
container: root.container
chatHorizontalPadding: root.chatHorizontalPadding
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
}
UserImage {
id: chatImage
active: isMessage && headerRepeatCondition
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.top: parent.top
anchors.top: chatReply.active ? chatReply.bottom : parent.top
anchors.topMargin: Style.current.smallPadding
}
@ -100,24 +110,17 @@ Item {
Item {
id: messageContent
height: childrenRect.height + (isEmoji ? 2 : 0)
anchors.top: chatName.visible ? chatName.bottom : parent.top
anchors.top: chatName.visible ? chatName.bottom :
chatReply.active ? chatReply.bottom : parent.top
anchors.left: chatImage.right
anchors.leftMargin: root.chatHorizontalPadding
anchors.right: parent.right
anchors.rightMargin: root.chatHorizontalPadding
ChatReply {
id: chatReply
longReply: active && textFieldImplicitWidth > width
container: root.container
chatHorizontalPadding: root.chatHorizontalPadding
width: parent.width
}
ChatText {
readonly property int leftPadding: chatImage.anchors.leftMargin + chatImage.width + root.chatHorizontalPadding
id: chatText
anchors.top: chatReply.active ? chatReply.bottom : parent.top
anchors.top: parent.top
anchors.topMargin: isEmoji ? 2 : 0
anchors.left: parent.left
anchors.right: parent.right
@ -130,7 +133,7 @@ Item {
Loader {
id: chatImageContent
active: isImage
anchors.top: chatReply.bottom
anchors.top: parent.top
z: 51
sourceComponent: Component {

View File

@ -13,6 +13,7 @@ Item {
signal clicked(var image)
property var container
property alias imageAlias: imageMessage
property bool allCornersRounded: false
id: imageContainer
width: loadingImage.visible ? loadingImage.width : imageMessage.width
@ -88,7 +89,7 @@ Item {
width: 32
height: 32
radius: 4
visible: !imageContainer.isCurrentUser
visible: !imageContainer.isCurrentUser && !allCornersRounded
}
Rectangle {
anchors.bottom: parent.bottom
@ -96,7 +97,7 @@ Item {
width: 32
height: 32
radius: 4
visible: imageContainer.isCurrentUser
visible: imageContainer.isCurrentUser && !allCornersRounded
}
}
}

View File

@ -6,6 +6,9 @@ Loader {
property color color
property var container
property int contentType: -1
property string stickerData: sticker
property int imageHeight: 140
property int imageWidth: 140
id: root
active: contentType === Constants.stickerType
@ -15,9 +18,9 @@ Loader {
color: root.color
onLoaded: scrollToBottom(true, root.container)
width: 140
height: this.visible ? 140 : 0
source: this.visible ? ("https://ipfs.infura.io/ipfs/" + sticker) : ""
width: imageWidth
height: this.visible ? imageHeight : 0
source: this.visible ? ("https://ipfs.infura.io/ipfs/" + stickerData) : ""
}
}
}

View File

@ -3,6 +3,13 @@ import "../../../../../shared"
import "../../../../../imports"
Loader {
property int imageHeight: 36
property int imageWidth: 36
property string identiconImageSource: identicon
property string profileImage: profileImageSource
property bool isReplyImage: false
id: root
active: isMessage
height: active ? item.height : 0
@ -14,16 +21,16 @@ Loader {
RoundedImage {
id: identiconImage
width: 36
height: 36
width: root.imageWidth
height: root.imageHeight
border.width: 1
border.color: Style.current.border
source: {
if (profileImageSource) {
return profileImageSource
if (root.profileImage) {
return root.profileImage
}
identiconImage.showLoadingIndicator = false
return !isCurrentUser ? identicon : profileModel.profile.identicon
return !isCurrentUser || isReplyImage ? root.identiconImageSource : profileModel.profile.identicon
}
smooth: false
antialiasing: true

View File

@ -0,0 +1,3 @@
<svg width="22" height="27" viewBox="0 0 22 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.47619 26L1.15528 9.15236C1.07001 4.67527 4.67594 1 9.15383 1H21" stroke="#939BA1" stroke-opacity="0.4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 284 B