From acd932ccc9dedc63ed0f6d3f7031ad935d6452c7 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Wed, 4 Aug 2021 16:42:01 +0200 Subject: [PATCH 1/7] feat: add image property to user --- .../lib/src/core/models/own_user.dart | 38 ++++--- .../lib/src/core/models/own_user.g.dart | 1 + .../stream_chat/lib/src/core/models/user.dart | 104 ++++++++++++++---- .../lib/src/core/models/user.g.dart | 4 +- .../lib/src/user_avatar.dart | 7 +- 5 files changed, 112 insertions(+), 42 deletions(-) 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 fb5b1caf..5adc753c 100644 --- a/packages/stream_chat/lib/src/core/models/own_user.dart +++ b/packages/stream_chat/lib/src/core/models/own_user.dart @@ -28,6 +28,7 @@ class OwnUser extends User { bool banned = false, List teams = const [], String? language, + String? image, }) : super( id: id, role: role, @@ -39,6 +40,7 @@ class OwnUser extends User { banned: banned, teams: teams, language: language, + image: image, ); /// Create a new instance from a json @@ -57,6 +59,7 @@ class OwnUser extends User { extraData: user.extraData, teams: user.teams, language: user.language, + image: user.image, ); /// Creates a copy of [OwnUser] with specified attributes overridden. @@ -77,24 +80,26 @@ class OwnUser extends User { int? totalUnreadCount, int? unreadChannels, String? language, + String? image, }) => OwnUser( - id: id ?? this.id, - banned: banned ?? this.banned, - role: role ?? this.role, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - lastActive: lastActive ?? this.lastActive, - online: online ?? this.online, - extraData: extraData ?? this.extraData, - teams: teams ?? this.teams, - channelMutes: channelMutes ?? this.channelMutes, - devices: devices ?? this.devices, - mutes: mutes ?? this.mutes, - totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, - unreadChannels: unreadChannels ?? this.unreadChannels, - language: language ?? this.language, - ); + id: id ?? this.id, + banned: banned ?? this.banned, + role: role ?? this.role, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastActive: lastActive ?? this.lastActive, + online: online ?? this.online, + extraData: extraData ?? this.extraData, + teams: teams ?? this.teams, + channelMutes: channelMutes ?? this.channelMutes, + devices: devices ?? this.devices, + mutes: mutes ?? this.mutes, + totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, + unreadChannels: unreadChannels ?? this.unreadChannels, + language: language ?? this.language, + image: image // if null, it will be retrieved from extraData['image'] + ); /// Returns a new [OwnUser] that is a combination of this ownUser /// and the given [other] ownUser. @@ -116,6 +121,7 @@ class OwnUser extends User { unreadChannels: other.unreadChannels, updatedAt: other.updatedAt, language: other.language, + image: other.image, ); } diff --git a/packages/stream_chat/lib/src/core/models/own_user.g.dart b/packages/stream_chat/lib/src/core/models/own_user.g.dart index ca4acdea..cacb99c5 100644 --- a/packages/stream_chat/lib/src/core/models/own_user.g.dart +++ b/packages/stream_chat/lib/src/core/models/own_user.g.dart @@ -40,5 +40,6 @@ OwnUser _$OwnUserFromJson(Map json) { (json['teams'] as List?)?.map((e) => e as String).toList() ?? [], language: json['language'] as String?, + image: json['image'] as String?, ); } diff --git a/packages/stream_chat/lib/src/core/models/user.dart b/packages/stream_chat/lib/src/core/models/user.dart index a7e7a51e..9baaf049 100644 --- a/packages/stream_chat/lib/src/core/models/user.dart +++ b/packages/stream_chat/lib/src/core/models/user.dart @@ -4,29 +4,45 @@ import 'package:stream_chat/src/core/util/serializer.dart'; part 'user.g.dart'; -/// The class that defines the user model +/// Class that defines a Stream Chat User. @JsonSerializable() class User extends Equatable { - /// Constructor used for json serialization + /// Creates a new user. + /// + /// If an [image] is provided it will be set on [extraData] with a `key` + /// of 'image'. + /// + /// For example: + /// ```dart + /// final user = User(id: 'id', image: 'https://getstream.io/image.png'); + /// print(user.image == user.extraData['image']); // true + /// ``` User({ required this.id, this.role, + String? image, DateTime? createdAt, DateTime? updatedAt, this.lastActive, + Map extraData = const {}, this.online = false, - this.extraData = const {}, this.banned = false, this.teams = const [], this.language, - }) : createdAt = createdAt ?? DateTime.now(), - updatedAt = updatedAt ?? DateTime.now(); + }) : _image = image, + createdAt = createdAt ?? DateTime.now(), + updatedAt = updatedAt ?? DateTime.now(), - /// Create a new instance from a json + // For backwards compatibalitity, set 'image' on [extraData]. + extraData = + (image != null) ? {...extraData, 'image': image} : extraData; + + /// Create a new instance from json. factory User.fromJson(Map json) => _$UserFromJson(Serializer.moveToExtraDataFromRoot(json, topLevelFields)); /// Known top level fields. + /// /// Useful for [Serializer] methods. static const topLevelFields = [ 'id', @@ -38,16 +54,64 @@ class User extends Equatable { 'banned', 'teams', 'language', + 'image', ]; - /// User id + /// User id. final String id; - /// User role + /// User role. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) final String? role; - /// User role + /// Image for user. This is also set on `extraData['image']`. + /// + /// {@template image} + /// There are a few ways to set an image. + /// + /// Setting an image by passing in an image argument: + /// ```dart + /// final user = User( + /// id: 'id', + /// image: 'https://getstream.io/image', + /// ); + /// ``` + /// + /// Or by directly setting it in [extraData], for example: + /// ```dart + /// final user = User( + /// id: 'id', + /// extraData: const {'image': 'https://getstream.io/image'}, + /// ); + /// + /// ``` + /// Parsing json with an 'image' key will automatically set the `image` + /// property and `extraData['image']` key/value. + /// + /// ```dart + /// final user = User.fromJson({ + /// id: 'id', + /// image: 'https://getstream.io/image', // key: image + /// }); + /// + /// print(user.image == user.extraData['image']); // true + /// ``` + /// {@endtemplate} + final String? _image; + + /// Shortcut for user image. + /// + /// {@macro image} + @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) + String? get image { + if (_image != null) { + return _image; + } else { + return extraData['image'] as String?; + } + } + + /// User teams @JsonKey( includeIfNull: false, toJson: Serializer.readOnly, @@ -55,29 +119,29 @@ class User extends Equatable { ) final List teams; - /// Date of user creation + /// Date of user creation. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) final DateTime createdAt; - /// Date of last user update + /// Date of last user update. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) final DateTime updatedAt; - /// Date of last user connection + /// Date of last user connection. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) final DateTime? lastActive; - /// True if user is online + /// True if user is online. @JsonKey( includeIfNull: false, toJson: Serializer.readOnly, defaultValue: false) final bool online; - /// True if user is banned from the chat + /// True if user is banned from the chat. @JsonKey( includeIfNull: false, toJson: Serializer.readOnly, defaultValue: false) final bool banned; - /// Map of custom user extraData + /// Map of custom user extraData. @JsonKey( includeIfNull: false, defaultValue: {}, @@ -85,12 +149,10 @@ class User extends Equatable { final Map extraData; /// The language this user prefers. - /// - /// Defaults to 'en'. @JsonKey(includeIfNull: false) final String? language; - /// Shortcut for user name + /// Shortcut for user name. String get name { if (extraData.containsKey('name')) { final name = extraData['name']! as String; @@ -99,11 +161,11 @@ class User extends Equatable { return id; } - /// List of users to list of userIds + /// List of users to list of userIds. static List? toIds(List? users) => users?.map((u) => u.id).toList(); - /// Serialize to json + /// Serialize to json. Map toJson() => Serializer.moveFromExtraDataToRoot( _$UserToJson(this), ); @@ -120,6 +182,7 @@ class User extends Equatable { bool? banned, List? teams, String? language, + String? image, }) => User( id: id ?? this.id, @@ -132,6 +195,7 @@ class User extends Equatable { banned: banned ?? this.banned, teams: teams ?? this.teams, language: language ?? this.language, + image: image, // if null, it will be retrieved from extraData['image'] ); @override diff --git a/packages/stream_chat/lib/src/core/models/user.g.dart b/packages/stream_chat/lib/src/core/models/user.g.dart index dd3183d5..c685cd57 100644 --- a/packages/stream_chat/lib/src/core/models/user.g.dart +++ b/packages/stream_chat/lib/src/core/models/user.g.dart @@ -10,6 +10,7 @@ User _$UserFromJson(Map json) { return User( id: json['id'] as String, role: json['role'] as String?, + image: json['image'] as String?, createdAt: json['created_at'] == null ? null : DateTime.parse(json['created_at'] as String), @@ -19,8 +20,8 @@ User _$UserFromJson(Map json) { lastActive: json['last_active'] == null ? null : DateTime.parse(json['last_active'] as String), - online: json['online'] as bool? ?? false, extraData: json['extra_data'] as Map? ?? {}, + online: json['online'] as bool? ?? false, banned: json['banned'] as bool? ?? false, teams: (json['teams'] as List?)?.map((e) => e as String).toList() ?? @@ -41,6 +42,7 @@ Map _$UserToJson(User instance) { } writeNotNull('role', readonly(instance.role)); + writeNotNull('image', readonly(instance.image)); writeNotNull('teams', readonly(instance.teams)); writeNotNull('created_at', readonly(instance.createdAt)); writeNotNull('updated_at', readonly(instance.updatedAt)); diff --git a/packages/stream_chat_flutter/lib/src/user_avatar.dart b/packages/stream_chat_flutter/lib/src/user_avatar.dart index 31e07f0a..0c897084 100644 --- a/packages/stream_chat_flutter/lib/src/user_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/user_avatar.dart @@ -56,9 +56,7 @@ class UserAvatar extends StatelessWidget { @override Widget build(BuildContext context) { - final hasImage = user.extraData.containsKey('image') && - user.extraData['image'] != null && - user.extraData['image'] != ''; + final hasImage = user.image != null && user.image!.isNotEmpty; final streamChatTheme = StreamChatTheme.of(context); Widget avatar = FittedBox( @@ -75,8 +73,7 @@ class UserAvatar extends StatelessWidget { child: hasImage ? CachedNetworkImage( filterQuality: FilterQuality.high, - // ignore: cast_nullable_to_non_nullable - imageUrl: user.extraData['image'] as String, + imageUrl: user.image!, errorWidget: (_, __, ___) => streamChatTheme.defaultUserImage(context, user), fit: BoxFit.cover, From 27893e147a7e10c69be895f57e02883fdd8f8731 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Wed, 4 Aug 2021 16:43:45 +0200 Subject: [PATCH 2/7] test: add additional user tests --- packages/stream_chat/test/fixtures/user.json | 11 ++ .../test/src/core/models/own_user_test.dart | 112 ++++++++++++- .../test/src/core/models/user_test.dart | 153 +++++++++++++++++- 3 files changed, 263 insertions(+), 13 deletions(-) diff --git a/packages/stream_chat/test/fixtures/user.json b/packages/stream_chat/test/fixtures/user.json index b22c8553..146a4242 100644 --- a/packages/stream_chat/test/fixtures/user.json +++ b/packages/stream_chat/test/fixtures/user.json @@ -2,5 +2,16 @@ "id": "bbb19d9a-ee50-45bc-84e5-0584e79d0c9e", "role": "test-role", "name": "John", + "image": "https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow", + "extraDataStringTest": "Extra data test", + "extraDataIntTest": 1, + "extraDataDoubleTest": 1.1, + "extraDataBoolTest": true, + "banned": true, + "online": true, + "teams": ["team-1", "team-2"], + "created_at": "2021-08-03 12:39:21.817646", + "updated_at": "2021-08-04 12:39:21.817646", + "last_active" : "2021-08-05 12:39:21.817646", "language": "en" } \ No newline at end of file diff --git a/packages/stream_chat/test/src/core/models/own_user_test.dart b/packages/stream_chat/test/src/core/models/own_user_test.dart index 7aef859d..e1d12ada 100644 --- a/packages/stream_chat/test/src/core/models/own_user_test.dart +++ b/packages/stream_chat/test/src/core/models/own_user_test.dart @@ -1,10 +1,23 @@ +import 'package:mocktail/mocktail.dart'; import 'package:stream_chat/src/core/models/own_user.dart'; import 'package:stream_chat/src/core/models/user.dart'; +import 'package:stream_chat/stream_chat.dart'; import 'package:test/test.dart'; import '../../utils.dart'; +class MockMute extends Mock implements Mute {} + +class MockDevice extends Mock implements Device {} + void main() { + final devices = [MockDevice(), MockDevice()]; + final mutes = [MockMute(), MockMute()]; + final channelMutes = [MockMute()]; + final createdAt = DateTime.parse('2021-05-03 12:39:21.817646'); + final updatedAt = DateTime.parse('2021-04-03 12:39:21.817646'); + final lastActive = DateTime.parse('2021-03-03 12:39:21.817646'); + group('src/models/own_user', () { test('should parse json correctly', () { final ownUser = OwnUser.fromJson(jsonFixture('own_user.json')); @@ -22,6 +35,7 @@ void main() { expect(ownUser.channelMutes.length, 1); expect(ownUser.totalUnreadCount, 0); expect(ownUser.unreadChannels, 0); + expect(ownUser.image, 'https://placehold.jp/150x150.png'); expect(ownUser.extraData['image'], 'https://placehold.jp/150x150.png'); expect(ownUser.extraData['name'], 'Proud darkness'); expect(ownUser.extraData['username'], 'Rioland'); @@ -40,6 +54,7 @@ void main() { expect(ownUser.online, user.online); expect(ownUser.banned, user.banned); expect(ownUser.extraData, user.extraData); + expect(ownUser.image, user.image); }); test('copyWith', () { @@ -49,35 +64,116 @@ void main() { expect(newUser.id, user.id); expect(newUser.role, user.role); expect(newUser.name, user.name); + expect(newUser.devices, user.devices); + expect(newUser.mutes, user.mutes); + expect(newUser.totalUnreadCount, user.totalUnreadCount); + expect(newUser.channelMutes, user.channelMutes); + expect(newUser.createdAt, user.createdAt); + expect(newUser.updatedAt, user.updatedAt); + expect(newUser.lastActive, user.lastActive); + expect(newUser.online, user.online); + expect(newUser.extraData, user.extraData); + expect(newUser.banned, user.banned); + expect(newUser.teams, user.teams); + expect(newUser.language, user.language); + expect(newUser.image, user.image); newUser = user.copyWith( id: 'test', role: 'test', + image: 'https://getstream.io/image-new', extraData: { 'name': 'test', }, + devices: devices, + mutes: mutes, + totalUnreadCount: 10, + unreadChannels: 5, + channelMutes: channelMutes, + createdAt: createdAt, + updatedAt: updatedAt, + lastActive: lastActive, + online: true, + banned: true, + teams: ['team1', 'team2'], + language: 'fr', ); expect(newUser.id, 'test'); expect(newUser.role, 'test'); expect(newUser.name, 'test'); + expect(newUser.image, 'https://getstream.io/image-new'); + expect( + newUser.extraData, + { + 'name': 'test', + 'image': 'https://getstream.io/image-new', + }, + reason: 'Should get image from user.image', + ); + expect(newUser.devices, devices); + expect(newUser.mutes, mutes); + expect(newUser.totalUnreadCount, 10); + expect(newUser.unreadChannels, 5); + expect(newUser.channelMutes, channelMutes); + expect(newUser.createdAt, createdAt); + expect(newUser.updatedAt, updatedAt); + expect(newUser.createdAt, createdAt); + expect(newUser.online, true); + expect(newUser.banned, true); + expect(newUser.teams, ['team1', 'team2']); + expect(newUser.language, 'fr'); }); test('merge', () { final user = OwnUser.fromJson(jsonFixture('own_user.json')); - final newUser = user.merge(OwnUser( - id: 'test', - role: 'test', - extraData: const { - 'name': 'test', - }, - banned: true, - )); + final newUser = user.merge( + OwnUser( + id: 'test', + role: 'test', + extraData: const { + 'name': 'test', + }, + image: 'https://getstream.io/image-new', + devices: devices, + mutes: mutes, + totalUnreadCount: 10, + unreadChannels: 5, + channelMutes: channelMutes, + createdAt: createdAt, + updatedAt: updatedAt, + lastActive: lastActive, + online: true, + banned: true, + teams: const ['team1', 'team2'], + language: 'fr', + ), + ); expect(newUser.id, 'test'); expect(newUser.role, 'test'); expect(newUser.name, 'test'); + expect(newUser.image, 'https://getstream.io/image-new'); + expect( + newUser.extraData, + { + 'name': 'test', + 'image': 'https://getstream.io/image-new', + }, + reason: 'Should get image from user.image', + ); + expect(newUser.devices, devices); + expect(newUser.mutes, mutes); + expect(newUser.totalUnreadCount, 10); + expect(newUser.unreadChannels, 5); + expect(newUser.channelMutes, channelMutes); + expect(newUser.createdAt, createdAt); + expect(newUser.updatedAt, updatedAt); + expect(newUser.createdAt, createdAt); + expect(newUser.online, true); expect(newUser.banned, true); + expect(newUser.teams, ['team1', 'team2']); + expect(newUser.language, 'fr'); }); }); } diff --git a/packages/stream_chat/test/src/core/models/user_test.dart b/packages/stream_chat/test/src/core/models/user_test.dart index ce488cab..48306017 100644 --- a/packages/stream_chat/test/src/core/models/user_test.dart +++ b/packages/stream_chat/test/src/core/models/user_test.dart @@ -4,21 +4,73 @@ import 'package:test/test.dart'; import '../../utils.dart'; void main() { + const id = 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e'; + const role = 'test-role'; + const name = 'John'; + const image = + 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow'; + const extraDataStringTest = 'Extra data test'; + const extraDataIntTest = 1; + const extraDataDoubleTest = 1.1; + const extraDataBoolTest = true; + const online = true; + const banned = true; + const teams = ['team-1', 'team-2']; + const createdAtString = '2021-08-03 12:39:21.817646'; + const updatedAtString = '2021-08-04 12:39:21.817646'; + const lastActiveString = '2021-08-05 12:39:21.817646'; + group('src/models/user', () { test('should parse json correctly', () { final user = User.fromJson(jsonFixture('user.json')); - expect(user.id, 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e'); - expect(user.name, 'John'); + expect(user.id, id); + expect(user.role, role); + expect(user.name, name); + expect(user.image, image); + expect(user.extraData['image'], image); + expect(user.extraData['extraDataStringTest'], extraDataStringTest); + expect(user.extraData['extraDataIntTest'], extraDataIntTest); + expect(user.extraData['extraDataDoubleTest'], extraDataDoubleTest); + expect(user.extraData['extraDataBoolTest'], extraDataBoolTest); + expect(user.online, online); + expect(user.banned, banned); + expect(user.teams, teams); + expect(user.createdAt, DateTime.parse(createdAtString)); + expect(user.updatedAt, DateTime.parse(updatedAtString)); + expect(user.lastActive, DateTime.parse(lastActiveString)); + expect(user.language, 'en'); }); test('should serialize to json correctly', () { final user = User( - id: 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e', - role: 'abc', + id: id, + role: role, + image: image, + extraData: const { + 'name': name, + 'extraDataStringTest': extraDataStringTest, + 'extraDataIntTest': extraDataIntTest, + 'extraDataDoubleTest': extraDataDoubleTest, + 'extraDataBoolTest': extraDataBoolTest, + }, + createdAt: DateTime.parse(createdAtString), + updatedAt: DateTime.parse(updatedAtString), + lastActive: DateTime.parse(lastActiveString), + banned: online, + online: banned, + teams: const ['team-1', 'team-2'], + language: 'fr', ); expect(user.toJson(), { - 'id': 'bbb19d9a-ee50-45bc-84e5-0584e79d0c9e', + 'id': id, + 'name': name, + 'image': image, + 'extraDataStringTest': extraDataStringTest, + 'extraDataIntTest': extraDataIntTest, + 'extraDataDoubleTest': extraDataDoubleTest, + 'extraDataBoolTest': extraDataBoolTest, + 'language': 'fr', }); }); @@ -29,6 +81,14 @@ void main() { expect(newUser.id, user.id); expect(newUser.role, user.role); expect(newUser.name, user.name); + expect(newUser.image, user.image); + expect(newUser.online, user.online); + expect(newUser.banned, user.banned); + expect(newUser.teams, user.teams); + expect(newUser.createdAt, user.createdAt); + expect(newUser.updatedAt, user.updatedAt); + expect(newUser.lastActive, user.lastActive); + expect(newUser.language, user.language); newUser = user.copyWith( id: 'test', @@ -36,11 +96,94 @@ void main() { extraData: { 'name': 'test', }, + image: 'https://stream.io/new-image', + online: false, + banned: false, + teams: ['new-team1', 'new-team2'], + createdAt: DateTime.parse('2021-05-03 12:39:21.817646'), + updatedAt: DateTime.parse('2021-05-04 12:39:21.817646'), + lastActive: DateTime.parse('2021-05-06 12:39:21.817646'), + language: 'it', ); expect(newUser.id, 'test'); expect(newUser.role, 'test'); expect(newUser.name, 'test'); + expect(newUser.image, 'https://stream.io/new-image'); + expect(newUser.extraData['image'], 'https://stream.io/new-image'); + expect(newUser.online, false); + expect(newUser.banned, false); + expect(newUser.teams, ['new-team1', 'new-team2']); + expect(newUser.createdAt, DateTime.parse('2021-05-03 12:39:21.817646')); + expect(newUser.updatedAt, DateTime.parse('2021-05-04 12:39:21.817646')); + expect(newUser.lastActive, DateTime.parse('2021-05-06 12:39:21.817646')); + expect(newUser.language, 'it'); + }); + + test('image property and extraData manipulation', () { + final user = User(id: id, image: image); + + expect(user.image, image); + expect(user.extraData['image'], image); + expect(user.toJson(), {'id': id, 'image': image}); + expect(User.fromJson(user.toJson()).toJson(), {'id': id, 'image': image}); + + const imageURLOne = 'https://stream.io/image-one'; + var newUser = user.copyWith( + extraData: {'image': imageURLOne}, + ); + + expect(newUser.extraData['image'], imageURLOne); + expect(newUser.image, imageURLOne); + + const imageURLTwo = 'https://stream.io/image-two'; + newUser = user.copyWith( + image: imageURLTwo, + ); + + expect(newUser.extraData['image'], imageURLTwo); + expect(newUser.image, imageURLTwo); + + const imageURLThree = 'https://stream.io/image-three'; + newUser = user.copyWith( + image: imageURLThree, + extraData: {'image': imageURLThree}, + ); + + expect(newUser.extraData['image'], imageURLThree); + expect(newUser.image, imageURLThree); + }); + + test('default values, constructor', () { + final user = User(id: id); + + expect(user.id, id); + expect(user.role, null); + expect(user.name, id, reason: 'if a name is not supplied, default to id'); + expect(user.image, null); + expect(user.extraData, const {}); + expect(user.online, false); + expect(user.banned, false); + expect(user.teams, []); + expect(user.lastActive, null); + expect(user.createdAt, isNotNull); + expect(user.updatedAt, isNotNull); + }); + + test('default values, parse json', () { + final user = User.fromJson(const {'id': id}); + + expect(user.id, id); + expect(user.role, null); + expect(user.name, id, reason: 'if a name is not supplied, default to id'); + expect(user.image, null); + expect(user.extraData, const {}); + expect(user.online, false); + expect(user.banned, false); + expect(user.teams, []); + expect(user.lastActive, null); + expect(user.createdAt, isNotNull); + expect(user.updatedAt, isNotNull); }); }); } From 46828764c1311d3b116e8b344c6934612abac68c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 5 Aug 2021 16:37:23 +0530 Subject: [PATCH 3/7] feat(ui): minor fixes, add support for `name` in user.dart Signed-off-by: xsahil03x --- .../lib/src/core/models/own_user.dart | 56 +++++---- .../lib/src/core/models/own_user.g.dart | 1 - .../stream_chat/lib/src/core/models/user.dart | 106 +++++++----------- .../lib/src/core/models/user.g.dart | 2 - .../test/src/core/models/user_test.dart | 40 ++++++- 5 files changed, 111 insertions(+), 94 deletions(-) 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 5adc753c..ee81e909 100644 --- a/packages/stream_chat/lib/src/core/models/own_user.dart +++ b/packages/stream_chat/lib/src/core/models/own_user.dart @@ -20,6 +20,8 @@ class OwnUser extends User { this.channelMutes = const [], required String id, String? role, + String? name, + String? image, DateTime? createdAt, DateTime? updatedAt, DateTime? lastActive, @@ -28,10 +30,11 @@ class OwnUser extends User { bool banned = false, List teams = const [], String? language, - String? image, }) : super( id: id, role: role, + name: name, + image: image, createdAt: createdAt, updatedAt: updatedAt, lastActive: lastActive, @@ -40,7 +43,6 @@ class OwnUser extends User { banned: banned, teams: teams, language: language, - image: image, ); /// Create a new instance from a json @@ -51,6 +53,8 @@ class OwnUser extends User { factory OwnUser.fromUser(User user) => OwnUser( id: user.id, role: user.role, + name: user.name, + image: user.image, createdAt: user.createdAt, updatedAt: user.updatedAt, lastActive: user.lastActive, @@ -59,7 +63,6 @@ class OwnUser extends User { extraData: user.extraData, teams: user.teams, language: user.language, - image: user.image, ); /// Creates a copy of [OwnUser] with specified attributes overridden. @@ -67,6 +70,8 @@ class OwnUser extends User { OwnUser copyWith({ String? id, String? role, + String? name, + String? image, DateTime? createdAt, DateTime? updatedAt, DateTime? lastActive, @@ -80,48 +85,51 @@ class OwnUser extends User { int? totalUnreadCount, int? unreadChannels, String? language, - String? image, }) => OwnUser( - id: id ?? this.id, - banned: banned ?? this.banned, - role: role ?? this.role, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - lastActive: lastActive ?? this.lastActive, - online: online ?? this.online, - extraData: extraData ?? this.extraData, - teams: teams ?? this.teams, - channelMutes: channelMutes ?? this.channelMutes, - devices: devices ?? this.devices, - mutes: mutes ?? this.mutes, - totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, - unreadChannels: unreadChannels ?? this.unreadChannels, - language: language ?? this.language, - image: image // if null, it will be retrieved from extraData['image'] - ); + 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, + banned: banned ?? this.banned, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastActive: lastActive ?? this.lastActive, + online: online ?? this.online, + extraData: extraData ?? this.extraData, + teams: teams ?? this.teams, + channelMutes: channelMutes ?? this.channelMutes, + devices: devices ?? this.devices, + mutes: mutes ?? this.mutes, + totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, + unreadChannels: unreadChannels ?? this.unreadChannels, + language: language ?? this.language, + ); /// Returns a new [OwnUser] that is a combination of this ownUser /// and the given [other] ownUser. OwnUser merge(OwnUser? other) { if (other == null) return this; return copyWith( + id: other.id, + role: other.role, + name: other.name, + image: other.image, banned: other.banned, channelMutes: other.channelMutes, createdAt: other.createdAt, devices: other.devices, extraData: other.extraData, - id: other.id, lastActive: other.lastActive, mutes: other.mutes, online: other.online, - role: other.role, teams: other.teams, totalUnreadCount: other.totalUnreadCount, unreadChannels: other.unreadChannels, updatedAt: other.updatedAt, language: other.language, - image: other.image, ); } diff --git a/packages/stream_chat/lib/src/core/models/own_user.g.dart b/packages/stream_chat/lib/src/core/models/own_user.g.dart index cacb99c5..ca4acdea 100644 --- a/packages/stream_chat/lib/src/core/models/own_user.g.dart +++ b/packages/stream_chat/lib/src/core/models/own_user.g.dart @@ -40,6 +40,5 @@ OwnUser _$OwnUserFromJson(Map json) { (json['teams'] as List?)?.map((e) => e as String).toList() ?? [], language: json['language'] as String?, - image: json['image'] as String?, ); } diff --git a/packages/stream_chat/lib/src/core/models/user.dart b/packages/stream_chat/lib/src/core/models/user.dart index 9baaf049..5a5ef8e5 100644 --- a/packages/stream_chat/lib/src/core/models/user.dart +++ b/packages/stream_chat/lib/src/core/models/user.dart @@ -9,6 +9,18 @@ part 'user.g.dart'; class User extends Equatable { /// Creates a new user. /// + /// {@template name} + /// If an [name] is provided it will be set on [extraData] with a `key` + /// of 'name'. + /// + /// For example: + /// ```dart + /// final user = User(id: 'id', name: 'Sahil Kumar'); + /// print(user.name == user.extraData['name']); // true + /// ``` + /// {@endtemplate} + /// + /// {@template image} /// If an [image] is provided it will be set on [extraData] with a `key` /// of 'image'. /// @@ -17,9 +29,11 @@ class User extends Equatable { /// final user = User(id: 'id', image: 'https://getstream.io/image.png'); /// print(user.image == user.extraData['image']); // true /// ``` + /// {@endtemplate} User({ required this.id, this.role, + String? name, String? image, DateTime? createdAt, DateTime? updatedAt, @@ -29,13 +43,14 @@ class User extends Equatable { this.banned = false, this.teams = const [], this.language, - }) : _image = image, - createdAt = createdAt ?? DateTime.now(), + }) : createdAt = createdAt ?? DateTime.now(), updatedAt = updatedAt ?? DateTime.now(), - - // For backwards compatibalitity, set 'image' on [extraData]. - extraData = - (image != null) ? {...extraData, 'image': image} : extraData; + /*For backwards compatibility, set 'name', 'image' in [extraData].*/ + extraData = { + ...extraData, + if (name != null) 'name': name, + if (image != null) 'image': image, + }; /// Create a new instance from json. factory User.fromJson(Map json) => @@ -54,62 +69,32 @@ class User extends Equatable { 'banned', 'teams', 'language', - 'image', ]; /// User id. final String id; - /// User role. - @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) - final String? role; - - /// Image for user. This is also set on `extraData['image']`. + /// Shortcut for user name. /// - /// {@template image} - /// There are a few ways to set an image. - /// - /// Setting an image by passing in an image argument: - /// ```dart - /// final user = User( - /// id: 'id', - /// image: 'https://getstream.io/image', - /// ); - /// ``` - /// - /// Or by directly setting it in [extraData], for example: - /// ```dart - /// final user = User( - /// id: 'id', - /// extraData: const {'image': 'https://getstream.io/image'}, - /// ); - /// - /// ``` - /// Parsing json with an 'image' key will automatically set the `image` - /// property and `extraData['image']` key/value. - /// - /// ```dart - /// final user = User.fromJson({ - /// id: 'id', - /// image: 'https://getstream.io/image', // key: image - /// }); - /// - /// print(user.image == user.extraData['image']); // true - /// ``` - /// {@endtemplate} - final String? _image; + /// {@macro name} + @JsonKey(ignore: true) + String get name { + if (extraData.containsKey('name')) { + final name = extraData['name']! as String; + if (name.isNotEmpty) return name; + } + return id; + } /// Shortcut for user image. /// /// {@macro image} + @JsonKey(ignore: true) + String? get image => extraData['image'] as String?; + + /// User role. @JsonKey(includeIfNull: false, toJson: Serializer.readOnly) - String? get image { - if (_image != null) { - return _image; - } else { - return extraData['image'] as String?; - } - } + final String? role; /// User teams @JsonKey( @@ -152,15 +137,6 @@ class User extends Equatable { @JsonKey(includeIfNull: false) final String? language; - /// Shortcut for user name. - String get name { - if (extraData.containsKey('name')) { - final name = extraData['name']! as String; - if (name.isNotEmpty) return name; - } - return id; - } - /// List of users to list of userIds. static List? toIds(List? users) => users?.map((u) => u.id).toList(); @@ -174,6 +150,8 @@ class User extends Equatable { User copyWith({ String? id, String? role, + String? name, + String? image, DateTime? createdAt, DateTime? updatedAt, DateTime? lastActive, @@ -182,11 +160,14 @@ class User extends Equatable { bool? banned, List? teams, String? language, - String? image, }) => 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, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, lastActive: lastActive ?? this.lastActive, @@ -195,9 +176,8 @@ class User extends Equatable { banned: banned ?? this.banned, teams: teams ?? this.teams, language: language ?? this.language, - image: image, // if null, it will be retrieved from extraData['image'] ); @override - List get props => [id]; + List get props => [id, role]; } diff --git a/packages/stream_chat/lib/src/core/models/user.g.dart b/packages/stream_chat/lib/src/core/models/user.g.dart index c685cd57..ab2f04d5 100644 --- a/packages/stream_chat/lib/src/core/models/user.g.dart +++ b/packages/stream_chat/lib/src/core/models/user.g.dart @@ -10,7 +10,6 @@ User _$UserFromJson(Map json) { return User( id: json['id'] as String, role: json['role'] as String?, - image: json['image'] as String?, createdAt: json['created_at'] == null ? null : DateTime.parse(json['created_at'] as String), @@ -42,7 +41,6 @@ Map _$UserToJson(User instance) { } writeNotNull('role', readonly(instance.role)); - writeNotNull('image', readonly(instance.image)); writeNotNull('teams', readonly(instance.teams)); writeNotNull('created_at', readonly(instance.createdAt)); writeNotNull('updated_at', readonly(instance.updatedAt)); diff --git a/packages/stream_chat/test/src/core/models/user_test.dart b/packages/stream_chat/test/src/core/models/user_test.dart index 48306017..c8e04ede 100644 --- a/packages/stream_chat/test/src/core/models/user_test.dart +++ b/packages/stream_chat/test/src/core/models/user_test.dart @@ -45,9 +45,9 @@ void main() { final user = User( id: id, role: role, + name: name, image: image, extraData: const { - 'name': name, 'extraDataStringTest': extraDataStringTest, 'extraDataIntTest': extraDataIntTest, 'extraDataDoubleTest': extraDataDoubleTest, @@ -93,9 +93,7 @@ void main() { newUser = user.copyWith( id: 'test', role: 'test', - extraData: { - 'name': 'test', - }, + name: 'test', image: 'https://stream.io/new-image', online: false, banned: false, @@ -120,6 +118,40 @@ void main() { expect(newUser.language, 'it'); }); + test('name property and extraData manipulation', () { + final user = User(id: id, name: name); + + expect(user.name, name); + expect(user.extraData['name'], name); + expect(user.toJson(), {'id': id, 'name': name}); + expect(User.fromJson(user.toJson()).toJson(), {'id': id, 'name': name}); + + const nameOne = 'Name One'; + var newUser = user.copyWith( + extraData: {'name': nameOne}, + ); + + expect(newUser.extraData['name'], nameOne); + expect(newUser.name, nameOne); + + const nameTwo = 'Name Two'; + newUser = user.copyWith( + name: nameTwo, + ); + + expect(newUser.extraData['name'], nameTwo); + expect(newUser.name, nameTwo); + + const nameThree = 'Name Three'; + newUser = user.copyWith( + name: nameThree, + extraData: {'name': nameThree}, + ); + + expect(newUser.extraData['name'], nameThree); + expect(newUser.name, nameThree); + }); + test('image property and extraData manipulation', () { final user = User(id: id, image: image); From 3ab363a8b297a58351c20905d50caec7533faabf Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 5 Aug 2021 16:38:32 +0530 Subject: [PATCH 4/7] chore(llc, ui, core, localization, persistence): analysis fixes, move `extraData.image` to `image` field Signed-off-by: xsahil03x --- packages/stream_chat/example/lib/main.dart | 7 +++---- packages/stream_chat_flutter/example/lib/main.dart | 3 +-- packages/stream_chat_flutter_core/example/lib/main.dart | 9 +++------ .../example/lib/add_new_lang.dart | 3 +-- packages/stream_chat_localizations/example/lib/main.dart | 3 +-- .../example/lib/override_lang.dart | 3 +-- packages/stream_chat_persistence/example/lib/main.dart | 6 ++---- 7 files changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/stream_chat/example/lib/main.dart b/packages/stream_chat/example/lib/main.dart index 46030341..d2c5dcea 100644 --- a/packages/stream_chat/example/lib/main.dart +++ b/packages/stream_chat/example/lib/main.dart @@ -13,10 +13,9 @@ Future main() async { await client.connectUser( User( id: 'cool-shadow-7', - extraData: const { - 'image': - 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', - }, + name: 'Cool Shadow', + image: + 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', ), '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo''', ); diff --git a/packages/stream_chat_flutter/example/lib/main.dart b/packages/stream_chat_flutter/example/lib/main.dart index c2663a6a..a9e1366c 100644 --- a/packages/stream_chat_flutter/example/lib/main.dart +++ b/packages/stream_chat_flutter/example/lib/main.dart @@ -22,8 +22,7 @@ void main() async { /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ await client.connectUser( User(id: 'super-band-9'), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.' - '0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', + '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', ); final channel = client.channel('messaging', id: 'godevs'); diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index 0a7b0bce..03e791de 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -13,13 +13,10 @@ Future main() async { await client.connectUser( User( id: 'cool-shadow-7', - extraData: const { - 'image': - 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', - }, + image: + 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', ), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9' - '.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo', + '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo''', ); runApp( diff --git a/packages/stream_chat_localizations/example/lib/add_new_lang.dart b/packages/stream_chat_localizations/example/lib/add_new_lang.dart index 1412f4e0..8a1d196e 100644 --- a/packages/stream_chat_localizations/example/lib/add_new_lang.dart +++ b/packages/stream_chat_localizations/example/lib/add_new_lang.dart @@ -401,8 +401,7 @@ void main() async { /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ await client.connectUser( User(id: 'super-band-9'), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.' - '0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', + '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', ); final channel = client.channel('messaging', id: 'godevs'); diff --git a/packages/stream_chat_localizations/example/lib/main.dart b/packages/stream_chat_localizations/example/lib/main.dart index 818086df..c99a4c6c 100644 --- a/packages/stream_chat_localizations/example/lib/main.dart +++ b/packages/stream_chat_localizations/example/lib/main.dart @@ -20,8 +20,7 @@ void main() async { /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ await client.connectUser( User(id: 'super-band-9'), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.' - '0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', + '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', ); final channel = client.channel('messaging', id: 'godevs'); diff --git a/packages/stream_chat_localizations/example/lib/override_lang.dart b/packages/stream_chat_localizations/example/lib/override_lang.dart index 0e45019a..5be8f9a6 100644 --- a/packages/stream_chat_localizations/example/lib/override_lang.dart +++ b/packages/stream_chat_localizations/example/lib/override_lang.dart @@ -45,8 +45,7 @@ void main() async { /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ await client.connectUser( User(id: 'super-band-9'), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.' - '0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', + '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', ); final channel = client.channel('messaging', id: 'godevs'); diff --git a/packages/stream_chat_persistence/example/lib/main.dart b/packages/stream_chat_persistence/example/lib/main.dart index 5c83ed78..e187da56 100644 --- a/packages/stream_chat_persistence/example/lib/main.dart +++ b/packages/stream_chat_persistence/example/lib/main.dart @@ -22,10 +22,8 @@ Future main() async { await client.connectUser( User( id: 'cool-shadow-7', - extraData: const { - 'image': - 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', - }, + image: + 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow', ), 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.' 'gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo', From 22f323b37dc445650d648b0f3353838295e26574 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Thu, 5 Aug 2021 13:40:00 +0200 Subject: [PATCH 5/7] chore: fix formatting --- .../lib/src/core/models/own_user.dart | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) 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 ee81e909..a65052f4 100644 --- a/packages/stream_chat/lib/src/core/models/own_user.dart +++ b/packages/stream_chat/lib/src/core/models/own_user.dart @@ -7,11 +7,12 @@ import 'package:stream_chat/stream_chat.dart'; part 'own_user.g.dart'; -/// The class that defines the own user model -/// This object can be found in [Event] +/// The class that defines the own user model. +/// +/// This object can be found in [Event]. @JsonSerializable(createToJson: false) class OwnUser extends User { - /// Constructor used for json serialization + /// Constructor used for json serialization. OwnUser({ this.devices = const [], this.mutes = const [], @@ -45,11 +46,11 @@ class OwnUser extends User { language: language, ); - /// Create a new instance from a json + /// Create a new instance from json. factory OwnUser.fromJson(Map json) => _$OwnUserFromJson( Serializer.moveToExtraDataFromRoot(json, topLevelFields)); - /// Create a new instance from [User] object + /// Create a new instance from [User] object. factory OwnUser.fromUser(User user) => OwnUser( id: user.id, role: user.role, @@ -133,27 +134,28 @@ class OwnUser extends User { ); } - /// List of user devices + /// List of user devices. @JsonKey(includeIfNull: false, defaultValue: []) final List devices; - /// List of users muted by the user + /// List of users muted by the user. @JsonKey(includeIfNull: false, defaultValue: []) final List mutes; - /// List of users muted by the user + /// List of users muted by the user. @JsonKey(includeIfNull: false, defaultValue: []) final List channelMutes; - /// Total unread messages by the user + /// Total unread messages by the user. @JsonKey(includeIfNull: false, defaultValue: 0) final int totalUnreadCount; - /// Total unread channels by the user + /// Total unread channels by the user. @JsonKey(includeIfNull: false) final int? unreadChannels; /// Known top level fields. + /// /// Useful for [Serializer] methods. static final topLevelFields = [ 'devices', From dd3b67a62a589d97836a3af7f625ff5d5c0cb8cf Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Thu, 5 Aug 2021 13:41:32 +0200 Subject: [PATCH 6/7] chore: update CHANGELOG.md --- packages/stream_chat/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index d8860425..0228a0f8 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -4,6 +4,10 @@ - Fixed `channel.markAllRead` throwing failed host lookup. +✅ Added + +- `User` and `OwnUser` classes now have an `image` property. Setting an image will also set the 'image' key on `extraData`, so `user.image` and `user.extraData['image']` is the same. + ## 2.1.1 🐞 Fixed From 35adf26f4cb2c0054276232529527f68a640202f Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Thu, 5 Aug 2021 14:04:35 +0200 Subject: [PATCH 7/7] chore: update CHANGELOG.md --- packages/stream_chat/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 0228a0f8..e3e31db6 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -7,6 +7,7 @@ ✅ Added - `User` and `OwnUser` classes now have an `image` property. Setting an image will also set the 'image' key on `extraData`, so `user.image` and `user.extraData['image']` is the same. +- `User` and `OwnUser` classes now have a `name` property. Setting a name will also set the 'name' key on `extraData`, so `user.name` and `user.extraData['name']` is the same. ## 2.1.1