From d492e05d6bf376fd0d889e0361f498804ddb5b2a Mon Sep 17 00:00:00 2001 From: PuPha Date: Tue, 7 Jan 2025 15:14:47 +0700 Subject: [PATCH] Refactor Balance --- lib/model/currency_exchange.dart | 10 + lib/screen/app_router.dart | 47 +-- lib/screen/bloc/accounts/accounts_bloc.dart | 37 +- lib/screen/bloc/accounts/accounts_state.dart | 16 +- .../linked_wallet_detail_page.dart | 45 ++- .../wallet_detail/wallet_detail_bloc.dart | 44 +-- .../wallet_detail/wallet_detail_state.dart | 32 +- lib/util/int_ext.dart | 23 +- lib/view/account_view.dart | 34 +- lib/view/select_address.dart | 327 ------------------ 10 files changed, 165 insertions(+), 450 deletions(-) delete mode 100644 lib/view/select_address.dart diff --git a/lib/model/currency_exchange.dart b/lib/model/currency_exchange.dart index 4e4391b56..d801a9062 100644 --- a/lib/model/currency_exchange.dart +++ b/lib/model/currency_exchange.dart @@ -7,6 +7,8 @@ import 'dart:math'; +import 'package:autonomy_flutter/util/constants.dart'; + class CurrencyExchange { CurrencyExchange({required this.currency, required this.rates}); @@ -51,4 +53,12 @@ class CurrencyExchangeRate { String xtzToUsd(int amount) { return (amount / pow(10, 6) / double.parse(xtz)).toStringAsFixed(2); } + + String toUsd({required BigInt amount, required CryptoType cryptoType}) { + if (cryptoType == CryptoType.ETH) { + return '${ethToUsd(amount)} USD'; + } else { + return '${xtzToUsd(amount.toInt())} USD'; + } + } } diff --git a/lib/screen/app_router.dart b/lib/screen/app_router.dart index 9e372f79a..9a4cf9e26 100644 --- a/lib/screen/app_router.dart +++ b/lib/screen/app_router.dart @@ -5,7 +5,6 @@ // that can be found in the LICENSE file. // -import 'package:autonomy_flutter/common/database.dart'; import 'package:autonomy_flutter/common/injector.dart'; import 'package:autonomy_flutter/model/ff_exhibition.dart'; import 'package:autonomy_flutter/model/play_list_model.dart'; @@ -149,9 +148,10 @@ class AppRouter { static const playlistActivationPage = 'playlist_activation_page'; static Route onGenerateRoute(RouteSettings settings) { - final accountsBloc = AccountsBloc(injector(), injector()); + final accountsBloc = injector(); + final walletDetailBloc = injector(); - final identityBloc = IdentityBloc(ObjectBox.identityBox, injector()); + final identityBloc = injector(); final canvasDeviceBloc = injector(); final subscriptionBloc = injector(); @@ -212,7 +212,7 @@ class AppRouter { settings: settings, child: MultiBlocProvider( providers: [ - BlocProvider(create: (_) => identityBloc), + BlocProvider.value(value: identityBloc), ], child: PreviewPrimerPage( token: settings.arguments! as AssetToken, @@ -229,12 +229,12 @@ class AppRouter { BlocProvider( create: (_) => HomeBloc(), ), - BlocProvider(create: (_) => identityBloc), + BlocProvider.value(value: identityBloc), BlocProvider.value(value: royaltyBloc), BlocProvider.value( value: subscriptionBloc, ), - BlocProvider(create: (_) => canvasDeviceBloc), + BlocProvider.value(value: canvasDeviceBloc), BlocProvider.value(value: listPlaylistBloc), ], child: HomeNavigationPage( @@ -323,7 +323,7 @@ class AppRouter { providers: [ BlocProvider.value(value: accountsBloc), BlocProvider.value(value: subscriptionBloc), - BlocProvider(create: (_) => identityBloc), + BlocProvider.value(value: identityBloc), ], child: const SettingsPage(), ), @@ -334,13 +334,10 @@ class AppRouter { settings: settings, builder: (context) => MultiBlocProvider( providers: [ - BlocProvider( - create: (_) => WalletDetailBloc( - injector(), - injector(), - injector(), - ), + BlocProvider.value( + value: walletDetailBloc, ), + BlocProvider.value(value: accountsBloc), ], child: LinkedWalletDetailPage( payload: settings.arguments! as LinkedWalletDetailsPayload, @@ -368,7 +365,7 @@ class AppRouter { child: MultiBlocProvider( providers: [ BlocProvider.value(value: accountsBloc), - BlocProvider(create: (_) => identityBloc), + BlocProvider.value(value: identityBloc), BlocProvider(create: (_) => royaltyBloc), BlocProvider( create: (_) => ArtworkDetailBloc( @@ -380,8 +377,8 @@ class AppRouter { injector(), ), ), - BlocProvider( - create: (_) => canvasDeviceBloc, + BlocProvider.value( + value: canvasDeviceBloc, ), BlocProvider.value( value: subscriptionBloc, @@ -393,14 +390,6 @@ class AppRouter { ), ); - // TODO: Implement the recovery phrase page - // case recoveryPhrasePage: - // return CupertinoPageRoute( - // settings: settings, - // builder: (context) => RecoveryPhrasePage( - // payload: settings.arguments! as RecoveryPhrasePayload, - // )); - case autonomySecurityPage: return CupertinoPageRoute( settings: settings, @@ -467,8 +456,8 @@ class AppRouter { BlocProvider( create: (_) => ExhibitionDetailBloc(injector()), ), - BlocProvider( - create: (_) => canvasDeviceBloc, + BlocProvider.value( + value: canvasDeviceBloc, ), BlocProvider.value( value: subscriptionBloc, @@ -485,8 +474,8 @@ class AppRouter { settings: settings, builder: (context) => MultiBlocProvider( providers: [ - BlocProvider( - create: (_) => royaltyBloc, + BlocProvider.value( + value: royaltyBloc, ), BlocProvider.value( value: subscriptionBloc, @@ -585,7 +574,7 @@ class AppRouter { settings: settings, builder: (context) => MultiBlocProvider( providers: [ - BlocProvider(create: (_) => identityBloc), + BlocProvider.value(value: identityBloc), ], child: const DataManagementPage(), ), diff --git a/lib/screen/bloc/accounts/accounts_bloc.dart b/lib/screen/bloc/accounts/accounts_bloc.dart index 6602505ee..82365b492 100644 --- a/lib/screen/bloc/accounts/accounts_bloc.dart +++ b/lib/screen/bloc/accounts/accounts_bloc.dart @@ -7,11 +7,16 @@ // ignore_for_file: sort_constructors_first +import 'dart:async'; + import 'package:autonomy_flutter/au_bloc.dart'; import 'package:autonomy_flutter/graphql/account_settings/cloud_manager.dart'; +import 'package:autonomy_flutter/model/pair.dart'; import 'package:autonomy_flutter/model/wallet_address.dart'; import 'package:autonomy_flutter/screen/bloc/accounts/accounts_state.dart'; import 'package:autonomy_flutter/service/address_service.dart'; +import 'package:autonomy_flutter/view/account_view.dart'; +import 'package:sentry/sentry.dart'; class AccountsBloc extends AuBloc { final AddressService _addressService; @@ -22,10 +27,11 @@ class AccountsBloc extends AuBloc { on((event, emit) async { final addresses = _cloudObject.addressObject.getAllAddresses(); emit( - AccountsState( + state.copyWith( addresses: addresses, ), ); + add(GetAccountBalanceEvent(addresses.map((e) => e.address).toList())); }); on((event, emit) { @@ -48,6 +54,35 @@ class AccountsBloc extends AuBloc { _addressService.insertAddresses(newAddresses); }); + on((event, emit) async { + final addressBalances = >{}; + for (final address in event.addresses) { + try { + final balance = await getAddressBalance(address); + if (balance != null) { + addressBalances[address] = balance; + } + emit( + state.copyWith( + addressBalances: Map.from( + addressBalances + ..addAll( + state.addressBalances, + ), + ), + ), + ); + } catch (e, s) { + unawaited( + Sentry.captureException( + 'Failed to get balance for $address: $e', + stackTrace: s, + ), + ); + } + } + }); + on((event, emit) async { final addresses = _addressService.getAllWalletAddresses() ..removeWhere((e) => e.address.isEmpty); diff --git a/lib/screen/bloc/accounts/accounts_state.dart b/lib/screen/bloc/accounts/accounts_state.dart index 294c9579d..372c42e98 100644 --- a/lib/screen/bloc/accounts/accounts_state.dart +++ b/lib/screen/bloc/accounts/accounts_state.dart @@ -5,7 +5,9 @@ // that can be found in the LICENSE file. // +import 'package:autonomy_flutter/model/pair.dart'; import 'package:autonomy_flutter/model/wallet_address.dart'; +import 'package:autonomy_flutter/util/log.dart'; abstract class AccountsEvent {} @@ -20,18 +22,30 @@ class ChangeAccountOrderEvent extends AccountsEvent { class FetchAllAddressesEvent extends AccountsEvent {} +class GetAccountBalanceEvent extends AccountsEvent { + GetAccountBalanceEvent(this.addresses); + + final List addresses; +} + class AccountsState { AccountsState({ this.addresses, - }); + this.addressBalances = const {}, + }) { + log.info('Create AccountsState'); + } List? addresses; + final Map> addressBalances; AccountsState copyWith({ List? addresses, + Map>? addressBalances, }) => AccountsState( addresses: addresses ?? this.addresses, + addressBalances: addressBalances ?? this.addressBalances, ); } diff --git a/lib/screen/settings/crypto/wallet_detail/linked_wallet_detail_page.dart b/lib/screen/settings/crypto/wallet_detail/linked_wallet_detail_page.dart index ecc2c4202..7e784d2df 100644 --- a/lib/screen/settings/crypto/wallet_detail/linked_wallet_detail_page.dart +++ b/lib/screen/settings/crypto/wallet_detail/linked_wallet_detail_page.dart @@ -10,6 +10,8 @@ import 'dart:async'; import 'package:autonomy_flutter/common/injector.dart'; import 'package:autonomy_flutter/main.dart'; import 'package:autonomy_flutter/model/wallet_address.dart'; +import 'package:autonomy_flutter/screen/bloc/accounts/accounts_bloc.dart'; +import 'package:autonomy_flutter/screen/bloc/accounts/accounts_state.dart'; import 'package:autonomy_flutter/screen/settings/crypto/wallet_detail/wallet_detail_bloc.dart'; import 'package:autonomy_flutter/screen/settings/crypto/wallet_detail/wallet_detail_state.dart'; import 'package:autonomy_flutter/service/address_service.dart'; @@ -18,6 +20,7 @@ import 'package:autonomy_flutter/util/au_icons.dart'; import 'package:autonomy_flutter/util/constants.dart'; import 'package:autonomy_flutter/util/feral_file_custom_tab.dart'; import 'package:autonomy_flutter/util/inapp_notifications.dart'; +import 'package:autonomy_flutter/util/int_ext.dart'; import 'package:autonomy_flutter/util/string_ext.dart'; import 'package:autonomy_flutter/util/style.dart'; import 'package:autonomy_flutter/util/ui_helper.dart'; @@ -91,20 +94,10 @@ class _LinkedWalletDetailPageState extends State } void _callBloc() { - final cryptoType = widget.payload.address.cryptoType; - - switch (cryptoType) { - case CryptoType.ETH: - context - .read() - .add(WalletDetailBalanceEvent(cryptoType, _address)); - case CryptoType.XTZ: - context - .read() - .add(WalletDetailBalanceEvent(cryptoType, _address)); - default: - // do nothing - } + // update exchange rate + context.read().add(WalletDetailBalanceEvent(_address)); + // update balance + context.read().add(GetAccountBalanceEvent([_address])); } void _listener() { @@ -189,10 +182,26 @@ class _LinkedWalletDetailPageState extends State AnimatedContainer( duration: const Duration(milliseconds: 3000), height: hideConnection ? 60 : null, - child: _balanceSection( - context, - state.balance, - state.balanceInUSD, + child: BlocBuilder( + builder: (context, accountsState) { + final balance = accountsState.addressBalances[_address]; + final cryptoBalance = balance?.first; + final exchangeRate = state.exchangeRate; + final balanceString = cryptoBalance == null + ? '--' + : cryptoBalance + .toBalanceStringValue(_walletAddress.cryptoType); + final balanceInUSD = + exchangeRate != null && cryptoBalance != null + ? exchangeRate.toUsd( + amount: cryptoBalance, cryptoType: cryptoType) + : ''; + return _balanceSection( + context, + balanceString, + balanceInUSD, + ); + }, ), ), Visibility( diff --git a/lib/screen/settings/crypto/wallet_detail/wallet_detail_bloc.dart b/lib/screen/settings/crypto/wallet_detail/wallet_detail_bloc.dart index 06af6343c..977398b8c 100644 --- a/lib/screen/settings/crypto/wallet_detail/wallet_detail_bloc.dart +++ b/lib/screen/settings/crypto/wallet_detail/wallet_detail_bloc.dart @@ -8,46 +8,20 @@ import 'package:autonomy_flutter/au_bloc.dart'; import 'package:autonomy_flutter/screen/settings/crypto/wallet_detail/wallet_detail_state.dart'; import 'package:autonomy_flutter/service/currency_service.dart'; -import 'package:autonomy_flutter/service/ethereum_service.dart'; -import 'package:autonomy_flutter/service/tezos_service.dart'; -import 'package:autonomy_flutter/util/constants.dart'; -import 'package:autonomy_flutter/util/eth_amount_formatter.dart'; -import 'package:autonomy_flutter/util/xtz_utils.dart'; class WalletDetailBloc extends AuBloc { - final EthereumService _ethereumService; - final TezosService _tezosService; - final CurrencyService _currencyService; - final ethFormatter = EthAmountFormatter(); - final xtzFormatter = XtzAmountFormatter(); - WalletDetailBloc( - this._ethereumService, this._tezosService, this._currencyService) - : super(WalletDetailState()) { + this._currencyService, + ) : super(WalletDetailState()) { on((event, emit) async { final exchangeRate = await _currencyService.getExchangeRates(); - String balanceS = ''; - String balanceInUSD = ''; - - switch (event.type) { - case CryptoType.ETH: - final balance = await _ethereumService.getBalance(event.address); - balanceS = '${ethFormatter.format(balance.getInWei)} ETH'; - final usdBalance = exchangeRate.ethToUsd(balance.getInWei); - balanceInUSD = '$usdBalance USD'; - case CryptoType.XTZ: - final balance = await _tezosService.getBalance(event.address); - balanceS = '${xtzFormatter.format(balance)} XTZ'; - final usdBalance = exchangeRate.xtzToUsd(balance); - balanceInUSD = '$usdBalance USD'; - - default: - } - - emit(state.copyWith( - balance: balanceS, - balanceInUSD: balanceInUSD, - )); + emit( + state.copyWith( + exchangeRate: exchangeRate, + ), + ); }); } + + final CurrencyService _currencyService; } diff --git a/lib/screen/settings/crypto/wallet_detail/wallet_detail_state.dart b/lib/screen/settings/crypto/wallet_detail/wallet_detail_state.dart index 8e97fe41c..da548336f 100644 --- a/lib/screen/settings/crypto/wallet_detail/wallet_detail_state.dart +++ b/lib/screen/settings/crypto/wallet_detail/wallet_detail_state.dart @@ -5,43 +5,27 @@ // that can be found in the LICENSE file. // -import 'package:autonomy_flutter/model/wallet_address.dart'; -import 'package:autonomy_flutter/util/constants.dart'; +import 'package:autonomy_flutter/model/currency_exchange.dart'; abstract class WalletDetailEvent {} class WalletDetailBalanceEvent extends WalletDetailEvent { - CryptoType type; - String address; - - WalletDetailBalanceEvent(this.type, this.address); -} - -class WalletDetailPrimaryAddressEvent extends WalletDetailEvent { - WalletAddress walletAddress; + WalletDetailBalanceEvent(this.address); - WalletDetailPrimaryAddressEvent(this.walletAddress); + String address; } class WalletDetailState { - final String balance; - final String balanceInUSD; - final bool isPrimary; - WalletDetailState({ - this.balance = '', - this.balanceInUSD = '', - this.isPrimary = false, + this.exchangeRate, }); + final CurrencyExchangeRate? exchangeRate; + WalletDetailState copyWith({ - String? balance, - String? balanceInUSD, - bool? isPrimary, + CurrencyExchangeRate? exchangeRate, }) => WalletDetailState( - balance: balance ?? this.balance, - balanceInUSD: balanceInUSD ?? this.balanceInUSD, - isPrimary: isPrimary ?? this.isPrimary, + exchangeRate: exchangeRate ?? this.exchangeRate, ); } diff --git a/lib/util/int_ext.dart b/lib/util/int_ext.dart index 86d21bd0c..ee33358a5 100644 --- a/lib/util/int_ext.dart +++ b/lib/util/int_ext.dart @@ -1,7 +1,26 @@ +import 'package:autonomy_flutter/util/constants.dart'; +import 'package:autonomy_flutter/util/ether_amount_ext.dart'; import 'package:autonomy_flutter/util/xtz_utils.dart'; +import 'package:web3dart/web3dart.dart'; -extension IntExtension on int { - String get toXTZStringValue => '${XtzAmountFormatter().format(this)} XTZ'; +extension BigIntExtension on BigInt { + String get toXTZStringValue => + '${XtzAmountFormatter().format(this.toInt())} XTZ'; + + String get toEthStringValue => + EtherAmount.fromBigInt(EtherUnit.wei, this).toEthStringValue; + + String toBalanceStringValue(CryptoType cryptoType) { + switch (cryptoType) { + case CryptoType.XTZ: + return toXTZStringValue; + case CryptoType.ETH: + return toEthStringValue; + case CryptoType.USDC: + case CryptoType.UNKNOWN: + return '--'; + } + } } extension MapExtention on Map { diff --git a/lib/view/account_view.dart b/lib/view/account_view.dart index 35623f300..f14471865 100644 --- a/lib/view/account_view.dart +++ b/lib/view/account_view.dart @@ -10,15 +10,17 @@ import 'dart:async'; import 'package:autonomy_flutter/common/injector.dart'; import 'package:autonomy_flutter/model/pair.dart'; import 'package:autonomy_flutter/model/wallet_address.dart'; +import 'package:autonomy_flutter/screen/bloc/accounts/accounts_bloc.dart'; +import 'package:autonomy_flutter/screen/bloc/accounts/accounts_state.dart'; import 'package:autonomy_flutter/service/ethereum_service.dart'; import 'package:autonomy_flutter/service/tezos_service.dart'; import 'package:autonomy_flutter/util/constants.dart'; -import 'package:autonomy_flutter/util/ether_amount_ext.dart'; import 'package:autonomy_flutter/util/int_ext.dart'; import 'package:autonomy_flutter/view/crypto_view.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:feralfile_app_theme/feral_file_app_theme.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:nft_collection/database/dao/dao.dart'; @@ -28,8 +30,6 @@ Widget accountItem( FutureOr Function()? onTap, }) { final theme = Theme.of(context); - // ignore: discarded_futures - final balance = getAddressBalance(address.key, address.cryptoType); return GestureDetector( onTap: onTap, child: Container( @@ -69,19 +69,27 @@ Widget accountItem( ], ), const SizedBox(height: 10), - FutureBuilder?>( - future: balance, - builder: (context, snapshot) { - final balances = snapshot.data ?? Pair('--', '--'); + BlocConsumer( + builder: (context, state) { + final balances = state.addressBalances[address.address] ?? + Pair(null, '--'); final style = theme.textTheme.ppMori400Grey14; + final cryptoBalance = balances.first?.toBalanceStringValue( + address.cryptoType, + ) ?? + '--'; return Row( children: [ - Text(balances.first, style: style), + Text(cryptoBalance, style: style), const SizedBox(width: 20), Text(balances.second, style: style), ], ); }, + buildWhen: (previous, current) => + previous.addressBalances[address.address] != + current.addressBalances[address.address], + listener: (BuildContext context, AccountsState state) {}, ), const SizedBox(height: 10), Row( @@ -101,10 +109,10 @@ Widget accountItem( ); } -Future?> getAddressBalance( +Future> getAddressBalance( String address, - CryptoType cryptoType, ) async { + final cryptoType = CryptoType.fromAddress(address); final tokenDao = injector(); final tokens = await tokenDao.findTokenIDsOwnersOwn([address]); final nftBalance = @@ -112,12 +120,12 @@ Future?> getAddressBalance( switch (cryptoType) { case CryptoType.ETH: final etherAmount = await injector().getBalance(address); - return Pair(etherAmount.toEthStringValue, nftBalance); + return Pair(etherAmount.getInWei, nftBalance); case CryptoType.XTZ: final tezosAmount = await injector().getBalance(address); - return Pair(tezosAmount.toXTZStringValue, nftBalance); + return Pair(BigInt.from(tezosAmount), nftBalance); case CryptoType.USDC: case CryptoType.UNKNOWN: - return Pair('', ''); + return Pair(null, ''); } } diff --git a/lib/view/select_address.dart b/lib/view/select_address.dart deleted file mode 100644 index f1976546b..000000000 --- a/lib/view/select_address.dart +++ /dev/null @@ -1,327 +0,0 @@ -import 'dart:async'; - -import 'package:autonomy_flutter/common/injector.dart'; -import 'package:autonomy_flutter/model/wallet_address.dart'; -import 'package:autonomy_flutter/service/ethereum_service.dart'; -import 'package:autonomy_flutter/service/tezos_service.dart'; -import 'package:autonomy_flutter/util/constants.dart'; -import 'package:autonomy_flutter/util/ether_amount_ext.dart'; -import 'package:autonomy_flutter/util/int_ext.dart'; -import 'package:autonomy_flutter/util/string_ext.dart'; -import 'package:autonomy_flutter/util/style.dart'; -import 'package:autonomy_flutter/view/crypto_view.dart'; -import 'package:autonomy_flutter/view/primary_button.dart'; -import 'package:autonomy_flutter/view/radio_check_box.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:feralfile_app_theme/feral_file_app_theme.dart'; -import 'package:flutter/material.dart'; -import 'package:web3dart/web3dart.dart'; - -class IRLSelectAddressView extends StatefulWidget { - const IRLSelectAddressView({ - required this.addresses, - super.key, - this.selectButton, - this.minimumCryptoBalance, - }); - - final List addresses; - final String? selectButton; - final int? minimumCryptoBalance; - - @override - State createState() => _IRLSelectAddressViewState(); -} - -class _IRLSelectAddressViewState extends State { - String? _selectedAddress; - final Map _isViewing = {}; - - @override - Widget build(BuildContext context) { - final minimumCryptoBalance = widget.minimumCryptoBalance ?? 0; - return ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 325), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: SingleChildScrollView( - child: Column( - children: [ - if (_isViewing.isEmpty && minimumCryptoBalance > 0) ...[ - loadingIndicator(valueColor: AppColor.white), - ], - if (_noAddressHasEnoughBalance()) ...[ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 14), - child: Text( - 'no_address_has_enough_balance'.tr(), - style: Theme.of(context) - .textTheme - .ppMori400White14 - .copyWith(color: AppColor.disabledColor), - ), - ), - ] else - ...widget.addresses.map( - (e) => AddressView( - key: Key(e.address), - address: e, - selectedAddress: _selectedAddress, - onTap: () { - if (context.mounted) { - setState(() { - _selectedAddress = e.address; - }); - } - }, - onDoneLoading: (notShowing) { - if (context.mounted) { - setState(() { - _isViewing[e.address] = !notShowing; - }); - } - }, - minimumCryptoBalance: minimumCryptoBalance, - ), - ), - ], - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 14), - child: Row( - children: [ - Expanded( - child: Column( - children: [ - PrimaryButton( - text: widget.selectButton ?? 'connect'.tr(), - enabled: _selectedAddress != null, - onTap: () { - Navigator.pop(context, _selectedAddress); - }, - ), - const SizedBox( - height: 10, - ), - OutlineButton( - text: 'cancel'.tr(), - onTap: () { - Navigator.pop(context); - }, - ), - ], - ), - ), - ], - ), - ), - ], - ), - ); - } - - bool _noAddressHasEnoughBalance() => - widget.addresses.every((element) => _isViewing[element.address] == false); -} - -class AddressView extends StatefulWidget { - const AddressView({ - required this.address, - super.key, - this.selectedAddress, - this.onTap, - this.minimumCryptoBalance = 0, - this.onDoneLoading, - }); - - final WalletAddress address; - final String? selectedAddress; - final FutureOr Function()? onTap; - final int minimumCryptoBalance; - final FutureOr Function(bool notShowing)? onDoneLoading; - - @override - State createState() => _AddressViewState(); -} - -class _AddressViewState extends State { - bool _didLoad = false; - EtherAmount? _ethBalance; - int? _tezBalance; - late CryptoType _cryptoType; - - @override - void initState() { - super.initState(); - _cryptoType = widget.address.cryptoType; - unawaited(_loadBalance(context)); - } - - Future _loadBalance(BuildContext context) async { - switch (_cryptoType) { - case CryptoType.ETH: - _ethBalance = await injector() - .getBalance(widget.address.address); - case CryptoType.XTZ: - _tezBalance = - await injector().getBalance(widget.address.address); - default: - } - if (context.mounted) { - setState(() { - _didLoad = true; - }); - } - } - - bool _isEnoughBalance() { - if (widget.minimumCryptoBalance == 0) { - return true; - } - switch (_cryptoType) { - case CryptoType.ETH: - if (_ethBalance == null) { - return false; - } - return _ethBalance!.getInWei >= - BigInt.from(widget.minimumCryptoBalance); - case CryptoType.XTZ: - if (_tezBalance == null) { - return false; - } - return _tezBalance! >= widget.minimumCryptoBalance; - default: - return false; - } - } - - String _getBalanceString() { - switch (_cryptoType) { - case CryptoType.ETH: - return _ethBalance?.toEthStringValue ?? '--'; - case CryptoType.XTZ: - return _tezBalance?.toXTZStringValue ?? '--'; - default: - return ''; - } - } - - @override - Widget build(BuildContext context) { - if (_didLoad) { - Future.delayed(const Duration(milliseconds: 50), () { - widget.onDoneLoading?.call(!_isEnoughBalance()); - }); - } - if (!_isEnoughBalance()) { - return const SizedBox(); - } - return _addressView(context, _getBalanceString()); - } - - Widget _addressView(BuildContext context, String balance) { - final theme = Theme.of(context); - final isSelected = widget.address.address == widget.selectedAddress; - final color = isSelected ? AppColor.white : AppColor.disabledColor; - final name = widget.address.name; - final style = theme.textTheme.ppMori400White14.copyWith(color: color); - return GestureDetector( - onTap: widget.onTap, - child: Column( - children: [ - Container( - padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 14), - color: isSelected - ? const Color.fromRGBO(30, 30, 30, 1) - : Colors.transparent, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LogoCrypto( - cryptoType: _cryptoType, - size: 24, - ), - const SizedBox( - width: 10, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - name.isNotEmpty - ? name - : _cryptoType == CryptoType.ETH - ? 'ethereum'.tr() - : 'tezos'.tr(), - style: style, - ), - Text(balance, style: style), - ], - ), - const Spacer(), - Text(widget.address.address.maskOnly(6), style: style), - const SizedBox( - width: 20, - ), - AuCheckBox( - isChecked: isSelected, - color: color, - ), - ], - ), - ), - addOnlyDivider(color: AppColor.disabledColor), - ], - ), - ); - } -} - -enum SelectAddressType { - connect, - purchase, - receive, - unknown, - ; - - String get popUpTitle { - switch (this) { - case SelectAddressType.connect: - case SelectAddressType.purchase: - case SelectAddressType.receive: - return 'select_address_to_'.tr(args: [selectButton.toLowerCase()]); - default: - return 'select_address_irl'.tr(); - } - } - - String get selectButton { - switch (this) { - case SelectAddressType.connect: - return 'connect'.tr(); - case SelectAddressType.purchase: - return 'purchase'.tr(); - case SelectAddressType.receive: - return 'receive'.tr(); - default: - return 'select'.tr(); - } - } - - static SelectAddressType fromString(String value) { - switch (value) { - case 'connect': - return SelectAddressType.connect; - case 'purchase': - return SelectAddressType.purchase; - case 'receive': - return SelectAddressType.receive; - default: - return SelectAddressType.unknown; - } - } -}