From 218017ca51177c38ed62411724a8f8bc69922d8b Mon Sep 17 00:00:00 2001 From: julian <julian@cypherstack.com> Date: Fri, 10 Feb 2023 08:04:12 -0600 Subject: [PATCH 1/6] populate initial values in exchange form --- lib/main.dart | 3 ++ lib/models/exchange/exchange_form_state.dart | 2 +- .../exchange_currency_selection_view.dart | 4 ++ lib/pages/exchange_view/exchange_view.dart | 10 +++- .../wallet_initiated_exchange_view.dart | 11 ++++- .../desktop_exchange_view.dart | 11 ++++- .../exchange_data_loading_service.dart | 49 +++++++++++++++++++ 7 files changed, 83 insertions(+), 7 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index b83a89354..11c694fff 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -294,6 +294,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme> await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) { if (Constants.enableExchange) { await ExchangeDataLoadingService.instance.init(); + await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( + ref.read(exchangeFormStateProvider), + ); unawaited(ExchangeDataLoadingService.instance.loadAll()); } // if (Constants.enableBuy) { diff --git a/lib/models/exchange/exchange_form_state.dart b/lib/models/exchange/exchange_form_state.dart index c96f7df34..32578ebd9 100644 --- a/lib/models/exchange/exchange_form_state.dart +++ b/lib/models/exchange/exchange_form_state.dart @@ -163,7 +163,7 @@ class ExchangeFormState extends ChangeNotifier { } } - void setCurrencies(AggregateCurrency from, AggregateCurrency to) { + void setCurrencies(AggregateCurrency? from, AggregateCurrency? to) { _sendCurrency = from; _receiveCurrency = to; } 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 6d1956256..069e863e4 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 @@ -108,6 +108,8 @@ class _ExchangeCurrencySelectionViewState return ExchangeDataLoadingService.instance.isar.currencies .where() .filter() + .isFiatEqualTo(false) + .and() .tickerEqualTo(ticker, caseSensitive: false) .group((q) => widget.isFixedRate ? q @@ -150,6 +152,8 @@ class _ExchangeCurrencySelectionViewState return ExchangeDataLoadingService.instance.isar.currencies .where() .filter() + .isFiatEqualTo(false) + .and() .group((q) => widget.isFixedRate ? q .rateTypeEqualTo(SupportedRateType.both) diff --git a/lib/pages/exchange_view/exchange_view.dart b/lib/pages/exchange_view/exchange_view.dart index 054ced189..f96ed39c3 100644 --- a/lib/pages/exchange_view/exchange_view.dart +++ b/lib/pages/exchange_view/exchange_view.dart @@ -36,7 +36,10 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> { ExchangeDataLoadingService.cacheVersion) { _initialCachePopulationUnderway = true; ExchangeDataLoadingService.instance.onLoadingComplete = () { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( + ref.read(exchangeFormStateProvider), + ); setState(() { _initialCachePopulationUnderway = false; }); @@ -51,7 +54,10 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> { ExchangeDataLoadingService.cacheVersion) { _initialCachePopulationUnderway = true; ExchangeDataLoadingService.instance.onLoadingComplete = () { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( + ref.read(exchangeFormStateProvider), + ); setState(() { _initialCachePopulationUnderway = false; }); diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index e6ee7d3a3..bfdb5e9cd 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/exchange_view/exchange_form.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; +import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; @@ -48,7 +49,10 @@ class _WalletInitiatedExchangeViewState ExchangeDataLoadingService.cacheVersion) { _initialCachePopulationUnderway = true; ExchangeDataLoadingService.instance.onLoadingComplete = () { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( + ref.read(exchangeFormStateProvider), + ); setState(() { _initialCachePopulationUnderway = false; }); @@ -63,7 +67,10 @@ class _WalletInitiatedExchangeViewState ExchangeDataLoadingService.cacheVersion) { _initialCachePopulationUnderway = true; ExchangeDataLoadingService.instance.onLoadingComplete = () { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( + ref.read(exchangeFormStateProvider), + ); setState(() { _initialCachePopulationUnderway = false; }); diff --git a/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart b/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart index 19484e376..39680fab0 100644 --- a/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart +++ b/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/exchange_view/exchange_form.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart'; +import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/utilities/text_styles.dart'; @@ -32,7 +33,10 @@ class _DesktopExchangeViewState extends ConsumerState<DesktopExchangeView> { ExchangeDataLoadingService.cacheVersion) { _initialCachePopulationUnderway = true; ExchangeDataLoadingService.instance.onLoadingComplete = () { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( + ref.read(exchangeFormStateProvider), + ); setState(() { _initialCachePopulationUnderway = false; }); @@ -47,7 +51,10 @@ class _DesktopExchangeViewState extends ConsumerState<DesktopExchangeView> { ExchangeDataLoadingService.cacheVersion) { _initialCachePopulationUnderway = true; ExchangeDataLoadingService.instance.onLoadingComplete = () { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty( + ref.read(exchangeFormStateProvider), + ); setState(() { _initialCachePopulationUnderway = false; }); diff --git a/lib/services/exchange/exchange_data_loading_service.dart b/lib/services/exchange/exchange_data_loading_service.dart index 3d29e038d..f6d2876c9 100644 --- a/lib/services/exchange/exchange_data_loading_service.dart +++ b/lib/services/exchange/exchange_data_loading_service.dart @@ -1,12 +1,16 @@ import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; import 'package:stackwallet/hive/db.dart'; +import 'package:stackwallet/models/exchange/aggregate_currency.dart'; +import 'package:stackwallet/models/exchange/exchange_form_state.dart'; import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; +import 'package:tuple/tuple.dart'; class ExchangeDataLoadingService { ExchangeDataLoadingService._(); @@ -50,6 +54,51 @@ class ExchangeDataLoadingService { ); } + Future<void> setCurrenciesIfEmpty(ExchangeFormState state) async { + if (state.sendCurrency == null && state.receiveCurrency == null) { + if (await isar.currencies.count() > 0) { + final sendCurrency = await getAggregateCurrency( + "BTC", + state.exchangeRateType, + ); + final receiveCurrency = await getAggregateCurrency( + "XMR", + state.exchangeRateType, + ); + state.setCurrencies(sendCurrency, receiveCurrency); + } + } + } + + Future<AggregateCurrency?> getAggregateCurrency( + String ticker, ExchangeRateType rateType) async { + final currencies = await ExchangeDataLoadingService.instance.isar.currencies + .filter() + .group((q) => rateType == ExchangeRateType.fixed + ? q + .rateTypeEqualTo(SupportedRateType.both) + .or() + .rateTypeEqualTo(SupportedRateType.fixed) + : q + .rateTypeEqualTo(SupportedRateType.both) + .or() + .rateTypeEqualTo(SupportedRateType.estimated)) + .and() + .tickerEqualTo( + ticker, + caseSensitive: false, + ) + .findAll(); + + final items = currencies + .map((e) => Tuple2(e.exchangeName, e)) + .toList(growable: false); + + return items.isNotEmpty + ? AggregateCurrency(exchangeCurrencyPairs: items) + : null; + } + bool get isLoading => _locked; bool _locked = false; From c275f0986976c85eebbdd4e9888f645a74edce36 Mon Sep 17 00:00:00 2001 From: julian <julian@cypherstack.com> Date: Fri, 10 Feb 2023 08:25:03 -0600 Subject: [PATCH 2/6] WIP restore mnemonic password ui --- .../restore_options_view.dart | 140 ++++++++++-------- 1 file changed, 82 insertions(+), 58 deletions(-) diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart index 213bee484..884ee09e0 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart @@ -468,9 +468,10 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { header: Container( color: Colors.transparent, child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16, + padding: const EdgeInsets.only( + top: 8.0, + bottom: 8.0, + right: 10, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -504,67 +505,90 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> { ), body: Container( color: Colors.transparent, - child: ClipRRect( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - child: TextField( - key: const Key("mnemonicPassphraseFieldKey1"), - focusNode: passwordFocusNode, - controller: passwordController, - style: isDesktop - ? STextStyles.desktopTextMedium(context).copyWith( - height: 2, - ) - : STextStyles.field(context), - obscureText: hidePassword, - enableSuggestions: false, - autocorrect: false, - decoration: standardInputDecoration( - "Recovery phrase password", - passwordFocusNode, - context, - ).copyWith( - suffixIcon: UnconstrainedBox( - child: ConditionalParent( - condition: isDesktop, - builder: (child) => SizedBox( - height: 70, - child: child, - ), - child: Row( - children: [ - SizedBox( - width: isDesktop ? 24 : 16, + child: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + key: const Key("mnemonicPassphraseFieldKey1"), + focusNode: passwordFocusNode, + controller: passwordController, + style: isDesktop + ? STextStyles.desktopTextMedium(context) + .copyWith( + height: 2, + ) + : STextStyles.field(context), + obscureText: hidePassword, + enableSuggestions: false, + autocorrect: false, + decoration: standardInputDecoration( + "Recovery phrase password", + passwordFocusNode, + context, + ).copyWith( + suffixIcon: UnconstrainedBox( + child: ConditionalParent( + condition: isDesktop, + builder: (child) => SizedBox( + height: 70, + child: child, ), - GestureDetector( - key: const Key( - "mnemonicPassphraseFieldShowPasswordButtonKey"), - onTap: () async { - setState(() { - hidePassword = !hidePassword; - }); - }, - child: SvgPicture.asset( - hidePassword - ? Assets.svg.eye - : Assets.svg.eyeSlash, - color: Theme.of(context) - .extension<StackColors>()! - .textDark3, - width: isDesktop ? 24 : 16, - height: isDesktop ? 24 : 16, - ), + child: Row( + children: [ + SizedBox( + width: isDesktop ? 24 : 16, + ), + GestureDetector( + key: const Key( + "mnemonicPassphraseFieldShowPasswordButtonKey"), + onTap: () async { + setState(() { + hidePassword = !hidePassword; + }); + }, + child: SvgPicture.asset( + hidePassword + ? Assets.svg.eye + : Assets.svg.eyeSlash, + color: Theme.of(context) + .extension<StackColors>()! + .textDark3, + width: isDesktop ? 24 : 16, + height: isDesktop ? 24 : 16, + ), + ), + const SizedBox( + width: 12, + ), + ], ), - const SizedBox( - width: 12, - ), - ], + ), ), ), ), ), - ), + const SizedBox( + height: 8, + ), + RoundedWhiteContainer( + child: Center( + child: Text( + "If the recovery phrase you are about to restore was created with an optional passphrase you can enter it here.", + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textSubtitle1, + ) + : STextStyles.itemSubtitle(context), + ), + ), + ), + ], ), ), ), From 279d37c06eeff8b128d38681ab94db41dbb9b244 Mon Sep 17 00:00:00 2001 From: julian <julian@cypherstack.com> Date: Fri, 10 Feb 2023 11:51:54 -0600 Subject: [PATCH 3/6] paynym send bug fix --- lib/services/mixins/paynym_wallet_interface.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/mixins/paynym_wallet_interface.dart b/lib/services/mixins/paynym_wallet_interface.dart index 697e00b53..dd5a2a814 100644 --- a/lib/services/mixins/paynym_wallet_interface.dart +++ b/lib/services/mixins/paynym_wallet_interface.dart @@ -306,7 +306,7 @@ mixin PaynymWalletInterface { {required PaymentCode paymentCode, required int satoshiAmount, Map<String, dynamic>? args}) async { - if (!(await hasConnected(paymentCode.notificationAddressP2PKH()))) { + if (!(await hasConnected(paymentCode.toString()))) { throw PaynymSendException( "No notification transaction sent to $paymentCode"); } else { From d5f401132bd7476f2046ff5b9ef950847797bc12 Mon Sep 17 00:00:00 2001 From: julian <julian@cypherstack.com> Date: Fri, 10 Feb 2023 12:07:57 -0600 Subject: [PATCH 4/6] Desktop paynym ui and some bug fixes --- lib/pages/paynym/paynym_home_view.dart | 1 + .../subwidgets/desktop_paynym_details.dart | 11 +- .../send_view/confirm_transaction_view.dart | 159 ++--- lib/pages/send_view/send_view.dart | 38 -- .../paynym/desktop_paynym_send_dialog.dart | 197 ++++++ .../wallet_view/sub_widgets/desktop_send.dart | 613 ++++++++---------- 6 files changed, 557 insertions(+), 462 deletions(-) create mode 100644 lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart diff --git a/lib/pages/paynym/paynym_home_view.dart b/lib/pages/paynym/paynym_home_view.dart index 9292b8acb..b989ba9c5 100644 --- a/lib/pages/paynym/paynym_home_view.dart +++ b/lib/pages/paynym/paynym_home_view.dart @@ -559,6 +559,7 @@ class _PaynymHomeViewState extends ConsumerState<PaynymHomeView> { height: isDesktop ? 56 : 48, width: isDesktop ? 490 : null, child: Toggle( + key: UniqueKey(), onColor: Theme.of(context).extension<StackColors>()!.popupBG, onText: "Following (${ref.watch(myPaynymAccountStateProvider.state).state?.following.length ?? 0})", diff --git a/lib/pages/paynym/subwidgets/desktop_paynym_details.dart b/lib/pages/paynym/subwidgets/desktop_paynym_details.dart index 2f7f05e9a..ad01b1f7e 100644 --- a/lib/pages/paynym/subwidgets/desktop_paynym_details.dart +++ b/lib/pages/paynym/subwidgets/desktop_paynym_details.dart @@ -11,6 +11,7 @@ import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/paynym/dialogs/confirm_paynym_connect_dialog.dart'; import 'package:stackwallet/pages/paynym/subwidgets/paynym_bot.dart'; import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart'; +import 'package:stackwallet/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -102,8 +103,6 @@ class _PaynymDetailsPopupState extends ConsumerState<DesktopPaynymDetails> { builder: (context) => ConfirmPaynymConnectDialog( nymName: widget.accountLite.nymName, onConfirmPressed: () { - // - print("CONFIRM NOTIF TX: $preparedTx"); Navigator.of(context, rootNavigator: true).pop(); unawaited( showDialog( @@ -148,7 +147,13 @@ class _PaynymDetailsPopupState extends ConsumerState<DesktopPaynymDetails> { } Future<void> _onSend() async { - print("sned"); + await showDialog<void>( + context: context, + builder: (context) => DesktopPaynymSendDialog( + walletId: widget.walletId, + accountLite: widget.accountLite, + ), + ); } @override diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart index f56911a63..8ad9f90fc 100644 --- a/lib/pages/send_view/confirm_transaction_view.dart +++ b/lib/pages/send_view/confirm_transaction_view.dart @@ -586,7 +586,9 @@ class _ConfirmTransactionViewState crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Send to", + widget.isPaynymTransaction + ? "PayNym recipient" + : "Send to", style: STextStyles.desktopTextExtraExtraSmall( context), ), @@ -594,7 +596,11 @@ class _ConfirmTransactionViewState height: 2, ), Text( - "${transactionInfo["address"] ?? "ERROR"}", + widget.isPaynymTransaction + ? (transactionInfo["paynymAccountLite"] + as PaynymAccountLite) + .nymName + : "${transactionInfo["address"] ?? "ERROR"}", style: STextStyles.desktopTextExtraExtraSmall( context) .copyWith( @@ -606,6 +612,64 @@ class _ConfirmTransactionViewState ], ), ), + if (widget.isPaynymTransaction) + Container( + height: 1, + color: Theme.of(context) + .extension<StackColors>()! + .background, + ), + if (widget.isPaynymTransaction) + Padding( + padding: const EdgeInsets.all(12), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Transaction fee", + style: STextStyles.desktopTextExtraExtraSmall( + context), + ), + const SizedBox( + height: 2, + ), + Builder( + builder: (context) { + final coin = ref + .watch(walletsChangeNotifierProvider + .select((value) => + value.getManager(walletId))) + .coin; + + final fee = Format.satoshisToAmount( + transactionInfo["fee"] as int, + coin: coin, + ); + + return Text( + "${Format.localizedStringAsFixed( + value: fee, + locale: ref.watch( + localeServiceChangeNotifierProvider + .select((value) => value.locale)), + decimalPlaces: + Constants.decimalPlacesForCoin(coin), + )} ${coin.ticker}", + style: + STextStyles.desktopTextExtraExtraSmall( + context) + .copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textDark, + ), + ); + }, + ), + ], + ), + ), // Container( // height: 1, // color: Theme.of(context) @@ -725,7 +789,7 @@ class _ConfirmTransactionViewState ], ), ), - if (isDesktop) + if (isDesktop && !widget.isPaynymTransaction) Padding( padding: const EdgeInsets.only( left: 32, @@ -735,22 +799,23 @@ class _ConfirmTransactionViewState style: STextStyles.desktopTextExtraExtraSmall(context), ), ), - if (isDesktop) + if (isDesktop && !widget.isPaynymTransaction) Padding( - padding: const EdgeInsets.only( - top: 10, - left: 32, - right: 32, + padding: const EdgeInsets.only( + top: 10, + left: 32, + right: 32, + ), + child: RoundedContainer( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 18, ), - child: RoundedContainer( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 18, - ), - color: Theme.of(context) - .extension<StackColors>()! - .textFieldDefaultBG, - child: Builder(builder: (context) { + color: Theme.of(context) + .extension<StackColors>()! + .textFieldDefaultBG, + child: Builder( + builder: (context) { final coin = ref .watch(walletsChangeNotifierProvider .select((value) => value.getManager(walletId))) @@ -770,64 +835,10 @@ class _ConfirmTransactionViewState )} ${coin.ticker}", style: STextStyles.itemSubtitle(context), ); - }), - ) - // DropdownButtonHideUnderline( - // child: DropdownButton2( - // offset: const Offset(0, -10), - // isExpanded: true, - // - // dropdownElevation: 0, - // value: _fee, - // items: [ - // ..._dropDownItems.map( - // (e) { - // String message = _fee.toString(); - // - // return DropdownMenuItem( - // value: e, - // child: Text(message), - // ); - // }, - // ), - // ], - // onChanged: (value) { - // if (value is int) { - // setState(() { - // _fee = value; - // }); - // } - // }, - // icon: SvgPicture.asset( - // Assets.svg.chevronDown, - // width: 12, - // height: 6, - // color: - // Theme.of(context).extension<StackColors>()!.textDark3, - // ), - // buttonPadding: const EdgeInsets.symmetric( - // horizontal: 16, - // vertical: 8, - // ), - // buttonDecoration: BoxDecoration( - // color: Theme.of(context) - // .extension<StackColors>()! - // .textFieldDefaultBG, - // borderRadius: BorderRadius.circular( - // Constants.size.circularBorderRadius, - // ), - // ), - // dropdownDecoration: BoxDecoration( - // color: Theme.of(context) - // .extension<StackColors>()! - // .textFieldDefaultBG, - // borderRadius: BorderRadius.circular( - // Constants.size.circularBorderRadius, - // ), - // ), - // ), - // ), + }, ), + ), + ), if (!isDesktop) const Spacer(), SizedBox( height: isDesktop ? 23 : 12, diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart index eab3d0638..fb05f3a38 100644 --- a/lib/pages/send_view/send_view.dart +++ b/lib/pages/send_view/send_view.dart @@ -297,44 +297,6 @@ class _SendViewState extends ConsumerState<SendView> { final manager = ref.read(walletsChangeNotifierProvider).getManager(walletId); - // // TODO: remove the need for this!! - // final bool isOwnAddress = - // await manager.isOwnAddress(_address!); - // if (isOwnAddress && coin != Coin.dogecoinTestNet) { - // await showDialog<dynamic>( - // context: context, - // useSafeArea: false, - // barrierDismissible: true, - // builder: (context) { - // return StackDialog( - // title: "Transaction failed", - // message: - // "Sending to self is currently disabled", - // rightButton: TextButton( - // style: Theme.of(context) - // .extension<StackColors>()! - // .getSecondaryEnabledButtonColor( - // context), - // child: Text( - // "Ok", - // style: STextStyles.button( - // context) - // .copyWith( - // color: Theme.of(context) - // .extension< - // StackColors>()! - // .accentColorDark), - // ), - // onPressed: () { - // Navigator.of(context).pop(); - // }, - // ), - // ); - // }, - // ); - // return; - // } - final amount = Format.decimalAmountToSatoshis(_amountToSend!, coin); int availableBalance; if ((coin == Coin.firo || coin == Coin.firoTestNet)) { diff --git a/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart b/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart new file mode 100644 index 000000000..df24e69c3 --- /dev/null +++ b/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart @@ -0,0 +1,197 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/models/paynym/paynym_account_lite.dart'; +import 'package:stackwallet/models/send_view_auto_fill_data.dart'; +import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart'; +import 'package:stackwallet/providers/global/locale_provider.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/providers/global/price_provider.dart'; +import 'package:stackwallet/providers/global/wallets_provider.dart'; +import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart'; +import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; +import 'package:stackwallet/utilities/clipboard_interface.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/format.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; +import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; + +class DesktopPaynymSendDialog extends ConsumerStatefulWidget { + const DesktopPaynymSendDialog({ + Key? key, + required this.walletId, + this.autoFillData, + this.clipboard = const ClipboardWrapper(), + this.barcodeScanner = const BarcodeScannerWrapper(), + this.accountLite, + }) : super(key: key); + + final String walletId; + final SendViewAutoFillData? autoFillData; + final ClipboardInterface clipboard; + final BarcodeScannerInterface barcodeScanner; + final PaynymAccountLite? accountLite; + + @override + ConsumerState<DesktopPaynymSendDialog> createState() => + _DesktopPaynymSendDialogState(); +} + +class _DesktopPaynymSendDialogState + extends ConsumerState<DesktopPaynymSendDialog> { + @override + Widget build(BuildContext context) { + final manager = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getManager(widget.walletId))); + final String locale = ref.watch( + localeServiceChangeNotifierProvider.select((value) => value.locale)); + + final coin = manager.coin; + + final isFiro = coin == Coin.firo || coin == Coin.firoTestNet; + + return DesktopDialog( + maxHeight: double.infinity, + maxWidth: 580, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(left: 32), + child: Text( + "Send ${manager.coin.ticker.toUpperCase()}", + style: STextStyles.desktopH3(context), + ), + ), + const DesktopDialogCloseButton(), + ], + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: RoundedWhiteContainer( + borderColor: + Theme.of(context).extension<StackColors>()!.background, + // Theme.of(context).extension<StackColors>()!.textSubtitle4, + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 36, + height: 36, + ), + const SizedBox( + width: 12, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + manager.walletName, + style: STextStyles.titleBold12(context), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + const SizedBox( + height: 2, + ), + Text( + isFiro + ? "${ref.watch(publicPrivateBalanceStateProvider.state).state} balance" + : "Available balance", + style: STextStyles.baseXS(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textSubtitle1, + ), + ), + ], + ), + const Spacer(), + Container( + color: Colors.transparent, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + "${Format.localizedStringAsFixed( + value: !isFiro + ? manager.balance.getSpendable() + : ref + .watch( + publicPrivateBalanceStateProvider + .state) + .state == + "Private" + ? (manager.wallet as FiroWallet) + .availablePrivateBalance() + : (manager.wallet as FiroWallet) + .availablePublicBalance(), + locale: locale, + decimalPlaces: 8, + )} ${coin.ticker}", + style: STextStyles.titleBold12(context), + textAlign: TextAlign.right, + ), + const SizedBox( + height: 2, + ), + Text( + "${Format.localizedStringAsFixed( + value: (!isFiro + ? manager.balance.getSpendable() + : ref + .watch( + publicPrivateBalanceStateProvider + .state) + .state == + "Private" + ? (manager.wallet as FiroWallet) + .availablePrivateBalance() + : (manager.wallet as FiroWallet) + .availablePublicBalance()) * + ref.watch( + priceAnd24hChangeNotifierProvider.select( + (value) => value.getPrice(coin).item1)), + locale: locale, + decimalPlaces: 2, + )} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.baseXS(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textSubtitle1, + ), + textAlign: TextAlign.right, + ) + ], + ), + ), + ], + ), + ), + ), + const SizedBox( + height: 20, + ), + Padding( + padding: const EdgeInsets.only( + left: 32, + right: 32, + bottom: 32, + ), + child: DesktopSend( + walletId: manager.walletId, + accountLite: widget.accountLite, + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart index cc63c67a8..09ed16610 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:bip47/bip47.dart'; import 'package:decimal/decimal.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; @@ -7,6 +8,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stackwallet/models/contact_address_entry.dart'; +import 'package:stackwallet/models/paynym/paynym_account_lite.dart'; import 'package:stackwallet/models/send_view_auto_fill_data.dart'; import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart'; import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart'; @@ -20,6 +22,7 @@ import 'package:stackwallet/providers/ui/preview_tx_button_state_provider.dart'; import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; import 'package:stackwallet/services/coins/manager.dart'; +import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; @@ -51,12 +54,14 @@ class DesktopSend extends ConsumerStatefulWidget { this.autoFillData, this.clipboard = const ClipboardWrapper(), this.barcodeScanner = const BarcodeScannerWrapper(), + this.accountLite, }) : super(key: key); final String walletId; final SendViewAutoFillData? autoFillData; final ClipboardInterface clipboard; final BarcodeScannerInterface barcodeScanner; + final PaynymAccountLite? accountLite; @override ConsumerState<DesktopSend> createState() => _DesktopSendState(); @@ -93,78 +98,12 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { bool _cryptoAmountChangeLock = false; late VoidCallback onCryptoAmountChanged; + bool get isPaynymSend => widget.accountLite != null; + Future<void> previewSend() async { final manager = ref.read(walletsChangeNotifierProvider).getManager(walletId); - // // TODO: remove the need for this!! - // final bool isOwnAddress = await manager.isOwnAddress(_address!); - // if (isOwnAddress) { - // await showDialog<dynamic>( - // context: context, - // useSafeArea: false, - // barrierDismissible: true, - // builder: (context) { - // return DesktopDialog( - // maxWidth: 400, - // maxHeight: double.infinity, - // child: Padding( - // padding: const EdgeInsets.only( - // left: 32, - // bottom: 32, - // ), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // Text( - // "Transaction failed", - // style: STextStyles.desktopH3(context), - // ), - // const DesktopDialogCloseButton(), - // ], - // ), - // const SizedBox( - // height: 12, - // ), - // Text( - // "Sending to self is currently disabled", - // textAlign: TextAlign.left, - // style: STextStyles.desktopTextExtraExtraSmall(context) - // .copyWith( - // fontSize: 18, - // ), - // ), - // const SizedBox( - // height: 40, - // ), - // Row( - // children: [ - // Expanded( - // child: SecondaryButton( - // buttonHeight: ButtonHeight.l, - // label: "Ok", - // onPressed: () { - // Navigator.of(context).pop(); - // }, - // ), - // ), - // const SizedBox( - // width: 32, - // ), - // ], - // ), - // ], - // ), - // ), - // ); - // }, - // ); - // return; - // } - final amount = Format.decimalAmountToSatoshis(_amountToSend!, coin); int availableBalance; if ((coin == Coin.firo || coin == Coin.firoTestNet)) { @@ -304,7 +243,19 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { Map<String, dynamic> txData; - if ((coin == Coin.firo || coin == Coin.firoTestNet) && + if (isPaynymSend) { + final wallet = manager.wallet as PaynymWalletInterface; + final paymentCode = PaymentCode.fromPaymentCode( + widget.accountLite!.code, + wallet.networkType, + ); + final feeRate = ref.read(feeRateTypeStateProvider); + txData = await wallet.preparePaymentCodeSend( + paymentCode: paymentCode, + satoshiAmount: amount, + args: {"feeRate": feeRate}, + ); + } else if ((coin == Coin.firo || coin == Coin.firoTestNet) && ref.read(publicPrivateBalanceStateProvider.state).state != "Private") { txData = await (manager.wallet as FiroWallet).prepareSendPublic( @@ -321,8 +272,13 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { } if (!wasCancelled && mounted) { - txData["note"] = _note ?? ""; - txData["address"] = _address; + if (isPaynymSend) { + txData["paynymAccountLite"] = widget.accountLite!; + txData["note"] = _note ?? "PayNym send"; + } else { + txData["address"] = _address; + txData["note"] = _note ?? ""; + } // pop building dialog Navigator.of( context, @@ -338,6 +294,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { child: ConfirmTransactionView( transactionInfo: txData, walletId: walletId, + isPaynymTransaction: isPaynymSend, routeOnSuccessName: DesktopHomeView.routeName, ), ), @@ -439,9 +396,9 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { _cachedAmountToSend == _amountToSend) { return; } - _cachedAmountToSend = _amountToSend; Logging.instance.log("it changed $_amountToSend $_cachedAmountToSend", level: LogLevel.Info); + _cachedAmountToSend = _amountToSend; final price = ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1; @@ -457,6 +414,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { } } else { _amountToSend = null; + _cachedAmountToSend = null; baseAmountController.text = ""; } @@ -475,87 +433,19 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { } void _updatePreviewButtonState(String? address, Decimal? amount) { - final isValidAddress = ref - .read(walletsChangeNotifierProvider) - .getManager(walletId) - .validateAddress(address ?? ""); - ref.read(previewTxButtonStateProvider.state).state = - (isValidAddress && amount != null && amount > Decimal.zero); + if (isPaynymSend) { + ref.read(previewTxButtonStateProvider.state).state = + (amount != null && amount > Decimal.zero); + } else { + final isValidAddress = ref + .read(walletsChangeNotifierProvider) + .getManager(walletId) + .validateAddress(address ?? ""); + ref.read(previewTxButtonStateProvider.state).state = + (isValidAddress && amount != null && amount > Decimal.zero); + } } - // late Future<String> _calculateFeesFuture; - - // Map<int, String> cachedFees = {}; - // Map<int, String> cachedFiroPrivateFees = {}; - // Map<int, String> cachedFiroPublicFees = {}; - - // Future<String> calculateFees(int amount) async { - // if (amount <= 0) { - // return "0"; - // } - // - // if (coin == Coin.firo || coin == Coin.firoTestNet) { - // if (ref.read(publicPrivateBalanceStateProvider.state).state == - // "Private") { - // if (cachedFiroPrivateFees[amount] != null) { - // return cachedFiroPrivateFees[amount]!; - // } - // } else { - // if (cachedFiroPublicFees[amount] != null) { - // return cachedFiroPublicFees[amount]!; - // } - // } - // } else if (cachedFees[amount] != null) { - // return cachedFees[amount]!; - // } - // - // final manager = - // ref.read(walletsChangeNotifierProvider).getManager(walletId); - // final feeObject = await manager.fees; - // - // late final int feeRate; - // - // switch (ref.read(feeRateTypeStateProvider.state).state) { - // case FeeRateType.fast: - // feeRate = feeObject.fast; - // break; - // case FeeRateType.average: - // feeRate = feeObject.medium; - // break; - // case FeeRateType.slow: - // feeRate = feeObject.slow; - // break; - // } - // - // int fee; - // - // if (coin == Coin.firo || coin == Coin.firoTestNet) { - // if (ref.read(publicPrivateBalanceStateProvider.state).state == - // "Private") { - // fee = await manager.estimateFeeFor(amount, feeRate); - // - // cachedFiroPrivateFees[amount] = Format.satoshisToAmount(fee) - // .toStringAsFixed(Constants.decimalPlaces); - // - // return cachedFiroPrivateFees[amount]!; - // } else { - // fee = await (manager.wallet as FiroWallet) - // .estimateFeeForPublic(amount, feeRate); - // - // cachedFiroPublicFees[amount] = Format.satoshisToAmount(fee) - // .toStringAsFixed(Constants.decimalPlaces); - // - // return cachedFiroPublicFees[amount]!; - // } - // } else { - // fee = await manager.estimateFeeFor(amount, feeRate); - // cachedFees[amount] = - // Format.satoshisToAmount(fee).toStringAsFixed(Constants.decimalPlaces); - // - // return cachedFees[amount]!; - // } - // } - Future<String?> _firoBalanceFuture( ChangeNotifierProvider<Manager> provider, String locale, @@ -773,7 +663,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { @override void initState() { - ref.refresh(feeSheetSessionCacheProvider); + WidgetsBinding.instance.addPostFrameCallback((_) { + ref.refresh(feeSheetSessionCacheProvider); + ref.read(previewTxButtonStateProvider.state).state = false; + }); // _calculateFeesFuture = calculateFees(0); _data = widget.autoFillData; @@ -799,6 +692,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { _addressToggleFlag = true; } + if (isPaynymSend) { + sendToController.text = widget.accountLite!.nymName; + } + _cryptoFocus.addListener(() { if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) { if (_amountToSend == null) { @@ -845,21 +742,6 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { final String locale = ref.watch( localeServiceChangeNotifierProvider.select((value) => value.locale)); - // if (coin == Coin.firo || coin == Coin.firoTestNet) { - // ref.listen(publicPrivateBalanceStateProvider, (previous, next) { - // if (_amountToSend == null) { - // setState(() { - // _calculateFeesFuture = calculateFees(0); - // }); - // } else { - // setState(() { - // _calculateFeesFuture = - // calculateFees(Format.decimalAmountToSatoshis(_amountToSend!)); - // }); - // } - // }); - // } - return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -975,6 +857,36 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { const SizedBox( height: 20, ), + if (isPaynymSend) + Text( + "Send to PayNym address", + style: STextStyles.smallMed12(context), + textAlign: TextAlign.left, + ), + if (isPaynymSend) + const SizedBox( + height: 10, + ), + if (isPaynymSend) + TextField( + key: const Key("sendViewPaynymAddressFieldKey"), + controller: sendToController, + enabled: false, + readOnly: true, + style: STextStyles.desktopTextFieldLabel(context).copyWith( + fontSize: 16, + ), + decoration: const InputDecoration( + contentPadding: EdgeInsets.symmetric( + vertical: 18, + horizontal: 16, + ), + ), + ), + if (isPaynymSend) + const SizedBox( + height: 20, + ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -1020,6 +932,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { ? newValue : oldValue), ], + onChanged: (newValue) {}, decoration: InputDecoration( contentPadding: const EdgeInsets.only( top: 22, @@ -1108,199 +1021,204 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { const SizedBox( height: 20, ), - Text( - "Send to", - style: STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of(context) - .extension<StackColors>()! - .textFieldActiveSearchIconRight, - ), - textAlign: TextAlign.left, - ), - const SizedBox( - height: 10, - ), - ClipRRect( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - child: TextField( - minLines: 1, - maxLines: 5, - key: const Key("sendViewAddressFieldKey"), - controller: sendToController, - readOnly: false, - autocorrect: false, - enableSuggestions: false, - // inputFormatters: <TextInputFormatter>[ - // FilteringTextInputFormatter.allow( - // RegExp("[a-zA-Z0-9]{34}")), - // ], - toolbarOptions: const ToolbarOptions( - copy: false, - cut: false, - paste: true, - selectAll: false, - ), - onChanged: (newValue) { - _address = newValue; - _updatePreviewButtonState(_address, _amountToSend); - - setState(() { - _addressToggleFlag = newValue.isNotEmpty; - }); - }, - focusNode: _addressFocusNode, + if (!isPaynymSend) + Text( + "Send to", style: STextStyles.desktopTextExtraSmall(context).copyWith( color: Theme.of(context) .extension<StackColors>()! - .textFieldActiveText, - height: 1.8, + .textFieldActiveSearchIconRight, ), - decoration: standardInputDecoration( - "Enter ${coin.ticker} address", - _addressFocusNode, - context, - desktopMed: true, - ).copyWith( - contentPadding: const EdgeInsets.only( - left: 16, - top: 11, - bottom: 12, - right: 5, + textAlign: TextAlign.left, + ), + if (!isPaynymSend) + const SizedBox( + height: 10, + ), + if (!isPaynymSend) + ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + minLines: 1, + maxLines: 5, + key: const Key("sendViewAddressFieldKey"), + controller: sendToController, + readOnly: false, + autocorrect: false, + enableSuggestions: false, + // inputFormatters: <TextInputFormatter>[ + // FilteringTextInputFormatter.allow( + // RegExp("[a-zA-Z0-9]{34}")), + // ], + toolbarOptions: const ToolbarOptions( + copy: false, + cut: false, + paste: true, + selectAll: false, ), - suffixIcon: Padding( - padding: sendToController.text.isEmpty - ? const EdgeInsets.only(right: 8) - : const EdgeInsets.only(right: 0), - child: UnconstrainedBox( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _addressToggleFlag - ? TextFieldIconButton( - key: const Key( - "sendViewClearAddressFieldButtonKey"), - onTap: () { - sendToController.text = ""; - _address = ""; - _updatePreviewButtonState( - _address, _amountToSend); - setState(() { - _addressToggleFlag = false; - }); - }, - child: const XIcon(), - ) - : TextFieldIconButton( - key: const Key( - "sendViewPasteAddressFieldButtonKey"), - onTap: pasteAddress, - child: sendToController.text.isEmpty - ? const ClipboardIcon() - : const XIcon(), - ), - if (sendToController.text.isEmpty) - TextFieldIconButton( - key: const Key("sendViewAddressBookButtonKey"), - onTap: () async { - final entry = - await showDialog<ContactAddressEntry?>( - context: context, - builder: (context) => DesktopDialog( - maxWidth: 696, - maxHeight: 600, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only( - left: 32, - ), - child: Text( - "Address book", - style: - STextStyles.desktopH3(context), - ), - ), - const DesktopDialogCloseButton(), - ], - ), - Expanded( - child: AddressBookAddressChooser( - coin: coin, - ), - ), - ], - ), + onChanged: (newValue) { + _address = newValue; + _updatePreviewButtonState(_address, _amountToSend); + + setState(() { + _addressToggleFlag = newValue.isNotEmpty; + }); + }, + focusNode: _addressFocusNode, + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textFieldActiveText, + height: 1.8, + ), + decoration: standardInputDecoration( + "Enter ${coin.ticker} address", + _addressFocusNode, + context, + desktopMed: true, + ).copyWith( + contentPadding: const EdgeInsets.only( + left: 16, + top: 11, + bottom: 12, + right: 5, + ), + suffixIcon: Padding( + padding: sendToController.text.isEmpty + ? const EdgeInsets.only(right: 8) + : const EdgeInsets.only(right: 0), + child: UnconstrainedBox( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _addressToggleFlag + ? TextFieldIconButton( + key: const Key( + "sendViewClearAddressFieldButtonKey"), + onTap: () { + sendToController.text = ""; + _address = ""; + _updatePreviewButtonState( + _address, _amountToSend); + setState(() { + _addressToggleFlag = false; + }); + }, + child: const XIcon(), + ) + : TextFieldIconButton( + key: const Key( + "sendViewPasteAddressFieldButtonKey"), + onTap: pasteAddress, + child: sendToController.text.isEmpty + ? const ClipboardIcon() + : const XIcon(), ), - ); - - if (entry != null) { - sendToController.text = - entry.other ?? entry.label; - - _address = entry.address; - - _updatePreviewButtonState( - _address, - _amountToSend, + if (sendToController.text.isEmpty) + TextFieldIconButton( + key: const Key("sendViewAddressBookButtonKey"), + onTap: () async { + final entry = + await showDialog<ContactAddressEntry?>( + context: context, + builder: (context) => DesktopDialog( + maxWidth: 696, + maxHeight: 600, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 32, + ), + child: Text( + "Address book", + style: STextStyles.desktopH3( + context), + ), + ), + const DesktopDialogCloseButton(), + ], + ), + Expanded( + child: AddressBookAddressChooser( + coin: coin, + ), + ), + ], + ), + ), ); - setState(() { - _addressToggleFlag = true; - }); - } - }, - child: const AddressBookIcon(), - ), - // if (sendToController.text.isEmpty) - // TextFieldIconButton( - // key: const Key("sendViewScanQrButtonKey"), - // onTap: scanQr, - // child: const QrCodeIcon(), - // ) - ], + if (entry != null) { + sendToController.text = + entry.other ?? entry.label; + + _address = entry.address; + + _updatePreviewButtonState( + _address, + _amountToSend, + ); + + setState(() { + _addressToggleFlag = true; + }); + } + }, + child: const AddressBookIcon(), + ), + // if (sendToController.text.isEmpty) + // TextFieldIconButton( + // key: const Key("sendViewScanQrButtonKey"), + // onTap: scanQr, + // child: const QrCodeIcon(), + // ) + ], + ), ), ), ), ), ), - ), - Builder( - builder: (_) { - final error = _updateInvalidAddressText( - _address ?? "", - ref.read(walletsChangeNotifierProvider).getManager(walletId), - ); + if (!isPaynymSend) + Builder( + builder: (_) { + final error = _updateInvalidAddressText( + _address ?? "", + ref.read(walletsChangeNotifierProvider).getManager(walletId), + ); - if (error == null || error.isEmpty) { - return Container(); - } else { - return Align( - alignment: Alignment.topLeft, - child: Padding( - padding: const EdgeInsets.only( - left: 12.0, - top: 4.0, - ), - child: Text( - error, - textAlign: TextAlign.left, - style: STextStyles.label(context).copyWith( - color: - Theme.of(context).extension<StackColors>()!.textError, + if (error == null || error.isEmpty) { + return Container(); + } else { + return Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.only( + left: 12.0, + top: 4.0, + ), + child: Text( + error, + textAlign: TextAlign.left, + style: STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textError, + ), ), ), - ), - ); - } - }, - ), + ); + } + }, + ), // const SizedBox( // height: 20, // ), @@ -1368,9 +1286,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> { // ), // ), // ), - const SizedBox( - height: 20, - ), + if (!isPaynymSend) + const SizedBox( + height: 20, + ), if (coin != Coin.epicCash) Text( "Transaction fee (estimated)", From d8c833548d413f282b7be2f1261d4aefe4f6ff36 Mon Sep 17 00:00:00 2001 From: julian <julian@cypherstack.com> Date: Fri, 10 Feb 2023 14:06:44 -0600 Subject: [PATCH 5/6] gap fix --- lib/pages/wallets_view/sub_widgets/favorite_wallets.dart | 4 ++-- lib/pages/wallets_view/wallets_view.dart | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/pages/wallets_view/sub_widgets/favorite_wallets.dart b/lib/pages/wallets_view/sub_widgets/favorite_wallets.dart index 073747386..5f1098ce4 100644 --- a/lib/pages/wallets_view/sub_widgets/favorite_wallets.dart +++ b/lib/pages/wallets_view/sub_widgets/favorite_wallets.dart @@ -106,12 +106,12 @@ class _FavoriteWalletsState extends ConsumerState<FavoriteWallets> { ManageFavoritesView.routeName, ); }, - ) + ), ], ), ), const SizedBox( - height: 12, + height: 20, ), !hasFavorites ? Padding( diff --git a/lib/pages/wallets_view/wallets_view.dart b/lib/pages/wallets_view/wallets_view.dart index ed970134a..1c7f99e4f 100644 --- a/lib/pages/wallets_view/wallets_view.dart +++ b/lib/pages/wallets_view/wallets_view.dart @@ -5,6 +5,8 @@ import 'package:stackwallet/pages/wallets_view/sub_widgets/all_wallets.dart'; import 'package:stackwallet/pages/wallets_view/sub_widgets/empty_wallets.dart'; import 'package:stackwallet/pages/wallets_view/sub_widgets/favorite_wallets.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; class WalletsView extends ConsumerWidget { const WalletsView({Key? key}) : super(key: key); @@ -22,8 +24,11 @@ class WalletsView extends ConsumerWidget { return SafeArea( child: hasWallets ? Padding( - padding: const EdgeInsets.only( - top: 20, + padding: EdgeInsets.only( + top: ref.watch(colorThemeProvider).themeType == + ThemeType.fruitSorbet + ? 6 + : 20, ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, From 24cdb0ac36d538cb89aa7c3f54e4d664f402cc28 Mon Sep 17 00:00:00 2001 From: julian <julian@cypherstack.com> Date: Fri, 10 Feb 2023 14:17:40 -0600 Subject: [PATCH 6/6] "all wallets" color fix --- lib/pages/wallets_view/sub_widgets/all_wallets.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/wallets_view/sub_widgets/all_wallets.dart b/lib/pages/wallets_view/sub_widgets/all_wallets.dart index b63e8eb6e..4c6e3174f 100644 --- a/lib/pages/wallets_view/sub_widgets/all_wallets.dart +++ b/lib/pages/wallets_view/sub_widgets/all_wallets.dart @@ -21,7 +21,7 @@ class AllWallets extends StatelessWidget { Text( "All wallets", style: STextStyles.itemSubtitle(context).copyWith( - color: Theme.of(context).extension<StackColors>()!.textDark, + color: Theme.of(context).extension<StackColors>()!.textDark3, ), ), CustomTextButton(