From 80192ae18faf993e0e4883c6e4a199d8235be6df Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Wed, 2 Aug 2023 18:09:12 -0700 Subject: [PATCH] api: Add reaction/add and reaction/remove events (not yet handled) Ongoing discussion about how to handle these: https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/flutter.3A.20reaction.20events/near/1619282 But for now, at least we can represent the events in the API model, before we handle them. Related: #121 --- lib/api/model/events.dart | 75 +++++++++++++++++++++++++++++++++++++ lib/api/model/events.g.dart | 49 ++++++++++++++++++++++++ lib/model/store.dart | 6 +++ 3 files changed, 130 insertions(+) diff --git a/lib/api/model/events.dart b/lib/api/model/events.dart index 47aa24256b4..a53b8204ac4 100644 --- a/lib/api/model/events.dart +++ b/lib/api/model/events.dart @@ -33,6 +33,12 @@ sealed class Event { case 'message': return MessageEvent.fromJson(json); case 'update_message': return UpdateMessageEvent.fromJson(json); case 'delete_message': return DeleteMessageEvent.fromJson(json); + case 'reaction': + switch (json['op'] as String) { + case 'add': return ReactionAddEvent.fromJson(json); + case 'remove': return ReactionRemoveEvent.fromJson(json); + default: return UnexpectedEvent.fromJson(json); + } case 'heartbeat': return HeartbeatEvent.fromJson(json); // TODO add many more event types default: return UnexpectedEvent.fromJson(json); @@ -370,6 +376,75 @@ enum MessageType { private; } +/// A Zulip event of type `reaction`. +abstract class ReactionEvent extends Event { + @override + @JsonKey(includeToJson: true) + String get type => 'reaction'; + + String get op; + + ReactionEvent({required super.id}); +} + +/// A [ReactionEvent] with op `add`: https://zulip.com/api/get-events#reaction-add +@JsonSerializable(fieldRename: FieldRename.snake) +class ReactionAddEvent extends ReactionEvent { + @override + String get op => 'add'; + + final String emojiName; + final String emojiCode; + final ReactionType reactionType; + final int userId; + // final Map user; // deprecated; ignore + final int messageId; + + ReactionAddEvent({ + required super.id, + required this.emojiName, + required this.emojiCode, + required this.reactionType, + required this.userId, + required this.messageId, + }); + + factory ReactionAddEvent.fromJson(Map json) => + _$ReactionAddEventFromJson(json); + + @override + Map toJson() => _$ReactionAddEventToJson(this); +} + +/// A [ReactionEvent] with op `remove`: https://zulip.com/api/get-events#reaction-remove +@JsonSerializable(fieldRename: FieldRename.snake) +class ReactionRemoveEvent extends ReactionEvent { + @override + String get op => 'remove'; + + final String emojiName; + final String emojiCode; + final ReactionType reactionType; + final int userId; + // final Map user; // deprecated; ignore + final int messageId; + + ReactionRemoveEvent({ + required super.id, + required this.emojiName, + required this.emojiCode, + required this.reactionType, + required this.userId, + required this.messageId, + }); + + factory ReactionRemoveEvent.fromJson(Map json) => + _$ReactionRemoveEventFromJson(json); + + @override + Map toJson() => _$ReactionRemoveEventToJson(this); +} + /// A Zulip event of type `heartbeat`: https://zulip.com/api/get-events#heartbeat @JsonSerializable(fieldRename: FieldRename.snake) class HeartbeatEvent extends Event { diff --git a/lib/api/model/events.g.dart b/lib/api/model/events.g.dart index 68aa0c4c7a9..38eb71a0d25 100644 --- a/lib/api/model/events.g.dart +++ b/lib/api/model/events.g.dart @@ -209,6 +209,55 @@ const _$MessageTypeEnumMap = { MessageType.private: 'private', }; +ReactionAddEvent _$ReactionAddEventFromJson(Map json) => + ReactionAddEvent( + id: json['id'] as int, + emojiName: json['emoji_name'] as String, + emojiCode: json['emoji_code'] as String, + reactionType: $enumDecode(_$ReactionTypeEnumMap, json['reaction_type']), + userId: json['user_id'] as int, + messageId: json['message_id'] as int, + ); + +Map _$ReactionAddEventToJson(ReactionAddEvent instance) => + { + 'id': instance.id, + 'type': instance.type, + 'emoji_name': instance.emojiName, + 'emoji_code': instance.emojiCode, + 'reaction_type': _$ReactionTypeEnumMap[instance.reactionType]!, + 'user_id': instance.userId, + 'message_id': instance.messageId, + }; + +const _$ReactionTypeEnumMap = { + ReactionType.unicodeEmoji: 'unicode_emoji', + ReactionType.realmEmoji: 'realm_emoji', + ReactionType.zulipExtraEmoji: 'zulip_extra_emoji', +}; + +ReactionRemoveEvent _$ReactionRemoveEventFromJson(Map json) => + ReactionRemoveEvent( + id: json['id'] as int, + emojiName: json['emoji_name'] as String, + emojiCode: json['emoji_code'] as String, + reactionType: $enumDecode(_$ReactionTypeEnumMap, json['reaction_type']), + userId: json['user_id'] as int, + messageId: json['message_id'] as int, + ); + +Map _$ReactionRemoveEventToJson( + ReactionRemoveEvent instance) => + { + 'id': instance.id, + 'type': instance.type, + 'emoji_name': instance.emojiName, + 'emoji_code': instance.emojiCode, + 'reaction_type': _$ReactionTypeEnumMap[instance.reactionType]!, + 'user_id': instance.userId, + 'message_id': instance.messageId, + }; + HeartbeatEvent _$HeartbeatEventFromJson(Map json) => HeartbeatEvent( id: json['id'] as int, diff --git a/lib/model/store.dart b/lib/model/store.dart index f5121f3da82..53011a19438 100644 --- a/lib/model/store.dart +++ b/lib/model/store.dart @@ -278,6 +278,12 @@ class PerAccountStore extends ChangeNotifier { } else if (event is DeleteMessageEvent) { assert(debugLog("server event: delete_message ${event.messageIds}")); // TODO handle + } else if (event is ReactionAddEvent) { + assert(debugLog("server event: reaction/add")); + // TODO handle + } else if (event is ReactionRemoveEvent) { + assert(debugLog("server event: reaction/remove")); + // TODO handle } else if (event is UnexpectedEvent) { assert(debugLog("server event: ${jsonEncode(event.toJson())}")); // TODO log better } else {