status-desktop/ui/imports/shared/views/chat/NormalMessageView.qml

389 lines
15 KiB
QML
Raw Normal View History

import QtQuick 2.13
import utils 1.0
import shared 1.0
import shared.status 1.0
import shared.views.chat 1.0
import shared.panels.chat 1.0
import shared.controls.chat 1.0
Item {
id: root
anchors.top: parent.top
anchors.topMargin: authorCurrentMsg !== authorPrevMsg ? Style.current.smallPadding : 0
2020-07-23 16:11:48 +00:00
height: childrenRect.height + this.anchors.topMargin + (dateGroupLbl.visible ? dateGroupLbl.height : 0)
width: parent.width
property var store
property var messageStore
property string linkUrls: ""
property bool isCurrentUser: false
property bool isExpired: false
property bool timeout: false
property int contentType: 2
property var container
property bool headerRepeatCondition: (authorCurrentMsg !== authorPrevMsg
|| shouldRepeatHeader || dateGroupLbl.visible)
DateGroup {
id: dateGroupLbl
previousMessageIndex: prevMessageIndex
previousMessageTimestamp: prevMsgTimestamp
messageTimestamp: timestamp
isActivityCenterMessage: activityCenterMessage
}
UserImage {
id: chatImage
active: root.store.chatsModelInst.channelView.activeChannel.chatType !== Constants.chatTypeOneToOne && isMessage && headerRepeatCondition && !root.isCurrentUser
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top
anchors.topMargin: 20
// isCurrentUser: root.messageStore.isCurrentUser
// profileImage: root.messageStore.profileImageSource
// isMessage: root.messageStore.isMessage
// identiconImageSource: root.messageStore.identicon
onClickMessage: {
root.parent.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker, isReply);
}
}
UsernameLabel {
id: chatName
visible: root.store.chatsModelInst.channelView.activeChannel.chatType !== Constants.chatTypeOneToOne && isMessage && headerRepeatCondition && !root.isCurrentUser
anchors.leftMargin: 20
anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top
anchors.topMargin: 0
anchors.left: chatImage.right
// isCurrentUser: root.messageStore.isCurrentUser
// userName: root.messageStore.userName
// localName: root.messageStore.localName
// displayUserName: root.messageStore.displayUserName
onClickMessage: {
root.parent.clickMessage(true, false, false, null, false, false, false);
}
}
Rectangle {
readonly property int defaultMessageWidth: 400
readonly property int defaultMaxMessageChars: 54
readonly property int messageWidth: Math.max(defaultMessageWidth, parent.width / 1.4)
readonly property int maxMessageChars: (defaultMaxMessageChars * messageWidth) / defaultMessageWidth
property int chatVerticalPadding: isImage ? 4 : 6
property int chatHorizontalPadding: isImage ? 0 : 12
property bool longReply: chatReply.active && repliedMessageContent.length > maxMessageChars
property bool longChatText: root.store.chatsModelInst.plainText(root.messageStore.message).split('\n').some(function (messagePart) {
return messagePart.length > maxMessageChars
})
id: chatBox
color: {
if (isSticker) {
return Style.current.background
}
if (isImage) {
return "transparent"
}
return isCurrentUser ? Style.current.primary : Style.current.secondaryBackground
}
border.color: isSticker ? Style.current.border : Style.current.transparent
border.width: 1
height: {
let h = (3 * chatVerticalPadding)
switch(contentType){
case Constants.stickerType:
h += stickerId.height;
break;
2020-07-30 16:07:41 +00:00
case Constants.audioType:
h += audioPlayerLoader.height;
break;
default:
2020-10-06 15:07:12 +00:00
if (!chatImageContent.active && !chatReply.active) {
h -= chatVerticalPadding
}
h += chatText.visible ? chatText.height : 0;
2020-10-06 15:07:12 +00:00
h += chatImageContent.active ? chatImageContent.height: 0;
h += chatReply.active ? chatReply.height : 0;
}
return h;
}
width: {
switch(contentType) {
case Constants.stickerType:
return stickerId.width + (2 * chatBox.chatHorizontalPadding);
case Constants.imageType:
return chatImageContent.width
default:
if (longChatText || longReply) {
return messageWidth;
}
let baseWidth = chatText.width;
if (chatReply.visible && chatText.width < chatReply.textFieldWidth) {
baseWidth = chatReply.textFieldWidth
}
if (chatReply.visible && chatText.width < chatReply.authorWidth) {
if(chatReply.authorWidth > baseWidth){
baseWidth = chatReply.authorWidth + 20
}
}
return baseWidth + 2 * chatHorizontalPadding
}
}
radius: 16
anchors.left: !root.isCurrentUser ? chatImage.right : undefined
anchors.leftMargin: !root.isCurrentUser ? 8 : 0
anchors.right: !root.isCurrentUser ? undefined : parent.right
anchors.rightMargin: !root.isCurrentUser ? 0 : Style.current.padding
anchors.top: headerRepeatCondition && !root.isCurrentUser ? chatImage.top : (dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top)
2020-08-14 12:08:09 +00:00
anchors.topMargin: 0
visible: isMessage && contentType !== Constants.transactionType
ChatReplyPanel {
id: chatReply
longReply: chatBox.longReply
anchors.top: parent.top
anchors.topMargin: chatReply.visible ? chatBox.chatVerticalPadding : 0
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.right: parent.right
anchors.rightMargin: chatBox.chatHorizontalPadding
container: root.container
chatHorizontalPadding: chatBox.chatHorizontalPadding
stickerData: root.store.chatsModelInst.messageView.messageList.getMessageData(replyMessageIndex, "sticker")
active: responseTo !== "" && replyMessageIndex > -1 && !activityCenterMessage
// To-Do move to store later?
// isCurrentUser: root.messageStore.isCurrentUser
// repliedMessageType: root.messageStore.repliedMessageType
// repliedMessageImage: root.messageStore.repliedMessageImage
// repliedMessageUserIdenticon: root.messageStore.repliedMessageUserIdenticon
// repliedMessageIsEdited: root.messageStore.repliedMessageIsEdited
// repliedMessageUserImage: root.messageStore.repliedMessageUserImage
// repliedMessageAuthor: root.messageStore.repliedMessageAuthor
// repliedMessageContent: root.messageStore.repliedMessageContent
// responseTo: root.messageStore.responseTo
// onScrollToBottom: {
// root.messageStore.scrollToBottom(isit, container);
// }
onClickMessage: {
root.parent.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker, isReply);
}
}
Connections {
target: root.store.chatsModelInst.messageView
onMessageEdited: {
if(chatReply.item)
chatReply.item.messageEdited(editedMessageId, editedMessageContent)
}
}
ChatTextView {
id: chatText
longChatText: chatBox.longChatText
anchors.top: chatReply.bottom
2020-10-06 15:07:12 +00:00
anchors.topMargin: chatReply.active ? chatBox.chatVerticalPadding : 0
anchors.left: parent.left
anchors.leftMargin: chatBox.chatHorizontalPadding
anchors.right: chatBox.longChatText ? parent.right : undefined
anchors.rightMargin: chatBox.longChatText ? chatBox.chatHorizontalPadding : 0
store: root.store
messageStore: root.store.messageStore
textField.color: !root.isCurrentUser ? Style.current.textColor : Style.current.currentUserTextColor
Connections {
target: localAccountSensitiveSettings.useCompactMode ? null : chatBox
onLongChatTextChanged: {
chatText.setWidths()
}
}
onLinkActivated: {
if (root.messageStore.activityCenterMessage) {
clickMessage(false, root.messageStore.isSticker, false)
}
}
}
2020-07-20 17:34:20 +00:00
Loader {
id: chatImageContent
active: root.messageStore.isImage && !!image
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
anchors.left: parent.left
anchors.leftMargin: chatBox.chatHorizontalPadding
z: 51
sourceComponent: Component {
Item {
width: chatImageComponent.width + 2 * chatBox.chatHorizontalPadding
height: chatImageComponent.height
StatusChatImage {
id: chatImageComponent
imageSource: image
imageWidth: 250
isCurrentUser: root.isCurrentUser
onClicked: imageClick(image)
container: root.container
}
}
2020-07-20 17:34:20 +00:00
}
}
2020-07-30 16:07:41 +00:00
Loader {
id: audioPlayerLoader
active: root.messageStore.isAudio
2020-07-30 16:07:41 +00:00
sourceComponent: audioPlayer
anchors.verticalCenter: parent.verticalCenter
}
Component {
id: audioPlayer
AudioPlayerPanel {
2020-07-30 16:07:41 +00:00
audioSource: audio
}
}
StatusSticker {
id: stickerId
anchors.left: parent.left
anchors.leftMargin: chatBox.chatHorizontalPadding
anchors.top: parent.top
anchors.topMargin: chatBox.chatVerticalPadding
color: Style.current.transparent
contentType: root.contentType
stickerData: root.messageStore.sticker
onLoaded: {
root.messageStore.scrollToBottom(true, root.container)
}
}
MessageMouseArea {
anchors.fill: parent
enabled: !chatText.linkHovered
isActivityCenterMessage: root.messageStore.activityCenterMessage
onClickMessage: {
root.parent.clickMessage(isProfileClick, root.messageStore.isSticker, root.messageStore.isImage)
}
onSetMessageActive: {
root.messageStore.setMessageActive(root.messageStore.messageId, active);
}
}
RectangleCorner {
// TODO find a way to show the corner for stickers since they have a border
visible: root.messageStore.isMessage
isCurrentUser: root.isCurrentUser
}
}
Loader {
id: transactionBubbleLoader
active: contentType === Constants.transactionType
anchors.left: !isCurrentUser ? chatImage.right : undefined
anchors.leftMargin: isCurrentUser ? 0 : Style.current.halfPadding
anchors.right: isCurrentUser ? parent.right : undefined
anchors.rightMargin: Style.current.padding
sourceComponent: Component {
TransactionBubbleView {
store: root.store
}
}
}
Rectangle {
id: dateTimeBackground
visible: isImage
height: visible ? chatTime.height + Style.current.halfPadding : 0
width: chatTime.width + 2 * chatTime.anchors.rightMargin +
(retry.visible ? retry.width + retry.anchors.rightMargin : sentMessage.width + sentMessage.anchors.rightMargin)
color: Utils.setColorAlpha(Style.current.black, 0.66)
radius: Style.current.radius
anchors.bottom: chatBox.bottom
anchors.bottomMargin: Style.current.halfPadding
anchors.right: chatBox.right
anchors.rightMargin: 6
}
ChatTimePanel {
id: chatTime
visible: root.messageStore.isMessage && !emojiReactionLoader.active
anchors.top: isImage ? undefined : (linksLoader.active ? linksLoader.bottom : chatBox.bottom)
anchors.topMargin: isImage ? 0 : 4
anchors.verticalCenter: isImage ? dateTimeBackground.verticalCenter : undefined
anchors.right: isImage ? dateTimeBackground.right : (linksLoader.active ? linksLoader.right : chatBox.right)
anchors.rightMargin: isImage ? 6 : (root.isCurrentUser ? 5 : Style.current.padding)
//timestamp: root.messageStore.timestamp
}
SentMessage {
id: sentMessage
visible: root.isCurrentUser && !root.messageStore.timeout && !root.messageStore.isExpired
&& root.messageStore.isMessage && root.messageStore.outgoingStatus === "sent"
anchors.verticalCenter: chatTime.verticalCenter
anchors.right: chatTime.left
anchors.rightMargin: 5
}
2020-07-14 15:35:21 +00:00
Retry {
id: retry
anchors.verticalCenter: chatTime.verticalCenter
2020-07-14 15:35:21 +00:00
anchors.right: chatTime.left
anchors.rightMargin: 5
isCurrentUser: root.isCurrentUser
isExpired: root.isExpired
timeout: root.timeout
onClicked: {
root.store.chatsModelInst.messageView.resendMessage(chatId, messageId)
}
2020-07-14 15:35:21 +00:00
}
2020-10-23 19:46:44 +00:00
Loader {
id: linksLoader
active: !!root.linkUrls
anchors.left: !root.isCurrentUser ? chatImage.right : undefined
anchors.leftMargin: !root.isCurrentUser ? 8 : 0
anchors.right: !root.isCurrentUser ? undefined : parent.right
anchors.rightMargin: !root.isCurrentUser ? 0 : Style.current.padding
2020-10-23 19:46:44 +00:00
anchors.top: chatBox.bottom
feat: whitelist gifs (no url extension needed) Fixes #1377. Fixes #1479. Two sites have been added to the whitelist: giphy.com and tenor.com. `imageUrls` in its entirety has been removed and instead all links are being handle through the message `linkUrls`. This prevents double-handling of urls that may or may not be images. The logic to automatically show links previews works like this: 1. If the setting "display chat images" is enabled, all links that *contain* ".png", ".jpg", ".jpeg", ".svg", ".gif" will be automatically shown. If the URL doesn't contain the extension, we are not downloading it. This was meant to be somewhat of a security compromise as we do not want to download each and every link posted in a message just to find out its true content type. 2. If the above setting is *disabled*, then we follow the whitelist settings for tenor and giphy. This allows us to preview gifs that do not have a file extension in their url. feat: bump status-go to the commit that supports the new whitelist (https://github.com/status-im/status-go/pull/2094), and also lets us get link preview data from urls in the whitelist. NOTE: this commit was branched off status-go `develop`, so once it is merged, and we update this PR to the new commit, we will effectively be getting status-go develop changes. We *could* base that status-go PR off of master if it makes things easier. fix: height on settings update issue feat: move date/time of message below links fix: layout issues when changing setting `neverAskAboutUnfurlingAgain` feat: Add MessageBorder component to aid in showing rounded corners with different radius
2020-12-11 00:53:44 +00:00
anchors.topMargin: Style.current.halfPadding
anchors.bottomMargin: Style.current.halfPadding
2020-10-23 19:46:44 +00:00
sourceComponent: Component {
LinksMessageView {
store: root.store
linkUrls: root.linkUrls
feat: whitelist gifs (no url extension needed) Fixes #1377. Fixes #1479. Two sites have been added to the whitelist: giphy.com and tenor.com. `imageUrls` in its entirety has been removed and instead all links are being handle through the message `linkUrls`. This prevents double-handling of urls that may or may not be images. The logic to automatically show links previews works like this: 1. If the setting "display chat images" is enabled, all links that *contain* ".png", ".jpg", ".jpeg", ".svg", ".gif" will be automatically shown. If the URL doesn't contain the extension, we are not downloading it. This was meant to be somewhat of a security compromise as we do not want to download each and every link posted in a message just to find out its true content type. 2. If the above setting is *disabled*, then we follow the whitelist settings for tenor and giphy. This allows us to preview gifs that do not have a file extension in their url. feat: bump status-go to the commit that supports the new whitelist (https://github.com/status-im/status-go/pull/2094), and also lets us get link preview data from urls in the whitelist. NOTE: this commit was branched off status-go `develop`, so once it is merged, and we update this PR to the new commit, we will effectively be getting status-go develop changes. We *could* base that status-go PR off of master if it makes things easier. fix: height on settings update issue feat: move date/time of message below links fix: layout issues when changing setting `neverAskAboutUnfurlingAgain` feat: Add MessageBorder component to aid in showing rounded corners with different radius
2020-12-11 00:53:44 +00:00
container: root.container
isCurrentUser: root.isCurrentUser
}
2020-10-23 19:46:44 +00:00
}
}
Loader {
id: emojiReactionLoader
active: emojiReactions !== ""
sourceComponent: emojiReactionsComponent
anchors.left: root.isCurrentUser ? undefined : chatBox.left
anchors.right: root.isCurrentUser ? chatBox.right : undefined
anchors.leftMargin: root.isCurrentUser ? Style.current.halfPadding : 1
anchors.top: chatBox.bottom
anchors.topMargin: 2
}
Component {
id: emojiReactionsComponent
EmojiReactionsPanel {
// isMessageActive: root.store.messageStore.isMessageActive
// emojiReactionsModel: root.store.messageStore.emojiReactionsModel
onSetMessageActive: {
root.store.messageStore.setMessageActive(messageId, active);;
}
onToggleReaction: root.store.chatsModelInst.toggleReaction(messageId, emojiID)
}
}
}