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

@@ -0,0 +1,140 @@
// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: GPL-3.0-only
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
Flow {
id: root
/**
* @brief The NeoChatRoom the delegate is being displayed in.
*/
required property NeoChatRoom room
/**
* @brief The matrix ID of the message event.
*/
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
required property string textContent
required property string reaction
required property string toolTip
required property bool hasLocalMember
width: Math.max(contentItem.implicitWidth + leftPadding + rightPadding, height)
height: Math.round(Kirigami.Units.gridUnit * 1.5)
contentItem: QQC2.Label {
id: reactionLabel
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: reactionDelegate.textContent
background: null
wrapMode: TextEdit.NoWrap
textFormat: Text.RichText
}
padding: Kirigami.Units.smallSpacing
background: Kirigami.ShadowedRectangle {
Kirigami.Theme.inherit: false
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
color: !reactionDelegate.hasLocalMember ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
}
}
onClicked: root.room.toggleReaction(root.eventId, reactionDelegate.reaction)
hoverEnabled: true
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
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
}
}
}