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);
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';
class PersonalProfile {
@ -6,18 +8,21 @@ class PersonalProfile {
final String email;
final DateTime? publicBanExpiration;
final String? publicBanType;
final List<StorageQuotas> storageQuotas;
final Map<String, int> quotaBytesSource;
final int quotaBytes;
final int usedBytes;
final bool twoFactor;
final bool isPatreonSupporter;
final UserProfile userProfile;
final List<Entitlement> entitlements;
final List<SupporterMetadata> supporterMetadata;
PersonalProfile({
required this.id, required this.username, required this.email, required this.publicBanExpiration,
required this.publicBanType, required this.storageQuotas, required this.quotaBytesSource, required this.quotaBytes,
required this.usedBytes, required this.twoFactor, required this.isPatreonSupporter, required this.userProfile,
required this.id,
required this.username,
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) {
@ -27,34 +32,83 @@ class PersonalProfile {
email: map["email"] ?? "",
publicBanExpiration: DateTime.tryParse(map["publicBanExpiration"] ?? ""),
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,
isPatreonSupporter: map["patreonData"]?["isPatreonSupporter"] ?? false,
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 StorageQuota {
final String id;
final int usedBytes;
final int quotaBytes;
final int fullQuotaBytes;
StorageQuota({
required this.id,
required this.usedBytes,
required this.quotaBytes,
required this.fullQuotaBytes,
});
factory StorageQuota.fromMap(Map map) {
return StorageQuota(
id: map["id"] ?? "",
usedBytes: map["usedBytes"] ?? 0,
quotaBytes: map["quotaBytes"] ?? 0,
fullQuotaBytes: map["fullQuotaBytes"] ?? 0,
);
}
}
class StorageQuotas {
final String id;
final int bytes;
final DateTime addedOn;
final DateTime expiresOn;
final String giftedByUserId;
class SupporterMetadata {
SupporterMetadata();
StorageQuotas({required this.id, required this.bytes, required this.addedOn, required this.expiresOn,
required this.giftedByUserId});
factory SupporterMetadata.fromMap(Map map) {
final type = map["\$type"];
return switch (type) {
"patreon" => PatreonSupporter.fromMap(map),
_ => SupporterMetadata(),
};
}
}
factory StorageQuotas.fromMap(Map map) {
return StorageQuotas(
id: map["id"] ?? "",
bytes: map["bytes"] ?? 0,
addedOn: DateTime.tryParse(map["addedOn"]) ?? DateTime.fromMillisecondsSinceEpoch(0),
expiresOn: DateTime.tryParse(map["expiresOn"]) ?? DateTime.fromMillisecondsSinceEpoch(0),
giftedByUserId: map["giftedByUserId"] ?? "",
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> {
ClientHolder? _clientHolder;
Future<PersonalProfile>? _personalProfileFuture;
Future<StorageQuota>? _storageQuotaFuture;
@override
@ -27,6 +28,7 @@ class _MyProfileDialogState extends State<MyProfileDialog> {
_clientHolder = clientHolder;
final apiClient = _clientHolder!.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,),
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,),
],
),