@@ -361,6 +361,8 @@ class Q_DECL_HIDDEN Room::Private {
361361
362362 bool isLocalUser (const User* u) const { return u == q->localUser (); }
363363
364+ void processRedactionsAndEdits (RoomEvents& events);
365+
364366#ifdef Quotient_E2EE_ENABLED
365367 UnorderedMap<QByteArray, QOlmInboundGroupSession> groupSessions;
366368 Omittable<QOlmOutboundGroupSession> currentOutboundMegolmSession = none;
@@ -2878,6 +2880,51 @@ inline bool isEditing(const RoomEventPtr& ep)
28782880 false );
28792881}
28802882
2883+ void Room::Private::processRedactionsAndEdits (RoomEvents& events)
2884+ {
2885+ // Pre-process redactions and edits so that events that get
2886+ // redacted/replaced in the same batch landed in the timeline already
2887+ // treated.
2888+ // NB: We have to store redacting/replacing events to the timeline too -
2889+ // see #220.
2890+ auto it = std::find_if (events.begin (), events.end (), isEditing);
2891+ for (const auto & eptr : RoomEventsRange (it, events.end ())) {
2892+ if (auto * r = eventCast<RedactionEvent>(eptr)) {
2893+ // Try to find the target in the timeline, then in the batch.
2894+ if (processRedaction (*r))
2895+ continue ;
2896+ if (auto targetIt = std::find_if (events.begin (), events.end (),
2897+ [id = r->redactedEvent ()](const RoomEventPtr& ep) {
2898+ return ep->id () == id;
2899+ }); targetIt != events.end ())
2900+ *targetIt = makeRedacted (**targetIt, *r);
2901+ else
2902+ qCDebug (STATE)
2903+ << " Redaction" << r->id () << " ignored: target event"
2904+ << r->redactedEvent () << " is not found" ;
2905+ // If the target event comes later, it comes already redacted.
2906+ }
2907+ if (auto * msg = eventCast<RoomMessageEvent>(eptr);
2908+ msg && !msg->replacedEvent ().isEmpty ()) {
2909+ if (processReplacement (*msg))
2910+ continue ;
2911+ auto targetIt = std::find_if (events.begin (), events.end (),
2912+ [id = msg->replacedEvent ()](const RoomEventPtr& ep) {
2913+ return ep->id () == id;
2914+ });
2915+ if (targetIt != events.end ())
2916+ *targetIt = makeReplaced (**targetIt, *msg);
2917+ else // FIXME: hide the replacing event when target arrives later
2918+ qCDebug (EVENTS)
2919+ << " Replacing event" << msg->id ()
2920+ << " ignored: target event" << msg->replacedEvent ()
2921+ << " is not found" ;
2922+ // Same as with redactions above, the replaced event coming
2923+ // later will come already with the new content.
2924+ }
2925+ }
2926+ }
2927+
28812928Room::Changes Room::Private::addNewMessageEvents (RoomEvents&& events)
28822929{
28832930 dropExtraneousEvents (events);
@@ -2889,49 +2936,7 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
28892936 QElapsedTimer et;
28902937 et.start ();
28912938
2892- {
2893- // Pre-process redactions and edits so that events that get
2894- // redacted/replaced in the same batch landed in the timeline already
2895- // treated.
2896- // NB: We have to store redacting/replacing events to the timeline too -
2897- // see #220.
2898- auto it = std::find_if (events.begin (), events.end (), isEditing);
2899- for (const auto & eptr : RoomEventsRange (it, events.end ())) {
2900- if (auto * r = eventCast<RedactionEvent>(eptr)) {
2901- // Try to find the target in the timeline, then in the batch.
2902- if (processRedaction (*r))
2903- continue ;
2904- if (auto targetIt = std::find_if (events.begin (), events.end (),
2905- [id = r->redactedEvent ()](const RoomEventPtr& ep) {
2906- return ep->id () == id;
2907- }); targetIt != events.end ())
2908- *targetIt = makeRedacted (**targetIt, *r);
2909- else
2910- qCDebug (STATE)
2911- << " Redaction" << r->id () << " ignored: target event"
2912- << r->redactedEvent () << " is not found" ;
2913- // If the target event comes later, it comes already redacted.
2914- }
2915- if (auto * msg = eventCast<RoomMessageEvent>(eptr);
2916- msg && !msg->replacedEvent ().isEmpty ()) {
2917- if (processReplacement (*msg))
2918- continue ;
2919- auto targetIt = std::find_if (events.begin (), it,
2920- [id = msg->replacedEvent ()](const RoomEventPtr& ep) {
2921- return ep->id () == id;
2922- });
2923- if (targetIt != it)
2924- *targetIt = makeReplaced (**targetIt, *msg);
2925- else // FIXME: hide the replacing event when target arrives later
2926- qCDebug (EVENTS)
2927- << " Replacing event" << msg->id ()
2928- << " ignored: target event" << msg->replacedEvent ()
2929- << " is not found" ;
2930- // Same as with redactions above, the replaced event coming
2931- // later will come already with the new content.
2932- }
2933- }
2934- }
2939+ processRedactionsAndEdits (events);
29352940
29362941 // State changes arrive as a part of timeline; the current room state gets
29372942 // updated before merging events to the timeline because that's what
@@ -3034,6 +3039,8 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events)
30343039
30353040 decryptIncomingEvents (events);
30363041
3042+ processRedactionsAndEdits (events);
3043+
30373044 QElapsedTimer et;
30383045 et.start ();
30393046 Changes changes {};
0 commit comments