Fixes

M committed Sep 29, 2020 at 20:56 UTC 696b808698a9b12f855f4340e38594f9a752bfab
10 files changed +948 -846
lib/main.dart
+1
@@ -131,6 +131,7 @@ class App extends StatelessWidget {
131 return Observer(builder: (BuildContext context) {
132 return Root(
133 authenticationStore: authenticationStore,
134 + navigatorKey: navigatorKey,
135 child: MaterialApp(
136 navigatorKey: navigatorKey,
137 debugShowCheckedModeBanner: false,
lib/src/screens/base_page.dart
+4 -4
@@ -37,7 +37,7 @@ abstract class BasePage extends StatelessWidget {
37
38 Widget Function(BuildContext, Widget) get rootWrapper => null;
39
40 - bool get _isDarkTheme => getIt.get<SettingsStore>().isDarkTheme;
40 + bool get isDarkTheme => getIt.get<SettingsStore>().isDarkTheme;
41
42 void onOpenEndDrawer() => _scaffoldKey.currentState.openEndDrawer();
43
@@ -51,7 +51,7 @@ abstract class BasePage extends StatelessWidget {
51 final _backButton = Image.asset('assets/images/back_arrow.png',
52 color: titleColor ?? Theme.of(context).primaryTextTheme.title.color);
53 final _closeButton =
54 - _isDarkTheme ? _closeButtonImageDarkTheme : _closeButtonImage;
54 + isDarkTheme ? _closeButtonImageDarkTheme : _closeButtonImage;
55
56 return SizedBox(
57 height: 37,
@@ -88,7 +88,7 @@ abstract class BasePage extends StatelessWidget {
88
89 ObstructingPreferredSizeWidget appBar(BuildContext context) {
90 final appBarColor =
91 - _isDarkTheme ? backgroundDarkColor : backgroundLightColor;
91 + isDarkTheme ? backgroundDarkColor : backgroundLightColor;
92
93 switch (appBarStyle) {
94 case AppBarStyle.regular:
@@ -133,7 +133,7 @@ abstract class BasePage extends StatelessWidget {
133 final root = Scaffold(
134 key: _scaffoldKey,
135 backgroundColor:
136 - _isDarkTheme ? backgroundDarkColor : backgroundLightColor,
136 + isDarkTheme ? backgroundDarkColor : backgroundLightColor,
137 resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
138 extendBodyBehindAppBar: extendBodyBehindAppBar,
139 endDrawer: endDrawer,
lib/src/screens/exchange/exchange_page.dart
+339 -307
@@ -1,7 +1,9 @@
1 import 'dart:ui';
2 +import 'package:cake_wallet/core/execution_state.dart';
3 import 'package:cake_wallet/exchange/exchange_template.dart';
4 import 'package:cake_wallet/src/screens/base_page.dart';
5 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
6 +import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
7 import 'package:cake_wallet/src/widgets/template_tile.dart';
8 import 'package:cake_wallet/src/widgets/trail_button.dart';
9 import 'package:cake_wallet/utils/show_pop_up.dart';
@@ -9,11 +11,13 @@ import 'package:dotted_border/dotted_border.dart';
11 import 'package:flutter/cupertino.dart';
12 import 'package:flutter/material.dart';
13 import 'package:flutter_mobx/flutter_mobx.dart';
14 +import 'package:keyboard_actions/keyboard_actions.dart';
15 import 'package:mobx/mobx.dart';
16 import 'package:cake_wallet/routes.dart';
17 import 'package:cake_wallet/generated/i18n.dart';
18 import 'package:cake_wallet/entities/crypto_currency.dart';
19 import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
20 +
21 // import 'package:cake_wallet/exchange/exchange_trade_state.dart';
22 // import 'package:cake_wallet/exchange/limits_state.dart';
23 import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart';
@@ -32,6 +36,8 @@ class ExchangePage extends BasePage {
36 final depositKey = GlobalKey<ExchangeCardState>();
37 final receiveKey = GlobalKey<ExchangeCardState>();
38 final _formKey = GlobalKey<FormState>();
39 + final _depositAmountFocus = FocusNode();
40 + final _receiveAmountFocus = FocusNode();
41 var _isReactionsSet = false;
42
43 @override
@@ -54,11 +60,8 @@ class ExchangePage extends BasePage {
60 PresentProviderPicker(exchangeViewModel: exchangeViewModel);
61
62 @override
57 - Widget trailing(BuildContext context) =>
58 - TrailButton(
59 - caption: S.of(context).reset,
60 - onPressed: () => exchangeViewModel.reset()
61 - );
63 + Widget trailing(BuildContext context) => TrailButton(
64 + caption: S.of(context).reset, onPressed: () => exchangeViewModel.reset());
65
66 @override
67 Widget body(BuildContext context) {
@@ -74,305 +77,334 @@ class ExchangePage extends BasePage {
77 );
78
79 final depositWalletName =
77 - exchangeViewModel.depositCurrency == CryptoCurrency.xmr
78 - ? exchangeViewModel.wallet.name
79 - : null;
80 + exchangeViewModel.depositCurrency == CryptoCurrency.xmr
81 + ? exchangeViewModel.wallet.name
82 + : null;
83 final receiveWalletName =
81 - exchangeViewModel.receiveCurrency == CryptoCurrency.xmr
82 - ? exchangeViewModel.wallet.name
83 - : null;
84 + exchangeViewModel.receiveCurrency == CryptoCurrency.xmr
85 + ? exchangeViewModel.wallet.name
86 + : null;
87
88 WidgetsBinding.instance
89 .addPostFrameCallback((_) => _setReactions(context, exchangeViewModel));
90
88 - return Container(
89 - color: Theme.of(context).backgroundColor,
90 - child: Form(
91 - key: _formKey,
92 - child: ScrollableWithBottomSection(
93 - contentPadding: EdgeInsets.only(bottom: 24),
94 - content: Column(
95 - children: <Widget>[
96 - Container(
97 - padding: EdgeInsets.only(bottom: 32),
98 - decoration: BoxDecoration(
99 - borderRadius: BorderRadius.only(
100 - bottomLeft: Radius.circular(24),
101 - bottomRight: Radius.circular(24)
91 + return KeyboardActions(
92 + config: KeyboardActionsConfig(
93 + keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
94 + keyboardBarColor: isDarkTheme
95 + ? Color.fromRGBO(48, 51, 60, 1.0)
96 + : Color.fromRGBO(98, 98, 98, 1.0),
97 + nextFocus: false,
98 + actions: [
99 + KeyboardActionsItem(
100 + focusNode: _depositAmountFocus,
101 + toolbarButtons: [(_) => KeyboardDoneButton()]),
102 + KeyboardActionsItem(
103 + focusNode: _receiveAmountFocus,
104 + toolbarButtons: [(_) => KeyboardDoneButton()])
105 + ]),
106 + child: Container(
107 + height: 1,
108 + color: Theme.of(context).backgroundColor,
109 + child: Form(
110 + key: _formKey,
111 + child: ScrollableWithBottomSection(
112 + contentPadding: EdgeInsets.only(bottom: 24),
113 + content: Column(
114 + children: <Widget>[
115 + Container(
116 + padding: EdgeInsets.only(bottom: 32),
117 + decoration: BoxDecoration(
118 + borderRadius: BorderRadius.only(
119 + bottomLeft: Radius.circular(24),
120 + bottomRight: Radius.circular(24)),
121 + gradient: LinearGradient(
122 + colors: [
123 + Theme.of(context).primaryTextTheme.body1.color,
124 + Theme.of(context)
125 + .primaryTextTheme
126 + .body1
127 + .decorationColor,
128 + ],
129 + stops: [
130 + 0.35,
131 + 1.0
132 + ],
133 + begin: Alignment.topLeft,
134 + end: Alignment.bottomRight),
135 ),
103 - gradient: LinearGradient(
104 - colors: [
105 - Theme.of(context).primaryTextTheme.body1.color,
106 - Theme.of(context).primaryTextTheme.body1.decorationColor,
107 - ],
108 - stops: [0.35, 1.0],
109 - begin: Alignment.topLeft,
110 - end: Alignment.bottomRight),
111 - ),
112 - child: Column(
113 - children: <Widget>[
114 - Container(
115 - decoration: BoxDecoration(
116 - borderRadius: BorderRadius.only(
117 - bottomLeft: Radius.circular(24),
118 - bottomRight: Radius.circular(24)
119 - ),
120 - gradient: LinearGradient(
121 - colors: [
122 - Theme.of(context)
136 + child: Column(
137 + children: <Widget>[
138 + Container(
139 + decoration: BoxDecoration(
140 + borderRadius: BorderRadius.only(
141 + bottomLeft: Radius.circular(24),
142 + bottomRight: Radius.circular(24)),
143 + gradient: LinearGradient(
144 + colors: [
145 + Theme.of(context)
146 + .primaryTextTheme
147 + .subtitle
148 + .color,
149 + Theme.of(context)
150 + .primaryTextTheme
151 + .subtitle
152 + .decorationColor,
153 + ],
154 + begin: Alignment.topLeft,
155 + end: Alignment.bottomRight),
156 + ),
157 + padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
158 + child: Observer(
159 + builder: (_) => ExchangeCard(
160 + amountFocusNode: _depositAmountFocus,
161 + key: depositKey,
162 + title: S.of(context).you_will_send,
163 + initialCurrency:
164 + exchangeViewModel.depositCurrency,
165 + initialWalletName: depositWalletName,
166 + initialAddress:
167 + exchangeViewModel.depositCurrency ==
168 + exchangeViewModel.wallet.currency
169 + ? exchangeViewModel.wallet.address
170 + : exchangeViewModel.depositAddress,
171 + initialIsAmountEditable: true,
172 + initialIsAddressEditable:
173 + exchangeViewModel.isDepositAddressEnabled,
174 + isAmountEstimated: false,
175 + currencies: CryptoCurrency.all,
176 + onCurrencySelected: (currency) =>
177 + exchangeViewModel.changeDepositCurrency(
178 + currency: currency),
179 + imageArrow: arrowBottomPurple,
180 + currencyButtonColor: Colors.transparent,
181 + addressButtonsColor:
182 + Theme.of(context).focusColor,
183 + borderColor: Theme.of(context)
184 .primaryTextTheme
124 - .subtitle
185 + .body2
186 .color,
126 - Theme.of(context)
127 - .primaryTextTheme
128 - .subtitle
129 - .decorationColor,
130 - ],
131 - begin: Alignment.topLeft,
132 - end: Alignment.bottomRight),
133 - ),
134 - padding: EdgeInsets.fromLTRB(24, 90, 24, 32),
135 - child: Observer(
136 - builder: (_) => ExchangeCard(
137 - key: depositKey,
138 - title: S.of(context).you_will_send,
139 - initialCurrency:
140 - exchangeViewModel.depositCurrency,
141 - initialWalletName: depositWalletName,
142 - initialAddress: exchangeViewModel
143 - .depositCurrency ==
144 - exchangeViewModel.wallet.currency
145 - ? exchangeViewModel.wallet.address
146 - : exchangeViewModel.depositAddress,
147 - initialIsAmountEditable: true,
148 - initialIsAddressEditable: exchangeViewModel
149 - .isDepositAddressEnabled,
150 - isAmountEstimated: false,
151 - currencies: CryptoCurrency.all,
152 - onCurrencySelected: (currency) =>
153 - exchangeViewModel.changeDepositCurrency(
154 - currency: currency),
155 - imageArrow: arrowBottomPurple,
156 - currencyButtonColor: Colors.transparent,
157 - addressButtonsColor:
158 - Theme.of(context).focusColor,
159 - borderColor: Theme.of(context)
160 - .primaryTextTheme
161 - .body2
162 - .color,
163 - currencyValueValidator: AmountValidator(
164 - type: exchangeViewModel.wallet.type),
165 - addressTextFieldValidator: AddressValidator(
166 - type:
167 - exchangeViewModel.depositCurrency),
187 + currencyValueValidator: AmountValidator(
188 + type: exchangeViewModel.wallet.type),
189 + addressTextFieldValidator: AddressValidator(
190 + type: exchangeViewModel.depositCurrency),
191 + ),
192 + ),
193 ),
169 - ),
194 + Padding(
195 + padding:
196 + EdgeInsets.only(top: 29, left: 24, right: 24),
197 + child: Observer(
198 + builder: (_) => ExchangeCard(
199 + amountFocusNode: _receiveAmountFocus,
200 + key: receiveKey,
201 + title: S.of(context).you_will_get,
202 + initialCurrency:
203 + exchangeViewModel.receiveCurrency,
204 + initialWalletName: receiveWalletName,
205 + initialAddress: exchangeViewModel
206 + .receiveCurrency ==
207 + exchangeViewModel.wallet.currency
208 + ? exchangeViewModel.wallet.address
209 + : exchangeViewModel.receiveAddress,
210 + initialIsAmountEditable: false,
211 + initialIsAddressEditable:
212 + exchangeViewModel
213 + .isReceiveAddressEnabled,
214 + isAmountEstimated: true,
215 + currencies: CryptoCurrency.all,
216 + onCurrencySelected: (currency) =>
217 + exchangeViewModel
218 + .changeReceiveCurrency(
219 + currency: currency),
220 + imageArrow: arrowBottomCakeGreen,
221 + currencyButtonColor: Colors.transparent,
222 + addressButtonsColor:
223 + Theme.of(context).focusColor,
224 + borderColor: Theme.of(context)
225 + .primaryTextTheme
226 + .body2
227 + .decorationColor,
228 + currencyValueValidator: AmountValidator(
229 + type: exchangeViewModel.wallet.type),
230 + addressTextFieldValidator:
231 + AddressValidator(
232 + type: exchangeViewModel
233 + .receiveCurrency),
234 + )),
235 + )
236 + ],
237 + ),
238 + ),
239 + Padding(
240 + padding: EdgeInsets.only(top: 30, left: 24, bottom: 24),
241 + child: Row(
242 + mainAxisAlignment: MainAxisAlignment.start,
243 + children: <Widget>[
244 + Text(
245 + S.of(context).send_templates,
246 + style: TextStyle(
247 + fontSize: 18,
248 + fontWeight: FontWeight.w600,
249 + color: Theme.of(context)
250 + .primaryTextTheme
251 + .display4
252 + .color),
253 + )
254 + ],
255 ),
171 - Padding(
172 - padding: EdgeInsets.only(top: 29, left: 24, right: 24),
173 - child: Observer(
174 - builder: (_) => ExchangeCard(
175 - key: receiveKey,
176 - title: S.of(context).you_will_get,
177 - initialCurrency:
178 - exchangeViewModel.receiveCurrency,
179 - initialWalletName: receiveWalletName,
180 - initialAddress:
181 - exchangeViewModel.receiveCurrency ==
182 - exchangeViewModel.wallet.currency
183 - ? exchangeViewModel.wallet.address
184 - : exchangeViewModel.receiveAddress,
185 - initialIsAmountEditable: false,
186 - initialIsAddressEditable:
187 - exchangeViewModel.isReceiveAddressEnabled,
188 - isAmountEstimated: true,
189 - currencies: CryptoCurrency.all,
190 - onCurrencySelected: (currency) =>
191 - exchangeViewModel.changeReceiveCurrency(
192 - currency: currency),
193 - imageArrow: arrowBottomCakeGreen,
194 - currencyButtonColor: Colors.transparent,
195 - addressButtonsColor:
196 - Theme.of(context).focusColor,
197 - borderColor: Theme.of(context)
256 + ),
257 + Container(
258 + height: 40,
259 + width: double.infinity,
260 + padding: EdgeInsets.only(left: 24),
261 + child: SingleChildScrollView(
262 + scrollDirection: Axis.horizontal,
263 + child: Row(
264 + children: <Widget>[
265 + GestureDetector(
266 + onTap: () => Navigator.of(context)
267 + .pushNamed(Routes.exchangeTemplate),
268 + child: Container(
269 + padding:
270 + EdgeInsets.only(left: 1, right: 10),
271 + child: DottedBorder(
272 + borderType: BorderType.RRect,
273 + dashPattern: [6, 4],
274 + color: Theme.of(context)
275 + .primaryTextTheme
276 + .display2
277 + .decorationColor,
278 + strokeWidth: 2,
279 + radius: Radius.circular(20),
280 + child: Container(
281 + height: 34,
282 + width: 75,
283 + padding: EdgeInsets.only(
284 + left: 10, right: 10),
285 + alignment: Alignment.center,
286 + decoration: BoxDecoration(
287 + borderRadius: BorderRadius.all(
288 + Radius.circular(20)),
289 + color: Colors.transparent,
290 + ),
291 + child: Text(
292 + S.of(context).send_new,
293 + style: TextStyle(
294 + fontSize: 14,
295 + fontWeight: FontWeight.w600,
296 + color: Theme.of(context)
297 + .primaryTextTheme
298 + .display3
299 + .color),
300 + ),
301 + )),
302 + ),
303 + ),
304 + Observer(builder: (_) {
305 + final templates = exchangeViewModel.templates;
306 + final itemCount =
307 + exchangeViewModel.templates.length;
308 +
309 + return ListView.builder(
310 + scrollDirection: Axis.horizontal,
311 + shrinkWrap: true,
312 + physics: NeverScrollableScrollPhysics(),
313 + itemCount: itemCount,
314 + itemBuilder: (context, index) {
315 + final template = templates[index];
316 +
317 + return TemplateTile(
318 + key: UniqueKey(),
319 + amount: template.amount,
320 + from: template.depositCurrency,
321 + to: template.receiveCurrency,
322 + onTap: () {
323 + applyTemplate(
324 + exchangeViewModel, template);
325 + },
326 + onRemove: () {
327 + showPopUp<void>(
328 + context: context,
329 + builder: (dialogContext) {
330 + return AlertWithTwoActions(
331 + alertTitle: S
332 + .of(context)
333 + .template,
334 + alertContent: S
335 + .of(context)
336 + .confirm_delete_template,
337 + leftButtonText:
338 + S.of(context).delete,
339 + rightButtonText:
340 + S.of(context).cancel,
341 + actionLeftButton: () {
342 + Navigator.of(
343 + dialogContext)
344 + .pop();
345 + exchangeViewModel
346 + .exchangeTemplateStore
347 + .remove(
348 + template:
349 + template);
350 + exchangeViewModel
351 + .exchangeTemplateStore
352 + .update();
353 + },
354 + actionRightButton: () =>
355 + Navigator.of(
356 + dialogContext)
357 + .pop());
358 + });
359 + },
360 + );
361 + });
362 + }),
363 + ],
364 + )))
365 + ],
366 + ),
367 + bottomSectionPadding:
368 + EdgeInsets.only(left: 24, right: 24, bottom: 24),
369 + bottomSection: Column(children: <Widget>[
370 + Padding(
371 + padding: EdgeInsets.only(bottom: 15),
372 + child: Observer(builder: (_) {
373 + final description =
374 + exchangeViewModel.provider is XMRTOExchangeProvider
375 + ? S.of(context).amount_is_guaranteed
376 + : S.of(context).amount_is_estimate;
377 + return Center(
378 + child: Text(
379 + description,
380 + style: TextStyle(
381 + color: Theme.of(context)
382 .primaryTextTheme
199 - .body2
383 + .display4
384 .decorationColor,
201 - currencyValueValidator: AmountValidator(
202 - type: exchangeViewModel.wallet.type),
203 - addressTextFieldValidator: AddressValidator(
204 - type: exchangeViewModel.receiveCurrency),
205 - )),
206 - )
207 - ],
208 - ),
209 - ),
210 - Padding(
211 - padding: EdgeInsets.only(top: 30, left: 24, bottom: 24),
212 - child: Row(
213 - mainAxisAlignment: MainAxisAlignment.start,
214 - children: <Widget>[
215 - Text(
216 - S.of(context).send_templates,
217 - style: TextStyle(
218 - fontSize: 18,
219 - fontWeight: FontWeight.w600,
220 - color: Theme.of(context)
221 - .primaryTextTheme
222 - .display4
223 - .color),
224 - )
225 - ],
385 + fontWeight: FontWeight.w500,
386 + fontSize: 12),
387 + ),
388 + );
389 + }),
390 ),
227 - ),
228 - Container(
229 - height: 40,
230 - width: double.infinity,
231 - padding: EdgeInsets.only(left: 24),
232 - child: SingleChildScrollView(
233 - scrollDirection: Axis.horizontal,
234 - child: Row(
235 - children: <Widget>[
236 - GestureDetector(
237 - onTap: () => Navigator.of(context)
238 - .pushNamed(Routes.exchangeTemplate),
239 - child: Container(
240 - padding: EdgeInsets.only(left: 1, right: 10),
241 - child: DottedBorder(
242 - borderType: BorderType.RRect,
243 - dashPattern: [6, 4],
244 - color: Theme.of(context)
245 - .primaryTextTheme
246 - .display2
247 - .decorationColor,
248 - strokeWidth: 2,
249 - radius: Radius.circular(20),
250 - child: Container(
251 - height: 34,
252 - width: 75,
253 - padding: EdgeInsets.only(
254 - left: 10, right: 10),
255 - alignment: Alignment.center,
256 - decoration: BoxDecoration(
257 - borderRadius: BorderRadius.all(
258 - Radius.circular(20)),
259 - color: Colors.transparent,
260 - ),
261 - child: Text(
262 - S.of(context).send_new,
263 - style: TextStyle(
264 - fontSize: 14,
265 - fontWeight: FontWeight.w600,
266 - color: Theme.of(context)
267 - .primaryTextTheme
268 - .display3
269 - .color),
270 - ),
271 - )),
272 - ),
273 - ),
274 - Observer(builder: (_) {
275 - final templates = exchangeViewModel.templates;
276 - final itemCount =
277 - exchangeViewModel.templates.length;
278 -
279 - return ListView.builder(
280 - scrollDirection: Axis.horizontal,
281 - shrinkWrap: true,
282 - physics: NeverScrollableScrollPhysics(),
283 - itemCount: itemCount,
284 - itemBuilder: (context, index) {
285 - final template = templates[index];
286 -
287 - return TemplateTile(
288 - key: UniqueKey(),
289 - amount: template.amount,
290 - from: template.depositCurrency,
291 - to: template.receiveCurrency,
292 - onTap: () {
293 - applyTemplate(
294 - exchangeViewModel, template);
295 - },
296 - onRemove: () {
297 - showPopUp<void>(
298 - context: context,
299 - builder: (dialogContext) {
300 - return AlertWithTwoActions(
301 - alertTitle:
302 - S.of(context).template,
303 - alertContent: S
304 - .of(context)
305 - .confirm_delete_template,
306 - leftButtonText:
307 - S.of(context).delete,
308 - rightButtonText:
309 - S.of(context).cancel,
310 - actionLeftButton: () {
311 - Navigator.of(
312 - dialogContext)
313 - .pop();
314 - exchangeViewModel
315 - .exchangeTemplateStore
316 - .remove(
317 - template:
318 - template);
319 - exchangeViewModel
320 - .exchangeTemplateStore
321 - .update();
322 - },
323 - actionRightButton: () =>
324 - Navigator.of(
325 - dialogContext)
326 - .pop());
327 - });
328 - },
329 - );
330 - });
331 - }),
332 - ],
333 - )))
334 - ],
335 - ),
336 - bottomSectionPadding:
337 - EdgeInsets.only(left: 24, right: 24, bottom: 24),
338 - bottomSection: Column(children: <Widget>[
339 - Padding(
340 - padding: EdgeInsets.only(bottom: 15),
341 - child: Observer(builder: (_) {
342 - final description =
343 - exchangeViewModel.provider is XMRTOExchangeProvider
344 - ? S.of(context).amount_is_guaranteed
345 - : S.of(context).amount_is_estimate;
346 - return Center(
347 - child: Text(
348 - description,
349 - style: TextStyle(
350 - color: Theme.of(context)
351 - .primaryTextTheme
352 - .display4
353 - .decorationColor,
354 - fontWeight: FontWeight.w500,
355 - fontSize: 12),
356 - ),
357 - );
358 - }),
359 - ),
360 - Observer(
361 - builder: (_) => LoadingPrimaryButton(
362 - text: S.of(context).exchange,
363 - onPressed: () {
364 - if (_formKey.currentState.validate()) {
365 - exchangeViewModel.createTrade();
366 - }
367 - },
368 - color: Theme.of(context).accentTextTheme.body2.color,
369 - textColor: Colors.white,
370 - isLoading:
371 - false, // FIXME: FIXME exchangeViewModel.tradeState is TradeIsCreating,
372 - )),
373 - ]),
374 - )),
375 - );
391 + Observer(
392 + builder: (_) => LoadingPrimaryButton(
393 + text: S.of(context).exchange,
394 + onPressed: () {
395 + if (_formKey.currentState.validate()) {
396 + exchangeViewModel.createTrade();
397 + }
398 + },
399 + color:
400 + Theme.of(context).accentTextTheme.body2.color,
401 + textColor: Colors.white,
402 + isLoading: exchangeViewModel.tradeState
403 + is IsExecutingState,
404 + )),
405 + ]),
406 + )),
407 + ));
408 }
409
410 void applyTemplate(
@@ -435,23 +467,23 @@ class ExchangePage extends BasePage {
467 exchangeViewModel.depositCurrency, exchangeViewModel, depositKey);
468
469 reaction(
438 - (_) => exchangeViewModel.wallet.name,
439 - (String _) => _onWalletNameChange(
470 + (_) => exchangeViewModel.wallet.name,
471 + (String _) => _onWalletNameChange(
472 exchangeViewModel, exchangeViewModel.receiveCurrency, receiveKey));
473
474 reaction(
443 - (_) => exchangeViewModel.wallet.name,
444 - (String _) => _onWalletNameChange(
475 + (_) => exchangeViewModel.wallet.name,
476 + (String _) => _onWalletNameChange(
477 exchangeViewModel, exchangeViewModel.depositCurrency, depositKey));
478
479 reaction(
448 - (_) => exchangeViewModel.receiveCurrency,
449 - (CryptoCurrency currency) =>
480 + (_) => exchangeViewModel.receiveCurrency,
481 + (CryptoCurrency currency) =>
482 _onCurrencyChange(currency, exchangeViewModel, receiveKey));
483
484 reaction(
453 - (_) => exchangeViewModel.depositCurrency,
454 - (CryptoCurrency currency) =>
485 + (_) => exchangeViewModel.depositCurrency,
486 + (CryptoCurrency currency) =>
487 _onCurrencyChange(currency, exchangeViewModel, depositKey));
488
489 reaction((_) => exchangeViewModel.depositAmount, (String amount) {
@@ -467,9 +499,9 @@ class ExchangePage extends BasePage {
499 });
500
501 reaction((_) => exchangeViewModel.isDepositAddressEnabled,
470 - (bool isEnabled) {
471 - depositKey.currentState.isAddressEditable(isEditable: isEnabled);
472 - });
502 + (bool isEnabled) {
503 + depositKey.currentState.isAddressEditable(isEditable: isEnabled);
504 + });
505
506 reaction((_) => exchangeViewModel.receiveAmount, (String amount) {
507 if (receiveKey.currentState.amountController.text != amount) {
@@ -484,9 +516,9 @@ class ExchangePage extends BasePage {
516 });
517
518 reaction((_) => exchangeViewModel.isReceiveAddressEnabled,
487 - (bool isEnabled) {
488 - receiveKey.currentState.isAddressEditable(isEditable: isEnabled);
489 - });
519 + (bool isEnabled) {
520 + receiveKey.currentState.isAddressEditable(isEditable: isEnabled);
521 + });
522
523 // FIXME: FIXME
524
@@ -535,7 +567,7 @@ class ExchangePage extends BasePage {
567 // });
568
569 depositAddressController.addListener(
538 - () => exchangeViewModel.depositAddress = depositAddressController.text);
570 + () => exchangeViewModel.depositAddress = depositAddressController.text);
571
572 depositAmountController.addListener(() {
573 if (depositAmountController.text != exchangeViewModel.depositAmount) {
@@ -545,7 +577,7 @@ class ExchangePage extends BasePage {
577 });
578
579 receiveAddressController.addListener(
548 - () => exchangeViewModel.receiveAddress = receiveAddressController.text);
580 + () => exchangeViewModel.receiveAddress = receiveAddressController.text);
581
582 receiveAmountController.addListener(() {
583 if (receiveAmountController.text != exchangeViewModel.receiveAmount) {
lib/src/screens/exchange/widgets/exchange_card.dart
+160 -158
@@ -24,7 +24,8 @@ class ExchangeCard extends StatefulWidget {
24 this.addressButtonsColor = Colors.transparent,
25 this.borderColor = Colors.transparent,
26 this.currencyValueValidator,
27 - this.addressTextFieldValidator})
27 + this.addressTextFieldValidator,
28 + this.amountFocusNode})
29 : super(key: key);
30
31 final List<CryptoCurrency> currencies;
@@ -42,6 +43,7 @@ class ExchangeCard extends StatefulWidget {
43 final Color borderColor;
44 final FormFieldValidator<String> currencyValueValidator;
45 final FormFieldValidator<String> addressTextFieldValidator;
46 + final FocusNode amountFocusNode;
47
48 @override
49 ExchangeCardState createState() => ExchangeCardState();
@@ -114,191 +116,191 @@ class ExchangeCardState extends State<ExchangeCard> {
116 @override
117 Widget build(BuildContext context) {
118 final copyImage = Image.asset('assets/images/copy_content.png',
117 - height: 16, width: 16,
119 + height: 16,
120 + width: 16,
121 color: Theme.of(context).primaryTextTheme.display2.color);
122
123 return Container(
124 width: double.infinity,
125 color: Colors.transparent,
123 - child: Column(
124 - crossAxisAlignment: CrossAxisAlignment.start,
125 - children: <Widget>[
126 + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: <
127 + Widget>[
128 Row(
129 mainAxisAlignment: MainAxisAlignment.start,
130 children: <Widget>[
131 Text(
132 _title,
133 style: TextStyle(
132 - fontSize: 18,
133 - fontWeight: FontWeight.w600,
134 - color: Theme.of(context).textTheme.headline.color
135 - ),
134 + fontSize: 18,
135 + fontWeight: FontWeight.w600,
136 + color: Theme.of(context).textTheme.headline.color),
137 )
138 ],
139 ),
140 Padding(
140 - padding: EdgeInsets.only(top: 20),
141 - child: Stack(
142 - children: <Widget>[
143 - BaseTextFormField(
144 - controller: amountController,
145 - enabled: _isAmountEditable,
146 - textAlign: TextAlign.left,
147 - keyboardType: TextInputType.numberWithOptions(
148 - signed: false, decimal: true),
149 - // inputFormatters: [
150 - // LengthLimitingTextInputFormatter(15),
151 - // BlacklistingTextInputFormatter(
152 - // RegExp('[\\-|\\ |\\,]'))
153 - // ],
154 - hintText: '0.0000',
155 - borderColor: widget.borderColor,
156 - textStyle: TextStyle(
157 - fontSize: 16,
158 - fontWeight: FontWeight.w600,
159 - color: Colors.white
160 - ),
161 - placeholderTextStyle: TextStyle(
162 - fontSize: 16,
163 - fontWeight: FontWeight.w600,
164 - color: Theme.of(context).textTheme.subhead.decorationColor
165 - ),
166 - validator: _isAmountEditable
167 - ? widget.currencyValueValidator
168 - : null
169 - ),
170 - Positioned(
171 - top: 8,
172 - right: 0,
173 - child: Container(
174 - height: 32,
175 - padding: EdgeInsets.only(left: 10),
176 - color: widget.currencyButtonColor,
177 - child: InkWell(
178 - onTap: () => _presentPicker(context),
179 - child: Row(
180 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
181 - mainAxisSize: MainAxisSize.min,
182 - children: <Widget>[
183 - Text(
184 - _selectedCurrency.toString(),
185 - style: TextStyle(
186 - fontWeight: FontWeight.w600,
187 - fontSize: 16,
188 - color: Colors.white)),
189 - Padding(
190 - padding: EdgeInsets.only(left: 5),
191 - child: widget.imageArrow,
192 - )
193 - ]),
141 + padding: EdgeInsets.only(top: 20),
142 + child: Stack(
143 + children: <Widget>[
144 + BaseTextFormField(
145 + focusNode: widget.amountFocusNode,
146 + controller: amountController,
147 + enabled: _isAmountEditable,
148 + textAlign: TextAlign.left,
149 + keyboardType: TextInputType.numberWithOptions(
150 + signed: false, decimal: true),
151 + // inputFormatters: [
152 + // LengthLimitingTextInputFormatter(15),
153 + // BlacklistingTextInputFormatter(
154 + // RegExp('[\\-|\\ |\\,]'))
155 + // ],
156 + hintText: '0.0000',
157 + borderColor: widget.borderColor,
158 + textStyle: TextStyle(
159 + fontSize: 16,
160 + fontWeight: FontWeight.w600,
161 + color: Colors.white),
162 + placeholderTextStyle: TextStyle(
163 + fontSize: 16,
164 + fontWeight: FontWeight.w600,
165 + color: Theme.of(context)
166 + .textTheme
167 + .subhead
168 + .decorationColor),
169 + validator: _isAmountEditable
170 + ? widget.currencyValueValidator
171 + : null),
172 + Positioned(
173 + top: 8,
174 + right: 0,
175 + child: Container(
176 + height: 32,
177 + padding: EdgeInsets.only(left: 10),
178 + color: widget.currencyButtonColor,
179 + child: InkWell(
180 + onTap: () => _presentPicker(context),
181 + child: Row(
182 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
183 + mainAxisSize: MainAxisSize.min,
184 + children: <Widget>[
185 + Text(_selectedCurrency.toString(),
186 + style: TextStyle(
187 + fontWeight: FontWeight.w600,
188 + fontSize: 16,
189 + color: Colors.white)),
190 + Padding(
191 + padding: EdgeInsets.only(left: 5),
192 + child: widget.imageArrow,
193 + )
194 + ]),
195 + ),
196 ),
195 - ),
196 - )
197 - ],
198 - )
199 - ),
197 + )
198 + ],
199 + )),
200 Padding(
201 padding: EdgeInsets.only(top: 5),
202 - child: Row(
203 - mainAxisAlignment: MainAxisAlignment.start,
204 - children: <Widget>[
205 - _min != null
202 + child: Row(mainAxisAlignment: MainAxisAlignment.start, children: <
203 + Widget>[
204 + _min != null
205 ? Text(
207 - S.of(context).min_value(
208 - _min, _selectedCurrency.toString()),
209 - style: TextStyle(
210 - fontSize: 10,
211 - height: 1.2,
212 - color: Theme.of(context).textTheme.subhead.decorationColor),
213 - )
206 + S.of(context).min_value(_min, _selectedCurrency.toString()),
207 + style: TextStyle(
208 + fontSize: 10,
209 + height: 1.2,
210 + color: Theme.of(context)
211 + .textTheme
212 + .subhead
213 + .decorationColor),
214 + )
215 : Offstage(),
215 - _min != null ? SizedBox(width: 10) : Offstage(),
216 - _max != null
216 + _min != null ? SizedBox(width: 10) : Offstage(),
217 + _max != null
218 ? Text(
218 - S.of(context).max_value(
219 - _max, _selectedCurrency.toString()),
219 + S.of(context).max_value(_max, _selectedCurrency.toString()),
220 style: TextStyle(
221 fontSize: 10,
222 height: 1.2,
223 - color: Theme.of(context).textTheme.subhead.decorationColor))
223 + color: Theme.of(context)
224 + .textTheme
225 + .subhead
226 + .decorationColor))
227 : Offstage(),
225 - ]),
228 + ]),
229 ),
230 _isAddressEditable
228 - ? Offstage()
229 - : Padding(
230 - padding: EdgeInsets.only(top: 20),
231 - child: Text(
232 - S.of(context).refund_address,
233 - style: TextStyle(
234 - fontSize: 14,
235 - fontWeight: FontWeight.w500,
236 - color: Theme.of(context).textTheme.subhead.decorationColor
237 - ),
238 - )
239 - ),
231 + ? Offstage()
232 + : Padding(
233 + padding: EdgeInsets.only(top: 20),
234 + child: Text(
235 + S.of(context).refund_address,
236 + style: TextStyle(
237 + fontSize: 14,
238 + fontWeight: FontWeight.w500,
239 + color:
240 + Theme.of(context).textTheme.subhead.decorationColor),
241 + )),
242 _isAddressEditable
241 - ? Padding(
242 - padding: EdgeInsets.only(top: 20),
243 - child: AddressTextField(
244 - controller: addressController,
245 - options: [
246 - AddressTextFieldOption.paste,
247 - AddressTextFieldOption.qrCode,
248 - AddressTextFieldOption.addressBook,
249 - ],
250 - isBorderExist: false,
251 - textStyle: TextStyle(
252 - fontSize: 16,
253 - fontWeight: FontWeight.w600,
254 - color: Colors.white),
255 - hintStyle: TextStyle(
256 - fontSize: 16,
257 - fontWeight: FontWeight.w600,
258 - color: Theme.of(context).textTheme.subhead.decorationColor),
259 - buttonColor: widget.addressButtonsColor,
260 - validator: widget.addressTextFieldValidator,
261 - ),
262 - )
263 - : Padding(
264 - padding: EdgeInsets.only(top: 10),
265 - child: Builder(
266 - builder: (context) => GestureDetector(
267 - onTap: () {
268 - Clipboard.setData(ClipboardData(
269 - text: addressController.text));
270 - Scaffold.of(context).showSnackBar(SnackBar(
271 - content: Text(
272 - S.of(context).copied_to_clipboard,
273 - style: TextStyle(color: Colors.white),
274 - ),
275 - backgroundColor: Colors.green,
276 - duration: Duration(milliseconds: 500),
277 - ));
278 - },
279 - child: Row(
280 - mainAxisSize: MainAxisSize.max,
281 - children: <Widget>[
282 - Expanded(
283 - child: Text(
284 - addressController.text,
285 - maxLines: 1,
286 - overflow: TextOverflow.ellipsis,
287 - style: TextStyle(
288 - fontSize: 16,
289 - fontWeight: FontWeight.w600,
290 - color: Colors.white),
291 - ),
292 - ),
293 - Padding(
294 - padding: EdgeInsets.only(left: 16),
295 - child: copyImage,
296 - )
243 + ? Padding(
244 + padding: EdgeInsets.only(top: 20),
245 + child: AddressTextField(
246 + controller: addressController,
247 + options: [
248 + AddressTextFieldOption.paste,
249 + AddressTextFieldOption.qrCode,
250 + AddressTextFieldOption.addressBook,
251 ],
252 + isBorderExist: false,
253 + textStyle: TextStyle(
254 + fontSize: 16,
255 + fontWeight: FontWeight.w600,
256 + color: Colors.white),
257 + hintStyle: TextStyle(
258 + fontSize: 16,
259 + fontWeight: FontWeight.w600,
260 + color:
261 + Theme.of(context).textTheme.subhead.decorationColor),
262 + buttonColor: widget.addressButtonsColor,
263 + validator: widget.addressTextFieldValidator,
264 ),
265 )
300 - ),
301 - ),
266 + : Padding(
267 + padding: EdgeInsets.only(top: 10),
268 + child: Builder(
269 + builder: (context) => GestureDetector(
270 + onTap: () {
271 + Clipboard.setData(
272 + ClipboardData(text: addressController.text));
273 + Scaffold.of(context).showSnackBar(SnackBar(
274 + content: Text(
275 + S.of(context).copied_to_clipboard,
276 + style: TextStyle(color: Colors.white),
277 + ),
278 + backgroundColor: Colors.green,
279 + duration: Duration(milliseconds: 500),
280 + ));
281 + },
282 + child: Row(
283 + mainAxisSize: MainAxisSize.max,
284 + children: <Widget>[
285 + Expanded(
286 + child: Text(
287 + addressController.text,
288 + maxLines: 1,
289 + overflow: TextOverflow.ellipsis,
290 + style: TextStyle(
291 + fontSize: 16,
292 + fontWeight: FontWeight.w600,
293 + color: Colors.white),
294 + ),
295 + ),
296 + Padding(
297 + padding: EdgeInsets.only(left: 16),
298 + child: copyImage,
299 + )
300 + ],
301 + ),
302 + )),
303 + ),
304 ]),
305 );
306 }
@@ -310,9 +312,9 @@ class ExchangeCardState extends State<ExchangeCard> {
312 items: widget.currencies,
313 title: S.of(context).change_currency,
314 onItemSelected: (CryptoCurrency item) =>
313 - widget.onCurrencySelected != null
314 - ? widget.onCurrencySelected(item)
315 - : null),
315 + widget.onCurrencySelected != null
316 + ? widget.onCurrencySelected(item)
317 + : null),
318 context: context);
319 }
320 }
lib/src/screens/root/root.dart
+8 -2
@@ -6,11 +6,17 @@ import 'package:cake_wallet/store/authentication_store.dart';
6 import 'package:cake_wallet/entities/qr_scanner.dart';
7
8 class Root extends StatefulWidget {
9 - Root({Key key, this.authenticationStore, this.appStore, this.child})
9 + Root(
10 + {Key key,
11 + this.authenticationStore,
12 + this.appStore,
13 + this.child,
14 + this.navigatorKey})
15 : super(key: key);
16
17 final AuthenticationStore authenticationStore;
18 final AppStore appStore;
19 + final GlobalKey<NavigatorState> navigatorKey;
20 final Widget child;
21
22 @override
@@ -53,7 +59,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
59 if (_isInactive && !_postFrameCallback) {
60 _postFrameCallback = true;
61 WidgetsBinding.instance.addPostFrameCallback((_) {
56 - Navigator.of(context).pushNamed(Routes.unlock,
62 + widget.navigatorKey.currentState.pushNamed(Routes.unlock,
63 arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
64 if (!isAuthenticatedSuccessfully) {
65 return;
lib/src/screens/send/send_page.dart
+405 -374
@@ -1,31 +1,26 @@
1 import 'dart:ui';
2 -
3 -// import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
2 +import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
3 +import 'package:flutter/cupertino.dart';
4 +import 'package:flutter/material.dart';
5 +import 'package:flutter/services.dart';
6 +import 'package:flutter_mobx/flutter_mobx.dart';
7 +import 'package:mobx/mobx.dart';
8 +import 'package:keyboard_actions/keyboard_actions.dart';
9 +import 'package:cake_wallet/routes.dart';
10 +import 'package:cake_wallet/view_model/send/send_view_model.dart';
11 import 'package:cake_wallet/core/execution_state.dart';
12 import 'package:cake_wallet/src/screens/base_page.dart';
6 -import 'package:cake_wallet/src/widgets/picker.dart';
13 import 'package:cake_wallet/src/widgets/primary_button.dart';
14 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
15 import 'package:cake_wallet/src/widgets/trail_button.dart';
16 import 'package:cake_wallet/utils/show_pop_up.dart';
17 import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
12 -import 'package:flutter/cupertino.dart';
13 -import 'package:flutter/material.dart';
14 -import 'package:cake_wallet/view_model/send/send_view_model.dart';
15 -import 'package:flutter/services.dart';
16 -import 'package:flutter_mobx/flutter_mobx.dart';
17 -import 'package:mobx/mobx.dart';
18 import 'package:cake_wallet/src/widgets/address_text_field.dart';
19 import 'package:cake_wallet/generated/i18n.dart';
20 import 'package:dotted_border/dotted_border.dart';
21 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
22 -import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
22 import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
24 -
25 -// import 'package:cake_wallet/src/screens/send/widgets/sending_alert.dart';
26 -import 'package:cake_wallet/src/widgets/template_tile.dart';
23 import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
28 -import 'package:cake_wallet/routes.dart';
24
25 class SendPage extends BasePage {
26 SendPage({@required this.sendViewModel});
@@ -34,8 +29,9 @@ class SendPage extends BasePage {
29 final _addressController = TextEditingController();
30 final _cryptoAmountController = TextEditingController();
31 final _fiatAmountController = TextEditingController();
37 - final _focusNode = FocusNode();
32 final _formKey = GlobalKey<FormState>();
33 + final _cryptoAmountFocus = FocusNode();
34 + final _fiatAmountFocus = FocusNode();
35
36 bool _effectsInstalled = false;
37
@@ -62,180 +58,75 @@ class SendPage extends BasePage {
58 Widget body(BuildContext context) {
59 _setEffects(context);
60
65 - return Container(
66 - color: Theme.of(context).backgroundColor,
67 - child: ScrollableWithBottomSection(
68 - contentPadding: EdgeInsets.only(bottom: 24),
69 - content: Column(
70 - children: <Widget>[
71 - Container(
72 - decoration: BoxDecoration(
73 - borderRadius: BorderRadius.only(
74 - bottomLeft: Radius.circular(24),
75 - bottomRight: Radius.circular(24)),
76 - gradient: LinearGradient(colors: [
77 - Theme.of(context).primaryTextTheme.subhead.color,
78 - Theme.of(context).primaryTextTheme.subhead.decorationColor,
79 - ], begin: Alignment.topLeft, end: Alignment.bottomRight),
80 - ),
81 - child: Form(
82 - key: _formKey,
83 - child: Column(children: <Widget>[
84 - Padding(
85 - padding: EdgeInsets.fromLTRB(24, 90, 24, 32),
86 - child: Column(
87 - children: <Widget>[
88 - AddressTextField(
89 - controller: _addressController,
90 - focusNode: _focusNode,
91 - onURIScanned: (uri) {
92 - var address = '';
93 - var amount = '';
94 -
95 - if (uri != null) {
96 - address = uri.path;
97 - amount = uri.queryParameters['tx_amount'];
98 - } else {
99 - address = uri.toString();
100 - }
101 -
102 - _addressController.text = address;
103 - _cryptoAmountController.text = amount;
104 - },
105 - options: [
106 - AddressTextFieldOption.paste,
107 - AddressTextFieldOption.qrCode,
108 - AddressTextFieldOption.addressBook
109 - ],
110 - buttonColor: Theme.of(context)
111 - .primaryTextTheme
112 - .display1
113 - .color,
114 - borderColor: Theme.of(context)
115 - .primaryTextTheme
116 - .headline
117 - .color,
118 - textStyle: TextStyle(
119 - fontSize: 14,
120 - fontWeight: FontWeight.w500,
121 - color: Colors.white),
122 - hintStyle: TextStyle(
123 - fontSize: 14,
124 - fontWeight: FontWeight.w500,
125 - color: Theme.of(context)
61 + return KeyboardActions(
62 + config: KeyboardActionsConfig(
63 + keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
64 + keyboardBarColor: isDarkTheme
65 + ? Color.fromRGBO(48, 51, 60, 1.0)
66 + : Color.fromRGBO(98, 98, 98, 1.0),
67 + nextFocus: false,
68 + actions: [
69 + KeyboardActionsItem(
70 + focusNode: _cryptoAmountFocus,
71 + toolbarButtons: [(_) => KeyboardDoneButton()],
72 + ),
73 + KeyboardActionsItem(
74 + focusNode: _fiatAmountFocus,
75 + toolbarButtons: [(_) => KeyboardDoneButton()],
76 + )
77 + ]),
78 + child: Container(
79 + height: 0,
80 + color: Theme.of(context).backgroundColor,
81 + child: ScrollableWithBottomSection(
82 + contentPadding: EdgeInsets.only(bottom: 24),
83 + content: Column(
84 + children: <Widget>[
85 + Container(
86 + decoration: BoxDecoration(
87 + borderRadius: BorderRadius.only(
88 + bottomLeft: Radius.circular(24),
89 + bottomRight: Radius.circular(24)),
90 + gradient: LinearGradient(colors: [
91 + Theme.of(context).primaryTextTheme.subhead.color,
92 + Theme.of(context)
93 + .primaryTextTheme
94 + .subhead
95 + .decorationColor,
96 + ], begin: Alignment.topLeft, end: Alignment.bottomRight),
97 + ),
98 + child: Form(
99 + key: _formKey,
100 + child: Column(children: <Widget>[
101 + Padding(
102 + padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
103 + child: Column(
104 + children: <Widget>[
105 + AddressTextField(
106 + controller: _addressController,
107 + onURIScanned: (uri) {
108 + var address = '';
109 + var amount = '';
110 +
111 + if (uri != null) {
112 + address = uri.path;
113 + amount = uri.queryParameters['tx_amount'];
114 + } else {
115 + address = uri.toString();
116 + }
117 +
118 + _addressController.text = address;
119 + _cryptoAmountController.text = amount;
120 + },
121 + options: [
122 + AddressTextFieldOption.paste,
123 + AddressTextFieldOption.qrCode,
124 + AddressTextFieldOption.addressBook
125 + ],
126 + buttonColor: Theme.of(context)
127 .primaryTextTheme
127 - .headline
128 - .decorationColor),
129 - validator: sendViewModel.addressValidator,
130 - ),
131 - Padding(
132 - padding: const EdgeInsets.only(top: 20),
133 - child: BaseTextFormField(
134 - controller: _cryptoAmountController,
135 - keyboardType: TextInputType.numberWithOptions(
136 - signed: false, decimal: true),
137 - prefixIcon: Padding(
138 - padding: EdgeInsets.only(top: 9),
139 - child:
140 - Text(sendViewModel.currency.title + ':',
141 - style: TextStyle(
142 - fontSize: 16,
143 - fontWeight: FontWeight.w600,
144 - color: Colors.white,
145 - )),
146 - ),
147 - suffixIcon: Container(
148 - height: 32,
149 - width: 32,
150 - margin: EdgeInsets.only(
151 - left: 14, top: 4, bottom: 10),
152 - decoration: BoxDecoration(
153 - color: Theme.of(context)
154 - .primaryTextTheme
155 - .display1
156 - .color,
157 - borderRadius: BorderRadius.all(
158 - Radius.circular(6))),
159 - child: InkWell(
160 - onTap: () => sendViewModel.setSendAll(),
161 - child: Center(
162 - child: Text(S.of(context).all,
163 - textAlign: TextAlign.center,
164 - style: TextStyle(
165 - fontSize: 12,
166 - fontWeight: FontWeight.bold,
167 - color: Theme.of(context)
168 - .primaryTextTheme
169 - .display1
170 - .decorationColor)),
171 - ),
172 - ),
173 - ),
174 - hintText: '0.0000',
175 - borderColor: Theme.of(context)
176 - .primaryTextTheme
177 - .headline
178 - .color,
179 - textStyle: TextStyle(
180 - fontSize: 14,
181 - fontWeight: FontWeight.w500,
182 - color: Colors.white),
183 - placeholderTextStyle: TextStyle(
184 - color: Theme.of(context)
185 - .primaryTextTheme
186 - .headline
187 - .decorationColor,
188 - fontWeight: FontWeight.w500,
189 - fontSize: 14),
190 - validator: sendViewModel.amountValidator)),
191 - Observer(
192 - builder: (_) => Padding(
193 - padding: EdgeInsets.only(top: 10),
194 - child: Row(
195 - mainAxisSize: MainAxisSize.max,
196 - mainAxisAlignment:
197 - MainAxisAlignment.spaceBetween,
198 - children: <Widget>[
199 - Expanded(
200 - child: Text(
201 - S.of(context).available_balance + ':',
202 - style: TextStyle(
203 - fontSize: 12,
204 - fontWeight: FontWeight.w600,
205 - color: Theme.of(context)
206 - .primaryTextTheme
207 - .headline
208 - .decorationColor),
209 - )),
210 - Text(
211 - sendViewModel.balance,
212 - style: TextStyle(
213 - fontSize: 12,
214 - fontWeight: FontWeight.w600,
215 - color: Theme.of(context)
216 - .primaryTextTheme
217 - .headline
218 - .decorationColor),
219 - )
220 - ],
221 - ),
222 - )),
223 - Padding(
224 - padding: const EdgeInsets.only(top: 20),
225 - child: BaseTextFormField(
226 - controller: _fiatAmountController,
227 - keyboardType: TextInputType.numberWithOptions(
228 - signed: false, decimal: true),
229 - prefixIcon: Padding(
230 - padding: EdgeInsets.only(top: 9),
231 - child: Text(sendViewModel.fiat.title + ':',
232 - style: TextStyle(
233 - fontSize: 16,
234 - fontWeight: FontWeight.w600,
235 - color: Colors.white,
236 - )),
237 - ),
238 - hintText: '0.00',
128 + .display1
129 + .color,
130 borderColor: Theme.of(context)
131 .primaryTextTheme
132 .headline
@@ -244,202 +135,342 @@ class SendPage extends BasePage {
135 fontSize: 14,
136 fontWeight: FontWeight.w500,
137 color: Colors.white),
247 - placeholderTextStyle: TextStyle(
138 + hintStyle: TextStyle(
139 + fontSize: 14,
140 + fontWeight: FontWeight.w500,
141 color: Theme.of(context)
142 .primaryTextTheme
143 .headline
251 - .decorationColor,
252 - fontWeight: FontWeight.w500,
253 - fontSize: 14),
254 - )),
255 - Observer(
256 - builder: (_) => GestureDetector(
257 - onTap: () =>
258 - _setTransactionPriority(context),
259 - child: Container(
260 - padding: EdgeInsets.only(top: 24),
261 - child: Row(
262 - mainAxisAlignment:
263 - MainAxisAlignment.spaceBetween,
264 - children: <Widget>[
265 - Text(S.of(context).send_estimated_fee,
144 + .decorationColor),
145 + validator: sendViewModel.addressValidator,
146 + ),
147 + Padding(
148 + padding: const EdgeInsets.only(top: 20),
149 + child: BaseTextFormField(
150 + focusNode: _cryptoAmountFocus,
151 + controller: _cryptoAmountController,
152 + keyboardType:
153 + TextInputType.numberWithOptions(
154 + signed: false, decimal: true),
155 + prefixIcon: Padding(
156 + padding: EdgeInsets.only(top: 9),
157 + child: Text(
158 + sendViewModel.currency.title + ':',
159 + style: TextStyle(
160 + fontSize: 16,
161 + fontWeight: FontWeight.w600,
162 + color: Colors.white,
163 + )),
164 + ),
165 + suffixIcon: Container(
166 + height: 32,
167 + width: 32,
168 + margin: EdgeInsets.only(
169 + left: 14, top: 4, bottom: 10),
170 + decoration: BoxDecoration(
171 + color: Theme.of(context)
172 + .primaryTextTheme
173 + .display1
174 + .color,
175 + borderRadius: BorderRadius.all(
176 + Radius.circular(6))),
177 + child: InkWell(
178 + onTap: () =>
179 + sendViewModel.setSendAll(),
180 + child: Center(
181 + child: Text(S.of(context).all,
182 + textAlign: TextAlign.center,
183 + style: TextStyle(
184 + fontSize: 12,
185 + fontWeight: FontWeight.bold,
186 + color: Theme.of(context)
187 + .primaryTextTheme
188 + .display1
189 + .decorationColor)),
190 + ),
191 + ),
192 + ),
193 + hintText: '0.0000',
194 + borderColor: Theme.of(context)
195 + .primaryTextTheme
196 + .headline
197 + .color,
198 + textStyle: TextStyle(
199 + fontSize: 14,
200 + fontWeight: FontWeight.w500,
201 + color: Colors.white),
202 + placeholderTextStyle: TextStyle(
203 + color: Theme.of(context)
204 + .primaryTextTheme
205 + .headline
206 + .decorationColor,
207 + fontWeight: FontWeight.w500,
208 + fontSize: 14),
209 + validator:
210 + sendViewModel.amountValidator)),
211 + Observer(
212 + builder: (_) => Padding(
213 + padding: EdgeInsets.only(top: 10),
214 + child: Row(
215 + mainAxisSize: MainAxisSize.max,
216 + mainAxisAlignment:
217 + MainAxisAlignment.spaceBetween,
218 + children: <Widget>[
219 + Expanded(
220 + child: Text(
221 + S.of(context).available_balance +
222 + ':',
223 + style: TextStyle(
224 + fontSize: 12,
225 + fontWeight: FontWeight.w600,
226 + color: Theme.of(context)
227 + .primaryTextTheme
228 + .headline
229 + .decorationColor),
230 + )),
231 + Text(
232 + sendViewModel.balance,
233 style: TextStyle(
234 fontSize: 12,
268 - fontWeight: FontWeight.w500,
269 - //color: Theme.of(context).primaryTextTheme.display2.color,
270 - color: Colors.white)),
271 - Container(
272 - child: Row(
273 - children: <Widget>[
274 - Text(
275 - sendViewModel.estimatedFee
276 - .toString() +
277 - ' ' +
235 + fontWeight: FontWeight.w600,
236 + color: Theme.of(context)
237 + .primaryTextTheme
238 + .headline
239 + .decorationColor),
240 + )
241 + ],
242 + ),
243 + )),
244 + Padding(
245 + padding: const EdgeInsets.only(top: 20),
246 + child: BaseTextFormField(
247 + focusNode: _fiatAmountFocus,
248 + controller: _fiatAmountController,
249 + keyboardType:
250 + TextInputType.numberWithOptions(
251 + signed: false, decimal: true),
252 + prefixIcon: Padding(
253 + padding: EdgeInsets.only(top: 9),
254 + child:
255 + Text(sendViewModel.fiat.title + ':',
256 + style: TextStyle(
257 + fontSize: 16,
258 + fontWeight: FontWeight.w600,
259 + color: Colors.white,
260 + )),
261 + ),
262 + hintText: '0.00',
263 + borderColor: Theme.of(context)
264 + .primaryTextTheme
265 + .headline
266 + .color,
267 + textStyle: TextStyle(
268 + fontSize: 14,
269 + fontWeight: FontWeight.w500,
270 + color: Colors.white),
271 + placeholderTextStyle: TextStyle(
272 + color: Theme.of(context)
273 + .primaryTextTheme
274 + .headline
275 + .decorationColor,
276 + fontWeight: FontWeight.w500,
277 + fontSize: 14),
278 + )),
279 + Observer(
280 + builder: (_) => GestureDetector(
281 + onTap: () =>
282 + _setTransactionPriority(context),
283 + child: Container(
284 + padding: EdgeInsets.only(top: 24),
285 + child: Row(
286 + mainAxisAlignment:
287 + MainAxisAlignment.spaceBetween,
288 + children: <Widget>[
289 + Text(
290 + S
291 + .of(context)
292 + .send_estimated_fee,
293 + style: TextStyle(
294 + fontSize: 12,
295 + fontWeight:
296 + FontWeight.w500,
297 + //color: Theme.of(context).primaryTextTheme.display2.color,
298 + color: Colors.white)),
299 + Container(
300 + child: Row(
301 + children: <Widget>[
302 + Text(
303 sendViewModel
279 - .currency.title,
280 - style: TextStyle(
281 - fontSize: 12,
282 - fontWeight:
283 - FontWeight.w600,
284 - //color: Theme.of(context).primaryTextTheme.display2.color,
285 - color: Colors.white)),
286 - Padding(
287 - padding:
288 - EdgeInsets.only(left: 5),
289 - child: Icon(
290 - Icons.arrow_forward_ios,
291 - size: 12,
292 - color: Colors.white,
293 - ),
294 - )
295 - ],
296 - ),
297 - )
298 - ],
299 - ),
304 + .estimatedFee
305 + .toString() +
306 + ' ' +
307 + sendViewModel
308 + .currency.title,
309 + style: TextStyle(
310 + fontSize: 12,
311 + fontWeight:
312 + FontWeight.w600,
313 + //color: Theme.of(context).primaryTextTheme.display2.color,
314 + color:
315 + Colors.white)),
316 + Padding(
317 + padding: EdgeInsets.only(
318 + left: 5),
319 + child: Icon(
320 + Icons.arrow_forward_ios,
321 + size: 12,
322 + color: Colors.white,
323 + ),
324 + )
325 + ],
326 + ),
327 + )
328 + ],
329 + ),
330 + ),
331 + ))
332 + ],
333 + ),
334 + )
335 + ]),
336 + ),
337 + ),
338 + Padding(
339 + padding: EdgeInsets.only(top: 30, left: 24, bottom: 24),
340 + child: Row(
341 + mainAxisAlignment: MainAxisAlignment.start,
342 + children: <Widget>[
343 + Text(
344 + S.of(context).send_templates,
345 + style: TextStyle(
346 + fontSize: 18,
347 + fontWeight: FontWeight.w600,
348 + color: Theme.of(context)
349 + .primaryTextTheme
350 + .display4
351 + .color),
352 + )
353 + ],
354 + ),
355 + ),
356 + Container(
357 + height: 40,
358 + width: double.infinity,
359 + padding: EdgeInsets.only(left: 24),
360 + child: SingleChildScrollView(
361 + scrollDirection: Axis.horizontal,
362 + child: Row(
363 + children: <Widget>[
364 + GestureDetector(
365 + onTap: () => Navigator.of(context)
366 + .pushNamed(Routes.sendTemplate),
367 + child: Container(
368 + padding: EdgeInsets.only(left: 1, right: 10),
369 + child: DottedBorder(
370 + borderType: BorderType.RRect,
371 + dashPattern: [6, 4],
372 + color: Theme.of(context)
373 + .primaryTextTheme
374 + .display2
375 + .decorationColor,
376 + strokeWidth: 2,
377 + radius: Radius.circular(20),
378 + child: Container(
379 + height: 34,
380 + width: 75,
381 + padding:
382 + EdgeInsets.only(left: 10, right: 10),
383 + alignment: Alignment.center,
384 + decoration: BoxDecoration(
385 + borderRadius:
386 + BorderRadius.all(Radius.circular(20)),
387 + color: Colors.transparent,
388 + ),
389 + child: Text(
390 + S.of(context).send_new,
391 + style: TextStyle(
392 + fontSize: 14,
393 + fontWeight: FontWeight.w600,
394 + color: Theme.of(context)
395 + .primaryTextTheme
396 + .display3
397 + .color),
398 ),
301 - ))
399 + )),
400 + ),
401 + ),
402 + // Observer(
403 + // builder: (_) {
404 + // final templates = sendViewModel.templates;
405 + // final itemCount = templates.length;
406 +
407 + // return ListView.builder(
408 + // scrollDirection: Axis.horizontal,
409 + // shrinkWrap: true,
410 + // physics: NeverScrollableScrollPhysics(),
411 + // itemCount: itemCount,
412 + // itemBuilder: (context, index) {
413 + // final template = templates[index];
414 +
415 + // return TemplateTile(
416 + // key: UniqueKey(),
417 + // to: template.name,
418 + // amount: template.amount,
419 + // from: template.cryptoCurrency,
420 + // onTap: () {
421 + // _addressController.text = template.address;
422 + // _cryptoAmountController.text = template.amount;
423 + // getOpenaliasRecord(context);
424 + // },
425 + // onRemove: () {
426 + // showPopUp<void>(
427 + // context: context,
428 + // builder: (dialogContext) {
429 + // return AlertWithTwoActions(
430 + // alertTitle: S.of(context).template,
431 + // alertContent: S.of(context).confirm_delete_template,
432 + // leftButtonText: S.of(context).delete,
433 + // rightButtonText: S.of(context).cancel,
434 + // actionLeftButton: () {
435 + // Navigator.of(dialogContext).pop();
436 + // sendViewModel.sendTemplateStore.remove(template: template);
437 + // sendViewModel.sendTemplateStore.update();
438 + // },
439 + // actionRightButton: () => Navigator.of(dialogContext).pop()
440 + // );
441 + // }
442 + // );
443 + // },
444 + // );
445 + // }
446 + // );
447 + // }
448 + // )
449 ],
450 ),
304 - )
305 - ]),
306 - ),
307 - ),
308 - Padding(
309 - padding: EdgeInsets.only(top: 30, left: 24, bottom: 24),
310 - child: Row(
311 - mainAxisAlignment: MainAxisAlignment.start,
312 - children: <Widget>[
313 - Text(
314 - S.of(context).send_templates,
315 - style: TextStyle(
316 - fontSize: 18,
317 - fontWeight: FontWeight.w600,
318 - color: Theme.of(context)
319 - .primaryTextTheme
320 - .display4
321 - .color),
322 - )
323 - ],
324 - ),
451 + ),
452 + )
453 + ],
454 ),
326 - Container(
327 - height: 40,
328 - width: double.infinity,
329 - padding: EdgeInsets.only(left: 24),
330 - child: SingleChildScrollView(
331 - scrollDirection: Axis.horizontal,
332 - child: Row(
333 - children: <Widget>[
334 - GestureDetector(
335 - onTap: () => Navigator.of(context)
336 - .pushNamed(Routes.sendTemplate),
337 - child: Container(
338 - padding: EdgeInsets.only(left: 1, right: 10),
339 - child: DottedBorder(
340 - borderType: BorderType.RRect,
341 - dashPattern: [6, 4],
342 - color: Theme.of(context)
343 - .primaryTextTheme
344 - .display2
345 - .decorationColor,
346 - strokeWidth: 2,
347 - radius: Radius.circular(20),
348 - child: Container(
349 - height: 34,
350 - width: 75,
351 - padding: EdgeInsets.only(left: 10, right: 10),
352 - alignment: Alignment.center,
353 - decoration: BoxDecoration(
354 - borderRadius:
355 - BorderRadius.all(Radius.circular(20)),
356 - color: Colors.transparent,
357 - ),
358 - child: Text(
359 - S.of(context).send_new,
360 - style: TextStyle(
361 - fontSize: 14,
362 - fontWeight: FontWeight.w600,
363 - color: Theme.of(context)
364 - .primaryTextTheme
365 - .display3
366 - .color),
367 - ),
368 - )),
369 - ),
370 - ),
371 - // Observer(
372 - // builder: (_) {
373 - // final templates = sendViewModel.templates;
374 - // final itemCount = templates.length;
375 -
376 - // return ListView.builder(
377 - // scrollDirection: Axis.horizontal,
378 - // shrinkWrap: true,
379 - // physics: NeverScrollableScrollPhysics(),
380 - // itemCount: itemCount,
381 - // itemBuilder: (context, index) {
382 - // final template = templates[index];
383 -
384 - // return TemplateTile(
385 - // key: UniqueKey(),
386 - // to: template.name,
387 - // amount: template.amount,
388 - // from: template.cryptoCurrency,
389 - // onTap: () {
390 - // _addressController.text = template.address;
391 - // _cryptoAmountController.text = template.amount;
392 - // getOpenaliasRecord(context);
393 - // },
394 - // onRemove: () {
395 - // showPopUp<void>(
396 - // context: context,
397 - // builder: (dialogContext) {
398 - // return AlertWithTwoActions(
399 - // alertTitle: S.of(context).template,
400 - // alertContent: S.of(context).confirm_delete_template,
401 - // leftButtonText: S.of(context).delete,
402 - // rightButtonText: S.of(context).cancel,
403 - // actionLeftButton: () {
404 - // Navigator.of(dialogContext).pop();
405 - // sendViewModel.sendTemplateStore.remove(template: template);
406 - // sendViewModel.sendTemplateStore.update();
407 - // },
408 - // actionRightButton: () => Navigator.of(dialogContext).pop()
409 - // );
410 - // }
411 - // );
412 - // },
413 - // );
414 - // }
415 - // );
416 - // }
417 - // )
418 - ],
419 - ),
420 - ),
421 - )
422 - ],
423 - ),
424 - bottomSectionPadding:
425 - EdgeInsets.only(left: 24, right: 24, bottom: 24),
426 - bottomSection: Observer(builder: (_) {
427 - return LoadingPrimaryButton(
428 - onPressed: () async {
429 - if (_formKey.currentState.validate()) {
430 - await sendViewModel.createTransaction();
431 - }
432 - },
433 - text: S.of(context).send,
434 - color: Theme.of(context).accentTextTheme.body2.color,
435 - textColor: Colors.white,
436 - isLoading: sendViewModel.state is IsExecutingState ||
437 - sendViewModel.state is TransactionCommitting,
438 - isDisabled:
439 - false // FIXME !(syncStore.status is SyncedSyncStatus),
440 - );
441 - })),
442 - );
455 + bottomSectionPadding:
456 + EdgeInsets.only(left: 24, right: 24, bottom: 24),
457 + bottomSection: Observer(builder: (_) {
458 + return LoadingPrimaryButton(
459 + onPressed: () async {
460 + if (_formKey.currentState.validate()) {
461 + await sendViewModel.createTransaction();
462 + }
463 + },
464 + text: S.of(context).send,
465 + color: Theme.of(context).accentTextTheme.body2.color,
466 + textColor: Colors.white,
467 + isLoading: sendViewModel.state is IsExecutingState ||
468 + sendViewModel.state is TransactionCommitting,
469 + isDisabled:
470 + false // FIXME !(syncStore.status is SyncedSyncStatus),
471 + );
472 + })),
473 + ));
474 }
475
476 void _setEffects(BuildContext context) {
lib/src/widgets/base_text_form_field.dart
+4 -1
@@ -22,7 +22,8 @@ class BaseTextFormField extends StatelessWidget {
22 this.validator,
23 this.textStyle,
24 this.placeholderTextStyle,
25 - this.maxLength});
25 + this.maxLength,
26 + this.focusNode});
27
28 final TextEditingController controller;
29 final TextInputType keyboardType;
@@ -44,10 +45,12 @@ class BaseTextFormField extends StatelessWidget {
45 final TextStyle placeholderTextStyle;
46 final TextStyle textStyle;
47 final int maxLength;
48 + final FocusNode focusNode;
49
50 @override
51 Widget build(BuildContext context) {
52 return TextFormField(
53 + focusNode: focusNode,
54 controller: controller,
55 keyboardType: keyboardType,
56 textInputAction: textInputAction,
lib/src/widgets/keyboard_done_button.dart new
+19
@@ -0,0 +1,19 @@
1 +import 'package:flutter/cupertino.dart';
2 +import 'package:flutter/material.dart';
3 +
4 +class KeyboardDoneButton extends StatelessWidget {
5 + @override
6 + Widget build(BuildContext context) {
7 + // FIXME: Add translation
8 + return CupertinoButton(
9 + padding: EdgeInsets.only(right: 24.0, top: 8.0, bottom: 8.0),
10 + onPressed: () {
11 + FocusScope.of(context).requestFocus(FocusNode());
12 + },
13 + child: Text(
14 + 'Done',
15 + style: TextStyle(color: Colors.blueAccent,fontWeight: FontWeight.bold)
16 + ),
17 + );
18 + }
19 +}
\ No newline at end of file
pubspec.lock
+7
@@ -534,6 +534,13 @@ packages:
534 url: "https://pub.dartlang.org"
535 source: hosted
536 version: "3.1.0"
537 + keyboard_actions:
538 + dependency: "direct main"
539 + description:
540 + name: keyboard_actions
541 + url: "https://pub.dartlang.org"
542 + source: hosted
543 + version: "3.3.0+1"
544 local_auth:
545 dependency: "direct main"
546 description:
pubspec.yaml
+1
@@ -64,6 +64,7 @@ dependencies:
64 bitcoin_flutter: ^2.0.0
65 get_it: ^4.0.2
66 connectivity: ^0.4.9+2
67 + keyboard_actions: ^3.3.0
68
69 dev_dependencies:
70 flutter_test: