From b157522fdbd96b9fa13a2e44de066de8f967aa40 Mon Sep 17 00:00:00 2001 From: Arseni Date: Tue, 30 Dec 2025 18:36:29 +0300 Subject: [PATCH] Refresh button for balance --- .../pshared/lib/provider/payment/wallets.dart | 27 ++++++++ frontend/pweb/lib/l10n/en.arb | 1 + frontend/pweb/lib/l10n/ru.arb | 1 + .../pages/dashboard/buttons/balance/card.dart | 18 ++++-- .../payment_methods/payment_page/content.dart | 19 +++++- .../lib/pages/payout_page/wallet/card.dart | 21 +++++-- .../pages/payout_page/wallet/edit/fields.dart | 16 +++-- .../wallet_balance_refresh_button.dart | 62 +++++++++++++++++++ 8 files changed, 148 insertions(+), 17 deletions(-) create mode 100644 frontend/pweb/lib/widgets/wallet_balance_refresh_button.dart diff --git a/frontend/pshared/lib/provider/payment/wallets.dart b/frontend/pshared/lib/provider/payment/wallets.dart index 2e655ef..5e24ae5 100644 --- a/frontend/pshared/lib/provider/payment/wallets.dart +++ b/frontend/pshared/lib/provider/payment/wallets.dart @@ -29,6 +29,8 @@ class WalletsProvider with ChangeNotifier { bool _isRefreshingBalances = false; bool get isRefreshingBalances => _isRefreshingBalances; + final Set _refreshingWallets = {}; + bool isWalletRefreshing(String walletId) => _refreshingWallets.contains(walletId); void update(OrganizationsProvider organizations) { _organizations = organizations; @@ -81,6 +83,31 @@ class WalletsProvider with ChangeNotifier { } } + Future refreshBalance(String walletId) async { + if (_refreshingWallets.contains(walletId)) return; + final wallet = wallets.firstWhereOrNull((w) => w.id == walletId); + if (wallet == null) return; + + _refreshingWallets.add(walletId); + notifyListeners(); + + try { + final balance = await _service.getBalance(_organizations.current.id, walletId); + final updatedWallet = wallet.copyWith(balance: balance); + final next = List.from(wallets); + final idx = next.indexWhere((w) => w.id == walletId); + if (idx >= 0) { + next[idx] = updatedWallet; + _setResource(_resource.copyWith(data: next)); + } + } catch (e) { + _setResource(_resource.copyWith(error: toException(e))); + } finally { + _refreshingWallets.remove(walletId); + notifyListeners(); + } + } + void toggleVisibility(String walletId) { final index = wallets.indexWhere((w) => w.id == walletId); if (index < 0) return; diff --git a/frontend/pweb/lib/l10n/en.arb b/frontend/pweb/lib/l10n/en.arb index 27fbfb9..24b7110 100644 --- a/frontend/pweb/lib/l10n/en.arb +++ b/frontend/pweb/lib/l10n/en.arb @@ -383,6 +383,7 @@ "payout": "Payout", "sendTo": "Send Payout To", "send": "Send Payout", + "refreshBalance": "Refresh balance", "recipientPaysFee": "Recipient pays the fee", "sentAmount": "Sent amount: {amount}", diff --git a/frontend/pweb/lib/l10n/ru.arb b/frontend/pweb/lib/l10n/ru.arb index 7aeb458..8ea6dcd 100644 --- a/frontend/pweb/lib/l10n/ru.arb +++ b/frontend/pweb/lib/l10n/ru.arb @@ -383,6 +383,7 @@ "payout": "Выплата", "sendTo": "Отправить выплату", "send": "Отправить выплату", + "refreshBalance": "Обновить баланс", "recipientPaysFee": "Получатель оплачивает комиссию", "sentAmount": "Отправленная сумма: {amount}", diff --git a/frontend/pweb/lib/pages/dashboard/buttons/balance/card.dart b/frontend/pweb/lib/pages/dashboard/buttons/balance/card.dart index 612e303..2cfd42c 100644 --- a/frontend/pweb/lib/pages/dashboard/buttons/balance/card.dart +++ b/frontend/pweb/lib/pages/dashboard/buttons/balance/card.dart @@ -8,6 +8,7 @@ import 'package:pweb/pages/dashboard/buttons/balance/amount.dart'; import 'package:pweb/pages/dashboard/buttons/balance/config.dart'; import 'package:pweb/pages/dashboard/buttons/balance/header.dart'; import 'package:pshared/provider/payment/wallets.dart'; +import 'package:pweb/widgets/wallet_balance_refresh_button.dart'; class WalletCard extends StatelessWidget { @@ -37,11 +38,18 @@ class WalletCard extends StatelessWidget { walletNetwork: wallet.network, tokenSymbol: wallet.tokenSymbol, ), - BalanceAmount( - wallet: wallet, - onToggleVisibility: () { - context.read().toggleVisibility(wallet.id); - }, + Row( + children: [ + BalanceAmount( + wallet: wallet, + onToggleVisibility: () { + context.read().toggleVisibility(wallet.id); + }, + ), + WalletBalanceRefreshButton( + walletId: wallet.id, + ), + ], ), BalanceAddFunds( onTopUp: () { diff --git a/frontend/pweb/lib/pages/payment_methods/payment_page/content.dart b/frontend/pweb/lib/pages/payment_methods/payment_page/content.dart index aa274cf..12b1289 100644 --- a/frontend/pweb/lib/pages/payment_methods/payment_page/content.dart +++ b/frontend/pweb/lib/pages/payment_methods/payment_page/content.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/models/recipient/recipient.dart'; +import 'package:pshared/provider/payment/wallets.dart'; import 'package:pshared/provider/recipient/provider.dart'; import 'package:pweb/pages/payment_methods/payment_page/back_button.dart'; @@ -14,6 +17,7 @@ import 'package:pweb/pages/payment_methods/widgets/recipient_section.dart'; import 'package:pweb/pages/payment_methods/widgets/section_title.dart'; import 'package:pweb/utils/dimensions.dart'; import 'package:pweb/widgets/sidebar/destinations.dart'; +import 'package:pweb/widgets/wallet_balance_refresh_button.dart'; import 'package:pweb/generated/i18n/app_localizations.dart'; @@ -74,7 +78,20 @@ class PaymentPageContent extends StatelessWidget { SizedBox(height: dimensions.paddingSmall), PaymentHeader(), SizedBox(height: dimensions.paddingXXLarge), - SectionTitle(loc.sourceOfFunds), + Row( + children: [ + Expanded(child: SectionTitle(loc.sourceOfFunds)), + Consumer( + builder: (context, provider, _) { + final selectedWalletId = provider.selectedWallet?.id; + if (selectedWalletId == null) { + return const SizedBox.shrink(); + } + return WalletBalanceRefreshButton(walletId: selectedWalletId); + }, + ), + ], + ), SizedBox(height: dimensions.paddingSmall), PaymentMethodSelector( onMethodChanged: onWalletSelected, diff --git a/frontend/pweb/lib/pages/payout_page/wallet/card.dart b/frontend/pweb/lib/pages/payout_page/wallet/card.dart index e70647d..b77c22f 100644 --- a/frontend/pweb/lib/pages/payout_page/wallet/card.dart +++ b/frontend/pweb/lib/pages/payout_page/wallet/card.dart @@ -5,8 +5,10 @@ import 'package:provider/provider.dart'; import 'package:pshared/utils/currency.dart'; import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/provider/payment/wallets.dart'; +import 'package:pweb/models/visibility.dart'; import 'package:pweb/pages/dashboard/buttons/balance/amount.dart'; +import 'package:pweb/widgets/wallet_balance_refresh_button.dart'; import 'package:pweb/generated/i18n/app_localizations.dart'; @@ -43,11 +45,20 @@ class WalletCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ - BalanceAmount( - wallet: wallet, - onToggleVisibility: () { - context.read().toggleVisibility(wallet.id); - }, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + BalanceAmount( + wallet: wallet, + onToggleVisibility: () { + context.read().toggleVisibility(wallet.id); + }, + ), + WalletBalanceRefreshButton( + walletId: wallet.id, + iconOnly: VisibilityState.hidden, + ), + ], ), Text( AppLocalizations.of(context)!.paymentTypeCryptoWallet, diff --git a/frontend/pweb/lib/pages/payout_page/wallet/edit/fields.dart b/frontend/pweb/lib/pages/payout_page/wallet/edit/fields.dart index 812ad97..bb56870 100644 --- a/frontend/pweb/lib/pages/payout_page/wallet/edit/fields.dart +++ b/frontend/pweb/lib/pages/payout_page/wallet/edit/fields.dart @@ -6,6 +6,7 @@ import 'package:provider/provider.dart'; import 'package:pshared/provider/payment/wallets.dart'; import 'package:pweb/pages/dashboard/buttons/balance/amount.dart'; +import 'package:pweb/widgets/wallet_balance_refresh_button.dart'; class WalletEditFields extends StatelessWidget { @@ -26,12 +27,15 @@ class WalletEditFields extends StatelessWidget { children: [ Row( children: [ - BalanceAmount( - wallet: wallet, - onToggleVisibility: () { - context.read().toggleVisibility(wallet.id); - }, + Expanded( + child: BalanceAmount( + wallet: wallet, + onToggleVisibility: () { + context.read().toggleVisibility(wallet.id); + }, + ), ), + WalletBalanceRefreshButton(walletId: wallet.id), ], ), const SizedBox(height: 8), @@ -51,4 +55,4 @@ class WalletEditFields extends StatelessWidget { }, ); } -} \ No newline at end of file +} diff --git a/frontend/pweb/lib/widgets/wallet_balance_refresh_button.dart b/frontend/pweb/lib/widgets/wallet_balance_refresh_button.dart new file mode 100644 index 0000000..2fdc2d8 --- /dev/null +++ b/frontend/pweb/lib/widgets/wallet_balance_refresh_button.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; + +import 'package:provider/provider.dart'; + +import 'package:pshared/provider/payment/wallets.dart'; + +import 'package:pweb/models/visibility.dart'; + +import 'package:pweb/generated/i18n/app_localizations.dart'; + + +class WalletBalanceRefreshButton extends StatelessWidget { + final String walletId; + final VisibilityState iconOnly; + final double iconSize = 18; + + const WalletBalanceRefreshButton({ + super.key, + required this.walletId, + this.iconOnly = VisibilityState.visible, + }); + + @override + Widget build(BuildContext context) { + final walletsProvider = context.watch(); + final loc = AppLocalizations.of(context)!; + final isBusy = walletsProvider.isWalletRefreshing(walletId) || walletsProvider.isLoading; + final hasTarget = walletsProvider.wallets.any((w) => w.id == walletId); + + void refresh() { + final provider = context.read(); + provider.refreshBalance(walletId); + } + + if (iconOnly == VisibilityState.hidden) { + return IconButton( + tooltip: loc.refreshBalance, + onPressed: hasTarget && !isBusy ? refresh : null, + icon: isBusy + ? SizedBox( + width: iconSize, + height: iconSize, + child: const CircularProgressIndicator(strokeWidth: 2), + ) + : const Icon(Icons.refresh), + ); + } + + return TextButton.icon( + onPressed: hasTarget && !isBusy ? refresh : null, + icon: isBusy + ? SizedBox( + width: iconSize, + height: iconSize, + child: const CircularProgressIndicator(strokeWidth: 2), + ) + : const Icon(Icons.refresh), + label: Text(loc.refreshBalance), + style: TextButton.styleFrom(visualDensity: VisualDensity.compact), + ); + } +} -- 2.49.1