mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-08 19:59:29 +00:00
show xpubs
This commit is contained in:
parent
d66e0580ec
commit
64b61779cd
4 changed files with 170 additions and 214 deletions
|
@ -35,6 +35,7 @@ import '../../../wallets/crypto_currency/intermediate/frost_currency.dart';
|
|||
import '../../../wallets/crypto_currency/intermediate/nano_currency.dart';
|
||||
import '../../../wallets/wallet/impl/bitcoin_frost_wallet.dart';
|
||||
import '../../../wallets/wallet/impl/epiccash_wallet.dart';
|
||||
import '../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
|
||||
import '../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
|
||||
import '../../../widgets/background.dart';
|
||||
import '../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
|
@ -95,9 +96,9 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
|||
void initState() {
|
||||
walletId = widget.walletId;
|
||||
coin = widget.coin;
|
||||
// TODO: [prio=low] xpubs
|
||||
// xPubEnabled = ref.read(pWallets).getWallet(walletId).hasXPub;
|
||||
xPubEnabled = false;
|
||||
xPubEnabled =
|
||||
ref.read(pWallets).getWallet(walletId) is ExtendedKeysInterface;
|
||||
|
||||
xpub = "";
|
||||
|
||||
_currentSyncStatus = widget.initialSyncStatus;
|
||||
|
@ -373,11 +374,30 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
|||
return SettingsListButton(
|
||||
iconAssetName: Assets.svg.eye,
|
||||
title: "Wallet xPub",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
XPubView.routeName,
|
||||
arguments: widget.walletId,
|
||||
onPressed: () async {
|
||||
final xpubData = await showLoading(
|
||||
delay: const Duration(
|
||||
milliseconds: 800,
|
||||
),
|
||||
whileFuture: (ref
|
||||
.read(pWallets)
|
||||
.getWallet(walletId)
|
||||
as ExtendedKeysInterface)
|
||||
.getXPubs(),
|
||||
context: context,
|
||||
message: "Loading xpubs",
|
||||
rootNavigator: Util.isDesktop,
|
||||
);
|
||||
if (context.mounted) {
|
||||
await Navigator.of(context)
|
||||
.pushNamed(
|
||||
XPubView.routeName,
|
||||
arguments: (
|
||||
widget.walletId,
|
||||
xpubData
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
|
@ -13,80 +13,45 @@ 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 '../../../../notifications/show_flush_bar.dart';
|
||||
import '../../../../providers/global/wallets_provider.dart';
|
||||
import '../../../../themes/stack_colors.dart';
|
||||
import '../../../../utilities/assets.dart';
|
||||
import '../../../../utilities/clipboard_interface.dart';
|
||||
import '../../../../utilities/text_styles.dart';
|
||||
import '../../../../utilities/util.dart';
|
||||
import '../../../../wallets/wallet/wallet.dart';
|
||||
import '../../../../wallets/isar/providers/wallet_info_provider.dart';
|
||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
|
||||
import '../../../../widgets/background.dart';
|
||||
import '../../../../widgets/conditional_parent.dart';
|
||||
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import '../../../../widgets/custom_tab_view.dart';
|
||||
import '../../../../widgets/desktop/desktop_dialog.dart';
|
||||
import '../../../../widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import '../../../../widgets/desktop/primary_button.dart';
|
||||
import '../../../../widgets/desktop/secondary_button.dart';
|
||||
import '../../../../widgets/loading_indicator.dart';
|
||||
import '../../../../widgets/detail_item.dart';
|
||||
import '../../../../widgets/qr.dart';
|
||||
import '../../../../widgets/rounded_white_container.dart';
|
||||
|
||||
class XPubView extends ConsumerStatefulWidget {
|
||||
class XPubView extends ConsumerWidget {
|
||||
const XPubView({
|
||||
super.key,
|
||||
required this.walletId,
|
||||
required this.xpubData,
|
||||
this.clipboardInterface = const ClipboardWrapper(),
|
||||
});
|
||||
|
||||
final String walletId;
|
||||
final ClipboardInterface clipboardInterface;
|
||||
final ({List<XPub> xpubs, String fingerprint}) xpubData;
|
||||
|
||||
static const String routeName = "/xpub";
|
||||
|
||||
@override
|
||||
ConsumerState<XPubView> createState() => _XPubViewState();
|
||||
}
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final bool isDesktop = Util.isDesktop;
|
||||
|
||||
class _XPubViewState extends ConsumerState<XPubView> {
|
||||
final bool isDesktop = Util.isDesktop;
|
||||
|
||||
late ClipboardInterface _clipboardInterface;
|
||||
late final Wallet wallet;
|
||||
|
||||
String? xpub;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_clipboardInterface = widget.clipboardInterface;
|
||||
wallet = ref.read(pWallets).getWallet(widget.walletId);
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _copy() async {
|
||||
await _clipboardInterface.setData(ClipboardData(text: xpub!));
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "Copied to clipboard",
|
||||
iconAsset: Assets.svg.copy,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) => Background(
|
||||
|
@ -100,35 +65,9 @@ class _XPubViewState extends ConsumerState<XPubView> {
|
|||
},
|
||||
),
|
||||
title: Text(
|
||||
"Wallet xPub",
|
||||
"Wallet xpub(s)",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: AppBarIconButton(
|
||||
color:
|
||||
Theme.of(context).extension<StackColors>()!.background,
|
||||
shadows: const [],
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.copy,
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.topNavIconPrimary,
|
||||
),
|
||||
onPressed: () {
|
||||
if (xpub != null) {
|
||||
_copy();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
|
@ -136,7 +75,7 @@ class _XPubViewState extends ConsumerState<XPubView> {
|
|||
left: 16,
|
||||
right: 16,
|
||||
),
|
||||
child: child,
|
||||
child: SingleChildScrollView(child: child),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -146,6 +85,7 @@ class _XPubViewState extends ConsumerState<XPubView> {
|
|||
maxWidth: 600,
|
||||
maxHeight: double.infinity,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
@ -155,7 +95,7 @@ class _XPubViewState extends ConsumerState<XPubView> {
|
|||
left: 32,
|
||||
),
|
||||
child: Text(
|
||||
"${wallet.info.name} xPub",
|
||||
"${ref.watch(pWalletName(walletId))} xpub(s)",
|
||||
style: STextStyles.desktopH2(context),
|
||||
),
|
||||
),
|
||||
|
@ -167,62 +107,40 @@ class _XPubViewState extends ConsumerState<XPubView> {
|
|||
),
|
||||
],
|
||||
),
|
||||
AnimatedSize(
|
||||
duration: const Duration(
|
||||
milliseconds: 150,
|
||||
),
|
||||
Flexible(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(32, 0, 32, 32),
|
||||
child: child,
|
||||
child: SingleChildScrollView(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (isDesktop) const SizedBox(height: 44),
|
||||
ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) => Expanded(
|
||||
child: child,
|
||||
),
|
||||
child: FutureBuilder(
|
||||
future: Future(() => "fixme"),
|
||||
// future: wallet.xpub,
|
||||
builder: (context, AsyncSnapshot<String> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
xpub = snapshot.data!;
|
||||
}
|
||||
|
||||
const height = 600.0;
|
||||
Widget child;
|
||||
if (xpub == null) {
|
||||
child = const SizedBox(
|
||||
key: Key("loadingXPUB"),
|
||||
height: height,
|
||||
child: Center(
|
||||
child: LoadingIndicator(
|
||||
width: 100,
|
||||
),
|
||||
if (isDesktop) const SizedBox(height: 16),
|
||||
DetailItem(
|
||||
title: "Master fingerprint",
|
||||
detail: xpubData.fingerprint,
|
||||
horizontal: true,
|
||||
),
|
||||
if (isDesktop) const SizedBox(height: 16),
|
||||
CustomTabView(
|
||||
titles: xpubData.xpubs.map((e) => e.path).toList(),
|
||||
children: xpubData.xpubs
|
||||
.map(
|
||||
(e) => Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: _XPub(
|
||||
xpub: e.xpub,
|
||||
derivation: e.path,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
child = _XPub(
|
||||
xpub: xpub!,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(
|
||||
milliseconds: 200,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -235,85 +153,86 @@ class _XPub extends StatelessWidget {
|
|||
const _XPub({
|
||||
super.key,
|
||||
required this.xpub,
|
||||
required this.height,
|
||||
required this.derivation,
|
||||
this.clipboardInterface = const ClipboardWrapper(),
|
||||
});
|
||||
|
||||
final String xpub;
|
||||
final double height;
|
||||
final String derivation;
|
||||
|
||||
final ClipboardInterface clipboardInterface;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool isDesktop = Util.isDesktop;
|
||||
|
||||
return SizedBox(
|
||||
height: isDesktop ? height : double.infinity,
|
||||
child: Column(
|
||||
children: [
|
||||
ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) => RoundedWhiteContainer(
|
||||
child: child,
|
||||
),
|
||||
child: QR(
|
||||
data: xpub,
|
||||
size: isDesktop ? 280 : MediaQuery.of(context).size.width / 1.5,
|
||||
),
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 25,
|
||||
),
|
||||
ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) => RoundedWhiteContainer(
|
||||
child: child,
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(16),
|
||||
borderColor:
|
||||
Theme.of(context).extension<StackColors>()!.backgroundAppBar,
|
||||
child: SelectableText(
|
||||
xpub,
|
||||
style: STextStyles.largeMedium14(context),
|
||||
),
|
||||
child: QR(
|
||||
data: xpub,
|
||||
size: isDesktop ? 280 : MediaQuery.of(context).size.width / 1.5,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Row(
|
||||
children: [
|
||||
if (isDesktop)
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
buttonHeight: ButtonHeight.xl,
|
||||
label: "Cancel",
|
||||
onPressed: Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop,
|
||||
),
|
||||
),
|
||||
if (isDesktop) const SizedBox(width: 16),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(16),
|
||||
borderColor:
|
||||
Theme.of(context).extension<StackColors>()!.backgroundAppBar,
|
||||
child: SelectableText(
|
||||
xpub,
|
||||
style: STextStyles.largeMedium14(context),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Row(
|
||||
children: [
|
||||
if (isDesktop)
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
child: SecondaryButton(
|
||||
buttonHeight: ButtonHeight.xl,
|
||||
label: "Copy",
|
||||
onPressed: () async {
|
||||
await clipboardInterface.setData(
|
||||
ClipboardData(
|
||||
text: xpub,
|
||||
),
|
||||
);
|
||||
if (context.mounted) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "Copied to clipboard",
|
||||
iconAsset: Assets.svg.copy,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
label: "Cancel",
|
||||
onPressed: Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!isDesktop) const Spacer(),
|
||||
],
|
||||
),
|
||||
if (isDesktop) const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
buttonHeight: ButtonHeight.xl,
|
||||
label: "Copy",
|
||||
onPressed: () async {
|
||||
await clipboardInterface.setData(
|
||||
ClipboardData(
|
||||
text: xpub,
|
||||
),
|
||||
);
|
||||
if (context.mounted) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "Copied to clipboard",
|
||||
iconAsset: Assets.svg.copy,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,19 @@ import 'package:flutter_svg/svg.dart';
|
|||
import '../../../../pages/settings_views/wallet_settings_view/frost_ms/frost_ms_options_view.dart';
|
||||
import '../../../../pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/change_representative_view.dart';
|
||||
import '../../../../pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/xpub_view.dart';
|
||||
import '../../../../providers/global/wallets_provider.dart';
|
||||
import '../../../../route_generator.dart';
|
||||
import '../../../../themes/stack_colors.dart';
|
||||
import '../../../../utilities/assets.dart';
|
||||
import '../../../../utilities/constants.dart';
|
||||
import '../../../../utilities/show_loading.dart';
|
||||
import '../../../../utilities/text_styles.dart';
|
||||
import '../../../../utilities/util.dart';
|
||||
import '../../../../wallets/crypto_currency/coins/firo.dart';
|
||||
import '../../../../wallets/crypto_currency/intermediate/frost_currency.dart';
|
||||
import '../../../../wallets/crypto_currency/intermediate/nano_currency.dart';
|
||||
import '../../../../wallets/isar/providers/wallet_info_provider.dart';
|
||||
import '../../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
|
||||
import '../../../addresses/desktop_wallet_addresses_view.dart';
|
||||
import '../../../lelantus_coins/lelantus_coins_view.dart';
|
||||
import '../../../spark_coins/spark_coins_view.dart';
|
||||
|
@ -61,7 +65,7 @@ enum _WalletOptions {
|
|||
}
|
||||
}
|
||||
|
||||
class WalletOptionsButton extends StatelessWidget {
|
||||
class WalletOptionsButton extends ConsumerWidget {
|
||||
const WalletOptionsButton({
|
||||
super.key,
|
||||
required this.walletId,
|
||||
|
@ -70,7 +74,7 @@ class WalletOptionsButton extends StatelessWidget {
|
|||
final String walletId;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return RawMaterialButton(
|
||||
constraints: const BoxConstraints(
|
||||
minHeight: 32,
|
||||
|
@ -148,28 +152,40 @@ class WalletOptionsButton extends StatelessWidget {
|
|||
}
|
||||
break;
|
||||
case _WalletOptions.showXpub:
|
||||
final result = await showDialog<bool?>(
|
||||
final xpubData = await showLoading(
|
||||
delay: const Duration(milliseconds: 800),
|
||||
whileFuture: (ref.read(pWallets).getWallet(walletId)
|
||||
as ExtendedKeysInterface)
|
||||
.getXPubs(),
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => Navigator(
|
||||
initialRoute: XPubView.routeName,
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
onGenerateInitialRoutes: (_, __) {
|
||||
return [
|
||||
RouteGenerator.generateRoute(
|
||||
RouteSettings(
|
||||
name: XPubView.routeName,
|
||||
arguments: walletId,
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
message: "Loading xpubs",
|
||||
rootNavigator: Util.isDesktop,
|
||||
);
|
||||
|
||||
if (result == true) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
if (context.mounted) {
|
||||
final result = await showDialog<bool?>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => Navigator(
|
||||
initialRoute: XPubView.routeName,
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
onGenerateInitialRoutes: (_, __) {
|
||||
return [
|
||||
RouteGenerator.generateRoute(
|
||||
RouteSettings(
|
||||
name: XPubView.routeName,
|
||||
arguments: (walletId, xpubData),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (result == true) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -279,9 +295,8 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
|
|||
|
||||
final firoDebug = kDebugMode && (coin is Firo);
|
||||
|
||||
// TODO: [prio=low]
|
||||
// final bool xpubEnabled = manager.hasXPub;
|
||||
final bool xpubEnabled = false;
|
||||
final bool xpubEnabled =
|
||||
ref.watch(pWallets).getWallet(walletId) is ExtendedKeysInterface;
|
||||
|
||||
final bool canChangeRep = coin is NanoCurrency;
|
||||
|
||||
|
|
|
@ -198,6 +198,7 @@ import 'wallets/crypto_currency/crypto_currency.dart';
|
|||
import 'wallets/crypto_currency/intermediate/frost_currency.dart';
|
||||
import 'wallets/models/tx_data.dart';
|
||||
import 'wallets/wallet/wallet.dart';
|
||||
import 'wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
|
||||
import 'widgets/choose_coin_view.dart';
|
||||
import 'widgets/frost_scaffold.dart';
|
||||
|
||||
|
@ -908,11 +909,12 @@ class RouteGenerator {
|
|||
);
|
||||
|
||||
case XPubView.routeName:
|
||||
if (args is String) {
|
||||
if (args is (String, ({List<XPub> xpubs, String fingerprint}))) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => XPubView(
|
||||
walletId: args,
|
||||
walletId: args.$1,
|
||||
xpubData: args.$2,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
|
|
Loading…
Reference in a new issue