Skip to content

Commit

Permalink
CW-229 Improved restore options from QR code (#793)
Browse files Browse the repository at this point in the history
* add restoring wallet from qr

* add restore mode

* add alert for exceptions

* add restore from seed

* add check for create wallet state

* convert sweeping page into stateful

* fix parsing url

* restoration flow update

* update restoring from key mode

* update config

* fix restor of BTC and LTC wallets

* fix pin code issue

* wallet Seed/keys uri or code fix

* fix key restore credentials

* update the restore workflow

* update from main

* PR coments fixes

* update

* update

* PR fixes
  • Loading branch information
Serhii-Borodenko authored Apr 21, 2023
1 parent f2b8dd2 commit 1eb8d0c
Show file tree
Hide file tree
Showing 38 changed files with 698 additions and 51 deletions.
13 changes: 12 additions & 1 deletion lib/di.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
Expand Down Expand Up @@ -320,6 +322,13 @@ Future setup(
type: type, language: language);
});

getIt
.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
return WalletRestorationFromQRVM(getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type),
_walletInfoSource, type);
});

getIt.registerFactory<WalletAddressListViewModel>(() =>
WalletAddressListViewModel(
appStore: getIt.get<AppStore>(), yatStore: getIt.get<YatStore>(),
Expand Down Expand Up @@ -743,7 +752,9 @@ Future setup(
getIt.registerFactory(
() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));

getIt.registerFactory(() => RestoreOptionsPage());
getIt.registerFactoryParam<RestoreOptionsPage, bool, void>((bool isNewInstall, _) =>
RestoreOptionsPage(isNewInstall: isNewInstall));


getIt.registerFactory(
() => RestoreFromBackupViewModel(getIt.get<BackupService>()));
Expand Down
2 changes: 1 addition & 1 deletion lib/entities/parse_address_from_domain.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class AddressResolver {
final addressPattern = AddressValidator.getAddressFromStringPattern(type);

if (addressPattern == null) {
throw 'Unexpected token: $type for getAddressFromStringPattern';
throw Exception('Unexpected token: $type for getAddressFromStringPattern');
}

final match = RegExp(addressPattern).firstMatch(raw);
Expand Down
20 changes: 17 additions & 3 deletions lib/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
import 'package:cake_wallet/src/screens/buy/payfura_page.dart';
import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_actions.dart';
Expand Down Expand Up @@ -40,6 +41,8 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
Expand Down Expand Up @@ -158,8 +161,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
param2: false));

case Routes.restoreOptions:
final isNewInstall = settings.arguments as bool;
return CupertinoPageRoute<void>(
builder: (_) => getIt.get<RestoreOptionsPage>());
builder: (_) => getIt.get<RestoreOptionsPage>(param1: isNewInstall));

case Routes.restoreWalletOptions:
final type = WalletType.monero; //settings.arguments as WalletType;
Expand Down Expand Up @@ -189,12 +193,18 @@ Route<dynamic> createRoute(RouteSettings settings) {
}));

case Routes.restoreWalletOptionsFromWelcome:
return CupertinoPageRoute<void>(
final isNewInstall = settings.arguments as bool;
return isNewInstall ? CupertinoPageRoute<void>(
builder: (_) => getIt.get<SetupPinCodePage>(
param1: (PinCodeState<PinCodeWidget> context, dynamic _) =>
Navigator.pushNamed(
context.context, Routes.restoreWalletType)),
fullscreenDialog: true);
fullscreenDialog: true) : CupertinoPageRoute<void>(
builder: (_) => getIt.get<NewWalletTypePage>(
param1: (BuildContext context, WalletType type) =>
Navigator.of(context)
.pushNamed(Routes.restoreWallet, arguments: type),
param2: false));

case Routes.seed:
return MaterialPageRoute<void>(
Expand Down Expand Up @@ -224,6 +234,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => RestoreWalletFromKeysPage(
walletRestorationFromKeysVM: walletRestorationFromKeysVM));

case Routes.sweepingWalletPage:
return CupertinoPageRoute<void>(
builder: (_) => getIt.get<SweepingWalletPage>());

