feat: Support fallback for threads in Event.getReplyEvent()

This commit is contained in:
Krille 2025-05-08 09:59:20 +02:00 committed by Christian Pauly
parent aefd690125
commit 35b352e8c1
No known key found for this signature in database
GPG Key ID: E067ECD60F1A0652
2 changed files with 72 additions and 6 deletions

View File

@ -481,13 +481,35 @@ class Event extends MatrixEvent {
Future<String?> redactEvent({String? reason, String? txid}) async =>
await room.redactEvent(eventId, reason: reason, txid: txid);
/// Searches for the reply event in the given timeline.
/// Searches for the reply event in the given timeline. Also returns the
/// event fallback if the relationship type is `m.thread`.
/// https://spec.matrix.org/v1.14/client-server-api/#fallback-for-unthreaded-clients
Future<Event?> getReplyEvent(Timeline timeline) async {
if (relationshipType != RelationshipTypes.reply) return null;
final relationshipEventId = this.relationshipEventId;
return relationshipEventId == null
? null
: await timeline.getEventById(relationshipEventId);
switch (relationshipType) {
case RelationshipTypes.reply:
final relationshipEventId = this.relationshipEventId;
return relationshipEventId == null
? null
: await timeline.getEventById(relationshipEventId);
case RelationshipTypes.thread:
final relationshipContent =
content.tryGetMap<String, Object?>('m.relates_to');
if (relationshipContent == null) return null;
final String? relationshipEventId;
if (relationshipContent.tryGet<bool>('is_falling_back') == true) {
relationshipEventId = relationshipContent
.tryGetMap<String, Object?>('m.in_reply_to')
?.tryGet<String>('event_id');
} else {
relationshipEventId = this.relationshipEventId;
}
return relationshipEventId == null
? null
: await timeline.getEventById(relationshipEventId);
default:
return null;
}
}
/// If this event is encrypted and the decryption was not successful because

View File

@ -2862,5 +2862,49 @@ void main() {
matrixEvent.toJson(),
);
});
test('getReplyEvent fallback', () async {
final event = Event.fromJson(
{
'content': {
'msgtype': 'text',
'body': 'Hello world',
'm.relates_to': {
'rel_type': 'm.thread',
'event_id': '\$root',
'm.in_reply_to': {'event_id': '\$target'},
'is_falling_back': true,
},
},
'event_id': '\$143273582443PhrSn:example.org',
'origin_server_ts': 1432735824653,
'room_id': room.id,
'sender': '@example:example.org',
'type': 'm.room.message',
'unsigned': {'age': 1234},
'redacts': 'abcd',
'prev_content': <String, Object?>{
'foo': 'bar',
},
},
room,
);
expect(event.relationshipType, RelationshipTypes.thread);
expect(event.relationshipEventId, '\$root');
final targetEvent = Event(
eventId: '\$target',
senderId: '@example:example.org',
type: 'm.room.message',
content: {
'msgtype': 'text',
'body': 'Hello world',
},
originServerTs: DateTime.now(),
room: room,
);
final timeline =
Timeline(room: room, chunk: TimelineChunk(events: [targetEvent]));
expect(await event.getReplyEvent(timeline), targetEvent);
});
});
}