From e99e43b639ccebf9fb18bf877c56184478f1e7d7 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 29 Sep 2022 12:05:11 -0600 Subject: [PATCH 01/18] background color fix --- lib/pages/exchange_view/confirm_change_now_send.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pages/exchange_view/confirm_change_now_send.dart b/lib/pages/exchange_view/confirm_change_now_send.dart index 6fd6c8a08..ffd089428 100644 --- a/lib/pages/exchange_view/confirm_change_now_send.dart +++ b/lib/pages/exchange_view/confirm_change_now_send.dart @@ -132,6 +132,7 @@ class _ConfirmChangeNowSendViewState final managerProvider = ref.watch(walletsChangeNotifierProvider .select((value) => value.getManagerProvider(walletId))); return Scaffold( + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( From 0274cbc95049cdd1d6b8ee0ec2355cb743d9bb29 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 29 Sep 2022 12:15:09 -0600 Subject: [PATCH 02/18] address book copy icon size increase --- .../subviews/contact_details_view.dart | 32 +++++++++++-------- .../subviews/contact_popup.dart | 6 ++-- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/pages/address_book_views/subviews/contact_details_view.dart b/lib/pages/address_book_views/subviews/contact_details_view.dart index 6538af0dc..c0c10b3b1 100644 --- a/lib/pages/address_book_views/subviews/contact_details_view.dart +++ b/lib/pages/address_book_views/subviews/contact_details_view.dart @@ -393,13 +393,15 @@ class _ContactDetailsViewState extends ConsumerState { color: Theme.of(context) .extension()! .textFieldDefaultBG, - padding: const EdgeInsets.all(4), - child: SvgPicture.asset(Assets.svg.pencil, - width: 12, - height: 12, - color: Theme.of(context) - .extension()! - .accentColorDark), + padding: const EdgeInsets.all(6), + child: SvgPicture.asset( + Assets.svg.pencil, + width: 14, + height: 14, + color: Theme.of(context) + .extension()! + .accentColorDark, + ), ), ), const SizedBox( @@ -421,13 +423,15 @@ class _ContactDetailsViewState extends ConsumerState { color: Theme.of(context) .extension()! .textFieldDefaultBG, - padding: const EdgeInsets.all(4), - child: SvgPicture.asset(Assets.svg.copy, - width: 12, - height: 12, - color: Theme.of(context) - .extension()! - .accentColorDark), + padding: const EdgeInsets.all(6), + child: SvgPicture.asset( + Assets.svg.copy, + width: 16, + height: 16, + color: Theme.of(context) + .extension()! + .accentColorDark, + ), ), ), ], diff --git a/lib/pages/address_book_views/subviews/contact_popup.dart b/lib/pages/address_book_views/subviews/contact_popup.dart index a14581c0a..11f1911d5 100644 --- a/lib/pages/address_book_views/subviews/contact_popup.dart +++ b/lib/pages/address_book_views/subviews/contact_popup.dart @@ -268,11 +268,11 @@ class ContactPopUp extends ConsumerWidget { color: Theme.of(context) .extension()! .textFieldDefaultBG, - padding: const EdgeInsets.all(4), + padding: const EdgeInsets.all(6), child: SvgPicture.asset( Assets.svg.copy, - width: 12, - height: 12, + width: 16, + height: 16, color: Theme.of(context) .extension()! .accentColorDark), From f81784c1c34479bf4cc55de3f71d503bedfecd55 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 09:04:50 -0600 Subject: [PATCH 03/18] Selecting Receive amount is disabled when Estimated rate is active. Display "-" in the Receive amount field in that case --- lib/pages/exchange_view/exchange_view.dart | 8 ++++---- .../exchange_view/wallet_initiated_exchange_view.dart | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/pages/exchange_view/exchange_view.dart b/lib/pages/exchange_view/exchange_view.dart index 1487f5f6a..5e2be20b3 100644 --- a/lib/pages/exchange_view/exchange_view.dart +++ b/lib/pages/exchange_view/exchange_view.dart @@ -232,7 +232,7 @@ class _ExchangeViewState extends ConsumerState { ? ref.read(estimatedRateExchangeFormProvider).fromAmountString : ref.read(fixedRateExchangeFormProvider).fromAmountString; _receiveController.text = isEstimated - ? ref.read(estimatedRateExchangeFormProvider).toAmountString + ? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString : ref.read(fixedRateExchangeFormProvider).toAmountString; _sendFocusNode.addListener(() async { @@ -325,7 +325,7 @@ class _ExchangeViewState extends ConsumerState { : fixedRateExchangeFormProvider.select( (value) => value.toAmountString), (previous, String next) { if (!_receiveFocusNode.hasFocus) { - _receiveController.text = next; + _receiveController.text = isEstimated ? "-" : next; debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED"); if (_swapLock) { _sendController.text = isEstimated @@ -345,7 +345,7 @@ class _ExchangeViewState extends ConsumerState { debugPrint("SEND AMOUNT LISTENER ACTIVATED"); if (_swapLock) { _receiveController.text = isEstimated - ? ref.read(estimatedRateExchangeFormProvider).toAmountString + ? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString : ref.read(fixedRateExchangeFormProvider).toAmountString; } } @@ -737,7 +737,7 @@ class _ExchangeViewState extends ConsumerState { .exchangeRateType == ExchangeRateType.estimated, onTap: () { - if (_receiveController.text == "-") { + if (!isEstimated && _receiveController.text == "-") { _receiveController.text = ""; } }, diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index 179555ba6..15d010765 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -329,7 +329,7 @@ class _WalletInitiatedExchangeViewState : fixedRateExchangeFormProvider.select( (value) => value.toAmountString), (previous, String next) { if (!_receiveFocusNode.hasFocus) { - _receiveController.text = next; + _receiveController.text = isEstimated ? "-" : next; debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED"); if (_swapLock) { _sendController.text = isEstimated @@ -349,7 +349,7 @@ class _WalletInitiatedExchangeViewState debugPrint("SEND AMOUNT LISTENER ACTIVATED"); if (_swapLock) { _receiveController.text = isEstimated - ? ref.read(estimatedRateExchangeFormProvider).toAmountString + ? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString : ref.read(fixedRateExchangeFormProvider).toAmountString; } } @@ -808,7 +808,8 @@ class _WalletInitiatedExchangeViewState .exchangeRateType == ExchangeRateType.estimated, onTap: () { - if (_receiveController.text == "-") { + if (!isEstimated && + _receiveController.text == "-") { _receiveController.text = ""; } }, From f02683581d7830768eb85f5c101ed713c7be231a Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 10:16:11 -0600 Subject: [PATCH 04/18] choose from stack exchange wallet addresses --- .../exchange_view/choose_from_stack_view.dart | 128 ++++++++++++++++++ .../exchange_step_views/step_2_view.dart | 120 +++++++++++++--- lib/route_generator.dart | 15 ++ 3 files changed, 241 insertions(+), 22 deletions(-) create mode 100644 lib/pages/exchange_view/choose_from_stack_view.dart 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( From 8268aaa7fe0278f9b205368d878dbf4372a6f453 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 10:34:25 -0600 Subject: [PATCH 05/18] fill in address from address book in exchange view --- .../subviews/contact_popup.dart | 43 ++++++++++++++ .../exchange_step_views/step_2_view.dart | 56 +++++++++++++++---- 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/lib/pages/address_book_views/subviews/contact_popup.dart b/lib/pages/address_book_views/subviews/contact_popup.dart index 11f1911d5..67ab32cda 100644 --- a/lib/pages/address_book_views/subviews/contact_popup.dart +++ b/lib/pages/address_book_views/subviews/contact_popup.dart @@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/send_view_auto_fill_data.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart'; +import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; import 'package:stackwallet/pages/send_view/send_view.dart'; import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart'; @@ -19,6 +20,9 @@ import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:tuple/tuple.dart'; +final exchangeFromAddressBookAddressStateProvider = + StateProvider((ref) => ""); + class ContactPopUp extends ConsumerWidget { const ContactPopUp({ Key? key, @@ -280,6 +284,45 @@ class ContactPopUp extends ConsumerWidget { ), ], ), + if (isExchangeFlow) + const SizedBox( + width: 6, + ), + if (isExchangeFlow) + Column( + children: [ + const SizedBox( + height: 2, + ), + GestureDetector( + onTap: () { + ref + .read( + exchangeFromAddressBookAddressStateProvider + .state) + .state = e.address; + Navigator.of(context).popUntil( + ModalRoute.withName( + Step2View.routeName)); + }, + child: RoundedContainer( + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, + padding: + const EdgeInsets.all(6), + child: SvgPicture.asset( + Assets.svg.chevronRight, + width: 16, + height: 16, + color: Theme.of(context) + .extension< + StackColors>()! + .accentColorDark), + ), + ), + ], + ), if (contact.id != "default" && hasActiveWallet && !isExchangeFlow) 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 d307513ed..85b58f481 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/address_book_views/subviews/contact_popup.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'; @@ -301,13 +302,31 @@ class _Step2ViewState extends ConsumerState { .state = true; Navigator.of(context) .pushNamed( - AddressBookView.routeName, - ) - .then((_) => ref + AddressBookView.routeName, + ) + .then((_) { + ref + .read( + exchangeFlowIsActiveStateProvider + .state) + .state = false; + + final address = ref + .read( + exchangeFromAddressBookAddressStateProvider + .state) + .state; + if (address.isNotEmpty) { + _toController.text = address; + model.recipientAddress = + _toController.text; + ref .read( - exchangeFlowIsActiveStateProvider + exchangeFromAddressBookAddressStateProvider .state) - .state = false); + .state = ""; + } + }); }, child: const AddressBookIcon(), ), @@ -525,13 +544,26 @@ class _Step2ViewState extends ConsumerState { .state = true; Navigator.of(context) .pushNamed( - AddressBookView.routeName, - ) - .then((_) => ref - .read( - exchangeFlowIsActiveStateProvider - .state) - .state = false); + AddressBookView.routeName, + ) + .then((_) { + ref + .read( + exchangeFlowIsActiveStateProvider + .state) + .state = false; + final address = ref + .read( + exchangeFromAddressBookAddressStateProvider + .state) + .state; + if (address.isNotEmpty) { + _refundController.text = + address; + model.refundAddress = + _refundController.text; + } + }); }, child: const AddressBookIcon(), ), From 77f4b2289821fec02eb48926a5f732269579f9f9 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 10:37:05 -0600 Subject: [PATCH 06/18] exchange overlay dark theme color fix --- lib/pages/exchange_view/wallet_initiated_exchange_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index 15d010765..7db0493b5 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -83,8 +83,8 @@ class _WalletInitiatedExchangeViewState child: Container( color: Theme.of(context) .extension()! - .accentColorDark - .withOpacity(0.8), + .overlay + .withOpacity(0.6), child: const CustomLoadingOverlay( message: "Updating exchange rate", eventBus: null, From 4283ce93601e9f641d7f510818048d745cf22ddc Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 10:53:36 -0600 Subject: [PATCH 07/18] fill in active wallet address --- .../exchange_step_views/step_2_view.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 85b58f481..5681018de 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 @@ -90,6 +90,18 @@ class _Step2ViewState extends ConsumerState { _toController.text = value; model.recipientAddress = _toController.text; }); + } else { + if (model.sendTicker.toUpperCase() == + tuple.item2.ticker.toUpperCase()) { + ref + .read(walletsChangeNotifierProvider) + .getManager(tuple.item1) + .currentReceivingAddress + .then((value) { + _refundController.text = value; + model.refundAddress = _refundController.text; + }); + } } } From 89e609254ff25a408121c72749ca8e40c67d7be8 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 11:02:35 -0600 Subject: [PATCH 08/18] creating trade overlay --- .../exchange_step_views/step_3_view.dart | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart index 604e3707f..a7b34571b 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart @@ -16,6 +16,7 @@ import 'package:stackwallet/utilities/clipboard_interface.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_loading_overlay.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -222,6 +223,26 @@ class _Step3ViewState extends ConsumerState { Expanded( child: TextButton( onPressed: () async { + unawaited( + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => WillPopScope( + onWillPop: () async => false, + child: Container( + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.6), + child: const CustomLoadingOverlay( + message: "Creating a trade", + eventBus: null, + ), + ), + ), + ), + ); + ChangeNowResponse response; if (model.rateType == @@ -251,6 +272,10 @@ class _Step3ViewState extends ConsumerState { } if (response.value == null) { + if (mounted) { + Navigator.of(context).pop(); + } + unawaited(showDialog( context: context, barrierDismissible: true, @@ -273,8 +298,6 @@ class _Step3ViewState extends ConsumerState { .getTransactionStatus( id: response.value!.id); - debugPrint("WTF: $statusResponse"); - String status = "Waiting"; if (statusResponse.value != null) { status = statusResponse.value!.status.name; @@ -290,6 +313,10 @@ class _Step3ViewState extends ConsumerState { status += " for deposit"; } + if (mounted) { + Navigator.of(context).pop(); + } + unawaited(NotificationApi.showNotification( changeNowId: model.trade!.id, title: status, From 241349d0cccc99224be86369dd1ff708a9912121 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 13:34:13 -0600 Subject: [PATCH 09/18] restore from date picker hint text style fix --- .../sub_widgets/restore_from_date_picker.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart index 0207a4c61..8a24e95bb 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart @@ -42,6 +42,11 @@ class _RestoreFromDatePickerState extends State { style: STextStyles.field(context), decoration: InputDecoration( hintText: "Restore from...", + hintStyle: STextStyles.fieldLabel(context).copyWith( + color: Theme.of(context) + .extension()! + .textFieldDefaultSearchIconLeft, + ), suffixIcon: UnconstrainedBox( child: Row( children: [ From 8f6c93869566c57ad23a58898f33da3e27b1bfdf Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 13:41:40 -0600 Subject: [PATCH 10/18] trade details send to address copy button --- .../exchange_view/trade_details_view.dart | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart index 6c299ed24..6cb7fbd59 100644 --- a/lib/pages/exchange_view/trade_details_view.dart +++ b/lib/pages/exchange_view/trade_details_view.dart @@ -345,9 +345,48 @@ class _TradeDetailsViewState extends ConsumerState { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "Send ${trade.fromCurrency.toUpperCase()} to this address", - style: STextStyles.itemSubtitle(context), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Send ${trade.fromCurrency.toUpperCase()} to this address", + style: STextStyles.itemSubtitle(context), + ), + GestureDetector( + onTap: () async { + final address = trade.payinAddress; + await Clipboard.setData( + ClipboardData( + text: address, + ), + ); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + context: context, + )); + }, + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.copy, + width: 12, + height: 12, + color: Theme.of(context) + .extension()! + .infoItemIcons, + ), + const SizedBox( + width: 4, + ), + Text( + "Copy", + style: STextStyles.link2(context), + ), + ], + ), + ), + ], ), const SizedBox( height: 4, From 626b0ee9ef0e558a8d0f7e8cb8c3e9543e8b0d1e Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 14:43:04 -0600 Subject: [PATCH 11/18] title fix --- lib/pages/exchange_view/choose_from_stack_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/exchange_view/choose_from_stack_view.dart b/lib/pages/exchange_view/choose_from_stack_view.dart index 67e6fcca5..f54a7552c 100644 --- a/lib/pages/exchange_view/choose_from_stack_view.dart +++ b/lib/pages/exchange_view/choose_from_stack_view.dart @@ -44,7 +44,7 @@ class _ChooseFromStackViewState extends ConsumerState { appBar: AppBar( leading: const AppBarBackButton(), title: Text( - "Edit trade note", + "Choose your ${coin.ticker.toUpperCase()} wallet", style: STextStyles.navBarTitle(context), ), ), From 5451698b9268d385b737920d114ce20f511fe947 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 15:21:10 -0600 Subject: [PATCH 12/18] send from button in trade details --- lib/pages/exchange_view/send_from_view.dart | 172 ++++++++++-------- .../exchange_view/trade_details_view.dart | 41 +++++ lib/route_generator.dart | 20 ++ lib/utilities/constants.dart | 2 + 4 files changed, 161 insertions(+), 74 deletions(-) diff --git a/lib/pages/exchange_view/send_from_view.dart b/lib/pages/exchange_view/send_from_view.dart index 586ffc0da..74a1f62d4 100644 --- a/lib/pages/exchange_view/send_from_view.dart +++ b/lib/pages/exchange_view/send_from_view.dart @@ -48,6 +48,26 @@ class _SendFromViewState extends ConsumerState { late final String address; late final ExchangeTransaction trade; + String formatAmount(Decimal amount, Coin coin) { + switch (coin) { + case Coin.bitcoin: + case Coin.bitcoincash: + case Coin.dogecoin: + case Coin.epicCash: + case Coin.firo: + case Coin.namecoin: + case Coin.bitcoinTestNet: + case Coin.bitcoincashTestnet: + case Coin.dogecoinTestNet: + case Coin.firoTestNet: + return amount.toStringAsFixed(Constants.decimalPlaces); + case Coin.monero: + return amount.toStringAsFixed(Constants.decimalPlacesMonero); + case Coin.wownero: + return amount.toStringAsFixed(Constants.decimalPlacesWownero); + } + } + @override void initState() { coin = widget.coin; @@ -59,6 +79,11 @@ class _SendFromViewState extends ConsumerState { @override Widget build(BuildContext context) { + debugPrint("BUILD: $runtimeType"); + + final walletIds = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getWalletIdsFor(coin: coin))); + return Scaffold( backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( @@ -68,44 +93,41 @@ class _SendFromViewState extends ConsumerState { }, ), title: Text( - "Send ", + "Send from", style: STextStyles.navBarTitle(context), ), ), body: Padding( padding: const EdgeInsets.all(16), - child: Wrap( - // crossAxisAlignment: CrossAxisAlignment.stretch, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, children: [ - Text( - "Choose your ${coin.ticker} wallet", - style: STextStyles.pageTitleH1(context), - ), - const SizedBox( - height: 8, - ), - Text( - "You need to send ${amount.toStringAsFixed(coin == Coin.monero ? Constants.satsPerCoinMonero : coin == Coin.wownero ? Constants.satsPerCoinWownero : Constants.satsPerCoin)} ${coin.ticker}", - style: STextStyles.itemSubtitle(context), + Row( + children: [ + Text( + "You need to send ${formatAmount(amount, coin)} ${coin.ticker}", + style: STextStyles.itemSubtitle(context), + ), + ], ), const SizedBox( height: 16, ), - ListView( - shrinkWrap: true, - children: [ - ...ref - .watch(walletsChangeNotifierProvider - .select((value) => value.managers)) - .where((element) => element.coin == coin) - .map((e) => SendFromCard( - walletId: e.walletId, - amount: amount, - address: address, - trade: trade, - )) - .toList(growable: false) - ], + Expanded( + child: ListView.builder( + itemCount: walletIds.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: SendFromCard( + walletId: walletIds[index], + amount: amount, + address: address, + trade: trade, + ), + ); + }, + ), ), ], ), @@ -163,7 +185,7 @@ class _SendFromCardState extends ConsumerState { child: MaterialButton( splashColor: Theme.of(context).extension()!.highlight, key: Key("walletsSheetItemButtonKey_$walletId"), - padding: const EdgeInsets.all(5), + padding: const EdgeInsets.all(8), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -276,59 +298,61 @@ class _SendFromCardState extends ConsumerState { ), ), child: Padding( - padding: const EdgeInsets.all(4), + padding: const EdgeInsets.all(6), child: SvgPicture.asset( Assets.svg.iconFor(coin: coin), - width: 20, - height: 20, + width: 24, + height: 24, ), ), ), const SizedBox( width: 12, ), - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - manager.walletName, - style: STextStyles.titleBold12(context), - ), - const SizedBox( - height: 2, - ), - FutureBuilder( - future: manager.totalBalance, - builder: (builderContext, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - return Text( - "${Format.localizedStringAsFixed( - value: snapshot.data!, - locale: locale, - decimalPlaces: coin == Coin.monero - ? Constants.satsPerCoinMonero - : coin == Coin.wownero - ? Constants.satsPerCoinWownero - : Constants.satsPerCoin, - )} ${coin.ticker}", - style: STextStyles.itemSubtitle(context), - ); - } else { - return AnimatedText( - stringsToLoopThrough: const [ - "Loading balance", - "Loading balance.", - "Loading balance..", - "Loading balance..." - ], - style: STextStyles.itemSubtitle(context), - ); - } - }, - ), - ], + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + manager.walletName, + style: STextStyles.titleBold12(context), + ), + const SizedBox( + height: 2, + ), + FutureBuilder( + future: manager.totalBalance, + builder: (builderContext, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) { + return Text( + "${Format.localizedStringAsFixed( + value: snapshot.data!, + locale: locale, + decimalPlaces: coin == Coin.monero + ? Constants.decimalPlacesMonero + : coin == Coin.wownero + ? Constants.decimalPlacesWownero + : Constants.decimalPlaces, + )} ${coin.ticker}", + style: STextStyles.itemSubtitle(context), + ); + } else { + return AnimatedText( + stringsToLoopThrough: const [ + "Loading balance", + "Loading balance.", + "Loading balance..", + "Loading balance..." + ], + style: STextStyles.itemSubtitle(context), + ); + } + }, + ), + ], + ), ), ], ), diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart index 6cb7fbd59..2730be657 100644 --- a/lib/pages/exchange_view/trade_details_view.dart +++ b/lib/pages/exchange_view/trade_details_view.dart @@ -10,6 +10,7 @@ import 'package:stackwallet/models/exchange/change_now/exchange_transaction_stat import 'package:stackwallet/models/paymint/transactions_model.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart'; +import 'package:stackwallet/pages/exchange_view/send_from_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart'; import 'package:stackwallet/providers/exchange/change_now_provider.dart'; @@ -24,6 +25,7 @@ import 'package:stackwallet/utilities/format.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/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -60,6 +62,15 @@ class _TradeDetailsViewState extends ConsumerState { String _note = ""; + bool isStackCoin(String ticker) { + try { + coinFromTickerCaseInsensitive(ticker); + return true; + } on ArgumentError catch (_) { + return false; + } + } + @override initState() { tradeId = widget.tradeId; @@ -756,6 +767,36 @@ class _TradeDetailsViewState extends ConsumerState { const SizedBox( height: 12, ), + if (isStackCoin(trade.fromCurrency) && + trade.statusObject != null && + (trade.statusObject!.status == + ChangeNowTransactionStatus.New || + trade.statusObject!.status == + ChangeNowTransactionStatus.Waiting)) + SecondaryButton( + label: "Send from Stack", + onPressed: () { + final amount = sendAmount; + final address = trade.payinAddress; + + final coin = + coinFromTickerCaseInsensitive(trade.fromCurrency); + + print("amount: $amount"); + print("address: $address"); + print("coin: $coin"); + + Navigator.of(context).pushNamed( + SendFromView.routeName, + arguments: Tuple4( + coin, + amount, + address, + trade, + ), + ); + }, + ), ], ), ), diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 811205f6b..368188171 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -1,7 +1,9 @@ +import 'package:decimal/decimal.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/contact_address_entry.dart'; +import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/paymint/transactions_model.dart'; import 'package:stackwallet/models/send_view_auto_fill_data.dart'; @@ -27,6 +29,7 @@ import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view. import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart'; +import 'package:stackwallet/pages/exchange_view/send_from_view.dart'; import 'package:stackwallet/pages/exchange_view/trade_details_view.dart'; import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart'; import 'package:stackwallet/pages/home_view/home_view.dart'; @@ -894,6 +897,23 @@ class RouteGenerator { } return _routeError("${settings.name} invalid args: ${args.toString()}"); + case SendFromView.routeName: + if (args is Tuple4) { + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => SendFromView( + coin: args.item1, + amount: args.item2, + trade: args.item4, + address: args.item3, + ), + settings: RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); + // == Desktop specific routes ============================================ case CreatePasswordView.routeName: return getRoute( diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index f5139477c..69c1444c3 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -21,6 +21,8 @@ abstract class Constants { static const int satsPerCoinWownero = 100000000000; static const int satsPerCoin = 100000000; static const int decimalPlaces = 8; + static const int decimalPlacesWownero = 11; + static const int decimalPlacesMonero = 12; static const int notificationsMax = 0xFFFFFFFF; static const Duration networkAliveTimerDuration = Duration(seconds: 10); From c2db998eb2ff76745eafaf9848d209268ad129a4 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 15:22:52 -0600 Subject: [PATCH 13/18] clean up --- lib/pages/exchange_view/trade_details_view.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart index 2730be657..ae44faeef 100644 --- a/lib/pages/exchange_view/trade_details_view.dart +++ b/lib/pages/exchange_view/trade_details_view.dart @@ -782,10 +782,6 @@ class _TradeDetailsViewState extends ConsumerState { final coin = coinFromTickerCaseInsensitive(trade.fromCurrency); - print("amount: $amount"); - print("address: $address"); - print("coin: $coin"); - Navigator.of(context).pushNamed( SendFromView.routeName, arguments: Tuple4( From 98bf94316036e18214f3425d844b7af04f7db3d8 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 16:43:45 -0600 Subject: [PATCH 14/18] total send amount from trade flow color fix --- .../exchange_view/confirm_change_now_send.dart | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/pages/exchange_view/confirm_change_now_send.dart b/lib/pages/exchange_view/confirm_change_now_send.dart index ffd089428..3ddf8932a 100644 --- a/lib/pages/exchange_view/confirm_change_now_send.dart +++ b/lib/pages/exchange_view/confirm_change_now_send.dart @@ -328,7 +328,12 @@ class _ConfirmChangeNowSendViewState children: [ Text( "Total amount", - style: STextStyles.titleBold12(context), + style: + STextStyles.titleBold12(context).copyWith( + color: Theme.of(context) + .extension()! + .textConfirmTotalAmount, + ), ), Text( "${Format.satoshiAmountToPrettyString( @@ -342,7 +347,12 @@ class _ConfirmChangeNowSendViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12(context), + style: STextStyles.itemSubtitle12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textConfirmTotalAmount, + ), textAlign: TextAlign.right, ), ], From 4fcebda78c43ec000dd7d590191a78561aa11c52 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 16:43:59 -0600 Subject: [PATCH 15/18] show trades in tx history --- .../sub_widgets/transactions_list.dart | 78 ++++++++++++++++--- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/lib/pages/wallet_view/sub_widgets/transactions_list.dart b/lib/pages/wallet_view/sub_widgets/transactions_list.dart index bda060071..64e1266d9 100644 --- a/lib/pages/wallet_view/sub_widgets/transactions_list.dart +++ b/lib/pages/wallet_view/sub_widgets/transactions_list.dart @@ -9,7 +9,12 @@ import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; +import 'package:stackwallet/widgets/trade_card.dart'; import 'package:stackwallet/widgets/transaction_card.dart'; +import 'package:tuple/tuple.dart'; + +import '../../../providers/global/trades_service_provider.dart'; +import '../../exchange_view/trade_details_view.dart'; class TransactionsList extends ConsumerStatefulWidget { const TransactionsList({ @@ -125,18 +130,67 @@ class _TransactionsListState extends ConsumerState { radius = _borderRadiusFirst; } final tx = list[index]; - return Container( - decoration: BoxDecoration( - color: Theme.of(context).extension()!.popupBG, - borderRadius: radius, - ), - child: TransactionCard( - // this may mess with combined firo transactions - key: Key(tx.toString()), // - transaction: tx, - walletId: widget.walletId, - ), - ); + + final matchingTrades = ref + .read(tradesServiceProvider) + .trades + .where((e) => + e.statusObject != null && + (e.statusObject!.payinHash == tx.txid || + e.statusObject!.payoutHash == tx.txid)); + if (matchingTrades.isNotEmpty) { + final trade = matchingTrades.first; + return Container( + decoration: BoxDecoration( + color: + Theme.of(context).extension()!.popupBG, + borderRadius: radius, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TransactionCard( + // this may mess with combined firo transactions + key: Key(tx.toString()), // + transaction: tx, + walletId: widget.walletId, + ), + TradeCard( + // this may mess with combined firo transactions + key: Key(tx.toString() + trade.uuid), // + trade: trade, + onTap: () { + unawaited( + Navigator.of(context).pushNamed( + TradeDetailsView.routeName, + arguments: Tuple4( + trade.id, + tx, + widget.walletId, + ref.read(managerProvider).walletName, + ), + ), + ); + }, + ) + ], + ), + ); + } else { + return Container( + decoration: BoxDecoration( + color: + Theme.of(context).extension()!.popupBG, + borderRadius: radius, + ), + child: TransactionCard( + // this may mess with combined firo transactions + key: Key(tx.toString()), // + transaction: tx, + walletId: widget.walletId, + ), + ); + } }, ), ); From bc740fd5b1d8d3469d8c34de56d9b4ac6d597b70 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 16:57:12 -0600 Subject: [PATCH 16/18] extra swb logging --- .../helpers/restore_create_backup.dart | 101 ++++++++++++++---- 1 file changed, 82 insertions(+), 19 deletions(-) diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart index 9665fdbaf..721141cb8 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart @@ -209,6 +209,10 @@ abstract class SWB { Logging.instance.log( "...createStackWalletJSON DB.instance.mutex acquired", level: LogLevel.Info); + Logging.instance.log( + "SWB backing up nodes", + level: LogLevel.Warning, + ); try { var primaryNodes = nodeService.primaryNodes.map((e) async { final map = e.toMap(); @@ -231,6 +235,11 @@ abstract class SWB { Logging.instance.log("$e $s", level: LogLevel.Error); } + Logging.instance.log( + "SWB backing up prefs", + level: LogLevel.Warning, + ); + Map prefs = {}; final _prefs = Prefs.instance; await _prefs.init(); @@ -251,11 +260,21 @@ abstract class SWB { backupJson['prefs'] = prefs; + Logging.instance.log( + "SWB backing up addressbook", + level: LogLevel.Warning, + ); + AddressBookService addressBookService = AddressBookService(); var addresses = await addressBookService.addressBookEntries; backupJson['addressBookEntries'] = addresses.map((e) => e.toMap()).toList(); + Logging.instance.log( + "SWB backing up wallets", + level: LogLevel.Warning, + ); + List backupWallets = []; for (var manager in _wallets.managers) { Map backupWallet = {}; @@ -283,6 +302,11 @@ abstract class SWB { } backupJson['wallets'] = backupWallets; + Logging.instance.log( + "SWB backing up trades", + level: LogLevel.Warning, + ); + // back up trade history final tradesService = TradesService(); final trades = @@ -295,6 +319,11 @@ abstract class SWB { tradeTxidLookupDataService.all.map((e) => e.toMap()).toList(); backupJson["tradeTxidLookupData"] = lookupData; + Logging.instance.log( + "SWB backing up trade notes", + level: LogLevel.Warning, + ); + // back up trade notes final tradeNotesService = TradeNotesService(); final tradeNotes = tradeNotesService.all; @@ -357,7 +386,7 @@ abstract class SWB { final notes = walletbackup["notes"] as Map?; if (notes != null) { for (final note in notes.entries) { - notesService.editOrAddNote( + await notesService.editOrAddNote( txid: note.key as String, note: note.value as String); } } @@ -432,11 +461,19 @@ abstract class SWB { uiState?.preferences = StackRestoringStatus.restoring; + Logging.instance.log( + "SWB restoring prefs", + level: LogLevel.Warning, + ); await _restorePrefs(prefs); uiState?.preferences = StackRestoringStatus.success; uiState?.addressBook = StackRestoringStatus.restoring; + Logging.instance.log( + "SWB restoring addressbook", + level: LogLevel.Warning, + ); if (addressBookEntries != null) { await _restoreAddressBook(addressBookEntries); } @@ -444,6 +481,10 @@ abstract class SWB { uiState?.addressBook = StackRestoringStatus.success; uiState?.nodes = StackRestoringStatus.restoring; + Logging.instance.log( + "SWB restoring nodes", + level: LogLevel.Warning, + ); await _restoreNodes(nodes, primaryNodes); uiState?.nodes = StackRestoringStatus.success; @@ -451,17 +492,29 @@ abstract class SWB { // restore trade history if (trades != null) { + Logging.instance.log( + "SWB restoring trades", + level: LogLevel.Warning, + ); await _restoreTrades(trades); } // restore trade history lookup data for trades send from stack wallet if (tradeTxidLookupData != null) { + Logging.instance.log( + "SWB restoring trade look up data", + level: LogLevel.Warning, + ); await _restoreTradesLookUpData(tradeTxidLookupData, oldToNewWalletIdMap); } // restore trade notes if (tradeNotes != null) { + Logging.instance.log( + "SWB restoring trade notes", + level: LogLevel.Warning, + ); await _restoreTradesNotes(tradeNotes); } @@ -490,9 +543,17 @@ abstract class SWB { String jsonBackup, StackRestoringUIState? uiState, ) async { - if (!Platform.isLinux) Wakelock.enable(); + if (!Platform.isLinux) await Wakelock.enable(); + Logging.instance.log( + "SWB creating temp backup", + level: LogLevel.Warning, + ); final preRestoreJSON = await createStackWalletJSON(); + Logging.instance.log( + "SWB temp backup created", + level: LogLevel.Warning, + ); List _currentWalletIds = Map.from(DB.instance .get( @@ -814,13 +875,13 @@ abstract class SWB { } await asyncRestore(epicCashWallets[i], uiState, walletsService); } - if (!Platform.isLinux) Wakelock.disable(); + if (!Platform.isLinux) await Wakelock.disable(); // check if cancel was requested and restore previous state if (_checkShouldCancel(preRestoreState)) { return false; } - Logging.instance.log("done with SWB restore", level: LogLevel.Info); + Logging.instance.log("done with SWB restore", level: LogLevel.Warning); return true; } @@ -849,7 +910,7 @@ abstract class SWB { // if no contacts were present before attempted restore then delete any that // could have been added before the restore was cancelled for (final String idToDelete in allContactIds) { - addressBookService.removeContact(idToDelete); + await addressBookService.removeContact(idToDelete); } } else { final Map preContactMap = {}; @@ -886,7 +947,7 @@ abstract class SWB { ); } else { // otherwise remove it as it was not there before attempting SWB restore - addressBookService.removeContact(id); + await addressBookService.removeContact(id); } } } @@ -898,7 +959,7 @@ abstract class SWB { // no pre nodes found so we delete all but defaults for (final node in currentNodes) { if (!node.isDefault) { - nodeService.delete(node.id, true); + await nodeService.delete(node.id, true); } } } else { @@ -912,7 +973,7 @@ abstract class SWB { if (nodeData != null) { // node existed before restore attempt // revert to pre restore node - nodeService.edit( + await nodeService.edit( node.copyWith( host: nodeData['host'] as String, port: nodeData['port'] as int, @@ -927,7 +988,7 @@ abstract class SWB { nodeData['password'] as String?, true); } else { - nodeService.delete(node.id, true); + await nodeService.delete(node.id, true); } } } @@ -951,7 +1012,7 @@ abstract class SWB { // no trade history found pre restore attempt so we delete anything that // was added during the restore attempt for (final tradeTx in currentTrades) { - tradesService.delete(trade: tradeTx, shouldNotifyListeners: true); + await tradesService.delete(trade: tradeTx, shouldNotifyListeners: true); } } else { final Map preTradeMap = {}; @@ -964,13 +1025,14 @@ abstract class SWB { if (tradeData != null) { // trade existed before attempted restore so we don't delete it, only // revert data to pre restore state - tradesService.edit( + await tradesService.edit( trade: ExchangeTransaction.fromJson( tradeData as Map), shouldNotifyListeners: true); } else { // trade did not exist before so we delete it - tradesService.delete(trade: tradeTx, shouldNotifyListeners: true); + await tradesService.delete( + trade: tradeTx, shouldNotifyListeners: true); } } } @@ -982,7 +1044,7 @@ abstract class SWB { if (tradeNotes == null) { for (final noteEntry in currentNotes.entries) { - tradeNotesService.delete(tradeId: noteEntry.key); + await tradeNotesService.delete(tradeId: noteEntry.key); } } else { // grab all trade IDs of (reverted to pre state) trades @@ -991,7 +1053,7 @@ abstract class SWB { // delete all notes that don't correspond to an id that we have for (final noteEntry in currentNotes.entries) { if (!idsToKeep.contains(noteEntry.key)) { - tradeNotesService.delete(tradeId: noteEntry.key); + await tradeNotesService.delete(tradeId: noteEntry.key); } } } @@ -1009,7 +1071,7 @@ abstract class SWB { for (int i = 0; i < tradeTxidLookupData.length; i++) { final json = Map.from(tradeTxidLookupData[i] as Map); TradeWalletLookup lookup = TradeWalletLookup.fromJson(json); - tradeTxidLookupDataService.save(tradeWalletLookup: lookup); + await tradeTxidLookupDataService.save(tradeWalletLookup: lookup); } } @@ -1127,14 +1189,14 @@ abstract class SWB { ) async { final tradesService = TradesService(); for (int i = 0; i < trades.length - 1; i++) { - tradesService.add( + await tradesService.add( trade: ExchangeTransaction.fromJson(trades[i] as Map), shouldNotifyListeners: false, ); } // only call notifyListeners on last one added if (trades.isNotEmpty) { - tradesService.add( + await tradesService.add( trade: ExchangeTransaction.fromJson(trades.last as Map), shouldNotifyListeners: true, @@ -1177,7 +1239,7 @@ abstract class SWB { } } - tradeTxidLookupDataService.save(tradeWalletLookup: lookup); + await tradeTxidLookupDataService.save(tradeWalletLookup: lookup); } } @@ -1186,7 +1248,8 @@ abstract class SWB { ) async { final tradeNotesService = TradeNotesService(); for (final note in tradeNotes.entries) { - tradeNotesService.set(tradeId: note.key, note: note.value as String); + await tradeNotesService.set( + tradeId: note.key, note: note.value as String); } } } From 02bc6060f5d61088e6fca8104e210f3aa7fb55ed Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 17:00:21 -0600 Subject: [PATCH 17/18] wow min confirms updated to match standard network requirements --- lib/services/coins/wownero/wownero_wallet.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/coins/wownero/wownero_wallet.dart b/lib/services/coins/wownero/wownero_wallet.dart index 7114269ec..4f7cf9706 100644 --- a/lib/services/coins/wownero/wownero_wallet.dart +++ b/lib/services/coins/wownero/wownero_wallet.dart @@ -51,7 +51,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; -const int MINIMUM_CONFIRMATIONS = 10; +const int MINIMUM_CONFIRMATIONS = 4; //https://github.com/wownero-project/wownero/blob/8361d60aef6e17908658128284899e3a11d808d4/src/cryptonote_config.h#L162 const String GENESIS_HASH_MAINNET = From c9a064e3f6038c6094989f8fc00f3f173cf4ffdd Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 30 Sep 2022 17:24:23 -0600 Subject: [PATCH 18/18] temp trade history fix --- lib/pages/wallet_view/sub_widgets/transactions_list.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/wallet_view/sub_widgets/transactions_list.dart b/lib/pages/wallet_view/sub_widgets/transactions_list.dart index 64e1266d9..f95e75997 100644 --- a/lib/pages/wallet_view/sub_widgets/transactions_list.dart +++ b/lib/pages/wallet_view/sub_widgets/transactions_list.dart @@ -138,7 +138,7 @@ class _TransactionsListState extends ConsumerState { e.statusObject != null && (e.statusObject!.payinHash == tx.txid || e.statusObject!.payoutHash == tx.txid)); - if (matchingTrades.isNotEmpty) { + if (tx.txType == "Sent" && matchingTrades.isNotEmpty) { final trade = matchingTrades.first; return Container( decoration: BoxDecoration(