feat: add image property to user

This commit is contained in:
Gordon Hayes
2021-08-04 16:42:01 +02:00
parent 1842a4b086
commit acd932ccc9
5 changed files with 112 additions and 42 deletions
@@ -28,6 +28,7 @@ class OwnUser extends User {
bool banned = false, bool banned = false,
List<String> teams = const [], List<String> teams = const [],
String? language, String? language,
String? image,
}) : super( }) : super(
id: id, id: id,
role: role, role: role,
@@ -39,6 +40,7 @@ class OwnUser extends User {
banned: banned, banned: banned,
teams: teams, teams: teams,
language: language, language: language,
image: image,
); );
/// Create a new instance from a json /// Create a new instance from a json
@@ -57,6 +59,7 @@ class OwnUser extends User {
extraData: user.extraData, extraData: user.extraData,
teams: user.teams, teams: user.teams,
language: user.language, language: user.language,
image: user.image,
); );
/// Creates a copy of [OwnUser] with specified attributes overridden. /// Creates a copy of [OwnUser] with specified attributes overridden.
@@ -77,24 +80,26 @@ class OwnUser extends User {
int? totalUnreadCount, int? totalUnreadCount,
int? unreadChannels, int? unreadChannels,
String? language, String? language,
String? image,
}) => }) =>
OwnUser( OwnUser(
id: id ?? this.id, id: id ?? this.id,
banned: banned ?? this.banned, banned: banned ?? this.banned,
role: role ?? this.role, role: role ?? this.role,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt, updatedAt: updatedAt ?? this.updatedAt,
lastActive: lastActive ?? this.lastActive, lastActive: lastActive ?? this.lastActive,
online: online ?? this.online, online: online ?? this.online,
extraData: extraData ?? this.extraData, extraData: extraData ?? this.extraData,
teams: teams ?? this.teams, teams: teams ?? this.teams,
channelMutes: channelMutes ?? this.channelMutes, channelMutes: channelMutes ?? this.channelMutes,
devices: devices ?? this.devices, devices: devices ?? this.devices,
mutes: mutes ?? this.mutes, mutes: mutes ?? this.mutes,
totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount,
unreadChannels: unreadChannels ?? this.unreadChannels, unreadChannels: unreadChannels ?? this.unreadChannels,
language: language ?? this.language, 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 /// Returns a new [OwnUser] that is a combination of this ownUser
/// and the given [other] ownUser. /// and the given [other] ownUser.
@@ -116,6 +121,7 @@ class OwnUser extends User {
unreadChannels: other.unreadChannels, unreadChannels: other.unreadChannels,
updatedAt: other.updatedAt, updatedAt: other.updatedAt,
language: other.language, language: other.language,
image: other.image,
); );
} }
@@ -40,5 +40,6 @@ OwnUser _$OwnUserFromJson(Map<String, dynamic> json) {
(json['teams'] as List<dynamic>?)?.map((e) => e as String).toList() ?? (json['teams'] as List<dynamic>?)?.map((e) => e as String).toList() ??
[], [],
language: json['language'] as String?, language: json['language'] as String?,
image: json['image'] as String?,
); );
} }
@@ -4,29 +4,45 @@ import 'package:stream_chat/src/core/util/serializer.dart';
part 'user.g.dart'; part 'user.g.dart';
/// The class that defines the user model /// Class that defines a Stream Chat User.
@JsonSerializable() @JsonSerializable()
class User extends Equatable { 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({ User({
required this.id, required this.id,
this.role, this.role,
String? image,
DateTime? createdAt, DateTime? createdAt,
DateTime? updatedAt, DateTime? updatedAt,
this.lastActive, this.lastActive,
Map<String, Object?> extraData = const {},
this.online = false, this.online = false,
this.extraData = const {},
this.banned = false, this.banned = false,
this.teams = const [], this.teams = const [],
this.language, this.language,
}) : createdAt = createdAt ?? DateTime.now(), }) : _image = image,
updatedAt = updatedAt ?? DateTime.now(); 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<String, dynamic> json) => factory User.fromJson(Map<String, dynamic> json) =>
_$UserFromJson(Serializer.moveToExtraDataFromRoot(json, topLevelFields)); _$UserFromJson(Serializer.moveToExtraDataFromRoot(json, topLevelFields));
/// Known top level fields. /// Known top level fields.
///
/// Useful for [Serializer] methods. /// Useful for [Serializer] methods.
static const topLevelFields = [ static const topLevelFields = [
'id', 'id',
@@ -38,16 +54,64 @@ class User extends Equatable {
'banned', 'banned',
'teams', 'teams',
'language', 'language',
'image',
]; ];
/// User id /// User id.
final String id; final String id;
/// User role /// User role.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly) @JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
final String? role; 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( @JsonKey(
includeIfNull: false, includeIfNull: false,
toJson: Serializer.readOnly, toJson: Serializer.readOnly,
@@ -55,29 +119,29 @@ class User extends Equatable {
) )
final List<String> teams; final List<String> teams;
/// Date of user creation /// Date of user creation.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly) @JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
final DateTime createdAt; final DateTime createdAt;
/// Date of last user update /// Date of last user update.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly) @JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
final DateTime updatedAt; final DateTime updatedAt;
/// Date of last user connection /// Date of last user connection.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly) @JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
final DateTime? lastActive; final DateTime? lastActive;
/// True if user is online /// True if user is online.
@JsonKey( @JsonKey(
includeIfNull: false, toJson: Serializer.readOnly, defaultValue: false) includeIfNull: false, toJson: Serializer.readOnly, defaultValue: false)
final bool online; final bool online;
/// True if user is banned from the chat /// True if user is banned from the chat.
@JsonKey( @JsonKey(
includeIfNull: false, toJson: Serializer.readOnly, defaultValue: false) includeIfNull: false, toJson: Serializer.readOnly, defaultValue: false)
final bool banned; final bool banned;
/// Map of custom user extraData /// Map of custom user extraData.
@JsonKey( @JsonKey(
includeIfNull: false, includeIfNull: false,
defaultValue: {}, defaultValue: {},
@@ -85,12 +149,10 @@ class User extends Equatable {
final Map<String, Object?> extraData; final Map<String, Object?> extraData;
/// The language this user prefers. /// The language this user prefers.
///
/// Defaults to 'en'.
@JsonKey(includeIfNull: false) @JsonKey(includeIfNull: false)
final String? language; final String? language;
/// Shortcut for user name /// Shortcut for user name.
String get name { String get name {
if (extraData.containsKey('name')) { if (extraData.containsKey('name')) {
final name = extraData['name']! as String; final name = extraData['name']! as String;
@@ -99,11 +161,11 @@ class User extends Equatable {
return id; return id;
} }
/// List of users to list of userIds /// List of users to list of userIds.
static List<String>? toIds(List<User>? users) => static List<String>? toIds(List<User>? users) =>
users?.map((u) => u.id).toList(); users?.map((u) => u.id).toList();
/// Serialize to json /// Serialize to json.
Map<String, dynamic> toJson() => Serializer.moveFromExtraDataToRoot( Map<String, dynamic> toJson() => Serializer.moveFromExtraDataToRoot(
_$UserToJson(this), _$UserToJson(this),
); );
@@ -120,6 +182,7 @@ class User extends Equatable {
bool? banned, bool? banned,
List<String>? teams, List<String>? teams,
String? language, String? language,
String? image,
}) => }) =>
User( User(
id: id ?? this.id, id: id ?? this.id,
@@ -132,6 +195,7 @@ class User extends Equatable {
banned: banned ?? this.banned, banned: banned ?? this.banned,
teams: teams ?? this.teams, teams: teams ?? this.teams,
language: language ?? this.language, language: language ?? this.language,
image: image, // if null, it will be retrieved from extraData['image']
); );
@override @override
@@ -10,6 +10,7 @@ User _$UserFromJson(Map<String, dynamic> json) {
return User( return User(
id: json['id'] as String, id: json['id'] as String,
role: json['role'] as String?, role: json['role'] as String?,
image: json['image'] as String?,
createdAt: json['created_at'] == null createdAt: json['created_at'] == null
? null ? null
: DateTime.parse(json['created_at'] as String), : DateTime.parse(json['created_at'] as String),
@@ -19,8 +20,8 @@ User _$UserFromJson(Map<String, dynamic> json) {
lastActive: json['last_active'] == null lastActive: json['last_active'] == null
? null ? null
: DateTime.parse(json['last_active'] as String), : DateTime.parse(json['last_active'] as String),
online: json['online'] as bool? ?? false,
extraData: json['extra_data'] as Map<String, dynamic>? ?? {}, extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
online: json['online'] as bool? ?? false,
banned: json['banned'] as bool? ?? false, banned: json['banned'] as bool? ?? false,
teams: teams:
(json['teams'] as List<dynamic>?)?.map((e) => e as String).toList() ?? (json['teams'] as List<dynamic>?)?.map((e) => e as String).toList() ??
@@ -41,6 +42,7 @@ Map<String, dynamic> _$UserToJson(User instance) {
} }
writeNotNull('role', readonly(instance.role)); writeNotNull('role', readonly(instance.role));
writeNotNull('image', readonly(instance.image));
writeNotNull('teams', readonly(instance.teams)); writeNotNull('teams', readonly(instance.teams));
writeNotNull('created_at', readonly(instance.createdAt)); writeNotNull('created_at', readonly(instance.createdAt));
writeNotNull('updated_at', readonly(instance.updatedAt)); writeNotNull('updated_at', readonly(instance.updatedAt));
@@ -56,9 +56,7 @@ class UserAvatar extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final hasImage = user.extraData.containsKey('image') && final hasImage = user.image != null && user.image!.isNotEmpty;
user.extraData['image'] != null &&
user.extraData['image'] != '';
final streamChatTheme = StreamChatTheme.of(context); final streamChatTheme = StreamChatTheme.of(context);
Widget avatar = FittedBox( Widget avatar = FittedBox(
@@ -75,8 +73,7 @@ class UserAvatar extends StatelessWidget {
child: hasImage child: hasImage
? CachedNetworkImage( ? CachedNetworkImage(
filterQuality: FilterQuality.high, filterQuality: FilterQuality.high,
// ignore: cast_nullable_to_non_nullable imageUrl: user.image!,
imageUrl: user.extraData['image'] as String,
errorWidget: (_, __, ___) => errorWidget: (_, __, ___) =>
streamChatTheme.defaultUserImage(context, user), streamChatTheme.defaultUserImage(context, user),
fit: BoxFit.cover, fit: BoxFit.cover,