feat: overhaul My Profile dialog

This commit is contained in:
Garrett Watson 2024-02-16 10:39:59 -05:00
parent 85a3d65d23
commit bcff2214aa
2 changed files with 160 additions and 94 deletions

View file

@ -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 {

View file

@ -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)),
]),
],
)),
]),
) )
], ],
), ),