From 510a152b238b894bd07c35857deb554a36d4a8e8 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 08:53:47 -0600 Subject: [PATCH 01/21] mobile eth restore flow navigation bug fix --- .../edit_wallet_tokens_view.dart | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart b/lib/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart index 936ca5405..11f05c206 100644 --- a/lib/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart +++ b/lib/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart @@ -11,6 +11,7 @@ import 'package:stackwallet/pages/add_wallet_views/add_token_view/add_custom_tok import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list_element.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_text.dart'; +import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; @@ -97,16 +98,25 @@ class _EditWalletTokensViewState extends ConsumerState { if (widget.contractsToMarkSelected == null) { Navigator.of(context).pop(42); } else { - Navigator.of(context).popUntil( - ModalRoute.withName(DesktopHomeView.routeName), - ); - unawaited( - showFloatingFlushBar( - type: FlushBarType.success, - message: "${ethWallet.walletName} tokens saved", - context: context, - ), - ); + if (isDesktop) { + Navigator.of(context).popUntil( + ModalRoute.withName(DesktopHomeView.routeName), + ); + } else { + await Navigator.of(context).pushNamedAndRemoveUntil( + HomeView.routeName, + (route) => false, + ); + } + if (mounted) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "${ethWallet.walletName} tokens saved", + context: context, + ), + ); + } } } } From 7ef2d5f0d7e512e7a80201f8f0ab3ff52c5e4f4b Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 09:12:07 -0600 Subject: [PATCH 02/21] mobile open wallet gui flow changes --- lib/pages/wallets_sheet/wallets_sheet.dart | 101 ------------------ .../sub_widgets/wallet_list_item.dart | 23 +--- ...ts_overview.dart => wallets_overview.dart} | 36 ++++--- lib/route_generator.dart | 23 ++-- 4 files changed, 42 insertions(+), 141 deletions(-) delete mode 100644 lib/pages/wallets_sheet/wallets_sheet.dart rename lib/pages/wallets_view/{eth_wallets_overview.dart => wallets_overview.dart} (64%) diff --git a/lib/pages/wallets_sheet/wallets_sheet.dart b/lib/pages/wallets_sheet/wallets_sheet.dart deleted file mode 100644 index dbbe371f1..000000000 --- a/lib/pages/wallets_sheet/wallets_sheet.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/constants.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/widgets/wallet_card.dart'; - -class WalletsSheet extends ConsumerWidget { - const WalletsSheet({ - Key? key, - required this.coin, - }) : super(key: key); - - final Coin coin; - - @override - Widget build(BuildContext context, WidgetRef ref) { - final providers = ref - .watch(walletsChangeNotifierProvider - .select((value) => value.getManagerProvidersByCoin())) - .where((e) => e.item1 == coin) - .map((e) => e.item2) - .expand((e) => e) - .toList(); - - final maxHeight = MediaQuery.of(context).size.height * 0.60; - - return Container( - decoration: BoxDecoration( - color: Theme.of(context).extension()!.popupBG, - borderRadius: const BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - child: LimitedBox( - maxHeight: maxHeight, - child: Padding( - padding: const EdgeInsets.only( - left: 24, - right: 24, - top: 10, - bottom: 0, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Container( - decoration: BoxDecoration( - color: Theme.of(context) - .extension()! - .textFieldDefaultBG, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - ), - width: 60, - height: 4, - ), - ), - const SizedBox( - height: 36, - ), - Text( - "${coin.prettyName} (${coin.ticker}) wallets", - style: STextStyles.pageTitleH2(context), - textAlign: TextAlign.left, - ), - const SizedBox( - height: 16, - ), - Flexible( - child: ListView.builder( - shrinkWrap: true, - itemCount: providers.length, - itemBuilder: (builderContext, index) { - final walletId = ref.watch( - providers[index].select((value) => value.walletId)); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: WalletSheetCard( - walletId: walletId, - popPrevious: true, - ), - ); - }, - ), - ), - const SizedBox( - height: 24, - ), - ], - ), - ), - ), - ); - } -} 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 ac4c6fb85..851d2445f 100644 --- a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart +++ b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; 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/pages/wallets_view/wallets_overview.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -46,13 +45,7 @@ class WalletListItem extends ConsumerWidget { BorderRadius.circular(Constants.size.circularBorderRadius), ), onPressed: () async { - if (coin == Coin.ethereum) { - unawaited( - Navigator.of(context).pushNamed( - EthWalletsOverview.routeName, - ), - ); - } else if (walletCount == 1) { + if (walletCount == 1 && coin != Coin.ethereum) { final providersByCoin = ref .watch(walletsChangeNotifierProvider .select((value) => value.getManagerProvidersByCoin())) @@ -77,15 +70,9 @@ class WalletListItem extends ConsumerWidget { } } else { unawaited( - showModalBottomSheet( - backgroundColor: Colors.transparent, - context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - builder: (_) => WalletsSheet(coin: coin), + Navigator.of(context).pushNamed( + WalletsOverview.routeName, + arguments: coin, ), ); } diff --git a/lib/pages/wallets_view/eth_wallets_overview.dart b/lib/pages/wallets_view/wallets_overview.dart similarity index 64% rename from lib/pages/wallets_view/eth_wallets_overview.dart rename to lib/pages/wallets_view/wallets_overview.dart index 35e1b4411..e79c13383 100644 --- a/lib/pages/wallets_view/eth_wallets_overview.dart +++ b/lib/pages/wallets_view/wallets_overview.dart @@ -9,29 +9,35 @@ 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'; +import 'package:stackwallet/widgets/wallet_card.dart'; -class EthWalletsOverview extends ConsumerStatefulWidget { - const EthWalletsOverview({Key? key}) : super(key: key); +class WalletsOverview extends ConsumerStatefulWidget { + const WalletsOverview({ + Key? key, + required this.coin, + }) : super(key: key); + + final Coin coin; static const routeName = "/ethWalletsOverview"; @override - ConsumerState createState() => _EthWalletsOverviewState(); + ConsumerState createState() => _EthWalletsOverviewState(); } -class _EthWalletsOverviewState extends ConsumerState { +class _EthWalletsOverviewState extends ConsumerState { final isDesktop = Util.isDesktop; - final List ethWalletIds = []; + final List walletIds = []; @override void initState() { final walletsData = ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData(); - walletsData.removeWhere((key, value) => value.coin != Coin.ethereum); - ethWalletIds.clear(); + walletsData.removeWhere((key, value) => value.coin != widget.coin); + walletIds.clear(); - ethWalletIds.addAll(walletsData.values.map((e) => e.walletId)); + walletIds.addAll(walletsData.values.map((e) => e.walletId)); super.initState(); } @@ -47,7 +53,7 @@ class _EthWalletsOverviewState extends ConsumerState { appBar: AppBar( leading: const AppBarBackButton(), title: Text( - "Ethereum (ETH) wallets", + "${widget.coin.prettyName} (${widget.coin.ticker}) wallets", style: STextStyles.navBarTitle(context), ), ), @@ -59,13 +65,17 @@ class _EthWalletsOverviewState extends ConsumerState { ), ), child: ListView.separated( - itemCount: ethWalletIds.length, + itemCount: walletIds.length, separatorBuilder: (_, __) => const SizedBox( height: 8, ), - itemBuilder: (_, index) => MasterWalletCard( - walletId: ethWalletIds[index], - ), + itemBuilder: (_, index) => widget.coin == Coin.ethereum + ? MasterWalletCard( + walletId: walletIds[index], + ) + : WalletSheetCard( + walletId: walletIds[index], + ), ), ), ); diff --git a/lib/route_generator.dart b/lib/route_generator.dart index db3a7450c..4031e425e 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -106,7 +106,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_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/addresses/desktop_wallet_addresses_view.dart'; @@ -280,14 +280,19 @@ class RouteGenerator { ), ); - case EthWalletsOverview.routeName: - return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const EthWalletsOverview(), - settings: RouteSettings( - name: settings.name, - ), - ); + case WalletsOverview.routeName: + if (args is Coin) { + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => WalletsOverview( + coin: args, + ), + settings: RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); case TokenContractDetailsView.routeName: if (args is Tuple2) { From 3a3bb8887087a2d5953021f13c5d471da814f0b1 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 09:16:07 -0600 Subject: [PATCH 03/21] expand eth wallet card dropdown when header is clicked/tapped anywhere, not just the tiny grey button area --- .../dialogs/desktop_coin_wallets_dialog.dart | 8 +++++++- lib/widgets/master_wallet_card.dart | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart index 46d8a3b19..114503206 100644 --- a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart @@ -306,7 +306,13 @@ class _DesktopWalletCardState extends State<_DesktopWalletCard> { ? ExpandableState.expanded : ExpandableState.collapsed, controller: expandableController, - expandOverride: () {}, + onExpandWillChange: (toState) { + if (toState == ExpandableState.expanded) { + rotateIconController.forward?.call(); + } else { + rotateIconController.reverse?.call(); + } + }, header: Padding( padding: const EdgeInsets.symmetric( horizontal: 20, diff --git a/lib/widgets/master_wallet_card.dart b/lib/widgets/master_wallet_card.dart index 65f65c3a1..165ae9ec5 100644 --- a/lib/widgets/master_wallet_card.dart +++ b/lib/widgets/master_wallet_card.dart @@ -49,7 +49,13 @@ class _MasterWalletCardState extends ConsumerState { padding: EdgeInsets.zero, child: Expandable( controller: expandableController, - expandOverride: () {}, + onExpandWillChange: (toState) { + if (toState == ExpandableState.expanded) { + rotateIconController.forward?.call(); + } else { + rotateIconController.reverse?.call(); + } + }, header: Padding( padding: const EdgeInsets.all(12), child: Row( From 2b0ad1c7eb27a2c9960f883b5f18a27f8fd46120 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 09:44:38 -0600 Subject: [PATCH 04/21] add search to mobile coin wallets per-coin list --- lib/pages/wallets_view/wallets_overview.dart | 255 +++++++++- .../dialogs/desktop_coin_wallets_dialog.dart | 441 ------------------ .../desktop_expanding_wallet_card.dart | 192 ++++++++ .../my_stack_view/wallet_summary_table.dart | 4 +- lib/widgets/master_wallet_card.dart | 4 +- lib/widgets/wallet_card.dart | 6 +- test/widget_tests/wallet_card_test.dart | 4 +- 7 files changed, 441 insertions(+), 465 deletions(-) delete mode 100644 lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart create mode 100644 lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart diff --git a/lib/pages/wallets_view/wallets_overview.dart b/lib/pages/wallets_view/wallets_overview.dart index e79c13383..bc68ec30b 100644 --- a/lib/pages/wallets_view/wallets_overview.dart +++ b/lib/pages/wallets_view/wallets_overview.dart @@ -1,6 +1,14 @@ 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_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart'; +import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; +import 'package:stackwallet/services/coins/manager.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/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; @@ -8,18 +16,25 @@ 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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/master_wallet_card.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/stack_text_field.dart'; +import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/wallet_card.dart'; +import 'package:tuple/tuple.dart'; class WalletsOverview extends ConsumerStatefulWidget { const WalletsOverview({ Key? key, required this.coin, + this.navigatorState, }) : super(key: key); final Coin coin; + final NavigatorState? navigatorState; - static const routeName = "/ethWalletsOverview"; + static const routeName = "/walletsOverview"; @override ConsumerState createState() => _EthWalletsOverviewState(); @@ -28,20 +43,123 @@ class WalletsOverview extends ConsumerStatefulWidget { class _EthWalletsOverviewState extends ConsumerState { final isDesktop = Util.isDesktop; - final List walletIds = []; + late final TextEditingController _searchController; + late final FocusNode searchFieldFocusNode; + + String _searchString = ""; + + final List>> wallets = []; + + List>> _filter(String searchTerm) { + if (searchTerm.isEmpty) { + return wallets; + } + + final List>> results = []; + final term = searchTerm.toLowerCase(); + + for (final tuple in wallets) { + bool includeManager = false; + // search wallet name and total balance + includeManager |= _elementContains(tuple.item1.walletName, term); + includeManager |= _elementContains( + tuple.item1.balance.total.decimal.toString(), + term, + ); + + final List contracts = []; + + for (final contract in tuple.item2) { + if (_elementContains(contract.name, term)) { + contracts.add(contract); + } else if (_elementContains(contract.symbol, term)) { + contracts.add(contract); + } else if (_elementContains(contract.type.name, term)) { + contracts.add(contract); + } else if (_elementContains(contract.address, term)) { + contracts.add(contract); + } + } + + if (includeManager || contracts.isNotEmpty) { + results.add(Tuple2(tuple.item1, contracts)); + } + } + + return results; + } + + bool _elementContains(String element, String term) { + return element.toLowerCase().contains(term); + } @override void initState() { + _searchController = TextEditingController(); + searchFieldFocusNode = FocusNode(); + final walletsData = ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData(); walletsData.removeWhere((key, value) => value.coin != widget.coin); - walletIds.clear(); - walletIds.addAll(walletsData.values.map((e) => e.walletId)); + if (widget.coin == Coin.ethereum) { + for (final data in walletsData.values) { + final List contracts = []; + final manager = + ref.read(walletsChangeNotifierProvider).getManager(data.walletId); + final contractAddresses = (manager.wallet as EthereumWallet) + .getWalletTokenContractAddresses(); + + // fetch each contract + for (final contractAddress in contractAddresses) { + final contract = ref + .read( + mainDBProvider, + ) + .getEthContractSync( + contractAddress, + ); + + // add it to list if it exists in DB + if (contract != null) { + contracts.add(contract); + } + } + + // add tuple to list + wallets.add( + Tuple2( + ref.read(walletsChangeNotifierProvider).getManager( + data.walletId, + ), + contracts, + ), + ); + } + } else { + // add non token wallet tuple to list + for (final data in walletsData.values) { + wallets.add( + Tuple2( + ref.read(walletsChangeNotifierProvider).getManager( + data.walletId, + ), + [], + ), + ); + } + } super.initState(); } + @override + void dispose() { + _searchController.dispose(); + searchFieldFocusNode.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Background( @@ -64,18 +182,125 @@ class _EthWalletsOverviewState extends ConsumerState { ), ), ), - child: ListView.separated( - itemCount: walletIds.length, - separatorBuilder: (_, __) => const SizedBox( - height: 8, - ), - itemBuilder: (_, index) => widget.coin == Coin.ethereum - ? MasterWalletCard( - walletId: walletIds[index], - ) - : WalletSheetCard( - walletId: walletIds[index], + child: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + autocorrect: !isDesktop, + enableSuggestions: !isDesktop, + controller: _searchController, + focusNode: searchFieldFocusNode, + onChanged: (value) { + setState(() { + _searchString = value; + }); + }, + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textFieldActiveText, + height: 1.8, + ) + : STextStyles.field(context), + decoration: standardInputDecoration( + "Search...", + searchFieldFocusNode, + context, + desktopMed: isDesktop, + ).copyWith( + prefixIcon: Padding( + padding: EdgeInsets.symmetric( + horizontal: isDesktop ? 12 : 10, + vertical: isDesktop ? 18 : 16, + ), + child: SvgPicture.asset( + Assets.svg.search, + width: isDesktop ? 20 : 16, + height: isDesktop ? 20 : 16, + ), + ), + suffixIcon: _searchController.text.isNotEmpty + ? Padding( + padding: const EdgeInsets.only(right: 0), + child: UnconstrainedBox( + child: Row( + children: [ + TextFieldIconButton( + child: const XIcon(), + onTap: () async { + setState(() { + _searchController.text = ""; + _searchString = ""; + }); + }, + ), + ], + ), + ), + ) + : null, ), + ), + ), + const SizedBox( + height: 16, + ), + Expanded( + child: Builder( + builder: (context) { + final data = _filter(_searchString); + return ListView.separated( + itemBuilder: (_, index) { + final element = data[index]; + + if (element.item1.hasTokenSupport) { + if (isDesktop) { + return DesktopExpandingWalletCard( + key: Key( + "${element.item1.walletName}_${element.item2.map((e) => e.address).join()}"), + data: element, + navigatorState: widget.navigatorState!, + ); + } else { + return MasterWalletCard( + walletId: element.item1.walletId, + ); + } + } else { + return ConditionalParent( + condition: isDesktop, + builder: (child) => RoundedWhiteContainer( + padding: const EdgeInsets.symmetric( + vertical: 14, + horizontal: 20, + ), + borderColor: Theme.of(context) + .extension()! + .backgroundAppBar, + child: child, + ), + child: SimpleWalletCard( + walletId: element.item1.walletId, + popPrevious: isDesktop, + desktopNavigatorState: + isDesktop ? widget.navigatorState : null, + ), + ); + } + }, + separatorBuilder: (_, __) => SizedBox( + height: isDesktop ? 10 : 8, + ), + itemCount: data.length, + ); + }, + ), + ), + ], ), ), ); diff --git a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart deleted file mode 100644 index 114503206..000000000 --- a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart +++ /dev/null @@ -1,441 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; -import 'package:stackwallet/providers/db/main_db_provider.dart'; -import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; -import 'package:stackwallet/services/coins/manager.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/text_styles.dart'; -import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/utilities/util.dart'; -import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart'; -import 'package:stackwallet/widgets/expandable.dart'; -import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; -import 'package:stackwallet/widgets/rounded_white_container.dart'; -import 'package:stackwallet/widgets/stack_text_field.dart'; -import 'package:stackwallet/widgets/textfield_icon_button.dart'; -import 'package:stackwallet/widgets/wallet_card.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; -import 'package:tuple/tuple.dart'; - -class DesktopCoinWalletsDialog extends ConsumerStatefulWidget { - const DesktopCoinWalletsDialog({ - Key? key, - required this.coin, - required this.navigatorState, - }) : super(key: key); - - final Coin coin; - final NavigatorState navigatorState; - - @override - ConsumerState createState() => - _DesktopCoinWalletsDialogState(); -} - -class _DesktopCoinWalletsDialogState - extends ConsumerState { - final isDesktop = Util.isDesktop; - - late final TextEditingController _searchController; - late final FocusNode searchFieldFocusNode; - - String _searchString = ""; - - final List>> wallets = []; - - List>> _filter(String searchTerm) { - if (searchTerm.isEmpty) { - return wallets; - } - - final List>> results = []; - final term = searchTerm.toLowerCase(); - - for (final tuple in wallets) { - bool includeManager = false; - // search wallet name and total balance - includeManager |= _elementContains(tuple.item1.walletName, term); - includeManager |= _elementContains( - tuple.item1.balance.total.decimal.toString(), - term, - ); - - final List contracts = []; - - for (final contract in tuple.item2) { - if (_elementContains(contract.name, term)) { - contracts.add(contract); - } else if (_elementContains(contract.symbol, term)) { - contracts.add(contract); - } else if (_elementContains(contract.type.name, term)) { - contracts.add(contract); - } else if (_elementContains(contract.address, term)) { - contracts.add(contract); - } - } - - if (includeManager || contracts.isNotEmpty) { - results.add(Tuple2(tuple.item1, contracts)); - } - } - - return results; - } - - bool _elementContains(String element, String term) { - return element.toLowerCase().contains(term); - } - - @override - void initState() { - _searchController = TextEditingController(); - searchFieldFocusNode = FocusNode(); - - final walletsData = - ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData(); - walletsData.removeWhere((key, value) => value.coin != widget.coin); - - if (widget.coin == Coin.ethereum) { - for (final data in walletsData.values) { - final List contracts = []; - final manager = - ref.read(walletsChangeNotifierProvider).getManager(data.walletId); - final contractAddresses = (manager.wallet as EthereumWallet) - .getWalletTokenContractAddresses(); - - // fetch each contract - for (final contractAddress in contractAddresses) { - final contract = ref - .read( - mainDBProvider, - ) - .getEthContractSync( - contractAddress, - ); - - // add it to list if it exists in DB - if (contract != null) { - contracts.add(contract); - } - } - - // add tuple to list - wallets.add( - Tuple2( - ref.read(walletsChangeNotifierProvider).getManager( - data.walletId, - ), - contracts, - ), - ); - } - } else { - // add non token wallet tuple to list - for (final data in walletsData.values) { - wallets.add( - Tuple2( - ref.read(walletsChangeNotifierProvider).getManager( - data.walletId, - ), - [], - ), - ); - } - } - - super.initState(); - } - - @override - void dispose() { - _searchController.dispose(); - searchFieldFocusNode.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Column( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - child: TextField( - autocorrect: !isDesktop, - enableSuggestions: !isDesktop, - controller: _searchController, - focusNode: searchFieldFocusNode, - onChanged: (value) { - setState(() { - _searchString = value; - }); - }, - style: isDesktop - ? STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of(context) - .extension()! - .textFieldActiveText, - height: 1.8, - ) - : STextStyles.field(context), - decoration: standardInputDecoration( - "Search...", - searchFieldFocusNode, - context, - desktopMed: isDesktop, - ).copyWith( - prefixIcon: Padding( - padding: EdgeInsets.symmetric( - horizontal: isDesktop ? 12 : 10, - vertical: isDesktop ? 18 : 16, - ), - child: SvgPicture.asset( - Assets.svg.search, - width: isDesktop ? 20 : 16, - height: isDesktop ? 20 : 16, - ), - ), - suffixIcon: _searchController.text.isNotEmpty - ? Padding( - padding: const EdgeInsets.only(right: 0), - child: UnconstrainedBox( - child: Row( - children: [ - TextFieldIconButton( - child: const XIcon(), - onTap: () async { - setState(() { - _searchController.text = ""; - _searchString = ""; - }); - }, - ), - ], - ), - ), - ) - : null, - ), - ), - ), - const SizedBox( - height: 16, - ), - Expanded( - child: Builder(builder: (context) { - final data = _filter(_searchString); - return ListView.separated( - itemBuilder: (_, index) => widget.coin == Coin.ethereum - ? _DesktopWalletCard( - key: Key( - "${data[index].item1.walletName}_${data[index].item2.map((e) => e.address).join()}"), - data: data[index], - navigatorState: widget.navigatorState, - ) - : RoundedWhiteContainer( - padding: const EdgeInsets.symmetric( - vertical: 14, - horizontal: 20, - ), - borderColor: Theme.of(context) - .extension()! - .backgroundAppBar, - child: WalletSheetCard( - walletId: data[index].item1.walletId, - popPrevious: true, - desktopNavigatorState: widget.navigatorState, - ), - ), - separatorBuilder: (_, __) => const SizedBox( - height: 10, - ), - itemCount: data.length, - ); - }), - ), - ], - ); - } -} - -class _DesktopWalletCard extends StatefulWidget { - const _DesktopWalletCard({ - Key? key, - required this.data, - required this.navigatorState, - }) : super(key: key); - - final Tuple2> data; - final NavigatorState navigatorState; - - @override - State<_DesktopWalletCard> createState() => _DesktopWalletCardState(); -} - -class _DesktopWalletCardState extends State<_DesktopWalletCard> { - final expandableController = ExpandableController(); - final rotateIconController = RotateIconController(); - final List tokenContractAddresses = []; - - @override - void initState() { - if (widget.data.item1.hasTokenSupport) { - tokenContractAddresses.addAll( - widget.data.item2.map((e) => e.address), - ); - } - - super.initState(); - } - - @override - Widget build(BuildContext context) { - return RoundedWhiteContainer( - padding: EdgeInsets.zero, - borderColor: Theme.of(context).extension()!.backgroundAppBar, - child: Expandable( - initialState: widget.data.item1.hasTokenSupport - ? ExpandableState.expanded - : ExpandableState.collapsed, - controller: expandableController, - onExpandWillChange: (toState) { - if (toState == ExpandableState.expanded) { - rotateIconController.forward?.call(); - } else { - rotateIconController.reverse?.call(); - } - }, - header: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 14, - ), - child: Row( - children: [ - Expanded( - child: Row( - children: [ - Expanded( - flex: 2, - child: Row( - children: [ - WalletInfoCoinIcon( - coin: widget.data.item1.coin, - ), - const SizedBox( - width: 12, - ), - Text( - widget.data.item1.walletName, - style: STextStyles.desktopTextExtraSmall(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textDark, - ), - ), - ], - ), - ), - Expanded( - flex: 4, - child: WalletInfoRowBalance( - walletId: widget.data.item1.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: RotatedBox( - quarterTurns: 2, - child: SvgPicture.asset( - Assets.svg.chevronDown, - width: 14, - ), - ), - curve: Curves.easeInOut, - ), - ), - ], - ), - ), - body: ListView( - shrinkWrap: true, - primary: false, - children: [ - Container( - width: double.infinity, - height: 1, - color: - Theme.of(context).extension()!.backgroundAppBar, - ), - Padding( - padding: const EdgeInsets.only( - left: 32, - right: 14, - top: 14, - bottom: 14, - ), - child: WalletSheetCard( - walletId: widget.data.item1.walletId, - popPrevious: true, - desktopNavigatorState: widget.navigatorState, - ), - ), - ...tokenContractAddresses.map( - (e) => Padding( - padding: const EdgeInsets.only( - left: 32, - right: 14, - top: 14, - bottom: 14, - ), - child: WalletSheetCard( - walletId: widget.data.item1.walletId, - contractAddress: e, - popPrevious: true, - desktopNavigatorState: widget.navigatorState, - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart new file mode 100644 index 000000000..3d40d7e9e --- /dev/null +++ b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart @@ -0,0 +1,192 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; +import 'package:stackwallet/services/coins/manager.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/text_styles.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/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; +import 'package:tuple/tuple.dart'; + +class DesktopExpandingWalletCard extends StatefulWidget { + const DesktopExpandingWalletCard({ + Key? key, + required this.data, + required this.navigatorState, + }) : super(key: key); + + final Tuple2> data; + final NavigatorState navigatorState; + + @override + State createState() => + _DesktopExpandingWalletCardState(); +} + +class _DesktopExpandingWalletCardState + extends State { + final expandableController = ExpandableController(); + final rotateIconController = RotateIconController(); + final List tokenContractAddresses = []; + + @override + void initState() { + if (widget.data.item1.hasTokenSupport) { + tokenContractAddresses.addAll( + widget.data.item2.map((e) => e.address), + ); + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return RoundedWhiteContainer( + padding: EdgeInsets.zero, + borderColor: Theme.of(context).extension()!.backgroundAppBar, + child: Expandable( + initialState: widget.data.item1.hasTokenSupport + ? ExpandableState.expanded + : ExpandableState.collapsed, + controller: expandableController, + onExpandWillChange: (toState) { + if (toState == ExpandableState.expanded) { + rotateIconController.forward?.call(); + } else { + rotateIconController.reverse?.call(); + } + }, + header: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 14, + ), + child: Row( + children: [ + Expanded( + child: Row( + children: [ + Expanded( + flex: 2, + child: Row( + children: [ + WalletInfoCoinIcon( + coin: widget.data.item1.coin, + ), + const SizedBox( + width: 12, + ), + Text( + widget.data.item1.walletName, + style: STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ), + ), + ], + ), + ), + Expanded( + flex: 4, + child: WalletInfoRowBalance( + walletId: widget.data.item1.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: RotatedBox( + quarterTurns: 2, + child: SvgPicture.asset( + Assets.svg.chevronDown, + width: 14, + ), + ), + curve: Curves.easeInOut, + ), + ), + ], + ), + ), + body: ListView( + shrinkWrap: true, + primary: false, + children: [ + Container( + width: double.infinity, + height: 1, + color: + Theme.of(context).extension()!.backgroundAppBar, + ), + Padding( + padding: const EdgeInsets.only( + left: 32, + right: 14, + top: 14, + bottom: 14, + ), + child: SimpleWalletCard( + walletId: widget.data.item1.walletId, + popPrevious: true, + desktopNavigatorState: widget.navigatorState, + ), + ), + ...tokenContractAddresses.map( + (e) => Padding( + padding: const EdgeInsets.only( + left: 32, + right: 14, + top: 14, + bottom: 14, + ), + child: SimpleWalletCard( + walletId: widget.data.item1.walletId, + contractAddress: e, + popPrevious: true, + desktopNavigatorState: widget.navigatorState, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart index 9741ae905..505906849 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart'; +import 'package:stackwallet/pages/wallets_view/wallets_overview.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -103,7 +103,7 @@ class _DesktopWalletSummaryRowState extends State { right: 32, bottom: 32, ), - child: DesktopCoinWalletsDialog( + child: WalletsOverview( coin: widget.coin, navigatorState: Navigator.of(context), ), diff --git a/lib/widgets/master_wallet_card.dart b/lib/widgets/master_wallet_card.dart index 165ae9ec5..929edb039 100644 --- a/lib/widgets/master_wallet_card.dart +++ b/lib/widgets/master_wallet_card.dart @@ -116,7 +116,7 @@ class _MasterWalletCardState extends ConsumerState { padding: const EdgeInsets.all( 7, ), - child: WalletSheetCard( + child: SimpleWalletCard( walletId: widget.walletId, popPrevious: true, ), @@ -128,7 +128,7 @@ class _MasterWalletCardState extends ConsumerState { right: 7, bottom: 7, ), - child: WalletSheetCard( + child: SimpleWalletCard( walletId: widget.walletId, contractAddress: e, popPrevious: true, diff --git a/lib/widgets/wallet_card.dart b/lib/widgets/wallet_card.dart index 9e4fbc034..5e1ed21fd 100644 --- a/lib/widgets/wallet_card.dart +++ b/lib/widgets/wallet_card.dart @@ -21,8 +21,8 @@ import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; import 'package:tuple/tuple.dart'; -class WalletSheetCard extends ConsumerWidget { - const WalletSheetCard({ +class SimpleWalletCard extends ConsumerWidget { + const SimpleWalletCard({ Key? key, required this.walletId, this.contractAddress, @@ -113,7 +113,7 @@ class WalletSheetCard extends ConsumerWidget { child: MaterialButton( // splashColor: Theme.of(context).extension()!.highlight, key: Key("walletsSheetItemButtonKey_$walletId"), - padding: const EdgeInsets.all(5), + padding: const EdgeInsets.all(10), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( diff --git a/test/widget_tests/wallet_card_test.dart b/test/widget_tests/wallet_card_test.dart index c8d2231c8..fe2479e1e 100644 --- a/test/widget_tests/wallet_card_test.dart +++ b/test/widget_tests/wallet_card_test.dart @@ -84,7 +84,7 @@ void main() { ), home: mockingjay.MockNavigatorProvider( navigator: navigator, - child: const WalletSheetCard( + child: const SimpleWalletCard( walletId: "wallet id", )), ), @@ -122,7 +122,7 @@ void main() { mockito.when(wallets.getManagerProvider("wallet id")).thenAnswer( (realInvocation) => ChangeNotifierProvider((ref) => manager)); - const walletSheetCard = WalletSheetCard( + const walletSheetCard = SimpleWalletCard( walletId: "wallet id", ); From 5615fbaeca5a79b653458734c8d6fdf0a80806ab Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 10:02:19 -0600 Subject: [PATCH 05/21] Balance class clean up --- lib/models/balance.dart | 17 ++--- lib/models/token_balance.dart | 62 ------------------- .../exchange_view/choose_from_stack_view.dart | 2 +- .../desktop_expanding_wallet_card.dart | 2 +- .../coins/epiccash/epiccash_wallet.dart | 1 - .../coins/ethereum/ethereum_wallet.dart | 9 +-- lib/services/coins/firo/firo_wallet.dart | 2 - lib/services/coins/monero/monero_wallet.dart | 1 - .../coins/wownero/wownero_wallet.dart | 1 - .../ethereum/cached_eth_token_balance.dart | 5 +- .../ethereum/ethereum_token_service.dart | 9 ++- .../mixins/coin_control_interface.dart | 1 - lib/services/mixins/eth_token_cache.dart | 11 ++-- lib/services/mixins/wallet_cache.dart | 6 +- lib/widgets/eth_wallet_radio.dart | 2 +- ...ture.dart => wallet_info_row_balance.dart} | 0 .../wallet_info_row/wallet_info_row.dart | 2 +- .../wallet_info_row_balance_future_test.dart | 2 +- .../wallet_info_row/wallet_info_row_test.dart | 2 +- 19 files changed, 28 insertions(+), 109 deletions(-) delete mode 100644 lib/models/token_balance.dart rename lib/widgets/wallet_info_row/sub_widgets/{wallet_info_row_balance_future.dart => wallet_info_row_balance.dart} (100%) diff --git a/lib/models/balance.dart b/lib/models/balance.dart index da03b3dae..63fbe9ab7 100644 --- a/lib/models/balance.dart +++ b/lib/models/balance.dart @@ -1,17 +1,14 @@ import 'dart:convert'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; class Balance { - final Coin coin; final Amount total; final Amount spendable; final Amount blockedTotal; final Amount pendingSpendable; Balance({ - required this.coin, required this.total, required this.spendable, required this.blockedTotal, @@ -25,42 +22,40 @@ class Balance { "pendingSpendable": pendingSpendable.toJsonString(), }); - // need to fall back to parsing from in due to cached balances being previously + // need to fall back to parsing from int due to cached balances being previously // stored as int values instead of Amounts - factory Balance.fromJson(String json, Coin coin) { + factory Balance.fromJson(String json, int deprecatedValue) { final decoded = jsonDecode(json); return Balance( - coin: coin, total: decoded["total"] is String ? Amount.fromSerializedJsonString(decoded["total"] as String) : Amount( rawValue: BigInt.from(decoded["total"] as int), - fractionDigits: coin.decimals, + fractionDigits: deprecatedValue, ), spendable: decoded["spendable"] is String ? Amount.fromSerializedJsonString(decoded["spendable"] as String) : Amount( rawValue: BigInt.from(decoded["spendable"] as int), - fractionDigits: coin.decimals, + fractionDigits: deprecatedValue, ), blockedTotal: decoded["blockedTotal"] is String ? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String) : Amount( rawValue: BigInt.from(decoded["blockedTotal"] as int), - fractionDigits: coin.decimals, + fractionDigits: deprecatedValue, ), pendingSpendable: decoded["pendingSpendable"] is String ? Amount.fromSerializedJsonString( decoded["pendingSpendable"] as String) : Amount( rawValue: BigInt.from(decoded["pendingSpendable"] as int), - fractionDigits: coin.decimals, + fractionDigits: deprecatedValue, ), ); } Map toMap() => { - "coin": coin, "total": total, "spendable": spendable, "blockedTotal": blockedTotal, diff --git a/lib/models/token_balance.dart b/lib/models/token_balance.dart deleted file mode 100644 index f2606f04d..000000000 --- a/lib/models/token_balance.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'dart:convert'; - -import 'package:stackwallet/models/balance.dart'; -import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; - -class TokenBalance extends Balance { - TokenBalance({ - required this.contractAddress, - required super.total, - required super.spendable, - required super.blockedTotal, - required super.pendingSpendable, - super.coin = Coin.ethereum, - }); - - final String contractAddress; - - @override - String toJsonIgnoreCoin() => jsonEncode({ - "contractAddress": contractAddress, - "total": total.toJsonString(), - "spendable": spendable.toJsonString(), - "blockedTotal": blockedTotal.toJsonString(), - "pendingSpendable": pendingSpendable.toJsonString(), - }); - - factory TokenBalance.fromJson( - String json, - int fractionDigits, - ) { - final decoded = jsonDecode(json); - return TokenBalance( - contractAddress: decoded["contractAddress"] as String, - total: decoded["total"] is String - ? Amount.fromSerializedJsonString(decoded["total"] as String) - : Amount( - rawValue: BigInt.from(decoded["total"] as int), - fractionDigits: fractionDigits, - ), - spendable: decoded["spendable"] is String - ? Amount.fromSerializedJsonString(decoded["spendable"] as String) - : Amount( - rawValue: BigInt.from(decoded["spendable"] as int), - fractionDigits: fractionDigits, - ), - blockedTotal: decoded["blockedTotal"] is String - ? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String) - : Amount( - rawValue: BigInt.from(decoded["blockedTotal"] as int), - fractionDigits: fractionDigits, - ), - pendingSpendable: decoded["pendingSpendable"] is String - ? Amount.fromSerializedJsonString( - decoded["pendingSpendable"] as String) - : Amount( - rawValue: BigInt.from(decoded["pendingSpendable"] as int), - fractionDigits: fractionDigits, - ), - ); - } -} diff --git a/lib/pages/exchange_view/choose_from_stack_view.dart b/lib/pages/exchange_view/choose_from_stack_view.dart index 505554a7c..bbfe91880 100644 --- a/lib/pages/exchange_view/choose_from_stack_view.dart +++ b/lib/pages/exchange_view/choose_from_stack_view.dart @@ -8,7 +8,7 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; class ChooseFromStackView extends ConsumerStatefulWidget { diff --git a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart index 3d40d7e9e..21493a31d 100644 --- a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart +++ b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart @@ -11,7 +11,7 @@ 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/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; import 'package:tuple/tuple.dart'; diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index cbbbc76c8..c15a5bee3 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1978,7 +1978,6 @@ class EpicCashWallet extends CoinServiceAPI (jsonBalances['amount_awaiting_finalization'] as double).toString(); _balance = Balance( - coin: coin, total: Amount.fromDecimal( Decimal.parse(total) + Decimal.parse(awaiting), fractionDigits: coin.decimals, diff --git a/lib/services/coins/ethereum/ethereum_wallet.dart b/lib/services/coins/ethereum/ethereum_wallet.dart index b5fafeff5..380f4dc04 100644 --- a/lib/services/coins/ethereum/ethereum_wallet.dart +++ b/lib/services/coins/ethereum/ethereum_wallet.dart @@ -10,7 +10,6 @@ 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'; @@ -78,14 +77,13 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { ); } - TokenBalance getCachedTokenBalance(EthContract contract) { + Balance 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, + return Balance( total: Amount( rawValue: BigInt.zero, fractionDigits: contract.decimals, @@ -104,7 +102,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { ), ); } - return TokenBalance.fromJson( + return Balance.fromJson( jsonString, contract.decimals, ); @@ -222,7 +220,6 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { web3.Web3Client client = getEthClient(); web3.EtherAmount ethBalance = await client.getBalance(_credentials.address); _balance = Balance( - coin: coin, total: Amount( rawValue: ethBalance.getInWei, fractionDigits: coin.decimals, diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart index 22cdde933..38d1fb172 100644 --- a/lib/services/coins/firo/firo_wallet.dart +++ b/lib/services/coins/firo/firo_wallet.dart @@ -2515,7 +2515,6 @@ class FiroWallet extends CoinServiceAPI } _balancePrivate = Balance( - coin: coin, total: Amount( rawValue: BigInt.from(intLelantusBalance + unconfirmedLelantusBalance), @@ -3803,7 +3802,6 @@ class FiroWallet extends CoinServiceAPI // finally update public balance _balance = Balance( - coin: coin, total: satoshiBalanceTotal, spendable: satoshiBalanceSpendable, blockedTotal: satoshiBalanceBlocked, diff --git a/lib/services/coins/monero/monero_wallet.dart b/lib/services/coins/monero/monero_wallet.dart index 87b803255..29debe753 100644 --- a/lib/services/coins/monero/monero_wallet.dart +++ b/lib/services/coins/monero/monero_wallet.dart @@ -747,7 +747,6 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB { final total = await _totalBalance; final available = await _availableBalance; _balance = Balance( - coin: coin, total: total, spendable: available, blockedTotal: Amount( diff --git a/lib/services/coins/wownero/wownero_wallet.dart b/lib/services/coins/wownero/wownero_wallet.dart index 84f806be2..4e3591d8c 100644 --- a/lib/services/coins/wownero/wownero_wallet.dart +++ b/lib/services/coins/wownero/wownero_wallet.dart @@ -774,7 +774,6 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB { final total = await _totalBalance; final available = await _availableBalance; _balance = Balance( - coin: coin, total: total, spendable: available, blockedTotal: Amount( diff --git a/lib/services/ethereum/cached_eth_token_balance.dart b/lib/services/ethereum/cached_eth_token_balance.dart index f36cf2ea3..d477d0460 100644 --- a/lib/services/ethereum/cached_eth_token_balance.dart +++ b/lib/services/ethereum/cached_eth_token_balance.dart @@ -1,5 +1,5 @@ +import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; -import 'package:stackwallet/models/token_balance.dart'; import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/mixins/eth_token_cache.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; @@ -21,8 +21,7 @@ class CachedEthTokenBalance with EthTokenCache { if (response.value != null) { await updateCachedBalance( - TokenBalance( - contractAddress: token.address, + Balance( total: response.value!, spendable: response.value!, blockedTotal: Amount( diff --git a/lib/services/ethereum/ethereum_token_service.dart b/lib/services/ethereum/ethereum_token_service.dart index 90edb1904..f56561e8d 100644 --- a/lib/services/ethereum/ethereum_token_service.dart +++ b/lib/services/ethereum/ethereum_token_service.dart @@ -8,10 +8,10 @@ import 'package:isar/isar.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/dto/ethereum/eth_token_tx_dto.dart'; import 'package:stackwallet/dto/ethereum/eth_token_tx_extra_dto.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/ethereum/ethereum_wallet.dart'; import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart'; @@ -60,8 +60,8 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { EthContract get tokenContract => _tokenContract; EthContract _tokenContract; - TokenBalance get balance => _balance ??= getCachedBalance(); - TokenBalance? _balance; + Balance get balance => _balance ??= getCachedBalance(); + Balance? _balance; Coin get coin => Coin.ethereum; @@ -413,8 +413,7 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { String _balance = balanceRequest.first.toString(); - final newBalance = TokenBalance( - contractAddress: tokenContract.address, + final newBalance = Balance( total: Amount.fromDecimal( Decimal.parse(_balance), fractionDigits: tokenContract.decimals, diff --git a/lib/services/mixins/coin_control_interface.dart b/lib/services/mixins/coin_control_interface.dart index e9af99161..d3e6079a0 100644 --- a/lib/services/mixins/coin_control_interface.dart +++ b/lib/services/mixins/coin_control_interface.dart @@ -76,7 +76,6 @@ mixin CoinControlInterface { } final balance = Balance( - coin: _coin, total: satoshiBalanceTotal, spendable: satoshiBalanceSpendable, blockedTotal: satoshiBalanceBlocked, diff --git a/lib/services/mixins/eth_token_cache.dart b/lib/services/mixins/eth_token_cache.dart index ccaa293d0..b1fdf6bb3 100644 --- a/lib/services/mixins/eth_token_cache.dart +++ b/lib/services/mixins/eth_token_cache.dart @@ -1,6 +1,6 @@ import 'package:stackwallet/db/hive/db.dart'; +import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; -import 'package:stackwallet/models/token_balance.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; abstract class TokenCacheKeys { @@ -19,14 +19,13 @@ mixin EthTokenCache { } // token balance cache - TokenBalance getCachedBalance() { + Balance getCachedBalance() { final jsonString = DB.instance.get( boxName: _walletId, key: TokenCacheKeys.tokenBalance(_token.address), ) as String?; if (jsonString == null) { - return TokenBalance( - contractAddress: _token.address, + return Balance( total: Amount( rawValue: BigInt.zero, fractionDigits: _token.decimals, @@ -45,13 +44,13 @@ mixin EthTokenCache { ), ); } - return TokenBalance.fromJson( + return Balance.fromJson( jsonString, _token.decimals, ); } - Future updateCachedBalance(TokenBalance balance) async { + Future updateCachedBalance(Balance balance) async { await DB.instance.put( boxName: _walletId, key: TokenCacheKeys.tokenBalance(_token.address), diff --git a/lib/services/mixins/wallet_cache.dart b/lib/services/mixins/wallet_cache.dart index 49f53381a..435e28717 100644 --- a/lib/services/mixins/wallet_cache.dart +++ b/lib/services/mixins/wallet_cache.dart @@ -70,7 +70,6 @@ mixin WalletCache { ) as String?; if (jsonString == null) { return Balance( - coin: _coin, total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), spendable: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), @@ -80,7 +79,7 @@ mixin WalletCache { Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), ); } - return Balance.fromJson(jsonString, _coin); + return Balance.fromJson(jsonString, _coin.decimals); } Future updateCachedBalance(Balance balance) async { @@ -99,7 +98,6 @@ mixin WalletCache { ) as String?; if (jsonString == null) { return Balance( - coin: _coin, total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), spendable: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), @@ -109,7 +107,7 @@ mixin WalletCache { Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), ); } - return Balance.fromJson(jsonString, _coin); + return Balance.fromJson(jsonString, _coin.decimals); } Future updateCachedBalanceSecondary(Balance balance) async { diff --git a/lib/widgets/eth_wallet_radio.dart b/lib/widgets/eth_wallet_radio.dart index c20a4cbb9..e5a0c2bb5 100644 --- a/lib/widgets/eth_wallet_radio.dart +++ b/lib/widgets/eth_wallet_radio.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; class EthWalletRadio extends ConsumerStatefulWidget { 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.dart similarity index 100% rename from lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart rename to lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart diff --git a/lib/widgets/wallet_info_row/wallet_info_row.dart b/lib/widgets/wallet_info_row/wallet_info_row.dart index 26879aa7e..c31e8e19f 100644 --- a/lib/widgets/wallet_info_row/wallet_info_row.dart +++ b/lib/widgets/wallet_info_row/wallet_info_row.dart @@ -8,7 +8,7 @@ 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/custom_buttons/blue_text_button.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; class WalletInfoRow extends ConsumerWidget { diff --git a/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.dart b/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.dart index 943a02e99..70dfbfdc4 100644 --- a/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.dart +++ b/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.dart @@ -15,7 +15,7 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/theme/light_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'wallet_info_row_balance_future_test.mocks.dart'; diff --git a/test/widget_tests/wallet_info_row/wallet_info_row_test.dart b/test/widget_tests/wallet_info_row/wallet_info_row_test.dart index 4308ac273..a9318e11a 100644 --- a/test/widget_tests/wallet_info_row/wallet_info_row_test.dart +++ b/test/widget_tests/wallet_info_row/wallet_info_row_test.dart @@ -15,7 +15,7 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/theme/light_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; import 'wallet_info_row_test.mocks.dart'; From 9b027bd7494640c2007a14129e8be2fe689b84b4 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 11:28:36 -0600 Subject: [PATCH 06/21] token theme colors --- .../token_view/sub_widgets/token_summary.dart | 83 +++++++++++----- lib/pages/token_view/token_view.dart | 3 + .../sub_widgets/wallet_refresh_button.dart | 16 +++- lib/utilities/theme/chan_colors.dart | 20 ++++ lib/utilities/theme/color_theme.dart | 16 +++- lib/utilities/theme/dark_colors.dart | 20 ++++ lib/utilities/theme/forest_colors.dart | 20 ++++ lib/utilities/theme/fruit_sorbet_colors.dart | 20 ++++ lib/utilities/theme/light_colors.dart | 20 ++++ lib/utilities/theme/ocean_breeze_colors.dart | 20 ++++ lib/utilities/theme/oled_black_colors.dart | 20 ++++ lib/utilities/theme/oled_chans_colors.dart | 20 ++++ lib/utilities/theme/orange_colors.dart | 20 ++++ lib/utilities/theme/stack_colors.dart | 94 +++++++++++++++++++ 14 files changed, 363 insertions(+), 29 deletions(-) diff --git a/lib/pages/token_view/sub_widgets/token_summary.dart b/lib/pages/token_view/sub_widgets/token_summary.dart index 2d9db8b62..d9c62ae66 100644 --- a/lib/pages/token_view/sub_widgets/token_summary.dart +++ b/lib/pages/token_view/sub_widgets/token_summary.dart @@ -21,6 +21,7 @@ import 'package:stackwallet/utilities/constants.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/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:tuple/tuple.dart'; @@ -44,8 +45,7 @@ class TokenSummary extends ConsumerWidget { return Stack( children: [ RoundedContainer( - color: const Color(0xFFE9EAFF), // todo: fix color - // color: Theme.of(context).extension()!., + color: Theme.of(context).extension()!.tokenSummaryBG, padding: const EdgeInsets.all(24), child: Column( children: [ @@ -54,7 +54,9 @@ class TokenSummary extends ConsumerWidget { children: [ SvgPicture.asset( Assets.svg.walletDesktop, - color: const Color(0xFF8488AB), // todo: fix color + color: Theme.of(context) + .extension()! + .tokenSummaryTextSecondary, width: 12, height: 12, ), @@ -68,7 +70,9 @@ class TokenSummary extends ConsumerWidget { ), ), style: STextStyles.w500_12(context).copyWith( - color: const Color(0xFF8488AB), // todo: fix color + color: Theme.of(context) + .extension()! + .tokenSummaryTextSecondary, ), ), ], @@ -88,7 +92,11 @@ class TokenSummary extends ConsumerWidget { ), )}" " ${token.symbol}", - style: STextStyles.pageTitleH1(context), + style: STextStyles.pageTitleH1(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ), const SizedBox( width: 10, @@ -119,7 +127,11 @@ class TokenSummary extends ConsumerWidget { (value) => value.currency, ), )}", - style: STextStyles.subtitle500(context), + style: STextStyles.subtitle500(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ), const SizedBox( height: 20, @@ -137,8 +149,13 @@ class TokenSummary extends ConsumerWidget { child: WalletRefreshButton( walletId: walletId, initialSyncStatus: initialSyncStatus, - tokenContractAddress: ref.watch(tokenServiceProvider - .select((value) => value!.tokenContract.address)), + tokenContractAddress: ref.watch( + tokenServiceProvider.select( + (value) => value!.tokenContract.address, + ), + ), + overrideIconColor: + Theme.of(context).extension()!.topNavIconPrimary, ), ), ], @@ -197,7 +214,7 @@ class TokenWalletOptions extends StatelessWidget { ); }, subLabel: "Receive", - iconAssetSVG: Assets.svg.receive(context), + iconAssetSVG: Assets.svg.arrowDownLeft, ), const SizedBox( width: 16, @@ -214,7 +231,7 @@ class TokenWalletOptions extends StatelessWidget { ); }, subLabel: "Send", - iconAssetSVG: Assets.svg.send(context), + iconAssetSVG: Assets.svg.arrowUpRight, ), const SizedBox( width: 16, @@ -251,12 +268,14 @@ class TokenOptionsButton extends StatelessWidget { @override Widget build(BuildContext context) { + final iconSize = subLabel == "Send" || subLabel == "Receive" ? 12.0 : 24.0; return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ RawMaterialButton( - fillColor: Theme.of(context).extension()!.popupBG, + fillColor: + Theme.of(context).extension()!.tokenSummaryButtonBG, elevation: 0, focusElevation: 0, hoverElevation: 0, @@ -270,11 +289,27 @@ class TokenOptionsButton extends StatelessWidget { onPressed: onPressed, child: Padding( padding: const EdgeInsets.all(10), - child: SvgPicture.asset( - iconAssetSVG, - color: const Color(0xFF424A97), // todo: fix color - width: 24, - height: 24, + child: ConditionalParent( + condition: iconSize < 24, + builder: (child) => RoundedContainer( + padding: const EdgeInsets.all(6), + color: Theme.of(context) + .extension()! + .tokenSummaryIcon + .withOpacity(0.4), + radiusMultiplier: 10, + child: Center( + child: child, + ), + ), + child: SvgPicture.asset( + iconAssetSVG, + color: Theme.of(context) + .extension()! + .tokenSummaryIcon, + width: iconSize, + height: iconSize, + ), ), ), ), @@ -283,7 +318,11 @@ class TokenOptionsButton extends StatelessWidget { ), Text( subLabel, - style: STextStyles.w500_12(context), + style: STextStyles.w500_12(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ) ], ); @@ -303,12 +342,14 @@ class CoinTickerTag extends ConsumerWidget { return RoundedContainer( padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 4), radiusMultiplier: 0.25, - color: const Color(0xFF4D5798), // TODO: color theme for multi themes + color: Theme.of(context).extension()!.ethTagBG, child: Text( - ref.watch(walletsChangeNotifierProvider - .select((value) => value.getManager(walletId).coin.ticker)), + ref.watch( + walletsChangeNotifierProvider + .select((value) => value.getManager(walletId).coin.ticker), + ), style: STextStyles.w600_12(context).copyWith( - color: Colors.white, // TODO: design is wrong? + color: Theme.of(context).extension()!.ethTagText, ), ), ); diff --git a/lib/pages/token_view/token_view.dart b/lib/pages/token_view/token_view.dart index 851119f06..0faae0bce 100644 --- a/lib/pages/token_view/token_view.dart +++ b/lib/pages/token_view/token_view.dart @@ -110,6 +110,9 @@ class _TokenViewState extends ConsumerState { child: AppBarIconButton( icon: SvgPicture.asset( Assets.svg.verticalEllipsis, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, ), onPressed: () { // todo: context menu diff --git a/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart b/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart index 453762b80..ac82fc98c 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart @@ -22,6 +22,7 @@ class WalletRefreshButton extends ConsumerStatefulWidget { this.tokenContractAddress, this.onPressed, this.eventBus, + this.overrideIconColor, }) : super(key: key); final String walletId; @@ -29,6 +30,7 @@ class WalletRefreshButton extends ConsumerStatefulWidget { final String? tokenContractAddress; final VoidCallback? onPressed; final EventBus? eventBus; + final Color? overrideIconColor; @override ConsumerState createState() => _RefreshButtonState(); @@ -155,11 +157,15 @@ class _RefreshButtonState extends ConsumerState Assets.svg.arrowRotate, width: isDesktop ? 12 : 24, height: isDesktop ? 12 : 24, - color: isDesktop - ? Theme.of(context) - .extension()! - .textFieldDefaultSearchIconRight - : Theme.of(context).extension()!.textFavoriteCard, + color: widget.overrideIconColor != null + ? widget.overrideIconColor! + : isDesktop + ? Theme.of(context) + .extension()! + .textFieldDefaultSearchIconRight + : Theme.of(context) + .extension()! + .textFavoriteCard, ), ), ), diff --git a/lib/utilities/theme/chan_colors.dart b/lib/utilities/theme/chan_colors.dart index f9ea1bb54..cce17b7bb 100644 --- a/lib/utilities/theme/chan_colors.dart +++ b/lib/utilities/theme/chan_colors.dart @@ -335,6 +335,26 @@ class ChanColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFF0F3FD); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF8488AB); + @override + Color get tokenSummaryBG => const Color(0xFFE9EAFF); + @override + Color get tokenSummaryButtonBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryIcon => const Color(0xFF424A97); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/color_theme.dart b/lib/utilities/theme/color_theme.dart index eaa3d702b..879c7be71 100644 --- a/lib/utilities/theme/color_theme.dart +++ b/lib/utilities/theme/color_theme.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/theme/chan_colors.dart'; import 'package:stackwallet/utilities/theme/dark_colors.dart'; import 'package:stackwallet/utilities/theme/forest_colors.dart'; import 'package:stackwallet/utilities/theme/fruit_sorbet_colors.dart'; @@ -7,9 +8,7 @@ import 'package:stackwallet/utilities/theme/light_colors.dart'; import 'package:stackwallet/utilities/theme/ocean_breeze_colors.dart'; import 'package:stackwallet/utilities/theme/oled_black_colors.dart'; import 'package:stackwallet/utilities/theme/oled_chans_colors.dart'; - -import 'chan_colors.dart'; -import 'orange_colors.dart'; +import 'package:stackwallet/utilities/theme/orange_colors.dart'; enum ThemeType { light, @@ -285,6 +284,17 @@ abstract class StackColorTheme { Color get rateTypeToggleDesktopColorOn; Color get rateTypeToggleDesktopColorOff; + // token view colors + Color get ethTagText; + Color get ethTagBG; + Color get ethWalletTagText; + Color get ethWalletTagBG; + Color get tokenSummaryTextPrimary; + Color get tokenSummaryTextSecondary; + Color get tokenSummaryBG; + Color get tokenSummaryButtonBG; + Color get tokenSummaryIcon; + BoxShadow get standardBoxShadow; BoxShadow? get homeViewButtonBarBoxShadow; } diff --git a/lib/utilities/theme/dark_colors.dart b/lib/utilities/theme/dark_colors.dart index fbbf113ef..549bb677c 100644 --- a/lib/utilities/theme/dark_colors.dart +++ b/lib/utilities/theme/dark_colors.dart @@ -335,6 +335,26 @@ class DarkColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF5761A2); + @override + Color get ethWalletTagText => const Color(0xFFE7EBFF); + @override + Color get ethWalletTagBG => const Color(0xFF414868); + @override + Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryBG => const Color(0xFF464C73); + @override + Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryIcon => const Color(0xFF252C78); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/forest_colors.dart b/lib/utilities/theme/forest_colors.dart index 8d66befda..0fd4b1774 100644 --- a/lib/utilities/theme/forest_colors.dart +++ b/lib/utilities/theme/forest_colors.dart @@ -335,6 +335,26 @@ class ForestColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFEBEFFE); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF4D5798); + @override + Color get tokenSummaryBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryButtonBG => const Color(0xFFE9FBEF); + @override + Color get tokenSummaryIcon => const Color(0xFF22867A); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/fruit_sorbet_colors.dart b/lib/utilities/theme/fruit_sorbet_colors.dart index a13985a93..86358aa6f 100644 --- a/lib/utilities/theme/fruit_sorbet_colors.dart +++ b/lib/utilities/theme/fruit_sorbet_colors.dart @@ -335,6 +335,26 @@ class FruitSorbetColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => popupBG; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFEBEFFE); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF4D5798); + @override + Color get tokenSummaryBG => const Color(0xFFFFF8EE); + @override + Color get tokenSummaryButtonBG => const Color(0xFFFEDED4); + @override + Color get tokenSummaryIcon => const Color(0xFFF62A45); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/light_colors.dart b/lib/utilities/theme/light_colors.dart index b42f2dd9a..8fa83da95 100644 --- a/lib/utilities/theme/light_colors.dart +++ b/lib/utilities/theme/light_colors.dart @@ -335,6 +335,26 @@ class LightColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFF0F3FD); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF8488AB); + @override + Color get tokenSummaryBG => const Color(0xFFE9EAFF); + @override + Color get tokenSummaryButtonBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryIcon => const Color(0xFF424A97); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/ocean_breeze_colors.dart b/lib/utilities/theme/ocean_breeze_colors.dart index 1b528d6a1..dc2e7268b 100644 --- a/lib/utilities/theme/ocean_breeze_colors.dart +++ b/lib/utilities/theme/ocean_breeze_colors.dart @@ -342,6 +342,26 @@ class OceanBreezeColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFEBEFFE); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF4D5798); + @override + Color get tokenSummaryBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryButtonBG => const Color(0xFFEDF4F9); + @override + Color get tokenSummaryIcon => const Color(0xFF197287); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/oled_black_colors.dart b/lib/utilities/theme/oled_black_colors.dart index 4f273eeff..40bf3ee8f 100644 --- a/lib/utilities/theme/oled_black_colors.dart +++ b/lib/utilities/theme/oled_black_colors.dart @@ -338,6 +338,26 @@ class OledBlackColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF5761A2); + @override + Color get ethWalletTagText => const Color(0xFFDEDEDE); + @override + Color get ethWalletTagBG => const Color(0xFF222539); + @override + Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryBG => const Color(0xFF292D45); + @override + Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryIcon => const Color(0xFF252C78); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/oled_chans_colors.dart b/lib/utilities/theme/oled_chans_colors.dart index 83600d5d5..22179dd08 100644 --- a/lib/utilities/theme/oled_chans_colors.dart +++ b/lib/utilities/theme/oled_chans_colors.dart @@ -335,6 +335,26 @@ class DarkChansColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF5761A2); + @override + Color get ethWalletTagText => const Color(0xFFDEDEDE); + @override + Color get ethWalletTagBG => const Color(0xFF222539); + @override + Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryBG => const Color(0xFF292D45); + @override + Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryIcon => const Color(0xFF252C78); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/orange_colors.dart b/lib/utilities/theme/orange_colors.dart index eeac65b89..fb4c7a937 100644 --- a/lib/utilities/theme/orange_colors.dart +++ b/lib/utilities/theme/orange_colors.dart @@ -335,6 +335,26 @@ class OrangeColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFEBEFFE); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF4D5798); + @override + Color get tokenSummaryBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryButtonBG => const Color(0xAAFFC58F); + @override + Color get tokenSummaryIcon => const Color(0xFFF36B43); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/stack_colors.dart b/lib/utilities/theme/stack_colors.dart index cbba0bb36..f9a1f39c1 100644 --- a/lib/utilities/theme/stack_colors.dart +++ b/lib/utilities/theme/stack_colors.dart @@ -187,6 +187,17 @@ class StackColors extends ThemeExtension { final Color rateTypeToggleDesktopColorOn; final Color rateTypeToggleDesktopColorOff; + // token view colors + final Color ethTagText; + final Color ethTagBG; + final Color ethWalletTagText; + final Color ethWalletTagBG; + final Color tokenSummaryTextPrimary; + final Color tokenSummaryTextSecondary; + final Color tokenSummaryBG; + final Color tokenSummaryButtonBG; + final Color tokenSummaryIcon; + final BoxShadow standardBoxShadow; final BoxShadow? homeViewButtonBarBoxShadow; @@ -337,6 +348,15 @@ class StackColors extends ThemeExtension { required this.rateTypeToggleDesktopColorOff, required this.standardBoxShadow, required this.homeViewButtonBarBoxShadow, + required this.ethTagText, + required this.ethTagBG, + required this.ethWalletTagText, + required this.ethWalletTagBG, + required this.tokenSummaryTextPrimary, + required this.tokenSummaryTextSecondary, + required this.tokenSummaryBG, + required this.tokenSummaryButtonBG, + required this.tokenSummaryIcon, }); factory StackColors.fromStackColorTheme(StackColorTheme colorTheme) { @@ -490,6 +510,15 @@ class StackColors extends ThemeExtension { rateTypeToggleDesktopColorOff: colorTheme.rateTypeToggleDesktopColorOff, homeViewButtonBarBoxShadow: colorTheme.homeViewButtonBarBoxShadow, standardBoxShadow: colorTheme.standardBoxShadow, + ethTagText: colorTheme.ethTagText, + ethTagBG: colorTheme.ethTagBG, + ethWalletTagText: colorTheme.ethWalletTagText, + ethWalletTagBG: colorTheme.ethWalletTagBG, + tokenSummaryTextPrimary: colorTheme.tokenSummaryTextPrimary, + tokenSummaryTextSecondary: colorTheme.tokenSummaryTextSecondary, + tokenSummaryBG: colorTheme.tokenSummaryBG, + tokenSummaryButtonBG: colorTheme.tokenSummaryButtonBG, + tokenSummaryIcon: colorTheme.tokenSummaryIcon, ); } @@ -639,6 +668,15 @@ class StackColors extends ThemeExtension { Color? rateTypeToggleColorOff, Color? rateTypeToggleDesktopColorOn, Color? rateTypeToggleDesktopColorOff, + Color? ethTagText, + Color? ethTagBG, + Color? ethWalletTagText, + Color? ethWalletTagBG, + Color? tokenSummaryTextPrimary, + Color? tokenSummaryTextSecondary, + Color? tokenSummaryBG, + Color? tokenSummaryButtonBG, + Color? tokenSummaryIcon, BoxShadow? homeViewButtonBarBoxShadow, BoxShadow? standardBoxShadow, }) { @@ -833,6 +871,17 @@ class StackColors extends ThemeExtension { rateTypeToggleDesktopColorOn ?? this.rateTypeToggleDesktopColorOn, rateTypeToggleDesktopColorOff: rateTypeToggleDesktopColorOff ?? this.rateTypeToggleDesktopColorOff, + ethTagText: ethTagText ?? this.ethTagText, + ethTagBG: ethTagBG ?? this.ethTagBG, + ethWalletTagText: ethWalletTagText ?? this.ethWalletTagText, + ethWalletTagBG: ethWalletTagBG ?? this.ethWalletTagBG, + tokenSummaryTextPrimary: + tokenSummaryTextPrimary ?? this.tokenSummaryTextPrimary, + tokenSummaryTextSecondary: + tokenSummaryTextSecondary ?? this.tokenSummaryTextSecondary, + tokenSummaryBG: tokenSummaryBG ?? this.tokenSummaryBG, + tokenSummaryButtonBG: tokenSummaryButtonBG ?? this.tokenSummaryButtonBG, + tokenSummaryIcon: tokenSummaryIcon ?? this.tokenSummaryIcon, homeViewButtonBarBoxShadow: homeViewButtonBarBoxShadow ?? this.homeViewButtonBarBoxShadow, standardBoxShadow: standardBoxShadow ?? this.standardBoxShadow, @@ -1557,6 +1606,51 @@ class StackColors extends ThemeExtension { other.rateTypeToggleDesktopColorOff, t, )!, + ethTagText: Color.lerp( + ethTagText, + other.ethTagText, + t, + )!, + ethTagBG: Color.lerp( + ethTagBG, + other.ethTagBG, + t, + )!, + ethWalletTagText: Color.lerp( + ethWalletTagText, + other.ethWalletTagText, + t, + )!, + ethWalletTagBG: Color.lerp( + ethWalletTagBG, + other.ethWalletTagBG, + t, + )!, + tokenSummaryTextPrimary: Color.lerp( + tokenSummaryTextPrimary, + other.tokenSummaryTextPrimary, + t, + )!, + tokenSummaryTextSecondary: Color.lerp( + tokenSummaryTextSecondary, + other.tokenSummaryTextSecondary, + t, + )!, + tokenSummaryBG: Color.lerp( + tokenSummaryBG, + other.tokenSummaryBG, + t, + )!, + tokenSummaryButtonBG: Color.lerp( + tokenSummaryButtonBG, + other.tokenSummaryButtonBG, + t, + )!, + tokenSummaryIcon: Color.lerp( + tokenSummaryIcon, + other.tokenSummaryIcon, + t, + )!, ); } From b3b4d803a63f48d512f9ef08b63cc57281d755c0 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 08:53:47 -0600 Subject: [PATCH 07/21] mobile eth restore flow navigation bug fix --- .../edit_wallet_tokens_view.dart | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart b/lib/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart index 936ca5405..11f05c206 100644 --- a/lib/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart +++ b/lib/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart @@ -11,6 +11,7 @@ import 'package:stackwallet/pages/add_wallet_views/add_token_view/add_custom_tok import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list_element.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_text.dart'; +import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; @@ -97,16 +98,25 @@ class _EditWalletTokensViewState extends ConsumerState { if (widget.contractsToMarkSelected == null) { Navigator.of(context).pop(42); } else { - Navigator.of(context).popUntil( - ModalRoute.withName(DesktopHomeView.routeName), - ); - unawaited( - showFloatingFlushBar( - type: FlushBarType.success, - message: "${ethWallet.walletName} tokens saved", - context: context, - ), - ); + if (isDesktop) { + Navigator.of(context).popUntil( + ModalRoute.withName(DesktopHomeView.routeName), + ); + } else { + await Navigator.of(context).pushNamedAndRemoveUntil( + HomeView.routeName, + (route) => false, + ); + } + if (mounted) { + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "${ethWallet.walletName} tokens saved", + context: context, + ), + ); + } } } } From 000e98cbb6849a1374f63526336ceb1468ccb879 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 09:12:07 -0600 Subject: [PATCH 08/21] mobile open wallet gui flow changes --- lib/pages/wallets_sheet/wallets_sheet.dart | 101 ------------------ .../sub_widgets/wallet_list_item.dart | 23 +--- ...ts_overview.dart => wallets_overview.dart} | 36 ++++--- lib/route_generator.dart | 23 ++-- 4 files changed, 42 insertions(+), 141 deletions(-) delete mode 100644 lib/pages/wallets_sheet/wallets_sheet.dart rename lib/pages/wallets_view/{eth_wallets_overview.dart => wallets_overview.dart} (64%) diff --git a/lib/pages/wallets_sheet/wallets_sheet.dart b/lib/pages/wallets_sheet/wallets_sheet.dart deleted file mode 100644 index dbbe371f1..000000000 --- a/lib/pages/wallets_sheet/wallets_sheet.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/constants.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/widgets/wallet_card.dart'; - -class WalletsSheet extends ConsumerWidget { - const WalletsSheet({ - Key? key, - required this.coin, - }) : super(key: key); - - final Coin coin; - - @override - Widget build(BuildContext context, WidgetRef ref) { - final providers = ref - .watch(walletsChangeNotifierProvider - .select((value) => value.getManagerProvidersByCoin())) - .where((e) => e.item1 == coin) - .map((e) => e.item2) - .expand((e) => e) - .toList(); - - final maxHeight = MediaQuery.of(context).size.height * 0.60; - - return Container( - decoration: BoxDecoration( - color: Theme.of(context).extension()!.popupBG, - borderRadius: const BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - child: LimitedBox( - maxHeight: maxHeight, - child: Padding( - padding: const EdgeInsets.only( - left: 24, - right: 24, - top: 10, - bottom: 0, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Container( - decoration: BoxDecoration( - color: Theme.of(context) - .extension()! - .textFieldDefaultBG, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - ), - width: 60, - height: 4, - ), - ), - const SizedBox( - height: 36, - ), - Text( - "${coin.prettyName} (${coin.ticker}) wallets", - style: STextStyles.pageTitleH2(context), - textAlign: TextAlign.left, - ), - const SizedBox( - height: 16, - ), - Flexible( - child: ListView.builder( - shrinkWrap: true, - itemCount: providers.length, - itemBuilder: (builderContext, index) { - final walletId = ref.watch( - providers[index].select((value) => value.walletId)); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: WalletSheetCard( - walletId: walletId, - popPrevious: true, - ), - ); - }, - ), - ), - const SizedBox( - height: 24, - ), - ], - ), - ), - ), - ); - } -} 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 ac4c6fb85..851d2445f 100644 --- a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart +++ b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; 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/pages/wallets_view/wallets_overview.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -46,13 +45,7 @@ class WalletListItem extends ConsumerWidget { BorderRadius.circular(Constants.size.circularBorderRadius), ), onPressed: () async { - if (coin == Coin.ethereum) { - unawaited( - Navigator.of(context).pushNamed( - EthWalletsOverview.routeName, - ), - ); - } else if (walletCount == 1) { + if (walletCount == 1 && coin != Coin.ethereum) { final providersByCoin = ref .watch(walletsChangeNotifierProvider .select((value) => value.getManagerProvidersByCoin())) @@ -77,15 +70,9 @@ class WalletListItem extends ConsumerWidget { } } else { unawaited( - showModalBottomSheet( - backgroundColor: Colors.transparent, - context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - builder: (_) => WalletsSheet(coin: coin), + Navigator.of(context).pushNamed( + WalletsOverview.routeName, + arguments: coin, ), ); } diff --git a/lib/pages/wallets_view/eth_wallets_overview.dart b/lib/pages/wallets_view/wallets_overview.dart similarity index 64% rename from lib/pages/wallets_view/eth_wallets_overview.dart rename to lib/pages/wallets_view/wallets_overview.dart index 35e1b4411..e79c13383 100644 --- a/lib/pages/wallets_view/eth_wallets_overview.dart +++ b/lib/pages/wallets_view/wallets_overview.dart @@ -9,29 +9,35 @@ 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'; +import 'package:stackwallet/widgets/wallet_card.dart'; -class EthWalletsOverview extends ConsumerStatefulWidget { - const EthWalletsOverview({Key? key}) : super(key: key); +class WalletsOverview extends ConsumerStatefulWidget { + const WalletsOverview({ + Key? key, + required this.coin, + }) : super(key: key); + + final Coin coin; static const routeName = "/ethWalletsOverview"; @override - ConsumerState createState() => _EthWalletsOverviewState(); + ConsumerState createState() => _EthWalletsOverviewState(); } -class _EthWalletsOverviewState extends ConsumerState { +class _EthWalletsOverviewState extends ConsumerState { final isDesktop = Util.isDesktop; - final List ethWalletIds = []; + final List walletIds = []; @override void initState() { final walletsData = ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData(); - walletsData.removeWhere((key, value) => value.coin != Coin.ethereum); - ethWalletIds.clear(); + walletsData.removeWhere((key, value) => value.coin != widget.coin); + walletIds.clear(); - ethWalletIds.addAll(walletsData.values.map((e) => e.walletId)); + walletIds.addAll(walletsData.values.map((e) => e.walletId)); super.initState(); } @@ -47,7 +53,7 @@ class _EthWalletsOverviewState extends ConsumerState { appBar: AppBar( leading: const AppBarBackButton(), title: Text( - "Ethereum (ETH) wallets", + "${widget.coin.prettyName} (${widget.coin.ticker}) wallets", style: STextStyles.navBarTitle(context), ), ), @@ -59,13 +65,17 @@ class _EthWalletsOverviewState extends ConsumerState { ), ), child: ListView.separated( - itemCount: ethWalletIds.length, + itemCount: walletIds.length, separatorBuilder: (_, __) => const SizedBox( height: 8, ), - itemBuilder: (_, index) => MasterWalletCard( - walletId: ethWalletIds[index], - ), + itemBuilder: (_, index) => widget.coin == Coin.ethereum + ? MasterWalletCard( + walletId: walletIds[index], + ) + : WalletSheetCard( + walletId: walletIds[index], + ), ), ), ); diff --git a/lib/route_generator.dart b/lib/route_generator.dart index db3a7450c..4031e425e 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -106,7 +106,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_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/addresses/desktop_wallet_addresses_view.dart'; @@ -280,14 +280,19 @@ class RouteGenerator { ), ); - case EthWalletsOverview.routeName: - return getRoute( - shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const EthWalletsOverview(), - settings: RouteSettings( - name: settings.name, - ), - ); + case WalletsOverview.routeName: + if (args is Coin) { + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => WalletsOverview( + coin: args, + ), + settings: RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); case TokenContractDetailsView.routeName: if (args is Tuple2) { From 26cfa84da7039fea0b24a0a7abdfd29d44918cbd Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 09:16:07 -0600 Subject: [PATCH 09/21] expand eth wallet card dropdown when header is clicked/tapped anywhere, not just the tiny grey button area --- .../dialogs/desktop_coin_wallets_dialog.dart | 8 +++++++- lib/widgets/master_wallet_card.dart | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart index 46d8a3b19..114503206 100644 --- a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart @@ -306,7 +306,13 @@ class _DesktopWalletCardState extends State<_DesktopWalletCard> { ? ExpandableState.expanded : ExpandableState.collapsed, controller: expandableController, - expandOverride: () {}, + onExpandWillChange: (toState) { + if (toState == ExpandableState.expanded) { + rotateIconController.forward?.call(); + } else { + rotateIconController.reverse?.call(); + } + }, header: Padding( padding: const EdgeInsets.symmetric( horizontal: 20, diff --git a/lib/widgets/master_wallet_card.dart b/lib/widgets/master_wallet_card.dart index 65f65c3a1..165ae9ec5 100644 --- a/lib/widgets/master_wallet_card.dart +++ b/lib/widgets/master_wallet_card.dart @@ -49,7 +49,13 @@ class _MasterWalletCardState extends ConsumerState { padding: EdgeInsets.zero, child: Expandable( controller: expandableController, - expandOverride: () {}, + onExpandWillChange: (toState) { + if (toState == ExpandableState.expanded) { + rotateIconController.forward?.call(); + } else { + rotateIconController.reverse?.call(); + } + }, header: Padding( padding: const EdgeInsets.all(12), child: Row( From 742036138b29044c1d071c3f0184991d7bc43178 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 09:44:38 -0600 Subject: [PATCH 10/21] add search to mobile coin wallets per-coin list --- lib/pages/wallets_view/wallets_overview.dart | 255 +++++++++- .../dialogs/desktop_coin_wallets_dialog.dart | 441 ------------------ .../desktop_expanding_wallet_card.dart | 192 ++++++++ .../my_stack_view/wallet_summary_table.dart | 4 +- lib/widgets/master_wallet_card.dart | 4 +- lib/widgets/wallet_card.dart | 6 +- test/widget_tests/wallet_card_test.dart | 4 +- 7 files changed, 441 insertions(+), 465 deletions(-) delete mode 100644 lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart create mode 100644 lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart diff --git a/lib/pages/wallets_view/wallets_overview.dart b/lib/pages/wallets_view/wallets_overview.dart index e79c13383..bc68ec30b 100644 --- a/lib/pages/wallets_view/wallets_overview.dart +++ b/lib/pages/wallets_view/wallets_overview.dart @@ -1,6 +1,14 @@ 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_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart'; +import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; +import 'package:stackwallet/services/coins/manager.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/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; @@ -8,18 +16,25 @@ 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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/master_wallet_card.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/stack_text_field.dart'; +import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/wallet_card.dart'; +import 'package:tuple/tuple.dart'; class WalletsOverview extends ConsumerStatefulWidget { const WalletsOverview({ Key? key, required this.coin, + this.navigatorState, }) : super(key: key); final Coin coin; + final NavigatorState? navigatorState; - static const routeName = "/ethWalletsOverview"; + static const routeName = "/walletsOverview"; @override ConsumerState createState() => _EthWalletsOverviewState(); @@ -28,20 +43,123 @@ class WalletsOverview extends ConsumerStatefulWidget { class _EthWalletsOverviewState extends ConsumerState { final isDesktop = Util.isDesktop; - final List walletIds = []; + late final TextEditingController _searchController; + late final FocusNode searchFieldFocusNode; + + String _searchString = ""; + + final List>> wallets = []; + + List>> _filter(String searchTerm) { + if (searchTerm.isEmpty) { + return wallets; + } + + final List>> results = []; + final term = searchTerm.toLowerCase(); + + for (final tuple in wallets) { + bool includeManager = false; + // search wallet name and total balance + includeManager |= _elementContains(tuple.item1.walletName, term); + includeManager |= _elementContains( + tuple.item1.balance.total.decimal.toString(), + term, + ); + + final List contracts = []; + + for (final contract in tuple.item2) { + if (_elementContains(contract.name, term)) { + contracts.add(contract); + } else if (_elementContains(contract.symbol, term)) { + contracts.add(contract); + } else if (_elementContains(contract.type.name, term)) { + contracts.add(contract); + } else if (_elementContains(contract.address, term)) { + contracts.add(contract); + } + } + + if (includeManager || contracts.isNotEmpty) { + results.add(Tuple2(tuple.item1, contracts)); + } + } + + return results; + } + + bool _elementContains(String element, String term) { + return element.toLowerCase().contains(term); + } @override void initState() { + _searchController = TextEditingController(); + searchFieldFocusNode = FocusNode(); + final walletsData = ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData(); walletsData.removeWhere((key, value) => value.coin != widget.coin); - walletIds.clear(); - walletIds.addAll(walletsData.values.map((e) => e.walletId)); + if (widget.coin == Coin.ethereum) { + for (final data in walletsData.values) { + final List contracts = []; + final manager = + ref.read(walletsChangeNotifierProvider).getManager(data.walletId); + final contractAddresses = (manager.wallet as EthereumWallet) + .getWalletTokenContractAddresses(); + + // fetch each contract + for (final contractAddress in contractAddresses) { + final contract = ref + .read( + mainDBProvider, + ) + .getEthContractSync( + contractAddress, + ); + + // add it to list if it exists in DB + if (contract != null) { + contracts.add(contract); + } + } + + // add tuple to list + wallets.add( + Tuple2( + ref.read(walletsChangeNotifierProvider).getManager( + data.walletId, + ), + contracts, + ), + ); + } + } else { + // add non token wallet tuple to list + for (final data in walletsData.values) { + wallets.add( + Tuple2( + ref.read(walletsChangeNotifierProvider).getManager( + data.walletId, + ), + [], + ), + ); + } + } super.initState(); } + @override + void dispose() { + _searchController.dispose(); + searchFieldFocusNode.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Background( @@ -64,18 +182,125 @@ class _EthWalletsOverviewState extends ConsumerState { ), ), ), - child: ListView.separated( - itemCount: walletIds.length, - separatorBuilder: (_, __) => const SizedBox( - height: 8, - ), - itemBuilder: (_, index) => widget.coin == Coin.ethereum - ? MasterWalletCard( - walletId: walletIds[index], - ) - : WalletSheetCard( - walletId: walletIds[index], + child: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + autocorrect: !isDesktop, + enableSuggestions: !isDesktop, + controller: _searchController, + focusNode: searchFieldFocusNode, + onChanged: (value) { + setState(() { + _searchString = value; + }); + }, + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textFieldActiveText, + height: 1.8, + ) + : STextStyles.field(context), + decoration: standardInputDecoration( + "Search...", + searchFieldFocusNode, + context, + desktopMed: isDesktop, + ).copyWith( + prefixIcon: Padding( + padding: EdgeInsets.symmetric( + horizontal: isDesktop ? 12 : 10, + vertical: isDesktop ? 18 : 16, + ), + child: SvgPicture.asset( + Assets.svg.search, + width: isDesktop ? 20 : 16, + height: isDesktop ? 20 : 16, + ), + ), + suffixIcon: _searchController.text.isNotEmpty + ? Padding( + padding: const EdgeInsets.only(right: 0), + child: UnconstrainedBox( + child: Row( + children: [ + TextFieldIconButton( + child: const XIcon(), + onTap: () async { + setState(() { + _searchController.text = ""; + _searchString = ""; + }); + }, + ), + ], + ), + ), + ) + : null, ), + ), + ), + const SizedBox( + height: 16, + ), + Expanded( + child: Builder( + builder: (context) { + final data = _filter(_searchString); + return ListView.separated( + itemBuilder: (_, index) { + final element = data[index]; + + if (element.item1.hasTokenSupport) { + if (isDesktop) { + return DesktopExpandingWalletCard( + key: Key( + "${element.item1.walletName}_${element.item2.map((e) => e.address).join()}"), + data: element, + navigatorState: widget.navigatorState!, + ); + } else { + return MasterWalletCard( + walletId: element.item1.walletId, + ); + } + } else { + return ConditionalParent( + condition: isDesktop, + builder: (child) => RoundedWhiteContainer( + padding: const EdgeInsets.symmetric( + vertical: 14, + horizontal: 20, + ), + borderColor: Theme.of(context) + .extension()! + .backgroundAppBar, + child: child, + ), + child: SimpleWalletCard( + walletId: element.item1.walletId, + popPrevious: isDesktop, + desktopNavigatorState: + isDesktop ? widget.navigatorState : null, + ), + ); + } + }, + separatorBuilder: (_, __) => SizedBox( + height: isDesktop ? 10 : 8, + ), + itemCount: data.length, + ); + }, + ), + ), + ], ), ), ); diff --git a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart deleted file mode 100644 index 114503206..000000000 --- a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart +++ /dev/null @@ -1,441 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; -import 'package:stackwallet/providers/db/main_db_provider.dart'; -import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; -import 'package:stackwallet/services/coins/manager.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/text_styles.dart'; -import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/utilities/util.dart'; -import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart'; -import 'package:stackwallet/widgets/expandable.dart'; -import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; -import 'package:stackwallet/widgets/rounded_white_container.dart'; -import 'package:stackwallet/widgets/stack_text_field.dart'; -import 'package:stackwallet/widgets/textfield_icon_button.dart'; -import 'package:stackwallet/widgets/wallet_card.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; -import 'package:tuple/tuple.dart'; - -class DesktopCoinWalletsDialog extends ConsumerStatefulWidget { - const DesktopCoinWalletsDialog({ - Key? key, - required this.coin, - required this.navigatorState, - }) : super(key: key); - - final Coin coin; - final NavigatorState navigatorState; - - @override - ConsumerState createState() => - _DesktopCoinWalletsDialogState(); -} - -class _DesktopCoinWalletsDialogState - extends ConsumerState { - final isDesktop = Util.isDesktop; - - late final TextEditingController _searchController; - late final FocusNode searchFieldFocusNode; - - String _searchString = ""; - - final List>> wallets = []; - - List>> _filter(String searchTerm) { - if (searchTerm.isEmpty) { - return wallets; - } - - final List>> results = []; - final term = searchTerm.toLowerCase(); - - for (final tuple in wallets) { - bool includeManager = false; - // search wallet name and total balance - includeManager |= _elementContains(tuple.item1.walletName, term); - includeManager |= _elementContains( - tuple.item1.balance.total.decimal.toString(), - term, - ); - - final List contracts = []; - - for (final contract in tuple.item2) { - if (_elementContains(contract.name, term)) { - contracts.add(contract); - } else if (_elementContains(contract.symbol, term)) { - contracts.add(contract); - } else if (_elementContains(contract.type.name, term)) { - contracts.add(contract); - } else if (_elementContains(contract.address, term)) { - contracts.add(contract); - } - } - - if (includeManager || contracts.isNotEmpty) { - results.add(Tuple2(tuple.item1, contracts)); - } - } - - return results; - } - - bool _elementContains(String element, String term) { - return element.toLowerCase().contains(term); - } - - @override - void initState() { - _searchController = TextEditingController(); - searchFieldFocusNode = FocusNode(); - - final walletsData = - ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData(); - walletsData.removeWhere((key, value) => value.coin != widget.coin); - - if (widget.coin == Coin.ethereum) { - for (final data in walletsData.values) { - final List contracts = []; - final manager = - ref.read(walletsChangeNotifierProvider).getManager(data.walletId); - final contractAddresses = (manager.wallet as EthereumWallet) - .getWalletTokenContractAddresses(); - - // fetch each contract - for (final contractAddress in contractAddresses) { - final contract = ref - .read( - mainDBProvider, - ) - .getEthContractSync( - contractAddress, - ); - - // add it to list if it exists in DB - if (contract != null) { - contracts.add(contract); - } - } - - // add tuple to list - wallets.add( - Tuple2( - ref.read(walletsChangeNotifierProvider).getManager( - data.walletId, - ), - contracts, - ), - ); - } - } else { - // add non token wallet tuple to list - for (final data in walletsData.values) { - wallets.add( - Tuple2( - ref.read(walletsChangeNotifierProvider).getManager( - data.walletId, - ), - [], - ), - ); - } - } - - super.initState(); - } - - @override - void dispose() { - _searchController.dispose(); - searchFieldFocusNode.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Column( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - child: TextField( - autocorrect: !isDesktop, - enableSuggestions: !isDesktop, - controller: _searchController, - focusNode: searchFieldFocusNode, - onChanged: (value) { - setState(() { - _searchString = value; - }); - }, - style: isDesktop - ? STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of(context) - .extension()! - .textFieldActiveText, - height: 1.8, - ) - : STextStyles.field(context), - decoration: standardInputDecoration( - "Search...", - searchFieldFocusNode, - context, - desktopMed: isDesktop, - ).copyWith( - prefixIcon: Padding( - padding: EdgeInsets.symmetric( - horizontal: isDesktop ? 12 : 10, - vertical: isDesktop ? 18 : 16, - ), - child: SvgPicture.asset( - Assets.svg.search, - width: isDesktop ? 20 : 16, - height: isDesktop ? 20 : 16, - ), - ), - suffixIcon: _searchController.text.isNotEmpty - ? Padding( - padding: const EdgeInsets.only(right: 0), - child: UnconstrainedBox( - child: Row( - children: [ - TextFieldIconButton( - child: const XIcon(), - onTap: () async { - setState(() { - _searchController.text = ""; - _searchString = ""; - }); - }, - ), - ], - ), - ), - ) - : null, - ), - ), - ), - const SizedBox( - height: 16, - ), - Expanded( - child: Builder(builder: (context) { - final data = _filter(_searchString); - return ListView.separated( - itemBuilder: (_, index) => widget.coin == Coin.ethereum - ? _DesktopWalletCard( - key: Key( - "${data[index].item1.walletName}_${data[index].item2.map((e) => e.address).join()}"), - data: data[index], - navigatorState: widget.navigatorState, - ) - : RoundedWhiteContainer( - padding: const EdgeInsets.symmetric( - vertical: 14, - horizontal: 20, - ), - borderColor: Theme.of(context) - .extension()! - .backgroundAppBar, - child: WalletSheetCard( - walletId: data[index].item1.walletId, - popPrevious: true, - desktopNavigatorState: widget.navigatorState, - ), - ), - separatorBuilder: (_, __) => const SizedBox( - height: 10, - ), - itemCount: data.length, - ); - }), - ), - ], - ); - } -} - -class _DesktopWalletCard extends StatefulWidget { - const _DesktopWalletCard({ - Key? key, - required this.data, - required this.navigatorState, - }) : super(key: key); - - final Tuple2> data; - final NavigatorState navigatorState; - - @override - State<_DesktopWalletCard> createState() => _DesktopWalletCardState(); -} - -class _DesktopWalletCardState extends State<_DesktopWalletCard> { - final expandableController = ExpandableController(); - final rotateIconController = RotateIconController(); - final List tokenContractAddresses = []; - - @override - void initState() { - if (widget.data.item1.hasTokenSupport) { - tokenContractAddresses.addAll( - widget.data.item2.map((e) => e.address), - ); - } - - super.initState(); - } - - @override - Widget build(BuildContext context) { - return RoundedWhiteContainer( - padding: EdgeInsets.zero, - borderColor: Theme.of(context).extension()!.backgroundAppBar, - child: Expandable( - initialState: widget.data.item1.hasTokenSupport - ? ExpandableState.expanded - : ExpandableState.collapsed, - controller: expandableController, - onExpandWillChange: (toState) { - if (toState == ExpandableState.expanded) { - rotateIconController.forward?.call(); - } else { - rotateIconController.reverse?.call(); - } - }, - header: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 14, - ), - child: Row( - children: [ - Expanded( - child: Row( - children: [ - Expanded( - flex: 2, - child: Row( - children: [ - WalletInfoCoinIcon( - coin: widget.data.item1.coin, - ), - const SizedBox( - width: 12, - ), - Text( - widget.data.item1.walletName, - style: STextStyles.desktopTextExtraSmall(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textDark, - ), - ), - ], - ), - ), - Expanded( - flex: 4, - child: WalletInfoRowBalance( - walletId: widget.data.item1.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: RotatedBox( - quarterTurns: 2, - child: SvgPicture.asset( - Assets.svg.chevronDown, - width: 14, - ), - ), - curve: Curves.easeInOut, - ), - ), - ], - ), - ), - body: ListView( - shrinkWrap: true, - primary: false, - children: [ - Container( - width: double.infinity, - height: 1, - color: - Theme.of(context).extension()!.backgroundAppBar, - ), - Padding( - padding: const EdgeInsets.only( - left: 32, - right: 14, - top: 14, - bottom: 14, - ), - child: WalletSheetCard( - walletId: widget.data.item1.walletId, - popPrevious: true, - desktopNavigatorState: widget.navigatorState, - ), - ), - ...tokenContractAddresses.map( - (e) => Padding( - padding: const EdgeInsets.only( - left: 32, - right: 14, - top: 14, - bottom: 14, - ), - child: WalletSheetCard( - walletId: widget.data.item1.walletId, - contractAddress: e, - popPrevious: true, - desktopNavigatorState: widget.navigatorState, - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart new file mode 100644 index 000000000..3d40d7e9e --- /dev/null +++ b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart @@ -0,0 +1,192 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; +import 'package:stackwallet/services/coins/manager.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/text_styles.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/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; +import 'package:tuple/tuple.dart'; + +class DesktopExpandingWalletCard extends StatefulWidget { + const DesktopExpandingWalletCard({ + Key? key, + required this.data, + required this.navigatorState, + }) : super(key: key); + + final Tuple2> data; + final NavigatorState navigatorState; + + @override + State createState() => + _DesktopExpandingWalletCardState(); +} + +class _DesktopExpandingWalletCardState + extends State { + final expandableController = ExpandableController(); + final rotateIconController = RotateIconController(); + final List tokenContractAddresses = []; + + @override + void initState() { + if (widget.data.item1.hasTokenSupport) { + tokenContractAddresses.addAll( + widget.data.item2.map((e) => e.address), + ); + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return RoundedWhiteContainer( + padding: EdgeInsets.zero, + borderColor: Theme.of(context).extension()!.backgroundAppBar, + child: Expandable( + initialState: widget.data.item1.hasTokenSupport + ? ExpandableState.expanded + : ExpandableState.collapsed, + controller: expandableController, + onExpandWillChange: (toState) { + if (toState == ExpandableState.expanded) { + rotateIconController.forward?.call(); + } else { + rotateIconController.reverse?.call(); + } + }, + header: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 14, + ), + child: Row( + children: [ + Expanded( + child: Row( + children: [ + Expanded( + flex: 2, + child: Row( + children: [ + WalletInfoCoinIcon( + coin: widget.data.item1.coin, + ), + const SizedBox( + width: 12, + ), + Text( + widget.data.item1.walletName, + style: STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ), + ), + ], + ), + ), + Expanded( + flex: 4, + child: WalletInfoRowBalance( + walletId: widget.data.item1.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: RotatedBox( + quarterTurns: 2, + child: SvgPicture.asset( + Assets.svg.chevronDown, + width: 14, + ), + ), + curve: Curves.easeInOut, + ), + ), + ], + ), + ), + body: ListView( + shrinkWrap: true, + primary: false, + children: [ + Container( + width: double.infinity, + height: 1, + color: + Theme.of(context).extension()!.backgroundAppBar, + ), + Padding( + padding: const EdgeInsets.only( + left: 32, + right: 14, + top: 14, + bottom: 14, + ), + child: SimpleWalletCard( + walletId: widget.data.item1.walletId, + popPrevious: true, + desktopNavigatorState: widget.navigatorState, + ), + ), + ...tokenContractAddresses.map( + (e) => Padding( + padding: const EdgeInsets.only( + left: 32, + right: 14, + top: 14, + bottom: 14, + ), + child: SimpleWalletCard( + walletId: widget.data.item1.walletId, + contractAddress: e, + popPrevious: true, + desktopNavigatorState: widget.navigatorState, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart index 9741ae905..505906849 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart'; +import 'package:stackwallet/pages/wallets_view/wallets_overview.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -103,7 +103,7 @@ class _DesktopWalletSummaryRowState extends State { right: 32, bottom: 32, ), - child: DesktopCoinWalletsDialog( + child: WalletsOverview( coin: widget.coin, navigatorState: Navigator.of(context), ), diff --git a/lib/widgets/master_wallet_card.dart b/lib/widgets/master_wallet_card.dart index 165ae9ec5..929edb039 100644 --- a/lib/widgets/master_wallet_card.dart +++ b/lib/widgets/master_wallet_card.dart @@ -116,7 +116,7 @@ class _MasterWalletCardState extends ConsumerState { padding: const EdgeInsets.all( 7, ), - child: WalletSheetCard( + child: SimpleWalletCard( walletId: widget.walletId, popPrevious: true, ), @@ -128,7 +128,7 @@ class _MasterWalletCardState extends ConsumerState { right: 7, bottom: 7, ), - child: WalletSheetCard( + child: SimpleWalletCard( walletId: widget.walletId, contractAddress: e, popPrevious: true, diff --git a/lib/widgets/wallet_card.dart b/lib/widgets/wallet_card.dart index 9e4fbc034..5e1ed21fd 100644 --- a/lib/widgets/wallet_card.dart +++ b/lib/widgets/wallet_card.dart @@ -21,8 +21,8 @@ import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; import 'package:tuple/tuple.dart'; -class WalletSheetCard extends ConsumerWidget { - const WalletSheetCard({ +class SimpleWalletCard extends ConsumerWidget { + const SimpleWalletCard({ Key? key, required this.walletId, this.contractAddress, @@ -113,7 +113,7 @@ class WalletSheetCard extends ConsumerWidget { child: MaterialButton( // splashColor: Theme.of(context).extension()!.highlight, key: Key("walletsSheetItemButtonKey_$walletId"), - padding: const EdgeInsets.all(5), + padding: const EdgeInsets.all(10), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( diff --git a/test/widget_tests/wallet_card_test.dart b/test/widget_tests/wallet_card_test.dart index c8d2231c8..fe2479e1e 100644 --- a/test/widget_tests/wallet_card_test.dart +++ b/test/widget_tests/wallet_card_test.dart @@ -84,7 +84,7 @@ void main() { ), home: mockingjay.MockNavigatorProvider( navigator: navigator, - child: const WalletSheetCard( + child: const SimpleWalletCard( walletId: "wallet id", )), ), @@ -122,7 +122,7 @@ void main() { mockito.when(wallets.getManagerProvider("wallet id")).thenAnswer( (realInvocation) => ChangeNotifierProvider((ref) => manager)); - const walletSheetCard = WalletSheetCard( + const walletSheetCard = SimpleWalletCard( walletId: "wallet id", ); From 5bf678d41ac56952cd008945f6e32ebe428c4f9a Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 10:02:19 -0600 Subject: [PATCH 11/21] Balance class clean up --- lib/models/balance.dart | 17 ++--- lib/models/token_balance.dart | 62 ------------------- .../exchange_view/choose_from_stack_view.dart | 2 +- .../desktop_expanding_wallet_card.dart | 2 +- .../coins/epiccash/epiccash_wallet.dart | 1 - .../coins/ethereum/ethereum_wallet.dart | 9 +-- lib/services/coins/firo/firo_wallet.dart | 2 - lib/services/coins/monero/monero_wallet.dart | 1 - .../coins/wownero/wownero_wallet.dart | 1 - .../ethereum/cached_eth_token_balance.dart | 5 +- .../ethereum/ethereum_token_service.dart | 9 ++- .../mixins/coin_control_interface.dart | 1 - lib/services/mixins/eth_token_cache.dart | 11 ++-- lib/services/mixins/wallet_cache.dart | 6 +- lib/widgets/eth_wallet_radio.dart | 2 +- ...ture.dart => wallet_info_row_balance.dart} | 0 .../wallet_info_row/wallet_info_row.dart | 2 +- .../wallet_info_row_balance_future_test.dart | 2 +- .../wallet_info_row/wallet_info_row_test.dart | 2 +- 19 files changed, 28 insertions(+), 109 deletions(-) delete mode 100644 lib/models/token_balance.dart rename lib/widgets/wallet_info_row/sub_widgets/{wallet_info_row_balance_future.dart => wallet_info_row_balance.dart} (100%) diff --git a/lib/models/balance.dart b/lib/models/balance.dart index da03b3dae..63fbe9ab7 100644 --- a/lib/models/balance.dart +++ b/lib/models/balance.dart @@ -1,17 +1,14 @@ import 'dart:convert'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; class Balance { - final Coin coin; final Amount total; final Amount spendable; final Amount blockedTotal; final Amount pendingSpendable; Balance({ - required this.coin, required this.total, required this.spendable, required this.blockedTotal, @@ -25,42 +22,40 @@ class Balance { "pendingSpendable": pendingSpendable.toJsonString(), }); - // need to fall back to parsing from in due to cached balances being previously + // need to fall back to parsing from int due to cached balances being previously // stored as int values instead of Amounts - factory Balance.fromJson(String json, Coin coin) { + factory Balance.fromJson(String json, int deprecatedValue) { final decoded = jsonDecode(json); return Balance( - coin: coin, total: decoded["total"] is String ? Amount.fromSerializedJsonString(decoded["total"] as String) : Amount( rawValue: BigInt.from(decoded["total"] as int), - fractionDigits: coin.decimals, + fractionDigits: deprecatedValue, ), spendable: decoded["spendable"] is String ? Amount.fromSerializedJsonString(decoded["spendable"] as String) : Amount( rawValue: BigInt.from(decoded["spendable"] as int), - fractionDigits: coin.decimals, + fractionDigits: deprecatedValue, ), blockedTotal: decoded["blockedTotal"] is String ? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String) : Amount( rawValue: BigInt.from(decoded["blockedTotal"] as int), - fractionDigits: coin.decimals, + fractionDigits: deprecatedValue, ), pendingSpendable: decoded["pendingSpendable"] is String ? Amount.fromSerializedJsonString( decoded["pendingSpendable"] as String) : Amount( rawValue: BigInt.from(decoded["pendingSpendable"] as int), - fractionDigits: coin.decimals, + fractionDigits: deprecatedValue, ), ); } Map toMap() => { - "coin": coin, "total": total, "spendable": spendable, "blockedTotal": blockedTotal, diff --git a/lib/models/token_balance.dart b/lib/models/token_balance.dart deleted file mode 100644 index f2606f04d..000000000 --- a/lib/models/token_balance.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'dart:convert'; - -import 'package:stackwallet/models/balance.dart'; -import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; - -class TokenBalance extends Balance { - TokenBalance({ - required this.contractAddress, - required super.total, - required super.spendable, - required super.blockedTotal, - required super.pendingSpendable, - super.coin = Coin.ethereum, - }); - - final String contractAddress; - - @override - String toJsonIgnoreCoin() => jsonEncode({ - "contractAddress": contractAddress, - "total": total.toJsonString(), - "spendable": spendable.toJsonString(), - "blockedTotal": blockedTotal.toJsonString(), - "pendingSpendable": pendingSpendable.toJsonString(), - }); - - factory TokenBalance.fromJson( - String json, - int fractionDigits, - ) { - final decoded = jsonDecode(json); - return TokenBalance( - contractAddress: decoded["contractAddress"] as String, - total: decoded["total"] is String - ? Amount.fromSerializedJsonString(decoded["total"] as String) - : Amount( - rawValue: BigInt.from(decoded["total"] as int), - fractionDigits: fractionDigits, - ), - spendable: decoded["spendable"] is String - ? Amount.fromSerializedJsonString(decoded["spendable"] as String) - : Amount( - rawValue: BigInt.from(decoded["spendable"] as int), - fractionDigits: fractionDigits, - ), - blockedTotal: decoded["blockedTotal"] is String - ? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String) - : Amount( - rawValue: BigInt.from(decoded["blockedTotal"] as int), - fractionDigits: fractionDigits, - ), - pendingSpendable: decoded["pendingSpendable"] is String - ? Amount.fromSerializedJsonString( - decoded["pendingSpendable"] as String) - : Amount( - rawValue: BigInt.from(decoded["pendingSpendable"] as int), - fractionDigits: fractionDigits, - ), - ); - } -} diff --git a/lib/pages/exchange_view/choose_from_stack_view.dart b/lib/pages/exchange_view/choose_from_stack_view.dart index 505554a7c..bbfe91880 100644 --- a/lib/pages/exchange_view/choose_from_stack_view.dart +++ b/lib/pages/exchange_view/choose_from_stack_view.dart @@ -8,7 +8,7 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; class ChooseFromStackView extends ConsumerStatefulWidget { diff --git a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart index 3d40d7e9e..21493a31d 100644 --- a/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart +++ b/lib/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart @@ -11,7 +11,7 @@ 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/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; import 'package:tuple/tuple.dart'; diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index cbbbc76c8..c15a5bee3 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1978,7 +1978,6 @@ class EpicCashWallet extends CoinServiceAPI (jsonBalances['amount_awaiting_finalization'] as double).toString(); _balance = Balance( - coin: coin, total: Amount.fromDecimal( Decimal.parse(total) + Decimal.parse(awaiting), fractionDigits: coin.decimals, diff --git a/lib/services/coins/ethereum/ethereum_wallet.dart b/lib/services/coins/ethereum/ethereum_wallet.dart index b5fafeff5..380f4dc04 100644 --- a/lib/services/coins/ethereum/ethereum_wallet.dart +++ b/lib/services/coins/ethereum/ethereum_wallet.dart @@ -10,7 +10,6 @@ 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'; @@ -78,14 +77,13 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { ); } - TokenBalance getCachedTokenBalance(EthContract contract) { + Balance 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, + return Balance( total: Amount( rawValue: BigInt.zero, fractionDigits: contract.decimals, @@ -104,7 +102,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { ), ); } - return TokenBalance.fromJson( + return Balance.fromJson( jsonString, contract.decimals, ); @@ -222,7 +220,6 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { web3.Web3Client client = getEthClient(); web3.EtherAmount ethBalance = await client.getBalance(_credentials.address); _balance = Balance( - coin: coin, total: Amount( rawValue: ethBalance.getInWei, fractionDigits: coin.decimals, diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart index 22cdde933..38d1fb172 100644 --- a/lib/services/coins/firo/firo_wallet.dart +++ b/lib/services/coins/firo/firo_wallet.dart @@ -2515,7 +2515,6 @@ class FiroWallet extends CoinServiceAPI } _balancePrivate = Balance( - coin: coin, total: Amount( rawValue: BigInt.from(intLelantusBalance + unconfirmedLelantusBalance), @@ -3803,7 +3802,6 @@ class FiroWallet extends CoinServiceAPI // finally update public balance _balance = Balance( - coin: coin, total: satoshiBalanceTotal, spendable: satoshiBalanceSpendable, blockedTotal: satoshiBalanceBlocked, diff --git a/lib/services/coins/monero/monero_wallet.dart b/lib/services/coins/monero/monero_wallet.dart index 87b803255..29debe753 100644 --- a/lib/services/coins/monero/monero_wallet.dart +++ b/lib/services/coins/monero/monero_wallet.dart @@ -747,7 +747,6 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB { final total = await _totalBalance; final available = await _availableBalance; _balance = Balance( - coin: coin, total: total, spendable: available, blockedTotal: Amount( diff --git a/lib/services/coins/wownero/wownero_wallet.dart b/lib/services/coins/wownero/wownero_wallet.dart index 84f806be2..4e3591d8c 100644 --- a/lib/services/coins/wownero/wownero_wallet.dart +++ b/lib/services/coins/wownero/wownero_wallet.dart @@ -774,7 +774,6 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB { final total = await _totalBalance; final available = await _availableBalance; _balance = Balance( - coin: coin, total: total, spendable: available, blockedTotal: Amount( diff --git a/lib/services/ethereum/cached_eth_token_balance.dart b/lib/services/ethereum/cached_eth_token_balance.dart index f36cf2ea3..d477d0460 100644 --- a/lib/services/ethereum/cached_eth_token_balance.dart +++ b/lib/services/ethereum/cached_eth_token_balance.dart @@ -1,5 +1,5 @@ +import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; -import 'package:stackwallet/models/token_balance.dart'; import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/mixins/eth_token_cache.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; @@ -21,8 +21,7 @@ class CachedEthTokenBalance with EthTokenCache { if (response.value != null) { await updateCachedBalance( - TokenBalance( - contractAddress: token.address, + Balance( total: response.value!, spendable: response.value!, blockedTotal: Amount( diff --git a/lib/services/ethereum/ethereum_token_service.dart b/lib/services/ethereum/ethereum_token_service.dart index 90edb1904..f56561e8d 100644 --- a/lib/services/ethereum/ethereum_token_service.dart +++ b/lib/services/ethereum/ethereum_token_service.dart @@ -8,10 +8,10 @@ import 'package:isar/isar.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/dto/ethereum/eth_token_tx_dto.dart'; import 'package:stackwallet/dto/ethereum/eth_token_tx_extra_dto.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/ethereum/ethereum_wallet.dart'; import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart'; @@ -60,8 +60,8 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { EthContract get tokenContract => _tokenContract; EthContract _tokenContract; - TokenBalance get balance => _balance ??= getCachedBalance(); - TokenBalance? _balance; + Balance get balance => _balance ??= getCachedBalance(); + Balance? _balance; Coin get coin => Coin.ethereum; @@ -413,8 +413,7 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { String _balance = balanceRequest.first.toString(); - final newBalance = TokenBalance( - contractAddress: tokenContract.address, + final newBalance = Balance( total: Amount.fromDecimal( Decimal.parse(_balance), fractionDigits: tokenContract.decimals, diff --git a/lib/services/mixins/coin_control_interface.dart b/lib/services/mixins/coin_control_interface.dart index e9af99161..d3e6079a0 100644 --- a/lib/services/mixins/coin_control_interface.dart +++ b/lib/services/mixins/coin_control_interface.dart @@ -76,7 +76,6 @@ mixin CoinControlInterface { } final balance = Balance( - coin: _coin, total: satoshiBalanceTotal, spendable: satoshiBalanceSpendable, blockedTotal: satoshiBalanceBlocked, diff --git a/lib/services/mixins/eth_token_cache.dart b/lib/services/mixins/eth_token_cache.dart index ccaa293d0..b1fdf6bb3 100644 --- a/lib/services/mixins/eth_token_cache.dart +++ b/lib/services/mixins/eth_token_cache.dart @@ -1,6 +1,6 @@ import 'package:stackwallet/db/hive/db.dart'; +import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; -import 'package:stackwallet/models/token_balance.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; abstract class TokenCacheKeys { @@ -19,14 +19,13 @@ mixin EthTokenCache { } // token balance cache - TokenBalance getCachedBalance() { + Balance getCachedBalance() { final jsonString = DB.instance.get( boxName: _walletId, key: TokenCacheKeys.tokenBalance(_token.address), ) as String?; if (jsonString == null) { - return TokenBalance( - contractAddress: _token.address, + return Balance( total: Amount( rawValue: BigInt.zero, fractionDigits: _token.decimals, @@ -45,13 +44,13 @@ mixin EthTokenCache { ), ); } - return TokenBalance.fromJson( + return Balance.fromJson( jsonString, _token.decimals, ); } - Future updateCachedBalance(TokenBalance balance) async { + Future updateCachedBalance(Balance balance) async { await DB.instance.put( boxName: _walletId, key: TokenCacheKeys.tokenBalance(_token.address), diff --git a/lib/services/mixins/wallet_cache.dart b/lib/services/mixins/wallet_cache.dart index 49f53381a..435e28717 100644 --- a/lib/services/mixins/wallet_cache.dart +++ b/lib/services/mixins/wallet_cache.dart @@ -70,7 +70,6 @@ mixin WalletCache { ) as String?; if (jsonString == null) { return Balance( - coin: _coin, total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), spendable: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), @@ -80,7 +79,7 @@ mixin WalletCache { Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), ); } - return Balance.fromJson(jsonString, _coin); + return Balance.fromJson(jsonString, _coin.decimals); } Future updateCachedBalance(Balance balance) async { @@ -99,7 +98,6 @@ mixin WalletCache { ) as String?; if (jsonString == null) { return Balance( - coin: _coin, total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), spendable: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), @@ -109,7 +107,7 @@ mixin WalletCache { Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), ); } - return Balance.fromJson(jsonString, _coin); + return Balance.fromJson(jsonString, _coin.decimals); } Future updateCachedBalanceSecondary(Balance balance) async { diff --git a/lib/widgets/eth_wallet_radio.dart b/lib/widgets/eth_wallet_radio.dart index c20a4cbb9..e5a0c2bb5 100644 --- a/lib/widgets/eth_wallet_radio.dart +++ b/lib/widgets/eth_wallet_radio.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; class EthWalletRadio extends ConsumerStatefulWidget { 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.dart similarity index 100% rename from lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart rename to lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart diff --git a/lib/widgets/wallet_info_row/wallet_info_row.dart b/lib/widgets/wallet_info_row/wallet_info_row.dart index 26879aa7e..c31e8e19f 100644 --- a/lib/widgets/wallet_info_row/wallet_info_row.dart +++ b/lib/widgets/wallet_info_row/wallet_info_row.dart @@ -8,7 +8,7 @@ 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/custom_buttons/blue_text_button.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; class WalletInfoRow extends ConsumerWidget { diff --git a/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.dart b/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.dart index 943a02e99..70dfbfdc4 100644 --- a/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.dart +++ b/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.dart @@ -15,7 +15,7 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/theme/light_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'wallet_info_row_balance_future_test.mocks.dart'; diff --git a/test/widget_tests/wallet_info_row/wallet_info_row_test.dart b/test/widget_tests/wallet_info_row/wallet_info_row_test.dart index 4308ac273..a9318e11a 100644 --- a/test/widget_tests/wallet_info_row/wallet_info_row_test.dart +++ b/test/widget_tests/wallet_info_row/wallet_info_row_test.dart @@ -15,7 +15,7 @@ import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/theme/light_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; import 'wallet_info_row_test.mocks.dart'; From 7ee5c196a089ab8fe9d0165e89690975936102c0 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 11:28:36 -0600 Subject: [PATCH 12/21] token theme colors --- .../token_view/sub_widgets/token_summary.dart | 83 +++++++++++----- lib/pages/token_view/token_view.dart | 3 + .../sub_widgets/wallet_refresh_button.dart | 16 +++- lib/utilities/theme/chan_colors.dart | 20 ++++ lib/utilities/theme/color_theme.dart | 16 +++- lib/utilities/theme/dark_colors.dart | 20 ++++ lib/utilities/theme/forest_colors.dart | 20 ++++ lib/utilities/theme/fruit_sorbet_colors.dart | 20 ++++ lib/utilities/theme/light_colors.dart | 20 ++++ lib/utilities/theme/ocean_breeze_colors.dart | 20 ++++ lib/utilities/theme/oled_black_colors.dart | 20 ++++ lib/utilities/theme/oled_chans_colors.dart | 20 ++++ lib/utilities/theme/orange_colors.dart | 20 ++++ lib/utilities/theme/stack_colors.dart | 94 +++++++++++++++++++ 14 files changed, 363 insertions(+), 29 deletions(-) diff --git a/lib/pages/token_view/sub_widgets/token_summary.dart b/lib/pages/token_view/sub_widgets/token_summary.dart index 2d9db8b62..d9c62ae66 100644 --- a/lib/pages/token_view/sub_widgets/token_summary.dart +++ b/lib/pages/token_view/sub_widgets/token_summary.dart @@ -21,6 +21,7 @@ import 'package:stackwallet/utilities/constants.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/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:tuple/tuple.dart'; @@ -44,8 +45,7 @@ class TokenSummary extends ConsumerWidget { return Stack( children: [ RoundedContainer( - color: const Color(0xFFE9EAFF), // todo: fix color - // color: Theme.of(context).extension()!., + color: Theme.of(context).extension()!.tokenSummaryBG, padding: const EdgeInsets.all(24), child: Column( children: [ @@ -54,7 +54,9 @@ class TokenSummary extends ConsumerWidget { children: [ SvgPicture.asset( Assets.svg.walletDesktop, - color: const Color(0xFF8488AB), // todo: fix color + color: Theme.of(context) + .extension()! + .tokenSummaryTextSecondary, width: 12, height: 12, ), @@ -68,7 +70,9 @@ class TokenSummary extends ConsumerWidget { ), ), style: STextStyles.w500_12(context).copyWith( - color: const Color(0xFF8488AB), // todo: fix color + color: Theme.of(context) + .extension()! + .tokenSummaryTextSecondary, ), ), ], @@ -88,7 +92,11 @@ class TokenSummary extends ConsumerWidget { ), )}" " ${token.symbol}", - style: STextStyles.pageTitleH1(context), + style: STextStyles.pageTitleH1(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ), const SizedBox( width: 10, @@ -119,7 +127,11 @@ class TokenSummary extends ConsumerWidget { (value) => value.currency, ), )}", - style: STextStyles.subtitle500(context), + style: STextStyles.subtitle500(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ), const SizedBox( height: 20, @@ -137,8 +149,13 @@ class TokenSummary extends ConsumerWidget { child: WalletRefreshButton( walletId: walletId, initialSyncStatus: initialSyncStatus, - tokenContractAddress: ref.watch(tokenServiceProvider - .select((value) => value!.tokenContract.address)), + tokenContractAddress: ref.watch( + tokenServiceProvider.select( + (value) => value!.tokenContract.address, + ), + ), + overrideIconColor: + Theme.of(context).extension()!.topNavIconPrimary, ), ), ], @@ -197,7 +214,7 @@ class TokenWalletOptions extends StatelessWidget { ); }, subLabel: "Receive", - iconAssetSVG: Assets.svg.receive(context), + iconAssetSVG: Assets.svg.arrowDownLeft, ), const SizedBox( width: 16, @@ -214,7 +231,7 @@ class TokenWalletOptions extends StatelessWidget { ); }, subLabel: "Send", - iconAssetSVG: Assets.svg.send(context), + iconAssetSVG: Assets.svg.arrowUpRight, ), const SizedBox( width: 16, @@ -251,12 +268,14 @@ class TokenOptionsButton extends StatelessWidget { @override Widget build(BuildContext context) { + final iconSize = subLabel == "Send" || subLabel == "Receive" ? 12.0 : 24.0; return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ RawMaterialButton( - fillColor: Theme.of(context).extension()!.popupBG, + fillColor: + Theme.of(context).extension()!.tokenSummaryButtonBG, elevation: 0, focusElevation: 0, hoverElevation: 0, @@ -270,11 +289,27 @@ class TokenOptionsButton extends StatelessWidget { onPressed: onPressed, child: Padding( padding: const EdgeInsets.all(10), - child: SvgPicture.asset( - iconAssetSVG, - color: const Color(0xFF424A97), // todo: fix color - width: 24, - height: 24, + child: ConditionalParent( + condition: iconSize < 24, + builder: (child) => RoundedContainer( + padding: const EdgeInsets.all(6), + color: Theme.of(context) + .extension()! + .tokenSummaryIcon + .withOpacity(0.4), + radiusMultiplier: 10, + child: Center( + child: child, + ), + ), + child: SvgPicture.asset( + iconAssetSVG, + color: Theme.of(context) + .extension()! + .tokenSummaryIcon, + width: iconSize, + height: iconSize, + ), ), ), ), @@ -283,7 +318,11 @@ class TokenOptionsButton extends StatelessWidget { ), Text( subLabel, - style: STextStyles.w500_12(context), + style: STextStyles.w500_12(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ) ], ); @@ -303,12 +342,14 @@ class CoinTickerTag extends ConsumerWidget { return RoundedContainer( padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 4), radiusMultiplier: 0.25, - color: const Color(0xFF4D5798), // TODO: color theme for multi themes + color: Theme.of(context).extension()!.ethTagBG, child: Text( - ref.watch(walletsChangeNotifierProvider - .select((value) => value.getManager(walletId).coin.ticker)), + ref.watch( + walletsChangeNotifierProvider + .select((value) => value.getManager(walletId).coin.ticker), + ), style: STextStyles.w600_12(context).copyWith( - color: Colors.white, // TODO: design is wrong? + color: Theme.of(context).extension()!.ethTagText, ), ), ); diff --git a/lib/pages/token_view/token_view.dart b/lib/pages/token_view/token_view.dart index 851119f06..0faae0bce 100644 --- a/lib/pages/token_view/token_view.dart +++ b/lib/pages/token_view/token_view.dart @@ -110,6 +110,9 @@ class _TokenViewState extends ConsumerState { child: AppBarIconButton( icon: SvgPicture.asset( Assets.svg.verticalEllipsis, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, ), onPressed: () { // todo: context menu diff --git a/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart b/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart index 453762b80..ac82fc98c 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart @@ -22,6 +22,7 @@ class WalletRefreshButton extends ConsumerStatefulWidget { this.tokenContractAddress, this.onPressed, this.eventBus, + this.overrideIconColor, }) : super(key: key); final String walletId; @@ -29,6 +30,7 @@ class WalletRefreshButton extends ConsumerStatefulWidget { final String? tokenContractAddress; final VoidCallback? onPressed; final EventBus? eventBus; + final Color? overrideIconColor; @override ConsumerState createState() => _RefreshButtonState(); @@ -155,11 +157,15 @@ class _RefreshButtonState extends ConsumerState Assets.svg.arrowRotate, width: isDesktop ? 12 : 24, height: isDesktop ? 12 : 24, - color: isDesktop - ? Theme.of(context) - .extension()! - .textFieldDefaultSearchIconRight - : Theme.of(context).extension()!.textFavoriteCard, + color: widget.overrideIconColor != null + ? widget.overrideIconColor! + : isDesktop + ? Theme.of(context) + .extension()! + .textFieldDefaultSearchIconRight + : Theme.of(context) + .extension()! + .textFavoriteCard, ), ), ), diff --git a/lib/utilities/theme/chan_colors.dart b/lib/utilities/theme/chan_colors.dart index f9ea1bb54..cce17b7bb 100644 --- a/lib/utilities/theme/chan_colors.dart +++ b/lib/utilities/theme/chan_colors.dart @@ -335,6 +335,26 @@ class ChanColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFF0F3FD); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF8488AB); + @override + Color get tokenSummaryBG => const Color(0xFFE9EAFF); + @override + Color get tokenSummaryButtonBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryIcon => const Color(0xFF424A97); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/color_theme.dart b/lib/utilities/theme/color_theme.dart index eaa3d702b..879c7be71 100644 --- a/lib/utilities/theme/color_theme.dart +++ b/lib/utilities/theme/color_theme.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/theme/chan_colors.dart'; import 'package:stackwallet/utilities/theme/dark_colors.dart'; import 'package:stackwallet/utilities/theme/forest_colors.dart'; import 'package:stackwallet/utilities/theme/fruit_sorbet_colors.dart'; @@ -7,9 +8,7 @@ import 'package:stackwallet/utilities/theme/light_colors.dart'; import 'package:stackwallet/utilities/theme/ocean_breeze_colors.dart'; import 'package:stackwallet/utilities/theme/oled_black_colors.dart'; import 'package:stackwallet/utilities/theme/oled_chans_colors.dart'; - -import 'chan_colors.dart'; -import 'orange_colors.dart'; +import 'package:stackwallet/utilities/theme/orange_colors.dart'; enum ThemeType { light, @@ -285,6 +284,17 @@ abstract class StackColorTheme { Color get rateTypeToggleDesktopColorOn; Color get rateTypeToggleDesktopColorOff; + // token view colors + Color get ethTagText; + Color get ethTagBG; + Color get ethWalletTagText; + Color get ethWalletTagBG; + Color get tokenSummaryTextPrimary; + Color get tokenSummaryTextSecondary; + Color get tokenSummaryBG; + Color get tokenSummaryButtonBG; + Color get tokenSummaryIcon; + BoxShadow get standardBoxShadow; BoxShadow? get homeViewButtonBarBoxShadow; } diff --git a/lib/utilities/theme/dark_colors.dart b/lib/utilities/theme/dark_colors.dart index fbbf113ef..549bb677c 100644 --- a/lib/utilities/theme/dark_colors.dart +++ b/lib/utilities/theme/dark_colors.dart @@ -335,6 +335,26 @@ class DarkColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF5761A2); + @override + Color get ethWalletTagText => const Color(0xFFE7EBFF); + @override + Color get ethWalletTagBG => const Color(0xFF414868); + @override + Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryBG => const Color(0xFF464C73); + @override + Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryIcon => const Color(0xFF252C78); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/forest_colors.dart b/lib/utilities/theme/forest_colors.dart index 8d66befda..0fd4b1774 100644 --- a/lib/utilities/theme/forest_colors.dart +++ b/lib/utilities/theme/forest_colors.dart @@ -335,6 +335,26 @@ class ForestColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFEBEFFE); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF4D5798); + @override + Color get tokenSummaryBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryButtonBG => const Color(0xFFE9FBEF); + @override + Color get tokenSummaryIcon => const Color(0xFF22867A); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/fruit_sorbet_colors.dart b/lib/utilities/theme/fruit_sorbet_colors.dart index a13985a93..86358aa6f 100644 --- a/lib/utilities/theme/fruit_sorbet_colors.dart +++ b/lib/utilities/theme/fruit_sorbet_colors.dart @@ -335,6 +335,26 @@ class FruitSorbetColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => popupBG; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFEBEFFE); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF4D5798); + @override + Color get tokenSummaryBG => const Color(0xFFFFF8EE); + @override + Color get tokenSummaryButtonBG => const Color(0xFFFEDED4); + @override + Color get tokenSummaryIcon => const Color(0xFFF62A45); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/light_colors.dart b/lib/utilities/theme/light_colors.dart index b42f2dd9a..8fa83da95 100644 --- a/lib/utilities/theme/light_colors.dart +++ b/lib/utilities/theme/light_colors.dart @@ -335,6 +335,26 @@ class LightColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFF0F3FD); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF8488AB); + @override + Color get tokenSummaryBG => const Color(0xFFE9EAFF); + @override + Color get tokenSummaryButtonBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryIcon => const Color(0xFF424A97); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/ocean_breeze_colors.dart b/lib/utilities/theme/ocean_breeze_colors.dart index 1b528d6a1..dc2e7268b 100644 --- a/lib/utilities/theme/ocean_breeze_colors.dart +++ b/lib/utilities/theme/ocean_breeze_colors.dart @@ -342,6 +342,26 @@ class OceanBreezeColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFEBEFFE); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF4D5798); + @override + Color get tokenSummaryBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryButtonBG => const Color(0xFFEDF4F9); + @override + Color get tokenSummaryIcon => const Color(0xFF197287); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/oled_black_colors.dart b/lib/utilities/theme/oled_black_colors.dart index 4f273eeff..40bf3ee8f 100644 --- a/lib/utilities/theme/oled_black_colors.dart +++ b/lib/utilities/theme/oled_black_colors.dart @@ -338,6 +338,26 @@ class OledBlackColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF5761A2); + @override + Color get ethWalletTagText => const Color(0xFFDEDEDE); + @override + Color get ethWalletTagBG => const Color(0xFF222539); + @override + Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryBG => const Color(0xFF292D45); + @override + Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryIcon => const Color(0xFF252C78); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/oled_chans_colors.dart b/lib/utilities/theme/oled_chans_colors.dart index 83600d5d5..22179dd08 100644 --- a/lib/utilities/theme/oled_chans_colors.dart +++ b/lib/utilities/theme/oled_chans_colors.dart @@ -335,6 +335,26 @@ class DarkChansColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF5761A2); + @override + Color get ethWalletTagText => const Color(0xFFDEDEDE); + @override + Color get ethWalletTagBG => const Color(0xFF222539); + @override + Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryBG => const Color(0xFF292D45); + @override + Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF); + @override + Color get tokenSummaryIcon => const Color(0xFF252C78); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/orange_colors.dart b/lib/utilities/theme/orange_colors.dart index eeac65b89..fb4c7a937 100644 --- a/lib/utilities/theme/orange_colors.dart +++ b/lib/utilities/theme/orange_colors.dart @@ -335,6 +335,26 @@ class OrangeColors extends StackColorTheme { @override Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; + // token view colors + @override + Color get ethTagText => const Color(0xFFFFFFFF); + @override + Color get ethTagBG => const Color(0xFF4D5798); + @override + Color get ethWalletTagText => const Color(0xFF4D5798); + @override + Color get ethWalletTagBG => const Color(0xFFEBEFFE); + @override + Color get tokenSummaryTextPrimary => const Color(0xFF232323); + @override + Color get tokenSummaryTextSecondary => const Color(0xFF4D5798); + @override + Color get tokenSummaryBG => const Color(0xFFFFFFFF); + @override + Color get tokenSummaryButtonBG => const Color(0xAAFFC58F); + @override + Color get tokenSummaryIcon => const Color(0xFFF36B43); + @override BoxShadow get standardBoxShadow => BoxShadow( color: shadow, diff --git a/lib/utilities/theme/stack_colors.dart b/lib/utilities/theme/stack_colors.dart index cbba0bb36..f9a1f39c1 100644 --- a/lib/utilities/theme/stack_colors.dart +++ b/lib/utilities/theme/stack_colors.dart @@ -187,6 +187,17 @@ class StackColors extends ThemeExtension { final Color rateTypeToggleDesktopColorOn; final Color rateTypeToggleDesktopColorOff; + // token view colors + final Color ethTagText; + final Color ethTagBG; + final Color ethWalletTagText; + final Color ethWalletTagBG; + final Color tokenSummaryTextPrimary; + final Color tokenSummaryTextSecondary; + final Color tokenSummaryBG; + final Color tokenSummaryButtonBG; + final Color tokenSummaryIcon; + final BoxShadow standardBoxShadow; final BoxShadow? homeViewButtonBarBoxShadow; @@ -337,6 +348,15 @@ class StackColors extends ThemeExtension { required this.rateTypeToggleDesktopColorOff, required this.standardBoxShadow, required this.homeViewButtonBarBoxShadow, + required this.ethTagText, + required this.ethTagBG, + required this.ethWalletTagText, + required this.ethWalletTagBG, + required this.tokenSummaryTextPrimary, + required this.tokenSummaryTextSecondary, + required this.tokenSummaryBG, + required this.tokenSummaryButtonBG, + required this.tokenSummaryIcon, }); factory StackColors.fromStackColorTheme(StackColorTheme colorTheme) { @@ -490,6 +510,15 @@ class StackColors extends ThemeExtension { rateTypeToggleDesktopColorOff: colorTheme.rateTypeToggleDesktopColorOff, homeViewButtonBarBoxShadow: colorTheme.homeViewButtonBarBoxShadow, standardBoxShadow: colorTheme.standardBoxShadow, + ethTagText: colorTheme.ethTagText, + ethTagBG: colorTheme.ethTagBG, + ethWalletTagText: colorTheme.ethWalletTagText, + ethWalletTagBG: colorTheme.ethWalletTagBG, + tokenSummaryTextPrimary: colorTheme.tokenSummaryTextPrimary, + tokenSummaryTextSecondary: colorTheme.tokenSummaryTextSecondary, + tokenSummaryBG: colorTheme.tokenSummaryBG, + tokenSummaryButtonBG: colorTheme.tokenSummaryButtonBG, + tokenSummaryIcon: colorTheme.tokenSummaryIcon, ); } @@ -639,6 +668,15 @@ class StackColors extends ThemeExtension { Color? rateTypeToggleColorOff, Color? rateTypeToggleDesktopColorOn, Color? rateTypeToggleDesktopColorOff, + Color? ethTagText, + Color? ethTagBG, + Color? ethWalletTagText, + Color? ethWalletTagBG, + Color? tokenSummaryTextPrimary, + Color? tokenSummaryTextSecondary, + Color? tokenSummaryBG, + Color? tokenSummaryButtonBG, + Color? tokenSummaryIcon, BoxShadow? homeViewButtonBarBoxShadow, BoxShadow? standardBoxShadow, }) { @@ -833,6 +871,17 @@ class StackColors extends ThemeExtension { rateTypeToggleDesktopColorOn ?? this.rateTypeToggleDesktopColorOn, rateTypeToggleDesktopColorOff: rateTypeToggleDesktopColorOff ?? this.rateTypeToggleDesktopColorOff, + ethTagText: ethTagText ?? this.ethTagText, + ethTagBG: ethTagBG ?? this.ethTagBG, + ethWalletTagText: ethWalletTagText ?? this.ethWalletTagText, + ethWalletTagBG: ethWalletTagBG ?? this.ethWalletTagBG, + tokenSummaryTextPrimary: + tokenSummaryTextPrimary ?? this.tokenSummaryTextPrimary, + tokenSummaryTextSecondary: + tokenSummaryTextSecondary ?? this.tokenSummaryTextSecondary, + tokenSummaryBG: tokenSummaryBG ?? this.tokenSummaryBG, + tokenSummaryButtonBG: tokenSummaryButtonBG ?? this.tokenSummaryButtonBG, + tokenSummaryIcon: tokenSummaryIcon ?? this.tokenSummaryIcon, homeViewButtonBarBoxShadow: homeViewButtonBarBoxShadow ?? this.homeViewButtonBarBoxShadow, standardBoxShadow: standardBoxShadow ?? this.standardBoxShadow, @@ -1557,6 +1606,51 @@ class StackColors extends ThemeExtension { other.rateTypeToggleDesktopColorOff, t, )!, + ethTagText: Color.lerp( + ethTagText, + other.ethTagText, + t, + )!, + ethTagBG: Color.lerp( + ethTagBG, + other.ethTagBG, + t, + )!, + ethWalletTagText: Color.lerp( + ethWalletTagText, + other.ethWalletTagText, + t, + )!, + ethWalletTagBG: Color.lerp( + ethWalletTagBG, + other.ethWalletTagBG, + t, + )!, + tokenSummaryTextPrimary: Color.lerp( + tokenSummaryTextPrimary, + other.tokenSummaryTextPrimary, + t, + )!, + tokenSummaryTextSecondary: Color.lerp( + tokenSummaryTextSecondary, + other.tokenSummaryTextSecondary, + t, + )!, + tokenSummaryBG: Color.lerp( + tokenSummaryBG, + other.tokenSummaryBG, + t, + )!, + tokenSummaryButtonBG: Color.lerp( + tokenSummaryButtonBG, + other.tokenSummaryButtonBG, + t, + )!, + tokenSummaryIcon: Color.lerp( + tokenSummaryIcon, + other.tokenSummaryIcon, + t, + )!, ); } From 004c39102ce84d5b6f3a4947a1a0df2607a02b36 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 11:55:02 -0600 Subject: [PATCH 13/21] token balance fix --- .../ethereum/ethereum_token_service.dart | 55 +++++++++---------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/lib/services/ethereum/ethereum_token_service.dart b/lib/services/ethereum/ethereum_token_service.dart index f56561e8d..13e52b72e 100644 --- a/lib/services/ethereum/ethereum_token_service.dart +++ b/lib/services/ethereum/ethereum_token_service.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:decimal/decimal.dart'; import 'package:ethereum_addresses/ethereum_addresses.dart'; import 'package:flutter/widgets.dart'; import 'package:http/http.dart'; @@ -40,7 +39,6 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { // late web3dart.EthereumAddress _contractAddress; late web3dart.EthPrivateKey _credentials; late web3dart.DeployedContract _deployedContract; - late web3dart.ContractFunction _balanceFunction; late web3dart.ContractFunction _sendFunction; late web3dart.Web3Client _client; @@ -284,7 +282,6 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { ); try { - _balanceFunction = _deployedContract.function('balanceOf'); _sendFunction = _deployedContract.function('transfer'); } catch (_) { //==================================================================== @@ -359,7 +356,6 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { contractAddress, ); - _balanceFunction = _deployedContract.function('balanceOf'); _sendFunction = _deployedContract.function('transfer'); _client = await getEthClient(); @@ -405,34 +401,33 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { } Future refreshCachedBalance() async { - final balanceRequest = await _client.call( - contract: _deployedContract, - function: _balanceFunction, - params: [_credentials.address], + final response = await EthereumAPI.getWalletTokenBalance( + address: _credentials.address.hex, + contractAddress: tokenContract.address, ); - String _balance = balanceRequest.first.toString(); - - final newBalance = Balance( - total: Amount.fromDecimal( - Decimal.parse(_balance), - fractionDigits: tokenContract.decimals, - ), - spendable: Amount.fromDecimal( - Decimal.parse(_balance), - fractionDigits: tokenContract.decimals, - ), - blockedTotal: Amount( - rawValue: BigInt.zero, - fractionDigits: tokenContract.decimals, - ), - pendingSpendable: Amount( - rawValue: BigInt.zero, - fractionDigits: tokenContract.decimals, - ), - ); - await updateCachedBalance(newBalance); - notifyListeners(); + if (response.value != null) { + await updateCachedBalance( + Balance( + total: response.value!, + spendable: response.value!, + blockedTotal: Amount( + rawValue: BigInt.zero, + fractionDigits: tokenContract.decimals, + ), + pendingSpendable: Amount( + rawValue: BigInt.zero, + fractionDigits: tokenContract.decimals, + ), + ), + ); + notifyListeners(); + } else { + Logging.instance.log( + "CachedEthTokenBalance.fetchAndUpdateCachedBalance failed: ${response.exception}", + level: LogLevel.Warning, + ); + } } Future> get transactions => ethWallet.db From 0ea4517952a74d8c47eaa2420fe9c60737b34926 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 11:58:19 -0600 Subject: [PATCH 14/21] quicker token wallet loading --- lib/services/ethereum/ethereum_token_service.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/services/ethereum/ethereum_token_service.dart b/lib/services/ethereum/ethereum_token_service.dart index 13e52b72e..1f930cf4c 100644 --- a/lib/services/ethereum/ethereum_token_service.dart +++ b/lib/services/ethereum/ethereum_token_service.dart @@ -257,12 +257,12 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache { final contractAddress = web3dart.EthereumAddress.fromHex(tokenContract.address); - // if (tokenContract.abi == null) { - _tokenContract = await _updateTokenABI( - forContract: tokenContract, - usingContractAddress: contractAddress.hex, - ); - // } + if (tokenContract.abi == null) { + _tokenContract = await _updateTokenABI( + forContract: tokenContract, + usingContractAddress: contractAddress.hex, + ); + } String? mnemonicString = await ethWallet.mnemonicString; From bc90723c8601d7f295ce290ce010ea7840571c53 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 13:30:19 -0600 Subject: [PATCH 15/21] single coin list for swap currency selection --- .../exchange_currency_selection_view.dart | 316 +++++++----------- 1 file changed, 124 insertions(+), 192 deletions(-) diff --git a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart index 1b2376b4c..c0d027ff4 100644 --- a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart +++ b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart @@ -111,26 +111,28 @@ class _ExchangeCurrencySelectionViewState return currencies; } - await showDialog( - context: context, - builder: (context) => StackDialog( - title: "ChangeNOW Error", - message: "Failed to load currency data: ${cn.exception}", - leftButton: SecondaryButton( - label: "Ok", - onPressed: Navigator.of(context, rootNavigator: isDesktop).pop, + if (mounted) { + await showDialog( + context: context, + builder: (context) => StackDialog( + title: "ChangeNOW Error", + message: "Failed to load currency data: ${cn.exception}", + leftButton: SecondaryButton( + label: "Ok", + onPressed: Navigator.of(context, rootNavigator: isDesktop).pop, + ), + rightButton: PrimaryButton( + label: "Retry", + onPressed: () async { + Navigator.of(context, rootNavigator: isDesktop).pop(); + _currencies = await _showUpdatingCurrencies( + whileFuture: _loadCurrencies()); + setState(() {}); + }, + ), ), - rightButton: PrimaryButton( - label: "Retry", - onPressed: () async { - Navigator.of(context, rootNavigator: isDesktop).pop(); - _currencies = - await _showUpdatingCurrencies(whileFuture: _loadCurrencies()); - setState(() {}); - }, - ), - ), - ); + ); + } } else { currencies.addAll(cn.value!); } @@ -180,13 +182,13 @@ class _ExchangeCurrencySelectionViewState .where((e) => e.name.toLowerCase().contains(text.toLowerCase()) || e.ticker.toLowerCase().contains(text.toLowerCase())) - .toList(growable: false); + .toList(); } else { if (text.isEmpty) { return _currencies .where((e) => e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase()) - .toList(growable: false); + .toList(); } return _currencies @@ -194,7 +196,7 @@ class _ExchangeCurrencySelectionViewState e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase() && (e.name.toLowerCase().contains(text.toLowerCase()) || e.ticker.toLowerCase().contains(text.toLowerCase()))) - .toList(growable: false); + .toList(); } } @@ -328,181 +330,111 @@ class _ExchangeCurrencySelectionViewState height: 12, ), Flexible( - child: Builder(builder: (context) { - final coins = Coin.values.where((e) => - e.ticker.toLowerCase() != widget.pairedTicker?.toLowerCase()); + child: Builder( + builder: (context) { + final coins = Coin.values.where((e) => + e.ticker.toLowerCase() != + widget.pairedTicker?.toLowerCase()); - final items = filter(_searchString) - .where((e) => coins - .where((coin) => - coin.ticker.toLowerCase() == e.ticker.toLowerCase()) - .isNotEmpty) - .toList(growable: false); - items.sort((a, b) => a.name.compareTo(b.name)); + final items = filter(_searchString); - return RoundedWhiteContainer( - padding: const EdgeInsets.all(0), - child: ListView.builder( - shrinkWrap: true, - primary: isDesktop ? false : null, - itemCount: items.length, - itemBuilder: (builderContext, index) { - final bool hasImageUrl = - items[index].image.startsWith("http"); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: GestureDetector( - onTap: () { - Navigator.of(context).pop(items[index]); - }, - child: RoundedWhiteContainer( - child: Row( - children: [ - SizedBox( - width: 24, - height: 24, - child: isStackCoin(items[index].ticker) - ? getIconForTicker( - items[index].ticker, - size: 24, - ) - : hasImageUrl - ? SvgPicture.network( - items[index].image, - width: 24, - height: 24, - placeholderBuilder: (_) => - const LoadingIndicator(), - ) - : const SizedBox( - width: 24, - height: 24, - ), - ), - const SizedBox( - width: 10, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - items[index].name, - style: STextStyles.largeMedium14(context), - ), - const SizedBox( - height: 2, - ), - Text( - items[index].ticker.toUpperCase(), - style: STextStyles.smallMed12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ), - ], + final walletCoins = items + .where((currency) => coins + .where((coin) => + coin.ticker.toLowerCase() == + currency.ticker.toLowerCase()) + .isNotEmpty) + .toList(); + + // sort alphabetically by name + items.sort((a, b) => a.name.compareTo(b.name)); + + // reverse sort walletCoins to prepare for next step + walletCoins.sort((a, b) => b.name.compareTo(a.name)); + + // insert wallet coins at beginning + for (final c in walletCoins) { + items.remove(c); + items.insert(0, c); + } + + return RoundedWhiteContainer( + padding: const EdgeInsets.all(0), + child: ListView.builder( + shrinkWrap: true, + primary: isDesktop ? false : null, + itemCount: items.length, + itemBuilder: (builderContext, index) { + final bool hasImageUrl = + items[index].image.startsWith("http"); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: GestureDetector( + onTap: () { + Navigator.of(context).pop(items[index]); + }, + child: RoundedWhiteContainer( + child: Row( + children: [ + SizedBox( + width: 24, + height: 24, + child: isStackCoin(items[index].ticker) + ? getIconForTicker( + items[index].ticker, + size: 24, + ) + : hasImageUrl + ? SvgPicture.network( + items[index].image, + width: 24, + height: 24, + placeholderBuilder: (_) => + const LoadingIndicator(), + ) + : const SizedBox( + width: 24, + height: 24, + ), ), - ), - ], + const SizedBox( + width: 10, + ), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + items[index].name, + style: + STextStyles.largeMedium14(context), + ), + const SizedBox( + height: 2, + ), + Text( + items[index].ticker.toUpperCase(), + style: STextStyles.smallMed12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ], + ), + ), + ], + ), ), ), - ), - ); - }, - ), - ); - }), - ), - const SizedBox( - height: 20, - ), - Text( - "All coins", - style: STextStyles.smallMed12(context), - ), - const SizedBox( - height: 12, - ), - Flexible( - child: Builder(builder: (context) { - final filtered = filter(_searchString); - filtered.sort((a, b) => a.name.compareTo(b.name)); - return RoundedWhiteContainer( - padding: const EdgeInsets.all(0), - child: ListView.builder( - shrinkWrap: true, - primary: isDesktop ? false : null, - itemCount: filtered.length, - itemBuilder: (builderContext, index) { - final bool hasImageUrl = - filtered[index].image.startsWith("http"); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: GestureDetector( - onTap: () { - Navigator.of(context).pop(filtered[index]); - }, - child: RoundedWhiteContainer( - child: Row( - children: [ - SizedBox( - width: 24, - height: 24, - child: isStackCoin(filtered[index].ticker) - ? getIconForTicker( - filtered[index].ticker, - size: 24, - ) - : hasImageUrl - ? SvgPicture.network( - filtered[index].image, - width: 24, - height: 24, - placeholderBuilder: (_) => - const LoadingIndicator(), - ) - : const SizedBox( - width: 24, - height: 24, - ), - ), - const SizedBox( - width: 10, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - filtered[index].name, - style: STextStyles.largeMedium14(context), - ), - const SizedBox( - height: 2, - ), - Text( - filtered[index].ticker.toUpperCase(), - style: STextStyles.smallMed12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ), - ], - ), - ), - ], - ), - ), - ), - ); - }, - ), - ); - }), + ); + }, + ), + ); + }, + ), ), ], ), From 051eb6c9244b355a93be839482cd746ae1e94a76 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 14:14:03 -0600 Subject: [PATCH 16/21] change now token contract "fix" --- lib/pages/exchange_view/exchange_form.dart | 3 +++ lib/services/exchange/exchange_data_loading_service.dart | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/pages/exchange_view/exchange_form.dart b/lib/pages/exchange_view/exchange_form.dart index 76bba50ad..3d4dcfcde 100644 --- a/lib/pages/exchange_view/exchange_form.dart +++ b/lib/pages/exchange_view/exchange_form.dart @@ -149,6 +149,8 @@ class _ExchangeFormState extends ConsumerState { currency.ticker, caseSensitive: false, ) + .and() + .tokenContractEqualTo(currency.tokenContract) .findAll(); final items = [Tuple2(currency.exchangeName, currency)]; @@ -631,6 +633,7 @@ class _ExchangeFormState extends ConsumerState { .getAggregateCurrency( widget.contract == null ? coin!.ticker : widget.contract!.symbol, ExchangeRateType.estimated, + widget.contract == null ? null : widget.contract!.address, ) .then((value) { if (value != null) { diff --git a/lib/services/exchange/exchange_data_loading_service.dart b/lib/services/exchange/exchange_data_loading_service.dart index 8e73e46a9..4eed07504 100644 --- a/lib/services/exchange/exchange_data_loading_service.dart +++ b/lib/services/exchange/exchange_data_loading_service.dart @@ -61,10 +61,12 @@ class ExchangeDataLoadingService { final sendCurrency = await getAggregateCurrency( "BTC", state.exchangeRateType, + null, ); final receiveCurrency = await getAggregateCurrency( "XMR", state.exchangeRateType, + null, ); state.setCurrencies(sendCurrency, receiveCurrency); } @@ -72,7 +74,10 @@ class ExchangeDataLoadingService { } Future getAggregateCurrency( - String ticker, ExchangeRateType rateType) async { + String ticker, + ExchangeRateType rateType, + String? contract, + ) async { final currencies = await ExchangeDataLoadingService.instance.isar.currencies .filter() .group((q) => rateType == ExchangeRateType.fixed @@ -89,6 +94,8 @@ class ExchangeDataLoadingService { ticker, caseSensitive: false, ) + .and() + .tokenContractEqualTo(contract) .findAll(); final items = currencies From 77b1e231445574c23c9a4a09fc962686c26e0041 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 10 Apr 2023 15:21:33 -0500 Subject: [PATCH 17/21] assume mints listed in lelantus txs are confirmed TODO make sure that mints/_mintTxnData only contains confirmed tx / filter unconfirmed --- lib/services/coins/firo/firo_wallet.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart index 22cdde933..113c2e7f5 100644 --- a/lib/services/coins/firo/firo_wallet.dart +++ b/lib/services/coins/firo/firo_wallet.dart @@ -900,6 +900,10 @@ class FiroWallet extends CoinServiceAPI .findAll(); // _transactionData ??= _refreshTransactions(); + // Query for lelantus txs / mints + Future> get _mintsTxnData => + db.getTransactions(walletId).filter().isLelantusEqualTo(true).findAll(); + // models.TransactionData? cachedTxData; // hack to add tx to txData before refresh completes @@ -2385,6 +2389,7 @@ class FiroWallet extends CoinServiceAPI } final jindexes = firoGetJIndex(); final transactions = await _txnData; + final mints = await _mintsTxnData; final lelantusTransactionsd = await db .getTransactions(walletId) .filter() @@ -2413,7 +2418,9 @@ class FiroWallet extends CoinServiceAPI if (!jindexes!.contains(lelantusCoinsList[i].index) && transactions .where((e) => e.txid == lelantusCoinsList[i].txId) - .isEmpty) { + .isEmpty && + mints.where((e) => e.txid == lelantusCoinsList[i].txId).isEmpty) { + // TODO make sure that mints is filtered to remove unconfirmed tx isUnconfirmed = true; } From 1268278adf6ce0a4ce0bf641aff8b725acf6eeeb Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 10 Apr 2023 14:23:52 -0600 Subject: [PATCH 18/21] show contract symbol on mobile token receive page --- lib/pages/receive_view/receive_view.dart | 13 ++++++++----- .../token_view/sub_widgets/token_summary.dart | 2 +- lib/pages/wallet_view/wallet_view.dart | 5 +---- lib/route_generator.dart | 14 ++++++++++++-- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/lib/pages/receive_view/receive_view.dart b/lib/pages/receive_view/receive_view.dart index 94cec7c14..87587aa46 100644 --- a/lib/pages/receive_view/receive_view.dart +++ b/lib/pages/receive_view/receive_view.dart @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:qr_flutter/qr_flutter.dart'; +import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/receive_view/addresses/wallet_addresses_view.dart'; import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_view.dart'; @@ -25,15 +26,15 @@ import 'package:stackwallet/widgets/rounded_white_container.dart'; class ReceiveView extends ConsumerStatefulWidget { const ReceiveView({ Key? key, - required this.coin, required this.walletId, + this.tokenContract, this.clipboard = const ClipboardWrapper(), }) : super(key: key); static const String routeName = "/receiveView"; - final Coin coin; final String walletId; + final EthContract? tokenContract; final ClipboardInterface clipboard; @override @@ -86,7 +87,7 @@ class _ReceiveViewState extends ConsumerState { @override void initState() { walletId = widget.walletId; - coin = widget.coin; + coin = ref.read(walletsChangeNotifierProvider).getManager(walletId).coin; clipboard = widget.clipboard; WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { @@ -117,6 +118,8 @@ class _ReceiveViewState extends ConsumerState { } }); + final ticker = widget.tokenContract?.symbol ?? coin.ticker; + return Background( child: Scaffold( backgroundColor: Theme.of(context).extension()!.background, @@ -127,7 +130,7 @@ class _ReceiveViewState extends ConsumerState { }, ), title: Text( - "Receive ${coin.ticker}", + "Receive $ticker", style: STextStyles.navBarTitle(context), ), actions: [ @@ -245,7 +248,7 @@ class _ReceiveViewState extends ConsumerState { Row( children: [ Text( - "Your ${coin.ticker} address", + "Your $ticker address", style: STextStyles.itemSubtitle(context), ), const Spacer(), diff --git a/lib/pages/token_view/sub_widgets/token_summary.dart b/lib/pages/token_view/sub_widgets/token_summary.dart index d9c62ae66..30b60a885 100644 --- a/lib/pages/token_view/sub_widgets/token_summary.dart +++ b/lib/pages/token_view/sub_widgets/token_summary.dart @@ -209,7 +209,7 @@ class TokenWalletOptions extends StatelessWidget { ReceiveView.routeName, arguments: Tuple2( walletId, - Coin.ethereum, + tokenContract, ), ); }, diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 82adc3b6a..941acd719 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -800,10 +800,7 @@ class _WalletViewState extends ConsumerState { unawaited( Navigator.of(context).pushNamed( ReceiveView.routeName, - arguments: Tuple2( - walletId, - coin, - ), + arguments: walletId, ), ); } diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 4031e425e..340b7803d 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -1019,12 +1019,22 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case ReceiveView.routeName: - if (args is Tuple2) { + if (args is String) { + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => ReceiveView( + walletId: args, + ), + settings: RouteSettings( + name: settings.name, + ), + ); + } else if (args is Tuple2) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => ReceiveView( walletId: args.item1, - coin: args.item2, + tokenContract: args.item2, ), settings: RouteSettings( name: settings.name, From d3db4e686855bff3e4a078f00619ae34b7a03eb0 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 10 Apr 2023 15:35:25 -0500 Subject: [PATCH 19/21] instead of assuming mint = confirmed, move logic down so isUnconfirmed has an exception --- lib/services/coins/firo/firo_wallet.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart index 113c2e7f5..c2c712bb1 100644 --- a/lib/services/coins/firo/firo_wallet.dart +++ b/lib/services/coins/firo/firo_wallet.dart @@ -2418,9 +2418,7 @@ class FiroWallet extends CoinServiceAPI if (!jindexes!.contains(lelantusCoinsList[i].index) && transactions .where((e) => e.txid == lelantusCoinsList[i].txId) - .isEmpty && - mints.where((e) => e.txid == lelantusCoinsList[i].txId).isEmpty) { - // TODO make sure that mints is filtered to remove unconfirmed tx + .isEmpty) { isUnconfirmed = true; } @@ -2443,7 +2441,11 @@ class FiroWallet extends CoinServiceAPI } if (!lelantusCoinsList[i].isUsed && lelantusCoinsList[i].anonymitySetId != ANONYMITY_SET_EMPTY_ID && - !isUnconfirmed) { + (!isUnconfirmed || + mints + .where((e) => e.txid == lelantusCoinsList[i].txId) + .isNotEmpty)) { + // TODO make sure that mints is filtered to remove unconfirmed tx coins.add(lelantusCoinsList[i]); } } From 80ca2f2d2c35d43e32100cc0a3cdedeb753600a6 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 10 Apr 2023 15:58:56 -0500 Subject: [PATCH 20/21] check if mint txs are confirmed --- lib/services/coins/firo/firo_wallet.dart | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart index c2c712bb1..f422a34eb 100644 --- a/lib/services/coins/firo/firo_wallet.dart +++ b/lib/services/coins/firo/firo_wallet.dart @@ -900,10 +900,6 @@ class FiroWallet extends CoinServiceAPI .findAll(); // _transactionData ??= _refreshTransactions(); - // Query for lelantus txs / mints - Future> get _mintsTxnData => - db.getTransactions(walletId).filter().isLelantusEqualTo(true).findAll(); - // models.TransactionData? cachedTxData; // hack to add tx to txData before refresh completes @@ -2389,7 +2385,6 @@ class FiroWallet extends CoinServiceAPI } final jindexes = firoGetJIndex(); final transactions = await _txnData; - final mints = await _mintsTxnData; final lelantusTransactionsd = await db .getTransactions(walletId) .filter() @@ -2418,7 +2413,14 @@ class FiroWallet extends CoinServiceAPI if (!jindexes!.contains(lelantusCoinsList[i].index) && transactions .where((e) => e.txid == lelantusCoinsList[i].txId) - .isEmpty) { + .isEmpty && + !(lelantusTransactionsd + .where((e) => e.txid == lelantusCoinsList[i].txId) + .isNotEmpty && + lelantusTransactionsd + .where((e) => e.txid == lelantusCoinsList[i].txId) + .first + .isConfirmed(currentChainHeight, MINIMUM_CONFIRMATIONS))) { isUnconfirmed = true; } @@ -2441,11 +2443,7 @@ class FiroWallet extends CoinServiceAPI } if (!lelantusCoinsList[i].isUsed && lelantusCoinsList[i].anonymitySetId != ANONYMITY_SET_EMPTY_ID && - (!isUnconfirmed || - mints - .where((e) => e.txid == lelantusCoinsList[i].txId) - .isNotEmpty)) { - // TODO make sure that mints is filtered to remove unconfirmed tx + !isUnconfirmed) { coins.add(lelantusCoinsList[i]); } } From b45146ac4b3d747647974814ecc6e47be9f8414f Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 10 Apr 2023 16:23:44 -0500 Subject: [PATCH 21/21] amount-related ui fixes for firo/spend-mints --- lib/pages/send_view/confirm_transaction_view.dart | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart index 8cb4f42c9..9f9b7c9df 100644 --- a/lib/pages/send_view/confirm_transaction_view.dart +++ b/lib/pages/send_view/confirm_transaction_view.dart @@ -539,13 +539,15 @@ class _ConfirmTransactionViewState ), Builder( builder: (context) { - final amount = - transactionInfo["recipientAmt"] as Amount; final coin = ref.watch( managerProvider.select( (value) => value.coin, ), ); + final amount = Amount( + rawValue: BigInt.from( + transactionInfo["recipientAmt"] as int), + fractionDigits: coin.decimals); final externalCalls = ref.watch( prefsChangeNotifierProvider.select( (value) => value.externalCalls)); @@ -922,7 +924,10 @@ class _ConfirmTransactionViewState localeServiceChangeNotifierProvider .select((value) => value.locale), ); - final amount = transactionInfo["recipientAmt"] as Amount; + final amount = Amount( + rawValue: BigInt.from( + transactionInfo["recipientAmt"] as int), + fractionDigits: coin.decimals); return Text( "${(amount + fee).localizedStringAsFixed( locale: locale,