Fix user storage indicator

This commit is contained in:
Nutcake 2023-10-10 10:33:51 +02:00
parent fd5b234ba9
commit 1c77951431
4 changed files with 148 additions and 30 deletions

View file

@ -39,4 +39,11 @@ class UserApi {
final data = jsonDecode(response.body); final data = jsonDecode(response.body);
return PersonalProfile.fromMap(data); return PersonalProfile.fromMap(data);
} }
static Future<StorageQuota> getStorageQuota(ApiClient client) async {
final response = await client.get("/users/${client.userId}/storage");
client.checkResponse(response);
final data = jsonDecode(response.body);
return StorageQuota.fromMap(data);
}
} }

View file

@ -1,3 +1,5 @@
import 'package:recon/auxiliary.dart';
import 'package:recon/models/users/entitlement.dart';
import 'package:recon/models/users/user_profile.dart'; import 'package:recon/models/users/user_profile.dart';
class PersonalProfile { class PersonalProfile {
@ -6,18 +8,21 @@ class PersonalProfile {
final String email; final String email;
final DateTime? publicBanExpiration; final DateTime? publicBanExpiration;
final String? publicBanType; final String? publicBanType;
final List<StorageQuotas> storageQuotas;
final Map<String, int> quotaBytesSource;
final int quotaBytes;
final int usedBytes;
final bool twoFactor; final bool twoFactor;
final bool isPatreonSupporter;
final UserProfile userProfile; final UserProfile userProfile;
final List<Entitlement> entitlements;
final List<SupporterMetadata> supporterMetadata;
PersonalProfile({ PersonalProfile({
required this.id, required this.username, required this.email, required this.publicBanExpiration, required this.id,
required this.publicBanType, required this.storageQuotas, required this.quotaBytesSource, required this.quotaBytes, required this.username,
required this.usedBytes, required this.twoFactor, required this.isPatreonSupporter, required this.userProfile, required this.email,
required this.publicBanExpiration,
required this.publicBanType,
required this.twoFactor,
required this.userProfile,
required this.entitlements,
required this.supporterMetadata,
}); });
factory PersonalProfile.fromMap(Map map) { factory PersonalProfile.fromMap(Map map) {
@ -27,34 +32,83 @@ class PersonalProfile {
email: map["email"] ?? "", email: map["email"] ?? "",
publicBanExpiration: DateTime.tryParse(map["publicBanExpiration"] ?? ""), publicBanExpiration: DateTime.tryParse(map["publicBanExpiration"] ?? ""),
publicBanType: map["publicBanType"], publicBanType: map["publicBanType"],
storageQuotas: (map["storageQuotas"] as List? ?? []).map((e) => StorageQuotas.fromMap(e)).toList(),
quotaBytesSource: (map["quotaBytesSources"] as Map? ?? {}).map((key, value) => MapEntry(key, value as int)),
quotaBytes: map["quotaBytes"] ?? 0,
usedBytes: map["usedBytes"] ?? 0,
twoFactor: map["2fa_login"] ?? false, twoFactor: map["2fa_login"] ?? false,
isPatreonSupporter: map["patreonData"]?["isPatreonSupporter"] ?? false,
userProfile: UserProfile.fromMap(map["profile"]), userProfile: UserProfile.fromMap(map["profile"]),
entitlements: ((map["entitlements"] ?? []) as List).map((e) => Entitlement.fromMap(e)).toList(),
supporterMetadata: ((map["supporterMetadata"] ?? []) as List).map((e) => SupporterMetadata.fromMap(e)).toList(),
); );
} }
bool get isPatreonSupporter =>
supporterMetadata.whereType<PatreonSupporter>().any((element) => element.isActiveSupporter);
} }
class StorageQuotas { class StorageQuota {
final String id; final String id;
final int bytes; final int usedBytes;
final DateTime addedOn; final int quotaBytes;
final DateTime expiresOn; final int fullQuotaBytes;
final String giftedByUserId;
StorageQuotas({required this.id, required this.bytes, required this.addedOn, required this.expiresOn, StorageQuota({
required this.giftedByUserId}); required this.id,
required this.usedBytes,
required this.quotaBytes,
required this.fullQuotaBytes,
});
factory StorageQuotas.fromMap(Map map) { factory StorageQuota.fromMap(Map map) {
return StorageQuotas( return StorageQuota(
id: map["id"] ?? "", id: map["id"] ?? "",
bytes: map["bytes"] ?? 0, usedBytes: map["usedBytes"] ?? 0,
addedOn: DateTime.tryParse(map["addedOn"]) ?? DateTime.fromMillisecondsSinceEpoch(0), quotaBytes: map["quotaBytes"] ?? 0,
expiresOn: DateTime.tryParse(map["expiresOn"]) ?? DateTime.fromMillisecondsSinceEpoch(0), fullQuotaBytes: map["fullQuotaBytes"] ?? 0,
giftedByUserId: map["giftedByUserId"] ?? "", );
}
}
class SupporterMetadata {
SupporterMetadata();
factory SupporterMetadata.fromMap(Map map) {
final type = map["\$type"];
return switch (type) {
"patreon" => PatreonSupporter.fromMap(map),
_ => SupporterMetadata(),
};
}
}
class PatreonSupporter extends SupporterMetadata {
final bool isActiveSupporter;
final int totalSupportMonths;
final int totalSupportCents;
final int lastTierCents;
final int highestTierCents;
final int lowestTierCents;
final DateTime firstSupportTimestamp;
final DateTime lastSupportTimestamp;
PatreonSupporter({
required this.isActiveSupporter,
required this.totalSupportMonths,
required this.totalSupportCents,
required this.lastTierCents,
required this.highestTierCents,
required this.lowestTierCents,
required this.firstSupportTimestamp,
required this.lastSupportTimestamp,
});
factory PatreonSupporter.fromMap(Map map) {
return PatreonSupporter(
isActiveSupporter: map["isActiveSupporter"],
totalSupportMonths: map["totalSupportMonths"],
totalSupportCents: map["totalSupportCents"],
lastTierCents: map["lastTierCents"],
highestTierCents: map["highestTierCents"],
lowestTierCents: map["lowestTierCents"],
firstSupportTimestamp: DateTime.tryParse(map["firstSupportTimestamp"] ?? "") ?? DateTimeX.epoch,
lastSupportTimestamp: DateTime.tryParse(map["lastSupportTimestamp"] ?? "") ?? DateTimeX.epoch,
); );
} }
} }

