diff --git a/lib/pages/exchange_view/choose_from_stack_view.dart b/lib/pages/exchange_view/choose_from_stack_view.dart new file mode 100644 index 000000000..67e6fcca5 --- /dev/null +++ b/lib/pages/exchange_view/choose_from_stack_view.dart @@ -0,0 +1,128 @@ +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/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_coin_icon.dart'; + +class ChooseFromStackView extends ConsumerStatefulWidget { + const ChooseFromStackView({ + Key? key, + required this.coin, + }) : super(key: key); + + final Coin coin; + + static const String routeName = "/chooseFromStack"; + + @override + ConsumerState createState() => + _ChooseFromStackViewState(); +} + +class _ChooseFromStackViewState extends ConsumerState { + late final Coin coin; + + @override + void initState() { + coin = widget.coin; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final walletIds = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getWalletIdsFor(coin: coin))); + + return Scaffold( + backgroundColor: Theme.of(context).extension()!.background, + appBar: AppBar( + leading: const AppBarBackButton(), + title: Text( + "Edit trade note", + style: STextStyles.navBarTitle(context), + ), + ), + body: Padding( + padding: const EdgeInsets.all(16), + child: walletIds.isEmpty + ? Column( + children: [ + RoundedWhiteContainer( + child: Center( + child: Text( + "No ${coin.ticker.toUpperCase()} wallets", + style: STextStyles.itemSubtitle(context), + ), + ), + ), + ], + ) + : ListView.builder( + itemCount: walletIds.length, + itemBuilder: (context, index) { + final manager = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getManager(walletIds[index]))); + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 5.0), + child: RawMaterialButton( + splashColor: + Theme.of(context).extension()!.highlight, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + padding: const EdgeInsets.all(0), + // color: Theme.of(context).extension()!.popupBG, + elevation: 0, + onPressed: () async { + if (mounted) { + Navigator.of(context).pop(manager.walletId); + } + }, + child: RoundedWhiteContainer( + // color: Colors.transparent, + child: Row( + children: [ + WalletInfoCoinIcon(coin: coin), + const SizedBox( + width: 12, + ), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + manager.walletName, + style: STextStyles.titleBold12(context), + overflow: TextOverflow.ellipsis, + ), + const SizedBox( + height: 2, + ), + WalletInfoRowBalanceFuture( + walletId: walletIds[index], + ), + ], + ), + ) + ], + ), + ), + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart index 3ac7fd8ec..d307513ed 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/pages/address_book_views/address_book_view.dart'; +import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart'; @@ -17,6 +18,7 @@ import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; @@ -54,6 +56,15 @@ class _Step2ViewState extends ConsumerState { late final FocusNode _toFocusNode; late final FocusNode _refundFocusNode; + bool isStackCoin(String ticker) { + try { + coinFromTickerCaseInsensitive(ticker); + return true; + } on ArgumentError catch (_) { + return false; + } + } + @override void initState() { model = widget.model; @@ -74,7 +85,10 @@ class _Step2ViewState extends ConsumerState { .read(walletsChangeNotifierProvider) .getManager(tuple.item1) .currentReceivingAddress - .then((value) => _toController.text = value); + .then((value) { + _toController.text = value; + model.recipientAddress = _toController.text; + }); } } @@ -158,15 +172,36 @@ class _Step2ViewState extends ConsumerState { "Recipient Wallet", style: STextStyles.smallMed12(context), ), - // GestureDetector( - // onTap: () { - // // TODO: choose from stack? - // }, - // child: Text( - // "Choose from Stack", - // style: STextStyles.link2(context), - // ), - // ), + if (isStackCoin(model.receiveTicker)) + BlueTextButton( + text: "Choose from stack", + onTap: () { + try { + final coin = coinFromTickerCaseInsensitive( + model.receiveTicker, + ); + Navigator.of(context) + .pushNamed( + ChooseFromStackView.routeName, + arguments: coin, + ) + .then((value) async { + if (value is String) { + final manager = ref + .read(walletsChangeNotifierProvider) + .getManager(value); + + _toController.text = manager.walletName; + model.recipientAddress = await manager + .currentReceivingAddress; + } + }); + } catch (e, s) { + Logging.instance + .log("$e\n$s", level: LogLevel.Info); + } + }, + ), ], ), const SizedBox( @@ -195,6 +230,9 @@ class _Step2ViewState extends ConsumerState { ), focusNode: _toFocusNode, style: STextStyles.field(context), + onChanged: (value) { + setState(() {}); + }, decoration: standardInputDecoration( "Enter the ${model.receiveTicker.toUpperCase()} payout address", _toFocusNode, @@ -221,6 +259,8 @@ class _Step2ViewState extends ConsumerState { "sendViewClearAddressFieldButtonKey"), onTap: () { _toController.text = ""; + model.recipientAddress = + _toController.text; setState(() {}); }, @@ -239,6 +279,8 @@ class _Step2ViewState extends ConsumerState { data.text!.trim(); _toController.text = content; + model.recipientAddress = + _toController.text; setState(() {}); } @@ -299,11 +341,15 @@ class _Step2ViewState extends ConsumerState { // auto fill address _toController.text = results["address"] ?? ""; + model.recipientAddress = + _toController.text; setState(() {}); } else { _toController.text = qrResult.rawContent; + model.recipientAddress = + _toController.text; setState(() {}); } @@ -348,15 +394,37 @@ class _Step2ViewState extends ConsumerState { "Refund Wallet (required)", style: STextStyles.smallMed12(context), ), - // GestureDetector( - // onTap: () { - // // TODO: choose from stack? - // }, - // child: Text( - // "Choose from Stack", - // style: STextStyles.link2(context), - // ), - // ), + if (isStackCoin(model.sendTicker)) + BlueTextButton( + text: "Choose from stack", + onTap: () { + try { + final coin = coinFromTickerCaseInsensitive( + model.sendTicker, + ); + Navigator.of(context) + .pushNamed( + ChooseFromStackView.routeName, + arguments: coin, + ) + .then((value) async { + if (value is String) { + final manager = ref + .read(walletsChangeNotifierProvider) + .getManager(value); + + _refundController.text = + manager.walletName; + model.refundAddress = await manager + .currentReceivingAddress; + } + }); + } catch (e, s) { + Logging.instance + .log("$e\n$s", level: LogLevel.Info); + } + }, + ), ], ), const SizedBox( @@ -384,6 +452,9 @@ class _Step2ViewState extends ConsumerState { ), focusNode: _refundFocusNode, style: STextStyles.field(context), + onChanged: (value) { + setState(() {}); + }, decoration: standardInputDecoration( "Enter ${model.sendTicker.toUpperCase()} refund address", _refundFocusNode, @@ -410,6 +481,8 @@ class _Step2ViewState extends ConsumerState { "sendViewClearAddressFieldButtonKey"), onTap: () { _refundController.text = ""; + model.refundAddress = + _refundController.text; setState(() {}); }, @@ -429,6 +502,8 @@ class _Step2ViewState extends ConsumerState { _refundController.text = content; + model.refundAddress = + _refundController.text; setState(() {}); } @@ -490,11 +565,15 @@ class _Step2ViewState extends ConsumerState { // auto fill address _refundController.text = results["address"] ?? ""; + model.refundAddress = + _refundController.text; setState(() {}); } else { _refundController.text = qrResult.rawContent; + model.refundAddress = + _refundController.text; setState(() {}); } @@ -556,9 +635,6 @@ class _Step2ViewState extends ConsumerState { Expanded( child: TextButton( onPressed: () { - model.recipientAddress = _toController.text; - model.refundAddress = _refundController.text; - Navigator.of(context).pushNamed( Step3View.routeName, arguments: model); diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 797b62969..811205f6b 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -20,6 +20,7 @@ import 'package:stackwallet/pages/address_book_views/subviews/address_book_filte import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart'; +import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart'; import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_loading_overlay.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart'; @@ -879,6 +880,20 @@ class RouteGenerator { } return _routeError("${settings.name} invalid args: ${args.toString()}"); + case ChooseFromStackView.routeName: + if (args is Coin) { + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => ChooseFromStackView( + coin: args, + ), + settings: RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); + // == Desktop specific routes ============================================ case CreatePasswordView.routeName: return getRoute(