recovery warning desktop ui

This commit is contained in:
julian 2022-09-18 11:27:38 -06:00
parent 3047a90b41
commit f63acf4fa7
5 changed files with 228 additions and 153 deletions

View file

@ -1,6 +1,10 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/coin_service.dart';
import 'package:stackwallet/services/coins/manager.dart';
@ -12,7 +16,10 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart';
class NewWalletRecoveryPhraseWarningView extends StatefulWidget {
@ -36,11 +43,13 @@ class _NewWalletRecoveryPhraseWarningViewState
extends State<NewWalletRecoveryPhraseWarningView> {
late final Coin coin;
late final String walletName;
late final bool isDesktop;
@override
void initState() {
coin = widget.coin;
walletName = widget.walletName;
isDesktop = Platform.isMacOS || Platform.isWindows || Platform.isLinux;
super.initState();
}
@ -52,24 +61,28 @@ class _NewWalletRecoveryPhraseWarningViewState
? Constants.seedPhraseWordCountMonero
: Constants.seedPhraseWordCountBip39;
return Scaffold(
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () {
Navigator.of(context).pop();
},
),
),
body: Container(
color: CFColors.almostWhite,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 4,
),
return MasterScaffold(
isDesktop: isDesktop,
appBar: isDesktop
? const DesktopAppBar(
isCompactHeight: false,
leading: AppBarBackButton(),
trailing: ExitToMyStackButton(),
)
: AppBar(
leading: const AppBarBackButton(),
),
body: Padding(
padding: EdgeInsets.all(isDesktop ? 0 : 16),
child: Column(
crossAxisAlignment: isDesktop
? CrossAxisAlignment.center
: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 4,
),
if (!isDesktop)
Text(
walletName,
textAlign: TextAlign.center,
@ -77,35 +90,42 @@ class _NewWalletRecoveryPhraseWarningViewState
fontSize: 12,
),
),
const SizedBox(
height: 4,
),
Text(
"Recovery Phrase",
textAlign: TextAlign.center,
style:
isDesktop ? STextStyles.desktopH2 : STextStyles.pageTitleH1,
),
SizedBox(
height: isDesktop ? 32 : 16,
),
RoundedWhiteContainer(
padding: isDesktop
? const EdgeInsets.all(32)
: const EdgeInsets.all(12),
width: isDesktop ? 480 : null,
child: Text(
"On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.",
style: isDesktop
? STextStyles.desktopTextMediumRegular
: STextStyles.subtitle.copyWith(
fontSize: 12,
),
),
),
if (!isDesktop) const Spacer(),
if (isDesktop)
const SizedBox(
height: 4,
height: 32,
),
Text(
"Recovery Phrase",
textAlign: TextAlign.center,
style: STextStyles.pageTitleH1,
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: isDesktop ? 480 : 0,
),
const SizedBox(
height: 16,
),
Container(
decoration: BoxDecoration(
color: CFColors.white,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Text(
"On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.",
style: STextStyles.subtitle.copyWith(
fontSize: 12,
),
),
),
),
const Spacer(),
Consumer(
child: Consumer(
builder: (_, ref, __) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
@ -119,6 +139,9 @@ class _NewWalletRecoveryPhraseWarningViewState
child: Container(
color: Colors.transparent,
child: Row(
crossAxisAlignment: isDesktop
? CrossAxisAlignment.start
: CrossAxisAlignment.center,
children: [
Checkbox(
materialTapTargetSize:
@ -131,138 +154,139 @@ class _NewWalletRecoveryPhraseWarningViewState
newValue!;
},
),
const SizedBox(
width: 4,
SizedBox(
width: isDesktop ? 14 : 4,
),
Flexible(
child: Text(
"I understand that if I lose my recovery phrase, I will not be able to access my funds.",
style: STextStyles.baseXS,
style: isDesktop
? STextStyles.desktopTextMedium
: STextStyles.baseXS,
),
),
],
),
),
),
const SizedBox(
height: 16,
SizedBox(
height: isDesktop ? 32 : 16,
),
TextButton(
onPressed: ref.read(checkBoxStateProvider.state).state
? () async {
try {
showDialog<dynamic>(
context: context,
barrierDismissible: false,
useSafeArea: true,
builder: (ctx) {
return const Center(
child: LoadingIndicator(
width: 50,
height: 50,
),
);
},
);
final walletsService = ref.read(
walletsServiceChangeNotifierProvider);
final walletId =
await walletsService.addNewWallet(
name: walletName,
coin: coin,
shouldNotifyListeners: false,
);
var node = ref
.read(nodeServiceChangeNotifierProvider)
.getPrimaryNodeFor(coin: coin);
if (node == null) {
node = DefaultNodes.getNodeFor(coin);
ref
.read(nodeServiceChangeNotifierProvider)
.setPrimaryNodeFor(
coin: coin,
node: node,
ConstrainedBox(
constraints: BoxConstraints(
minHeight: isDesktop ? 70 : 0,
),
child: TextButton(
onPressed: ref.read(checkBoxStateProvider.state).state
? () async {
try {
unawaited(showDialog<dynamic>(
context: context,
barrierDismissible: false,
useSafeArea: true,
builder: (ctx) {
return const Center(
child: LoadingIndicator(
width: 50,
height: 50,
),
);
}
},
));
final txTracker =
TransactionNotificationTracker(
walletId: walletId!);
final walletsService = ref.read(
walletsServiceChangeNotifierProvider);
final failovers = ref
.read(nodeServiceChangeNotifierProvider)
.failoverNodesFor(coin: widget.coin);
final wallet = CoinServiceAPI.from(
coin,
walletId,
walletName,
node,
txTracker,
ref.read(prefsChangeNotifierProvider),
failovers,
);
final manager = Manager(wallet);
await manager.initializeNew();
// pop progress dialog
if (mounted) {
Navigator.pop(context);
}
// set checkbox back to unchecked to annoy users to agree again :P
ref.read(checkBoxStateProvider.state).state =
false;
if (mounted) {
Navigator.of(context).pushNamed(
NewWalletRecoveryPhraseView.routeName,
arguments: Tuple2(
manager,
await manager.mnemonic,
),
final walletId =
await walletsService.addNewWallet(
name: walletName,
coin: coin,
shouldNotifyListeners: false,
);
var node = ref
.read(nodeServiceChangeNotifierProvider)
.getPrimaryNodeFor(coin: coin);
if (node == null) {
node = DefaultNodes.getNodeFor(coin);
await ref
.read(
nodeServiceChangeNotifierProvider)
.setPrimaryNodeFor(
coin: coin,
node: node,
);
}
final txTracker =
TransactionNotificationTracker(
walletId: walletId!);
final failovers = ref
.read(nodeServiceChangeNotifierProvider)
.failoverNodesFor(coin: widget.coin);
final wallet = CoinServiceAPI.from(
coin,
walletId,
walletName,
node,
txTracker,
ref.read(prefsChangeNotifierProvider),
failovers,
);
final manager = Manager(wallet);
await manager.initializeNew();
// pop progress dialog
if (mounted) {
Navigator.pop(context);
}
// set checkbox back to unchecked to annoy users to agree again :P
ref
.read(checkBoxStateProvider.state)
.state = false;
if (mounted) {
unawaited(Navigator.of(context).pushNamed(
NewWalletRecoveryPhraseView.routeName,
arguments: Tuple2(
manager,
await manager.mnemonic,
),
));
}
} catch (e, s) {
Logging.instance
.log("$e\n$s", level: LogLevel.Fatal);
// TODO: handle gracefully
// any network/socket exception here will break new wallet creation
rethrow;
}
} catch (e, s) {
Logging.instance
.log("$e\n$s", level: LogLevel.Fatal);
// TODO: handle gracefully
// any network/socket exception here will break new wallet creation
rethrow;
}
}
: null,
style: ref.read(checkBoxStateProvider.state).state
? Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor:
MaterialStateProperty.all<Color>(
CFColors.stackAccent,
),
)
: Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor:
MaterialStateProperty.all<Color>(
CFColors.stackAccent.withOpacity(
0.25,
),
),
),
child: Text(
"View recovery phrase",
style: STextStyles.button,
: null,
style: ref.read(checkBoxStateProvider.state).state
? CFColors.getPrimaryEnabledButtonColor(context)
: CFColors.getPrimaryDisabledButtonColor(context),
child: Text(
"View recovery phrase",
style: isDesktop
? ref.read(checkBoxStateProvider.state).state
? STextStyles.desktopButtonEnabled
: STextStyles.desktopButtonDisabled
: STextStyles.button,
),
),
),
],
);
},
),
],
),
),
],
),
),
);

