feat: overhaul My Profile dialog
This commit is contained in:
parent
85a3d65d23
commit
bcff2214aa
2 changed files with 160 additions and 94 deletions
|
@ -46,23 +46,15 @@ class PersonalProfile {
|
||||||
bool get isPatreonSupporter =>
|
bool get isPatreonSupporter =>
|
||||||
supporterMetadata.whereType<PatreonSupporter>().any((element) => element.isActiveSupporter);
|
supporterMetadata.whereType<PatreonSupporter>().any((element) => element.isActiveSupporter);
|
||||||
|
|
||||||
static final List<AccountType> accountTypes = [
|
|
||||||
AccountType(label: "Standard Account", color: const Color(0xFF86888B)),
|
|
||||||
AccountType(label: "Patreon Supporter", color: const Color(0xFFFF7676)),
|
|
||||||
AccountType(label: "Resonite Mentor", color: const Color(0xFF59EB5C)),
|
|
||||||
AccountType(label: "Resonite Moderator", color: const Color(0xFF61D1FA)),
|
|
||||||
AccountType(label: "Resonite Team", color: const Color.fromARGB(255, 255, 230, 0)),
|
|
||||||
];
|
|
||||||
|
|
||||||
AccountType get accountType => tags.contains("team member")
|
AccountType get accountType => tags.contains("team member")
|
||||||
? accountTypes[4]
|
? AccountType(label: "Resonite Team", color: const Color.fromARGB(255, 255, 230, 0))
|
||||||
: tags.contains("moderator")
|
: tags.contains("moderator")
|
||||||
? accountTypes[3]
|
? AccountType(label: "Resonite Moderator", color: const Color(0xFF61D1FA))
|
||||||
: tags.contains("mentor")
|
: tags.contains("mentor")
|
||||||
? accountTypes[2]
|
? AccountType(label: "Resonite Mentor", color: const Color(0xFF59EB5C))
|
||||||
: isPatreonSupporter
|
: isPatreonSupporter
|
||||||
? accountTypes[1]
|
? AccountType(label: "Patreon Supporter", color: const Color(0xFFFF7676))
|
||||||
: accountTypes[0];
|
: AccountType(label: "Standard Account", color: const Color(0xFF86888B));
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccountType {
|
class AccountType {
|
||||||
|
|
|
@ -33,84 +33,138 @@ class _MyProfileDialogState extends State<MyProfileDialog> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final tt = Theme.of(context).textTheme;
|
final textTheme = Theme.of(context).textTheme;
|
||||||
DateFormat dateFormat = DateFormat.yMd();
|
DateFormat dateFormat = DateFormat.yMd();
|
||||||
return Dialog(
|
return Dialog(
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||||
|
backgroundColor: const Color(0xFF11151D),
|
||||||
child: FutureBuilder(
|
child: FutureBuilder(
|
||||||
future: _personalProfileFuture,
|
future: _personalProfileFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
final profile = snapshot.data as PersonalProfile;
|
final profile = snapshot.data as PersonalProfile;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.only(bottom: 16),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Container(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
padding: const EdgeInsets.all(16),
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
decoration: const BoxDecoration(
|
||||||
children: [
|
color: Color(0x6611151D),
|
||||||
GenericAvatar(
|
),
|
||||||
imageUri: Aux.resdbToHttp(profile.userProfile.iconUrl),
|
child: Row(
|
||||||
radius: 32,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
),
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
Padding(
|
children: [
|
||||||
padding: const EdgeInsets.only(left: 12),
|
GenericAvatar(
|
||||||
child: Column(
|
imageUri: Aux.resdbToHttp(profile.userProfile.iconUrl),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
radius: 32,
|
||||||
children: [
|
),
|
||||||
Text(profile.username, style: tt.titleLarge),
|
Padding(
|
||||||
Text(
|
padding: const EdgeInsets.only(left: 12),
|
||||||
profile.accountType.label,
|
child: Column(
|
||||||
style: tt.labelMedium?.copyWith(color: profile.accountType.color),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
children: [
|
||||||
],
|
Text(profile.username, style: textTheme.titleLarge),
|
||||||
)),
|
Text(
|
||||||
],
|
profile.accountType.label,
|
||||||
|
style: textTheme.labelMedium?.copyWith(color: profile.accountType.color),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 12,
|
||||||
),
|
),
|
||||||
Row(
|
Padding(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
children: [
|
child: Column(
|
||||||
Text(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
"User ID: ",
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
style: tt.labelLarge,
|
children: [
|
||||||
),
|
Text(
|
||||||
Text(profile.id)
|
"Account Info",
|
||||||
],
|
style: textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
Row(
|
const SizedBox(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
height: 8,
|
||||||
children: [
|
),
|
||||||
Text(
|
ClipRRect(
|
||||||
"Email: ",
|
borderRadius: BorderRadius.circular(8),
|
||||||
style: tt.labelLarge,
|
child: Container(
|
||||||
),
|
width: double.infinity,
|
||||||
Text(profile.email)
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
],
|
color: const Color(0x6611151D),
|
||||||
),
|
child: Column(
|
||||||
Row(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Column(
|
||||||
"Patreon Supporter: ",
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
style: tt.labelLarge,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
children: [
|
||||||
Text(profile.isPatreonSupporter ? "Yes" : "No")
|
Text(
|
||||||
],
|
"User ID",
|
||||||
),
|
style: textTheme.titleSmall,
|
||||||
Row(
|
),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
Text(profile.id,
|
||||||
children: [
|
style: textTheme.bodySmall?.copyWith(color: const Color(0xFFE1E1E0)))
|
||||||
Text(
|
],
|
||||||
"2FA: ",
|
),
|
||||||
style: tt.labelLarge,
|
const SizedBox(
|
||||||
),
|
height: 8,
|
||||||
Text(profile.twoFactor ? "Enabled" : "Disabled")
|
),
|
||||||
],
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Email",
|
||||||
|
style: textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
Text(profile.email,
|
||||||
|
style: textTheme.bodySmall?.copyWith(color: const Color(0xFFE1E1E0)))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Patreon Supporter",
|
||||||
|
style: textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
Text(profile.isPatreonSupporter ? "Yes" : "No",
|
||||||
|
style: textTheme.bodySmall?.copyWith(color: const Color(0xFFE1E1E0)))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Two Factor Authentication",
|
||||||
|
style: textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
Text(profile.twoFactor ? "Enabled" : "Disabled",
|
||||||
|
style: textTheme.bodySmall?.copyWith(color: const Color(0xFFE1E1E0)))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (profile.publicBanExpiration?.isAfter(DateTime.now()) ?? false)
|
if (profile.publicBanExpiration?.isAfter(DateTime.now()) ?? false)
|
||||||
Row(
|
Row(
|
||||||
|
@ -118,11 +172,14 @@ class _MyProfileDialogState extends State<MyProfileDialog> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Ban Expiration: ",
|
"Ban Expiration: ",
|
||||||
style: tt.labelLarge,
|
style: textTheme.labelLarge,
|
||||||
),
|
),
|
||||||
Text(dateFormat.format(profile.publicBanExpiration!))
|
Text(dateFormat.format(profile.publicBanExpiration!))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
future: _storageQuotaFuture,
|
future: _storageQuotaFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
@ -132,9 +189,6 @@ class _MyProfileDialogState extends State<MyProfileDialog> {
|
||||||
maxBytes: storage?.fullQuotaBytes ?? 1,
|
maxBytes: storage?.fullQuotaBytes ?? 1,
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
const SizedBox(
|
|
||||||
height: 12,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -179,28 +233,48 @@ class StorageIndicator extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final value = usedBytes / maxBytes;
|
final value = usedBytes / maxBytes;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(top: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Text("Storage", style: Theme.of(context).textTheme.titleMedium),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text("Storage:", style: Theme.of(context).textTheme.titleMedium),
|
|
||||||
Text(// Displayed in GiB instead of GB for consistency with Resonite
|
|
||||||
"${(usedBytes * 9.3132257461548e-10).toStringAsFixed(2)}/${(maxBytes * 9.3132257461548e-10).toStringAsFixed(2)} GB"),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: LinearProgressIndicator(
|
child: Stack(children: [
|
||||||
minHeight: 12,
|
LinearProgressIndicator(
|
||||||
color: value > 0.95 ? Theme.of(context).colorScheme.error : null,
|
value: value,
|
||||||
value: value,
|
minHeight: 48,
|
||||||
),
|
color: value > 0.95 ? Theme.of(context).colorScheme.error : const Color(0xFF61D1FA),
|
||||||
|
backgroundColor: const Color(0xFF284C5D),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 48,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${(value * 100).toStringAsFixed(0)}%",
|
||||||
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
// Displayed in GiB instead of GB for consistency with Resonite
|
||||||
|
Text(
|
||||||
|
"${(usedBytes * 9.3132257461548e-10).toStringAsFixed(2)} GB of ${(maxBytes * 9.3132257461548e-10).toStringAsFixed(2)} GB"),
|
||||||
|
Text("Storage Space Used",
|
||||||
|
style: Theme.of(context).textTheme.labelSmall?.copyWith(fontSize: 10)),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
]),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue