import 'package:json_annotation/json_annotation.dart'; import '../../../../extensions/date_time.dart'; import '../../../api_response.dart'; import '../../../json_lenient.dart'; import '../room/get_room_response.dart'; part 'get_chat_response.g.dart'; @JsonSerializable(explicitToJson: true) class GetChatResponse extends ApiResponse { @JsonKey(fromJson: _messagesFromJson) Set data; GetChatResponse(this.data); factory GetChatResponse.fromJson(Map json) => _$GetChatResponseFromJson(json); Map toJson() => _$GetChatResponseToJson(this); List sortByTimestamp() { var sorted = data.toList(); sorted.sort((a, b) => a.timestamp.compareTo(b.timestamp)); return sorted; } } Set _messagesFromJson(Object? raw) => decodeSetLenient(raw, GetChatResponseObject.fromJson, what: 'message'); @JsonSerializable(explicitToJson: true) class GetChatResponseObject { int id; String token; @JsonKey(unknownEnumValue: GetRoomResponseObjectMessageActorType.unknown) GetRoomResponseObjectMessageActorType actorType; String actorId; String actorDisplayName; int timestamp; String systemMessage; @JsonKey(unknownEnumValue: GetRoomResponseObjectMessageType.unknown) GetRoomResponseObjectMessageType messageType; bool isReplyable; String referenceId; String message; Map? reactions; List? reactionsSelf; @JsonKey(fromJson: _fromJson) Map? messageParameters; /// The quoted message. When the original is no longer available (expired, /// purged) the server only sends `{id, deleted: true}`; that becomes a /// deleted-comment placeholder so the quote still renders. @JsonKey(fromJson: _parentFromJson) GetChatResponseObject? parent; /// Whether the server flagged this message to be rendered as Markdown /// (capability `markdown-messages`). Absent on older servers/messages, in /// which case it stays `false` and the body renders as plain text. bool markdown; GetChatResponseObject( this.id, this.token, this.actorType, this.actorId, this.actorDisplayName, this.timestamp, this.systemMessage, this.messageType, this.isReplyable, this.referenceId, this.message, this.messageParameters, this.reactions, this.reactionsSelf, this.parent, [ this.markdown = false, ]); factory GetChatResponseObject.fromJson(Map json) => _$GetChatResponseObjectFromJson(json); Map toJson() => _$GetChatResponseObjectToJson(this); /// [timestamp] is in seconds. DateTime get sentAt => DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); static GetChatResponseObject getDateDummy(int timestamp) => getTextDummy( DateTime.fromMillisecondsSinceEpoch( timestamp * 1000, ).formatDateRelativeShort(), ); static GetChatResponseObject deletedPlaceholder(int id) => GetChatResponseObject( id, '', GetRoomResponseObjectMessageActorType.user, '', '', 0, '', GetRoomResponseObjectMessageType.deletedComment, false, '', 'Nachricht wurde gelöscht', null, null, null, null, ); static GetChatResponseObject getTextDummy(String text) => GetChatResponseObject( 0, '', GetRoomResponseObjectMessageActorType.user, '', '', 0, '', GetRoomResponseObjectMessageType.system, false, '', text, null, null, null, null, ); } GetChatResponseObject? _parentFromJson(Object? json) { if (json is! Map) return null; if (json['deleted'] == true) { return GetChatResponseObject.deletedPlaceholder( (json['id'] as num?)?.toInt() ?? 0, ); } return GetChatResponseObject.fromJson(json); } Map? _fromJson(dynamic json) { if (json is Map) { final data = {}; for (final entry in json.entries) { final value = entry.value; if (value is Map) { data[entry.key] = RichObjectString.fromJson(value); } } return data; } return null; } @JsonSerializable(explicitToJson: true) class RichObjectString { @JsonKey(unknownEnumValue: RichObjectStringObjectType.unknown) RichObjectStringObjectType type; String id; String name; String? path; String? link; RichObjectString(this.type, this.id, this.name, this.path, this.link); factory RichObjectString.fromJson(Map json) => _$RichObjectStringFromJson(json); Map toJson() => _$RichObjectStringToJson(this); } enum RichObjectStringObjectType { @JsonValue('user') user, @JsonValue('group') group, @JsonValue('file') file, @JsonValue('guest') guest, @JsonValue('highlight') highlight, @JsonValue('talk-poll') talkPoll, @JsonValue('geo-location') geoLocation, @JsonValue('call') call, @JsonValue('user-group') userGroup, @JsonValue('circle') circle, @JsonValue('email') email, /// Anything else (deck cards, contacts, calendar events, ...); the /// placeholder still resolves to the object's name. unknown, }