Refactor hover actions
Refactor hover actions into their own component.
This commit is contained in:
116
src/qml/Component/HoverActions.qml
Normal file
116
src/qml/Component/HoverActions.qml
Normal file
@@ -0,0 +1,116 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
|
||||
/**
|
||||
* @brief A component that provides a set of actions when a message is hovered in the timeline.
|
||||
*
|
||||
* There is also an icon to show that a message has come from a verified device in
|
||||
* encrypted chats.
|
||||
*/
|
||||
QQC2.Control {
|
||||
id: root
|
||||
|
||||
/**
|
||||
* @brief Whether the actions should be shown.
|
||||
*/
|
||||
property bool showActions: false
|
||||
|
||||
/**
|
||||
* @brief Whether the message has been sent from a verified matrix session.
|
||||
*/
|
||||
property bool verified: false
|
||||
|
||||
/**
|
||||
* @brief Whether the edit button should be shown.
|
||||
*/
|
||||
property bool editable: false
|
||||
|
||||
/**
|
||||
* @brief The react button has been clicked.
|
||||
*/
|
||||
signal reactClicked(string emoji)
|
||||
|
||||
/**
|
||||
* @brief The edit button has been clicked.
|
||||
*/
|
||||
signal editClicked()
|
||||
|
||||
/**
|
||||
* @brief The reply button has been clicked.
|
||||
*/
|
||||
signal replyClicked()
|
||||
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
|
||||
visible: (root.hovered || root.showActions || showActionsTimer.running) && !Kirigami.Settings.isMobile
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
// HACK: delay disapearing by 200ms, otherwise this can create some glitches
|
||||
// See https://invent.kde.org/network/neochat/-/issues/333
|
||||
showActionsTimer.restart()
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: showActionsTimer
|
||||
interval: 200
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Kirigami.Icon {
|
||||
source: "security-high"
|
||||
width: height
|
||||
height: root.height
|
||||
visible: root.verified
|
||||
HoverHandler {
|
||||
id: hover
|
||||
}
|
||||
QQC2.ToolTip.text: i18n("This message was sent from a verified device")
|
||||
QQC2.ToolTip.visible: hover.hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
Kirigami.ActionToolBar {
|
||||
Layout.maximumWidth: maximumContentWidth + Kirigami.Units.largeSpacing
|
||||
rightPadding: Kirigami.Units.largeSpacing
|
||||
alignment: Qt.AlignRight
|
||||
flat: false
|
||||
display: QQC2.Button.IconOnly
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("React")
|
||||
icon.name: "preferences-desktop-emoticons"
|
||||
onTriggered: emojiDialog.open()
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Edit")
|
||||
icon.name: "document-edit"
|
||||
onTriggered: root.editClicked()
|
||||
visible: root.editable
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Reply")
|
||||
icon.name: "mail-replied-symbolic"
|
||||
onTriggered: root.replyClicked()
|
||||
}
|
||||
]
|
||||
|
||||
EmojiDialog {
|
||||
id: emojiDialog
|
||||
showQuickReaction: true
|
||||
onChosen: (emoji) => root.reactClicked(emoji)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,19 @@ import org.kde.neochat 1.0
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property string eventId: model.eventId
|
||||
|
||||
property var author: model.author
|
||||
|
||||
property int delegateType: model.delegateType
|
||||
|
||||
property bool verified: model.verified
|
||||
|
||||
readonly property real bubbleX: bubble.x + bubble.anchors.leftMargin
|
||||
readonly property alias bubbleY: mainContainer.y
|
||||
readonly property alias bubbleWidth: bubble.width
|
||||
readonly property alias hovered: bubble.hovered
|
||||
|
||||
signal openContextMenu
|
||||
signal openExternally()
|
||||
signal replyClicked(string eventID)
|
||||
@@ -99,21 +112,7 @@ ColumnLayout {
|
||||
// show hover actions
|
||||
onHoveredChanged: {
|
||||
if (hovered && !Kirigami.Settings.isMobile) {
|
||||
updateHoverComponent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Show hover actions by updating the global hover component to this delegate
|
||||
function updateHoverComponent() {
|
||||
if (!hoverComponent) {
|
||||
return;
|
||||
}
|
||||
if (hovered && !Kirigami.Settings.isMobile) {
|
||||
hoverComponent.delegate = root
|
||||
hoverComponent.bubble = bubble
|
||||
hoverComponent.event = model
|
||||
hoverComponent.updateFunction = updateHoverComponent;
|
||||
root.setHoverActionsToDelegate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +279,6 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
background: Item {
|
||||
Kirigami.ShadowedRectangle {
|
||||
id: bubbleBackground
|
||||
@@ -382,4 +380,8 @@ ColumnLayout {
|
||||
});
|
||||
contextMenu.open();
|
||||
}
|
||||
|
||||
function setHoverActionsToDelegate() {
|
||||
ListView.view.setHoverActionsToDelegate(root)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,108 +297,39 @@ QQC2.ScrollView {
|
||||
itemAtIndex(index).isTemporaryHighlighted = true
|
||||
}
|
||||
|
||||
Item {
|
||||
HoverActions {
|
||||
id: hoverActions
|
||||
property var event: null
|
||||
property bool userMsg: event && event.author.id === Controller.activeConnection.localUserId
|
||||
property bool showEdit: event && userMsg && (event.delegateType === MessageEventModel.Emote || event.delegateType === MessageEventModel.Message)
|
||||
|
||||
property var delegate: null
|
||||
property var bubble: null
|
||||
property var hovered: bubble && bubble.hovered
|
||||
property var visibleDelayed: (hovered || hoverHandler.hovered) && !Kirigami.Settings.isMobile
|
||||
property var updateFunction
|
||||
onVisibleDelayedChanged: if (visibleDelayed) {
|
||||
visible = true;
|
||||
} else {
|
||||
// HACK: delay disapearing by 200ms, otherwise this can create some glitches
|
||||
// See https://invent.kde.org/network/neochat/-/issues/333
|
||||
hoverActionsTimer.restart();
|
||||
|
||||
x: delegate ? delegate.x + delegate.bubbleX : 0
|
||||
y: delegate ? delegate.mapToItem(parent, 0, 0).y + delegate.bubbleY - height + Kirigami.Units.smallSpacing : 0
|
||||
width: delegate.bubbleWidth
|
||||
|
||||
showActions: delegate && delegate.hovered
|
||||
verified: delegate && delegate.verified
|
||||
editable: delegate && delegate.author.isLocalUser && (delegate.delegateType === MessageEventModel.Emote || delegate.delegateType === MessageEventModel.Message)
|
||||
|
||||
onReactClicked: (emoji) => {
|
||||
root.currentRoom.toggleReaction(delegate.eventId, emoji);
|
||||
if (!Kirigami.Settings.isMobile) {
|
||||
root.focusChatBox();
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: hoverActionsTimer
|
||||
interval: 200
|
||||
onTriggered: hoverActions.visible = hoverActions.visibleDelayed
|
||||
;
|
||||
onEditClicked: {
|
||||
root.currentRoom.chatBoxEditId = delegate.eventId;
|
||||
root.currentRoom.chatBoxReplyId = "";
|
||||
}
|
||||
|
||||
property int childOffset: userMsg && Config.showLocalMessagesOnRight && !Config.compactLayout ? (bubble ? bubble.width : 0) - childWidth : Math.max((bubble ? bubble.width : 0) - childWidth, 0)
|
||||
x: delegate && bubble ? (delegate.x + bubble.x + Kirigami.Units.largeSpacing + childOffset - (Config.compactLayout ? Kirigami.Units.gridUnit * 3 : 0) - (userMsg && !Config.compactLayout ? Kirigami.Units.gridUnit : 0)) : 0
|
||||
y: bubble ? bubble.mapToItem(parent, 0, 0).y - hoverActions.childHeight + Kirigami.Units.smallSpacing : 0
|
||||
;
|
||||
|
||||
visible: false
|
||||
|
||||
property alias childWidth: hoverActionsRow.width
|
||||
property alias childHeight: hoverActionsRow.height
|
||||
|
||||
RowLayout {
|
||||
id: hoverActionsRow
|
||||
z: 4
|
||||
spacing: 0
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
margin: Kirigami.Units.smallSpacing
|
||||
}
|
||||
Kirigami.Icon {
|
||||
source: "security-high"
|
||||
width: height
|
||||
height: parent.height
|
||||
visible: hoverActions.event ? hoverActions.event.verified : false
|
||||
HoverHandler {
|
||||
id: hover
|
||||
}
|
||||
QQC2.ToolTip.text: i18n("This message was sent from a verified device")
|
||||
QQC2.ToolTip.visible: hover.hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
QQC2.ToolTip.text: i18n("React")
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
icon.name: "preferences-desktop-emoticons"
|
||||
|
||||
onClicked: emojiDialog.open()
|
||||
;
|
||||
EmojiDialog {
|
||||
id: emojiDialog
|
||||
showQuickReaction: true
|
||||
onChosen: {
|
||||
root.currentRoom.toggleReaction(hoverActions.event.eventId, emoji);
|
||||
if (!Kirigami.Settings.isMobile) {
|
||||
root.focusChatBox();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
QQC2.ToolTip.text: i18n("Edit")
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
visible: hoverActions.showEdit
|
||||
icon.name: "document-edit"
|
||||
onClicked: {
|
||||
root.currentRoom.chatBoxEditId = hoverActions.event.eventId;
|
||||
root.currentRoom.chatBoxReplyId = "";
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
QQC2.ToolTip.text: i18n("Reply")
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
icon.name: "mail-replied-symbolic"
|
||||
onClicked: {
|
||||
root.currentRoom.chatBoxReplyId = hoverActions.event.eventId;
|
||||
root.currentRoom.chatBoxEditId = "";
|
||||
root.focusChatBox();
|
||||
}
|
||||
}
|
||||
onReplyClicked: {
|
||||
root.currentRoom.chatBoxReplyId = delegate.eventId;
|
||||
root.currentRoom.chatBoxEditId = "";
|
||||
root.focusChatBox();
|
||||
}
|
||||
}
|
||||
|
||||
onContentYChanged: {
|
||||
if (hoverActions.updateFunction) {
|
||||
hoverActions.updateFunction();
|
||||
if (hoverActions.delegate) {
|
||||
hoverActions.delegate.setHoverActionsToDelegate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,6 +443,10 @@ QQC2.ScrollView {
|
||||
root.currentRoom.markAllMessagesAsRead()
|
||||
}
|
||||
}
|
||||
|
||||
function setHoverActionsToDelegate(delegate) {
|
||||
hoverActions.delegate = delegate
|
||||
}
|
||||
}
|
||||
|
||||
function goToLastMessage() {
|
||||
|
||||
Reference in New Issue
Block a user