From 6754c2ebdf94eba6a9aeac3ac50311f85431382f Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 7 Apr 2023 15:08:06 -0600 Subject: [PATCH] add token functionality to desktop eth wallet view --- .../sub_widgets/add_token_list.dart | 6 +- lib/pages/token_view/my_tokens_view.dart | 371 ++++++++---------- .../sub_widgets/my_token_select_item.dart | 125 +++--- .../sub_widgets/my_tokens_list.dart | 7 +- .../wallet_view/desktop_wallet_view.dart | 43 +- 5 files changed, 276 insertions(+), 276 deletions(-) diff --git a/lib/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list.dart b/lib/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list.dart index b3280c066..a8532f307 100644 --- a/lib/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list.dart +++ b/lib/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list.dart @@ -13,7 +13,7 @@ class AddTokenList extends StatelessWidget { final String walletId; final List items; - final VoidCallback addFunction; + final VoidCallback? addFunction; @override Widget build(BuildContext context) { @@ -23,13 +23,13 @@ class AddTokenList extends StatelessWidget { itemCount: items.length, itemBuilder: (ctx, index) { return ConditionalParent( - condition: index == items.length - 1, + condition: index == items.length - 1 && addFunction != null, builder: (child) => Column( mainAxisSize: MainAxisSize.min, children: [ child, AddCustomTokenSelector( - addFunction: addFunction, + addFunction: addFunction!, ), ], ), diff --git a/lib/pages/token_view/my_tokens_view.dart b/lib/pages/token_view/my_tokens_view.dart index 3dd10ed01..78fa352d0 100644 --- a/lib/pages/token_view/my_tokens_view.dart +++ b/lib/pages/token_view/my_tokens_view.dart @@ -12,10 +12,9 @@ import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; -import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; -import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart'; @@ -34,6 +33,8 @@ class MyTokensView extends ConsumerStatefulWidget { } class _MyTokensViewState extends ConsumerState { + final bool isDesktop = Util.isDesktop; + late final String walletAddress; late final TextEditingController _searchController; final searchFieldFocusNode = FocusNode(); @@ -56,222 +57,180 @@ class _MyTokensViewState extends ConsumerState { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - final isDesktop = Util.isDesktop; - - return MasterScaffold( - background: Theme.of(context).extension()!.background, - isDesktop: isDesktop, - appBar: isDesktop - ? DesktopAppBar( - isCompactHeight: true, - background: Theme.of(context).extension()!.popupBG, - leading: Row( - children: [ - const SizedBox( - width: 32, - ), - AppBarIconButton( - size: 32, - color: Theme.of(context) - .extension()! - .textFieldDefaultBG, + return ConditionalParent( + condition: !isDesktop, + builder: (child) => Background( + child: Scaffold( + backgroundColor: + Theme.of(context).extension()!.background, + appBar: AppBar( + backgroundColor: + Theme.of(context).extension()!.background, + leading: AppBarBackButton( + onPressed: () async { + if (FocusScope.of(context).hasFocus) { + FocusScope.of(context).unfocus(); + await Future.delayed(const Duration(milliseconds: 75)); + } + if (mounted) { + Navigator.of(context).pop(); + } + }, + ), + title: Text( + "${ref.watch( + walletsChangeNotifierProvider.select( + (value) => value.getManager(widget.walletId).walletName), + )} Tokens", + style: STextStyles.navBarTitle(context), + ), + actions: [ + Padding( + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + right: 20, + ), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + key: const Key("addTokenAppBarIconButtonKey"), + size: 36, shadows: const [], + color: + Theme.of(context).extension()!.background, icon: SvgPicture.asset( - Assets.svg.arrowLeft, - width: 18, - height: 18, + Assets.svg.circlePlusDark, color: Theme.of(context) .extension()! - .topNavIconPrimary, + .accentColorDark, + width: 20, + height: 20, ), - onPressed: Navigator.of(context).pop, - ), - const SizedBox( - width: 12, - ), - Text( - "${ref.watch( - walletsChangeNotifierProvider.select((value) => - value.getManager(widget.walletId).walletName), - )} Tokens", - style: STextStyles.desktopH3(context), - ), - ], - ), - ) - : AppBar( - backgroundColor: - Theme.of(context).extension()!.background, - leading: AppBarBackButton( - onPressed: () async { - if (FocusScope.of(context).hasFocus) { - FocusScope.of(context).unfocus(); - await Future.delayed( - const Duration(milliseconds: 75)); - } - if (mounted) { - Navigator.of(context).pop(); - } - }, - ), - title: Text( - "${ref.watch( - walletsChangeNotifierProvider.select( - (value) => value.getManager(widget.walletId).walletName), - )} Tokens", - style: STextStyles.navBarTitle(context), - ), - actions: [ - Padding( - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - right: 20, - ), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - key: const Key("addTokenAppBarIconButtonKey"), - size: 36, - shadows: const [], - color: Theme.of(context) - .extension()! - .background, - icon: SvgPicture.asset( - Assets.svg.circlePlusDark, - color: Theme.of(context) - .extension()! - .accentColorDark, - width: 20, - height: 20, - ), - onPressed: () async { - final result = await Navigator.of(context).pushNamed( - EditWalletTokensView.routeName, - arguments: widget.walletId, - ); + onPressed: () async { + final result = await Navigator.of(context).pushNamed( + EditWalletTokensView.routeName, + arguments: widget.walletId, + ); - if (mounted && result == 42) { - setState(() {}); - } - }, + if (mounted && result == 42) { + setState(() {}); + } + }, + ), + ), + ), + ], + ), + body: Padding( + padding: const EdgeInsets.only( + left: 12, + top: 12, + right: 12, + ), + child: child, + ), + ), + ), + child: Column( + children: [ + Padding( + padding: EdgeInsets.all(isDesktop ? 0 : 4), + child: Row( + children: [ + ConditionalParent( + condition: isDesktop, + builder: (child) => Expanded( + child: child, + ), + child: ConditionalParent( + condition: !isDesktop, + builder: (child) => Expanded( + child: child, + ), + child: 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, + ), + ), ), ), ), ], ), - body: Padding( - padding: EdgeInsets.only( - left: isDesktop ? 20 : 12, - top: isDesktop ? 20 : 12, - right: isDesktop ? 20 : 12, - ), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(4), - child: Row( - children: [ - ConditionalParent( - condition: isDesktop, - builder: (child) => SizedBox( - width: 570, - child: child, - ), - child: ConditionalParent( - condition: !isDesktop, - builder: (child) => Expanded( - child: child, - ), - child: 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, - ), - ), - ), - ), - ), - if (isDesktop) - const SizedBox( - width: 20, - ), - // const NoTransActionsFound(), - ], - ), + ), + const SizedBox( + height: 8, + ), + Expanded( + child: MyTokensList( + walletId: widget.walletId, + searchTerm: _searchString, + tokenContracts: ref + .watch(walletsChangeNotifierProvider.select((value) => value + .getManager(widget.walletId) + .wallet as EthereumWallet)) + .getWalletTokenContractAddresses(), ), - const SizedBox( - height: 8, - ), - Expanded( - child: MyTokensList( - walletId: widget.walletId, - searchTerm: _searchString, - tokenContracts: ref - .watch(walletsChangeNotifierProvider.select((value) => value - .getManager(widget.walletId) - .wallet as EthereumWallet)) - .getWalletTokenContractAddresses(), - ), - ), - ], - ), + ), + ], ), ); } diff --git a/lib/pages/token_view/sub_widgets/my_token_select_item.dart b/lib/pages/token_view/sub_widgets/my_token_select_item.dart index fa01e031b..f6a327f52 100644 --- a/lib/pages/token_view/sub_widgets/my_token_select_item.dart +++ b/lib/pages/token_view/sub_widgets/my_token_select_item.dart @@ -1,19 +1,19 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; import 'package:stackwallet/pages/token_view/token_view.dart'; +import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/desktop_token_view.dart'; import 'package:stackwallet/providers/global/secure_store_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; import 'package:stackwallet/services/ethereum/cached_eth_token_balance.dart'; import 'package:stackwallet/services/ethereum/ethereum_token_service.dart'; import 'package:stackwallet/services/transaction_notification_tracker.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/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/icon_widgets/eth_token_icon.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class MyTokenSelectItem extends ConsumerStatefulWidget { @@ -31,8 +31,38 @@ class MyTokenSelectItem extends ConsumerStatefulWidget { } class _MyTokenSelectItemState extends ConsumerState { + final bool isDesktop = Util.isDesktop; + late final CachedEthTokenBalance cachedBalance; + void _onPressed() async { + ref.read(tokenServiceStateProvider.state).state = EthTokenWallet( + token: widget.token, + secureStore: ref.read(secureStoreProvider), + ethWallet: ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .wallet as EthereumWallet, + tracker: TransactionNotificationTracker( + walletId: widget.walletId, + ), + ); + + await showLoading( + whileFuture: ref.read(tokenServiceProvider)!.initialize(), + context: context, + isDesktop: isDesktop, + message: "Loading ${widget.token.name}", + ); + + if (mounted) { + await Navigator.of(context).pushNamed( + isDesktop ? DesktopTokenView.routeName : TokenView.routeName, + arguments: widget.walletId, + ); + } + } + @override void initState() { cachedBalance = CachedEthTokenBalance(widget.walletId, widget.token); @@ -57,47 +87,23 @@ class _MyTokenSelectItemState extends ConsumerState { padding: const EdgeInsets.all(0), child: MaterialButton( key: Key("walletListItemButtonKey_${widget.token.symbol}"), - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 13), + padding: isDesktop + ? const EdgeInsets.symmetric(horizontal: 28, vertical: 24) + : const EdgeInsets.symmetric(horizontal: 12, vertical: 13), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), ), - onPressed: () async { - ref.read(tokenServiceStateProvider.state).state = EthTokenWallet( - token: widget.token, - secureStore: ref.read(secureStoreProvider), - ethWallet: ref - .read(walletsChangeNotifierProvider) - .getManager(widget.walletId) - .wallet as EthereumWallet, - tracker: TransactionNotificationTracker( - walletId: widget.walletId, - ), - ); - - await showLoading( - whileFuture: ref.read(tokenServiceProvider)!.initialize(), - context: context, - message: "Loading ${widget.token.name}", - ); - - if (mounted) { - await Navigator.of(context).pushNamed( - TokenView.routeName, - arguments: widget.walletId, - ); - } - }, + onPressed: _onPressed, child: Row( children: [ - SvgPicture.asset( - Assets.svg.iconFor(coin: Coin.ethereum), - width: 28, - height: 28, + EthTokenIcon( + contractAddress: widget.token.address, + size: isDesktop ? 32 : 28, ), - const SizedBox( - width: 10, + SizedBox( + width: isDesktop ? 12 : 10, ), Expanded( child: Consumer( @@ -109,7 +115,9 @@ class _MyTokenSelectItemState extends ConsumerState { children: [ Text( widget.token.name, - style: STextStyles.titleBold12(context), + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context) + : STextStyles.titleBold12(context), ), const Spacer(), Text( @@ -121,33 +129,44 @@ class _MyTokenSelectItemState extends ConsumerState { ), )} " "${widget.token.symbol}", - style: STextStyles.itemSubtitle(context), + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context) + : STextStyles.itemSubtitle(context), ), ], ), const SizedBox( - height: 1, + height: 2, ), Row( children: [ Text( widget.token.symbol, - style: STextStyles.itemSubtitle(context), + style: isDesktop + ? STextStyles.desktopTextExtraExtraSmall( + context) + : STextStyles.itemSubtitle(context), ), const Spacer(), - Text("${ref.watch( - priceAnd24hChangeNotifierProvider.select( - (value) => value - .getTokenPrice(widget.token.address) - .item1 - .toStringAsFixed(2), - ), - )} " - "${ref.watch( - prefsChangeNotifierProvider.select( - (value) => value.currency, - ), - )}"), + Text( + "${ref.watch( + priceAnd24hChangeNotifierProvider.select( + (value) => value + .getTokenPrice(widget.token.address) + .item1 + .toStringAsFixed(2), + ), + )} " + "${ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.currency, + ), + )}", + style: isDesktop + ? STextStyles.desktopTextExtraExtraSmall( + context) + : STextStyles.itemSubtitle(context), + ), ], ), ], diff --git a/lib/pages/token_view/sub_widgets/my_tokens_list.dart b/lib/pages/token_view/sub_widgets/my_tokens_list.dart index fb8c8ef13..659ed5221 100644 --- a/lib/pages/token_view/sub_widgets/my_tokens_list.dart +++ b/lib/pages/token_view/sub_widgets/my_tokens_list.dart @@ -4,6 +4,7 @@ import 'package:isar/isar.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; import 'package:stackwallet/pages/token_view/sub_widgets/my_token_select_item.dart'; +import 'package:stackwallet/utilities/util.dart'; class MyTokensList extends StatelessWidget { const MyTokensList({ @@ -52,6 +53,8 @@ class MyTokensList extends StatelessWidget { @override Widget build(BuildContext context) { + final bool isDesktop = Util.isDesktop; + return Consumer( builder: (_, ref, __) { final tokens = _filter(searchTerm); @@ -61,7 +64,9 @@ class MyTokensList extends StatelessWidget { final token = tokens[index]; return Padding( key: Key(token.address), - padding: const EdgeInsets.all(4), + padding: isDesktop + ? const EdgeInsets.symmetric(vertical: 5) + : const EdgeInsets.all(4), child: MyTokenSelectItem( walletId: walletId, token: token, diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart index edfb0a1cc..7e786ace6 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart @@ -4,8 +4,9 @@ import 'package:event_bus/event_bus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart'; +import 'package:stackwallet/pages/token_view/my_tokens_view.dart'; import 'package:stackwallet/pages/wallet_view/sub_widgets/transactions_list.dart'; -import 'package:stackwallet/pages/wallet_view/transaction_views/all_transactions_view.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/my_wallet.dart'; @@ -282,7 +283,7 @@ class _DesktopWalletViewState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - "Recent transactions", + "Tokens", style: STextStyles.desktopTextExtraSmall(context) .copyWith( color: Theme.of(context) @@ -291,12 +292,20 @@ class _DesktopWalletViewState extends ConsumerState { ), ), CustomTextButton( - text: "See all", - onTap: () { - Navigator.of(context).pushNamed( - AllTransactionsView.routeName, - arguments: widget.walletId, + text: "Edit", + onTap: () async { + final result = await showDialog( + context: context, + builder: (context) => EditWalletTokensView( + walletId: widget.walletId, + isDesktopPopup: true, + ), ); + + if (result == 42) { + // wallet tokens were edited so update ui + setState(() {}); + } }, ), ], @@ -321,12 +330,20 @@ class _DesktopWalletViewState extends ConsumerState { width: 16, ), Expanded( - child: TransactionsList( - managerProvider: ref.watch( - walletsChangeNotifierProvider.select((value) => - value.getManagerProvider(widget.walletId))), - walletId: widget.walletId, - ), + child: ref.watch(walletsChangeNotifierProvider.select( + (value) => value + .getManager(widget.walletId) + .hasTokenSupport)) + ? MyTokensView( + walletId: widget.walletId, + ) + : TransactionsList( + managerProvider: ref.watch( + walletsChangeNotifierProvider.select( + (value) => value.getManagerProvider( + widget.walletId))), + walletId: widget.walletId, + ), ), ], ),