Move the reaction delegate into the bubble

Move the reaction delegate into the bubble so it can be instantiated by the Content model. This aims to make sure we only instantiate it when needed rather than for every event. You can now hover the event to show the ReactionComponent with a button to add a reaction if none are currently present

Added bonus ReactionModel no longer needs an event pointer, the event ID is enough to get reaction from the room so things are less likely to blow up.
This commit is contained in:
James Graham
2025-02-09 19:07:53 +00:00
parent 08b29f7081
commit 5d7cb5c28f
14 changed files with 171 additions and 142 deletions

View File

@@ -193,6 +193,14 @@ DelegateChooser {
}
}
DelegateChoice {
roleValue: MessageComponentType.Reaction
delegate: ReactionComponent {
room: root.room
maxContentWidth: root.maxContentWidth
}
}
DelegateChoice {
roleValue: MessageComponentType.LinkPreview
delegate: LinkPreviewComponent {

View File

@@ -17,7 +17,6 @@ ecm_add_qml_module(timeline GENERATE_PLUGIN_SOURCE
TimelineEndDelegate.qml
Bubble.qml
AvatarFlow.qml
ReactionDelegate.qml
SectionDelegate.qml
BaseMessageComponentChooser.qml
MessageComponentChooser.qml
@@ -47,6 +46,7 @@ ecm_add_qml_module(timeline GENERATE_PLUGIN_SOURCE
PdfPreviewComponent.qml
PollComponent.qml
QuoteComponent.qml
ReactionComponent.qml
ReplyAuthorComponent.qml
ReplyButtonComponent.qml
ReplyComponent.qml

View File

@@ -14,7 +14,7 @@ import org.kde.neochat
/**
* @brief The base delegate for all messages in the timeline.
*
* This supports a message bubble plus sender avatar for each message as well as reactions
* This supports a message bubble plus sender avatar for each message
* and read markers. A date section can be show for when the message is on a different
* day to the previous one.
*
@@ -72,16 +72,6 @@ TimelineDelegate {
*/
required property bool showSection
/**
* @brief A model with the reactions to the message in.
*/
required property var reaction
/**
* @brief Whether the reaction component should be shown.
*/
required property bool showReactions
/**
* @brief A model with the first 5 other user read markers for this message.
*/
@@ -337,18 +327,6 @@ TimelineDelegate {
onLongPressed: _private.showMessageMenu()
}
}
ReactionDelegate {
Layout.maximumWidth: root.width - Kirigami.Units.largeSpacing * 2
Layout.alignment: _private.showUserMessageOnRight ? Qt.AlignRight : Qt.AlignLeft
Layout.leftMargin: _private.showUserMessageOnRight ? 0 : bubble.x + bubble.anchors.leftMargin
Layout.rightMargin: _private.showUserMessageOnRight ? Kirigami.Units.largeSpacing : 0
visible: root.showReactions
model: root.reaction
onReactionClicked: reaction => root.room.toggleReaction(root.eventId, reaction)
}
AvatarFlow {
Layout.alignment: Qt.AlignRight
Layout.rightMargin: Kirigami.Units.largeSpacing

View File

@@ -4,6 +4,7 @@
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
@@ -13,22 +14,36 @@ Flow {
id: root
/**
* @brief The reaction model to get the reactions from.
* @brief The NeoChatRoom the delegate is being displayed in.
*/
property alias model: reactionRepeater.model
required property NeoChatRoom room
/**
* @brief The given reaction has been clicked.
*
* Thrown when one of the reaction buttons in the flow is clicked.
* @brief The matrix ID of the message event.
*/
signal reactionClicked(string reaction)
required property string eventId
/**
* @brief The reaction model to get the reactions from.
*/
required property ReactionModel reactionModel
/**
* @brief The maximum width that the bubble's content can be.
*/
property real maxContentWidth: -1
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumWidth: root.maxContentWidth
spacing: Kirigami.Units.smallSpacing
Repeater {
id: reactionRepeater
model: root.reactionModel
delegate: QQC2.AbstractButton {
id: reactionDelegate
@@ -54,9 +69,9 @@ Flow {
padding: Kirigami.Units.smallSpacing
background: Kirigami.ShadowedRectangle {
color: reactionDelegate.hasLocalMember ? Kirigami.Theme.positiveBackgroundColor : Kirigami.Theme.backgroundColor
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: NeoChatConfig.compactLayout ? Kirigami.Theme.Window : Kirigami.Theme.View
Kirigami.Theme.colorSet: NeoChatConfig.compactLayout ? Kirigami.Theme.View : Kirigami.Theme.Window
color: reactionDelegate.hasLocalMember ? Kirigami.Theme.positiveBackgroundColor : Kirigami.Theme.backgroundColor
radius: height / 2
shadow {
size: Kirigami.Units.smallSpacing
@@ -64,7 +79,7 @@ Flow {
}
}
onClicked: reactionClicked(reactionDelegate.reaction)
onClicked: root.room.toggleReaction(root.eventId, reactionDelegate.reaction)
hoverEnabled: true
@@ -73,4 +88,53 @@ Flow {
QQC2.ToolTip.text: reactionDelegate.toolTip
}
}
QQC2.AbstractButton {
id: reactButton
width: Math.round(Kirigami.Units.gridUnit * 1.5)
height: Math.round(Kirigami.Units.gridUnit * 1.5)
text: i18nc("@button", "React")
contentItem: Kirigami.Icon {
source: "list-add"
}
padding: Kirigami.Units.smallSpacing
background: Rectangle {
color: Kirigami.Theme.backgroundColor
radius: height / 2
border {
width: reactButton.hovered ? 1 : 0
color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, Kirigami.Theme.frameContrast)
}
}
onClicked: {
var dialog = emojiDialog.createObject(reactButton);
dialog.chosen.connect(emoji => {
root.room.toggleReaction(root.eventId, emoji);
if (!Kirigami.Settings.isMobile) {
root.focusChatBar();
}
});
dialog.open();
}
hoverEnabled: true
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: reactButton.text
}
Component {
id: emojiDialog
EmojiDialog {
currentRoom: root.room
showQuickReaction: true
}
}
}