usability fixes

This commit is contained in:
2026-06-24 18:01:34 +02:00
parent 9e55ec1097
commit a6b4a04bd5
26 changed files with 1099 additions and 216 deletions

View File

@@ -17,6 +17,9 @@ class AccountProvider extends ChangeNotifier {
String? _accountError;
String? _statementError;
/// Cached balances keyed by currency code (e.g. 'USD', 'ZWG').
final Map<String, AccountModel?> _balances = {};
AccountModel? get account => _account;
StatementModel? get statement => _statement;
bool get isLoadingAccount => _isLoadingAccount;
@@ -25,6 +28,20 @@ class AccountProvider extends ChangeNotifier {
String? get statementError => _statementError;
bool _isDisposed = false;
/// Returns a cached account balance for [currency], or null if not yet
/// fetched.
AccountModel? balanceForCurrency(String currency) {
return _balances[currency.toUpperCase()];
}
/// Returns the account with name 'City Wallet' for [currency], or null.
AccountModel? cityWalletBalance() {
return _balances.values.firstWhere(
(a) => a?.name == 'City Wallet',
orElse: () => null,
);
}
@override
void notifyListeners() {
if (!_isDisposed) {
@@ -52,6 +69,7 @@ class AccountProvider extends ChangeNotifier {
);
_account = AccountModel.fromJson(response);
_balances[currency.toUpperCase()] = _account;
_isLoadingAccount = false;
notifyListeners();
return ApiResponse.success(_account!);
@@ -71,6 +89,17 @@ class AccountProvider extends ChangeNotifier {
}
}
/// Pre-load multiple currency balances at once. Results are stored in the
/// [_balances] map so any widget can access them later.
Future<void> preloadBalances(
String? workspaceId,
List<String> currencies,
) async {
for (final currency in currencies) {
await fetchAccount(workspaceId, currency);
}
}
Future<ApiResponse<StatementModel>> fetchStatement({
required String workspaceId,
required String currency,
@@ -117,4 +146,4 @@ class AccountProvider extends ChangeNotifier {
_statementError = null;
notifyListeners();
}
}
}

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:qpay/screens/accounts/account_provider.dart';
import 'package:qpay/screens/accounts/models/account_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -20,8 +21,6 @@ class AccountBalanceWidget extends StatefulWidget {
}
class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
late AccountProvider _accountProvider;
bool _isLoggedIn = false;
String? _workspaceId;
@@ -36,20 +35,12 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
@override
void initState() {
super.initState();
_accountProvider = AccountProvider();
_loadAuthStateAndBalances();
}
@override
void dispose() {
_accountProvider.dispose();
super.dispose();
}
Future<void> _loadAuthStateAndBalances() async {
final prefs = await SharedPreferences.getInstance();
// Determine login state from persisted token
if (prefs.getString("token") != null) {
setState(() {
_isLoggedIn = true;
@@ -62,18 +53,37 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
return;
}
if (!_isLoggedIn) {
return;
}
if (!mounted) return;
final accountProvider = context.read<AccountProvider>();
setState(() {
_isLoadingUsd = true;
_isLoadingZwG = true;
});
// no need to proceed if not logged in
if (!_isLoggedIn) {
// Try the cached balances first
final cachedUsd = accountProvider.balanceForCurrency('USD');
final cachedZwg = accountProvider.balanceForCurrency('ZWG');
if (cachedUsd != null && cachedZwg != null) {
if (mounted) {
setState(() {
_usdAccount = cachedUsd;
_zwgAccount = cachedZwg;
_isLoadingUsd = false;
_isLoadingZwG = false;
});
}
return;
}
// Fetch USD balance
final usdResult = await _accountProvider.fetchAccount(_workspaceId, 'USD');
final usdResult = await accountProvider.fetchAccount(_workspaceId, 'USD');
if (mounted) {
setState(() {
_isLoadingUsd = false;
@@ -87,7 +97,7 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
}
// Fetch ZWG balance
final zwgResult = await _accountProvider.fetchAccount(_workspaceId, 'ZWG');
final zwgResult = await accountProvider.fetchAccount(_workspaceId, 'ZWG');
if (mounted) {
setState(() {
_isLoadingZwG = false;
@@ -117,12 +127,16 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
if (_workspaceId == null || _workspaceId!.isEmpty) return;
if (!mounted) return;
final accountProvider = context.read<AccountProvider>();
setState(() {
_isLoadingUsd = true;
_isLoadingZwG = true;
});
final usdResult = await _accountProvider.fetchAccount(_workspaceId, 'USD');
final usdResult = await accountProvider.fetchAccount(_workspaceId, 'USD');
if (mounted) {
setState(() {
_isLoadingUsd = false;
@@ -135,7 +149,7 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
});
}
final zwgResult = await _accountProvider.fetchAccount(_workspaceId, 'ZWG');
final zwgResult = await accountProvider.fetchAccount(_workspaceId, 'ZWG');
if (mounted) {
setState(() {
_isLoadingZwG = false;
@@ -509,4 +523,4 @@ class _AccountBalanceWidgetState extends State<AccountBalanceWidget> {
final formatter = NumberFormat('#,##0.00', 'en_US');
return '\$${formatter.format(balance)}';
}
}
}