case Routes.dashboard:
return CupertinoPageRoute<void>(
builder: (_) => getIt.get<DashboardPage>());
Expand Down
1 change: 1 addition & 0 deletions lib/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class Routes {
static const displaySettingsPage = '/display_settings_page';
static const otherSettingsPage = '/other_settings_page';
static const advancedPrivacySettings = '/advanced_privacy_settings';
static const sweepingWalletPage = '/sweeping_wallet_page';
static const anonPayInvoicePage = '/anon_pay_invoice_page';
static const anonPayReceivePage = '/anon_pay_receive_page';
static const anonPayDetailsPage = '/anon_pay_details_page';
Expand Down
78 changes: 66 additions & 12 deletions lib/src/screens/restore/restore_options_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/language_list.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
Expand All @@ -7,15 +15,16 @@ import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/generated/i18n.dart';

class RestoreOptionsPage extends BasePage {
RestoreOptionsPage();

static const _aspectRatioImage = 2.086;
RestoreOptionsPage({required this.isNewInstall});

@override
String get title => S.current.restore_restore_wallet;


final bool isNewInstall;
final imageSeedKeys = Image.asset('assets/images/restore_wallet_image.png');
final imageBackup = Image.asset('assets/images/backup.png');
final qrCode = Image.asset('assets/images/qr_code_icon.png');

@override
Widget body(BuildContext context) {
Expand All @@ -28,24 +37,69 @@ class RestoreOptionsPage extends BasePage {
child: Column(
children: <Widget>[
RestoreButton(
onPressed: () =>
Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome),
onPressed: () => Navigator.pushNamed(
context, Routes.restoreWalletOptionsFromWelcome,
arguments: isNewInstall),
image: imageSeedKeys,
title: S.of(context).restore_title_from_seed_keys,
description:
S.of(context).restore_description_from_seed_keys),
description: S.of(context).restore_description_from_seed_keys),
if (isNewInstall)
Padding(
padding: EdgeInsets.only(top: 24),
child: RestoreButton(
onPressed: () => Navigator.pushNamed(context, Routes.restoreFromBackup),
image: imageBackup,
title: S.of(context).restore_title_from_backup,
description: S.of(context).restore_description_from_backup),
),
Padding(
padding: EdgeInsets.only(top: 24),
child: RestoreButton(
onPressed: () =>
Navigator.pushNamed(context, Routes.restoreFromBackup),
image: imageBackup,
title: S.of(context).restore_title_from_backup,
description: S.of(context).restore_description_from_backup),
onPressed: () async {
bool isPinSet = false;
if (isNewInstall) {
await Navigator.pushNamed(context, Routes.setupPin,
arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
setupPinContext.close();
isPinSet = true;
});
}
if (!isNewInstall || isPinSet) {
try {
final restoreWallet =
await WalletRestoreFromQRCode.scanQRCodeForRestoring(context);

final restoreFromQRViewModel = getIt.get<WalletRestorationFromQRVM>(param1: restoreWallet.type);

await restoreFromQRViewModel.create(restoreWallet: restoreWallet);
if (restoreFromQRViewModel.state is FailureState) {
_onWalletCreateFailure(context,
'Create wallet state: ${restoreFromQRViewModel.state.runtimeType.toString()}');
}
} catch (e) {
_onWalletCreateFailure(context, e.toString());
}
}
},
image: qrCode,
title: S.of(context).scan_qr_code,
description: S.of(context).cold_or_recover_wallet),
)
],
),
)),
);
}

void _onWalletCreateFailure(BuildContext context, String error) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.current.error,
alertContent: error,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
}
}
123 changes: 123 additions & 0 deletions lib/src/screens/restore/sweeping_wallet_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter/scheduler.dart';

class SweepingWalletPage extends BasePage {
SweepingWalletPage();

static const aspectRatioImage = 1.25;
final welcomeImageLight = Image.asset('assets/images/welcome_light.png');
final welcomeImageDark = Image.asset('assets/images/welcome.png');



@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
resizeToAvoidBottomInset: false,
body: body(context));
}

@override
Widget body(BuildContext context) {
final welcomeImage = currentTheme.type == ThemeType.dark ? welcomeImageDark : welcomeImageLight;

return SweepingWalletWidget(
aspectRatioImage: aspectRatioImage,
welcomeImage: welcomeImage,
);
}
}

class SweepingWalletWidget extends StatefulWidget {
const SweepingWalletWidget({
required this.aspectRatioImage,
required this.welcomeImage,
});

final double aspectRatioImage;
final Image welcomeImage;

@override
State<SweepingWalletWidget> createState() => _SweepingWalletWidgetState();
}

class _SweepingWalletWidgetState extends State<SweepingWalletWidget> {
@override
void initState() {
SchedulerBinding.instance.addPostFrameCallback((_) async {

});
super.initState();
}

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: Container(
padding: EdgeInsets.only(top: 64, bottom: 24, left: 24, right: 24),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
flex: 2,
child: AspectRatio(
aspectRatio: widget.aspectRatioImage,
child: FittedBox(child: widget.welcomeImage, fit: BoxFit.fill))),
Flexible(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 24),
child: Text(
S.of(context).please_wait,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme!.headline2!.color!,
),
textAlign: TextAlign.center,
),
),
Padding(
padding: EdgeInsets.only(top: 5),
child: Text(
S.of(context).sweeping_wallet,
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
),
textAlign: TextAlign.center,
),
),
Padding(
padding: EdgeInsets.only(top: 5),
child: Text(
S.of(context).sweeping_wallet_alert,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme!.headline2!.color!,
),
textAlign: TextAlign.center,
),
),
],
),
],
))
],
)));
}
}


1 change: 1 addition & 0 deletions lib/src/screens/restore/wallet_restore_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/core/seed_validator.dart';
import 'package:cake_wallet/view_model/restore/restore_mode.dart';

class WalletRestorePage extends BasePage {
WalletRestorePage(this.walletRestoreViewModel)
Expand Down
2 changes: 1 addition & 1 deletion lib/src/screens/wallet_list/wallet_list_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class WalletListBodyState extends State<WalletListBody> {
Navigator.of(context).pushNamed(Routes.restoreWallet,
arguments: widget.walletListViewModel.currentWalletType);
} else {
Navigator.of(context).pushNamed(Routes.restoreWalletType);
Navigator.of(context).pushNamed(Routes.restoreOptions, arguments: false);
}
},
image: restoreWalletImage,
Expand Down
3 changes: 2 additions & 1 deletion lib/src/screens/welcome/welcome_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ class WelcomePage extends BasePage {
padding: EdgeInsets.only(top: 10),
child: PrimaryImageButton(
onPressed: () {
Navigator.pushNamed(context, Routes.restoreOptions);
Navigator.pushNamed(context, Routes.restoreOptions,
arguments: true);
},
image: restoreWalletImage,
text: S.of(context).restore_wallet,
Expand Down
Loading

0 comments on commit 1eb8d0c

Please sign in to comment.