Fix reactions
This commit is contained in:
parent
6f2bc908ba
commit
19f27236ea
@ -34,7 +34,7 @@ Flow {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + " in room " + reactionFlow.roomId + ". selfReactedEvent: " + modelData.selfReactedEvent)
|
console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + " in room " + reactionFlow.roomId + ". selfReactedEvent: " + modelData.selfReactedEvent)
|
||||||
timelineManager.reactToMessage(reactionFlow.roomId, reactionFlow.eventId, modelData.key, modelData.selfReactedEvent)
|
timelineManager.queueReactionMessage(reactionFlow.eventId, modelData.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,7 +90,6 @@ MouseArea {
|
|||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: qsTr("React")
|
ToolTip.text: qsTr("React")
|
||||||
emojiPicker: emojiPopup
|
emojiPicker: emojiPopup
|
||||||
room_id: model.roomId
|
|
||||||
event_id: model.id
|
event_id: model.id
|
||||||
}
|
}
|
||||||
ImageButton {
|
ImageButton {
|
||||||
|
@ -40,19 +40,20 @@ Page {
|
|||||||
id: messageContextMenu
|
id: messageContextMenu
|
||||||
modal: true
|
modal: true
|
||||||
|
|
||||||
function show(eventId_, eventType_, isEncrypted_, showAt) {
|
function show(eventId_, eventType_, isEncrypted_, showAt_) {
|
||||||
eventId = eventId_
|
eventId = eventId_
|
||||||
eventType = eventType_
|
eventType = eventType_
|
||||||
isEncrypted = isEncrypted_
|
isEncrypted = isEncrypted_
|
||||||
popup(showAt)
|
popup(showAt_)
|
||||||
}
|
}
|
||||||
|
|
||||||
property string eventId
|
property string eventId
|
||||||
property int eventType
|
property int eventType
|
||||||
property bool isEncrypted
|
property bool isEncrypted
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: qsTr("React")
|
text: qsTr("React")
|
||||||
onClicked: chat.model.reactAction(messageContextMenu.eventId)
|
onClicked: emojiPopup.show(messageContextMenu.parent, messageContextMenu.eventId)
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: qsTr("Reply")
|
text: qsTr("Reply")
|
||||||
|
@ -8,11 +8,10 @@ import "../"
|
|||||||
ImageButton {
|
ImageButton {
|
||||||
property var colors: currentActivePalette
|
property var colors: currentActivePalette
|
||||||
property var emojiPicker
|
property var emojiPicker
|
||||||
property string room_id
|
|
||||||
property string event_id
|
property string event_id
|
||||||
|
|
||||||
image: ":/icons/icons/ui/smile.png"
|
image: ":/icons/icons/ui/smile.png"
|
||||||
id: emojiButton
|
id: emojiButton
|
||||||
onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.show(emojiButton, room_id, event_id)
|
onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.show(emojiButton, event_id)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,17 @@ import "../"
|
|||||||
|
|
||||||
Popup {
|
Popup {
|
||||||
|
|
||||||
function show(showAt, room_id, event_id) {
|
function show(showAt, event_id) {
|
||||||
console.debug("Showing emojiPicker for " + event_id + "in room " + room_id)
|
console.debug("Showing emojiPicker for " + event_id)
|
||||||
|
if (showAt){
|
||||||
parent = showAt
|
parent = showAt
|
||||||
x = Math.round((showAt.width - width) / 2)
|
x = Math.round((showAt.width - width) / 2)
|
||||||
y = showAt.height
|
y = showAt.height
|
||||||
emojiPopup.room_id = room_id
|
}
|
||||||
emojiPopup.event_id = event_id
|
emojiPopup.event_id = event_id
|
||||||
open()
|
open()
|
||||||
}
|
}
|
||||||
|
|
||||||
property string room_id
|
|
||||||
property string event_id
|
property string event_id
|
||||||
property var colors
|
property var colors
|
||||||
property alias model: gridView.model
|
property alias model: gridView.model
|
||||||
@ -102,9 +102,9 @@ Popup {
|
|||||||
}
|
}
|
||||||
// TODO: maybe add favorites at some point?
|
// TODO: maybe add favorites at some point?
|
||||||
onClicked: {
|
onClicked: {
|
||||||
console.debug("Picked " + model.unicode + "in response to " + emojiPopup.event_id + " in room " + emojiPopup.room_id)
|
console.debug("Picked " + model.unicode + "in response to " + emojiPopup.event_id)
|
||||||
emojiPopup.close()
|
emojiPopup.close()
|
||||||
timelineManager.queueReactionMessage(emojiPopup.room_id, emojiPopup.event_id, model.unicode)
|
timelineManager.queueReactionMessage(emojiPopup.event_id, model.unicode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +223,20 @@ struct EventInReplyTo
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EventRelatesTo
|
||||||
|
{
|
||||||
|
template<class Content>
|
||||||
|
using related_ev_id_t = decltype(Content::relates_to.event_id);
|
||||||
|
template<class T>
|
||||||
|
std::string operator()(const mtx::events::Event<T> &e)
|
||||||
|
{
|
||||||
|
if constexpr (is_detected<related_ev_id_t, T>::value) {
|
||||||
|
return e.content.relates_to.event_id;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct EventTransactionId
|
struct EventTransactionId
|
||||||
{
|
{
|
||||||
template<class T>
|
template<class T>
|
||||||
@ -378,6 +392,11 @@ mtx::accessors::in_reply_to_event(const mtx::events::collections::TimelineEvents
|
|||||||
{
|
{
|
||||||
return std::visit(EventInReplyTo{}, event);
|
return std::visit(EventInReplyTo{}, event);
|
||||||
}
|
}
|
||||||
|
std::string
|
||||||
|
mtx::accessors::relates_to_event_id(const mtx::events::collections::TimelineEvents &event)
|
||||||
|
{
|
||||||
|
return std::visit(EventRelatesTo{}, event);
|
||||||
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
mtx::accessors::transaction_id(const mtx::events::collections::TimelineEvents &event)
|
mtx::accessors::transaction_id(const mtx::events::collections::TimelineEvents &event)
|
||||||
|
@ -53,6 +53,8 @@ mimetype(const mtx::events::collections::TimelineEvents &event);
|
|||||||
std::string
|
std::string
|
||||||
in_reply_to_event(const mtx::events::collections::TimelineEvents &event);
|
in_reply_to_event(const mtx::events::collections::TimelineEvents &event);
|
||||||
std::string
|
std::string
|
||||||
|
relates_to_event_id(const mtx::events::collections::TimelineEvents &event);
|
||||||
|
std::string
|
||||||
transaction_id(const mtx::events::collections::TimelineEvents &event);
|
transaction_id(const mtx::events::collections::TimelineEvents &event);
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
|
@ -202,6 +202,20 @@ EventStore::handleSync(const mtx::responses::Timeline &events)
|
|||||||
if (auto redaction =
|
if (auto redaction =
|
||||||
std::get_if<mtx::events::RedactionEvent<mtx::events::msg::Redaction>>(
|
std::get_if<mtx::events::RedactionEvent<mtx::events::msg::Redaction>>(
|
||||||
&event)) {
|
&event)) {
|
||||||
|
// fixup reactions
|
||||||
|
auto redacted = events_by_id_.object({room_id_, redaction->redacts});
|
||||||
|
if (redacted) {
|
||||||
|
auto id = mtx::accessors::relates_to_event_id(*redacted);
|
||||||
|
if (!id.empty()) {
|
||||||
|
auto idx = idToIndex(id);
|
||||||
|
if (idx) {
|
||||||
|
events_by_id_.remove(
|
||||||
|
{room_id_, redaction->redacts});
|
||||||
|
emit dataChanged(*idx, *idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
relates_to = redaction->redacts;
|
relates_to = redaction->redacts;
|
||||||
} else if (auto reaction =
|
} else if (auto reaction =
|
||||||
std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(
|
std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(
|
||||||
|
@ -1069,8 +1069,9 @@ struct SendMessageVisitor
|
|||||||
// reactions need to have the relation outside of ciphertext, or synapse / the homeserver
|
// reactions need to have the relation outside of ciphertext, or synapse / the homeserver
|
||||||
// cannot handle it correctly. See the MSC for more details:
|
// cannot handle it correctly. See the MSC for more details:
|
||||||
// https://github.com/matrix-org/matrix-doc/blob/matthew/msc1849/proposals/1849-aggregations.md#end-to-end-encryption
|
// https://github.com/matrix-org/matrix-doc/blob/matthew/msc1849/proposals/1849-aggregations.md#end-to-end-encryption
|
||||||
void operator()(const mtx::events::RoomEvent<mtx::events::msg::Reaction> &msg)
|
void operator()(mtx::events::RoomEvent<mtx::events::msg::Reaction> msg)
|
||||||
{
|
{
|
||||||
|
msg.type = mtx::events::EventType::Reaction;
|
||||||
emit model_->addPendingMessageToStore(msg);
|
emit model_->addPendingMessageToStore(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +197,15 @@ public:
|
|||||||
Q_INVOKABLE void cacheMedia(QString eventId);
|
Q_INVOKABLE void cacheMedia(QString eventId);
|
||||||
Q_INVOKABLE bool saveMedia(QString eventId) const;
|
Q_INVOKABLE bool saveMedia(QString eventId) const;
|
||||||
|
|
||||||
|
std::vector<::Reaction> reactions(const std::string &event_id)
|
||||||
|
{
|
||||||
|
auto list = events.reactions(event_id);
|
||||||
|
std::vector<::Reaction> vec;
|
||||||
|
for (const auto &r : list)
|
||||||
|
vec.push_back(r.value<Reaction>());
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
void updateLastMessage();
|
void updateLastMessage();
|
||||||
void addEvents(const mtx::responses::Timeline &events);
|
void addEvents(const mtx::responses::Timeline &events);
|
||||||
template<class T>
|
template<class T>
|
||||||
|
@ -314,33 +314,36 @@ TimelineViewManager::queueEmoteMessage(const QString &msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::reactToMessage(const QString &roomId,
|
TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey)
|
||||||
const QString &reactedEvent,
|
|
||||||
const QString &reactionKey,
|
|
||||||
const QString &selfReactedEvent)
|
|
||||||
{
|
{
|
||||||
|
if (!timeline_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto reactions = timeline_->reactions(reactedEvent.toStdString());
|
||||||
|
|
||||||
|
QString selfReactedEvent;
|
||||||
|
for (const auto &reaction : reactions) {
|
||||||
|
if (reactionKey == reaction.key_) {
|
||||||
|
selfReactedEvent = reaction.selfReactedEvent_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selfReactedEvent.startsWith("m"))
|
||||||
|
return;
|
||||||
|
|
||||||
// If selfReactedEvent is empty, that means we haven't previously reacted
|
// If selfReactedEvent is empty, that means we haven't previously reacted
|
||||||
if (selfReactedEvent.isEmpty()) {
|
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,
|
|
||||||
const QString &reactionKey)
|
|
||||||
{
|
|
||||||
mtx::events::msg::Reaction reaction;
|
mtx::events::msg::Reaction reaction;
|
||||||
reaction.relates_to.rel_type = mtx::common::RelationType::Annotation;
|
reaction.relates_to.rel_type = mtx::common::RelationType::Annotation;
|
||||||
reaction.relates_to.event_id = reactedEvent.toStdString();
|
reaction.relates_to.event_id = reactedEvent.toStdString();
|
||||||
reaction.relates_to.key = reactionKey.toStdString();
|
reaction.relates_to.key = reactionKey.toStdString();
|
||||||
|
|
||||||
auto model = models.value(roomId);
|
timeline_->sendMessage(reaction);
|
||||||
model->sendMessage(reaction);
|
// Otherwise, we have previously reacted and the reaction should be redacted
|
||||||
|
} else {
|
||||||
|
timeline_->redactEvent(selfReactedEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -61,13 +61,7 @@ public slots:
|
|||||||
|
|
||||||
void setHistoryView(const QString &room_id);
|
void setHistoryView(const QString &room_id);
|
||||||
void updateColorPalette();
|
void updateColorPalette();
|
||||||
void queueReactionMessage(const QString &roomId,
|
void queueReactionMessage(const QString &reactedEvent, const QString &reactionKey);
|
||||||
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 queueTextMessage(const QString &msg);
|
||||||
void queueEmoteMessage(const QString &msg);
|
void queueEmoteMessage(const QString &msg);
|
||||||
void queueImageMessage(const QString &roomid,
|
void queueImageMessage(const QString &roomid,
|
||||||
|
Loading…
Reference in New Issue
Block a user