diff --git a/resources/qml/Reactions.qml b/resources/qml/Reactions.qml index ac5efbd1..b272e2e6 100644 --- a/resources/qml/Reactions.qml +++ b/resources/qml/Reactions.qml @@ -1,7 +1,21 @@ import QtQuick 2.6 import QtQuick.Controls 2.2 +// This class is for showing Reactions in the timeline row, not for +// adding new reactions via the emoji picker Flow { + id: reactionFlow + // Signal for when a reaction is picked / unpicked + signal picked(string room_id, string event_id, string key, string selfReactedEvent) + + // highlight colors for selfReactedEvent background + property real highlightHue: colors.highlight.hslHue + property real highlightSat: colors.highlight.hslSaturation + property real highlightLight: colors.highlight.hslLightness + + property string eventId + property string roomId + anchors.left: parent.left anchors.right: parent.right spacing: 4 @@ -11,7 +25,7 @@ Flow { Repeater { id: repeater - AbstractButton { + delegate: AbstractButton { id: reaction hoverEnabled: true implicitWidth: contentItem.childrenRect.width + contentItem.leftPadding*2 @@ -20,6 +34,11 @@ Flow { ToolTip.visible: hovered ToolTip.text: model.users + onClicked: { + console.debug("Picked " + model.key + "in response to " + reactionFlow.eventId + " in room " + reactionFlow.roomId + ". selfReactedEvent: " + model.selfReactedEvent) + reactionFlow.picked(reactionFlow.roomId, reactionFlow.eventId, model.key, model.selfReactedEvent) + } + contentItem: Row { anchors.centerIn: parent @@ -48,7 +67,7 @@ Flow { id: divider height: reactionCounter.implicitHeight * 1.4 width: 1 - color: reaction.hovered ? colors.highlight : colors.text + color: (reaction.hovered || model.selfReactedEvent !== '') ? colors.highlight : colors.text } Text { @@ -62,10 +81,11 @@ Flow { background: Rectangle { anchors.centerIn: parent + implicitWidth: reaction.implicitWidth implicitHeight: reaction.implicitHeight - border.color: (reaction.hovered || model.selfReacted )? colors.highlight : colors.text - color: colors.base + border.color: (reaction.hovered || model.selfReactedEvent !== '') ? colors.highlight : colors.text + color: model.selfReactedEvent !== '' ? Qt.hsla(highlightHue, highlightSat, highlightLight, 0.20) : colors.base border.width: 1 radius: reaction.height / 2.0 } diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml index f2e3e12b..1f2f1615 100644 --- a/resources/qml/TimelineRow.qml +++ b/resources/qml/TimelineRow.qml @@ -59,7 +59,13 @@ MouseArea { } Reactions { + id: reactionRow reactions: model.reactions + roomId: model.roomId + eventId: model.id + Component.onCompleted: { + reactionRow.picked.connect(timelineManager.reactToMessage) + } } } diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 3da2f09c..e5359910 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -16,6 +16,9 @@ Page { property var systemInactive: SystemPalette { colorGroup: SystemPalette.Disabled } property var inactiveColors: currentInactivePalette ? currentInactivePalette : systemInactive property int avatarSize: 40 + property real highlightHue: colors.highlight.hslHue + property real highlightSat: colors.highlight.hslSaturation + property real highlightLight: colors.highlight.hslLightness palette: colors diff --git a/resources/qml/emoji/EmojiPicker.qml b/resources/qml/emoji/EmojiPicker.qml index 8618e63f..c416337d 100644 --- a/resources/qml/emoji/EmojiPicker.qml +++ b/resources/qml/emoji/EmojiPicker.qml @@ -27,6 +27,9 @@ Popup { property alias model: gridView.model property var textArea property string emojiCategory: "people" + property real highlightHue: colors.highlight.hslHue + property real highlightSat: colors.highlight.hslSaturation + property real highlightLight: colors.highlight.hslLightness id: emojiPopup @@ -39,6 +42,8 @@ Popup { focus: true closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + onPicked: emojiPopup.close() + ColumnLayout { id: columnView anchors.fill: parent @@ -98,7 +103,7 @@ Popup { color: "#80000000" source: parent.contentItem } - // TODO: emit a signal and maybe add favorites at some point? + // TODO: maybe add favorites at some point? onClicked: { console.debug("Picked " + model.unicode + "in response to " + emojiPopup.event_id + " in room " + emojiPopup.room_id) emojiPopup.picked(emojiPopup.room_id, emojiPopup.event_id, model.unicode) @@ -191,11 +196,8 @@ Popup { background: Rectangle { anchors.fill: parent - property real highlightHue: colors.highlight.hslHue - property real highlightSat: colors.highlight.hslSaturation - property real highlightLight: colors.highlight.hslLightness - color: emojiPopup.model.category === model.category ? Qt.hsla(highlightHue, highlightSat, highlightLight, 0.25) : 'transparent' + color: emojiPopup.model.category === model.category ? Qt.hsla(highlightHue, highlightSat, highlightLight, 0.20) : 'transparent' radius: 5 border.color: emojiPopup.model.category === model.category ? colors.highlight : 'transparent' } diff --git a/src/timeline/ReactionsModel.cpp b/src/timeline/ReactionsModel.cpp index 2e249819..1200e2ba 100644 --- a/src/timeline/ReactionsModel.cpp +++ b/src/timeline/ReactionsModel.cpp @@ -10,7 +10,7 @@ ReactionsModel::roleNames() const {Key, "key"}, {Count, "counter"}, {Users, "users"}, - {SelfReacted, "selfReacted"}, + {SelfReactedEvent, "selfReactedEvent"}, }; } @@ -45,11 +45,11 @@ ReactionsModel::data(const QModelIndex &index, int role) const } return users; } - case SelfReacted: + case SelfReactedEvent: for (const auto &reaction : reactions[i].reactions) if (reaction.second.sender == http::client()->user_id().to_string()) - return true; - return false; + return QString::fromStdString(reaction.second.event_id); + return QStringLiteral(""); default: return {}; } diff --git a/src/timeline/ReactionsModel.h b/src/timeline/ReactionsModel.h index 5f61cd42..c839afc8 100644 --- a/src/timeline/ReactionsModel.h +++ b/src/timeline/ReactionsModel.h @@ -18,7 +18,7 @@ public: Key, Count, Users, - SelfReacted, + SelfReactedEvent, }; QHash roleNames() const override; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 3f8a5b76..0375ccc8 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -290,6 +290,22 @@ TimelineViewManager::queueEmoteMessage(const QString &msg) timeline_->sendMessage(emote); } +void +TimelineViewManager::reactToMessage(const QString &roomId, + const QString &reactedEvent, + const QString &reactionKey, + const QString &selfReactedEvent) +{ + // If selfReactedEvent is empty, that means we haven't previously reacted + if (selfReactedEvent.isEmpty()) { + queueReactionMessage(roomId, reactedEvent, reactionKey); + // Otherwise, we have previously reacted and the reaction should be redacted + } else { + auto model = models.value(roomId); + model->redactEvent(selfReactedEvent); + } +} + void TimelineViewManager::queueReactionMessage(const QString &roomId, const QString &reactedEvent, diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index f5f57df4..48505bc0 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -61,6 +61,10 @@ public slots: void queueReactionMessage(const QString &roomId, const QString &reactedEvent, const QString &reaction); + void reactToMessage(const QString &roomId, + const QString &reactedEvent, + const QString &reactionKey, + const QString &selfReactedEvent); void queueTextMessage(const QString &msg); void queueEmoteMessage(const QString &msg); void queueImageMessage(const QString &roomid,