fix delete frost wallet on mobile

This commit is contained in:
julian 2024-05-14 09:49:20 -06:00
parent 33c78a4b42
commit 738cb55a40
4 changed files with 338 additions and 115 deletions

View file

@ -17,6 +17,7 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
import 'package:stackwallet/pages/home_view/home_view.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/themes/stack_colors.dart';
@ -24,23 +25,35 @@ import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart';
import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/detail_item.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
class DeleteWalletRecoveryPhraseView extends ConsumerStatefulWidget {
const DeleteWalletRecoveryPhraseView({
Key? key,
super.key,
required this.walletId,
required this.mnemonic,
this.frostWalletData,
this.clipboardInterface = const ClipboardWrapper(),
}) : super(key: key);
});
static const routeName = "/deleteWalletRecoveryPhrase";
final String walletId;
final List<String> mnemonic;
final ({
String myName,
String config,
String keys,
({String config, String keys})? prevGen,
})? frostWalletData;
final ClipboardInterface clipboardInterface;
@ -54,6 +67,62 @@ class _DeleteWalletRecoveryPhraseViewState
late List<String> _mnemonic;
late ClipboardInterface _clipboardInterface;
bool _lock = false;
void _continuePressed() {
if (_lock) {
return;
}
_lock = true;
try {
showDialog<dynamic>(
barrierDismissible: true,
context: context,
builder: (_) => StackDialog(
title: "Thanks! Your wallet will be deleted.",
leftButton: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getSecondaryEnabledButtonStyle(context),
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Cancel",
style: STextStyles.button(context).copyWith(
color:
Theme.of(context).extension<StackColors>()!.accentColorDark,
),
),
),
rightButton: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonStyle(context),
onPressed: () async {
await ref.read(pWallets).deleteWallet(
ref.read(pWalletInfo(widget.walletId)),
ref.read(secureStoreProvider),
);
if (mounted) {
Navigator.of(context).popUntil(
ModalRoute.withName(HomeView.routeName),
);
}
},
child: Text(
"Ok",
style: STextStyles.button(context),
),
),
),
);
} finally {
_lock = false;
}
}
@override
void initState() {
_mnemonic = widget.mnemonic;
@ -65,6 +134,9 @@ class _DeleteWalletRecoveryPhraseViewState
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
final bool frost = widget.frostWalletData != null;
final prevGen = widget.frostWalletData?.prevGen != null;
return Background(
child: Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
@ -93,7 +165,7 @@ class _DeleteWalletRecoveryPhraseViewState
onPressed: () async {
await _clipboardInterface
.setData(ClipboardData(text: _mnemonic.join(" ")));
if (mounted) {
if (context.mounted) {
unawaited(
showFloatingFlushBar(
type: FlushBarType.info,
@ -111,7 +183,138 @@ class _DeleteWalletRecoveryPhraseViewState
),
body: Padding(
padding: const EdgeInsets.all(16),
child: frost
? LayoutBuilder(
builder: (builderContext, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
RoundedWhiteContainer(
child: Text(
"Please write down your backup data. Keep it safe and "
"never share it with anyone. "
"Your backup data is the only way you can access your "
"funds if you forget your PIN, lose your phone, etc."
"\n\n"
"Stack Wallet does not keep nor is able to restore "
"your backup data. "
"Only you have access to your wallet.",
style: STextStyles.label(context),
),
),
const SizedBox(
height: 24,
),
// DetailItem(
// title: "My name",
// detail: frostWalletData!.myName,
// button: Util.isDesktop
// ? IconCopyButton(
// data: frostWalletData!.myName,
// )
// : SimpleCopyButton(
// data: frostWalletData!.myName,
// ),
// ),
// const SizedBox(
// height: 16,
// ),
DetailItem(
title: "Multisig config",
detail: widget.frostWalletData!.config,
button: Util.isDesktop
? IconCopyButton(
data: widget.frostWalletData!.config,
)
: SimpleCopyButton(
data: widget.frostWalletData!.config,
),
),
const SizedBox(
height: 16,
),
DetailItem(
title: "Keys",
detail: widget.frostWalletData!.keys,
button: Util.isDesktop
? IconCopyButton(
data: widget.frostWalletData!.keys,
)
: SimpleCopyButton(
data: widget.frostWalletData!.keys,
),
),
if (prevGen)
const SizedBox(
height: 24,
),
if (prevGen)
RoundedWhiteContainer(
child: Text(
"Previous generation info",
style: STextStyles.label(context),
),
),
if (prevGen)
const SizedBox(
height: 12,
),
if (prevGen)
DetailItem(
title: "Previous multisig config",
detail:
widget.frostWalletData!.prevGen!.config,
button: Util.isDesktop
? IconCopyButton(
data: widget
.frostWalletData!.prevGen!.config,
)
: SimpleCopyButton(
data: widget
.frostWalletData!.prevGen!.config,
),
),
if (prevGen)
const SizedBox(
height: 16,
),
if (prevGen)
DetailItem(
title: "Previous keys",
detail: widget.frostWalletData!.prevGen!.keys,
button: Util.isDesktop
? IconCopyButton(
data: widget
.frostWalletData!.prevGen!.keys,
)
: SimpleCopyButton(
data: widget
.frostWalletData!.prevGen!.keys,
),
),
const Spacer(),
const SizedBox(
height: 16,
),
PrimaryButton(
label: "Continue",
onPressed: _continuePressed,
),
],
),
),
),
);
},
)
: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
@ -137,9 +340,11 @@ class _DeleteWalletRecoveryPhraseViewState
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).extension<StackColors>()!.popupBG,
color:
Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius),
Constants.size.circularBorderRadius,
),
),
child: Padding(
padding: const EdgeInsets.all(12),
@ -148,7 +353,8 @@ class _DeleteWalletRecoveryPhraseViewState
style: STextStyles.label(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
.accentColorDark,
),
),
),
),
@ -170,50 +376,7 @@ class _DeleteWalletRecoveryPhraseViewState
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonStyle(context),
onPressed: () {
showDialog<dynamic>(
barrierDismissible: true,
context: context,
builder: (_) => StackDialog(
title: "Thanks! Your wallet will be deleted.",
leftButton: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getSecondaryEnabledButtonStyle(context),
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Cancel",
style: STextStyles.button(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
),
),
rightButton: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonStyle(context),
onPressed: () async {
await ref.read(pWallets).deleteWallet(
ref.read(pWalletInfo(widget.walletId)),
ref.read(secureStoreProvider),
);
if (mounted) {
Navigator.of(context).popUntil(
ModalRoute.withName(HomeView.routeName));
}
},
child: Text(
"Ok",
style: STextStyles.button(context),
),
),
),
);
},
onPressed: _continuePressed,
child: Text(
"Continue",
style: STextStyles.button(context),

View file

@ -14,6 +14,7 @@ import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_set
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/wallets/wallet/impl/bitcoin_frost_wallet.dart';
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart';
import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
@ -21,9 +22,9 @@ import 'package:stackwallet/widgets/rounded_container.dart';
class DeleteWalletWarningView extends ConsumerWidget {
const DeleteWalletWarningView({
Key? key,
super.key,
required this.walletId,
}) : super(key: key);
});
static const String routeName = "/deleteWalletWarning";
@ -100,14 +101,50 @@ class DeleteWalletWarningView extends ConsumerWidget {
.getPrimaryEnabledButtonStyle(context),
onPressed: () async {
final wallet = ref.read(pWallets).getWallet(walletId);
final mnemonic =
await (wallet as MnemonicInterface).getMnemonicAsWords();
// TODO: [prio=med] take wallets that don't have a mnemonic into account
List<String>? mnemonic;
({
String myName,
String config,
String keys,
({String config, String keys})? prevGen,
})? frostWalletData;
if (wallet is BitcoinFrostWallet) {
final futures = [
wallet.getSerializedKeys(),
wallet.getMultisigConfig(),
wallet.getSerializedKeysPrevGen(),
wallet.getMultisigConfigPrevGen(),
];
final results = await Future.wait(futures);
if (results.length == 4) {
frostWalletData = (
myName: wallet.frostInfo.myName,
config: results[1]!,
keys: results[0]!,
prevGen: results[2] == null || results[3] == null
? null
: (
config: results[3]!,
keys: results[2]!,
),
);
}
} else if (wallet is MnemonicInterface) {
mnemonic = await wallet.getMnemonicAsWords();
}
if (context.mounted) {
await Navigator.of(context).pushNamed(
DeleteWalletRecoveryPhraseView.routeName,
arguments: (
walletId: walletId,
mnemonicWords: mnemonic,
mnemonicWords: mnemonic ?? [],
frostWalletData: frostWalletData,
),
);
}

View file

@ -124,7 +124,8 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget {
style: STextStyles.button(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
.accentColorDark,
),
),
),
rightButton: TextButton(
@ -150,7 +151,8 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget {
"Delete wallet",
),
settings: const RouteSettings(
name: "/deleteWalletLockscreen"),
name: "/deleteWalletLockscreen",
),
),
);
},

View file

@ -1745,6 +1745,27 @@ class RouteGenerator {
name: settings.name,
),
);
} else if (args is ({
String walletId,
List<String> mnemonicWords,
({
String myName,
String config,
String keys,
({String config, String keys})? prevGen,
})? frostWalletData,
})) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => DeleteWalletRecoveryPhraseView(
mnemonic: args.mnemonicWords,
walletId: args.walletId,
frostWalletData: args.frostWalletData,
),
settings: RouteSettings(
name: settings.name,
),
);
}
return _routeError("${settings.name} invalid args: ${args.toString()}");