From 244a1914b370098151c8751b48ba2a1203349181 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 22 Aug 2023 17:06:30 -0600 Subject: [PATCH] verify mnemonic passphrase dialog --- .../verify_mnemonic_passphrase_dialog.dart | 218 ++++++++++++++++++ .../verify_recovery_phrase_view.dart | 19 ++ lib/widgets/stack_dialog.dart | 9 +- 3 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_mnemonic_passphrase_dialog.dart diff --git a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_mnemonic_passphrase_dialog.dart b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_mnemonic_passphrase_dialog.dart new file mode 100644 index 000000000..3326622ad --- /dev/null +++ b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_mnemonic_passphrase_dialog.dart @@ -0,0 +1,218 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/notifications/show_flush_bar.dart'; +import 'package:stackwallet/pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart'; +import 'package:stackwallet/themes/stack_colors.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; +import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; +import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; +import 'package:stackwallet/widgets/desktop/primary_button.dart'; +import 'package:stackwallet/widgets/desktop/secondary_button.dart'; +import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/stack_text_field.dart'; + +class VerifyMnemonicPassphraseDialog extends ConsumerStatefulWidget { + const VerifyMnemonicPassphraseDialog({super.key}); + + @override + ConsumerState createState() => + _VerifyMnemonicPassphraseDialogState(); +} + +class _VerifyMnemonicPassphraseDialogState + extends ConsumerState { + late final FocusNode passwordFocusNode; + late final TextEditingController passwordController; + + bool hidePassword = true; + + bool _verifyLock = false; + + void _verify() { + if (_verifyLock) { + return; + } + _verifyLock = true; + + if (passwordController.text == + ref.read(pNewWalletOptions.state).state!.mnemonicPassphrase) { + Navigator.of(context, rootNavigator: Util.isDesktop).pop("verified"); + } else { + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Passphrase does not match", + context: context, + ); + } + + _verifyLock = false; + } + + @override + void initState() { + passwordController = TextEditingController(); + passwordFocusNode = FocusNode(); + + super.initState(); + } + + @override + void dispose() { + passwordController.dispose(); + passwordFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ConditionalParent( + condition: Util.isDesktop, + builder: (child) => DesktopDialog( + maxHeight: double.infinity, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 32, + ), + child: Text( + "Verify mnemonic passphrase", + style: STextStyles.desktopH3(context), + ), + ), + const DesktopDialogCloseButton(), + ], + ), + Padding( + padding: const EdgeInsets.only( + left: 32, + right: 32, + bottom: 32, + ), + child: child, + ), + ], + ), + ), + child: ConditionalParent( + condition: !Util.isDesktop, + builder: (child) => StackDialogBase( + keyboardPaddingAmount: MediaQuery.of(context).viewInsets.bottom, + child: child, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (!Util.isDesktop) + Text( + "Verify mnemonic passphrase", + style: STextStyles.pageTitleH2(context), + ), + const SizedBox( + height: 24, + ), + ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + key: const Key("mnemonicPassphraseFieldKey1"), + focusNode: passwordFocusNode, + controller: passwordController, + style: Util.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: Util.isDesktop, + builder: (child) => SizedBox( + height: 70, + child: child, + ), + child: Row( + children: [ + SizedBox( + width: Util.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()! + .textDark3, + width: Util.isDesktop ? 24 : 16, + height: Util.isDesktop ? 24 : 16, + ), + ), + const SizedBox( + width: 12, + ), + ], + ), + ), + ), + ), + ), + ), + SizedBox( + height: Util.isDesktop ? 48 : 24, + ), + ConditionalParent( + condition: !Util.isDesktop, + builder: (child) => Row( + children: [ + Expanded( + child: SecondaryButton( + label: "Cancel", + onPressed: Navigator.of( + context, + rootNavigator: Util.isDesktop, + ).pop, + ), + ), + const SizedBox( + width: 16, + ), + Expanded( + child: child, + ), + ], + ), + child: PrimaryButton( + label: "Verify", + onPressed: _verify, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart index fda4419d9..0d0083cc6 100644 --- a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart +++ b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart @@ -16,9 +16,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/edit_wallet_tokens_view.dart'; +import 'package:stackwallet/pages/add_wallet_views/new_wallet_options/new_wallet_options_view.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; import 'package:stackwallet/pages/add_wallet_views/select_wallet_for_token_view.dart'; import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart'; +import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/verify_mnemonic_passphrase_dialog.dart'; import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart'; @@ -98,8 +100,25 @@ class _VerifyRecoveryPhraseViewState // } // } + Future _verifyMnemonicPassphrase() async { + final result = await showDialog( + context: context, + builder: (_) => const VerifyMnemonicPassphraseDialog(), + ); + + return result == "verified"; + } + Future _continue(bool isMatch) async { if (isMatch) { + if (ref.read(pNewWalletOptions.state).state != null) { + final passphraseVerified = await _verifyMnemonicPassphrase(); + + if (!passphraseVerified) { + return; + } + } + await ref.read(walletsServiceChangeNotifierProvider).setMnemonicVerified( walletId: _manager.walletId, ); diff --git a/lib/widgets/stack_dialog.dart b/lib/widgets/stack_dialog.dart index fead6a00a..be7f22ed9 100644 --- a/lib/widgets/stack_dialog.dart +++ b/lib/widgets/stack_dialog.dart @@ -18,15 +18,22 @@ class StackDialogBase extends StatelessWidget { Key? key, this.child, this.padding = const EdgeInsets.all(24), + this.keyboardPaddingAmount = 0, }) : super(key: key); final EdgeInsets padding; final Widget? child; + final double keyboardPaddingAmount; @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.all(16), + padding: EdgeInsets.only( + top: 16, + left: 16, + right: 16, + bottom: 16 + keyboardPaddingAmount, + ), child: Column( mainAxisAlignment: !Util.isDesktop ? MainAxisAlignment.end : MainAxisAlignment.center,