✨ Badges
This commit is contained in:
		| @@ -182,5 +182,29 @@ | |||||||
|   "uploadAll": "Upload All", |   "uploadAll": "Upload All", | ||||||
|   "stickerCopyPlaceholder": "Copy Placeholder", |   "stickerCopyPlaceholder": "Copy Placeholder", | ||||||
|   "realmSelection": "Select a Realm", |   "realmSelection": "Select a Realm", | ||||||
|   "publisherIndividual": "Individual Publishers" |   "publisherIndividual": "Individual Publishers", | ||||||
|  |   "firstPostBadgeName": "First Post", | ||||||
|  |   "firstPostBadgeDescription": "Created your first post on Solar Network", | ||||||
|  |   "popularPostBadgeName": "Popular Post", | ||||||
|  |   "popularPostBadgeDescription": "Your post received significant engagement from the community", | ||||||
|  |   "viralPostBadgeName": "Viral Post", | ||||||
|  |   "viralPostBadgeDescription": "Your post went viral and reached a wide audience", | ||||||
|  |   "helpfulCommentBadgeName": "Helpful Comment", | ||||||
|  |   "helpfulCommentBadgeDescription": "Your comment was marked as helpful by others", | ||||||
|  |   "newcomerBadgeName": "Newcomer", | ||||||
|  |   "newcomerBadgeDescription": "Welcome to Solar Network! Start exploring and connecting", | ||||||
|  |   "contributorBadgeName": "Contributor", | ||||||
|  |   "contributorBadgeDescription": "Actively contributing to the Solar Network community", | ||||||
|  |   "expertBadgeName": "Expert", | ||||||
|  |   "expertBadgeDescription": "Recognized for your expertise and valuable contributions", | ||||||
|  |   "founderBadgeName": "Founder", | ||||||
|  |   "founderBadgeDescription": "One of the earliest members of Solar Network", | ||||||
|  |   "betaTesterBadgeName": "Beta Tester", | ||||||
|  |   "betaTesterBadgeDescription": "Helped test and improve Solar Network during beta", | ||||||
|  |   "moderatorBadgeName": "Moderator", | ||||||
|  |   "moderatorBadgeDescription": "Helping maintain and moderate the community", | ||||||
|  |   "developerBadgeName": "Developer", | ||||||
|  |   "developerBadgeDescription": "Contributing to Solar Network's development", | ||||||
|  |   "translatorBadgeName": "Translator", | ||||||
|  |   "translatorBadgeDescription": "Helping translate Solar Network into different languages" | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										104
									
								
								lib/models/badge.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								lib/models/badge.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | class BadgeInfo { | ||||||
|  |   final String type; | ||||||
|  |   final String name; | ||||||
|  |   final String description; | ||||||
|  |   final IconData icon; | ||||||
|  |   final Color color; | ||||||
|  |  | ||||||
|  |   const BadgeInfo({ | ||||||
|  |     required this.type, | ||||||
|  |     required this.name, | ||||||
|  |     required this.description, | ||||||
|  |     this.icon = Icons.star, | ||||||
|  |     this.color = Colors.blue, | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const Map<String, BadgeInfo> kBadgeTemplates = { | ||||||
|  |   'achievements.post.first': BadgeInfo( | ||||||
|  |     type: 'achievements.post.first', | ||||||
|  |     name: 'firstPostBadgeName', | ||||||
|  |     description: 'firstPostBadgeDescription', | ||||||
|  |     icon: Icons.create, | ||||||
|  |     color: Colors.green, | ||||||
|  |   ), | ||||||
|  |   'achievements.post.popular': BadgeInfo( | ||||||
|  |     type: 'achievements.post.popular', | ||||||
|  |     name: 'popularPostBadgeName', | ||||||
|  |     description: 'popularPostBadgeDescription', | ||||||
|  |     icon: Icons.trending_up, | ||||||
|  |     color: Colors.orange, | ||||||
|  |   ), | ||||||
|  |   'achievements.post.viral': BadgeInfo( | ||||||
|  |     type: 'achievements.post.viral', | ||||||
|  |     name: 'viralPostBadgeName', | ||||||
|  |     description: 'viralPostBadgeDescription', | ||||||
|  |     icon: Icons.whatshot, | ||||||
|  |     color: Colors.red, | ||||||
|  |   ), | ||||||
|  |   'achievements.comment.helpful': BadgeInfo( | ||||||
|  |     type: 'achievements.comment.helpful', | ||||||
|  |     name: 'helpfulCommentBadgeName', | ||||||
|  |     description: 'helpfulCommentBadgeDescription', | ||||||
|  |     icon: Icons.thumb_up, | ||||||
|  |     color: Colors.lightBlue, | ||||||
|  |   ), | ||||||
|  |   'ranks.newcomer': BadgeInfo( | ||||||
|  |     type: 'ranks.newcomer', | ||||||
|  |     name: 'newcomerBadgeName', | ||||||
|  |     description: 'newcomerBadgeDescription', | ||||||
|  |     icon: Icons.person_outline, | ||||||
|  |     color: Colors.blue, | ||||||
|  |   ), | ||||||
|  |   'ranks.contributor': BadgeInfo( | ||||||
|  |     type: 'ranks.contributor', | ||||||
|  |     name: 'contributorBadgeName', | ||||||
|  |     description: 'contributorBadgeDescription', | ||||||
|  |     icon: Icons.stars, | ||||||
|  |     color: Colors.purple, | ||||||
|  |   ), | ||||||
|  |   'ranks.expert': BadgeInfo( | ||||||
|  |     type: 'ranks.expert', | ||||||
|  |     name: 'expertBadgeName', | ||||||
|  |     description: 'expertBadgeDescription', | ||||||
|  |     icon: Icons.workspace_premium, | ||||||
|  |     color: Colors.amber, | ||||||
|  |   ), | ||||||
|  |   'event.founder': BadgeInfo( | ||||||
|  |     type: 'event.founder', | ||||||
|  |     name: 'founderBadgeName', | ||||||
|  |     description: 'founderBadgeDescription', | ||||||
|  |     icon: Icons.foundation, | ||||||
|  |     color: Colors.deepPurple, | ||||||
|  |   ), | ||||||
|  |   'event.beta.tester': BadgeInfo( | ||||||
|  |     type: 'event.beta.tester', | ||||||
|  |     name: 'betaTesterBadgeName', | ||||||
|  |     description: 'betaTesterBadgeDescription', | ||||||
|  |     icon: Icons.bug_report, | ||||||
|  |     color: Colors.teal, | ||||||
|  |   ), | ||||||
|  |   'special.moderator': BadgeInfo( | ||||||
|  |     type: 'special.moderator', | ||||||
|  |     name: 'moderatorBadgeName', | ||||||
|  |     description: 'moderatorBadgeDescription', | ||||||
|  |     icon: Icons.construction, | ||||||
|  |     color: Colors.indigo, | ||||||
|  |   ), | ||||||
|  |   'special.developer': BadgeInfo( | ||||||
|  |     type: 'special.developer', | ||||||
|  |     name: 'developerBadgeName', | ||||||
|  |     description: 'developerBadgeDescription', | ||||||
|  |     icon: Icons.code, | ||||||
|  |     color: Colors.indigo, | ||||||
|  |   ), | ||||||
|  |   'special.translator': BadgeInfo( | ||||||
|  |     type: 'special.translator', | ||||||
|  |     name: 'translatorBadgeName', | ||||||
|  |     description: 'translatorBadgeDescription', | ||||||
|  |     icon: Icons.code, | ||||||
|  |     color: Colors.grey, | ||||||
|  |   ), | ||||||
|  | }; | ||||||
| @@ -13,6 +13,7 @@ abstract class SnAccount with _$SnAccount { | |||||||
|     required String language, |     required String language, | ||||||
|     required bool isSuperuser, |     required bool isSuperuser, | ||||||
|     required SnAccountProfile profile, |     required SnAccountProfile profile, | ||||||
|  |     @Default([]) List<SnAccountBadge> badges, | ||||||
|     required DateTime createdAt, |     required DateTime createdAt, | ||||||
|     required DateTime updatedAt, |     required DateTime updatedAt, | ||||||
|     required DateTime? deletedAt, |     required DateTime? deletedAt, | ||||||
| @@ -63,3 +64,22 @@ abstract class SnAccountStatus with _$SnAccountStatus { | |||||||
|   factory SnAccountStatus.fromJson(Map<String, dynamic> json) => |   factory SnAccountStatus.fromJson(Map<String, dynamic> json) => | ||||||
|       _$SnAccountStatusFromJson(json); |       _$SnAccountStatusFromJson(json); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | abstract class SnAccountBadge with _$SnAccountBadge { | ||||||
|  |   const factory SnAccountBadge({ | ||||||
|  |     required String id, | ||||||
|  |     required String type, | ||||||
|  |     required String? label, | ||||||
|  |     required String? caption, | ||||||
|  |     required Map<String, dynamic> meta, | ||||||
|  |     required DateTime? expiredAt, | ||||||
|  |     required int accountId, | ||||||
|  |     required DateTime createdAt, | ||||||
|  |     required DateTime updatedAt, | ||||||
|  |     required DateTime? deletedAt, | ||||||
|  |   }) = _SnAccountBadge; | ||||||
|  |  | ||||||
|  |   factory SnAccountBadge.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$SnAccountBadgeFromJson(json); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ T _$identity<T>(T value) => value; | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnAccount { | mixin _$SnAccount { | ||||||
|  |  | ||||||
|  int get id; String get name; String get nick; String get language; bool get isSuperuser; SnAccountProfile get profile; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; |  int get id; String get name; String get nick; String get language; bool get isSuperuser; SnAccountProfile get profile; List<SnAccountBadge> get badges; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||||
| /// Create a copy of SnAccount | /// Create a copy of SnAccount | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @@ -29,16 +29,16 @@ $SnAccountCopyWith<SnAccount> get copyWith => _$SnAccountCopyWithImpl<SnAccount> | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccount&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.language, language) || other.language == language)&&(identical(other.isSuperuser, isSuperuser) || other.isSuperuser == isSuperuser)&&(identical(other.profile, profile) || other.profile == profile)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccount&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.language, language) || other.language == language)&&(identical(other.isSuperuser, isSuperuser) || other.isSuperuser == isSuperuser)&&(identical(other.profile, profile) || other.profile == profile)&&const DeepCollectionEquality().equals(other.badges, badges)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,id,name,nick,language,isSuperuser,profile,createdAt,updatedAt,deletedAt); | int get hashCode => Object.hash(runtimeType,id,name,nick,language,isSuperuser,profile,const DeepCollectionEquality().hash(badges),createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAccount(id: $id, name: $name, nick: $nick, language: $language, isSuperuser: $isSuperuser, profile: $profile, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAccount(id: $id, name: $name, nick: $nick, language: $language, isSuperuser: $isSuperuser, profile: $profile, badges: $badges, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -49,7 +49,7 @@ abstract mixin class $SnAccountCopyWith<$Res>  { | |||||||
|   factory $SnAccountCopyWith(SnAccount value, $Res Function(SnAccount) _then) = _$SnAccountCopyWithImpl; |   factory $SnAccountCopyWith(SnAccount value, $Res Function(SnAccount) _then) = _$SnAccountCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  int id, String name, String nick, String language, bool isSuperuser, SnAccountProfile profile, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  int id, String name, String nick, String language, bool isSuperuser, SnAccountProfile profile, List<SnAccountBadge> badges, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -66,7 +66,7 @@ class _$SnAccountCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAccount | /// Create a copy of SnAccount | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? nick = null,Object? language = null,Object? isSuperuser = null,Object? profile = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? nick = null,Object? language = null,Object? isSuperuser = null,Object? profile = null,Object? badges = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|   return _then(_self.copyWith( |   return _then(_self.copyWith( | ||||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
| as int,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | as int,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -74,7 +74,8 @@ as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non | |||||||
| as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable | as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable | ||||||
| as String,isSuperuser: null == isSuperuser ? _self.isSuperuser : isSuperuser // ignore: cast_nullable_to_non_nullable | as String,isSuperuser: null == isSuperuser ? _self.isSuperuser : isSuperuser // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,profile: null == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable | as bool,profile: null == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable | ||||||
| as SnAccountProfile,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | as SnAccountProfile,badges: null == badges ? _self.badges : badges // ignore: cast_nullable_to_non_nullable | ||||||
|  | as List<SnAccountBadge>,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?, | as DateTime?, | ||||||
| @@ -97,7 +98,7 @@ $SnAccountProfileCopyWith<$Res> get profile { | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnAccount implements SnAccount { | class _SnAccount implements SnAccount { | ||||||
|   const _SnAccount({required this.id, required this.name, required this.nick, required this.language, required this.isSuperuser, required this.profile, required this.createdAt, required this.updatedAt, required this.deletedAt}); |   const _SnAccount({required this.id, required this.name, required this.nick, required this.language, required this.isSuperuser, required this.profile, final  List<SnAccountBadge> badges = const [], required this.createdAt, required this.updatedAt, required this.deletedAt}): _badges = badges; | ||||||
|   factory _SnAccount.fromJson(Map<String, dynamic> json) => _$SnAccountFromJson(json); |   factory _SnAccount.fromJson(Map<String, dynamic> json) => _$SnAccountFromJson(json); | ||||||
|  |  | ||||||
| @override final  int id; | @override final  int id; | ||||||
| @@ -106,6 +107,13 @@ class _SnAccount implements SnAccount { | |||||||
| @override final  String language; | @override final  String language; | ||||||
| @override final  bool isSuperuser; | @override final  bool isSuperuser; | ||||||
| @override final  SnAccountProfile profile; | @override final  SnAccountProfile profile; | ||||||
|  |  final  List<SnAccountBadge> _badges; | ||||||
|  | @override@JsonKey() List<SnAccountBadge> get badges { | ||||||
|  |   if (_badges is EqualUnmodifiableListView) return _badges; | ||||||
|  |   // ignore: implicit_dynamic_type | ||||||
|  |   return EqualUnmodifiableListView(_badges); | ||||||
|  | } | ||||||
|  |  | ||||||
| @override final  DateTime createdAt; | @override final  DateTime createdAt; | ||||||
| @override final  DateTime updatedAt; | @override final  DateTime updatedAt; | ||||||
| @override final  DateTime? deletedAt; | @override final  DateTime? deletedAt; | ||||||
| @@ -123,16 +131,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccount&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.language, language) || other.language == language)&&(identical(other.isSuperuser, isSuperuser) || other.isSuperuser == isSuperuser)&&(identical(other.profile, profile) || other.profile == profile)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccount&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.language, language) || other.language == language)&&(identical(other.isSuperuser, isSuperuser) || other.isSuperuser == isSuperuser)&&(identical(other.profile, profile) || other.profile == profile)&&const DeepCollectionEquality().equals(other._badges, _badges)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,id,name,nick,language,isSuperuser,profile,createdAt,updatedAt,deletedAt); | int get hashCode => Object.hash(runtimeType,id,name,nick,language,isSuperuser,profile,const DeepCollectionEquality().hash(_badges),createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAccount(id: $id, name: $name, nick: $nick, language: $language, isSuperuser: $isSuperuser, profile: $profile, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAccount(id: $id, name: $name, nick: $nick, language: $language, isSuperuser: $isSuperuser, profile: $profile, badges: $badges, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -143,7 +151,7 @@ abstract mixin class _$SnAccountCopyWith<$Res> implements $SnAccountCopyWith<$Re | |||||||
|   factory _$SnAccountCopyWith(_SnAccount value, $Res Function(_SnAccount) _then) = __$SnAccountCopyWithImpl; |   factory _$SnAccountCopyWith(_SnAccount value, $Res Function(_SnAccount) _then) = __$SnAccountCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  int id, String name, String nick, String language, bool isSuperuser, SnAccountProfile profile, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  int id, String name, String nick, String language, bool isSuperuser, SnAccountProfile profile, List<SnAccountBadge> badges, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -160,7 +168,7 @@ class __$SnAccountCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAccount | /// Create a copy of SnAccount | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? nick = null,Object? language = null,Object? isSuperuser = null,Object? profile = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? nick = null,Object? language = null,Object? isSuperuser = null,Object? profile = null,Object? badges = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|   return _then(_SnAccount( |   return _then(_SnAccount( | ||||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
| as int,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | as int,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -168,7 +176,8 @@ as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non | |||||||
| as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable | as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable | ||||||
| as String,isSuperuser: null == isSuperuser ? _self.isSuperuser : isSuperuser // ignore: cast_nullable_to_non_nullable | as String,isSuperuser: null == isSuperuser ? _self.isSuperuser : isSuperuser // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,profile: null == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable | as bool,profile: null == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable | ||||||
| as SnAccountProfile,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | as SnAccountProfile,badges: null == badges ? _self._badges : badges // ignore: cast_nullable_to_non_nullable | ||||||
|  | as List<SnAccountBadge>,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?, | as DateTime?, | ||||||
| @@ -565,6 +574,172 @@ as DateTime?, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | mixin _$SnAccountBadge { | ||||||
|  |  | ||||||
|  |  String get id; String get type; String? get label; String? get caption; Map<String, dynamic> get meta; DateTime? get expiredAt; int get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||||
|  | /// Create a copy of SnAccountBadge | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnAccountBadgeCopyWith<SnAccountBadge> get copyWith => _$SnAccountBadgeCopyWithImpl<SnAccountBadge>(this as SnAccountBadge, _$identity); | ||||||
|  |  | ||||||
|  |   /// Serializes this SnAccountBadge to a JSON map. | ||||||
|  |   Map<String, dynamic> toJson(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccountBadge&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.label, label) || other.label == label)&&(identical(other.caption, caption) || other.caption == caption)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,type,label,caption,const DeepCollectionEquality().hash(meta),expiredAt,accountId,createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnAccountBadge(id: $id, type: $type, label: $label, caption: $caption, meta: $meta, expiredAt: $expiredAt, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class $SnAccountBadgeCopyWith<$Res>  { | ||||||
|  |   factory $SnAccountBadgeCopyWith(SnAccountBadge value, $Res Function(SnAccountBadge) _then) = _$SnAccountBadgeCopyWithImpl; | ||||||
|  | @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, String type, String? label, String? caption, Map<String, dynamic> meta, DateTime? expiredAt, int accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class _$SnAccountBadgeCopyWithImpl<$Res> | ||||||
|  |     implements $SnAccountBadgeCopyWith<$Res> { | ||||||
|  |   _$SnAccountBadgeCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final SnAccountBadge _self; | ||||||
|  |   final $Res Function(SnAccountBadge) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnAccountBadge | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? type = null,Object? label = freezed,Object? caption = freezed,Object? meta = null,Object? expiredAt = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|  |   return _then(_self.copyWith( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,caption: freezed == caption ? _self.caption : caption // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,meta: null == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable | ||||||
|  | as Map<String, dynamic>,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | @JsonSerializable() | ||||||
|  |  | ||||||
|  | class _SnAccountBadge implements SnAccountBadge { | ||||||
|  |   const _SnAccountBadge({required this.id, required this.type, required this.label, required this.caption, required final  Map<String, dynamic> meta, required this.expiredAt, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _meta = meta; | ||||||
|  |   factory _SnAccountBadge.fromJson(Map<String, dynamic> json) => _$SnAccountBadgeFromJson(json); | ||||||
|  |  | ||||||
|  | @override final  String id; | ||||||
|  | @override final  String type; | ||||||
|  | @override final  String? label; | ||||||
|  | @override final  String? caption; | ||||||
|  |  final  Map<String, dynamic> _meta; | ||||||
|  | @override Map<String, dynamic> get meta { | ||||||
|  |   if (_meta is EqualUnmodifiableMapView) return _meta; | ||||||
|  |   // ignore: implicit_dynamic_type | ||||||
|  |   return EqualUnmodifiableMapView(_meta); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @override final  DateTime? expiredAt; | ||||||
|  | @override final  int accountId; | ||||||
|  | @override final  DateTime createdAt; | ||||||
|  | @override final  DateTime updatedAt; | ||||||
|  | @override final  DateTime? deletedAt; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnAccountBadge | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | _$SnAccountBadgeCopyWith<_SnAccountBadge> get copyWith => __$SnAccountBadgeCopyWithImpl<_SnAccountBadge>(this, _$identity); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | Map<String, dynamic> toJson() { | ||||||
|  |   return _$SnAccountBadgeToJson(this, ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccountBadge&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.label, label) || other.label == label)&&(identical(other.caption, caption) || other.caption == caption)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,type,label,caption,const DeepCollectionEquality().hash(_meta),expiredAt,accountId,createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnAccountBadge(id: $id, type: $type, label: $label, caption: $caption, meta: $meta, expiredAt: $expiredAt, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class _$SnAccountBadgeCopyWith<$Res> implements $SnAccountBadgeCopyWith<$Res> { | ||||||
|  |   factory _$SnAccountBadgeCopyWith(_SnAccountBadge value, $Res Function(_SnAccountBadge) _then) = __$SnAccountBadgeCopyWithImpl; | ||||||
|  | @override @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, String type, String? label, String? caption, Map<String, dynamic> meta, DateTime? expiredAt, int accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class __$SnAccountBadgeCopyWithImpl<$Res> | ||||||
|  |     implements _$SnAccountBadgeCopyWith<$Res> { | ||||||
|  |   __$SnAccountBadgeCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final _SnAccountBadge _self; | ||||||
|  |   final $Res Function(_SnAccountBadge) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnAccountBadge | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? type = null,Object? label = freezed,Object? caption = freezed,Object? meta = null,Object? expiredAt = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|  |   return _then(_SnAccountBadge( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,caption: freezed == caption ? _self.caption : caption // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,meta: null == meta ? _self._meta : meta // ignore: cast_nullable_to_non_nullable | ||||||
|  | as Map<String, dynamic>,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // dart format on | // dart format on | ||||||
|   | |||||||
| @@ -13,6 +13,11 @@ _SnAccount _$SnAccountFromJson(Map<String, dynamic> json) => _SnAccount( | |||||||
|   language: json['language'] as String, |   language: json['language'] as String, | ||||||
|   isSuperuser: json['is_superuser'] as bool, |   isSuperuser: json['is_superuser'] as bool, | ||||||
|   profile: SnAccountProfile.fromJson(json['profile'] as Map<String, dynamic>), |   profile: SnAccountProfile.fromJson(json['profile'] as Map<String, dynamic>), | ||||||
|  |   badges: | ||||||
|  |       (json['badges'] as List<dynamic>?) | ||||||
|  |           ?.map((e) => SnAccountBadge.fromJson(e as Map<String, dynamic>)) | ||||||
|  |           .toList() ?? | ||||||
|  |       const [], | ||||||
|   createdAt: DateTime.parse(json['created_at'] as String), |   createdAt: DateTime.parse(json['created_at'] as String), | ||||||
|   updatedAt: DateTime.parse(json['updated_at'] as String), |   updatedAt: DateTime.parse(json['updated_at'] as String), | ||||||
|   deletedAt: |   deletedAt: | ||||||
| @@ -29,6 +34,7 @@ Map<String, dynamic> _$SnAccountToJson(_SnAccount instance) => | |||||||
|       'language': instance.language, |       'language': instance.language, | ||||||
|       'is_superuser': instance.isSuperuser, |       'is_superuser': instance.isSuperuser, | ||||||
|       'profile': instance.profile.toJson(), |       'profile': instance.profile.toJson(), | ||||||
|  |       'badges': instance.badges.map((e) => e.toJson()).toList(), | ||||||
|       'created_at': instance.createdAt.toIso8601String(), |       'created_at': instance.createdAt.toIso8601String(), | ||||||
|       'updated_at': instance.updatedAt.toIso8601String(), |       'updated_at': instance.updatedAt.toIso8601String(), | ||||||
|       'deleted_at': instance.deletedAt?.toIso8601String(), |       'deleted_at': instance.deletedAt?.toIso8601String(), | ||||||
| @@ -114,3 +120,37 @@ Map<String, dynamic> _$SnAccountStatusToJson(_SnAccountStatus instance) => | |||||||
|       'updated_at': instance.updatedAt.toIso8601String(), |       'updated_at': instance.updatedAt.toIso8601String(), | ||||||
|       'deleted_at': instance.deletedAt?.toIso8601String(), |       'deleted_at': instance.deletedAt?.toIso8601String(), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | _SnAccountBadge _$SnAccountBadgeFromJson(Map<String, dynamic> json) => | ||||||
|  |     _SnAccountBadge( | ||||||
|  |       id: json['id'] as String, | ||||||
|  |       type: json['type'] as String, | ||||||
|  |       label: json['label'] as String?, | ||||||
|  |       caption: json['caption'] as String?, | ||||||
|  |       meta: json['meta'] as Map<String, dynamic>, | ||||||
|  |       expiredAt: | ||||||
|  |           json['expired_at'] == null | ||||||
|  |               ? null | ||||||
|  |               : DateTime.parse(json['expired_at'] as String), | ||||||
|  |       accountId: (json['account_id'] as num).toInt(), | ||||||
|  |       createdAt: DateTime.parse(json['created_at'] as String), | ||||||
|  |       updatedAt: DateTime.parse(json['updated_at'] as String), | ||||||
|  |       deletedAt: | ||||||
|  |           json['deleted_at'] == null | ||||||
|  |               ? null | ||||||
|  |               : DateTime.parse(json['deleted_at'] as String), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$SnAccountBadgeToJson(_SnAccountBadge instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'id': instance.id, | ||||||
|  |       'type': instance.type, | ||||||
|  |       'label': instance.label, | ||||||
|  |       'caption': instance.caption, | ||||||
|  |       'meta': instance.meta, | ||||||
|  |       'expired_at': instance.expiredAt?.toIso8601String(), | ||||||
|  |       'account_id': instance.accountId, | ||||||
|  |       'created_at': instance.createdAt.toIso8601String(), | ||||||
|  |       'updated_at': instance.updatedAt.toIso8601String(), | ||||||
|  |       'deleted_at': instance.deletedAt?.toIso8601String(), | ||||||
|  |     }; | ||||||
|   | |||||||
| @@ -36,7 +36,7 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|               child: Column( |               child: Column( | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |                 crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                 children: [ |                 children: [ | ||||||
|                   if (user.value?.profile.background != null) |                   if (user.value?.profile.backgroundId != null) | ||||||
|                     ClipRRect( |                     ClipRRect( | ||||||
|                       borderRadius: BorderRadius.only( |                       borderRadius: BorderRadius.only( | ||||||
|                         topLeft: Radius.circular(8), |                         topLeft: Radius.circular(8), | ||||||
| @@ -44,8 +44,8 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|                       ), |                       ), | ||||||
|                       child: AspectRatio( |                       child: AspectRatio( | ||||||
|                         aspectRatio: 16 / 7, |                         aspectRatio: 16 / 7, | ||||||
|                         child: CloudFileWidget( |                         child: CloudImageWidget( | ||||||
|                           item: user.value!.profile.background!, |                           fileId: user.value!.profile.backgroundId!, | ||||||
|                           fit: BoxFit.cover, |                           fit: BoxFit.cover, | ||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
| @@ -65,7 +65,8 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|                           ); |                           ); | ||||||
|                         }, |                         }, | ||||||
|                       ), |                       ), | ||||||
|                       Column( |                       Expanded( | ||||||
|  |                         child: Column( | ||||||
|                           crossAxisAlignment: CrossAxisAlignment.start, |                           crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                           children: [ |                           children: [ | ||||||
|                             Row( |                             Row( | ||||||
| @@ -79,9 +80,12 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|                             ), |                             ), | ||||||
|                             Text( |                             Text( | ||||||
|                               user.value!.profile.bio ?? 'No description yet.', |                               user.value!.profile.bio ?? 'No description yet.', | ||||||
|  |                               maxLines: 1, | ||||||
|  |                               overflow: TextOverflow.ellipsis, | ||||||
|                             ), |                             ), | ||||||
|                           ], |                           ], | ||||||
|                         ), |                         ), | ||||||
|  |                       ), | ||||||
|                     ], |                     ], | ||||||
|                   ).padding(horizontal: 16, top: 16), |                   ).padding(horizontal: 16, top: 16), | ||||||
|                   AccountStatusCreationWidget(uname: user.value!.name), |                   AccountStatusCreationWidget(uname: user.value!.name), | ||||||
|   | |||||||
| @@ -143,7 +143,9 @@ class UpdateProfileScreen extends HookConsumerWidget { | |||||||
|         title: Text('updateYourProfile').tr(), |         title: Text('updateYourProfile').tr(), | ||||||
|         leading: const PageBackButton(), |         leading: const PageBackButton(), | ||||||
|       ), |       ), | ||||||
|       body: Column( |       body: SingleChildScrollView( | ||||||
|  |         padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), | ||||||
|  |         child: Column( | ||||||
|           crossAxisAlignment: CrossAxisAlignment.start, |           crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|           children: [ |           children: [ | ||||||
|             AspectRatio( |             AspectRatio( | ||||||
| @@ -254,6 +256,7 @@ class UpdateProfileScreen extends HookConsumerWidget { | |||||||
|             ), |             ), | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|  |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,12 +1,16 @@ | |||||||
| import 'package:auto_route/auto_route.dart'; | import 'package:auto_route/auto_route.dart'; | ||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:gap/gap.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/user.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
|  | import 'package:island/widgets/account/badge.dart'; | ||||||
|  | import 'package:island/widgets/account/status.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/content/cloud_files.dart'; | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
| part 'profile.g.dart'; | part 'profile.g.dart'; | ||||||
|  |  | ||||||
| @@ -28,6 +32,13 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final accountAsync = ref.watch(accountProvider(name)); |     final accountAsync = ref.watch(accountProvider(name)); | ||||||
|  |  | ||||||
|  |     final iconShadow = Shadow( | ||||||
|  |       color: Colors.black54, | ||||||
|  |       blurRadius: 5.0, | ||||||
|  |       offset: Offset(1.0, 1.0), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     return accountAsync.when( |     return accountAsync.when( | ||||||
|       data: |       data: | ||||||
|           (data) => AppScaffold( |           (data) => AppScaffold( | ||||||
| @@ -36,6 +47,7 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                 SliverAppBar( |                 SliverAppBar( | ||||||
|                   expandedHeight: 180, |                   expandedHeight: 180, | ||||||
|                   pinned: true, |                   pinned: true, | ||||||
|  |                   leading: PageBackButton(shadows: [iconShadow]), | ||||||
|                   flexibleSpace: FlexibleSpaceBar( |                   flexibleSpace: FlexibleSpaceBar( | ||||||
|                     background: |                     background: | ||||||
|                         data.profile.backgroundId != null |                         data.profile.backgroundId != null | ||||||
| @@ -47,33 +59,67 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                                   Theme.of(context).appBarTheme.backgroundColor, |                                   Theme.of(context).appBarTheme.backgroundColor, | ||||||
|                             ), |                             ), | ||||||
|                     title: Text( |                     title: Text( | ||||||
|                       data.name, |                       data.nick, | ||||||
|                       style: TextStyle( |                       style: TextStyle( | ||||||
|                         color: Theme.of(context).appBarTheme.foregroundColor, |                         color: Theme.of(context).appBarTheme.foregroundColor, | ||||||
|                         shadows: [ |                         shadows: [iconShadow], | ||||||
|                           Shadow( |  | ||||||
|                             color: Colors.black54, |  | ||||||
|                             blurRadius: 5.0, |  | ||||||
|                             offset: Offset(1.0, 1.0), |  | ||||||
|                           ), |  | ||||||
|                         ], |  | ||||||
|                       ), |                       ), | ||||||
|                     ), |                     ), | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|                 SliverToBoxAdapter( |                 SliverToBoxAdapter( | ||||||
|                   child: Padding( |                   child: Row( | ||||||
|                     padding: const EdgeInsets.all(16.0), |  | ||||||
|                     child: Column( |  | ||||||
|                     crossAxisAlignment: CrossAxisAlignment.start, |                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                     spacing: 20, | ||||||
|                     children: [ |                     children: [ | ||||||
|  |                       ProfilePictureWidget( | ||||||
|  |                         fileId: data.profile.pictureId!, | ||||||
|  |                         radius: 32, | ||||||
|  |                       ), | ||||||
|  |                       Expanded( | ||||||
|  |                         child: Column( | ||||||
|  |                           crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                           children: [ | ||||||
|  |                             Row( | ||||||
|  |                               spacing: 6, | ||||||
|  |                               children: [ | ||||||
|  |                                 Text(data.nick).fontSize(20), | ||||||
|                                 Text( |                                 Text( | ||||||
|                           data.profile.bio ?? '', |                                   '@${data.name}', | ||||||
|                           style: const TextStyle(fontSize: 16), |                                 ).fontSize(14).opacity(0.85), | ||||||
|  |                               ], | ||||||
|  |                             ), | ||||||
|  |                             AccountStatusWidget( | ||||||
|  |                               uname: name, | ||||||
|  |                               padding: EdgeInsets.zero, | ||||||
|                             ), |                             ), | ||||||
|                           ], |                           ], | ||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|  |                     ], | ||||||
|  |                   ).padding(horizontal: 24, top: 24, bottom: 8), | ||||||
|  |                 ), | ||||||
|  |                 if (data.badges.isNotEmpty) | ||||||
|  |                   SliverToBoxAdapter( | ||||||
|  |                     child: BadgeList( | ||||||
|  |                       badges: data.badges, | ||||||
|  |                     ).padding(horizontal: 24, bottom: 24), | ||||||
|  |                   ) | ||||||
|  |                 else | ||||||
|  |                   const Gap(16), | ||||||
|  |                 SliverToBoxAdapter( | ||||||
|  |                   child: const Divider(height: 1).padding(bottom: 24), | ||||||
|  |                 ), | ||||||
|  |                 SliverToBoxAdapter( | ||||||
|  |                   child: Column( | ||||||
|  |                     crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                     children: [ | ||||||
|  |                       Text('bio').tr().bold(), | ||||||
|  |                       if (data.profile.bio != null && | ||||||
|  |                           data.profile.bio!.isNotEmpty) | ||||||
|  |                         Text(data.profile.bio!), | ||||||
|  |                     ], | ||||||
|  |                   ).padding(horizontal: 24), | ||||||
|                 ), |                 ), | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								lib/widgets/account/badge.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/widgets/account/badge.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:island/models/user.dart'; | ||||||
|  | import 'package:island/models/badge.dart'; | ||||||
|  |  | ||||||
|  | class BadgeList extends StatelessWidget { | ||||||
|  |   final List<SnAccountBadge> badges; | ||||||
|  |   const BadgeList({super.key, required this.badges}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Wrap( | ||||||
|  |       spacing: 8, | ||||||
|  |       runSpacing: 8, | ||||||
|  |       children: badges.map((badge) => BadgeItem(badge: badge)).toList(), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class BadgeItem extends StatelessWidget { | ||||||
|  |   final SnAccountBadge badge; | ||||||
|  |   const BadgeItem({super.key, required this.badge}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     final template = kBadgeTemplates[badge.type]; | ||||||
|  |     final name = badge.label ?? template?.name.tr() ?? 'unknown'.tr(); | ||||||
|  |     final description = badge.caption ?? template?.description.tr() ?? ''; | ||||||
|  |  | ||||||
|  |     return Tooltip( | ||||||
|  |       message: '$name\n$description', | ||||||
|  |       child: Container( | ||||||
|  |         padding: const EdgeInsets.all(4), | ||||||
|  |         decoration: BoxDecoration( | ||||||
|  |           color: (template?.color ?? Colors.blue).withOpacity(0.1), | ||||||
|  |           shape: BoxShape.circle, | ||||||
|  |         ), | ||||||
|  |         child: Icon( | ||||||
|  |           template?.icon ?? Icons.stars, | ||||||
|  |           color: template?.color ?? Colors.orange, | ||||||
|  |           size: 20, | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -50,7 +50,10 @@ class AccountStatusCreationWidget extends HookConsumerWidget { | |||||||
|         data: |         data: | ||||||
|             (status) => |             (status) => | ||||||
|                 (status?.isCustomized ?? false) |                 (status?.isCustomized ?? false) | ||||||
|                     ? AccountStatusWidget(uname: uname) |                     ? Padding( | ||||||
|  |                       padding: const EdgeInsets.only(left: 4), | ||||||
|  |                       child: AccountStatusWidget(uname: uname), | ||||||
|  |                     ) | ||||||
|                     : Padding( |                     : Padding( | ||||||
|                       padding: |                       padding: | ||||||
|                           padding ?? |                           padding ?? | ||||||
| @@ -112,15 +115,13 @@ class AccountStatusWidget extends HookConsumerWidget { | |||||||
|       child: Row( |       child: Row( | ||||||
|         spacing: 4, |         spacing: 4, | ||||||
|         children: [ |         children: [ | ||||||
|           if (!(userStatus.value?.isCustomized ?? false)) |           if (userStatus.value!.isOnline) | ||||||
|             Icon(Symbols.keyboard_arrow_up) |  | ||||||
|           else if (userStatus.value!.isOnline) |  | ||||||
|             Icon( |             Icon( | ||||||
|               Symbols.circle, |               Symbols.circle, | ||||||
|               fill: 1, |               fill: 1, | ||||||
|               color: Colors.green, |               color: Colors.green, | ||||||
|               size: 16, |               size: 16, | ||||||
|             ).padding(all: 4) |             ).padding(right: 4) | ||||||
|           else |           else | ||||||
|             Icon(Symbols.circle, color: Colors.grey, size: 16).padding(all: 4), |             Icon(Symbols.circle, color: Colors.grey, size: 16).padding(all: 4), | ||||||
|           if (userStatus.value?.isCustomized ?? false) |           if (userStatus.value?.isCustomized ?? false) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user