View file

@ -0,0 +1,49 @@
import 'package:recon/auxiliary.dart';
class Entitlement {
Entitlement();
factory Entitlement.fromMap(Map map) {
final type = map["\$type"];
return switch (type) {
"storageSpace" => StorageSpace.fromMap(map),
_ => Entitlement(),
};
}
}
class StorageSpace extends Entitlement {
final int bytes;
final int maximumShareLevel;
final String storageId;
final String group;
final DateTime startsOn;
final DateTime expiresOn;
final String name;
final String description;
StorageSpace({
required this.bytes,
required this.maximumShareLevel,
required this.storageId,
required this.group,
required this.startsOn,
required this.expiresOn,
required this.name,
required this.description,
});
factory StorageSpace.fromMap(Map map) {
return StorageSpace(
bytes: map["bytes"],
maximumShareLevel: map["maximumShareLevel"],
storageId: map["storageId"],
group: map["group"],
startsOn: DateTime.tryParse(map["startsOn"] ?? "") ?? DateTimeX.epoch,
expiresOn: DateTime.tryParse(map["expiresOn"] ?? "") ?? DateTimeX.epoch,
name: map["name"],
description: map["description"],
);
}
}

View file

@ -17,6 +17,7 @@ class MyProfileDialog extends StatefulWidget {
class _MyProfileDialogState extends State<MyProfileDialog> { class _MyProfileDialogState extends State<MyProfileDialog> {
ClientHolder? _clientHolder; ClientHolder? _clientHolder;
Future<PersonalProfile>? _personalProfileFuture; Future<PersonalProfile>? _personalProfileFuture;
Future<StorageQuota>? _storageQuotaFuture;
@override @override
@ -27,6 +28,7 @@ class _MyProfileDialogState extends State<MyProfileDialog> {
_clientHolder = clientHolder; _clientHolder = clientHolder;
final apiClient = _clientHolder!.apiClient; final apiClient = _clientHolder!.apiClient;
_personalProfileFuture = UserApi.getPersonalProfile(apiClient); _personalProfileFuture = UserApi.getPersonalProfile(apiClient);
_storageQuotaFuture = UserApi.getStorageQuota(apiClient);
} }
} }
@ -87,7 +89,13 @@ class _MyProfileDialogState extends State<MyProfileDialog> {
children: [Text("Ban Expiration: ", style: tt.labelLarge,), children: [Text("Ban Expiration: ", style: tt.labelLarge,),
Text(dateFormat.format(profile.publicBanExpiration!))], Text(dateFormat.format(profile.publicBanExpiration!))],
), ),
StorageIndicator(usedBytes: profile.usedBytes, maxBytes: profile.quotaBytes,), FutureBuilder(
future: _storageQuotaFuture,
builder: (context, snapshot) {
final storage = snapshot.data;
return StorageIndicator(usedBytes: storage?.usedBytes ?? 0, maxBytes: storage?.fullQuotaBytes ?? 1,);
}
),
const SizedBox(height: 12,), const SizedBox(height: 12,),
], ],
), ),