Restore hover actions for the cpp message delegate

Restore hover actions for the cpp message delegate

BUG: 503843
This commit is contained in:
James Graham
2025-05-09 18:03:23 +01:00
committed by Joshua Goins
parent 3183be460e
commit 0a2af02c5f
6 changed files with 30 additions and 16 deletions

View File

@@ -7,6 +7,7 @@ ecm_add_qml_module(Timeline GENERATE_PLUGIN_SOURCE
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/timeline
QML_FILES
TimelineView.qml
HoverActions.qml
EventDelegate.qml
HiddenDelegate.qml
MessageDelegate.qml

View File

@@ -0,0 +1,181 @@
// 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
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
import org.kde.neochat.chatbar
/**
* @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 The current message delegate the actions are being shown on.
*/
property var delegate: null
/**
* @brief The current room that user is viewing.
*/
required property NeoChatRoom currentRoom
/**
* @brief Whether the actions should be shown.
*/
readonly property bool showActions: delegate && delegate.hovered
/**
* @brief Request that the chat bar be focussed.
*/
signal focusChatBar
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0
visible: (root.hovered || root.showActions || showActionsTimer.running) && !Kirigami.Settings.isMobile && (!root.delegate.isThreaded || !NeoChatConfig.threads)
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
}
function updatePosition(): void {
if (delegate) {
root.x = delegate.contentItem.x + delegate.bubbleWidth - root.implicitWidth - Kirigami.Units.largeSpacing;
root.y = delegate.mapToItem(parent, 0, 0).y + delegate.bubbleY - height + Kirigami.Units.smallSpacing;
}
}
onDelegateChanged: updatePosition()
onWidthChanged: updatePosition()
contentItem: RowLayout {
id: actionsLayout
spacing: Kirigami.Units.smallSpacing
Item {
Layout.fillWidth: true
}
Kirigami.Icon {
source: "security-high"
width: height
height: root.height
visible: root.delegate && root.delegate.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
}
QQC2.Button {
text: i18n("React")
icon.name: "preferences-desktop-emoticons"
onClicked: emojiDialog.open()
display: QQC2.ToolButton.IconOnly
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
QQC2.Button {
visible: root.delegate && root.delegate.isEditable && !root.currentRoom.readOnly
text: i18n("Edit")
icon.name: "document-edit"
display: QQC2.Button.IconOnly
onClicked: {
root.currentRoom.editCache.editId = root.delegate.eventId;
root.currentRoom.mainCache.replyId = "";
root.currentRoom.mainCache.threadId = "";
}
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
QQC2.Button {
visible: !root.currentRoom.readOnly
text: i18n("Reply")
icon.name: "mail-replied-symbolic"
display: QQC2.Button.IconOnly
onClicked: {
root.currentRoom.mainCache.replyId = root.delegate.eventId;
root.currentRoom.editCache.editId = "";
root.currentRoom.mainCache.threadId = "";
root.focusChatBar();
}
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
QQC2.Button {
visible: NeoChatConfig.threads && !root.currentRoom.readOnly && !root.delegate?.isPoll
text: i18n("Reply in Thread")
icon.name: "dialog-messages"
display: QQC2.Button.IconOnly
onClicked: {
root.currentRoom.threadCache.replyId = "";
root.currentRoom.threadCache.threadId = root.delegate.isThreaded ? root.delegate.threadRoot : root.delegate.eventId;
root.currentRoom.mainCache.clearRelations();
root.currentRoom.editCache.clearRelations();
root.focusChatBar();
}
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
QQC2.Button {
visible: (root.delegate?.isPoll ?? false) && !ContentProvider.handlerForPoll(root.currentRoom, root.delegate.eventId).hasEnded
text: i18n("End Poll")
icon.name: "gtk-stop"
display: QQC2.ToolButton.IconOnly
onClicked: root.currentRoom.poll(root.delegate.eventId).endPoll()
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
EmojiDialog {
id: emojiDialog
currentRoom: root.currentRoom
showQuickReaction: true
showStickers: false
onChosen: emoji => {
root.currentRoom.toggleReaction(root.delegate.eventId, emoji);
if (!Kirigami.Settings.isMobile) {
root.focusChatBar();
}
}
}
}
}

View File

@@ -89,13 +89,6 @@ MessageDelegateBase {
*/
required property bool verified
/**
* @brief The x position of the message bubble.
*
* @note Used for positioning the hover actions.
*/
readonly property real bubbleX: bubble.x + bubble.anchors.leftMargin
/**
* @brief The y position of the message bubble.
*
@@ -110,11 +103,6 @@ MessageDelegateBase {
*/
readonly property alias bubbleWidth: bubble.width
/**
* @brief Whether this message is hovered.
*/
readonly property alias hovered: bubble.hovered
/**
* @brief Open the any message media externally.
*/
@@ -214,6 +202,13 @@ MessageDelegateBase {
radius: Kirigami.Units.cornerRadius
}
// show hover actions
onHoveredChanged: {
if (hovered && !Kirigami.Settings.isMobile) {
root.setHoverActionsToDelegate();
}
}
function setHoverActionsToDelegate() {
if (ListView.view.setHoverActionsToDelegate) {
ListView.view.setHoverActionsToDelegate(root);

View File

@@ -39,6 +39,7 @@ MessageDelegateBase::MessageDelegateBase(QQuickItem *parent)
: TimelineDelegate(parent)
{
m_contentSizeHelper.setParentItem(this);
setAcceptHoverEvents(true);
setPercentageValues();
connect(this, &MessageDelegateBase::leftPaddingChanged, this, &MessageDelegateBase::setContentPadding);
@@ -395,7 +396,6 @@ void MessageDelegateBase::setCompactMode(bool compactMode)
m_compactMode = compactMode;
setAlwaysFillWidth(m_isThreaded || m_compactMode);
setPercentageValues(m_isThreaded || m_compactMode);
setAcceptHoverEvents(m_compactMode);
setBaseRightPadding();
Q_EMIT compactModeChanged();
@@ -542,13 +542,18 @@ void MessageDelegateBase::resizeContent()
void MessageDelegateBase::hoverEnterEvent(QHoverEvent *event)
{
m_hovered = true;
Q_EMIT hoveredChanged();
event->setAccepted(true);
updateBackground();
}
void MessageDelegateBase::hoverMoveEvent(QHoverEvent *event)
{
bool oldHovered = m_hovered;
m_hovered = contains(event->pos());
if (oldHovered != m_hovered) {
Q_EMIT hoveredChanged();
}
event->setAccepted(true);
updateBackground();
}
@@ -556,6 +561,7 @@ void MessageDelegateBase::hoverMoveEvent(QHoverEvent *event)
void MessageDelegateBase::hoverLeaveEvent(QHoverEvent *event)
{
m_hovered = false;
Q_EMIT hoveredChanged();
event->setAccepted(true);
updateBackground();
}
@@ -587,4 +593,9 @@ void MessageDelegateBase::setIsTemporaryHighlighted(bool isTemporaryHighlighted)
Q_EMIT isTemporaryHighlightedChanged();
}
bool MessageDelegateBase::hovered() const
{
return m_hovered;
}
#include "moc_messagedelegate.cpp"

View File

@@ -114,6 +114,11 @@ class MessageDelegateBase : public TimelineDelegate
*/
Q_PROPERTY(bool isTemporaryHighlighted READ isTemporaryHighlighted WRITE setIsTemporaryHighlighted NOTIFY isTemporaryHighlightedChanged FINAL)
/**
* @brief Whether the delegate is hovered.
*/
Q_PROPERTY(bool hovered READ hovered NOTIFY hoveredChanged FINAL)
public:
MessageDelegateBase(QQuickItem *parent = nullptr);
@@ -153,6 +158,8 @@ public:
bool isTemporaryHighlighted() const;
void setIsTemporaryHighlighted(bool isTemporaryHighlighted);
bool hovered() const;
Q_SIGNALS:
void authorChanged();
void isThreadedChanged();
@@ -168,6 +175,7 @@ Q_SIGNALS:
void compactModeChanged();
void showLocalMessagesOnRightChanged();
void isTemporaryHighlightedChanged();
void hoveredChanged();
private:
DelegateSizeHelper m_contentSizeHelper;
@@ -222,7 +230,7 @@ private:
}
cleanupIncubator(incubator);
};
static void cleanupIncubator(MessageObjectIncubator *incubator);
void cleanupIncubator(MessageObjectIncubator *incubator);
void cleanupItem(QQuickItem *item);
qreal m_spacing = 0.0;