diff --git a/packages/stream_feed/lib/src/core/models/index.dart b/packages/stream_feed/lib/src/core/models/index.dart index 84fc44e6b..11399d6fa 100644 --- a/packages/stream_feed/lib/src/core/models/index.dart +++ b/packages/stream_feed/lib/src/core/models/index.dart @@ -16,6 +16,7 @@ export 'following.dart'; export 'foreign_id_time_pair.dart'; export 'group.dart'; export 'lookup_attribute.dart'; +export 'mark_read_seen.dart'; export 'notification_feed_meta.dart'; export 'open_graph_data.dart'; export 'reaction.dart'; diff --git a/packages/stream_feed/lib/src/core/models/mark_read_seen.dart b/packages/stream_feed/lib/src/core/models/mark_read_seen.dart new file mode 100644 index 000000000..9c121aa89 --- /dev/null +++ b/packages/stream_feed/lib/src/core/models/mark_read_seen.dart @@ -0,0 +1,60 @@ +import 'package:equatable/equatable.dart'; +import 'package:meta/meta.dart'; + +enum ReadState { all, current, ids } + +class MarkRead extends Equatable { + final List? ids; + final ReadState readState; + const MarkRead({this.ids, this.readState = ReadState.ids}); + + factory MarkRead.fromJson(dynamic markRead) { + MarkRead? result; + if (markRead is List) { + result = MarkRead( + ids: List.from(markRead.map((x) => x)), + ); + } + if (markRead is String) { + result = MarkRead( + readState: markRead == 'all' ? ReadState.all : ReadState.current, + ); + } + return result!; + } + + Map toJson() => { + "mark_read": readState == ReadState.ids ? ids : readState.name, + }; + + @override + List get props => [ids, readState]; +} + +class MarkSeen extends Equatable { + final List? ids; + final ReadState readState; + const MarkSeen({this.ids, this.readState = ReadState.ids}); + + factory MarkSeen.fromJson(dynamic markSeen) { + MarkSeen? result; + if (markSeen is List) { + result = MarkSeen( + ids: List.from(markSeen.map((x) => x)), + ); + } + if (markSeen is String) { + result = MarkSeen( + readState: markSeen == 'all' ? ReadState.all : ReadState.current, + ); + } + return result!; + } + + Map toJson() => { + "mark_seen": readState == ReadState.ids ? ids : readState.name, + }; + + @override + List get props => [ids, readState]; +} diff --git a/packages/stream_feed/lib/src/core/models/realtime_message.dart b/packages/stream_feed/lib/src/core/models/realtime_message.dart index 48e63bd1e..9c46476f1 100644 --- a/packages/stream_feed/lib/src/core/models/realtime_message.dart +++ b/packages/stream_feed/lib/src/core/models/realtime_message.dart @@ -1,6 +1,11 @@ import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; +import 'package:stream_feed/src/core/models/feed_id.dart'; + +import 'package:stream_feed/src/core/models/foreign_id_time_pair.dart'; +import 'package:stream_feed/src/core/models/mark_read_seen.dart'; +import 'package:stream_feed/src/core/util/mark_read_seen_converter.dart'; import 'package:stream_feed/src/core/util/utc_converter.dart'; import 'package:stream_feed/stream_feed.dart'; @@ -22,16 +27,19 @@ part 'realtime_message.g.dart'; /// or `latest_reactions` @JsonSerializable(genericArgumentFactories: true) @DateTimeUTCConverter() +@MarkReadConverter() +@MarkSeenConverter() class RealtimeMessage extends Equatable { /// Builds a [RealtimeMessage]. - const RealtimeMessage({ - required this.feed, - this.deleted = const [], - this.deletedForeignIds = const [], - this.newActivities, - this.appId, - this.publishedAt, - }); + const RealtimeMessage( + {required this.feed, + this.deleted = const [], + this.deletedForeignIds = const [], + this.newActivities, + this.appId, + this.publishedAt, + this.markRead, + this.markSeen}); /// Create a new instance from a JSON object factory RealtimeMessage.fromJson( @@ -68,6 +76,9 @@ class RealtimeMessage extends Equatable { }, ); + final MarkSeen? markSeen; + final MarkRead? markRead; + /// Name of the feed this update was published on @JsonKey(toJson: FeedId.toId, fromJson: FeedId.fromId) final FeedId? feed; diff --git a/packages/stream_feed/lib/src/core/models/realtime_message.g.dart b/packages/stream_feed/lib/src/core/models/realtime_message.g.dart index 664952a19..59086b0ee 100644 --- a/packages/stream_feed/lib/src/core/models/realtime_message.g.dart +++ b/packages/stream_feed/lib/src/core/models/realtime_message.g.dart @@ -33,6 +33,10 @@ RealtimeMessage _$RealtimeMessageFromJson( publishedAt: json['published_at'] == null ? null : DateTime.parse(json['published_at'] as String), + markRead: + json['mark_read'] == null ? null : MarkRead.fromJson(json['mark_read']), + markSeen: + json['mark_seen'] == null ? null : MarkSeen.fromJson(json['mark_seen']), ); } @@ -44,6 +48,8 @@ Map _$RealtimeMessageToJson( Object? Function(Or value) toJsonOr, ) { final val = { + 'mark_seen': instance.markSeen?.toJson(), + 'mark_read': instance.markRead?.toJson(), 'feed': FeedId.toId(instance.feed), }; diff --git a/packages/stream_feed/lib/src/core/util/mark_read_seen_converter.dart b/packages/stream_feed/lib/src/core/util/mark_read_seen_converter.dart new file mode 100644 index 000000000..bc6fe9cc1 --- /dev/null +++ b/packages/stream_feed/lib/src/core/util/mark_read_seen_converter.dart @@ -0,0 +1,24 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:stream_feed/src/core/models/mark_read_seen.dart'; + +class MarkReadConverter implements JsonConverter { + const MarkReadConverter(); + + @override + MarkRead fromJson(dynamic json) => MarkRead.fromJson(json); + + @override + Map toJson(MarkRead markRead) => + markRead.toJson(); //formatDateWithOffset(json); +} + +class MarkSeenConverter implements JsonConverter { + const MarkSeenConverter(); + + @override + MarkSeen fromJson(dynamic json) => MarkSeen.fromJson(json); + + @override + Map toJson(MarkSeen markSeen) => + markSeen.toJson(); //formatDateWithOffset(json); +} diff --git a/packages/stream_feed/test/fixtures/realtime_message_issue193-bis.json b/packages/stream_feed/test/fixtures/realtime_message_issue193-bis.json new file mode 100644 index 000000000..a1226048d --- /dev/null +++ b/packages/stream_feed/test/fixtures/realtime_message_issue193-bis.json @@ -0,0 +1,6 @@ +{ + "new": [], + "deleted": [], + "deleted_foreign_ids": [], + "mark_read": "all" +} \ No newline at end of file diff --git a/packages/stream_feed/test/fixtures/realtime_message_issue193.json b/packages/stream_feed/test/fixtures/realtime_message_issue193.json new file mode 100644 index 000000000..2822f3274 --- /dev/null +++ b/packages/stream_feed/test/fixtures/realtime_message_issue193.json @@ -0,0 +1,8 @@ +{ + "new": [], + "deleted": [], + "deleted_foreign_ids": [], + "mark_read": [ + "123" + ] +} \ No newline at end of file diff --git a/packages/stream_feed/test/models_test.dart b/packages/stream_feed/test/models_test.dart index 0dbf605db..8fa4a3806 100644 --- a/packages/stream_feed/test/models_test.dart +++ b/packages/stream_feed/test/models_test.dart @@ -2,6 +2,12 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:stream_feed/src/core/models/follow_relation.dart'; +import 'package:stream_feed/src/core/models/follow_stats.dart'; +import 'package:stream_feed/src/core/models/followers.dart'; +import 'package:stream_feed/src/core/models/following.dart'; +import 'package:stream_feed/src/core/models/group.dart'; +import 'package:stream_feed/src/core/models/mark_read_seen.dart'; +import 'package:stream_feed/src/core/models/notification_feed_meta.dart'; import 'package:stream_feed/src/core/models/paginated_reactions.dart'; import 'package:stream_feed/src/core/models/personalized_feed.dart'; import 'package:stream_feed/src/core/util/utc_converter.dart'; @@ -155,6 +161,17 @@ void main() { ); }); + test('issue-193', () { + final fixture = RealtimeMessage.fromJson( + jsonFixture('realtime_message_issue193.json')); + expect(fixture.markRead, MarkRead(ids: ["123"])); + }); + + test('issue-193-bis', () { + final fixture = RealtimeMessage.fromJson( + jsonFixture('realtime_message_issue193-bis.json')); + expect(fixture.markRead, MarkRead(readState: ReadState.all)); + }); test('issue-89', () { final fixture = RealtimeMessage.fromJson( jsonFixture('realtime_message_issue89.json'),