diff --git a/packages/neon/lib/l10n/en.arb b/packages/neon/lib/l10n/en.arb index bf21482a..76e1ccf5 100644 --- a/packages/neon/lib/l10n/en.arb +++ b/packages/neon/lib/l10n/en.arb @@ -104,6 +104,21 @@ } } }, + "accountOptionsCategoryStorageInfo": "Storage info", + "accountOptionsQuotaUsedOf": "{used} used of {total} ({relative}%)", + "@accountOptionsQuotaUsedOf": { + "placeholders": { + "used": { + "type": "String" + }, + "total": { + "type": "String" + }, + "relative": { + "type": "String" + } + } + }, "accountOptionsInitialApp": "App to show initially", "accountOptionsAutomatic": "Automatic", "licenses": "Licenses", diff --git a/packages/neon/lib/l10n/localizations.dart b/packages/neon/lib/l10n/localizations.dart index 15ee243d..13b0f61e 100644 --- a/packages/neon/lib/l10n/localizations.dart +++ b/packages/neon/lib/l10n/localizations.dart @@ -503,6 +503,18 @@ abstract class AppLocalizations { /// **'Are you sure you want to remove the account {id}?'** String accountOptionsRemoveConfirm(String id); + /// No description provided for @accountOptionsCategoryStorageInfo. + /// + /// In en, this message translates to: + /// **'Storage info'** + String get accountOptionsCategoryStorageInfo; + + /// No description provided for @accountOptionsQuotaUsedOf. + /// + /// In en, this message translates to: + /// **'{used} used of {total} ({relative}%)'** + String accountOptionsQuotaUsedOf(String used, String total, String relative); + /// No description provided for @accountOptionsInitialApp. /// /// In en, this message translates to: diff --git a/packages/neon/lib/l10n/localizations_en.dart b/packages/neon/lib/l10n/localizations_en.dart index 20a9f1f5..6ca3f67a 100644 --- a/packages/neon/lib/l10n/localizations_en.dart +++ b/packages/neon/lib/l10n/localizations_en.dart @@ -226,6 +226,14 @@ class AppLocalizationsEn extends AppLocalizations { return 'Are you sure you want to remove the account $id?'; } + @override + String get accountOptionsCategoryStorageInfo => 'Storage info'; + + @override + String accountOptionsQuotaUsedOf(String used, String total, String relative) { + return '$used used of $total ($relative%)'; + } + @override String get accountOptionsInitialApp => 'App to show initially'; diff --git a/packages/neon/lib/src/blocs/user_details.dart b/packages/neon/lib/src/blocs/user_details.dart index c95ec004..ca0f263a 100644 --- a/packages/neon/lib/src/blocs/user_details.dart +++ b/packages/neon/lib/src/blocs/user_details.dart @@ -6,7 +6,9 @@ import 'package:rxdart/rxdart.dart'; part 'user_details.rxb.g.dart'; -abstract class UserDetailsBlocEvents {} +abstract class UserDetailsBlocEvents { + void refresh(); +} abstract class UserDetailsBlocStates { BehaviorSubject> get userDetails; @@ -18,6 +20,8 @@ class UserDetailsBloc extends $UserDetailsBloc { this._requestManager, this._client, ) { + _$refreshEvent.listen((final _) => _loadUserDetails()); + _loadUserDetails(); } diff --git a/packages/neon/lib/src/blocs/user_details.rxb.g.dart b/packages/neon/lib/src/blocs/user_details.rxb.g.dart index b1e0adc1..3d5cb6cf 100644 --- a/packages/neon/lib/src/blocs/user_details.rxb.g.dart +++ b/packages/neon/lib/src/blocs/user_details.rxb.g.dart @@ -19,9 +19,15 @@ abstract class $UserDetailsBloc extends RxBlocBase implements UserDetailsBlocEvents, UserDetailsBlocStates, UserDetailsBlocType { final _compositeSubscription = CompositeSubscription(); + /// Тhe [Subject] where events sink to by calling [refresh] + final _$refreshEvent = PublishSubject(); + /// The state of [userDetails] implemented in [_mapToUserDetailsState] late final BehaviorSubject> _userDetailsState = _mapToUserDetailsState(); + @override + void refresh() => _$refreshEvent.add(null); + @override BehaviorSubject> get userDetails => _userDetailsState; @@ -35,6 +41,7 @@ abstract class $UserDetailsBloc extends RxBlocBase @override void dispose() { + _$refreshEvent.close(); _compositeSubscription.dispose(); super.dispose(); } diff --git a/packages/neon/lib/src/neon.dart b/packages/neon/lib/src/neon.dart index 53784eff..bc935233 100644 --- a/packages/neon/lib/src/neon.dart +++ b/packages/neon/lib/src/neon.dart @@ -9,6 +9,7 @@ import 'dart:typed_data'; import 'package:collection/collection.dart'; import 'package:crypto/crypto.dart'; import 'package:file_picker/file_picker.dart'; +import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_file_dialog/flutter_file_dialog.dart'; diff --git a/packages/neon/lib/src/pages/settings/account_specific_settings.dart b/packages/neon/lib/src/pages/settings/account_specific_settings.dart index 634c8e84..2aa8e184 100644 --- a/packages/neon/lib/src/pages/settings/account_specific_settings.dart +++ b/packages/neon/lib/src/pages/settings/account_specific_settings.dart @@ -11,6 +11,7 @@ class AccountSpecificSettingsPage extends StatelessWidget { final Account account; late final _options = bloc.getOptions(account)!; + late final _userDetailsBloc = bloc.getUserDetailsBloc(account); late final _name = account.client.humanReadableID; @override @@ -44,17 +45,59 @@ class AccountSpecificSettingsPage extends StatelessWidget { ), ], ), - body: SettingsList( - categories: [ - SettingsCategory( - title: Text(AppLocalizations.of(context).optionsCategoryGeneral), - tiles: [ - DropdownButtonSettingsTile( - option: _options.initialApp, - ), - ], - ), - ], + body: StandardRxResultBuilder( + bloc: _userDetailsBloc, + state: (final bloc) => bloc.userDetails, + builder: (final context, final userDetailsData, final userDetailsError, final userDetailsLoading, final _) => + SettingsList( + categories: [ + SettingsCategory( + title: Text(AppLocalizations.of(context).accountOptionsCategoryStorageInfo), + tiles: [ + CustomSettingsTile( + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (userDetailsData != null) ...[ + LinearProgressIndicator( + value: userDetailsData.quota!.relative! / 100, + backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.3), + ), + const SizedBox( + height: 10, + ), + Text( + AppLocalizations.of(context).accountOptionsQuotaUsedOf( + filesize(userDetailsData.quota!.used!, 1), + filesize(userDetailsData.quota!.total!, 1), + userDetailsData.quota!.relative!.toString(), + ), + ), + ], + ExceptionWidget( + userDetailsError, + onRetry: () { + _userDetailsBloc.refresh(); + }, + ), + CustomLinearProgressIndicator( + visible: userDetailsLoading, + ), + ], + ), + ), + ], + ), + SettingsCategory( + title: Text(AppLocalizations.of(context).optionsCategoryGeneral), + tiles: [ + DropdownButtonSettingsTile( + option: _options.initialApp, + ), + ], + ), + ], + ), ), ); }