From b245d858aad42eb098f226bbe401bfa91c70447f Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Mon, 25 Jan 2021 15:50:42 -0500 Subject: [PATCH] feat: redisgn compact mode part 1 redesigns the compact mode to have a nice hover, easier replying and adding reactions and more Missing parts are aligning chat command, images and unfurlings, redesigning mentions and the channel list and also trying to find a way to re-enable link hovers in the text --- .../Chat/ChatColumn/ChatMessages.qml | 4 +- .../MessageComponents/ChatButtons.qml | 99 ++++++ .../ChatColumn/MessageComponents/ChatText.qml | 1 - .../MessageComponents/CompactMessage.qml | 325 +++++++++++------- .../MessageComponents/EmojiReactions.qml | 261 +++++++++----- .../MessageComponents/MessageMouseArea.qml | 2 +- .../MessageComponents/UsernameLabel.qml | 6 +- ui/app/img/reply.svg | 3 + ui/imports/Themes/DarkTheme.qml | 2 + ui/imports/Themes/LightTheme.qml | 2 + ui/imports/Themes/Theme.qml | 3 + ui/nim-status-client.pro | 1 + ui/shared/status/StatusToolTip.qml | 2 +- 13 files changed, 489 insertions(+), 222 deletions(-) create mode 100644 ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatButtons.qml create mode 100644 ui/app/img/reply.svg diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatMessages.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatMessages.qml index c2c9f0fc2e..b3789243c5 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/ChatMessages.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/ChatMessages.qml @@ -31,15 +31,17 @@ ScrollView { ListView { property string currentNotificationChatId + property bool chatButtonsHovered: false id: chatLogView anchors.fill: parent anchors.bottomMargin: Style.current.bigPadding - spacing: 4 + spacing: appSettings.compactMode ? 0 : 4 boundsBehavior: Flickable.StopAtBounds flickDeceleration: 10000 Layout.fillWidth: true Layout.fillHeight: true + verticalLayoutDirection: ListView.TopToBottom Timer { id: timer diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatButtons.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatButtons.qml new file mode 100644 index 0000000000..fa6ad75959 --- /dev/null +++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatButtons.qml @@ -0,0 +1,99 @@ +import QtQuick 2.13 +import QtGraphicalEffects 1.13 +import "../../../../../shared" +import "../../../../../shared/status" +import "../../../../../imports" + +Rectangle { + property bool parentIsHovered: false + signal hoverChanged(bool hovered) + property int containerMargin: 2 + + id: buttonsContainer + visible: buttonsContainer.parentIsHovered || isMessageActive + width: buttonRow.width + buttonsContainer.containerMargin * 2 + height: 36 + radius: Style.current.radius + color: Style.current.background + z: 52 + + layer.enabled: true + layer.effect: DropShadow { + width: buttonsContainer.width + height: buttonsContainer.height + x: buttonsContainer.x + y: buttonsContainer.y + 10 + visible: buttonsContainer.visible + source: buttonsContainer + horizontalOffset: 0 + verticalOffset: 2 + radius: 10 + samples: 15 + color: "#22000000" + } + + MouseArea { + anchors.fill: buttonsContainer + acceptedButtons: Qt.NoButton + hoverEnabled: true + onEntered: { + buttonsContainer.hoverChanged(true) + chatLogView.chatButtonsHovered = true + } + onExited: { + buttonsContainer.hoverChanged(false) + chatLogView.chatButtonsHovered = false + } + } + + Row { + id: buttonRow + spacing: buttonsContainer.containerMargin + anchors.left: parent.left + anchors.leftMargin: buttonsContainer.containerMargin + anchors.verticalCenter: buttonsContainer.verticalCenter + height: parent.height - 2 * buttonsContainer.containerMargin + + StatusIconButton { + id: emojiBtn + icon.name: "emoji" + width: 32 + height: 32 + onClicked: { + isMessageActive = true + clickMessage(false, false, false, null, true) + } + onHoveredChanged: { + chatLogView.chatButtonsHovered = this.hovered + buttonsContainer.hoverChanged(this.hovered) + } + + StatusToolTip { + visible: emojiBtn.hovered + text: qsTr("Add reaction") + width: 115 + } + } + + StatusIconButton { + id: replyBtn + icon.name: "reply" + width: 32 + height: 32 + onClicked: { + SelectedMessage.set(messageId, fromAuthor); + showReplyArea() + } + onHoveredChanged: { + chatLogView.chatButtonsHovered = this.hovered + buttonsContainer.hoverChanged(this.hovered) + } + + StatusToolTip { + visible: replyBtn.hovered + text: qsTr("Reply") + width: 75 + } + } + } +} diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatText.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatText.qml index 1100802059..2335a13536 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatText.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatText.qml @@ -105,7 +105,6 @@ Item { } } - Loader { id: mask anchors.fill: chatText diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/CompactMessage.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/CompactMessage.qml index a51e69e40b..26dabf6555 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/CompactMessage.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/CompactMessage.qml @@ -1,179 +1,240 @@ import QtQuick 2.13 +import QtGraphicalEffects 1.13 import "../../../../../shared" +import "../../../../../shared/status" import "../../../../../imports" Item { property var clickMessage: function () {} - property int chatHorizontalPadding: 12 + property int chatHorizontalPadding: 8 property int chatVerticalPadding: 7 property string linkUrls: "" property int contentType: 2 property var container property bool isCurrentUser: false + property bool isHovered: false + property bool isMessageActive: false id: root - anchors.top: parent.top - anchors.topMargin: authorCurrentMsg != authorPrevMsg ? Style.current.smallPadding : 0 - height: childrenRect.height + this.anchors.topMargin + width: parent.width + height: messageContainer.height - // FIXME @jonathanr: Adding this breaks the first line. Need to fix the height somehow -// DateGroup { -// id: dateGroupLbl -// } - - UserImage { - id: chatImage - anchors.left: parent.left - anchors.leftMargin: Style.current.padding -// anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top - anchors.top: parent.top + MouseArea { + anchors.fill: messageContainer + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: messageMouseArea.clicked(mouse) } - UsernameLabel { - id: chatName - anchors.leftMargin: root.chatHorizontalPadding -// anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top - anchors.top: parent.top - anchors.left: chatImage.right - } - - ChatReply { - id: chatReply -// anchors.top: chatName.visible ? chatName.bottom : (dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top) - anchors.top: chatName.visible ? chatName.bottom : parent.top - anchors.topMargin: chatName.visible && this.visible ? root.chatVerticalPadding : 0 - anchors.left: chatImage.right - anchors.leftMargin: root.chatHorizontalPadding + ChatButtons { + parentIsHovered: root.isHovered + onHoverChanged: root.isHovered = hovered anchors.right: parent.right - anchors.rightMargin: root.chatHorizontalPadding - container: root.container - chatHorizontalPadding: root.chatHorizontalPadding - } - - ChatText { - id: chatText - anchors.top: chatReply.bottom - anchors.topMargin: chatName.visible && this.visible ? root.chatVerticalPadding : 0 - anchors.left: chatImage.right - anchors.leftMargin: root.chatHorizontalPadding - anchors.right: parent.right - anchors.rightMargin: root.chatHorizontalPadding + anchors.rightMargin: 20 + anchors.top: parent.top + // This is not exactly like the design because the hover becomes messed up with the buttons on top of another Message + anchors.topMargin: -Style.current.halfPadding } Loader { - id: chatImageContent - active: isImage - anchors.left: chatText.left - anchors.leftMargin: 8 - anchors.top: chatReply.bottom - z: 51 - + active: typeof messageContextMenu !== "undefined" sourceComponent: Component { - ChatImage { - imageSource: image - imageWidth: 200 - onClicked: root.clickMessage(false, false, true, image) - container: root.container + Connections { + enabled: root.isMessageActive + target: messageContextMenu + onClosed: root.isMessageActive = false } } } - Loader { - id: stickerLoader - active: contentType === Constants.stickerType - anchors.left: chatText.left - anchors.top: chatName.visible ? chatName.bottom : parent.top - anchors.topMargin: this.visible && chatName.visible ? root.chatVerticalPadding : 0 + Rectangle { + property alias chatText: chatText - sourceComponent: Component { - Rectangle { - id: stickerContainer - color: Style.current.transparent - border.color: Style.current.grey - border.width: 1 - radius: 16 - width: stickerId.width + 2 * root.chatVerticalPadding - height: stickerId.height + 2 * root.chatVerticalPadding + id: messageContainer + height: childrenRect.height + (chatName.visible || emojiReactionLoader.active ? Style.current.smallPadding : 0) + + (emojiReactionLoader.active ? emojiReactionLoader.height + Style.current.halfPadding : 0) + width: parent.width - Sticker { - id: stickerId - anchors.top: parent.top - anchors.topMargin: root.chatVerticalPadding - anchors.left: parent.left - anchors.leftMargin: root.chatVerticalPadding - contentType: root.contentType + color: root.isHovered || isMessageActive ? Style.current.backgroundHover : Style.current.transparent + + // FIXME @jonathanr: Adding this breaks the first line. Need to fix the height somehow + // DateGroup { + // id: dateGroupLbl + // } + + UserImage { + id: chatImage + anchors.left: parent.left + anchors.leftMargin: Style.current.padding + // anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top + anchors.top: parent.top + anchors.topMargin: Style.current.smallPadding + } + + UsernameLabel { + id: chatName + anchors.leftMargin: root.chatHorizontalPadding + // anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top + anchors.top: chatImage.top + anchors.left: chatImage.right + } + + ChatReply { + id: chatReply + // anchors.top: chatName.visible ? chatName.bottom : (dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top) + anchors.top: chatName.visible ? chatName.bottom : parent.top + anchors.topMargin: chatName.visible && this.visible ? root.chatVerticalPadding : 0 + anchors.left: chatImage.right + anchors.leftMargin: root.chatHorizontalPadding + anchors.right: parent.right + anchors.rightMargin: root.chatHorizontalPadding + container: root.container + chatHorizontalPadding: root.chatHorizontalPadding + } + + ChatText { + id: chatText + anchors.top: chatReply.active ? chatReply.bottom : chatName.visible ? chatName.bottom : parent.top + anchors.left: parent.left + anchors.right: parent.right + // using a padding instead of a margin let's us select text more easily + textField.leftPadding: chatImage.anchors.leftMargin + chatImage.width + root.chatHorizontalPadding + textField.rightPadding: Style.current.bigPadding + } + + Loader { + id: chatImageContent + active: isImage + anchors.left: chatText.left + anchors.leftMargin: 8 + anchors.top: chatReply.bottom + z: 51 + + sourceComponent: Component { + ChatImage { + imageSource: image + imageWidth: 200 + onClicked: root.clickMessage(false, false, true, image) container: root.container } } } + + Loader { + id: stickerLoader + active: contentType === Constants.stickerType + anchors.left: chatText.left + anchors.top: chatName.visible ? chatName.bottom : parent.top + anchors.topMargin: this.visible && chatName.visible ? root.chatVerticalPadding : 0 + + sourceComponent: Component { + Rectangle { + id: stickerContainer + color: Style.current.transparent + border.color: Style.current.grey + border.width: 1 + radius: 16 + width: stickerId.width + 2 * root.chatVerticalPadding + height: stickerId.height + 2 * root.chatVerticalPadding + + Sticker { + id: stickerId + anchors.top: parent.top + anchors.topMargin: root.chatVerticalPadding + anchors.left: parent.left + anchors.leftMargin: root.chatVerticalPadding + contentType: root.contentType + container: root.container + } + } + } + } + + MessageMouseArea { + id: messageMouseArea + anchors.fill: stickerLoader.active ? stickerLoader : chatText + } + + ChatTime { + id: chatTime + visible: authorCurrentMsg != authorPrevMsg + anchors.verticalCenter: chatName.verticalCenter + anchors.left: chatName.right + anchors.leftMargin: 4 + } + + SentMessage { + id: sentMessage + visible: isCurrentUser && !timeout && !isExpired && isMessage && outgoingStatus !== "sent" + anchors.verticalCenter: chatTime.verticalCenter + anchors.left: chatTime.right + anchors.leftMargin: Style.current.halfPadding + } + + Retry { + id: retry + anchors.right: chatTime.right + anchors.rightMargin: 5 + } + + Loader { + id: linksLoader + active: !!root.linkUrls + anchors.left: chatText.left + anchors.leftMargin: 8 + anchors.top: chatText.bottom + + sourceComponent: Component { + LinksMessage { + linkUrls: root.linkUrls + container: root.container + isCurrentUser: root.isCurrentUser + } + } + } + + Loader { + id: audioPlayerLoader + active: isAudio + anchors.top: chatName.visible ? chatName.bottom : parent.top + anchors.left: chatImage.right + + sourceComponent: Component { + AudioPlayer { + audioSource: audio + } + } + } } - MessageMouseArea { - anchors.fill: stickerLoader.active ? stickerLoader : chatText - } - - // TODO show date for not the first messsage (on hover maybe) - ChatTime { - id: chatTime - visible: authorCurrentMsg != authorPrevMsg - anchors.verticalCenter: chatName.verticalCenter - anchors.left: chatName.right - anchors.leftMargin: Style.current.padding - } - - SentMessage { - id: sentMessage - visible: isCurrentUser && !timeout && !isExpired && isMessage && outgoingStatus !== "sent" - anchors.verticalCenter: chatTime.verticalCenter - anchors.left: chatTime.right - anchors.leftMargin: 8 - } - - Retry { - id: retry - anchors.right: chatTime.right - anchors.rightMargin: 5 - } - - Loader { - id: linksLoader - active: !!root.linkUrls - anchors.left: chatText.left - anchors.leftMargin: 8 - anchors.top: chatText.bottom - - sourceComponent: Component { - LinksMessage { - linkUrls: root.linkUrls - container: root.container - isCurrentUser: root.isCurrentUser - } + // TODO find a way for this to not eat link hovers + MouseArea { + anchors.fill: root + acceptedButtons: Qt.NoButton + hoverEnabled: true + onEntered: { + root.isHovered = true } - } - - Loader { - id: audioPlayerLoader - active: isAudio - anchors.top: chatName.visible ? chatName.bottom : parent.top - anchors.left: chatImage.right - - sourceComponent: Component { - AudioPlayer { - audioSource: audio + onExited: { + if (chatLogView.chatButtonsHovered) { + return } + root.isHovered = false } } Loader { id: emojiReactionLoader active: emojiReactions !== "" - anchors.top: chatText.bottom - anchors.left: chatText.left - anchors.topMargin: active ? 2 : 0 + anchors.bottom: messageContainer.bottom + anchors.bottomMargin: Style.current.smallPadding + anchors.left: messageContainer.left + anchors.leftMargin: messageContainer.chatText.textField.leftPadding sourceComponent: Component { - EmojiReactions {} + EmojiReactions { + onHoverChanged: root.isHovered = hovered + } } } } diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/EmojiReactions.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/EmojiReactions.qml index a79eb2a144..d53754d4bb 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/EmojiReactions.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/EmojiReactions.qml @@ -1,10 +1,14 @@ import QtQuick 2.3 import QtQuick.Controls 2.13 +import QtGraphicalEffects 1.13 import "../../../../../shared" +import "../../../../../shared/status" import "../../../../../imports" Item { property int imageMargin: 4 + signal hoverChanged(bool hovered) + id: root height: 20 width: childrenRect.width @@ -23,7 +27,7 @@ Item { if (fromAccounts.length > 3) { leftNode = fromAccounts.slice(0, 3); rightNode = fromAccounts.slice(3, fromAccounts.length); - return (rightNode.length == 1) ? + return (rightNode.length === 1) ? lastTwoItems([leftNode.join(", "), rightNode[0]]) : lastTwoItems([leftNode.join(", "), qsTr("%1 more reacted.").arg(rightNode.length)]); } @@ -33,109 +37,198 @@ Item { return lastTwoItems([leftNode.join(", "), rightNode[0]]); } - Repeater { - id: reactionepeater - model: { - if (!emojiReactions) { - return [] + Row { + spacing: root.imageMargin + + Repeater { + id: reactionRepeater + width: childrenRect.width + model: { + if (!emojiReactions) { + return [] + } + + try { + // group by id + var allReactions = Object.values(JSON.parse(emojiReactions)) + var byEmoji = {} + allReactions.forEach(function (reaction) { + if (!byEmoji[reaction.emojiId]) { + byEmoji[reaction.emojiId] = { + emojiId: reaction.emojiId, + fromAccounts: [], + count: 0, + currentUserReacted: false + } + } + byEmoji[reaction.emojiId].count++; + byEmoji[reaction.emojiId].fromAccounts.push(chatsModel.userNameOrAlias(reaction.from)); + if (!byEmoji[reaction.emojiId].currentUserReacted && reaction.from === profileModel.profile.pubKey) { + byEmoji[reaction.emojiId].currentUserReacted = true + } + + }) + return Object.values(byEmoji) + } catch (e) { + console.error('Error parsing emoji reactions', e) + return [] + } + } - try { - // group by id - var allReactions = Object.values(JSON.parse(emojiReactions)) - var byEmoji = {} - allReactions.forEach(function (reaction) { - if (!byEmoji[reaction.emojiId]) { - byEmoji[reaction.emojiId] = { - emojiId: reaction.emojiId, - fromAccounts: [], - count: 0, - currentUserReacted: false + Rectangle { + property bool isHovered: false + + id: emojiContainer + width: emojiImage.width + emojiCount.width + (root.imageMargin * 2) + + 8 + height: 20 + radius: 10 + color: modelData.currentUserReacted ? Style.current.secondaryBackground : + (isHovered ? Style.current.emojiReactionBackgroundHovered : Style.current.emojiReactionBackground) + + ToolTip { + visible: mouseArea.containsMouse + text: showReactionAuthors(modelData.fromAccounts) + } + + // Rounded corner to cover one corner + Rectangle { + color: parent.color + width: 8 + height: 8 + anchors.top: parent.top + anchors.left: !isCurrentUser || appSettings.compactMode ? parent.left : undefined + anchors.leftMargin: 0 + anchors.right: !isCurrentUser || appSettings.compactMode ? undefined : parent.right + anchors.rightMargin: 0 + radius: 2 + z: -1 + } + + // This is a workaround to get a "border" around the rectangle including the weird rectangle + Loader { + active: modelData.currentUserReacted + anchors.top: parent.top + anchors.topMargin: -1 + anchors.left: parent.left + anchors.leftMargin: -1 + z: -2 + + sourceComponent: Component { + Rectangle { + width: emojiContainer.width + 2 + height: emojiContainer.height + 2 + radius: emojiContainer.radius + color: Style.current.primary + + Rectangle { + color: parent.color + width: 8 + height: 8 + anchors.top: parent.top + anchors.left: !isCurrentUser || appSettings.compactMode ? parent.left : undefined + anchors.leftMargin: 0 + anchors.right: !isCurrentUser || appSettings.compactMode ? undefined : parent.right + anchors.rightMargin: 0 + radius: 2 + z: -1 + } } } - byEmoji[reaction.emojiId].count++; - byEmoji[reaction.emojiId].fromAccounts.push(chatsModel.userNameOrAlias(reaction.from)); - if (!byEmoji[reaction.emojiId].currentUserReacted && reaction.from === profileModel.profile.pubKey) { - byEmoji[reaction.emojiId].currentUserReacted = true + } + + SVGImage { + id: emojiImage + width: 15 + fillMode: Image.PreserveAspectFit + source: { + const basePath = "../../../../img/emojiReactions/" + switch (modelData.emojiId) { + case 1: return basePath + "heart.svg" + case 2: return basePath + "thumbsUp.svg" + case 3: return basePath + "thumbsDown.svg" + case 4: return basePath + "laughing.svg" + case 5: return basePath + "sad.svg" + case 6: return basePath + "angry.svg" + default: return "" + } } + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: root.imageMargin + } - }) - return Object.values(byEmoji) - } catch (e) { - console.error('Error parsing emoji reactions', e) - return [] - } + StyledText { + id: emojiCount + text: modelData.count + anchors.verticalCenter: parent.verticalCenter + anchors.left: emojiImage.right + anchors.leftMargin: root.imageMargin + font.pixelSize: 12 + color: modelData.currentUserReacted ? Style.current.textColorTertiary : Style.current.textColor + } - } + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onEntered: { + root.hoverChanged(true) + emojiContainer.isHovered = true + } + onExited: { + root.hoverChanged(false) + emojiContainer.isHovered = false + } + onClicked: { + chatsModel.toggleReaction(messageId, modelData.emojiId) - Rectangle { - width: emojiImage.width + emojiCount.width + (root.imageMargin * 2) + + 8 - height: 20 - radius: 10 - anchors.left: (index === 0) ? parent.left: parent.children[index-1].right - anchors.leftMargin: (index === 0) ? 0 : root.imageMargin - color: modelData.currentUserReacted ? Style.current.primary : Style.current.inputBackground - - ToolTip { - visible: mouseArea.containsMouse - text: showReactionAuthors(modelData.fromAccounts) - } - - // Rounded corner to cover one corner - Rectangle { - color: parent.color - width: 8 - height: 8 - anchors.top: parent.top - anchors.left: !isCurrentUser || appSettings.compactMode ? parent.left : undefined - anchors.leftMargin: 0 - anchors.right: !isCurrentUser || appSettings.compactMode ? undefined : parent.right - anchors.rightMargin: 0 - radius: 2 - z: -1 - } - - SVGImage { - id: emojiImage - width: 15 - fillMode: Image.PreserveAspectFit - source: { - const basePath = "../../../../img/emojiReactions/" - switch (modelData.emojiId) { - case 1: return basePath + "heart.svg" - case 2: return basePath + "thumbsUp.svg" - case 3: return basePath + "thumbsDown.svg" - case 4: return basePath + "laughing.svg" - case 5: return basePath + "sad.svg" - case 6: return basePath + "angry.svg" - default: return "" } } - anchors.verticalCenter: parent.verticalCenter + } + } + + Item { + width: addEmojiBtn.width + addEmojiBtn.anchors.leftMargin // there is more margin between the button and the emojis than between each emoji + height: addEmojiBtn.height + + SVGImage { + property bool isHovered: false + + id: addEmojiBtn + source: "../../../../img/emoji.svg" + width: 16.5 + height: 16.5 anchors.left: parent.left - anchors.leftMargin: root.imageMargin + anchors.leftMargin: 2.5 + } - StyledText { - id: emojiCount - text: modelData.count - anchors.verticalCenter: parent.verticalCenter - anchors.left: emojiImage.right - anchors.leftMargin: root.imageMargin - font.pixelSize: 12 - color: modelData.currentUserReacted ? Style.current.currentUserTextColor : Style.current.textColor + ColorOverlay { + anchors.fill: addEmojiBtn + antialiasing: true + source: addEmojiBtn + color: addEmojiBtn.isHovered ? Style.current.primary : Style.current.secondaryText } MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true + anchors.fill: addEmojiBtn cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onEntered: addEmojiBtn.isHovered = true + onExited: addEmojiBtn.isHovered = false onClicked: { - chatsModel.toggleReaction(messageId, modelData.emojiId) - + isMessageActive = true + clickMessage(false, false, false, null, true) } } + + StatusToolTip { + visible: addEmojiBtn.isHovered + text: qsTr("Add reaction") + width: 115 + } } } } diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/MessageMouseArea.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/MessageMouseArea.qml index b1a0055718..adaac0b442 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/MessageMouseArea.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/MessageMouseArea.qml @@ -1,4 +1,4 @@ -import QtQuick 2.3 +import QtQuick 2.13 import "../../../../../shared" import "../../../../../imports" diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/UsernameLabel.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/UsernameLabel.qml index b6bbcc2c42..798d5d06bf 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/UsernameLabel.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/UsernameLabel.qml @@ -4,6 +4,7 @@ import "../../../../../imports" Item { id: root + property bool isHovered: false height: childrenRect.height width: chatName.width + (ensOrAlias.visible ? ensOrAlias.width + ensOrAlias.anchors.leftMargin : 0) property alias label: chatName @@ -28,6 +29,7 @@ Item { color: text.startsWith("@") || isCurrentUser || localName !== "" ? Style.current.blue : Style.current.secondaryText font.weight: Font.Medium font.pixelSize: Style.current.secondaryTextFontSize + font.underline: root.isHovered readOnly: true wrapMode: Text.WordWrap selectByMouse: true @@ -37,10 +39,10 @@ Item { anchors.fill: parent hoverEnabled: true onEntered: { - parent.font.underline = true + root.isHovered = true } onExited: { - parent.font.underline = false + root.isHovered = false } onClicked: { clickMessage(true) diff --git a/ui/app/img/reply.svg b/ui/app/img/reply.svg new file mode 100644 index 0000000000..db8f058edf --- /dev/null +++ b/ui/app/img/reply.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/imports/Themes/DarkTheme.qml b/ui/imports/Themes/DarkTheme.qml index 94e80a99bc..66b25f3c54 100644 --- a/ui/imports/Themes/DarkTheme.qml +++ b/ui/imports/Themes/DarkTheme.qml @@ -51,6 +51,8 @@ Theme { property color topBarChatInfoColor: evenDarkerGrey property color codeBackground: "#2E386B" property color primarySelectionColor: "#b4c8ff" + property color emojiReactionBackground: "#2d2823" + property color emojiReactionBackgroundHovered: "#3a3632" property color buttonForegroundColor: blue property color buttonBackgroundColor: secondaryBackground diff --git a/ui/imports/Themes/LightTheme.qml b/ui/imports/Themes/LightTheme.qml index 7ac5f14d05..7a9e4bbb39 100644 --- a/ui/imports/Themes/LightTheme.qml +++ b/ui/imports/Themes/LightTheme.qml @@ -50,6 +50,8 @@ Theme { property color topBarChatInfoColor: grey property color codeBackground: "#2E386B" property color primarySelectionColor: "#b4c8ff" + property color emojiReactionBackground: "#e2e6e9" + property color emojiReactionBackgroundHovered: "#d7dadd" property color buttonForegroundColor: blue property color buttonBackgroundColor: secondaryBackground diff --git a/ui/imports/Themes/Theme.qml b/ui/imports/Themes/Theme.qml index 43fccd38bf..735958fd12 100644 --- a/ui/imports/Themes/Theme.qml +++ b/ui/imports/Themes/Theme.qml @@ -30,6 +30,7 @@ QtObject { property color orange: "#FE8F59" property color background + property color backgroundHover property color border property color textColor property color secondaryText @@ -38,6 +39,8 @@ QtObject { property color modalBackground property color codeBackground property color primarySelectioncolor + property color emojiReactionBackground + property color emojiReactionBackgroundHovered property color buttonForegroundColor property color buttonBackgroundColor diff --git a/ui/nim-status-client.pro b/ui/nim-status-client.pro index 201aa3f685..156318557b 100644 --- a/ui/nim-status-client.pro +++ b/ui/nim-status-client.pro @@ -145,6 +145,7 @@ DISTFILES += \ app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml \ app/AppLayouts/Chat/ChatColumn/CompactMessage.qml \ app/AppLayouts/Chat/ChatColumn/MessageComponents/ChannelIdentifier.qml \ + app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatButtons.qml \ app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatImage.qml \ app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatReply \ app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatReply.qml \ diff --git a/ui/shared/status/StatusToolTip.qml b/ui/shared/status/StatusToolTip.qml index 06bca2c2a3..07293f617a 100644 --- a/ui/shared/status/StatusToolTip.qml +++ b/ui/shared/status/StatusToolTip.qml @@ -36,7 +36,7 @@ ToolTip { color: Style.current.tooltipForegroundColor wrapMode: Text.WordWrap font.pixelSize: 13 - font.weight: Font.DemiBold + font.weight: Font.Medium horizontalAlignment: Text.AlignHCenter } }