View file

@ -166,6 +166,13 @@ class STextStyles {
height: 30 / 20,
);
static final TextStyle desktopTextMediumRegular = GoogleFonts.inter(
color: CFColors.textDark,
fontWeight: FontWeight.w400,
fontSize: 20,
height: 30 / 20,
);
static final TextStyle desktopSubtitleH2 = GoogleFonts.inter(
color: CFColors.textDark,
fontWeight: FontWeight.w400,

View file

@ -30,3 +30,35 @@ class DesktopScaffold extends StatelessWidget {
);
}
}
class MasterScaffold extends StatelessWidget {
const MasterScaffold({
Key? key,
required this.isDesktop,
required this.appBar,
required this.body,
this.background = CFColors.background,
}) : super(key: key);
final bool isDesktop;
final Widget appBar;
final Widget body;
final Color background;
@override
Widget build(BuildContext context) {
if (isDesktop) {
return DesktopScaffold(
background: background,
appBar: appBar,
body: body,
);
} else {
return Scaffold(
backgroundColor: background,
appBar: appBar as PreferredSizeWidget?,
body: body,
);
}
}
}

View file

@ -8,16 +8,22 @@ class RoundedContainer extends StatelessWidget {
required this.color,
this.padding = const EdgeInsets.all(12),
this.radiusMultiplier = 1.0,
this.width,
this.height,
}) : super(key: key);
final Widget? child;
final Color color;
final EdgeInsets padding;
final double radiusMultiplier;
final double? width;
final double? height;
@override
Widget build(BuildContext context) {
return Container(
width: width,
height: height,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(

View file

@ -8,11 +8,15 @@ class RoundedWhiteContainer extends StatelessWidget {
this.child,
this.padding = const EdgeInsets.all(12),
this.radiusMultiplier = 1.0,
this.width,
this.height,
}) : super(key: key);
final Widget? child;
final EdgeInsets padding;
final double radiusMultiplier;
final double? width;
final double? height;
@override
Widget build(BuildContext context) {
@ -20,6 +24,8 @@ class RoundedWhiteContainer extends StatelessWidget {
color: CFColors.white,
padding: padding,
radiusMultiplier: radiusMultiplier,
width: width,
height: height,
child: child,
);
}