feat: display and crop the user avatar correctly
This commit is contained in:
parent
1c8e357722
commit
2a05a9f8df
@ -1,24 +1,20 @@
|
|||||||
class PostCreator {
|
class PostCreator {
|
||||||
final String id;
|
final String id;
|
||||||
final String displayName;
|
final String displayName;
|
||||||
|
final String? avatar;
|
||||||
|
|
||||||
PostCreator({
|
PostCreator({required this.id, required this.displayName, this.avatar});
|
||||||
required this.id,
|
|
||||||
required this.displayName,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory PostCreator.fromJson(Map<String, dynamic> json) {
|
factory PostCreator.fromJson(Map<String, dynamic> json) {
|
||||||
return PostCreator(
|
return PostCreator(
|
||||||
id: json['id']?.toString() ?? '',
|
id: json['id']?.toString() ?? '',
|
||||||
displayName: json['displayName'] ?? '',
|
displayName: json['displayName'] ?? '',
|
||||||
|
avatar: json['avatar']?.toString(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {'id': id, 'displayName': displayName, 'avatar': avatar};
|
||||||
'id': id,
|
|
||||||
'displayName': displayName,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +49,9 @@ class Post {
|
|||||||
body: json['body'] ?? '',
|
body: json['body'] ?? '',
|
||||||
likes: int.tryParse(json['likes']?.toString() ?? '0') ?? 0,
|
likes: int.tryParse(json['likes']?.toString() ?? '0') ?? 0,
|
||||||
comments: int.tryParse(json['comments']?.toString() ?? '0') ?? 0,
|
comments: int.tryParse(json['comments']?.toString() ?? '0') ?? 0,
|
||||||
creationDate: DateTime.parse(json['creationDate'] ?? DateTime.now().toIso8601String()),
|
creationDate: DateTime.parse(
|
||||||
|
json['creationDate'] ?? DateTime.now().toIso8601String(),
|
||||||
|
),
|
||||||
liked: json['liked'] == true,
|
liked: json['liked'] == true,
|
||||||
images: json['images'] != null ? List<String>.from(json['images']) : null,
|
images: json['images'] != null ? List<String>.from(json['images']) : null,
|
||||||
);
|
);
|
||||||
@ -113,7 +111,9 @@ class LikedUser {
|
|||||||
return LikedUser(
|
return LikedUser(
|
||||||
id: json['id']?.toString() ?? '',
|
id: json['id']?.toString() ?? '',
|
||||||
displayName: json['displayName'] ?? '',
|
displayName: json['displayName'] ?? '',
|
||||||
likeTime: DateTime.parse(json['likeTime'] ?? DateTime.now().toIso8601String()),
|
likeTime: DateTime.parse(
|
||||||
|
json['likeTime'] ?? DateTime.now().toIso8601String(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,10 +157,14 @@ class DetailedPost {
|
|||||||
likes: int.tryParse(json['likes']?.toString() ?? '0') ?? 0,
|
likes: int.tryParse(json['likes']?.toString() ?? '0') ?? 0,
|
||||||
comments: int.tryParse(json['comments']?.toString() ?? '0') ?? 0,
|
comments: int.tryParse(json['comments']?.toString() ?? '0') ?? 0,
|
||||||
liked: json['liked'] == true,
|
liked: json['liked'] == true,
|
||||||
creationDate: DateTime.parse(json['creationDate'] ?? DateTime.now().toIso8601String()),
|
creationDate: DateTime.parse(
|
||||||
likedUsers: (json['likedUsers'] as List?)
|
json['creationDate'] ?? DateTime.now().toIso8601String(),
|
||||||
?.map((user) => LikedUser.fromJson(user))
|
),
|
||||||
.toList() ?? [],
|
likedUsers:
|
||||||
|
(json['likedUsers'] as List?)
|
||||||
|
?.map((user) => LikedUser.fromJson(user))
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
images: json['images'] != null ? List<String>.from(json['images']) : null,
|
images: json['images'] != null ? List<String>.from(json['images']) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -186,8 +190,6 @@ class CreatePostRequest {
|
|||||||
CreatePostRequest({required this.body});
|
CreatePostRequest({required this.body});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {'body': body};
|
||||||
'body': body,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -380,6 +380,98 @@ class PostImagesCarousel extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UserAvatar extends StatelessWidget {
|
||||||
|
final String displayName;
|
||||||
|
final String? avatarUrl;
|
||||||
|
final double radius;
|
||||||
|
final Color? backgroundColor;
|
||||||
|
|
||||||
|
const UserAvatar({
|
||||||
|
Key? key,
|
||||||
|
required this.displayName,
|
||||||
|
this.avatarUrl,
|
||||||
|
this.radius = 20,
|
||||||
|
this.backgroundColor,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
Color _getAvatarColor(String displayName) {
|
||||||
|
final colors = [
|
||||||
|
Color(0xFF32B0A5),
|
||||||
|
Color(0xFF4600B9),
|
||||||
|
Color(0xFF6A4C93),
|
||||||
|
Color(0xFFFF6347),
|
||||||
|
Color(0xFF32CD32),
|
||||||
|
Color(0xFF9932CC),
|
||||||
|
];
|
||||||
|
|
||||||
|
int hash = displayName.hashCode;
|
||||||
|
return colors[hash.abs() % colors.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getAvatarLetter(String displayName) {
|
||||||
|
return displayName.isNotEmpty ? displayName[0].toUpperCase() : '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isValidImageUrl(String? url) {
|
||||||
|
return url != null && url.isNotEmpty && url.trim().isNotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final color = backgroundColor ?? _getAvatarColor(displayName);
|
||||||
|
final letter = _getAvatarLetter(displayName);
|
||||||
|
|
||||||
|
return CircleAvatar(
|
||||||
|
radius: radius,
|
||||||
|
backgroundColor: color,
|
||||||
|
child: _isValidImageUrl(avatarUrl)
|
||||||
|
? ClipOval(
|
||||||
|
child: Image.network(
|
||||||
|
avatarUrl!,
|
||||||
|
width: radius * 2,
|
||||||
|
height: radius * 2,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
loadingBuilder: (context, child, loadingProgress) {
|
||||||
|
if (loadingProgress == null) return child;
|
||||||
|
return SizedBox(
|
||||||
|
width: radius * 2,
|
||||||
|
height: radius * 2,
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: radius * 0.6,
|
||||||
|
height: radius * 0.6,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2,
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
return Text(
|
||||||
|
letter,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: radius * 0.8,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Text(
|
||||||
|
letter,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: radius * 0.8,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PostCard extends StatefulWidget {
|
class PostCard extends StatefulWidget {
|
||||||
final Post post;
|
final Post post;
|
||||||
|
|
||||||
@ -413,24 +505,6 @@ class _PostCardState extends State<PostCard> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color _getAvatarColor(String displayName) {
|
|
||||||
final colors = [
|
|
||||||
Color(0xFF32B0A5),
|
|
||||||
Color(0xFF4600B9),
|
|
||||||
Color(0xFF6A4C93),
|
|
||||||
Color(0xFFFF6347),
|
|
||||||
Color(0xFF32CD32),
|
|
||||||
Color(0xFF9932CC),
|
|
||||||
];
|
|
||||||
|
|
||||||
int hash = displayName.hashCode;
|
|
||||||
return colors[hash.abs() % colors.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getAvatarLetter(String displayName) {
|
|
||||||
return displayName.isNotEmpty ? displayName[0].toUpperCase() : '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
void _sharePost(Post post) {
|
void _sharePost(Post post) {
|
||||||
final shareText =
|
final shareText =
|
||||||
'${post.creator.displayName} posted on Wesal.online:\n\n${post.body}';
|
'${post.creator.displayName} posted on Wesal.online:\n\n${post.body}';
|
||||||
@ -503,8 +577,6 @@ class _PostCardState extends State<PostCard> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final creator = _currentPost.creator;
|
final creator = _currentPost.creator;
|
||||||
final avatarColor = _getAvatarColor(creator.displayName);
|
|
||||||
final avatarLetter = _getAvatarLetter(creator.displayName);
|
|
||||||
final relativeTime = InvitationUtils.getRelativeTime(
|
final relativeTime = InvitationUtils.getRelativeTime(
|
||||||
_currentPost.creationDate,
|
_currentPost.creationDate,
|
||||||
);
|
);
|
||||||
@ -538,17 +610,10 @@ class _PostCardState extends State<PostCard> {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
UserAvatar(
|
||||||
|
displayName: creator.displayName,
|
||||||
|
avatarUrl: creator.avatar,
|
||||||
radius: 20,
|
radius: 20,
|
||||||
backgroundColor: avatarColor,
|
|
||||||
child: Text(
|
|
||||||
avatarLetter,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(width: 12),
|
SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user