dev
dart 233 lines 9.02 KB
Raw
1 import "dart:async";
2
3 import "package:cake_wallet/core/wallet_name_validator.dart";
4 import "package:cake_wallet/generated/i18n.dart";
5 import "package:cake_wallet/src/screens/base_page.dart";
6 import "package:cake_wallet/src/screens/connect_device/monero_hardware_wallet_passphrase_input.dart";
7 import "package:cake_wallet/src/widgets/alert_with_one_action.dart";
8 import "package:cake_wallet/src/widgets/base_text_form_field.dart";
9 import "package:cake_wallet/src/widgets/blockchain_height_widget.dart";
10 import "package:cake_wallet/src/widgets/primary_button.dart";
11 import "package:cake_wallet/src/widgets/scrollable_with_bottom_section.dart";
12 import "package:cake_wallet/utils/responsive_layout_util.dart";
13 import "package:cake_wallet/utils/show_pop_up.dart";
14 import "package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart";
15 import "package:cw_core/generate_name.dart";
16 import "package:cw_core/wallet_type.dart";
17 import "package:flutter/material.dart";
18 import "package:flutter_mobx/flutter_mobx.dart";
19 import "package:mobx/mobx.dart";
20
21 class MoneroHardwareWalletOptionsPage extends BasePage {
22 MoneroHardwareWalletOptionsPage(this._walletHardwareRestoreVM);
23
24 final WalletHardwareRestoreViewModel _walletHardwareRestoreVM;
25
26 @override
27 String get title => S.current.restore_title_from_hardware_wallet;
28
29 @override
30 Widget body(BuildContext context) => _MoneroHardwareWalletOptionsForm(_walletHardwareRestoreVM);
31 }
32
33 class _MoneroHardwareWalletOptionsForm extends StatefulWidget {
34 const _MoneroHardwareWalletOptionsForm(this._walletHardwareRestoreVM);
35
36 final WalletHardwareRestoreViewModel _walletHardwareRestoreVM;
37
38 @override
39 _MoneroHardwareWalletOptionsFormState createState() =>
40 _MoneroHardwareWalletOptionsFormState(_walletHardwareRestoreVM);
41 }
42
43 class _MoneroHardwareWalletOptionsFormState extends State<_MoneroHardwareWalletOptionsForm> {
44 _MoneroHardwareWalletOptionsFormState(this._walletHardwareRestoreVM)
45 : _formKey = GlobalKey<FormState>(),
46 _blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
47 _blockHeightFocusNode = FocusNode(),
48 _walletNameController = TextEditingController(),
49 _passphraseController = TextEditingController();
50
51 final GlobalKey<FormState> _formKey;
52 final GlobalKey<BlockchainHeightState> _blockchainHeightKey;
53 final FocusNode _blockHeightFocusNode;
54 final WalletHardwareRestoreViewModel _walletHardwareRestoreVM;
55 final TextEditingController _walletNameController;
56 final TextEditingController _passphraseController;
57
58 @override
59 void initState() {
60 super.initState();
61 _setEffects(context);
62 }
63
64 @override
65 Widget build(BuildContext context) => Padding(
66 padding: const EdgeInsets.only(top: 24),
67 child: ScrollableWithBottomSection(
68 contentPadding: const EdgeInsets.only(left: 24, right: 24, bottom: 24),
69 content: Center(
70 child: ConstrainedBox(
71 constraints: const BoxConstraints(
72 maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint,
73 ),
74 child: Column(
75 crossAxisAlignment: CrossAxisAlignment.center,
76 children: [
77 Padding(
78 padding: EdgeInsets.zero,
79 child: Form(
80 key: _formKey,
81 child: Stack(
82 alignment: Alignment.centerRight,
83 children: [
84 BaseTextFormField(
85 onChanged: (value) => _walletHardwareRestoreVM.name = value,
86 controller: _walletNameController,
87 textStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
88 fontSize: 20,
89 fontWeight: FontWeight.w600,
90 ),
91 placeholderTextStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
92 fontSize: 18,
93 fontWeight: FontWeight.w500,
94 color: Theme.of(context).colorScheme.onSurfaceVariant,
95 ),
96 hintText: S.of(context).wallet_name,
97 suffixIcon: Semantics(
98 label: S.of(context).generate_name,
99 child: IconButton(
100 onPressed: _onGenerateName,
101 icon: Container(
102 padding: const EdgeInsets.all(8),
103 decoration: BoxDecoration(
104 borderRadius: BorderRadius.circular(6),
105 color: Theme.of(context).colorScheme.surfaceContainerHighest,
106 ),
107 width: 34,
108 height: 34,
109 child: Image.asset(
110 "assets/images/refresh_icon.png",
111 color: Theme.of(context).colorScheme.primary,
112 ),
113 ),
114 ),
115 ),
116 validator: WalletNameValidator(),
117 ),
118 ],
119 ),
120 ),
121 ),
122 Padding(
123 padding: const EdgeInsets.only(top: 20),
124 child: BlockchainHeightWidget(
125 focusNode: _blockHeightFocusNode,
126 key: _blockchainHeightKey,
127 hasDatePicker: true,
128 walletType: WalletType.monero,
129 ),
130 ),
131 ],
132 ),
133 ),
134 ),
135 bottomSectionPadding: const EdgeInsets.all(24),
136 bottomSection: Observer(
137 builder: (_) => Column(
138 children: [
139 if (_walletHardwareRestoreVM.passphraseAvailable) ...[
140 TextButton(
141 onPressed: () {
142 showModalBottomSheet(
143 context: context,
144 isScrollControlled: true,
145 backgroundColor: Colors.transparent,
146 builder: (context) => MoneroHardwareWalletPassphraseInputModal(
147 controller: _passphraseController,
148 ),
149 );
150 },
151 child: Text(S.of(context).add_a_passphrase),
152 ),
153 ],
154 LoadingPrimaryButton(
155 onPressed: _confirmForm,
156 text: S.of(context).seed_language_next,
157 color: Theme.of(context).colorScheme.primary,
158 textColor: Theme.of(context).colorScheme.onPrimary,
159 isDisabled: _walletHardwareRestoreVM.name.isEmpty,
160 ),
161 ],
162 ),
163 ),
164 ),
165 );
166
167 Future<void> _onGenerateName() async {
168 final rName = await generateName();
169 FocusManager.instance.primaryFocus?.unfocus();
170
171 setState(() {
172 _walletNameController.text = rName;
173 _walletHardwareRestoreVM.name = rName;
174 _walletNameController.selection =
175 TextSelection.fromPosition(TextPosition(offset: _walletNameController.text.length));
176 });
177 }
178
179 Future<void> _confirmForm() async {
180 unawaited(
181 showPopUp<void>(
182 context: context,
183 builder: (context) => AlertWithOneAction(
184 alertTitle: S.of(context).proceed_on_device,
185 alertContent: S.of(context).proceed_on_device_description,
186 buttonText: S.of(context).cancel,
187 alertBarrierDismissible: false,
188 buttonAction: () => Navigator.of(context).pop(),
189 ),
190 ),
191 );
192
193 final options = <String, dynamic>{"height": _blockchainHeightKey.currentState?.height ?? -1};
194
195 if (_walletHardwareRestoreVM.passphraseAvailable && _passphraseController.text.isNotEmpty) {
196 options["passphrase"] = _passphraseController.text;
197 }
198 await _walletHardwareRestoreVM.create(options: options);
199 }
200
201 bool _effectsInstalled = false;
202
203 void _setEffects(BuildContext context) {
204 if (_effectsInstalled) {
205 return;
206 }
207
208 reaction((_) => _walletHardwareRestoreVM.error, (error) {
209 if (error != null) {
210 if (error == S.current.ledger_connection_error) {
211 Navigator.of(context).pop();
212 }
213
214 WidgetsBinding.instance.addPostFrameCallback((_) {
215 showPopUp<void>(
216 context: context,
217 builder: (context) => AlertWithOneAction(
218 alertTitle: S.of(context).error,
219 alertContent: error,
220 buttonText: S.of(context).ok,
221 buttonAction: () {
222 _walletHardwareRestoreVM.error = null;
223 Navigator.of(context).pop();
224 },
225 ),
226 );
227 });
228 }
229 });
230
231 _effectsInstalled = true;
232 }
233 }