refactor: (BREAKING) Replace Event.relationshipType
and Event.relationshipEventId with Event.inReplyToEventId() for replies. This fixes the situation that an event can be a reply and in a thread. Before we have seen reply as an relationshipType but this does conflict with the concept of threads, where an event can be of relationship type "thread" but also be a reply with being a fallback or not.
This commit is contained in:
parent
42964f388f
commit
1365cbffe5
|
|
@ -32,7 +32,6 @@ import 'package:matrix/src/utils/markdown.dart';
|
||||||
import 'package:matrix/src/utils/multipart_request_progress.dart';
|
import 'package:matrix/src/utils/multipart_request_progress.dart';
|
||||||
|
|
||||||
abstract class RelationshipTypes {
|
abstract class RelationshipTypes {
|
||||||
static const String reply = 'm.in_reply_to';
|
|
||||||
static const String edit = 'm.replace';
|
static const String edit = 'm.replace';
|
||||||
static const String reaction = 'm.annotation';
|
static const String reaction = 'm.annotation';
|
||||||
static const String reference = 'm.reference';
|
static const String reference = 'm.reference';
|
||||||
|
|
@ -490,31 +489,13 @@ class Event extends MatrixEvent {
|
||||||
/// event fallback if the relationship type is `m.thread`.
|
/// event fallback if the relationship type is `m.thread`.
|
||||||
/// https://spec.matrix.org/v1.14/client-server-api/#fallback-for-unthreaded-clients
|
/// https://spec.matrix.org/v1.14/client-server-api/#fallback-for-unthreaded-clients
|
||||||
Future<Event?> getReplyEvent(Timeline timeline) async {
|
Future<Event?> getReplyEvent(Timeline timeline) async {
|
||||||
switch (relationshipType) {
|
final relationshipEventId = content
|
||||||
case RelationshipTypes.reply:
|
.tryGetMap<String, Object?>('m.relates_to')
|
||||||
final relationshipEventId = this.relationshipEventId;
|
?.tryGetMap<String, Object?>('m.in_reply_to')
|
||||||
return relationshipEventId == null
|
?.tryGet<String>('event_id');
|
||||||
? null
|
return relationshipEventId == null
|
||||||
: await timeline.getEventById(relationshipEventId);
|
? 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
|
/// If this event is encrypted and the decryption was not successful because
|
||||||
|
|
@ -1021,30 +1002,30 @@ class Event extends MatrixEvent {
|
||||||
return transactionId == search;
|
return transactionId == search;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the relationship type of an event. `null` if there is none
|
/// Get the relationship type of an event. `null` if there is none.
|
||||||
String? get relationshipType {
|
String? get relationshipType => content
|
||||||
final mRelatesTo = content.tryGetMap<String, Object?>('m.relates_to');
|
.tryGetMap<String, Object?>('m.relates_to')
|
||||||
if (mRelatesTo == null) {
|
?.tryGet<String>('rel_type');
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final relType = mRelatesTo.tryGet<String>('rel_type');
|
|
||||||
if (relType == RelationshipTypes.thread) {
|
|
||||||
return RelationshipTypes.thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mRelatesTo.containsKey('m.in_reply_to')) {
|
/// Get the event ID that this relationship will reference and `null` if there
|
||||||
return RelationshipTypes.reply;
|
/// is none. This could for example be the thread root, the original event for
|
||||||
}
|
/// an edit or the event, this is an reaction for. For replies please use
|
||||||
return relType;
|
/// `Event.inReplyToEventId()` instead!
|
||||||
}
|
String? get relationshipEventId => content
|
||||||
|
.tryGetMap<String, Object?>('m.relates_to')
|
||||||
|
?.tryGet<String>('event_id');
|
||||||
|
|
||||||
/// Get the event ID that this relationship will reference. `null` if there is none
|
/// If this event is in reply to another event, this returns the event ID or
|
||||||
String? get relationshipEventId {
|
/// null if this event is not a reply.
|
||||||
final relatesToMap = content.tryGetMap<String, Object?>('m.relates_to');
|
String? inReplyToEventId({bool includingFallback = true}) {
|
||||||
return relatesToMap?.tryGet<String>('event_id') ??
|
final isFallback = content
|
||||||
relatesToMap
|
.tryGetMap<String, Object?>('m.relates_to')
|
||||||
?.tryGetMap<String, Object?>('m.in_reply_to')
|
?.tryGet<bool>('is_falling_back');
|
||||||
?.tryGet<String>('event_id');
|
if (isFallback == true && !includingFallback) return null;
|
||||||
|
return content
|
||||||
|
.tryGetMap<String, Object?>('m.relates_to')
|
||||||
|
?.tryGetMap<String, Object?>('m.in_reply_to')
|
||||||
|
?.tryGet<String>('event_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get whether this event has aggregated events from a certain [type]
|
/// Get whether this event has aggregated events from a certain [type]
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ void main() async {
|
||||||
expect(event.formattedText, formatted_body);
|
expect(event.formattedText, formatted_body);
|
||||||
expect(event.body, body);
|
expect(event.body, body);
|
||||||
expect(event.type, EventTypes.Message);
|
expect(event.type, EventTypes.Message);
|
||||||
expect(event.relationshipType, RelationshipTypes.reply);
|
expect(event.inReplyToEventId(), '\$1234:example.com');
|
||||||
jsonObj['state_key'] = '';
|
jsonObj['state_key'] = '';
|
||||||
final state = Event.fromJson(jsonObj, room);
|
final state = Event.fromJson(jsonObj, room);
|
||||||
expect(state.eventId, id);
|
expect(state.eventId, id);
|
||||||
|
|
@ -178,8 +178,8 @@ void main() async {
|
||||||
};
|
};
|
||||||
event = Event.fromJson(jsonObj, room);
|
event = Event.fromJson(jsonObj, room);
|
||||||
expect(event.messageType, MessageTypes.Text);
|
expect(event.messageType, MessageTypes.Text);
|
||||||
expect(event.relationshipType, RelationshipTypes.reply);
|
expect(event.inReplyToEventId(), '1234');
|
||||||
expect(event.relationshipEventId, '1234');
|
expect(event.relationshipEventId, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('relationship types', () async {
|
test('relationship types', () async {
|
||||||
|
|
@ -212,8 +212,22 @@ void main() async {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
event = Event.fromJson(jsonObj, room);
|
event = Event.fromJson(jsonObj, room);
|
||||||
expect(event.relationshipType, RelationshipTypes.reply);
|
expect(event.inReplyToEventId(), 'def');
|
||||||
expect(event.relationshipEventId, 'def');
|
expect(event.relationshipEventId, null);
|
||||||
|
|
||||||
|
jsonObj['content']['m.relates_to'] = {
|
||||||
|
'rel_type': 'm.thread',
|
||||||
|
'event_id': '\$root',
|
||||||
|
'm.in_reply_to': {
|
||||||
|
'event_id': '\$target',
|
||||||
|
},
|
||||||
|
'is_falling_back': true,
|
||||||
|
};
|
||||||
|
event = Event.fromJson(jsonObj, room);
|
||||||
|
expect(event.relationshipType, RelationshipTypes.thread);
|
||||||
|
expect(event.inReplyToEventId(), '\$target');
|
||||||
|
expect(event.inReplyToEventId(includingFallback: false), null);
|
||||||
|
expect(event.relationshipEventId, '\$root');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('redact', () async {
|
test('redact', () async {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue