From 5e5730d5a54f60fb38055ba53a20e08b21c43762 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 28 Mar 2023 16:18:11 -0600 Subject: [PATCH] eth token wallet general ui and wallet selection interface --- .../exchange_view/choose_from_stack_view.dart | 2 +- .../token_view/sub_widgets/token_summary.dart | 39 +++-- .../wallets_view/eth_wallets_overview.dart | 73 ++++++++++ .../sub_widgets/wallet_list_item.dart | 27 ++-- lib/route_generator.dart | 10 ++ .../coins/ethereum/ethereum_wallet.dart | 23 +++ lib/services/mixins/eth_token_cache.dart | 6 +- lib/widgets/master_wallet_card.dart | 137 ++++++++++++++++++ lib/widgets/wallet_card.dart | 71 +++++++-- .../wallet_info_row_balance_future.dart | 37 +++-- .../wallet_info_row_coin_icon.dart | 42 +++++- .../wallet_info_row/wallet_info_row.dart | 51 ++++++- 12 files changed, 455 insertions(+), 63 deletions(-) create mode 100644 lib/pages/wallets_view/eth_wallets_overview.dart create mode 100644 lib/widgets/master_wallet_card.dart diff --git a/lib/pages/exchange_view/choose_from_stack_view.dart b/lib/pages/exchange_view/choose_from_stack_view.dart index 7c7669430..505554a7c 100644 --- a/lib/pages/exchange_view/choose_from_stack_view.dart +++ b/lib/pages/exchange_view/choose_from_stack_view.dart @@ -112,7 +112,7 @@ class _ChooseFromStackViewState extends ConsumerState { const SizedBox( height: 2, ), - WalletInfoRowBalanceFuture( + WalletInfoRowBalance( walletId: walletIds[index], ), ], diff --git a/lib/pages/token_view/sub_widgets/token_summary.dart b/lib/pages/token_view/sub_widgets/token_summary.dart index eece604e5..208cdf699 100644 --- a/lib/pages/token_view/sub_widgets/token_summary.dart +++ b/lib/pages/token_view/sub_widgets/token_summary.dart @@ -69,18 +69,8 @@ class TokenSummary extends ConsumerWidget { const SizedBox( width: 10, ), - RoundedContainer( - padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 4), - radiusMultiplier: 0.25, - color: const Color( - 0xFF4D5798), // TODO: color theme for multi themes - child: Text( - ref.watch(walletsChangeNotifierProvider.select( - (value) => value.getManager(walletId).coin.ticker)), - style: STextStyles.w600_12(context).copyWith( - color: Colors.white, // TODO: design is wrong? - ), - ), + CoinTickerTag( + walletId: walletId, ), ], ), @@ -195,3 +185,28 @@ class TokenOptionsButton extends StatelessWidget { ); } } + +class CoinTickerTag extends ConsumerWidget { + const CoinTickerTag({ + Key? key, + required this.walletId, + }) : super(key: key); + + final String walletId; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return RoundedContainer( + padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 4), + radiusMultiplier: 0.25, + color: const Color(0xFF4D5798), // TODO: color theme for multi themes + child: Text( + ref.watch(walletsChangeNotifierProvider + .select((value) => value.getManager(walletId).coin.ticker)), + style: STextStyles.w600_12(context).copyWith( + color: Colors.white, // TODO: design is wrong? + ), + ), + ); + } +} diff --git a/lib/pages/wallets_view/eth_wallets_overview.dart b/lib/pages/wallets_view/eth_wallets_overview.dart new file mode 100644 index 000000000..35e1b4411 --- /dev/null +++ b/lib/pages/wallets_view/eth_wallets_overview.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/background.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; +import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/master_wallet_card.dart'; + +class EthWalletsOverview extends ConsumerStatefulWidget { + const EthWalletsOverview({Key? key}) : super(key: key); + + static const routeName = "/ethWalletsOverview"; + + @override + ConsumerState createState() => _EthWalletsOverviewState(); +} + +class _EthWalletsOverviewState extends ConsumerState { + final isDesktop = Util.isDesktop; + + final List ethWalletIds = []; + + @override + void initState() { + final walletsData = + ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData(); + walletsData.removeWhere((key, value) => value.coin != Coin.ethereum); + ethWalletIds.clear(); + + ethWalletIds.addAll(walletsData.values.map((e) => e.walletId)); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Background( + child: ConditionalParent( + condition: !isDesktop, + builder: (child) => Scaffold( + backgroundColor: + Theme.of(context).extension()!.background, + appBar: AppBar( + leading: const AppBarBackButton(), + title: Text( + "Ethereum (ETH) wallets", + style: STextStyles.navBarTitle(context), + ), + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.all(16), + child: child, + ), + ), + ), + child: ListView.separated( + itemCount: ethWalletIds.length, + separatorBuilder: (_, __) => const SizedBox( + height: 8, + ), + itemBuilder: (_, index) => MasterWalletCard( + walletId: ethWalletIds[index], + ), + ), + ), + ); + } +} diff --git a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart index 01b78c33f..c2e5991d6 100644 --- a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart +++ b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/pages/wallets_sheet/wallets_sheet.dart'; +import 'package:stackwallet/pages/wallets_view/eth_wallets_overview.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; @@ -45,7 +46,13 @@ class WalletListItem extends ConsumerWidget { BorderRadius.circular(Constants.size.circularBorderRadius), ), onPressed: () async { - if (walletCount == 1) { + if (coin == Coin.ethereum) { + unawaited( + Navigator.of(context).pushNamed( + EthWalletsOverview.routeName, + ), + ); + } else if (walletCount == 1) { final providersByCoin = ref .watch(walletsChangeNotifierProvider .select((value) => value.getManagerProvidersByCoin())) @@ -57,15 +64,17 @@ class WalletListItem extends ConsumerWidget { if (coin == Coin.monero || coin == Coin.wownero) { await manager.initializeExisting(); } - unawaited( - Navigator.of(context).pushNamed( - WalletView.routeName, - arguments: Tuple2( - manager.walletId, - providersByCoin.first, + if (context.mounted) { + unawaited( + Navigator.of(context).pushNamed( + WalletView.routeName, + arguments: Tuple2( + manager.walletId, + providersByCoin.first, + ), ), - ), - ); + ); + } } else { unawaited( showModalBottomSheet( diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 9ee9e85ad..2a94028fa 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -105,6 +105,7 @@ import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.d import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_search_filter_view.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; +import 'package:stackwallet/pages/wallets_view/eth_wallets_overview.dart'; import 'package:stackwallet/pages/wallets_view/wallets_view.dart'; import 'package:stackwallet/pages_desktop_specific/address_book_view/desktop_address_book.dart'; import 'package:stackwallet/pages_desktop_specific/coin_control/desktop_coin_control_view.dart'; @@ -250,6 +251,15 @@ class RouteGenerator { ), ); + case EthWalletsOverview.routeName: + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const EthWalletsOverview(), + settings: RouteSettings( + name: settings.name, + ), + ); + case TokenContractDetailsView.routeName: if (args is Tuple2) { return getRoute( diff --git a/lib/services/coins/ethereum/ethereum_wallet.dart b/lib/services/coins/ethereum/ethereum_wallet.dart index c9a5c5ad2..581770a2c 100644 --- a/lib/services/coins/ethereum/ethereum_wallet.dart +++ b/lib/services/coins/ethereum/ethereum_wallet.dart @@ -5,11 +5,13 @@ import 'package:decimal/decimal.dart'; import 'package:ethereum_addresses/ethereum_addresses.dart'; import 'package:http/http.dart'; import 'package:isar/isar.dart'; +import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart'; +import 'package:stackwallet/models/token_balance.dart'; import 'package:stackwallet/services/coins/coin_service.dart'; import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart'; @@ -17,6 +19,7 @@ import 'package:stackwallet/services/event_bus/events/global/refresh_percent_cha import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart'; import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/global_event_bus.dart'; +import 'package:stackwallet/services/mixins/eth_token_cache.dart'; import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/node_service.dart'; @@ -76,6 +79,26 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { ); } + TokenBalance getCachedTokenBalance(EthContract contract) { + final jsonString = DB.instance.get( + boxName: _walletId, + key: TokenCacheKeys.tokenBalance(contract.address), + ) as String?; + if (jsonString == null) { + return TokenBalance( + contractAddress: contract.address, + decimalPlaces: contract.decimals, + total: 0, + spendable: 0, + blockedTotal: 0, + pendingSpendable: 0, + ); + } + return TokenBalance.fromJson( + jsonString, + ); + } + // Future removeTokenContract(String contractAddress) async { // final set = getWalletTokenContractAddresses().toSet(); // set.removeWhere((e) => e == contractAddress); diff --git a/lib/services/mixins/eth_token_cache.dart b/lib/services/mixins/eth_token_cache.dart index 87ec3c189..9bb11bea4 100644 --- a/lib/services/mixins/eth_token_cache.dart +++ b/lib/services/mixins/eth_token_cache.dart @@ -2,7 +2,7 @@ import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; import 'package:stackwallet/models/token_balance.dart'; -abstract class _Keys { +abstract class TokenCacheKeys { static String tokenBalance(String contractAddress) { return "tokenBalanceCache_$contractAddress"; } @@ -21,7 +21,7 @@ mixin EthTokenCache { TokenBalance getCachedBalance() { final jsonString = DB.instance.get( boxName: _walletId, - key: _Keys.tokenBalance(_token.address), + key: TokenCacheKeys.tokenBalance(_token.address), ) as String?; if (jsonString == null) { return TokenBalance( @@ -41,7 +41,7 @@ mixin EthTokenCache { Future updateCachedBalance(TokenBalance balance) async { await DB.instance.put( boxName: _walletId, - key: _Keys.tokenBalance(_token.address), + key: TokenCacheKeys.tokenBalance(_token.address), value: balance.toJsonIgnoreCoin(), ); } diff --git a/lib/widgets/master_wallet_card.dart b/lib/widgets/master_wallet_card.dart new file mode 100644 index 000000000..af8b6e196 --- /dev/null +++ b/lib/widgets/master_wallet_card.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart'; +import 'package:stackwallet/widgets/expandable.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/wallet_card.dart'; +import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; + +class MasterWalletCard extends ConsumerStatefulWidget { + const MasterWalletCard({ + Key? key, + required this.walletId, + this.popPrevious = false, + }) : super(key: key); + + final String walletId; + final bool popPrevious; + + @override + ConsumerState createState() => _MasterWalletCardState(); +} + +class _MasterWalletCardState extends ConsumerState { + final expandableController = ExpandableController(); + final rotateIconController = RotateIconController(); + late final List tokenContractAddresses; + + @override + void initState() { + final ethWallet = ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .wallet as EthereumWallet; + + tokenContractAddresses = ethWallet.getWalletTokenContractAddresses(); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return RoundedWhiteContainer( + padding: EdgeInsets.zero, + child: Expandable( + controller: expandableController, + expandOverride: () {}, + header: Padding( + padding: const EdgeInsets.all(12), + child: Row( + children: [ + Expanded( + child: WalletInfoRow( + walletId: widget.walletId, + ), + ), + MaterialButton( + padding: const EdgeInsets.all(5), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + minWidth: 32, + height: 32, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, + elevation: 0, + hoverElevation: 0, + disabledElevation: 0, + highlightElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + onPressed: () { + if (expandableController.state == ExpandableState.collapsed) { + rotateIconController.forward?.call(); + } else { + rotateIconController.reverse?.call(); + } + expandableController.toggle?.call(); + }, + child: RotateIcon( + controller: rotateIconController, + icon: SvgPicture.asset( + Assets.svg.chevronDown, + width: 14, + ), + curve: Curves.easeInOut, + ), + ), + ], + ), + ), + body: ListView( + shrinkWrap: true, + primary: false, + children: [ + Container( + width: double.infinity, + height: 1.5, + color: + Theme.of(context).extension()!.backgroundAppBar, + ), + Padding( + padding: const EdgeInsets.all( + 7, + ), + child: WalletSheetCard( + walletId: widget.walletId, + popPrevious: true, + ), + ), + ...tokenContractAddresses.map( + (e) => Padding( + padding: const EdgeInsets.only( + left: 7, + right: 7, + bottom: 7, + ), + child: WalletSheetCard( + walletId: widget.walletId, + contractAddress: e, + // popPrevious: true, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/wallet_card.dart b/lib/widgets/wallet_card.dart index 194033de3..4648d6bf7 100644 --- a/lib/widgets/wallet_card.dart +++ b/lib/widgets/wallet_card.dart @@ -1,21 +1,33 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/pages/token_view/token_view.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; +import 'package:stackwallet/providers/db/main_db_provider.dart'; +import 'package:stackwallet/providers/global/secure_store_provider.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; +import 'package:stackwallet/services/ethereum/ethereum_token_service.dart'; +import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; import 'package:tuple/tuple.dart'; +import '../utilities/show_loading.dart'; + class WalletSheetCard extends ConsumerWidget { const WalletSheetCard({ Key? key, required this.walletId, + this.contractAddress, this.popPrevious = false, }) : super(key: key); final String walletId; + final String? contractAddress; final bool popPrevious; @override @@ -33,25 +45,56 @@ class WalletSheetCard extends ConsumerWidget { ), ), onPressed: () async { - final manager = ref - .read(walletsChangeNotifierProvider) - .getManager(walletId); - if (manager.coin == Coin.monero || - manager.coin == Coin.wownero) { + final manager = + ref.read(walletsChangeNotifierProvider).getManager(walletId); + if (manager.coin == Coin.monero || manager.coin == Coin.wownero) { await manager.initializeExisting(); } - if (popPrevious) Navigator.of(context).pop(); - Navigator.of(context).pushNamed( - WalletView.routeName, - arguments: Tuple2( - walletId, - ref - .read(walletsChangeNotifierProvider) - .getManagerProvider(walletId)), - ); + if (context.mounted) { + if (popPrevious) Navigator.of(context).pop(); + unawaited( + Navigator.of(context).pushNamed( + WalletView.routeName, + arguments: Tuple2( + walletId, + ref + .read(walletsChangeNotifierProvider) + .getManagerProvider(walletId)), + ), + ); + + if (contractAddress != null) { + final contract = ref + .read(mainDBProvider) + .getEthContractSync(contractAddress!)!; + ref.read(tokenServiceStateProvider.state).state = EthTokenWallet( + token: contract, + secureStore: ref.read(secureStoreProvider), + ethWallet: manager.wallet as EthereumWallet, + tracker: TransactionNotificationTracker( + walletId: walletId, + ), + ); + + await showLoading( + whileFuture: ref.read(tokenServiceProvider)!.initialize(), + context: context, + opaqueBG: true, + message: "Loading ${contract.name}", + ); + + if (context.mounted) { + await Navigator.of(context).pushNamed( + TokenView.routeName, + arguments: walletId, + ); + } + } + } }, child: WalletInfoRow( walletId: walletId, + contractAddress: contractAddress, ), ), ); diff --git a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart index 542cb545a..ddd491229 100644 --- a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart +++ b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart @@ -1,20 +1,25 @@ import 'package:decimal/decimal.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; -import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; -class WalletInfoRowBalanceFuture extends ConsumerWidget { - const WalletInfoRowBalanceFuture({Key? key, required this.walletId}) - : super(key: key); +class WalletInfoRowBalance extends ConsumerWidget { + const WalletInfoRowBalance({ + Key? key, + required this.walletId, + this.contractAddress, + }) : super(key: key); final String walletId; + final String? contractAddress; @override Widget build(BuildContext context, WidgetRef ref) { @@ -28,18 +33,30 @@ class WalletInfoRowBalanceFuture extends ConsumerWidget { ), ); - Decimal balance = manager.balance.getTotal(); - - if (manager.coin == Coin.firo || manager.coin == Coin.firoTestNet) { - balance += (manager.wallet as FiroWallet).balancePrivate.getTotal(); + Decimal balance; + int decimals; + String unit; + if (contractAddress == null) { + balance = manager.balance.getTotal(); + if (manager.coin == Coin.firo || manager.coin == Coin.firoTestNet) { + balance += (manager.wallet as FiroWallet).balancePrivate.getTotal(); + } + unit = manager.coin.ticker; + decimals = manager.coin.decimals; + } else { + final ethWallet = manager.wallet as EthereumWallet; + final contract = MainDB.instance.getEthContractSync(contractAddress!)!; + balance = ethWallet.getCachedTokenBalance(contract).getTotal(); + unit = contract.symbol; + decimals = contract.decimals; } return Text( "${Format.localizedStringAsFixed( value: balance, locale: locale, - decimalPlaces: Constants.decimalPlacesForCoin(manager.coin), - )} ${manager.coin.ticker}", + decimalPlaces: decimals, + )} $unit", style: Util.isDesktop ? STextStyles.desktopTextExtraSmall(context).copyWith( color: Theme.of(context).extension()!.textSubtitle1, diff --git a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart index 670fb3b8c..a0ebceb12 100644 --- a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart +++ b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart @@ -1,17 +1,41 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:isar/isar.dart'; +import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; +import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; +import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; class WalletInfoCoinIcon extends StatelessWidget { - const WalletInfoCoinIcon({Key? key, required this.coin}) : super(key: key); + const WalletInfoCoinIcon({ + Key? key, + required this.coin, + this.contractAddress, + }) : super(key: key); final Coin coin; + final String? contractAddress; @override Widget build(BuildContext context) { + Currency? currency; + if (contractAddress != null) { + currency = ExchangeDataLoadingService.instance.isar.currencies + .where() + .exchangeNameEqualTo(ChangeNowExchange.exchangeName) + .filter() + .tokenContractEqualTo( + contractAddress!, + caseSensitive: false, + ) + .and() + .imageIsNotEmpty() + .findFirstSync(); + } + return Container( decoration: BoxDecoration( color: Theme.of(context) @@ -24,11 +48,17 @@ class WalletInfoCoinIcon extends StatelessWidget { ), child: Padding( padding: const EdgeInsets.all(6), - child: SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - width: 20, - height: 20, - ), + child: currency != null && currency.image.isNotEmpty + ? SvgPicture.network( + currency.image, + width: 20, + height: 20, + ) + : SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 20, + height: 20, + ), ), ); } diff --git a/lib/widgets/wallet_info_row/wallet_info_row.dart b/lib/widgets/wallet_info_row/wallet_info_row.dart index a5dc81aea..3863c08d3 100644 --- a/lib/widgets/wallet_info_row/wallet_info_row.dart +++ b/lib/widgets/wallet_info_row/wallet_info_row.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; +import 'package:stackwallet/pages/token_view/sub_widgets/token_summary.dart'; +import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/text_styles.dart'; @@ -14,10 +17,12 @@ class WalletInfoRow extends ConsumerWidget { Key? key, required this.walletId, this.onPressedDesktop, + this.contractAddress, this.padding = const EdgeInsets.all(0), }) : super(key: key); final String walletId; + final String? contractAddress; final VoidCallback? onPressedDesktop; final EdgeInsets padding; @@ -27,6 +32,12 @@ class WalletInfoRow extends ConsumerWidget { .watch(walletsChangeNotifierProvider.notifier) .getManagerProvider(walletId)); + EthContract? contract; + if (contractAddress != null) { + contract = ref.watch(mainDBProvider + .select((value) => value.getEthContractSync(contractAddress!))); + } + if (Util.isDesktop) { return MouseRegion( cursor: SystemMouseCursors.click, @@ -42,7 +53,10 @@ class WalletInfoRow extends ConsumerWidget { flex: 4, child: Row( children: [ - WalletInfoCoinIcon(coin: manager.coin), + WalletInfoCoinIcon( + coin: manager.coin, + contractAddress: contractAddress, + ), const SizedBox( width: 12, ), @@ -60,7 +74,7 @@ class WalletInfoRow extends ConsumerWidget { ), Expanded( flex: 4, - child: WalletInfoRowBalanceFuture( + child: WalletInfoRowBalance( walletId: walletId, ), ), @@ -89,7 +103,10 @@ class WalletInfoRow extends ConsumerWidget { } else { return Row( children: [ - WalletInfoCoinIcon(coin: manager.coin), + WalletInfoCoinIcon( + coin: manager.coin, + contractAddress: contractAddress, + ), const SizedBox( width: 12, ), @@ -98,14 +115,32 @@ class WalletInfoRow extends ConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - manager.walletName, - style: STextStyles.titleBold12(context), - ), + contract != null + ? Row( + children: [ + Text( + contract.name, + style: STextStyles.titleBold12(context), + ), + const SizedBox( + width: 4, + ), + CoinTickerTag( + walletId: walletId, + ), + ], + ) + : Text( + manager.walletName, + style: STextStyles.titleBold12(context), + ), const SizedBox( height: 2, ), - WalletInfoRowBalanceFuture(walletId: walletId), + WalletInfoRowBalance( + walletId: walletId, + contractAddress: contractAddress, + ), ], ), ),