From de3e1c9862a044f1dda59a01837e01e128f313d9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 19 May 2022 18:07:22 +0530 Subject: [PATCH] refactor(llc): convert the implementation into non-breaking Signed-off-by: xsahil03x --- .../lib/src/core/models/channel_model.dart | 48 +++++-- .../lib/src/core/models/channel_model.g.dart | 8 -- .../lib/src/core/models/event.dart | 4 + .../lib/src/core/models/event.g.dart | 3 + .../lib/src/core/models/own_user.dart | 6 +- .../stream_chat/lib/src/core/models/user.dart | 7 +- .../test/src/core/models/channel_test.dart | 136 ++++++++++++++++++ 7 files changed, 182 insertions(+), 30 deletions(-) diff --git a/packages/stream_chat/lib/src/core/models/channel_model.dart b/packages/stream_chat/lib/src/core/models/channel_model.dart index 9fca07b5..942b9e63 100644 --- a/packages/stream_chat/lib/src/core/models/channel_model.dart +++ b/packages/stream_chat/lib/src/core/models/channel_model.dart @@ -22,12 +22,12 @@ class ChannelModel { DateTime? updatedAt, this.deletedAt, this.memberCount = 0, - this.extraData = const {}, + Map extraData = const {}, this.team, this.cooldown = 0, - this.disabled = false, - this.hidden = false, - this.truncatedAt, + bool? disabled, + bool? hidden, + DateTime? truncatedAt, }) : assert( (cid != null && cid.contains(':')) || (id != null && type != null), 'provide either a cid or an id and type', @@ -37,7 +37,18 @@ class ChannelModel { cid = cid ?? '$type:$id', config = config ?? ChannelConfig(), createdAt = createdAt ?? DateTime.now(), - updatedAt = updatedAt ?? DateTime.now(); + updatedAt = updatedAt ?? DateTime.now(), + + // TODO: Make them top-level fields in v5 + // For backwards compatibility, set 'disabled', 'hidden' + // and 'truncated_at' in [extraData]. + extraData = { + ...extraData, + if (disabled != null) 'disabled': disabled, + if (hidden != null) 'hidden': hidden, + if (truncatedAt != null) + 'truncated_at': truncatedAt.toIso8601String(), + }; /// Create a new instance from a json factory ChannelModel.fromJson(Map json) => @@ -96,13 +107,20 @@ class ChannelModel { final int cooldown; /// True if the channel is disabled - final bool disabled; + @JsonKey(ignore: true) + bool? get disabled => extraData['disabled'] as bool?; /// True if the channel is hidden - final bool hidden; + @JsonKey(ignore: true) + bool? get hidden => extraData['hidden'] as bool?; /// The date of the last time channel got truncated - final DateTime? truncatedAt; + @JsonKey(ignore: true) + DateTime? get truncatedAt { + final truncatedAt = extraData['truncated_at'] as String?; + if (truncatedAt == null) return null; + return DateTime.parse(truncatedAt); + } /// Map of custom channel extraData @JsonKey(includeIfNull: false) @@ -129,9 +147,6 @@ class ChannelModel { 'member_count', 'team', 'cooldown', - 'disabled', - 'hidden', - 'truncated_at', ]; /// Shortcut for channel name @@ -180,9 +195,14 @@ class ChannelModel { extraData: extraData ?? this.extraData, team: team ?? this.team, cooldown: cooldown ?? this.cooldown, - disabled: disabled ?? this.disabled, - hidden: hidden ?? this.hidden, - truncatedAt: truncatedAt ?? this.truncatedAt, + disabled: disabled ?? extraData?['disabled'] as bool? ?? this.disabled, + hidden: hidden ?? extraData?['hidden'] as bool? ?? this.hidden, + truncatedAt: truncatedAt ?? + (extraData?['truncated_at'] == null + ? null + // ignore: cast_nullable_to_non_nullable + : DateTime.parse(extraData?['truncated_at'] as String)) ?? + this.truncatedAt, ); /// Returns a new [ChannelModel] that is a combination of this channelModel diff --git a/packages/stream_chat/lib/src/core/models/channel_model.g.dart b/packages/stream_chat/lib/src/core/models/channel_model.g.dart index ee888ae7..9bd8f062 100644 --- a/packages/stream_chat/lib/src/core/models/channel_model.g.dart +++ b/packages/stream_chat/lib/src/core/models/channel_model.g.dart @@ -36,11 +36,6 @@ ChannelModel _$ChannelModelFromJson(Map json) => ChannelModel( extraData: json['extra_data'] as Map? ?? const {}, team: json['team'] as String?, cooldown: json['cooldown'] as int? ?? 0, - disabled: json['disabled'] as bool? ?? false, - hidden: json['hidden'] as bool? ?? false, - truncatedAt: json['truncated_at'] == null - ? null - : DateTime.parse(json['truncated_at'] as String), ); Map _$ChannelModelToJson(ChannelModel instance) { @@ -66,9 +61,6 @@ Map _$ChannelModelToJson(ChannelModel instance) { writeNotNull('deleted_at', readonly(instance.deletedAt)); writeNotNull('member_count', readonly(instance.memberCount)); val['cooldown'] = instance.cooldown; - val['disabled'] = instance.disabled; - val['hidden'] = instance.hidden; - val['truncated_at'] = instance.truncatedAt?.toIso8601String(); val['extra_data'] = instance.extraData; writeNotNull('team', readonly(instance.team)); return val; diff --git a/packages/stream_chat/lib/src/core/models/event.dart b/packages/stream_chat/lib/src/core/models/event.dart index 47270d40..13aec2b9 100644 --- a/packages/stream_chat/lib/src/core/models/event.dart +++ b/packages/stream_chat/lib/src/core/models/event.dart @@ -180,6 +180,7 @@ class EventChannel extends ChannelModel { super.id, super.type, required String super.cid, + super.ownCapabilities, required ChannelConfig super.config, super.createdBy, super.frozen, @@ -191,6 +192,9 @@ class EventChannel extends ChannelModel { Map? extraData, super.cooldown, super.team, + super.disabled, + super.hidden, + super.truncatedAt, }) : super(extraData: extraData ?? {}); /// Create a new instance from a json diff --git a/packages/stream_chat/lib/src/core/models/event.g.dart b/packages/stream_chat/lib/src/core/models/event.g.dart index d3a531fe..524b5bd9 100644 --- a/packages/stream_chat/lib/src/core/models/event.g.dart +++ b/packages/stream_chat/lib/src/core/models/event.g.dart @@ -81,6 +81,9 @@ EventChannel _$EventChannelFromJson(Map json) => EventChannel( id: json['id'] as String?, type: json['type'] as String?, cid: json['cid'] as String, + ownCapabilities: (json['own_capabilities'] as List?) + ?.map((e) => e as String) + .toList(), config: ChannelConfig.fromJson(json['config'] as Map), createdBy: json['created_by'] == null ? null diff --git a/packages/stream_chat/lib/src/core/models/own_user.dart b/packages/stream_chat/lib/src/core/models/own_user.dart index 85b6ba57..783b9371 100644 --- a/packages/stream_chat/lib/src/core/models/own_user.dart +++ b/packages/stream_chat/lib/src/core/models/own_user.dart @@ -76,10 +76,8 @@ class OwnUser extends User { OwnUser( id: id ?? this.id, role: role ?? this.role, - // if null, it will be retrieved from extraData['name'] - name: name, - // if null, it will be retrieved from extraData['image'] - image: image, + name: name ?? extraData?['name'] as String? ?? this.name, + image: image ?? extraData?['image'] as String? ?? this.image, banned: banned ?? this.banned, banExpires: banExpires ?? this.banExpires, createdAt: createdAt ?? this.createdAt, diff --git a/packages/stream_chat/lib/src/core/models/user.dart b/packages/stream_chat/lib/src/core/models/user.dart index 0d19d59d..2c702d01 100644 --- a/packages/stream_chat/lib/src/core/models/user.dart +++ b/packages/stream_chat/lib/src/core/models/user.dart @@ -46,6 +46,7 @@ class User extends Equatable { this.language, }) : createdAt = createdAt ?? DateTime.now(), updatedAt = updatedAt ?? DateTime.now(), + // TODO: Make them top-level fields in v5 // For backwards compatibility, set 'name', 'image' in [extraData]. extraData = { ...extraData, @@ -171,10 +172,8 @@ class User extends Equatable { User( id: id ?? this.id, role: role ?? this.role, - // if null, it will be retrieved from extraData['name'] - name: name, - // if null, it will be retrieved from extraData['image'] - image: image, + name: name ?? extraData?['name'] as String? ?? this.name, + image: image ?? extraData?['image'] as String? ?? this.image, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, lastActive: lastActive ?? this.lastActive, diff --git a/packages/stream_chat/test/src/core/models/channel_test.dart b/packages/stream_chat/test/src/core/models/channel_test.dart index e27f5970..e67c185e 100644 --- a/packages/stream_chat/test/src/core/models/channel_test.dart +++ b/packages/stream_chat/test/src/core/models/channel_test.dart @@ -55,4 +55,140 @@ void main() { ); }); }); + + test('hidden property and extraData manipulation', () { + final channel = ChannelModel(cid: 'test:cid', hidden: false); + + expect(channel.hidden, false); + expect(channel.extraData['hidden'], false); + print(channel.toJson()); + expect(channel.toJson(), { + 'id': 'cid', + 'type': 'test', + 'frozen': false, + 'cooldown': 0, + 'hidden': false, + }); + expect(ChannelModel.fromJson(channel.toJson()).toJson(), { + 'id': 'cid', + 'type': 'test', + 'frozen': false, + 'cooldown': 0, + 'hidden': false, + }); + + var newChannel = channel.copyWith( + extraData: {'hidden': true}, + ); + + expect(newChannel.extraData['hidden'], true); + expect(newChannel.hidden, true); + + newChannel = channel.copyWith( + hidden: false, + ); + + expect(newChannel.extraData['hidden'], false); + expect(newChannel.hidden, false); + + newChannel = channel.copyWith( + hidden: true, + extraData: {'hidden': true}, + ); + + expect(newChannel.extraData['hidden'], true); + expect(newChannel.hidden, true); + }); + + test('disabled property and extraData manipulation', () { + final channel = ChannelModel(cid: 'test:cid', disabled: false); + + expect(channel.disabled, false); + expect(channel.extraData['disabled'], false); + print(channel.toJson()); + expect(channel.toJson(), { + 'id': 'cid', + 'type': 'test', + 'frozen': false, + 'cooldown': 0, + 'disabled': false, + }); + expect(ChannelModel.fromJson(channel.toJson()).toJson(), { + 'id': 'cid', + 'type': 'test', + 'frozen': false, + 'cooldown': 0, + 'disabled': false, + }); + + var newChannel = channel.copyWith( + extraData: {'disabled': true}, + ); + + expect(newChannel.extraData['disabled'], true); + expect(newChannel.disabled, true); + + newChannel = channel.copyWith( + hidden: false, + ); + + expect(newChannel.extraData['disabled'], false); + expect(newChannel.disabled, false); + + newChannel = channel.copyWith( + hidden: true, + extraData: {'disabled': true}, + ); + + expect(newChannel.extraData['disabled'], true); + expect(newChannel.disabled, true); + }); + + test('truncatedAt property and extraData manipulation', () { + final currentDate = DateTime.now(); + final channel = ChannelModel(cid: 'test:cid', truncatedAt: currentDate); + + expect(channel.truncatedAt, currentDate); + expect(channel.extraData['truncated_at'], currentDate.toIso8601String()); + print(channel.toJson()); + expect(channel.toJson(), { + 'id': 'cid', + 'type': 'test', + 'frozen': false, + 'cooldown': 0, + 'truncated_at': currentDate.toIso8601String(), + }); + expect(ChannelModel.fromJson(channel.toJson()).toJson(), { + 'id': 'cid', + 'type': 'test', + 'frozen': false, + 'cooldown': 0, + 'truncated_at': currentDate.toIso8601String(), + }); + + final dateOne = DateTime.now(); + var newChannel = channel.copyWith( + extraData: {'truncated_at': dateOne.toIso8601String()}, + ); + + expect(newChannel.extraData['truncated_at'], dateOne.toIso8601String()); + expect(newChannel.truncatedAt, dateOne); + + final dateTwo = DateTime.now(); + newChannel = channel.copyWith( + truncatedAt: dateTwo, + ); + + expect(newChannel.extraData['truncated_at'], dateTwo.toIso8601String()); + expect(newChannel.truncatedAt, dateTwo); + + final dateThree = DateTime.now(); + newChannel = channel.copyWith( + truncatedAt: dateThree, + extraData: {'truncated_at': dateThree.toIso8601String()}, + ); + + expect(newChannel.extraData['truncated_at'], dateThree.toIso8601String()); + expect(newChannel.truncatedAt, dateThree); + }); }