From a6c793bdb97989bf981cad2db8d96f4b8ef90911 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Wed, 5 Apr 2023 16:27:14 -0500 Subject: [PATCH 01/17] add Show xPub dot option on desktop --- .../sub_widgets/wallet_options_button.dart | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart index f91448dda..8983985c1 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart @@ -13,7 +13,8 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart'; enum _WalletOptions { addressList, - deleteWallet; + deleteWallet, + showXpub; String get prettyName { switch (this) { @@ -21,6 +22,8 @@ enum _WalletOptions { return "Address list"; case _WalletOptions.deleteWallet: return "Delete wallet"; + case _WalletOptions.showXpub: + return "Show xPub"; } } } @@ -70,6 +73,9 @@ class _WalletOptionsButtonState extends ConsumerState { onAddressListPressed: () async { Navigator.of(context).pop(_WalletOptions.addressList); }, + onShowXpubPressed: () async { + Navigator.of(context).pop(_WalletOptions.showXpub); + }, ); }, ); @@ -110,6 +116,33 @@ class _WalletOptionsButtonState extends ConsumerState { } } break; + case _WalletOptions.showXpub: + print("TODO"); + // final result = await showDialog( + // context: context, + // barrierDismissible: false, + // builder: (context) => Navigator( + // initialRoute: DesktopShowXpubDialog.routeName, + // onGenerateRoute: RouteGenerator.generateRoute, + // onGenerateInitialRoutes: (_, __) { + // return [ + // RouteGenerator.generateRoute( + // RouteSettings( + // name: DesktopShowXpubDialog.routeName, + // arguments: walletId, + // ), + // ), + // ]; + // }, + // ), + // ); + // + // if (result == true) { + // if (mounted) { + // Navigator.of(context).pop(); + // } + // } + // break; } } }, @@ -140,10 +173,12 @@ class WalletOptionsPopupMenu extends StatelessWidget { Key? key, required this.onDeletePressed, required this.onAddressListPressed, + required this.onShowXpubPressed, }) : super(key: key); final VoidCallback onDeletePressed; final VoidCallback onAddressListPressed; + final VoidCallback onShowXpubPressed; @override Widget build(BuildContext context) { @@ -203,6 +238,41 @@ class WalletOptionsPopupMenu extends StatelessWidget { const SizedBox( height: 8, ), + TransparentButton( + onPressed: onShowXpubPressed, + child: Padding( + padding: const EdgeInsets.all(8), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset( + Assets.svg.eye, + width: 20, + height: 20, + color: Theme.of(context) + .extension()! + .textFieldActiveSearchIconLeft, + ), + const SizedBox(width: 14), + Expanded( + child: Text( + _WalletOptions.showXpub.prettyName, + style: STextStyles.desktopTextExtraExtraSmall( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ), + ), + ), + ], + ), + ), + ), + const SizedBox( + height: 8, + ), TransparentButton( onPressed: onDeletePressed, child: Padding( From 0c775373161306ca707620937d3fd840919a3343 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Wed, 5 Apr 2023 16:40:01 -0500 Subject: [PATCH 02/17] add desktop xpub dialog --- .../sub_widgets/desktop_show_xpub_dialog.dart | 82 +++++++++++++++++++ .../sub_widgets/wallet_options_button.dart | 52 ++++++------ lib/route_generator.dart | 14 ++++ 3 files changed, 122 insertions(+), 26 deletions(-) create mode 100644 lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart new file mode 100644 index 000000000..7f562a069 --- /dev/null +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/utilities/text_styles.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'; + +class DesktopShowXpubDialog extends ConsumerStatefulWidget { + const DesktopShowXpubDialog({ + Key? key, + required this.walletId, + }) : super(key: key); + + final String walletId; + + static const String routeName = "/desktopShowXpubDialog"; + + @override + ConsumerState createState() => + _DesktopShowXpubDialog(); +} + +class _DesktopShowXpubDialog extends ConsumerState { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return DesktopDialog( + maxWidth: 580, + maxHeight: double.infinity, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + DesktopDialogCloseButton( + onPressedOverride: Navigator.of( + context, + rootNavigator: true, + ).pop, + ), + ], + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 26), + child: Column( + children: [ + const SizedBox(height: 16), + Text( + "Wallet Xpub", + style: STextStyles.desktopH2(context), + ), + const SizedBox(height: 50), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + PrimaryButton( + width: 250, + buttonHeight: ButtonHeight.xl, + label: "Continue", + onPressed: Navigator.of( + context, + rootNavigator: true, + ).pop), + ], + ) + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart index 8983985c1..12d57a256 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages_desktop_specific/addresses/desktop_wallet_addresses_view.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart'; +import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; @@ -117,32 +118,31 @@ class _WalletOptionsButtonState extends ConsumerState { } break; case _WalletOptions.showXpub: - print("TODO"); - // final result = await showDialog( - // context: context, - // barrierDismissible: false, - // builder: (context) => Navigator( - // initialRoute: DesktopShowXpubDialog.routeName, - // onGenerateRoute: RouteGenerator.generateRoute, - // onGenerateInitialRoutes: (_, __) { - // return [ - // RouteGenerator.generateRoute( - // RouteSettings( - // name: DesktopShowXpubDialog.routeName, - // arguments: walletId, - // ), - // ), - // ]; - // }, - // ), - // ); - // - // if (result == true) { - // if (mounted) { - // Navigator.of(context).pop(); - // } - // } - // break; + final result = await showDialog( + context: context, + barrierDismissible: false, + builder: (context) => Navigator( + initialRoute: DesktopShowXpubDialog.routeName, + onGenerateRoute: RouteGenerator.generateRoute, + onGenerateInitialRoutes: (_, __) { + return [ + RouteGenerator.generateRoute( + RouteSettings( + name: DesktopShowXpubDialog.routeName, + arguments: walletId, + ), + ), + ]; + }, + ), + ); + + if (result == true) { + if (mounted) { + Navigator.of(context).pop(); + } + } + break; } } }, diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 5d5599902..3286611eb 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -111,6 +111,7 @@ import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/des import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/delete_wallet_keys_popup.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_attention_delete_wallet.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart'; +import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/unlock_wallet_keys_desktop.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart'; @@ -1526,6 +1527,19 @@ class RouteGenerator { } return _routeError("${settings.name} invalid args: ${args.toString()}"); + case DesktopShowXpubDialog.routeName: + if (args is String) { + return FadePageRoute( + DesktopShowXpubDialog( + walletId: args, + ), + RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); + case QRCodeDesktopPopupContent.routeName: if (args is String) { return FadePageRoute( From c396d97d85a650db01b947d21af00107dedaa2b0 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 11:08:32 -0500 Subject: [PATCH 03/17] show xpub qr code in dialog --- .../sub_widgets/desktop_show_xpub_dialog.dart | 17 +++++++++++++---- .../sub_widgets/wallet_options_button.dart | 14 +++++++++++++- lib/route_generator.dart | 2 +- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart index 7f562a069..30ff15ea1 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:qr_flutter/qr_flutter.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/desktop/primary_button.dart'; @@ -8,10 +10,10 @@ import 'package:stackwallet/widgets/desktop/primary_button.dart'; class DesktopShowXpubDialog extends ConsumerStatefulWidget { const DesktopShowXpubDialog({ Key? key, - required this.walletId, + required this.xpub, }) : super(key: key); - final String walletId; + final String xpub; static const String routeName = "/desktopShowXpubDialog"; @@ -50,7 +52,7 @@ class _DesktopShowXpubDialog extends ConsumerState { ], ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 26), + padding: const EdgeInsets.fromLTRB(32, 0, 32, 26), child: Column( children: [ const SizedBox(height: 16), @@ -58,7 +60,14 @@ class _DesktopShowXpubDialog extends ConsumerState { "Wallet Xpub", style: STextStyles.desktopH2(context), ), - const SizedBox(height: 50), + const SizedBox(height: 14), + QrImage( + data: widget.xpub, + size: 300, + foregroundColor: Theme.of(context) + .extension()! + .accentColorDark, + ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart index 12d57a256..498928853 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart @@ -1,11 +1,14 @@ import 'dart:async'; +import 'package:bip32/bip32.dart' as bip32; +import 'package:bip39/bip39.dart' as bip39; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages_desktop_specific/addresses/desktop_wallet_addresses_view.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart'; import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart'; +import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; @@ -118,6 +121,15 @@ class _WalletOptionsButtonState extends ConsumerState { } break; case _WalletOptions.showXpub: + final List mnemonic = await ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .mnemonic; + + final seed = bip39.mnemonicToSeed(mnemonic.join(' ')); + final node = bip32.BIP32.fromSeed(seed); + final xpub = node.neutered().toBase58(); + final result = await showDialog( context: context, barrierDismissible: false, @@ -129,7 +141,7 @@ class _WalletOptionsButtonState extends ConsumerState { RouteGenerator.generateRoute( RouteSettings( name: DesktopShowXpubDialog.routeName, - arguments: walletId, + arguments: xpub, ), ), ]; diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 3286611eb..80a093eb3 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -1531,7 +1531,7 @@ class RouteGenerator { if (args is String) { return FadePageRoute( DesktopShowXpubDialog( - walletId: args, + xpub: args, ), RouteSettings( name: settings.name, From c50d8fc49512483d5b98bfe19bff5eb5e13f97cc Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 11:22:29 -0500 Subject: [PATCH 04/17] add copy to clipboard functionality --- .../sub_widgets/desktop_show_xpub_dialog.dart | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart index 30ff15ea1..9832cde52 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart @@ -1,6 +1,12 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:qr_flutter/qr_flutter.dart'; +import 'package:stackwallet/notifications/show_flush_bar.dart'; +import 'package:stackwallet/utilities/assets.dart'; +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/desktop/desktop_dialog.dart'; @@ -11,10 +17,13 @@ class DesktopShowXpubDialog extends ConsumerStatefulWidget { const DesktopShowXpubDialog({ Key? key, required this.xpub, + this.clipboardInterface = const ClipboardWrapper(), }) : super(key: key); final String xpub; + final ClipboardInterface clipboardInterface; + static const String routeName = "/desktopShowXpubDialog"; @override @@ -23,8 +32,11 @@ class DesktopShowXpubDialog extends ConsumerStatefulWidget { } class _DesktopShowXpubDialog extends ConsumerState { + late ClipboardInterface _clipboardInterface; + @override void initState() { + _clipboardInterface = widget.clipboardInterface; super.initState(); } @@ -33,6 +45,16 @@ class _DesktopShowXpubDialog extends ConsumerState { super.dispose(); } + Future _copy() async { + await _clipboardInterface.setData(ClipboardData(text: widget.xpub)); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + iconAsset: Assets.svg.copy, + context: context, + )); + } + @override Widget build(BuildContext context) { return DesktopDialog( @@ -71,6 +93,14 @@ class _DesktopShowXpubDialog extends ConsumerState { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + PrimaryButton( + width: 250, + buttonHeight: ButtonHeight.xl, + label: "Copy to clipboard", + onPressed: () async { + await _copy(); + }), + const SizedBox(width: 16), PrimaryButton( width: 250, buttonHeight: ButtonHeight.xl, From 96f62490bbb28e46efea708984e1b57fcdbc33eb Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 11:22:37 -0500 Subject: [PATCH 05/17] add padding like in other dialogs --- .../wallet_view/sub_widgets/desktop_show_xpub_dialog.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart index 9832cde52..b101149e4 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart @@ -90,6 +90,7 @@ class _DesktopShowXpubDialog extends ConsumerState { .extension()! .accentColorDark, ), + const SizedBox(height: 50), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ From 4187de8c5b985dc0294b7ff72bbb5f1b3b15d11c Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 11:58:10 -0500 Subject: [PATCH 06/17] disable xpub wallet option for monero, wownero, and firo --- .../sub_widgets/wallet_options_button.dart | 79 +++++++++++-------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart index 498928853..88288506e 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/wallet_options_button.dart @@ -12,6 +12,7 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.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'; @@ -33,10 +34,8 @@ enum _WalletOptions { } class WalletOptionsButton extends ConsumerStatefulWidget { - const WalletOptionsButton({ - Key? key, - required this.walletId, - }) : super(key: key); + const WalletOptionsButton({Key? key, required this.walletId}) + : super(key: key); final String walletId; @@ -47,10 +46,12 @@ class WalletOptionsButton extends ConsumerStatefulWidget { class _WalletOptionsButtonState extends ConsumerState { late final String walletId; + late final Coin coin; @override void initState() { walletId = widget.walletId; + coin = ref.read(walletsChangeNotifierProvider).getManager(walletId).coin; super.initState(); } @@ -80,6 +81,7 @@ class _WalletOptionsButtonState extends ConsumerState { onShowXpubPressed: () async { Navigator.of(context).pop(_WalletOptions.showXpub); }, + coin: coin, ); }, ); @@ -186,14 +188,19 @@ class WalletOptionsPopupMenu extends StatelessWidget { required this.onDeletePressed, required this.onAddressListPressed, required this.onShowXpubPressed, + required this.coin, }) : super(key: key); final VoidCallback onDeletePressed; final VoidCallback onAddressListPressed; final VoidCallback onShowXpubPressed; + final Coin coin; @override Widget build(BuildContext context) { + final bool xpubEnabled = + coin != Coin.monero && coin != Coin.epicCash && coin != Coin.wownero; + return Stack( children: [ Positioned( @@ -247,41 +254,43 @@ class WalletOptionsPopupMenu extends StatelessWidget { ), ), ), - const SizedBox( - height: 8, - ), - TransparentButton( - onPressed: onShowXpubPressed, - child: Padding( - padding: const EdgeInsets.all(8), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SvgPicture.asset( - Assets.svg.eye, - width: 20, - height: 20, - color: Theme.of(context) - .extension()! - .textFieldActiveSearchIconLeft, - ), - const SizedBox(width: 14), - Expanded( - child: Text( - _WalletOptions.showXpub.prettyName, - style: STextStyles.desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension()! - .textDark, + if (xpubEnabled) + const SizedBox( + height: 8, + ), + if (xpubEnabled) + TransparentButton( + onPressed: onShowXpubPressed, + child: Padding( + padding: const EdgeInsets.all(8), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset( + Assets.svg.eye, + width: 20, + height: 20, + color: Theme.of(context) + .extension()! + .textFieldActiveSearchIconLeft, + ), + const SizedBox(width: 14), + Expanded( + child: Text( + _WalletOptions.showXpub.prettyName, + style: STextStyles.desktopTextExtraExtraSmall( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ), ), ), - ), - ], + ], + ), ), ), - ), const SizedBox( height: 8, ), From 4007c1558b0ffb1fa777b6a608ffe2ea0b165a3f Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 13:24:55 -0500 Subject: [PATCH 07/17] add xpub option to More menu in mobile wallet view --- lib/pages/wallet_view/wallet_view.dart | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 8d12df5a6..8d99d094b 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -60,6 +60,7 @@ import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/excha import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/paynym_nav_icon.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/receive_nav_icon.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/send_nav_icon.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/wallet_navigation_bar_item.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/wallet_navigation_bar.dart'; import 'package:tuple/tuple.dart'; @@ -259,7 +260,7 @@ class _WalletViewState extends ConsumerState { } void _onExchangePressed(BuildContext context) async { - final coin = ref.read(managerProvider).coin; + final Coin coin = ref.read(managerProvider).coin; if (coin.isTestNet) { await showDialog( @@ -384,7 +385,9 @@ class _WalletViewState extends ConsumerState { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - final coin = ref.watch(managerProvider.select((value) => value.coin)); + final Coin coin = ref.watch(managerProvider.select((value) => value.coin)); + final bool xPubEnabled = + coin != Coin.monero && coin != Coin.wownero && coin != Coin.epicCash; return ConditionalParent( condition: _rescanningOnOpen, @@ -910,6 +913,14 @@ class _WalletViewState extends ConsumerState { } }, ), + if (xPubEnabled) + WalletNavigationBarItemData( + label: "Show xPub", + icon: const XPubNavIcon(), + onTap: () async { + print("TODO"); + }, + ), ], ), ], From 767bcecd03ac4b357017b219842ad9a336a9f946 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 13:36:43 -0500 Subject: [PATCH 08/17] change copy to clipboard button color --- .../wallet_view/sub_widgets/desktop_show_xpub_dialog.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart index b101149e4..a99ddec71 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart @@ -12,6 +12,7 @@ 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/desktop/primary_button.dart'; +import 'package:stackwallet/widgets/desktop/secondary_button.dart'; class DesktopShowXpubDialog extends ConsumerStatefulWidget { const DesktopShowXpubDialog({ @@ -94,7 +95,7 @@ class _DesktopShowXpubDialog extends ConsumerState { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - PrimaryButton( + SecondaryButton( width: 250, buttonHeight: ButtonHeight.xl, label: "Copy to clipboard", From 6f3691625a8d8e3cca7ae711356887155b0835c1 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 13:56:35 -0500 Subject: [PATCH 09/17] add copy to clipboard button to mobile xpub dialog --- lib/pages/wallet_view/wallet_view.dart | 65 +++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 8d99d094b..61107e143 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -1,8 +1,11 @@ import 'dart:async'; +import 'package:bip32/bip32.dart' as bip32; +import 'package:bip39/bip39.dart' as bip39; import 'package:decimal/decimal.dart'; import 'package:event_bus/event_bus.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:isar/isar.dart'; @@ -38,6 +41,7 @@ import 'package:stackwallet/services/event_bus/global_event_bus.dart'; import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart'; import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; @@ -72,6 +76,7 @@ class WalletView extends ConsumerStatefulWidget { required this.walletId, required this.managerProvider, this.eventBus, + this.clipboardInterface = const ClipboardWrapper(), }) : super(key: key); static const String routeName = "/wallet"; @@ -81,6 +86,8 @@ class WalletView extends ConsumerStatefulWidget { final ChangeNotifierProvider managerProvider; final EventBus? eventBus; + final ClipboardInterface clipboardInterface; + @override ConsumerState createState() => _WalletViewState(); } @@ -100,10 +107,13 @@ class _WalletViewState extends ConsumerState { bool _rescanningOnOpen = false; + late ClipboardInterface _clipboardInterface; + @override void initState() { walletId = widget.walletId; managerProvider = widget.managerProvider; + _clipboardInterface = widget.clipboardInterface; ref.read(managerProvider).isActiveWallet = true; if (!ref.read(managerProvider).shouldAutoSync) { @@ -189,6 +199,16 @@ class _WalletViewState extends ConsumerState { super.dispose(); } + Future _copy(String xpub) async { + await _clipboardInterface.setData(ClipboardData(text: xpub)); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + iconAsset: Assets.svg.copy, + context: context, + )); + } + DateTime? _cachedTime; Future _onWillPop() async { @@ -918,7 +938,50 @@ class _WalletViewState extends ConsumerState { label: "Show xPub", icon: const XPubNavIcon(), onTap: () async { - print("TODO"); + final List mnemonic = await ref + .read(walletsChangeNotifierProvider) + .getManager(walletId) + .mnemonic; + + final seed = bip39.mnemonicToSeed(mnemonic.join(' ')); + final node = bip32.BIP32.fromSeed(seed); + final xpub = node.neutered().toBase58(); + + showDialog( + barrierDismissible: true, + context: context, + builder: (_) => StackDialog( + title: "Wallet xPub", + message: xpub, + leftButton: TextButton( + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonStyle(context), + onPressed: () async { + await _copy(xpub); + }, + child: Text( + "Copy to clipboard", + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), + ), + ), + rightButton: TextButton( + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonStyle(context), + onPressed: () { + Navigator.pop(context); + }, + child: Text( + "Continue", + style: STextStyles.button(context), + ), + ), + ), + ); }, ), ], From d91df1165f1dafa08e2387128ef3f7bf5f491b95 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 14:13:27 -0500 Subject: [PATCH 10/17] add qr dialog for mobile --- lib/pages/wallet_view/wallet_view.dart | 8 +- lib/widgets/qr_dialog.dart | 134 +++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 lib/widgets/qr_dialog.dart diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 61107e143..0f1c9c667 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -57,6 +57,7 @@ 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/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; +import 'package:stackwallet/widgets/qr_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/buy_nav_icon.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/coin_control_nav_icon.dart'; @@ -950,9 +951,10 @@ class _WalletViewState extends ConsumerState { showDialog( barrierDismissible: true, context: context, - builder: (_) => StackDialog( + builder: (_) => QrDialog( title: "Wallet xPub", - message: xpub, + // message: xpub, + qr: xpub, leftButton: TextButton( style: Theme.of(context) .extension()! @@ -961,7 +963,7 @@ class _WalletViewState extends ConsumerState { await _copy(xpub); }, child: Text( - "Copy to clipboard", + "Copy", style: STextStyles.button(context).copyWith( color: Theme.of(context) .extension()! diff --git a/lib/widgets/qr_dialog.dart b/lib/widgets/qr_dialog.dart new file mode 100644 index 000000000..6144c70a1 --- /dev/null +++ b/lib/widgets/qr_dialog.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; +import 'package:qr_flutter/qr_flutter.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; + +class QrDialogBase extends StatelessWidget { + const QrDialogBase({ + Key? key, + this.child, + this.padding = const EdgeInsets.all(24), + }) : super(key: key); + + final EdgeInsets padding; + final Widget? child; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisAlignment: + !Util.isDesktop ? MainAxisAlignment.end : MainAxisAlignment.center, + children: [ + Flexible( + child: SingleChildScrollView( + child: Material( + borderRadius: BorderRadius.circular( + 20, + ), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: BorderRadius.circular( + 20, + ), + ), + child: Padding( + padding: padding, + child: child, + ), + ), + ), + ), + ), + ], + ), + ); + } +} + +class QrDialog extends StatelessWidget { + const QrDialog({ + Key? key, + this.leftButton, + this.rightButton, + this.icon, + required this.title, + this.message, + this.qr, + }) : super(key: key); + + final Widget? leftButton; + final Widget? rightButton; + + final Widget? icon; + + final String title; + final String? message; + + final String? qr; + + @override + Widget build(BuildContext context) { + return QrDialogBase( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Text( + title, + style: STextStyles.pageTitleH2(context), + ), + ), + icon != null ? icon! : Container(), + ], + ), + if (message != null) + const SizedBox( + height: 8, + ), + if (message != null) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + message!, + style: STextStyles.smallMed14(context), + ), + ], + ), + if (qr != null) + QrImage( + data: qr!, + size: 300, + foregroundColor: + Theme.of(context).extension()!.accentColorDark, + ), + if (leftButton != null || rightButton != null) + const SizedBox( + height: 20, + ), + if (leftButton != null || rightButton != null) + Row( + children: [ + leftButton == null + ? const Spacer() + : Expanded(child: leftButton!), + const SizedBox( + width: 8, + ), + rightButton == null + ? const Spacer() + : Expanded(child: rightButton!), + ], + ) + ], + ), + ); + } +} From 84fea4e9ffa8654fa78c3f0d7d9962fdaaa5a198 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 14:14:03 -0500 Subject: [PATCH 11/17] change copy to clipboard text in desktop xpub dialog --- .../wallet_view/sub_widgets/desktop_show_xpub_dialog.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart index a99ddec71..905d1a616 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_show_xpub_dialog.dart @@ -98,7 +98,7 @@ class _DesktopShowXpubDialog extends ConsumerState { SecondaryButton( width: 250, buttonHeight: ButtonHeight.xl, - label: "Copy to clipboard", + label: "Copy", onPressed: () async { await _copy(); }), From 2fa00ff7a5824fb9d0fa37ff98dc37e08c04693c Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 14:14:18 -0500 Subject: [PATCH 12/17] add xpub nav icon --- .../components/icons/xpub_nav_icon.dart | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 lib/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart diff --git a/lib/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart new file mode 100644 index 000000000..966957780 --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class XPubNavIcon extends StatelessWidget { + const XPubNavIcon({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset( + Assets.svg.eye, + height: 20, + width: 20, + color: Theme.of(context).extension()!.bottomNavIconIcon, + ); + } +} From 1792af4ac88f650221c086a1f8f0e58f4a2c9d4a Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 14:14:42 -0500 Subject: [PATCH 13/17] remove qr dialog and xpub nav icon --- lib/widgets/qr_dialog.dart | 134 ------------------ .../components/icons/xpub_nav_icon.dart | 18 --- 2 files changed, 152 deletions(-) delete mode 100644 lib/widgets/qr_dialog.dart delete mode 100644 lib/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart diff --git a/lib/widgets/qr_dialog.dart b/lib/widgets/qr_dialog.dart deleted file mode 100644 index 6144c70a1..000000000 --- a/lib/widgets/qr_dialog.dart +++ /dev/null @@ -1,134 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:qr_flutter/qr_flutter.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; -import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/utilities/util.dart'; - -class QrDialogBase extends StatelessWidget { - const QrDialogBase({ - Key? key, - this.child, - this.padding = const EdgeInsets.all(24), - }) : super(key: key); - - final EdgeInsets padding; - final Widget? child; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisAlignment: - !Util.isDesktop ? MainAxisAlignment.end : MainAxisAlignment.center, - children: [ - Flexible( - child: SingleChildScrollView( - child: Material( - borderRadius: BorderRadius.circular( - 20, - ), - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).extension()!.popupBG, - borderRadius: BorderRadius.circular( - 20, - ), - ), - child: Padding( - padding: padding, - child: child, - ), - ), - ), - ), - ), - ], - ), - ); - } -} - -class QrDialog extends StatelessWidget { - const QrDialog({ - Key? key, - this.leftButton, - this.rightButton, - this.icon, - required this.title, - this.message, - this.qr, - }) : super(key: key); - - final Widget? leftButton; - final Widget? rightButton; - - final Widget? icon; - - final String title; - final String? message; - - final String? qr; - - @override - Widget build(BuildContext context) { - return QrDialogBase( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Text( - title, - style: STextStyles.pageTitleH2(context), - ), - ), - icon != null ? icon! : Container(), - ], - ), - if (message != null) - const SizedBox( - height: 8, - ), - if (message != null) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - message!, - style: STextStyles.smallMed14(context), - ), - ], - ), - if (qr != null) - QrImage( - data: qr!, - size: 300, - foregroundColor: - Theme.of(context).extension()!.accentColorDark, - ), - if (leftButton != null || rightButton != null) - const SizedBox( - height: 20, - ), - if (leftButton != null || rightButton != null) - Row( - children: [ - leftButton == null - ? const Spacer() - : Expanded(child: leftButton!), - const SizedBox( - width: 8, - ), - rightButton == null - ? const Spacer() - : Expanded(child: rightButton!), - ], - ) - ], - ), - ); - } -} diff --git a/lib/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart deleted file mode 100644 index 966957780..000000000 --- a/lib/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/theme/stack_colors.dart'; - -class XPubNavIcon extends StatelessWidget { - const XPubNavIcon({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return SvgPicture.asset( - Assets.svg.eye, - height: 20, - width: 20, - color: Theme.of(context).extension()!.bottomNavIconIcon, - ); - } -} From 1df670197288b49841b5413baf11ee491aa09b35 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 14:16:00 -0500 Subject: [PATCH 14/17] remove show xpub item from mobile more dialog --- lib/pages/wallet_view/wallet_view.dart | 69 -------------------------- 1 file changed, 69 deletions(-) diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 0f1c9c667..f586eaa80 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -1,11 +1,8 @@ import 'dart:async'; -import 'package:bip32/bip32.dart' as bip32; -import 'package:bip39/bip39.dart' as bip39; import 'package:decimal/decimal.dart'; import 'package:event_bus/event_bus.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:isar/isar.dart'; @@ -57,7 +54,6 @@ 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/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; -import 'package:stackwallet/widgets/qr_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/buy_nav_icon.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/coin_control_nav_icon.dart'; @@ -65,7 +61,6 @@ import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/excha import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/paynym_nav_icon.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/receive_nav_icon.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/send_nav_icon.dart'; -import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/xpub_nav_icon.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/components/wallet_navigation_bar_item.dart'; import 'package:stackwallet/widgets/wallet_navigation_bar/wallet_navigation_bar.dart'; import 'package:tuple/tuple.dart'; @@ -200,16 +195,6 @@ class _WalletViewState extends ConsumerState { super.dispose(); } - Future _copy(String xpub) async { - await _clipboardInterface.setData(ClipboardData(text: xpub)); - unawaited(showFloatingFlushBar( - type: FlushBarType.info, - message: "Copied to clipboard", - iconAsset: Assets.svg.copy, - context: context, - )); - } - DateTime? _cachedTime; Future _onWillPop() async { @@ -407,8 +392,6 @@ class _WalletViewState extends ConsumerState { debugPrint("BUILD: $runtimeType"); final Coin coin = ref.watch(managerProvider.select((value) => value.coin)); - final bool xPubEnabled = - coin != Coin.monero && coin != Coin.wownero && coin != Coin.epicCash; return ConditionalParent( condition: _rescanningOnOpen, @@ -934,58 +917,6 @@ class _WalletViewState extends ConsumerState { } }, ), - if (xPubEnabled) - WalletNavigationBarItemData( - label: "Show xPub", - icon: const XPubNavIcon(), - onTap: () async { - final List mnemonic = await ref - .read(walletsChangeNotifierProvider) - .getManager(walletId) - .mnemonic; - - final seed = bip39.mnemonicToSeed(mnemonic.join(' ')); - final node = bip32.BIP32.fromSeed(seed); - final xpub = node.neutered().toBase58(); - - showDialog( - barrierDismissible: true, - context: context, - builder: (_) => QrDialog( - title: "Wallet xPub", - // message: xpub, - qr: xpub, - leftButton: TextButton( - style: Theme.of(context) - .extension()! - .getSecondaryEnabledButtonStyle(context), - onPressed: () async { - await _copy(xpub); - }, - child: Text( - "Copy", - style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension()! - .accentColorDark), - ), - ), - rightButton: TextButton( - style: Theme.of(context) - .extension()! - .getPrimaryEnabledButtonStyle(context), - onPressed: () { - Navigator.pop(context); - }, - child: Text( - "Continue", - style: STextStyles.button(context), - ), - ), - ), - ); - }, - ), ], ), ], From d3f45f14b6125b83228d91d88571680de8033f62 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 14:28:11 -0500 Subject: [PATCH 15/17] add stub xpub settings view --- .../global_settings_view/xpub_view.dart | 55 +++++++++++++++++++ .../wallet_settings_view.dart | 17 ++++++ lib/route_generator.dart | 7 +++ 3 files changed, 79 insertions(+) create mode 100644 lib/pages/settings_views/global_settings_view/xpub_view.dart diff --git a/lib/pages/settings_views/global_settings_view/xpub_view.dart b/lib/pages/settings_views/global_settings_view/xpub_view.dart new file mode 100644 index 000000000..8875514d1 --- /dev/null +++ b/lib/pages/settings_views/global_settings_view/xpub_view.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/background.dart'; +import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; + +class XPubView extends ConsumerStatefulWidget { + const XPubView({Key? key}) : super(key: key); + + static const String routeName = "/xpub"; + + @override + ConsumerState createState() => _XPubViewState(); +} + +class _XPubViewState extends ConsumerState { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Background( + child: Scaffold( + backgroundColor: Theme.of(context).extension()!.background, + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () async { + Navigator.of(context).pop(); + }, + ), + title: Text( + "Wallet xPub", + style: STextStyles.navBarTitle(context), + ), + ), + body: Padding( + padding: const EdgeInsets.only( + top: 12, + left: 16, + right: 16, + ), + child: Text("TODO"), + ), + ), + ); + } +} diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart index 5d78e5de6..34196b8a9 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart @@ -10,6 +10,7 @@ import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/advanced_views/debug_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart'; +import 'package:stackwallet/pages/settings_views/global_settings_view/xpub_view.dart'; import 'package:stackwallet/pages/settings_views/sub_widgets/settings_list_button.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart'; @@ -57,6 +58,7 @@ class WalletSettingsView extends StatefulWidget { class _WalletSettingsViewState extends State { late final String walletId; late final Coin coin; + late final bool xPubEnabled; late final EventBus eventBus; @@ -70,6 +72,8 @@ class _WalletSettingsViewState extends State { void initState() { walletId = widget.walletId; coin = widget.coin; + xPubEnabled = + coin != Coin.monero && coin != Coin.wownero && coin != Coin.epicCash; _currentSyncStatus = widget.initialSyncStatus; // _currentNodeStatus = widget.initialNodeStatus; @@ -281,6 +285,19 @@ class _WalletSettingsViewState extends State { .pushNamed(DebugView.routeName); }, ), + if (xPubEnabled) + const SizedBox( + height: 8, + ), + if (xPubEnabled) + SettingsListButton( + iconAssetName: Assets.svg.eye, + title: "Wallet xPub", + onPressed: () { + Navigator.of(context) + .pushNamed(XPubView.routeName); + }, + ), ], ), ), diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 80a093eb3..f1a3d982f 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -84,6 +84,7 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/support_vi import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart'; +import 'package:stackwallet/pages/settings_views/global_settings_view/xpub_view.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_view.dart'; @@ -397,6 +398,12 @@ class RouteGenerator { builder: (_) => const DebugView(), settings: RouteSettings(name: settings.name)); + case XPubView.routeName: + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const XPubView(), + settings: RouteSettings(name: settings.name)); + case AppearanceSettingsView.routeName: return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, From 2038fbcec600f44d90216a3ea61cc4835c80fb07 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 15:04:30 -0500 Subject: [PATCH 16/17] add working xpub settings view with click to copy to clipboard --- .../global_settings_view/xpub_view.dart | 50 ++++++++++++++++++- .../wallet_settings_view.dart | 48 +++++++++++++----- lib/route_generator.dart | 14 ++++-- 3 files changed, 94 insertions(+), 18 deletions(-) diff --git a/lib/pages/settings_views/global_settings_view/xpub_view.dart b/lib/pages/settings_views/global_settings_view/xpub_view.dart index 8875514d1..acae5e837 100644 --- a/lib/pages/settings_views/global_settings_view/xpub_view.dart +++ b/lib/pages/settings_views/global_settings_view/xpub_view.dart @@ -1,12 +1,27 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:qr_flutter/qr_flutter.dart'; +import 'package:stackwallet/notifications/show_flush_bar.dart'; +import 'package:stackwallet/utilities/assets.dart'; +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/background.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; class XPubView extends ConsumerStatefulWidget { - const XPubView({Key? key}) : super(key: key); + const XPubView({ + Key? key, + this.xpub, + this.clipboardInterface = const ClipboardWrapper(), + }) : super(key: key); + + final String? xpub; + final ClipboardInterface clipboardInterface; static const String routeName = "/xpub"; @@ -15,8 +30,11 @@ class XPubView extends ConsumerStatefulWidget { } class _XPubViewState extends ConsumerState { + late ClipboardInterface _clipboardInterface; + @override void initState() { + _clipboardInterface = widget.clipboardInterface; super.initState(); } @@ -25,6 +43,16 @@ class _XPubViewState extends ConsumerState { super.dispose(); } + Future _copy() async { + await _clipboardInterface.setData(ClipboardData(text: widget.xpub)); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + iconAsset: Assets.svg.copy, + context: context, + )); + } + @override Widget build(BuildContext context) { return Background( @@ -47,7 +75,25 @@ class _XPubViewState extends ConsumerState { left: 16, right: 16, ), - child: Text("TODO"), + child: Column(children: [ + if (widget.xpub != null) + RoundedWhiteContainer( + padding: const EdgeInsets.all(12), + child: QrImage(data: widget.xpub!), + onPressed: () => _copy(), + ), + if (widget.xpub != null) + const SizedBox( + height: 8, + ), + if (widget.xpub != null) + RoundedWhiteContainer( + padding: const EdgeInsets.all(12), + child: Text(widget.xpub!, + style: STextStyles.largeMedium14(context)), + onPressed: () => _copy(), + ) + ]), ), ), ); diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart index 34196b8a9..ca48c8b6b 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'package:bip32/bip32.dart' as bip32; +import 'package:bip39/bip39.dart' as bip39; import 'package:event_bus/event_bus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -58,6 +60,7 @@ class WalletSettingsView extends StatefulWidget { class _WalletSettingsViewState extends State { late final String walletId; late final Coin coin; + late String xpub; late final bool xPubEnabled; late final EventBus eventBus; @@ -74,6 +77,7 @@ class _WalletSettingsViewState extends State { coin = widget.coin; xPubEnabled = coin != Coin.monero && coin != Coin.wownero && coin != Coin.epicCash; + xpub = ""; _currentSyncStatus = widget.initialSyncStatus; // _currentNodeStatus = widget.initialNodeStatus; @@ -274,6 +278,37 @@ class _WalletSettingsViewState extends State { SyncingPreferencesView.routeName); }, ), + if (xPubEnabled) + const SizedBox( + height: 8, + ), + if (xPubEnabled) + Consumer( + builder: (_, ref, __) { + return SettingsListButton( + iconAssetName: Assets.svg.eye, + title: "Wallet xPub", + onPressed: () async { + final List mnemonic = await ref + .read( + walletsChangeNotifierProvider) + .getManager(widget.walletId) + .mnemonic; + + final seed = bip39.mnemonicToSeed( + mnemonic.join(' ')); + final node = + bip32.BIP32.fromSeed(seed); + final xpub = + node.neutered().toBase58(); + + Navigator.of(context).pushNamed( + XPubView.routeName, + arguments: xpub); + }, + ); + }, + ), const SizedBox( height: 8, ), @@ -285,19 +320,6 @@ class _WalletSettingsViewState extends State { .pushNamed(DebugView.routeName); }, ), - if (xPubEnabled) - const SizedBox( - height: 8, - ), - if (xPubEnabled) - SettingsListButton( - iconAssetName: Assets.svg.eye, - title: "Wallet xPub", - onPressed: () { - Navigator.of(context) - .pushNamed(XPubView.routeName); - }, - ), ], ), ), diff --git a/lib/route_generator.dart b/lib/route_generator.dart index f1a3d982f..597db1b78 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -399,10 +399,18 @@ class RouteGenerator { settings: RouteSettings(name: settings.name)); case XPubView.routeName: - return getRoute( + if (args is String) { + return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, - builder: (_) => const XPubView(), - settings: RouteSettings(name: settings.name)); + builder: (_) => XPubView( + xpub: args, + ), + settings: RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); case AppearanceSettingsView.routeName: return getRoute( From 08b40c464bc188e90d6d87e7d96ab108129d6467 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Thu, 6 Apr 2023 15:12:33 -0500 Subject: [PATCH 17/17] add copy icon to top right of xpub view --- .../global_settings_view/xpub_view.dart | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/lib/pages/settings_views/global_settings_view/xpub_view.dart b/lib/pages/settings_views/global_settings_view/xpub_view.dart index acae5e837..fce352037 100644 --- a/lib/pages/settings_views/global_settings_view/xpub_view.dart +++ b/lib/pages/settings_views/global_settings_view/xpub_view.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -59,16 +60,39 @@ class _XPubViewState extends ConsumerState { child: Scaffold( backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( - leading: AppBarBackButton( - onPressed: () async { - Navigator.of(context).pop(); - }, - ), - title: Text( - "Wallet xPub", - style: STextStyles.navBarTitle(context), - ), - ), + leading: AppBarBackButton( + onPressed: () async { + Navigator.of(context).pop(); + }, + ), + title: Text( + "Wallet xPub", + style: STextStyles.navBarTitle(context), + ), + actions: [ + Padding( + padding: const EdgeInsets.all(10), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + color: + Theme.of(context).extension()!.background, + shadows: const [], + icon: SvgPicture.asset( + Assets.svg.copy, + width: 24, + height: 24, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, + ), + onPressed: () async { + await _copy(); + }, + ), + ), + ), + ]), body: Padding( padding: const EdgeInsets.only( top: 12,