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(