diff --git a/lib/models/content/content.dart b/lib/models/content/content.dart index dbe3695..2896049 100644 --- a/lib/models/content/content.dart +++ b/lib/models/content/content.dart @@ -1,3 +1,4 @@ +import "package:collection/collection.dart"; import "package:nexus/models/content/avatar.dart"; import "package:nexus/models/content/canonical_alias.dart"; import "package:nexus/models/content/create.dart"; @@ -9,30 +10,36 @@ import "package:nexus/models/content/name.dart"; import "package:nexus/models/content/pinned_events.dart"; import "package:nexus/models/content/power_levels.dart"; import "package:nexus/models/content/reaction.dart"; +import "package:nexus/models/content/encrypted.dart"; import "package:nexus/models/content/redaction.dart"; import "package:nexus/models/content/server_acl.dart"; import "package:nexus/models/content/topic.dart"; class Content { - final String? parseError; + final Error? parseError; Content({this.parseError}); factory Content.fromJson(Map json) => Content(); Map toJson() => {}; - static Content fromEventJson(Map eventJson, String type) { + static Map readValue(Map json, _) => + json["decrypted"] ?? json["content"]; + + static Content fromEventJson(Map json, String type) { try { - return EventType.values - .firstWhere((eventType) => eventType.type == type) - .contentFromJson(eventJson); + return (EventType.values + .firstWhereOrNull((eventType) => eventType.type == type) + ?.contentFromJson ?? + Content.fromJson)(json); } catch (error) { - return Content(parseError: error.toString()); + if (error is Error) return Content(parseError: error); + rethrow; } } } enum EventType { - encrypted("m.room.encrypted", Content.fromJson), + encrypted("m.room.encrypted", EncryptedContent.fromJson), redaction("m.room.redaction", RedactionContent.fromJson), encryption("m.room.encryption", EncryptionContent.fromJson), membership("m.room.member", MembershipContent.fromJson), diff --git a/lib/models/content/encrypted.dart b/lib/models/content/encrypted.dart new file mode 100644 index 0000000..b33a440 --- /dev/null +++ b/lib/models/content/encrypted.dart @@ -0,0 +1,13 @@ +import "package:freezed_annotation/freezed_annotation.dart"; +import "package:nexus/models/content/content.dart"; +part "encrypted.freezed.dart"; +part "encrypted.g.dart"; + +@freezed +abstract class EncryptedContent extends Content with _$EncryptedContent { + EncryptedContent._(); + factory EncryptedContent() = _EncryptedContent; + + factory EncryptedContent.fromJson(Map json) => + _$EncryptedContentFromJson(json); +} diff --git a/lib/models/content/reaction.dart b/lib/models/content/reaction.dart index 0361df8..7a3d714 100644 --- a/lib/models/content/reaction.dart +++ b/lib/models/content/reaction.dart @@ -3,13 +3,14 @@ import "package:nexus/models/content/content.dart"; part "reaction.freezed.dart"; part "reaction.g.dart"; -String? keyFromJson(Map json) => json["m.relates_to"]?["key"]; +String? keyFromJson(Map json) => json["key"]; @freezed abstract class ReactionContent extends Content with _$ReactionContent { ReactionContent._(); - factory ReactionContent({@JsonKey(fromJson: keyFromJson) String? key}) = - _ReactionContent; + factory ReactionContent({ + @JsonKey(fromJson: keyFromJson, name: "m.relates_to") String? key, + }) = _ReactionContent; factory ReactionContent.fromJson(Map json) => _$ReactionContentFromJson(json); diff --git a/lib/models/event.dart b/lib/models/event.dart index d77911b..3d9c0f6 100644 --- a/lib/models/event.dart +++ b/lib/models/event.dart @@ -6,24 +6,25 @@ import "package:nexus/models/profile.dart"; part "event.freezed.dart"; part "event.g.dart"; -Profile? pmpFromJson(Map? json) { - final pmp = json?["content"]?["com.beeper.per_message_profile"]; - return pmp == null ? null : Profile.fromJsonWithCatch(pmp); -} - @freezed abstract class Event with _$Event { + static Profile? pmpFromJson(Map? json) { + final pmp = json?["content"]?["com.beeper.per_message_profile"]; + return pmp == null ? null : Profile.fromJsonWithCatch(pmp); + } + + static String typeJsonFromJson(Map json, _) => + json["decrypted_type"] ?? json["type"]; + const factory Event({ @JsonKey(name: "rowid") required int rowId, @JsonKey(name: "timeline_rowid") required int timelineRowId, required String roomId, required String eventId, required String sender, - required String type, + @JsonKey(readValue: Event.typeJsonFromJson) required String type, String? stateKey, @EpochDateTimeConverter() required DateTime timestamp, - IMap? decrypted, - String? decryptedType, @Default(IMap.empty()) IMap unsigned, LocalContent? localContent, String? transactionId, @@ -35,13 +36,16 @@ abstract class Event with _$Event { @Default(IMap.empty()) IMap reactions, @JsonKey(name: "last_edit_rowid") int? lastEditRowId, @UnreadTypeConverter() UnreadType? unreadType, - @JsonKey(fromJson: pmpFromJson) Profile? pmp, + @JsonKey(fromJson: Event.pmpFromJson) Profile? pmp, @JsonKey(fromJson: Content.fromJson) required Content content, }) = _Event; factory Event.fromJson(Map json) => _$EventFromJson(json).copyWith( - content: Content.fromEventJson(json["content"], json["type"] as String), + content: Content.fromEventJson( + json["decrypted"] ?? json["content"], + json["decrypted_type"] ?? json["type"], + ), ); } diff --git a/lib/widgets/chat_page/render_event.dart b/lib/widgets/chat_page/render_event.dart index 99c9f04..5e9c78c 100644 --- a/lib/widgets/chat_page/render_event.dart +++ b/lib/widgets/chat_page/render_event.dart @@ -13,6 +13,7 @@ import "package:nexus/helpers/extensions/show_context_menu.dart"; import "package:nexus/helpers/launch_helper.dart"; import "package:nexus/models/content/avatar.dart"; import "package:nexus/models/content/content.dart"; +import "package:nexus/models/content/encrypted.dart"; import "package:nexus/models/content/message.dart"; import "package:nexus/models/event.dart"; import "package:nexus/widgets/chat_page/expandable_image.dart"; @@ -62,6 +63,11 @@ class RenderEvent extends ConsumerWidget { ); final child = switch (event.content) { + Content(:final parseError?) => SelectableText( + "An error occurred while parsing this event:\n$parseError", + style: errorStyle, + ), + EncryptedContent() => Text("Unable to decrypt event"), MessageContent() => Row( crossAxisAlignment: CrossAxisAlignment.start, spacing: 8, @@ -119,10 +125,6 @@ class RenderEvent extends ConsumerWidget { // EventText(replyEvent textOnly: true, maxLines: 1,) // ), switch (event.content) { - Content(:final parseError?) => SelectableText( - "An error occurred while parsing this message:\n$parseError", - style: errorStyle, - ), TextMessageContent( :final body, :final formattedBody, diff --git a/pubspec.lock b/pubspec.lock index 01a7833..19869cc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -720,7 +720,7 @@ packages: source: hosted version: "3.0.2" linkify: - dependency: "direct overridden" + dependency: "direct main" description: path: "." ref: "fix/consecutive-periods-loose-url" diff --git a/pubspec.yaml b/pubspec.yaml index dd7f365..56412f7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,11 +54,12 @@ dependencies: timeago: 3.7.1 http: 1.6.0 flutter_linkify: 6.0.0 + linkify: 5.0.0 emoji_text_field: git: url: https://github.com/Henry-Hiles/emoji_text_field - flutter_blurhash: ^0.9.1 - super_sliver_list: ^0.4.1 + flutter_blurhash: 0.9.1 + super_sliver_list: 0.4.1 dev_dependencies: build_runner: 2.15.0