dev
dart 242 lines 8.44 KB
Raw
1 import 'package:another_flushbar/flushbar.dart';
2 import 'package:cake_wallet/core/execution_state.dart';
3 import 'package:cake_wallet/generated/i18n.dart';
4 import 'package:cake_wallet/src/screens/auth/auth_page.dart';
5 import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
6 import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
7 import 'package:cake_wallet/src/widgets/primary_button.dart';
8 import 'package:cake_wallet/utils/responsive_layout_util.dart';
9 import 'package:cake_wallet/utils/show_bar.dart';
10 import 'package:flutter/cupertino.dart';
11 import 'package:flutter/material.dart';
12 import 'package:cake_wallet/view_model/wallet_unlock_view_model.dart';
13 import 'package:flutter_mobx/flutter_mobx.dart';
14 import 'package:mobx/mobx.dart';
15
16 class WalletUnlockPage extends StatefulWidget {
17 WalletUnlockPage(
18 this.walletUnlockViewModel, this.onAuthenticationFinished, this.authPasswordHandler,
19 {required this.closable});
20
21 final WalletUnlockViewModel walletUnlockViewModel;
22 final OnAuthenticationFinished onAuthenticationFinished;
23 final AuthPasswordHandler? authPasswordHandler;
24 final bool closable;
25
26 @override
27 State<StatefulWidget> createState() => WalletUnlockPageState();
28 }
29
30 class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> {
31 WalletUnlockPageState() : _passwordController = TextEditingController();
32
33 final TextEditingController _passwordController;
34 final _key = GlobalKey<ScaffoldState>();
35 final _backArrowImageDarkTheme = Image.asset('assets/images/close_button.png');
36 ReactionDisposer? _reaction;
37 Flushbar<void>? _authBar;
38 Flushbar<void>? _progressBar;
39 void Function()? _passwordControllerListener;
40
41 @override
42 void initState() {
43 _reaction ??= reaction((_) => widget.walletUnlockViewModel.state, (ExecutionState state) {
44 if (state is ExecutedSuccessfullyState) {
45 WidgetsBinding.instance.addPostFrameCallback((_) {
46 widget.onAuthenticationFinished(true, this);
47 });
48 setState(() {});
49 }
50
51 if (state is IsExecutingState) {
52 WidgetsBinding.instance.addPostFrameCallback((_) {
53 // null duration to make it indefinite until its disposed
54 _authBar = createBar<void>(S.of(context).authentication, context, duration: null)
55 ..show(context);
56 });
57 }
58
59 if (state is FailureState) {
60 WidgetsBinding.instance.addPostFrameCallback((_) async {
61 dismissFlushBar(_authBar);
62 showBar<void>(context, S.of(context).failed_authentication(state.error));
63
64 widget.onAuthenticationFinished(false, this);
65 });
66 }
67 });
68
69 _passwordControllerListener =
70 () => widget.walletUnlockViewModel.setPassword(_passwordController.text);
71
72 if (_passwordControllerListener != null) {
73 _passwordController.addListener(_passwordControllerListener!);
74 }
75
76 super.initState();
77 }
78
79 @override
80 void dispose() {
81 _reaction?.reaction.dispose();
82
83 if (_passwordControllerListener != null) {
84 _passwordController.removeListener(_passwordControllerListener!);
85 }
86
87 _passwordController.dispose();
88
89 super.dispose();
90 }
91
92 @override
93 void changeProcessText(String text) {
94 dismissFlushBar(_authBar);
95 _progressBar = createBar<void>(text, context, duration: null)..show(_key.currentContext!);
96 }
97
98 @override
99 void hideProgressText() {
100 dismissFlushBar(_progressBar);
101 _progressBar = null;
102 }
103
104 void dismissFlushBar(Flushbar<dynamic>? bar) {
105 WidgetsBinding.instance.addPostFrameCallback((_) async {
106 await bar?.dismiss();
107 });
108 }
109
110 Future<void> _unlockWallet() async {
111 if (widget.walletUnlockViewModel.state is IsExecutingState) {
112 return;
113 }
114
115 FocusScope.of(context).unfocus();
116
117 if (widget.authPasswordHandler != null) {
118 try {
119 await widget.authPasswordHandler!(widget.walletUnlockViewModel.password);
120 widget.walletUnlockViewModel.success();
121 } catch (e) {
122 widget.walletUnlockViewModel.failure(e);
123 }
124 return;
125 }
126
127 await widget.walletUnlockViewModel.unlock();
128 }
129
130 @override
131 Future<void> close({String? route, arguments}) async {
132 if (_key.currentContext == null) {
133 throw Exception('Key context is null. Should be not happened');
134 }
135
136 /// not the best scenario, but WidgetsBinding is not behaving correctly on Android
137 await Future<void>.delayed(Duration(milliseconds: 50));
138 await _authBar?.dismiss();
139 await Future<void>.delayed(Duration(milliseconds: 50));
140 await _progressBar?.dismiss();
141 await Future<void>.delayed(Duration(milliseconds: 50));
142 if (route != null) {
143 Navigator.of(_key.currentContext!).pushReplacementNamed(route, arguments: arguments);
144 } else {
145 Navigator.of(_key.currentContext!).pop();
146 }
147 }
148
149 @override
150 Widget build(BuildContext context) {
151 return Scaffold(
152 key: _key,
153 appBar: CupertinoNavigationBar(
154 leading: widget.closable
155 ? Container(
156 padding: EdgeInsets.only(top: 10),
157 child: SizedBox(
158 height: 37,
159 width: 37,
160 child: InkWell(
161 onTap: () {
162 if (context.mounted && Navigator.of(context).canPop()) {
163 Navigator.of(context).pop();
164 }
165 },
166 child: _backArrowImageDarkTheme,
167 ),
168 ))
169 : Container(),
170 backgroundColor: Theme.of(context).colorScheme.surface,
171 border: null),
172 resizeToAvoidBottomInset: false,
173 body: Center(
174 child: ConstrainedBox(
175 constraints: BoxConstraints(
176 maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint,
177 ),
178 child: Column(
179 mainAxisAlignment: MainAxisAlignment.spaceBetween,
180 crossAxisAlignment: CrossAxisAlignment.center,
181 children: [
182 Expanded(
183 child: Column(
184 mainAxisAlignment: MainAxisAlignment.center,
185 crossAxisAlignment: CrossAxisAlignment.center,
186 children: [
187 Text(
188 widget.walletUnlockViewModel.walletName,
189 textAlign: TextAlign.center,
190 style: Theme.of(context).textTheme.bodyMedium!.copyWith(
191 fontSize: 24,
192 fontWeight: FontWeight.w500,
193 color: Theme.of(context).colorScheme.onSurface,
194 ),
195 ),
196 SizedBox(height: 24),
197 Form(
198 child: BaseTextFormField(
199 key: ValueKey('enter_wallet_password'),
200 onChanged: (value) => null,
201 onSubmit: (_) async {
202 await _unlockWallet();
203 },
204 controller: _passwordController,
205 textAlign: TextAlign.center,
206 obscureText: true,
207 textStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
208 fontSize: 20.0,
209 fontWeight: FontWeight.w600,
210 ),
211 placeholderTextStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
212 fontSize: 18.0,
213 fontWeight: FontWeight.w500,
214 color: Theme.of(context).colorScheme.onSurfaceVariant,
215 ),
216 hintText: S.of(context).enter_wallet_password,
217 ),
218 ),
219 ],
220 ),
221 ),
222 Padding(
223 key: ValueKey('unlock'),
224 padding: EdgeInsets.only(bottom: 24),
225 child: Observer(
226 builder: (_) => LoadingPrimaryButton(
227 onPressed: _unlockWallet,
228 text: S.of(context).unlock,
229 color: Theme.of(context).colorScheme.primary,
230 textColor: Theme.of(context).colorScheme.onPrimary,
231 isLoading: widget.walletUnlockViewModel.state is IsExecutingState,
232 isDisabled: widget.walletUnlockViewModel.state is IsExecutingState,
233 ),
234 ),
235 ),
236 ],
237 ),
238 ),
239 ),
240 );
241 }
242 }