From 66356202c045683299ebb48a7c52b1186e55111c Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Wed, 13 May 2026 15:45:34 -0400 Subject: [PATCH] good framework for content models --- lib/controllers/client_controller.dart | 6 ++++-- lib/controllers/message_controller.dart | 1 + lib/models/content/content.dart | 17 +++++++++++++++++ lib/models/content/encrypted.dart | 9 +++++++++ lib/models/content/membership.dart | 21 +++++++++++++++++++++ lib/models/content/message.dart | 15 +++++++++++++++ lib/models/event.dart | 10 +++++++++- lib/models/profile.dart | 7 ++++--- 8 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 lib/models/content/content.dart create mode 100644 lib/models/content/encrypted.dart create mode 100644 lib/models/content/membership.dart create mode 100644 lib/models/content/message.dart diff --git a/lib/controllers/client_controller.dart b/lib/controllers/client_controller.dart index bbadd8e..4787b60 100644 --- a/lib/controllers/client_controller.dart +++ b/lib/controllers/client_controller.dart @@ -231,8 +231,10 @@ class ClientController extends AsyncNotifier { Future paginate(PaginateRequest request) async => Paginate.fromJson(await _sendCommand("paginate", request.toJson())); - Future getProfile(String userId) async => - Profile.fromJson(await _sendCommand("get_profile", {"user_id": userId})); + Future getProfile(String userId) async => Profile.fromJson({ + ...(await _sendCommand("get_profile", {"user_id": userId})), + "id": userId, + }); Future reportEvent(ReportRequest request) => _sendCommand("report_event", request.toJson()); diff --git a/lib/controllers/message_controller.dart b/lib/controllers/message_controller.dart index 18bee2b..d52a835 100644 --- a/lib/controllers/message_controller.dart +++ b/lib/controllers/message_controller.dart @@ -123,6 +123,7 @@ class MessageController extends AsyncNotifier { text: "Unable to decrypt message.", metadata: {...metadata, "body": "Unable to decrypt message."}, ), + // "org.matrix.msc3381.poll.start" => Message.custom( // metadata: { // ...metadata, diff --git a/lib/models/content/content.dart b/lib/models/content/content.dart new file mode 100644 index 0000000..06ec328 --- /dev/null +++ b/lib/models/content/content.dart @@ -0,0 +1,17 @@ +import "package:nexus/models/content/encrypted.dart"; +import "package:nexus/models/content/membership.dart"; +import "package:nexus/models/content/message.dart"; + +class Content { + Content(); + factory Content.fromJson(Map json) => Content(); + + Map toJson() => {}; + static Content fromEventJson(Map eventJson) => + switch (eventJson["type"]) { + EncryptedContent.type => EncryptedContent.fromJson, + MembershipContent.type => MembershipContent.fromJson, + MessageContent.type => MessageContent.fromJson, + _ => Content.fromJson, + }(eventJson); +} diff --git a/lib/models/content/encrypted.dart b/lib/models/content/encrypted.dart new file mode 100644 index 0000000..0b575e7 --- /dev/null +++ b/lib/models/content/encrypted.dart @@ -0,0 +1,9 @@ +import "package:nexus/models/content/content.dart"; + +class EncryptedContent extends Content { + EncryptedContent(); + factory EncryptedContent.fromJson(Map json) => + EncryptedContent(); + + static const type = "m.room.encrypted"; +} diff --git a/lib/models/content/membership.dart b/lib/models/content/membership.dart new file mode 100644 index 0000000..39a645b --- /dev/null +++ b/lib/models/content/membership.dart @@ -0,0 +1,21 @@ +import "package:freezed_annotation/freezed_annotation.dart"; +import "package:nexus/models/content/content.dart"; +import "package:nexus/models/membership_status.dart"; +part "membership.freezed.dart"; +part "membership.g.dart"; + +@freezed +abstract class MembershipContent extends Content with _$MembershipContent { + static const type = "m.room.membership"; + + MembershipContent._(); + const factory MembershipContent({ + @JsonKey(name: "displayname") required String displayName, + required MembershipStatus membership, + required Uri? avatarUrl, + required String? reason, + }) = _MembershipContent; + + factory MembershipContent.fromJson(Map json) => + _$MembershipContentFromJson(json); +} diff --git a/lib/models/content/message.dart b/lib/models/content/message.dart new file mode 100644 index 0000000..629f21c --- /dev/null +++ b/lib/models/content/message.dart @@ -0,0 +1,15 @@ +import "package:freezed_annotation/freezed_annotation.dart"; +import "package:nexus/models/content/content.dart"; +part "message.freezed.dart"; +part "message.g.dart"; + +@freezed +abstract class MessageContent extends Content with _$MessageContent { + static const type = "m.room.message"; + + MessageContent._(); + const factory MessageContent({required String msgtype}) = _MessageContent; + + factory MessageContent.fromJson(Map json) => + _$MessageContentFromJson(json); +} diff --git a/lib/models/event.dart b/lib/models/event.dart index 4a72817..7fbf729 100644 --- a/lib/models/event.dart +++ b/lib/models/event.dart @@ -1,9 +1,16 @@ import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:freezed_annotation/freezed_annotation.dart"; +import "package:nexus/models/content/content.dart"; import "package:nexus/models/epoch_date_time_converter.dart"; +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.fromJson(pmp); +} + @freezed abstract class Event with _$Event { const factory Event({ @@ -15,7 +22,6 @@ abstract class Event with _$Event { required String type, String? stateKey, @EpochDateTimeConverter() required DateTime timestamp, - required IMap content, IMap? decrypted, String? decryptedType, @Default(IMap.empty()) IMap unsigned, @@ -29,6 +35,8 @@ 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: Content.fromJson) required Content content, }) = _Event; factory Event.fromJson(Map json) => _$EventFromJson(json); diff --git a/lib/models/profile.dart b/lib/models/profile.dart index 584f27b..f0937f7 100644 --- a/lib/models/profile.dart +++ b/lib/models/profile.dart @@ -12,13 +12,14 @@ Object? readTimezone(Map map, _) => @freezed abstract class Profile with _$Profile { const factory Profile({ - String? avatarUrl, + required String id, + Uri? avatarUrl, @JsonKey(name: "displayname") String? displayName, - @JsonKey(readValue: readTimezone) String? timezone, + @JsonKey(readValue: readTimezone, name: "m.tz") String? timezone, @Default(IList.empty()) - @JsonKey(readValue: readPronouns) + @JsonKey(readValue: readPronouns, name: "io.fsky.nyx.pronouns") IList pronouns, }) = _Profile;