From 3a15538273bebc377b1c2b22fd5c91ee81fb441a Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 28 Oct 2022 13:51:25 -0600 Subject: [PATCH] WIP: desktop wallet keys popup layouts --- assets/svg/keys.svg | 23 ++ .../sub_widgets/mnemonic_table.dart | 4 + .../sub_widgets/mnemonic_table_item.dart | 3 + .../wallet_view/desktop_wallet_view.dart | 332 +++++++++++++++++- lib/utilities/assets.dart | 1 + lib/widgets/rounded_white_container.dart | 2 +- pubspec.yaml | 1 + 7 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 assets/svg/keys.svg diff --git a/assets/svg/keys.svg b/assets/svg/keys.svg new file mode 100644 index 000000000..cf86daea5 --- /dev/null +++ b/assets/svg/keys.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart index 946f54d4a..7d21dfec4 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart @@ -6,10 +6,12 @@ class MnemonicTable extends StatelessWidget { Key? key, required this.words, required this.isDesktop, + this.itemBorderColor, }) : super(key: key); final List words; final bool isDesktop; + final Color? itemBorderColor; @override Widget build(BuildContext context) { @@ -40,6 +42,7 @@ class MnemonicTable extends StatelessWidget { number: ++index, word: words[index - 1], isDesktop: isDesktop, + borderColor: itemBorderColor, ), ), ], @@ -61,6 +64,7 @@ class MnemonicTable extends StatelessWidget { number: i + 1, word: words[i], isDesktop: isDesktop, + borderColor: itemBorderColor, ), ), ], diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart index 8928ff3a6..ec103dfc6 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart @@ -9,16 +9,19 @@ class MnemonicTableItem extends StatelessWidget { required this.number, required this.word, required this.isDesktop, + this.borderColor, }) : super(key: key); final int number; final String word; final bool isDesktop; + final Color? borderColor; @override Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); return RoundedWhiteContainer( + borderColor: borderColor, padding: isDesktop ? const EdgeInsets.symmetric(horizontal: 12, vertical: 9) : const EdgeInsets.all(8), diff --git a/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart index 35b63174c..513be380b 100644 --- a/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart +++ b/lib/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart @@ -4,6 +4,7 @@ import 'package:event_bus/event_bus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart'; @@ -30,10 +31,14 @@ 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/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; +import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; +import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:tuple/tuple.dart'; /// [eventBus] should only be set during testing @@ -246,7 +251,9 @@ class _DesktopWalletViewState extends ConsumerState { const SizedBox( width: 32, ), - const WalletKeysButton(), + WalletKeysButton( + walletId: walletId, + ), const SizedBox( width: 32, ), @@ -766,11 +773,24 @@ class _NetworkInfoButtonState extends ConsumerState { } class WalletKeysButton extends StatelessWidget { - const WalletKeysButton({Key? key}) : super(key: key); + const WalletKeysButton({ + Key? key, + required this.walletId, + }) : super(key: key); + + final String walletId; @override Widget build(BuildContext context) { return GestureDetector( + onTap: () { + showDialog( + context: context, + builder: (context) => UnlockWalletKeysDesktop( + walletId: walletId, + ), + ); + }, child: Container( color: Colors.transparent, child: Row( @@ -796,3 +816,311 @@ class WalletKeysButton extends StatelessWidget { ); } } + +class UnlockWalletKeysDesktop extends ConsumerStatefulWidget { + const UnlockWalletKeysDesktop({ + Key? key, + required this.walletId, + }) : super(key: key); + + final String walletId; + + @override + ConsumerState createState() => + _UnlockWalletKeysDesktopState(); +} + +class _UnlockWalletKeysDesktopState + extends ConsumerState { + late final TextEditingController passwordController; + + late final FocusNode passwordFocusNode; + + bool continueEnabled = false; + bool hidePassword = true; + + @override + void initState() { + passwordController = TextEditingController(); + passwordFocusNode = FocusNode(); + super.initState(); + } + + @override + void dispose() { + passwordController.dispose(); + passwordFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return DesktopDialog( + maxWidth: 579, + maxHeight: double.infinity, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: const [ + DesktopDialogCloseButton(), + ], + ), + const SizedBox( + height: 12, + ), + SvgPicture.asset( + Assets.svg.keys, + width: 100, + height: 58, + ), + const SizedBox( + height: 55, + ), + Text( + "Wallet keys", + style: STextStyles.desktopH2(context), + ), + const SizedBox( + height: 16, + ), + Text( + "Enter your password", + style: STextStyles.desktopTextMedium(context).copyWith( + color: Theme.of(context).extension()!.textDark3, + ), + ), + const SizedBox( + height: 24, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 32, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + key: const Key("enterPasswordUnlockWalletKeysDesktopFieldKey"), + focusNode: passwordFocusNode, + controller: passwordController, + style: STextStyles.desktopTextMedium(context).copyWith( + height: 2, + ), + obscureText: hidePassword, + enableSuggestions: false, + autocorrect: false, + decoration: standardInputDecoration( + "Enter password", + passwordFocusNode, + context, + ).copyWith( + suffixIcon: UnconstrainedBox( + child: SizedBox( + height: 70, + child: Row( + children: [ + GestureDetector( + key: const Key( + "enterUnlockWalletKeysDesktopFieldShowPasswordButtonKey"), + onTap: () async { + setState(() { + hidePassword = !hidePassword; + }); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(1000), + ), + height: 32, + width: 32, + child: Center( + child: SvgPicture.asset( + hidePassword + ? Assets.svg.eye + : Assets.svg.eyeSlash, + color: Theme.of(context) + .extension()! + .textDark3, + width: 24, + height: 19, + ), + ), + ), + ), + const SizedBox( + width: 10, + ), + ], + ), + ), + ), + ), + onChanged: (newValue) { + setState(() { + continueEnabled = newValue.isNotEmpty; + }); + }, + ), + ), + ), + const SizedBox( + height: 55, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 32, + ), + child: Row( + children: [ + Expanded( + child: SecondaryButton( + label: "Cancel", + onPressed: Navigator.of(context).pop, + ), + ), + const SizedBox( + width: 16, + ), + Expanded( + child: PrimaryButton( + label: "Continue", + enabled: continueEnabled, + onPressed: continueEnabled + ? () async { + // todo: check password + Navigator.of(context).pop(); + final words = await ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .mnemonic; + await showDialog( + context: context, + builder: (context) => WalletKeysDesktopPopup( + words: words, + ), + ); + } + : null, + ), + ), + ], + ), + ), + const SizedBox( + height: 32, + ), + ], + ), + ); + } +} + +class WalletKeysDesktopPopup extends StatelessWidget { + const WalletKeysDesktopPopup({ + Key? key, + required this.words, + }) : super(key: key); + + final List words; + + @override + Widget build(BuildContext context) { + return DesktopDialog( + maxWidth: 614, + maxHeight: double.infinity, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 32, + ), + child: Text( + "Wallet keys", + style: STextStyles.desktopH3(context), + ), + ), + const DesktopDialogCloseButton(), + ], + ), + const SizedBox( + height: 28, + ), + Text( + "Recovery phrase", + style: STextStyles.desktopTextMedium(context), + ), + const SizedBox( + height: 8, + ), + Center( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 32, + ), + child: Text( + "Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.", + style: STextStyles.desktopTextExtraExtraSmall(context), + textAlign: TextAlign.center, + ), + ), + ), + const SizedBox( + height: 24, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 32, + ), + child: MnemonicTable( + words: words, + isDesktop: true, + itemBorderColor: Theme.of(context) + .extension()! + .buttonBackSecondary, + ), + ), + const SizedBox( + height: 24, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 32, + ), + child: Row( + children: [ + Expanded( + child: SecondaryButton( + label: "Show QR code", + onPressed: () { + // todo show qr code + }, + ), + ), + const SizedBox( + width: 16, + ), + Expanded( + child: PrimaryButton( + label: "Copy", + onPressed: () { + // todo copy to clipboard + }, + ), + ), + ], + ), + ), + const SizedBox( + height: 32, + ), + ], + ), + ); + } +} diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart index ebe2d9848..c730b1aa1 100644 --- a/lib/utilities/assets.dart +++ b/lib/utilities/assets.dart @@ -144,6 +144,7 @@ class _SVG { String get aboutDesktop => "assets/svg/about-desktop.svg"; String get walletDesktop => "assets/svg/wallet-desktop.svg"; String get exitDesktop => "assets/svg/exit-desktop.svg"; + String get keys => "assets/svg/keys.svg"; String get ellipse1 => "assets/svg/Ellipse-43.svg"; String get ellipse2 => "assets/svg/Ellipse-42.svg"; diff --git a/lib/widgets/rounded_white_container.dart b/lib/widgets/rounded_white_container.dart index a574dc1ce..1173e95b1 100644 --- a/lib/widgets/rounded_white_container.dart +++ b/lib/widgets/rounded_white_container.dart @@ -28,8 +28,8 @@ class RoundedWhiteContainer extends StatelessWidget { radiusMultiplier: radiusMultiplier, width: width, height: height, - child: child, borderColor: borderColor, + child: child, ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 42934fd5c..75cdc985a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -308,6 +308,7 @@ flutter: - assets/svg/exchange-desktop.svg - assets/svg/wallet-desktop.svg - assets/svg/exit-desktop.svg + - assets/svg/keys.svg # coin icons - assets/svg/coin_icons/Bitcoin.svg - assets/svg/coin_icons/Bitcoincash.svg