diff --git a/assets/images/ada.png b/assets/images/ada.png new file mode 100644 index 000000000..6dfc1615c Binary files /dev/null and b/assets/images/ada.png differ diff --git a/assets/images/bch.png b/assets/images/bch.png new file mode 100644 index 000000000..17872731f Binary files /dev/null and b/assets/images/bch.png differ diff --git a/assets/images/bnb.png b/assets/images/bnb.png new file mode 100644 index 000000000..45fe9ad93 Binary files /dev/null and b/assets/images/bnb.png differ diff --git a/assets/images/dash.png b/assets/images/dash.png new file mode 100644 index 000000000..0856db172 Binary files /dev/null and b/assets/images/dash.png differ diff --git a/assets/images/eos.png b/assets/images/eos.png new file mode 100644 index 000000000..2c4ea9ae5 Binary files /dev/null and b/assets/images/eos.png differ diff --git a/assets/images/eth.png b/assets/images/eth.png new file mode 100644 index 000000000..ba2d82a47 Binary files /dev/null and b/assets/images/eth.png differ diff --git a/assets/images/nano.png b/assets/images/nano.png new file mode 100644 index 000000000..b71974bc3 Binary files /dev/null and b/assets/images/nano.png differ diff --git a/assets/images/trx.png b/assets/images/trx.png new file mode 100644 index 000000000..a2bb353f2 Binary files /dev/null and b/assets/images/trx.png differ diff --git a/assets/images/usdt.png b/assets/images/usdt.png new file mode 100644 index 000000000..c7f71194f Binary files /dev/null and b/assets/images/usdt.png differ diff --git a/assets/images/xlm.png b/assets/images/xlm.png new file mode 100644 index 000000000..d4bf2f096 Binary files /dev/null and b/assets/images/xlm.png differ diff --git a/assets/images/xrp.png b/assets/images/xrp.png new file mode 100644 index 000000000..06b50c2a5 Binary files /dev/null and b/assets/images/xrp.png differ diff --git a/lib/src/screens/address_book/address_book_page.dart b/lib/src/screens/address_book/address_book_page.dart index 4a66c3092..bdcb3332d 100644 --- a/lib/src/screens/address_book/address_book_page.dart +++ b/lib/src/screens/address_book/address_book_page.dart @@ -216,43 +216,43 @@ class AddressBookPage extends BasePage { image = Image.asset('assets/images/monero.png', height: 24, width: 24); break; case CryptoCurrency.ada: - image = null; + image = Image.asset('assets/images/ada.png', height: 24, width: 24); break; case CryptoCurrency.bch: - image = null; + image = Image.asset('assets/images/bch.png', height: 24, width: 24); break; case CryptoCurrency.bnb: - image = null; + image = Image.asset('assets/images/bnb.png', height: 24, width: 24); break; case CryptoCurrency.btc: image = Image.asset('assets/images/bitcoin.png', height: 24, width: 24); break; case CryptoCurrency.dash: - image = null; + image = Image.asset('assets/images/dash.png', height: 24, width: 24); break; case CryptoCurrency.eos: - image = null; + image = Image.asset('assets/images/eos.png', height: 24, width: 24); break; case CryptoCurrency.eth: - image = null; + image = Image.asset('assets/images/eth.png', height: 24, width: 24); break; case CryptoCurrency.ltc: image = Image.asset('assets/images/litecoin.png', height: 24, width: 24); break; case CryptoCurrency.nano: - image = null; + image = Image.asset('assets/images/nano.png', height: 24, width: 24); break; case CryptoCurrency.trx: - image = null; + image = Image.asset('assets/images/trx.png', height: 24, width: 24); break; case CryptoCurrency.usdt: - image = null; + image = Image.asset('assets/images/usdt.png', height: 24, width: 24); break; case CryptoCurrency.xlm: - image = null; + image = Image.asset('assets/images/xlm.png', height: 24, width: 24); break; case CryptoCurrency.xrp: - image = null; + image = Image.asset('assets/images/xrp.png', height: 24, width: 24); break; default: image = null; diff --git a/lib/src/screens/address_book/contact_page.dart b/lib/src/screens/address_book/contact_page.dart index 7811c574c..13a9ff8cd 100644 --- a/lib/src/screens/address_book/contact_page.dart +++ b/lib/src/screens/address_book/contact_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:provider/provider.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; @@ -10,6 +11,9 @@ import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/address_text_field.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; class ContactPage extends BasePage { ContactPage({this.contact}); @@ -19,6 +23,9 @@ class ContactPage extends BasePage { @override String get title => S.current.contact; + @override + Color get backgroundColor => PaletteDark.historyPanel; + @override Widget body(BuildContext context) => ContactForm(contact); } @@ -37,22 +44,31 @@ class ContactFormState extends State<ContactForm> { final _contactNameController = TextEditingController(); final _currencyTypeController = TextEditingController(); final _addressController = TextEditingController(); + final currencies = CryptoCurrency.all; + final downArrow = Image.asset( + 'assets/images/arrow_bottom_purple_icon.png', + color: PaletteDark.walletCardText, + height: 8); - CryptoCurrency _selectectCrypto = CryptoCurrency.xmr; + CryptoCurrency _selectectCrypto; @override void initState() { super.initState(); - if (widget.contact == null) { - _currencyTypeController.text = _selectectCrypto.toString(); - } else { + if (widget.contact != null) { _selectectCrypto = widget.contact.type; _contactNameController.text = widget.contact.name; _currencyTypeController.text = _selectectCrypto.toString(); _addressController.text = widget.contact.address; + WidgetsBinding.instance.addPostFrameCallback(afterLayout); } } + void afterLayout(dynamic _) { + final addressBookStore = Provider.of<AddressBookStore>(context); + addressBookStore.setDisabledStatus(false); + } + @override void dispose() { _contactNameController.dispose(); @@ -61,198 +77,164 @@ class ContactFormState extends State<ContactForm> { super.dispose(); } - Future<void> _setCurrencyType(BuildContext context) async { - var currencyType = CryptoCurrency.all[0].toString(); - var selectedCurrency = CryptoCurrency.all[0]; - - await showDialog<void>( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text(S.of(context).please_select), - backgroundColor: Theme.of(context).backgroundColor, - content: Container( - height: 150.0, - child: CupertinoPicker( - backgroundColor: Theme.of(context).backgroundColor, - itemExtent: 45.0, - onSelectedItemChanged: (int index) { - selectedCurrency = CryptoCurrency.all[index]; - currencyType = CryptoCurrency.all[index].toString(); - }, - children: - List.generate(CryptoCurrency.all.length, (int index) { - return Center( - child: Text( - CryptoCurrency.all[index].toString(), - style: TextStyle( - color: Theme.of(context) - .primaryTextTheme - .caption - .color), - ), - ); - })), - ), - actions: <Widget>[ - FlatButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text(S.of(context).cancel)), - FlatButton( - onPressed: () { - _selectectCrypto = selectedCurrency; - _currencyTypeController.text = currencyType; - Navigator.of(context).pop(); - }, - child: Text(S.of(context).ok)) - ], - ); - }); + void onHandleControllers(AddressBookStore addressBookStore) { + if (_contactNameController.text.isNotEmpty && + _addressController.text.isNotEmpty && + _currencyTypeController.text.isNotEmpty) { + addressBookStore.setDisabledStatus(false); + } else { + addressBookStore.setDisabledStatus(true); + } } @override Widget build(BuildContext context) { final addressBookStore = Provider.of<AddressBookStore>(context); - return ScrollableWithBottomSection( - content: Form( - key: _formKey, - child: Column( - mainAxisSize: MainAxisSize.min, - children: <Widget>[ - TextFormField( - style: TextStyle( - fontSize: 14.0, - color: Theme.of(context).primaryTextTheme.headline.color), - decoration: InputDecoration( - hintStyle: TextStyle(color: Theme.of(context).hintColor), - hintText: S.of(context).contact_name, - focusedBorder: UnderlineInputBorder( - borderSide: - BorderSide(color: Palette.cakeGreen, width: 2.0)), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).focusColor, width: 1.0))), - controller: _contactNameController, - validator: (value) { - addressBookStore.validateContactName(value); - return addressBookStore.errorMessage; - }, - ), - SizedBox(height: 14.0), - Container( - child: InkWell( - onTap: () => _setCurrencyType(context), - child: IgnorePointer( - child: TextFormField( - style: TextStyle( - fontSize: 14.0, - color: Theme.of(context) - .primaryTextTheme - .headline - .color), - decoration: InputDecoration( - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Palette.cakeGreen, width: 2.0)), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).focusColor, - width: 1.0))), - controller: _currencyTypeController, + _contactNameController.addListener(() {onHandleControllers(addressBookStore);}); + _currencyTypeController.addListener(() {onHandleControllers(addressBookStore);}); + _addressController.addListener(() {onHandleControllers(addressBookStore);}); + + return Container( + color: PaletteDark.historyPanel, + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.all(24), + content: Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: <Widget>[ + BaseTextFormField( + controller: _contactNameController, + hintText: S.of(context).contact_name, + borderColor: PaletteDark.walletCardSubAddressField, + validator: (value) { + addressBookStore.validateContactName(value); + return addressBookStore.errorMessage; + } + ), + Padding( + padding: EdgeInsets.only(top: 20), + child: Container( + child: InkWell( + onTap: () => _presentPicker(context), + child: IgnorePointer( + child: BaseTextFormField( + controller: _currencyTypeController, + hintText: S.of(context).settings_currency, + borderColor: PaletteDark.walletCardSubAddressField, + suffixIcon: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, + children: <Widget>[ + downArrow + ], + ), + ) + ), ), ), ), + Padding( + padding: EdgeInsets.only(top: 20), + child: AddressTextField( + controller: _addressController, + options: [AddressTextFieldOption.qrCode], + validator: (value) { + addressBookStore.validateAddress(value, + cryptoCurrency: _selectectCrypto); + return addressBookStore.errorMessage; + }, + ), + ) + ], + ), + ), + bottomSectionPadding: EdgeInsets.only( + left: 24, + right: 24, + bottom: 24 + ), + bottomSection: Row( + children: <Widget>[ + Expanded( + child: PrimaryButton( + onPressed: () { + setState(() { + _selectectCrypto = null; + _contactNameController.text = ''; + _currencyTypeController.text = ''; + _addressController.text = ''; + }); + }, + text: S.of(context).reset, + color: Colors.red, + textColor: Colors.white + ), ), - SizedBox(height: 14.0), - AddressTextField( - controller: _addressController, - options: [AddressTextFieldOption.qrCode], - validator: (value) { - addressBookStore.validateAddress(value, - cryptoCurrency: _selectectCrypto); - return addressBookStore.errorMessage; - }, + SizedBox(width: 20), + Expanded( + child: Observer( + builder: (_) => PrimaryButton( + onPressed: () async { + if (!_formKey.currentState.validate()) { + return; + } + + try { + if (widget.contact == null) { + final newContact = Contact( + name: _contactNameController.text, + address: _addressController.text, + type: _selectectCrypto); + + await addressBookStore.add(contact: newContact); + } else { + widget.contact.name = _contactNameController.text; + widget.contact.address = _addressController.text; + widget.contact + .updateCryptoCurrency(currency: _selectectCrypto); + + await addressBookStore.update( + contact: widget.contact); + } + Navigator.pop(context); + } catch (e) { + await showDialog<void>( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.current.contact, + alertContent: e.toString(), + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop() + ); + }); + } + }, + text: S.of(context).save, + color: Colors.green, + textColor: Colors.white, + isDisabled: addressBookStore.isDisabledStatus, + ) + ) ) ], - ), + )), + ); + } + + void _presentPicker(BuildContext context) { + showDialog<void>( + builder: (_) => CurrencyPicker( + selectedAtIndex: currencies.indexOf(_selectectCrypto), + items: currencies, + title: S.of(context).please_select, + onItemSelected: (CryptoCurrency item) { + _selectectCrypto = item; + _currencyTypeController.text = _selectectCrypto.toString(); + } ), - bottomSection: Row( - children: <Widget>[ - Expanded( - child: PrimaryButton( - onPressed: () { - setState(() { - _selectectCrypto = CryptoCurrency.xmr; - _contactNameController.text = ''; - _currencyTypeController.text = - _selectectCrypto.toString(); - _addressController.text = ''; - }); - }, - text: S.of(context).reset, - color: - Theme.of(context).accentTextTheme.button.backgroundColor, - textColor: - Theme.of(context).primaryTextTheme.button.color), - ), - SizedBox(width: 20), - Expanded( - child: PrimaryButton( - onPressed: () async { - if (!_formKey.currentState.validate()) { - return; - } - - try { - if (widget.contact == null) { - final newContact = Contact( - name: _contactNameController.text, - address: _addressController.text, - type: _selectectCrypto); - - await addressBookStore.add(contact: newContact); - } else { - widget.contact.name = _contactNameController.text; - widget.contact.address = _addressController.text; - widget.contact - .updateCryptoCurrency(currency: _selectectCrypto); - - await addressBookStore.update( - contact: widget.contact); - } - Navigator.pop(context); - } catch (e) { - await showDialog<void>( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text( - e.toString(), - textAlign: TextAlign.center, - ), - actions: <Widget>[ - FlatButton( - onPressed: () => - Navigator.of(context).pop(), - child: Text(S.of(context).ok)) - ], - ); - }); - } - }, - text: S.of(context).save, - color: Theme.of(context) - .primaryTextTheme - .button - .backgroundColor, - textColor: Theme.of(context) - .primaryTextTheme - .button - .color)) - ], - )); + context: context); } } diff --git a/lib/src/stores/address_book/address_book_store.dart b/lib/src/stores/address_book/address_book_store.dart index 527809cbd..638d833ba 100644 --- a/lib/src/stores/address_book/address_book_store.dart +++ b/lib/src/stores/address_book/address_book_store.dart @@ -12,11 +12,15 @@ class AddressBookStore = AddressBookStoreBase with _$AddressBookStore; abstract class AddressBookStoreBase with Store { AddressBookStoreBase({@required this.contacts}) { updateContactList(); + isDisabledStatus = true; } @observable List<Contact> contactList; + @observable + bool isDisabledStatus; + @observable bool isValid; @@ -37,6 +41,11 @@ abstract class AddressBookStoreBase with Store { @action Future delete({Contact contact}) async => await contact.delete(); + @action + void setDisabledStatus(bool isDisabled) { + isDisabledStatus = isDisabled; + } + void validateContactName(String value) { const pattern = '''^[^`,'"]{1,32}\$'''; final regExp = RegExp(pattern); diff --git a/lib/src/widgets/base_text_form_field.dart b/lib/src/widgets/base_text_form_field.dart index e05c3a277..6c69d16c2 100644 --- a/lib/src/widgets/base_text_form_field.dart +++ b/lib/src/widgets/base_text_form_field.dart @@ -17,6 +17,7 @@ class BaseTextFormField extends StatelessWidget { this.borderColor = PaletteDark.menuList, this.prefix, this.suffix, + this.suffixIcon, this.enabled = true, this.validator }); @@ -34,6 +35,7 @@ class BaseTextFormField extends StatelessWidget { final Color borderColor; final Widget prefix; final Widget suffix; + final Widget suffixIcon; final bool enabled; final FormFieldValidator<String> validator; @@ -55,6 +57,7 @@ class BaseTextFormField extends StatelessWidget { decoration: InputDecoration( prefix: prefix, suffix: suffix, + suffixIcon: suffixIcon, hintStyle: TextStyle( color: hintColor, fontSize: 16 diff --git a/lib/src/widgets/seed_widget.dart b/lib/src/widgets/seed_widget.dart index 64298da6d..de4f38be7 100644 --- a/lib/src/widgets/seed_widget.dart +++ b/lib/src/widgets/seed_widget.dart @@ -13,7 +13,6 @@ import 'package:cake_wallet/src/domain/monero/mnemonics/russian.dart'; import 'package:cake_wallet/src/domain/monero/mnemonics/spanish.dart'; import 'package:cake_wallet/src/domain/common/mnemotic_item.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/widgets/top_panel.dart'; class SeedWidget extends StatefulWidget { SeedWidget({Key key, this.onMnemoticChange, this.onFinish, this.seedLanguage}) : super(key: key) { @@ -237,52 +236,61 @@ class SeedWidgetState extends State<SeedWidget> { Flexible( fit: FlexFit.tight, flex: 1, - child: TopPanel( - color: PaletteDark.menuList, - widget: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: <Widget>[ - Text( - S.of(context).restore_active_seed, - style: TextStyle( - fontSize: 14, - color: PaletteDark.walletCardText - ), - ), - Padding( - padding: EdgeInsets.only(top: 5), - child: Wrap( - children: items.map((item) { - final isValid = item.isCorrect(); - final isSelected = selectedItem == item; - - return InkWell( - onTap: () => onMnemoticTap(item), - child: Container( - decoration: BoxDecoration( - color: isValid ? Colors.transparent : Palette.red), - margin: EdgeInsets.only(right: 7, bottom: 8), - child: Text( - item.toString(), - style: TextStyle( - color: - isValid ? Colors.white : Palette.lightGrey, - fontSize: 16, - fontWeight: - isSelected ? FontWeight.w900 : FontWeight.w400, - decoration: isSelected - ? TextDecoration.underline - : TextDecoration.none), - )), - ); - }).toList(),) - ) - ], + child: Container( + width: double.infinity, + height: double.infinity, + padding: EdgeInsets.all(24), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), + bottomRight: Radius.circular(24) ), - ) - ) + color: PaletteDark.menuList + ), + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + Text( + S.of(context).restore_active_seed, + style: TextStyle( + fontSize: 14, + color: PaletteDark.walletCardText + ), + ), + Padding( + padding: EdgeInsets.only(top: 5), + child: Wrap( + children: items.map((item) { + final isValid = item.isCorrect(); + final isSelected = selectedItem == item; + + return InkWell( + onTap: () => onMnemoticTap(item), + child: Container( + decoration: BoxDecoration( + color: isValid ? Colors.transparent : Palette.red), + margin: EdgeInsets.only(right: 7, bottom: 8), + child: Text( + item.toString(), + style: TextStyle( + color: + isValid ? Colors.white : Palette.lightGrey, + fontSize: 16, + fontWeight: + isSelected ? FontWeight.w900 : FontWeight.w400, + decoration: isSelected + ? TextDecoration.underline + : TextDecoration.none), + )), + ); + }).toList(),) + ) + ], + ), + ), + ), ), Flexible( fit: FlexFit.tight,