✨ Badges
This commit is contained in:
parent
ee8d502fc6
commit
610b924daf
@ -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,22 +65,26 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Column(
|
Expanded(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Row(
|
children: [
|
||||||
spacing: 4,
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
spacing: 4,
|
||||||
textBaseline: TextBaseline.alphabetic,
|
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||||
children: [
|
textBaseline: TextBaseline.alphabetic,
|
||||||
Text(user.value!.nick).bold().fontSize(16),
|
children: [
|
||||||
Text('@${user.value!.name}'),
|
Text(user.value!.nick).bold().fontSize(16),
|
||||||
],
|
Text('@${user.value!.name}'),
|
||||||
),
|
],
|
||||||
Text(
|
),
|
||||||
user.value!.profile.bio ?? 'No description yet.',
|
Text(
|
||||||
),
|
user.value!.profile.bio ?? 'No description yet.',
|
||||||
],
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).padding(horizontal: 16, top: 16),
|
).padding(horizontal: 16, top: 16),
|
||||||
|
@ -143,116 +143,119 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
|||||||
title: Text('updateYourProfile').tr(),
|
title: Text('updateYourProfile').tr(),
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: SingleChildScrollView(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
|
||||||
children: [
|
child: Column(
|
||||||
AspectRatio(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
aspectRatio: 16 / 7,
|
children: [
|
||||||
child: Stack(
|
AspectRatio(
|
||||||
clipBehavior: Clip.none,
|
aspectRatio: 16 / 7,
|
||||||
fit: StackFit.expand,
|
child: Stack(
|
||||||
children: [
|
clipBehavior: Clip.none,
|
||||||
GestureDetector(
|
fit: StackFit.expand,
|
||||||
child: Container(
|
children: [
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
GestureDetector(
|
||||||
child:
|
child: Container(
|
||||||
user.value!.profile.background != null
|
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||||
? CloudFileWidget(
|
child:
|
||||||
item: user.value!.profile.background!,
|
user.value!.profile.background != null
|
||||||
fit: BoxFit.cover,
|
? CloudFileWidget(
|
||||||
)
|
item: user.value!.profile.background!,
|
||||||
: const SizedBox.shrink(),
|
fit: BoxFit.cover,
|
||||||
),
|
)
|
||||||
onTap: () {
|
: const SizedBox.shrink(),
|
||||||
updateProfilePicture('background');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
left: 20,
|
|
||||||
bottom: -32,
|
|
||||||
child: GestureDetector(
|
|
||||||
child: ProfilePictureWidget(
|
|
||||||
fileId: user.value!.profile.pictureId,
|
|
||||||
radius: 40,
|
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
updateProfilePicture('picture');
|
updateProfilePicture('background');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
Positioned(
|
||||||
],
|
left: 20,
|
||||||
|
bottom: -32,
|
||||||
|
child: GestureDetector(
|
||||||
|
child: ProfilePictureWidget(
|
||||||
|
fileId: user.value!.profile.pictureId,
|
||||||
|
radius: 40,
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
updateProfilePicture('picture');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).padding(bottom: 32),
|
||||||
|
Text('accountBasicInfo')
|
||||||
|
.tr()
|
||||||
|
.bold()
|
||||||
|
.fontSize(18)
|
||||||
|
.padding(horizontal: 24, top: 16, bottom: 12),
|
||||||
|
Form(
|
||||||
|
key: formKeyBasicInfo,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 16,
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'username'.tr(),
|
||||||
|
helperText: 'usernameCannotChangeHint'.tr(),
|
||||||
|
prefixText: '@',
|
||||||
|
),
|
||||||
|
controller: usernameController,
|
||||||
|
readOnly: true,
|
||||||
|
onTapOutside:
|
||||||
|
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
decoration: InputDecoration(labelText: 'nickname'.tr()),
|
||||||
|
controller: nicknameController,
|
||||||
|
onTapOutside:
|
||||||
|
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: TextButton.icon(
|
||||||
|
onPressed: submitting.value ? null : updateBasicInfo,
|
||||||
|
label: Text('saveChanges').tr(),
|
||||||
|
icon: const Icon(Symbols.save),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 24),
|
||||||
),
|
),
|
||||||
).padding(bottom: 32),
|
Text('accountProfile')
|
||||||
Text('accountBasicInfo')
|
.tr()
|
||||||
.tr()
|
.bold()
|
||||||
.bold()
|
.fontSize(18)
|
||||||
.fontSize(18)
|
.padding(horizontal: 24, top: 16, bottom: 8),
|
||||||
.padding(horizontal: 24, top: 16, bottom: 12),
|
Form(
|
||||||
Form(
|
key: formKeyProfile,
|
||||||
key: formKeyBasicInfo,
|
child: Column(
|
||||||
child: Column(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
spacing: 16,
|
||||||
spacing: 16,
|
children: [
|
||||||
children: [
|
TextFormField(
|
||||||
TextFormField(
|
decoration: InputDecoration(labelText: 'bio'.tr()),
|
||||||
decoration: InputDecoration(
|
maxLines: null,
|
||||||
labelText: 'username'.tr(),
|
minLines: 3,
|
||||||
helperText: 'usernameCannotChangeHint'.tr(),
|
controller: bioController,
|
||||||
prefixText: '@',
|
onTapOutside:
|
||||||
|
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
controller: usernameController,
|
Align(
|
||||||
readOnly: true,
|
alignment: Alignment.centerRight,
|
||||||
onTapOutside:
|
child: TextButton.icon(
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
onPressed: submitting.value ? null : updateProfile,
|
||||||
),
|
label: Text('saveChanges').tr(),
|
||||||
TextFormField(
|
icon: const Icon(Symbols.save),
|
||||||
decoration: InputDecoration(labelText: 'nickname'.tr()),
|
),
|
||||||
controller: nicknameController,
|
|
||||||
onTapOutside:
|
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
child: TextButton.icon(
|
|
||||||
onPressed: submitting.value ? null : updateBasicInfo,
|
|
||||||
label: Text('saveChanges').tr(),
|
|
||||||
icon: const Icon(Symbols.save),
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
).padding(horizontal: 24),
|
||||||
).padding(horizontal: 24),
|
),
|
||||||
),
|
],
|
||||||
Text('accountProfile')
|
),
|
||||||
.tr()
|
|
||||||
.bold()
|
|
||||||
.fontSize(18)
|
|
||||||
.padding(horizontal: 24, top: 16, bottom: 8),
|
|
||||||
Form(
|
|
||||||
key: formKeyProfile,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
spacing: 16,
|
|
||||||
children: [
|
|
||||||
TextFormField(
|
|
||||||
decoration: InputDecoration(labelText: 'bio'.tr()),
|
|
||||||
maxLines: null,
|
|
||||||
minLines: 3,
|
|
||||||
controller: bioController,
|
|
||||||
onTapOutside:
|
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
child: TextButton.icon(
|
|
||||||
onPressed: submitting.value ? null : updateProfile,
|
|
||||||
label: Text('saveChanges').tr(),
|
|
||||||
icon: const Icon(Symbols.save),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 24),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Column(
|
spacing: 20,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
ProfilePictureWidget(
|
||||||
Text(
|
fileId: data.profile.pictureId!,
|
||||||
data.profile.bio ?? '',
|
radius: 32,
|
||||||
style: const TextStyle(fontSize: 16),
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
spacing: 6,
|
||||||
|
children: [
|
||||||
|
Text(data.nick).fontSize(20),
|
||||||
|
Text(
|
||||||
|
'@${data.name}',
|
||||||
|
).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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user