dev
dart 183 lines 7.03 KB
Raw
1 import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/routes.dart';
3 import 'package:cake_wallet/src/screens/base_page.dart';
4 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
5 import 'package:cake_wallet/src/widgets/option_tile.dart';
6 import 'package:cake_wallet/themes/core/material_base_theme.dart';
7 import 'package:cake_wallet/utils/device_info.dart';
8 import 'package:cake_wallet/utils/feature_flag.dart';
9 import 'package:cake_wallet/utils/permission_handler.dart';
10 import 'package:cake_wallet/utils/responsive_layout_util.dart';
11 import 'package:cake_wallet/utils/show_pop_up.dart';
12 import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
13 import 'package:cw_core/wallet_info.dart';
14 import 'package:flutter/material.dart';
15 import 'package:permission_handler/permission_handler.dart';
16
17 class RestoreOptionsPage extends BasePage {
18 RestoreOptionsPage({required this.isNewInstall});
19
20 @override
21 String get title => S.current.restore_restore_wallet;
22 final bool isNewInstall;
23
24 @override
25 Widget body(BuildContext context) => _RestoreOptionsBody(
26 isNewInstall: isNewInstall,
27 themeType: currentTheme.type,
28 );
29 }
30
31 class _RestoreOptionsBody extends StatefulWidget {
32 const _RestoreOptionsBody({required this.isNewInstall, required this.themeType});
33
34 final bool isNewInstall;
35 final ThemeType themeType;
36
37 @override
38 _RestoreOptionsBodyState createState() => _RestoreOptionsBodyState();
39 }
40
41 class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
42 bool isRestoring = false;
43
44 String get imageRestoreHWPath => widget.themeType == ThemeType.dark
45 ? 'assets/images/restore_hw_dark.png'
46 : 'assets/images/restore_hw.png';
47
48 String get imageRestoreCupcakePath => widget.themeType == ThemeType.dark
49 ? 'assets/images/restore_cupcake_dark.png'
50 : 'assets/images/restore_cupcake.png';
51
52 String get imageRestoreQRPath => widget.themeType == ThemeType.dark
53 ? 'assets/images/restore_qr_dark.png'
54 : 'assets/images/restore_qr.png';
55
56 String get imageRestoreHotWalletPath => widget.themeType == ThemeType.dark
57 ? 'assets/images/restore_hot_wallet_dark.png'
58 : 'assets/images/restore_hot_wallet.png';
59
60 String get imageRestoreBackupPath => widget.themeType == ThemeType.dark
61 ? 'assets/images/restore_backup_dark.png'
62 : 'assets/images/restore_backup.png';
63
64 @override
65 Widget build(BuildContext context) {
66 final imageRestoreHW = Image.asset(imageRestoreHWPath, width: 55);
67 final imageRestoreCupcake = Image.asset(imageRestoreCupcakePath, width: 55);
68 final imageRestoreQR = Image.asset(imageRestoreQRPath, width: 55);
69 final imageSeedKeys = Image.asset(imageRestoreHotWalletPath, width: 55);
70 final imageRestoreBackup = Image.asset(imageRestoreBackupPath, width: 55);
71
72 return Center(
73 child: Container(
74 width: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint,
75 height: double.infinity,
76 padding: EdgeInsets.symmetric(vertical: 24, horizontal: 24),
77 child: SingleChildScrollView(
78 child: Column(
79 children: <Widget>[
80 OptionTile(
81 key: ValueKey('restore_options_from_seeds_or_keys_button_key'),
82 onPressed: () => Navigator.pushNamed(context, Routes.restoreWalletFromSeedKeys),
83 image: imageSeedKeys,
84 title: S.of(context).restore_title_from_seed_keys,
85 description: S.of(context).restore_description_from_seed_keys,
86 ),
87 if (FeatureFlag.hasBitcoinViewOnly && DeviceInfo.instance.isMobile)
88 Padding(
89 padding: EdgeInsets.only(top: 12),
90 child: OptionTile(
91 key: ValueKey('restore_options_from_cupcake_button_key'),
92 onPressed: () => _onScanQRCode(context),
93 image: imageRestoreCupcake,
94 title: S.of(context).restore_title_from_cupcake,
95 description: S.of(context).restore_description_from_cupcake,
96 ),
97 ),
98 Padding(
99 padding: EdgeInsets.only(top: 12),
100 child: OptionTile(
101 key: ValueKey('restore_options_from_hardware_wallet_button_key'),
102 onPressed: () =>
103 Navigator.pushNamed(context, Routes.restoreWalletFromHardwareWallet),
104 image: imageRestoreHW,
105 title: S.of(context).restore_title_from_hardware_wallet,
106 description: S.of(context).restore_description_from_hardware_wallet,
107 ),
108 ),
109 if (widget.isNewInstall)
110 Padding(
111 padding: EdgeInsets.only(top: 12),
112 child: OptionTile(
113 key: ValueKey('restore_options_from_backup_button_key'),
114 onPressed: () => Navigator.pushNamed(context, Routes.restoreFromBackup),
115 image: imageRestoreBackup,
116 title: S.of(context).restore_title_from_backup,
117 description: S.of(context).restore_description_from_backup,
118 ),
119 ),
120 if (DeviceInfo.instance.isMobile)
121 Padding(
122 padding: EdgeInsets.only(top: 12),
123 child: OptionTile(
124 key: ValueKey('restore_options_from_qr_button_key'),
125 onPressed: () => _onScanQRCode(context),
126 image: imageRestoreQR,
127 title: S.of(context).scan_qr_code,
128 description: S.of(context).cold_or_recover_wallet,
129 ),
130 ),
131 ],
132 ),
133 ),
134 ),
135 );
136 }
137
138 void _showQRScanError(BuildContext context, String error) {
139 if (mounted) {
140 setState(() => isRestoring = false);
141 }
142
143 WidgetsBinding.instance.addPostFrameCallback((_) {
144 if (mounted) {
145 showPopUp<void>(
146 context: context,
147 builder: (BuildContext context) {
148 return AlertWithOneAction(
149 alertTitle: S.current.error,
150 alertContent: error,
151 buttonText: S.of(context).ok,
152 buttonAction: () => Navigator.of(context).pop());
153 });
154 }
155 });
156 }
157
158 Future<void> _onScanQRCode(BuildContext context) async {
159 final isCameraPermissionGranted =
160 await PermissionHandler.checkPermission(Permission.camera, context);
161
162 if (!isCameraPermissionGranted) return;
163 try {
164 if (isRestoring) return;
165
166 setState(() => isRestoring = true);
167
168 final restoredWallet = await WalletRestoreFromQRCode.scanQRCodeForRestoring(context);
169
170 final params = {
171 'walletType': restoredWallet.type,
172 'restoredWallet': restoredWallet,
173 'hardwareWalletType': HardwareWalletType.cupcake,
174 };
175
176 Navigator.pushNamed(context, Routes.restoreWallet, arguments: params).then((_) {
177 if (mounted) setState(() => isRestoring = false);
178 });
179 } catch (e) {
180 _showQRScanError(context, e.toString());
181 }
182 }
183 }