mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-24 03:26:38 +00:00
Added 'AddBalanceViewModel'
Added form validations
This commit is contained in:
parent
93e7c129f1
commit
2798132313
6 changed files with 165 additions and 46 deletions
|
@ -8,6 +8,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/src/screens/cake_phone/phone_number_service/auto_renew_settings_page.dart';
|
import 'package:cake_wallet/src/screens/cake_phone/phone_number_service/auto_renew_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/cake_phone/phone_number_service/number_settings_page.dart';
|
import 'package:cake_wallet/src/screens/cake_phone/phone_number_service/number_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
|
||||||
|
import 'package:cake_wallet/view_model/cake_phone/add_balance_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cake_wallet/core/backup_service.dart';
|
import 'package:cake_wallet/core/backup_service.dart';
|
||||||
|
@ -662,7 +663,13 @@ Future setup(
|
||||||
));
|
));
|
||||||
|
|
||||||
getIt.registerFactory(() {
|
getIt.registerFactory(() {
|
||||||
return AddBalancePage(/* Add balance view model */);
|
final wallet = getIt.get<AppStore>().wallet;
|
||||||
|
|
||||||
|
return AddBalanceViewModel(getIt.get<BuyAmountViewModel>(), wallet: wallet);
|
||||||
|
});
|
||||||
|
|
||||||
|
getIt.registerFactory(() {
|
||||||
|
return AddBalancePage(addBalanceViewModel: getIt.get<AddBalanceViewModel>());
|
||||||
});
|
});
|
||||||
|
|
||||||
_isSetupFinished = true;
|
_isSetupFinished = true;
|
||||||
|
|
|
@ -4,18 +4,26 @@ import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||||
|
import 'package:cake_wallet/view_model/cake_phone/add_balance_view_model.dart';
|
||||||
|
|
||||||
class AddBalancePage extends BasePage {
|
class AddBalancePage extends BasePage {
|
||||||
AddBalancePage()
|
AddBalancePage({@required this.addBalanceViewModel})
|
||||||
: _amountFocus = FocusNode(),
|
: _amountFocus = FocusNode(),
|
||||||
_amountController = TextEditingController() {
|
_amountController = TextEditingController() {
|
||||||
_amountController.addListener(() {});
|
_amountController.addListener(() {
|
||||||
|
final amount = _amountController.text;
|
||||||
|
|
||||||
|
if (amount != addBalanceViewModel.buyAmountViewModel.amount) {
|
||||||
|
addBalanceViewModel.buyAmountViewModel.amount = amount;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static const _amountPattern = '^([0-9]+([.\,][0-9]{0,2})?|[.\,][0-9]{1,2})\$';
|
static const _amountPattern = '^([0-9]+([.\,][0-9]{0,2})?|[.\,][0-9]{1,2})\$';
|
||||||
|
@ -25,6 +33,7 @@ class AddBalancePage extends BasePage {
|
||||||
"500 additional SMS",
|
"500 additional SMS",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
final AddBalanceViewModel addBalanceViewModel;
|
||||||
final FocusNode _amountFocus;
|
final FocusNode _amountFocus;
|
||||||
final TextEditingController _amountController;
|
final TextEditingController _amountController;
|
||||||
|
|
||||||
|
@ -151,13 +160,19 @@ class AddBalancePage extends BasePage {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
bottomSection: LoadingPrimaryButton(
|
bottomSection: Observer(
|
||||||
onPressed: () {},
|
builder: (_) {
|
||||||
text: S.of(context).buy,
|
return LoadingPrimaryButton(
|
||||||
color: Theme.of(context).accentTextTheme.body2.color,
|
onPressed: () {
|
||||||
textColor: Colors.white,
|
|
||||||
isLoading: false,
|
},
|
||||||
isDisabled: _amountController.text.isEmpty,
|
text: S.of(context).buy,
|
||||||
|
color: Theme.of(context).accentTextTheme.body2.color,
|
||||||
|
textColor: Colors.white,
|
||||||
|
isLoading: false,
|
||||||
|
isDisabled: addBalanceViewModel.buyAmountViewModel.amount.isEmpty,
|
||||||
|
);
|
||||||
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -39,6 +39,9 @@ class CakePhoneAuthBody extends StatefulWidget {
|
||||||
|
|
||||||
class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
||||||
final _emailController = TextEditingController();
|
final _emailController = TextEditingController();
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
AutovalidateMode _autoValidate = AutovalidateMode.disabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -46,11 +49,23 @@ class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
||||||
padding: EdgeInsets.only(top: 16),
|
padding: EdgeInsets.only(top: 16),
|
||||||
child: ScrollableWithBottomSection(
|
child: ScrollableWithBottomSection(
|
||||||
contentPadding: EdgeInsets.fromLTRB(24, 100, 24, 20),
|
contentPadding: EdgeInsets.fromLTRB(24, 100, 24, 20),
|
||||||
content: BaseTextFormField(
|
content: Form(
|
||||||
controller: _emailController,
|
key: _formKey,
|
||||||
keyboardType: TextInputType.emailAddress,
|
autovalidateMode: _autoValidate,
|
||||||
maxLines: 1,
|
child: BaseTextFormField(
|
||||||
hintText: S.of(context).email_address,
|
controller: _emailController,
|
||||||
|
keyboardType: TextInputType.emailAddress,
|
||||||
|
maxLines: 1,
|
||||||
|
hintText: S.of(context).email_address,
|
||||||
|
validator: (String text) {
|
||||||
|
text = text.trim();
|
||||||
|
if (text.isNotEmpty && RegExp(r"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$").hasMatch(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S.of(context).invalid_email;
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
bottomSectionPadding: EdgeInsets.only(bottom: 24, right: 24, left: 24),
|
bottomSectionPadding: EdgeInsets.only(bottom: 24, right: 24, left: 24),
|
||||||
bottomSection: Column(
|
bottomSection: Column(
|
||||||
|
@ -114,11 +129,23 @@ class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
||||||
|
|
||||||
void _registerCakePhone() {
|
void _registerCakePhone() {
|
||||||
// TODO: Add Registration logic
|
// TODO: Add Registration logic
|
||||||
Navigator.pushNamed(context, Routes.cakePhoneVerification);
|
if (_formKey.currentState.validate()) {
|
||||||
|
Navigator.pushNamed(context, Routes.cakePhoneVerification);
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_autoValidate = AutovalidateMode.always;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _loginCakePhone() {
|
void _loginCakePhone() {
|
||||||
// TODO: Add Login logic
|
// TODO: Add Login logic
|
||||||
Navigator.pushNamed(context, Routes.cakePhoneVerification);
|
if (_formKey.currentState.validate()) {
|
||||||
|
Navigator.pushNamed(context, Routes.cakePhoneVerification);
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_autoValidate = AutovalidateMode.always;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,15 +37,30 @@ class CakePhoneVerificationBody extends StatefulWidget {
|
||||||
|
|
||||||
class CakePhoneVerificationBodyState extends State<CakePhoneVerificationBody> {
|
class CakePhoneVerificationBodyState extends State<CakePhoneVerificationBody> {
|
||||||
final _codeController = TextEditingController();
|
final _codeController = TextEditingController();
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
AutovalidateMode _autoValidate = AutovalidateMode.disabled;
|
||||||
|
|
||||||
int resendCount = 0;
|
int resendCount = 0;
|
||||||
int timeLeft = 0;
|
int timeLeft = 0;
|
||||||
|
|
||||||
|
bool disabled = true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_startTimer();
|
_startTimer();
|
||||||
|
|
||||||
|
_codeController.addListener(() {
|
||||||
|
if (_codeController.text.isEmpty) {
|
||||||
|
disabled = true;
|
||||||
|
setState(() {});
|
||||||
|
} else if (disabled) {
|
||||||
|
disabled = false;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -70,29 +85,40 @@ class CakePhoneVerificationBodyState extends State<CakePhoneVerificationBody> {
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 25),
|
padding: const EdgeInsets.symmetric(vertical: 25),
|
||||||
child: BaseTextFormField(
|
child: Form(
|
||||||
controller: _codeController,
|
key: _formKey,
|
||||||
maxLines: 1,
|
autovalidateMode: _autoValidate,
|
||||||
hintText: S.of(context).verification_code,
|
child: BaseTextFormField(
|
||||||
suffixIcon: timeLeft > 0
|
controller: _codeController,
|
||||||
? null
|
maxLines: 1,
|
||||||
: InkWell(
|
hintText: S.of(context).verification_code,
|
||||||
onTap: _startTimer,
|
suffixIcon: timeLeft > 0
|
||||||
child: Container(
|
? null
|
||||||
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
: InkWell(
|
||||||
margin: EdgeInsets.only(bottom: 12),
|
onTap: _startTimer,
|
||||||
decoration: BoxDecoration(
|
child: Container(
|
||||||
color: Theme.of(context).accentTextTheme.caption.color,
|
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||||
borderRadius: BorderRadius.circular(6),
|
margin: EdgeInsets.only(bottom: 12),
|
||||||
),
|
decoration: BoxDecoration(
|
||||||
child: Text(
|
color: Theme.of(context).accentTextTheme.caption.color,
|
||||||
S.of(context).get_code,
|
borderRadius: BorderRadius.circular(6),
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).primaryTextTheme.title.color,
|
|
||||||
fontWeight: FontWeight.w900,
|
|
||||||
),
|
),
|
||||||
)),
|
child: Text(
|
||||||
),
|
S.of(context).get_code,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).primaryTextTheme.title.color,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
validator: (String text) {
|
||||||
|
// TODO: check and apply verification constraints with backend
|
||||||
|
if (text.length < 4) {
|
||||||
|
return S.of(context).invalid_verification_code;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (timeLeft > 0)
|
if (timeLeft > 0)
|
||||||
|
@ -123,16 +149,22 @@ class CakePhoneVerificationBodyState extends State<CakePhoneVerificationBody> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
PrimaryButton(
|
PrimaryButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pushNamedAndRemoveUntil(
|
if (_formKey.currentState.validate()) {
|
||||||
context,
|
Navigator.pushNamedAndRemoveUntil(
|
||||||
Routes.cakePhoneProducts,
|
context,
|
||||||
ModalRoute.withName(Routes.cakePhoneWelcome),
|
Routes.cakePhoneProducts,
|
||||||
);
|
ModalRoute.withName(Routes.cakePhoneWelcome),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_autoValidate = AutovalidateMode.always;
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
text: S.of(context).continue_text,
|
text: S.of(context).continue_text,
|
||||||
color: Theme.of(context).accentTextTheme.body2.color,
|
color: Theme.of(context).accentTextTheme.body2.color,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
isDisabled: _codeController.text.isEmpty,
|
isDisabled: disabled,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
36
lib/view_model/cake_phone/add_balance_view_model.dart
Normal file
36
lib/view_model/cake_phone/add_balance_view_model.dart
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
|
||||||
|
part 'add_balance_view_model.g.dart';
|
||||||
|
|
||||||
|
class AddBalanceViewModel = AddBalanceViewModelBase with _$AddBalanceViewModel;
|
||||||
|
|
||||||
|
abstract class AddBalanceViewModelBase with Store {
|
||||||
|
AddBalanceViewModelBase(this.buyAmountViewModel, {@required this.wallet}) {
|
||||||
|
isRunning = false;
|
||||||
|
isDisabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final BuyAmountViewModel buyAmountViewModel;
|
||||||
|
final WalletBase wallet;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool isRunning;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool isDisabled;
|
||||||
|
|
||||||
|
WalletType get type => wallet.type;
|
||||||
|
|
||||||
|
double get doubleAmount => buyAmountViewModel.doubleAmount;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
FiatCurrency get fiatCurrency => buyAmountViewModel.fiatCurrency;
|
||||||
|
|
||||||
|
CryptoCurrency get cryptoCurrency => walletTypeToCryptoCurrency(type);
|
||||||
|
}
|
|
@ -594,5 +594,7 @@
|
||||||
"transaction_sent_popup_info": "Your transaction was sent. \n\nIf the screen doesn’t proceed after 1 minute, check a block explorer and your email.",
|
"transaction_sent_popup_info": "Your transaction was sent. \n\nIf the screen doesn’t proceed after 1 minute, check a block explorer and your email.",
|
||||||
"cake_phone_products_example": "Example independent uses",
|
"cake_phone_products_example": "Example independent uses",
|
||||||
"add_balance": "Add Balance",
|
"add_balance": "Add Balance",
|
||||||
"forwards": "forwards"
|
"forwards": "forwards",
|
||||||
|
"invalid_email": "Invalid Email",
|
||||||
|
"invalid_verification_code": "Invalid verification code"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue