diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 92dae7995..608c882b0 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -85,6 +85,7 @@ class S implements WidgetsLocalizations { String get error_text_xmr => "XMR value can't exceed available balance.\nThe number of fraction digits must be less or equal to 12"; String get estimated => "Estimated"; String get exchange => "Exchange"; + String get exchange_new_template => "New template"; String get exchange_result_write_down_ID => "*Please copy or write down your ID shown above."; String get exchange_result_write_down_trade_id => "Please copy or write down the trade ID to continue."; String get expired => "Expired"; @@ -869,6 +870,8 @@ class $de extends S { @override String get add_new_word => "Neues Wort hinzufügen"; @override + String get exchange_new_template => "Neue Vorlage"; + @override String get digit_pin => "-stelliger PIN"; @override String get first_wallet_text => "tolle Brieftasche zum Monero"; @@ -1479,6 +1482,8 @@ class $hi extends S { @override String get add_new_word => "नया शब्द जोड़ें"; @override + String get exchange_new_template => "नया टेम्पलेट"; + @override String get digit_pin => "-अंक पिन"; @override String get first_wallet_text => "बहुत बढ़िया बटुआ के लिये Monero"; @@ -2089,6 +2094,8 @@ class $ru extends S { @override String get add_new_word => "Добавить новое слово"; @override + String get exchange_new_template => "Новый шаблон"; + @override String get digit_pin => "-значный PIN"; @override String get first_wallet_text => "В самом удобном кошельке для Monero"; @@ -2699,6 +2706,8 @@ class $ko extends S { @override String get add_new_word => "새로운 단어 추가"; @override + String get exchange_new_template => "새 템플릿"; + @override String get digit_pin => "숫자 PIN"; @override String get first_wallet_text => "멋진 지갑 에 대한 Monero"; @@ -3309,6 +3318,8 @@ class $pt extends S { @override String get add_new_word => "Adicionar nova palavra"; @override + String get exchange_new_template => "Novo modelo"; + @override String get digit_pin => "dígitos"; @override String get first_wallet_text => "Uma fantástica carteira para Monero"; @@ -3919,6 +3930,8 @@ class $uk extends S { @override String get add_new_word => "Добавити нове слово"; @override + String get exchange_new_template => "Новий шаблон"; + @override String get digit_pin => "-значний PIN"; @override String get first_wallet_text => "В самому зручному гаманці для Monero"; @@ -4529,6 +4542,8 @@ class $ja extends S { @override String get add_new_word => "新しい単語を追加"; @override + String get exchange_new_template => "新しいテンプレート"; + @override String get digit_pin => "桁ピン"; @override String get first_wallet_text => "素晴らしい財布 ために Monero"; @@ -5143,6 +5158,8 @@ class $pl extends S { @override String get add_new_word => "Dodaj nowe słowo"; @override + String get exchange_new_template => "Nowy szablon"; + @override String get digit_pin => "-znak PIN"; @override String get first_wallet_text => "Niesamowity portfel dla Monero"; @@ -5753,6 +5770,8 @@ class $es extends S { @override String get add_new_word => "Agregar palabra nueva"; @override + String get exchange_new_template => "Nueva plantilla"; + @override String get digit_pin => "-dígito PIN"; @override String get first_wallet_text => "Impresionante billetera para Monero"; @@ -6363,6 +6382,8 @@ class $nl extends S { @override String get add_new_word => "Nieuw woord toevoegen"; @override + String get exchange_new_template => "Nieuwe sjabloon"; + @override String get digit_pin => "-cijferige PIN"; @override String get first_wallet_text => "Geweldige portemonnee fvoor Monero"; @@ -6973,6 +6994,8 @@ class $zh extends S { @override String get add_new_word => "添加新词"; @override + String get exchange_new_template => "新範本"; + @override String get digit_pin => "数字别针"; @override String get first_wallet_text => "很棒的钱包 对于 Monero"; diff --git a/lib/src/screens/exchange/exchange_page.dart b/lib/src/screens/exchange/exchange_page.dart index 327629ba0..b6e2bfca5 100644 --- a/lib/src/screens/exchange/exchange_page.dart +++ b/lib/src/screens/exchange/exchange_page.dart @@ -1,31 +1,15 @@ import 'dart:ui'; -import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart'; -import 'package:cake_wallet/src/domain/exchange/exchange_template.dart'; -import 'package:cake_wallet/src/widgets/template_tile.dart'; -import 'package:dotted_border/dotted_border.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:mobx/mobx.dart'; import 'package:provider/provider.dart'; import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; -import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart'; -import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart'; -import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart'; -import 'package:cake_wallet/src/stores/exchange/limits_state.dart'; import 'package:cake_wallet/src/stores/wallet/wallet_store.dart'; import 'package:cake_wallet/src/stores/exchange/exchange_store.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.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/top_panel.dart'; -import 'package:cake_wallet/src/screens/exchange/widgets/provider_picker.dart'; import 'package:cake_wallet/src/stores/exchange_template/exchange_template_store.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; +import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker.dart'; +import 'package:cake_wallet/src/screens/exchange/widgets/base_exchange_widget.dart'; class ExchangePage extends BasePage { @override @@ -34,46 +18,11 @@ class ExchangePage extends BasePage { @override Color get backgroundColor => PaletteDark.walletCardSubAddressField; - final Image arrowBottom = - Image.asset('assets/images/arrow_bottom_purple_icon.png', color: Colors.white, height: 6); - @override Widget middle(BuildContext context) { final exchangeStore = Provider.of(context); - return FlatButton( - onPressed: () => _presentProviderPicker(context), - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - child: Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text(S.of(context).exchange, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w400, - color: Colors.white)), - Observer( - builder: (_) => Text('${exchangeStore.provider.title}', - style: TextStyle( - fontSize: 10.0, - fontWeight: FontWeight.w400, - color:PaletteDark.walletCardText))) - ], - ), - SizedBox(width: 5), - Padding( - padding: EdgeInsets.only(top: 8), - child: arrowBottom, - ) - ], - ) - ); + return PresentProviderPicker(exchangeStore: exchangeStore); } @override @@ -99,37 +48,6 @@ class ExchangePage extends BasePage { @override Widget body(BuildContext context) => ExchangeForm(); - - void _presentProviderPicker(BuildContext context) { - final exchangeStore = Provider.of(context); - final items = exchangeStore.providersForCurrentPair(); - final selectedItem = items.indexOf(exchangeStore.provider); - final images = List(); - - for (ExchangeProvider provider in items) { - switch (provider.description) { - case ExchangeProviderDescription.xmrto: - images.add(Image.asset('assets/images/xmr_btc.png')); - break; - case ExchangeProviderDescription.changeNow: - images.add(Image.asset('assets/images/change_now.png')); - break; - case ExchangeProviderDescription.morphToken: - images.add(Image.asset('assets/images/morph_icon.png')); - break; - } - } - - showDialog( - builder: (_) => ProviderPicker( - items: items, - images: images, - selectedAtIndex: selectedItem, - title: S.of(context).change_exchange_provider, - onItemSelected: (ExchangeProvider provider) => - exchangeStore.changeProvider(provider: provider)), - context: context); - } } class ExchangeForm extends StatefulWidget { @@ -138,21 +56,6 @@ class ExchangeForm extends StatefulWidget { } class ExchangeFormState extends State { - final depositKey = GlobalKey(); - final receiveKey = GlobalKey(); - final _formKey = GlobalKey(); - var _isReactionsSet = false; - - final Image arrowBottomPurple = Image.asset( - 'assets/images/arrow_bottom_purple_icon.png', - color: Colors.white, - height: 8, - ); - final Image arrowBottomCakeGreen = Image.asset( - 'assets/images/arrow_bottom_cake_green.png', - color: Colors.white, - height: 8, - ); @override Widget build(BuildContext context) { @@ -160,422 +63,11 @@ class ExchangeFormState extends State { final walletStore = Provider.of(context); final exchangeTemplateStore = Provider.of(context); - final depositWalletName = - exchangeStore.depositCurrency == CryptoCurrency.xmr - ? walletStore.name - : null; - final receiveWalletName = - exchangeStore.receiveCurrency == CryptoCurrency.xmr - ? walletStore.name - : null; - - WidgetsBinding.instance.addPostFrameCallback( - (_) => _setReactions(context, exchangeStore, walletStore)); - - return Container( - color: PaletteDark.historyPanel, - child: Form( - key: _formKey, - child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.only(bottom: 24), - content: Column( - children: [ - TopPanel( - color: PaletteDark.menuList, - edgeInsets: EdgeInsets.only(bottom: 24), - widget: Column( - children: [ - TopPanel( - color: PaletteDark.walletCardSubAddressField, - widget: Observer( - builder: (_) => ExchangeCard( - key: depositKey, - title: S.of(context).you_will_send, - initialCurrency: exchangeStore.depositCurrency, - initialWalletName: depositWalletName, - initialAddress: - exchangeStore.depositCurrency == walletStore.type - ? walletStore.address - : exchangeStore.depositAddress, - initialIsAmountEditable: true, - initialIsAddressEditable: true, - isAmountEstimated: false, - currencies: CryptoCurrency.all, - onCurrencySelected: (currency) => - exchangeStore.changeDepositCurrency(currency: currency), - imageArrow: arrowBottomPurple, - currencyButtonColor: PaletteDark.walletCardSubAddressField, - addressButtonsColor: PaletteDark.menuList, - currencyValueValidator: (value) { - exchangeStore.validateCryptoCurrency(value); - return exchangeStore.errorMessage; - }, - addressTextFieldValidator: (value) { - exchangeStore.validateAddress(value, - cryptoCurrency: exchangeStore.depositCurrency); - return exchangeStore.errorMessage; - }, - ), - ) - ), - Padding( - padding: EdgeInsets.only(top: 32, left: 24, right: 24), - child: Observer( - builder: (_) => ExchangeCard( - key: receiveKey, - title: S.of(context).you_will_get, - initialCurrency: exchangeStore.receiveCurrency, - initialWalletName: receiveWalletName, - initialAddress: - exchangeStore.receiveCurrency == walletStore.type - ? walletStore.address - : exchangeStore.receiveAddress, - initialIsAmountEditable: false, - initialIsAddressEditable: true, - isAmountEstimated: true, - currencies: CryptoCurrency.all, - onCurrencySelected: (currency) => exchangeStore - .changeReceiveCurrency(currency: currency), - imageArrow: arrowBottomCakeGreen, - currencyButtonColor: PaletteDark.menuList, - currencyValueValidator: (value) { - exchangeStore.validateCryptoCurrency(value); - return exchangeStore.errorMessage; - }, - addressTextFieldValidator: (value) { - exchangeStore.validateAddress(value, - cryptoCurrency: exchangeStore.receiveCurrency); - return exchangeStore.errorMessage; - }, - )), - ) - ], - ) - ), - Padding( - padding: EdgeInsets.only( - top: 32, - left: 24, - bottom: 24 - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - S.of(context).send_templates, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: PaletteDark.walletCardText - ), - ) - ], - ), - ), - Container( - height: 40, - width: double.infinity, - padding: EdgeInsets.only(left: 24), - child: Observer( - builder: (_) { - final itemCount = exchangeTemplateStore.templates.length + 1; - - return ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: itemCount, - itemBuilder: (context, index) { - - if (index == 0) { - return GestureDetector( - onTap: () => Navigator.of(context) - .pushNamed(Routes.exchangeTemplate), - child: Container( - padding: EdgeInsets.only(right: 10), - child: DottedBorder( - borderType: BorderType.RRect, - dashPattern: [8, 4], - color: PaletteDark.menuList, - strokeWidth: 2, - radius: Radius.circular(20), - child: Container( - height: 40, - width: 75, - padding: EdgeInsets.only(left: 10, right: 10), - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(20)), - color: Colors.transparent, - ), - child: Text( - S.of(context).send_new, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: PaletteDark.walletCardText - ), - ), - ) - ), - ), - ); - } - - index -= 1; - - final template = exchangeTemplateStore.templates[index]; - - return TemplateTile( - amount: template.amount, - from: template.depositCurrency, - to: template.receiveCurrency, - onTap: () { - applyTemplate(exchangeStore, template); - } - ); - } - ); - } - ), - ) - ], - ), - bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), - bottomSection: Column(children: [ - Padding( - padding: EdgeInsets.only(bottom: 15), - child: Observer(builder: (_) { - final description = - exchangeStore.provider is XMRTOExchangeProvider - ? S.of(context).amount_is_guaranteed - : S.of(context).amount_is_estimate; - return Center( - child: Text( - description, - style: TextStyle( - color: PaletteDark.walletCardText, - fontSize: 12 - ), - ), - ); - }), - ), - Observer( - builder: (_) => LoadingPrimaryButton( - text: S.of(context).exchange, - onPressed: () { - if (_formKey.currentState.validate()) { - exchangeStore.createTrade(); - } - }, - color: Colors.blue, - textColor: Colors.white, - isLoading: exchangeStore.tradeState is TradeIsCreating, - )), - ]), - )), + return BaseExchangeWidget( + exchangeStore: exchangeStore, + walletStore: walletStore, + exchangeTemplateStore: exchangeTemplateStore, + isTemplate: false ); } - - void applyTemplate(ExchangeStore store, ExchangeTemplate template) { - store.changeDepositCurrency(currency: CryptoCurrency.fromString(template.depositCurrency)); - store.changeReceiveCurrency(currency: CryptoCurrency.fromString(template.receiveCurrency)); - - switch (template.provider) { - case 'XMR.TO': - store.changeProvider(provider: store.providerList[0]); - break; - case 'ChangeNOW': - store.changeProvider(provider: store.providerList[1]); - break; - case 'MorphToken': - store.changeProvider(provider: store.providerList[2]); - break; - } - - store.changeDepositAmount(amount: template.amount); - store.depositAddress = template.depositAddress; - store.receiveAddress = template.receiveAddress; - } - - void _setReactions( - BuildContext context, ExchangeStore store, WalletStore walletStore) { - if (_isReactionsSet) { - return; - } - - final depositAddressController = depositKey.currentState.addressController; - final depositAmountController = depositKey.currentState.amountController; - final receiveAddressController = receiveKey.currentState.addressController; - final receiveAmountController = receiveKey.currentState.amountController; - final limitsState = store.limitsState; - - if (limitsState is LimitsLoadedSuccessfully) { - final min = limitsState.limits.min != null - ? limitsState.limits.min.toString() - : null; - final max = limitsState.limits.max != null - ? limitsState.limits.max.toString() - : null; - final key = depositKey; - key.currentState.changeLimits(min: min, max: max); - } - - _onCurrencyChange(store.receiveCurrency, walletStore, receiveKey); - _onCurrencyChange(store.depositCurrency, walletStore, depositKey); - - reaction( - (_) => walletStore.name, - (String _) => _onWalletNameChange( - walletStore, store.receiveCurrency, receiveKey)); - - reaction( - (_) => walletStore.name, - (String _) => _onWalletNameChange( - walletStore, store.depositCurrency, depositKey)); - - reaction( - (_) => store.receiveCurrency, - (CryptoCurrency currency) => - _onCurrencyChange(currency, walletStore, receiveKey)); - - reaction( - (_) => store.depositCurrency, - (CryptoCurrency currency) => - _onCurrencyChange(currency, walletStore, depositKey)); - - reaction((_) => store.depositAmount, (String amount) { - if (depositKey.currentState.amountController.text != amount) { - depositKey.currentState.amountController.text = amount; - } - }); - - reaction((_) => store.depositAddress, (String address) { - if (depositKey.currentState.addressController.text != address) { - depositKey.currentState.addressController.text = address; - } - }); - - reaction((_) => store.receiveAmount, (String amount) { - if (receiveKey.currentState.amountController.text != - store.receiveAmount) { - receiveKey.currentState.amountController.text = amount; - } - }); - - reaction((_) => store.receiveAddress, (String address) { - if (receiveKey.currentState.addressController.text != address) { - receiveKey.currentState.addressController.text = address; - } - }); - - reaction((_) => store.provider, (ExchangeProvider provider) { - receiveKey.currentState.isAddressEditable(isEditable: true); - receiveKey.currentState.isAmountEditable(isEditable: false); - depositKey.currentState.isAddressEditable(isEditable: true); - depositKey.currentState.isAmountEditable(isEditable: true); - - receiveKey.currentState.changeIsAmountEstimated(true); - }); - - reaction((_) => store.tradeState, (ExchangeTradeState state) { - if (state is TradeIsCreatedFailure) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.of(context).error, - alertContent: state.error, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop() - ); - }); - }); - } - if (state is TradeIsCreatedSuccessfully) { - Navigator.of(context) - .pushNamed(Routes.exchangeConfirm, arguments: state.trade); - } - }); - - reaction((_) => store.limitsState, (LimitsState state) { - String min; - String max; - - if (state is LimitsLoadedSuccessfully) { - min = state.limits.min != null ? state.limits.min.toString() : null; - max = state.limits.max != null ? state.limits.max.toString() : null; - } - - if (state is LimitsLoadedFailure) { - min = '0'; - max = '0'; - } - - if (state is LimitsIsLoading) { - min = '...'; - max = '...'; - } - - depositKey.currentState.changeLimits(min: min, max: max); - receiveKey.currentState.changeLimits(min: null, max: null); - }); - - depositAddressController.addListener( - () => store.depositAddress = depositAddressController.text); - - depositAmountController.addListener(() { - if (depositAmountController.text != store.depositAmount) { - store.changeDepositAmount(amount: depositAmountController.text); - } - }); - - receiveAddressController.addListener( - () => store.receiveAddress = receiveAddressController.text); - - receiveAmountController.addListener(() { - if (receiveAmountController.text != store.receiveAmount) { - store.changeReceiveAmount(amount: receiveAmountController.text); - } - }); - - reaction((_) => walletStore.address, (String address) { - if (store.depositCurrency == CryptoCurrency.xmr) { - depositKey.currentState.changeAddress(address: address); - } - - if (store.receiveCurrency == CryptoCurrency.xmr) { - receiveKey.currentState.changeAddress(address: address); - } - }); - - _isReactionsSet = true; - } - - void _onCurrencyChange(CryptoCurrency currency, WalletStore walletStore, - GlobalKey key) { - final isCurrentTypeWallet = currency == walletStore.type; - - key.currentState.changeSelectedCurrency(currency); - key.currentState - .changeWalletName(isCurrentTypeWallet ? walletStore.name : null); - - key.currentState - .changeAddress(address: isCurrentTypeWallet ? walletStore.address : ''); - - key.currentState.changeAmount(amount: ''); - } - - void _onWalletNameChange(WalletStore walletStore, CryptoCurrency currency, - GlobalKey key) { - final isCurrentTypeWallet = currency == walletStore.type; - - if (isCurrentTypeWallet) { - key.currentState.changeWalletName(walletStore.name); - key.currentState.addressController.text = walletStore.address; - } else if (key.currentState.addressController.text == walletStore.address) { - key.currentState.changeWalletName(null); - key.currentState.addressController.text = null; - } - } } diff --git a/lib/src/screens/exchange/exchange_template_page.dart b/lib/src/screens/exchange/exchange_template_page.dart index 8d92dff74..9b13a082c 100644 --- a/lib/src/screens/exchange/exchange_template_page.dart +++ b/lib/src/screens/exchange/exchange_template_page.dart @@ -1,106 +1,28 @@ import 'dart:ui'; -import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:mobx/mobx.dart'; import 'package:provider/provider.dart'; import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; -import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart'; -import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart'; -import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart'; -import 'package:cake_wallet/src/stores/exchange/limits_state.dart'; import 'package:cake_wallet/src/stores/wallet/wallet_store.dart'; import 'package:cake_wallet/src/stores/exchange/exchange_store.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.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/top_panel.dart'; -import 'package:cake_wallet/src/screens/exchange/widgets/provider_picker.dart'; +import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker.dart'; import 'package:cake_wallet/src/stores/exchange_template/exchange_template_store.dart'; +import 'package:cake_wallet/src/screens/exchange/widgets/base_exchange_widget.dart'; +import 'package:cake_wallet/generated/i18n.dart'; class ExchangeTemplatePage extends BasePage { @override - String get title => 'New template'; + String get title => S.current.exchange_new_template; @override Color get backgroundColor => PaletteDark.walletCardSubAddressField; - final Image arrowBottom = - Image.asset('assets/images/arrow_bottom_purple_icon.png', color: Colors.white, height: 6); - @override Widget trailing(BuildContext context) { final exchangeStore = Provider.of(context); - return FlatButton( - onPressed: () => _presentProviderPicker(context), - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - child: Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text(S.of(context).exchange, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w400, - color: Colors.white)), - Observer( - builder: (_) => Text('${exchangeStore.provider.title}', - style: TextStyle( - fontSize: 10.0, - fontWeight: FontWeight.w400, - color:PaletteDark.walletCardText))) - ], - ), - SizedBox(width: 5), - Padding( - padding: EdgeInsets.only(top: 8), - child: arrowBottom, - ) - ], - ) - ); - } - - void _presentProviderPicker(BuildContext context) { - final exchangeStore = Provider.of(context); - final items = exchangeStore.providersForCurrentPair(); - final selectedItem = items.indexOf(exchangeStore.provider); - final images = List(); - - for (ExchangeProvider provider in items) { - switch (provider.description) { - case ExchangeProviderDescription.xmrto: - images.add(Image.asset('assets/images/xmr_btc.png')); - break; - case ExchangeProviderDescription.changeNow: - images.add(Image.asset('assets/images/change_now.png')); - break; - case ExchangeProviderDescription.morphToken: - images.add(Image.asset('assets/images/morph_icon.png')); - break; - } - } - - showDialog( - builder: (_) => ProviderPicker( - items: items, - images: images, - selectedAtIndex: selectedItem, - title: S.of(context).change_exchange_provider, - onItemSelected: (ExchangeProvider provider) => - exchangeStore.changeProvider(provider: provider)), - context: context); + return PresentProviderPicker(exchangeStore: exchangeStore); } @override @@ -113,21 +35,6 @@ class ExchangeTemplateForm extends StatefulWidget{ } class ExchangeTemplateFormState extends State { - final depositKey = GlobalKey(); - final receiveKey = GlobalKey(); - final _formKey = GlobalKey(); - var _isReactionsSet = false; - - final Image arrowBottomPurple = Image.asset( - 'assets/images/arrow_bottom_purple_icon.png', - color: Colors.white, - height: 8, - ); - final Image arrowBottomCakeGreen = Image.asset( - 'assets/images/arrow_bottom_cake_green.png', - color: Colors.white, - height: 8, - ); @override Widget build(BuildContext context) { @@ -135,314 +42,11 @@ class ExchangeTemplateFormState extends State { final walletStore = Provider.of(context); final exchangeTemplateStore = Provider.of(context); - final depositWalletName = - exchangeStore.depositCurrency == CryptoCurrency.xmr - ? walletStore.name - : null; - final receiveWalletName = - exchangeStore.receiveCurrency == CryptoCurrency.xmr - ? walletStore.name - : null; - - WidgetsBinding.instance.addPostFrameCallback( - (_) => _setReactions(context, exchangeStore, walletStore)); - - return Container( - color: PaletteDark.historyPanel, - child: Form( - key: _formKey, - child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.only(bottom: 24), - content: Column( - children: [ - TopPanel( - color: PaletteDark.menuList, - edgeInsets: EdgeInsets.only(bottom: 24), - widget: Column( - children: [ - TopPanel( - color: PaletteDark.walletCardSubAddressField, - widget: Observer( - builder: (_) => ExchangeCard( - key: depositKey, - title: S.of(context).you_will_send, - initialCurrency: exchangeStore.depositCurrency, - initialWalletName: depositWalletName, - initialAddress: - exchangeStore.depositCurrency == walletStore.type - ? walletStore.address - : null, - initialIsAmountEditable: true, - initialIsAddressEditable: true, - isAmountEstimated: false, - currencies: CryptoCurrency.all, - onCurrencySelected: (currency) => - exchangeStore.changeDepositCurrency(currency: currency), - imageArrow: arrowBottomPurple, - currencyButtonColor: PaletteDark.walletCardSubAddressField, - addressButtonsColor: PaletteDark.menuList, - currencyValueValidator: (value) { - exchangeStore.validateCryptoCurrency(value); - return exchangeStore.errorMessage; - }, - addressTextFieldValidator: (value) { - exchangeStore.validateAddress(value, - cryptoCurrency: exchangeStore.depositCurrency); - return exchangeStore.errorMessage; - }, - ), - ) - ), - Padding( - padding: EdgeInsets.only(top: 32, left: 24, right: 24), - child: Observer( - builder: (_) => ExchangeCard( - key: receiveKey, - title: S.of(context).you_will_get, - initialCurrency: exchangeStore.receiveCurrency, - initialWalletName: receiveWalletName, - initialAddress: - exchangeStore.receiveCurrency == walletStore.type - ? walletStore.address - : null, - initialIsAmountEditable: false, - initialIsAddressEditable: true, - isAmountEstimated: true, - currencies: CryptoCurrency.all, - onCurrencySelected: (currency) => exchangeStore - .changeReceiveCurrency(currency: currency), - imageArrow: arrowBottomCakeGreen, - currencyButtonColor: PaletteDark.menuList, - currencyValueValidator: (value) { - exchangeStore.validateCryptoCurrency(value); - return exchangeStore.errorMessage; - }, - addressTextFieldValidator: (value) { - exchangeStore.validateAddress(value, - cryptoCurrency: exchangeStore.receiveCurrency); - return exchangeStore.errorMessage; - }, - )), - ) - ], - ) - ), - ], - ), - bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), - bottomSection: Column(children: [ - Padding( - padding: EdgeInsets.only(bottom: 15), - child: Observer(builder: (_) { - final description = - exchangeStore.provider is XMRTOExchangeProvider - ? S.of(context).amount_is_guaranteed - : S.of(context).amount_is_estimate; - return Center( - child: Text( - description, - style: TextStyle( - color: PaletteDark.walletCardText, - fontSize: 12 - ), - ), - ); - }), - ), - PrimaryButton( - onPressed: () { - if (_formKey.currentState.validate()) { - exchangeTemplateStore.addTemplate( - amount: exchangeStore.depositAmount, - depositCurrency: exchangeStore.depositCurrency.toString(), - receiveCurrency: exchangeStore.receiveCurrency.toString(), - provider: exchangeStore.provider.toString(), - depositAddress: exchangeStore.depositAddress, - receiveAddress: exchangeStore.receiveAddress - ); - exchangeTemplateStore.update(); - Navigator.of(context).pop(); - } - }, - text: S.of(context).save, - color: Colors.green, - textColor: Colors.white - ), - ]), - )), + return BaseExchangeWidget( + exchangeStore: exchangeStore, + walletStore: walletStore, + exchangeTemplateStore: exchangeTemplateStore, + isTemplate: true ); } - - void _setReactions( - BuildContext context, ExchangeStore store, WalletStore walletStore) { - if (_isReactionsSet) { - return; - } - - final depositAddressController = depositKey.currentState.addressController; - final depositAmountController = depositKey.currentState.amountController; - final receiveAddressController = receiveKey.currentState.addressController; - final receiveAmountController = receiveKey.currentState.amountController; - final limitsState = store.limitsState; - - if (limitsState is LimitsLoadedSuccessfully) { - final min = limitsState.limits.min != null - ? limitsState.limits.min.toString() - : null; - final max = limitsState.limits.max != null - ? limitsState.limits.max.toString() - : null; - final key = depositKey; - key.currentState.changeLimits(min: min, max: max); - } - - _onCurrencyChange(store.receiveCurrency, walletStore, receiveKey); - _onCurrencyChange(store.depositCurrency, walletStore, depositKey); - - reaction( - (_) => walletStore.name, - (String _) => _onWalletNameChange( - walletStore, store.receiveCurrency, receiveKey)); - - reaction( - (_) => walletStore.name, - (String _) => _onWalletNameChange( - walletStore, store.depositCurrency, depositKey)); - - reaction( - (_) => store.receiveCurrency, - (CryptoCurrency currency) => - _onCurrencyChange(currency, walletStore, receiveKey)); - - reaction( - (_) => store.depositCurrency, - (CryptoCurrency currency) => - _onCurrencyChange(currency, walletStore, depositKey)); - - reaction((_) => store.depositAmount, (String amount) { - if (depositKey.currentState.amountController.text != amount) { - depositKey.currentState.amountController.text = amount; - } - }); - - reaction((_) => store.receiveAmount, (String amount) { - if (receiveKey.currentState.amountController.text != - store.receiveAmount) { - receiveKey.currentState.amountController.text = amount; - } - }); - - reaction((_) => store.provider, (ExchangeProvider provider) { - receiveKey.currentState.isAddressEditable(isEditable: true); - receiveKey.currentState.isAmountEditable(isEditable: false); - depositKey.currentState.isAddressEditable(isEditable: true); - depositKey.currentState.isAmountEditable(isEditable: true); - - receiveKey.currentState.changeIsAmountEstimated(true); - }); - - reaction((_) => store.tradeState, (ExchangeTradeState state) { - if (state is TradeIsCreatedFailure) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text(S.of(context).error), - content: Text(state.error), - actions: [ - FlatButton( - child: Text(S.of(context).ok), - onPressed: () => Navigator.of(context).pop()) - ], - ); - }); - }); - } - if (state is TradeIsCreatedSuccessfully) { - Navigator.of(context) - .pushNamed(Routes.exchangeConfirm, arguments: state.trade); - } - }); - - reaction((_) => store.limitsState, (LimitsState state) { - String min; - String max; - - if (state is LimitsLoadedSuccessfully) { - min = state.limits.min != null ? state.limits.min.toString() : null; - max = state.limits.max != null ? state.limits.max.toString() : null; - } - - if (state is LimitsLoadedFailure) { - min = '0'; - max = '0'; - } - - if (state is LimitsIsLoading) { - min = '...'; - max = '...'; - } - - depositKey.currentState.changeLimits(min: min, max: max); - receiveKey.currentState.changeLimits(min: null, max: null); - }); - - depositAddressController.addListener( - () => store.depositAddress = depositAddressController.text); - - depositAmountController.addListener(() { - if (depositAmountController.text != store.depositAmount) { - store.changeDepositAmount(amount: depositAmountController.text); - } - }); - - receiveAddressController.addListener( - () => store.receiveAddress = receiveAddressController.text); - - receiveAmountController.addListener(() { - if (receiveAmountController.text != store.receiveAmount) { - store.changeReceiveAmount(amount: receiveAmountController.text); - } - }); - - reaction((_) => walletStore.address, (String address) { - if (store.depositCurrency == CryptoCurrency.xmr) { - depositKey.currentState.changeAddress(address: address); - } - - if (store.receiveCurrency == CryptoCurrency.xmr) { - receiveKey.currentState.changeAddress(address: address); - } - }); - - _isReactionsSet = true; - } - - void _onCurrencyChange(CryptoCurrency currency, WalletStore walletStore, - GlobalKey key) { - final isCurrentTypeWallet = currency == walletStore.type; - - key.currentState.changeSelectedCurrency(currency); - key.currentState - .changeWalletName(isCurrentTypeWallet ? walletStore.name : null); - - key.currentState - .changeAddress(address: isCurrentTypeWallet ? walletStore.address : ''); - - key.currentState.changeAmount(amount: ''); - } - - void _onWalletNameChange(WalletStore walletStore, CryptoCurrency currency, - GlobalKey key) { - final isCurrentTypeWallet = currency == walletStore.type; - - if (isCurrentTypeWallet) { - key.currentState.changeWalletName(walletStore.name); - key.currentState.addressController.text = walletStore.address; - } else if (key.currentState.addressController.text == walletStore.address) { - key.currentState.changeWalletName(null); - key.currentState.addressController.text = null; - } - } } \ No newline at end of file diff --git a/lib/src/screens/exchange/widgets/base_exchange_widget.dart b/lib/src/screens/exchange/widgets/base_exchange_widget.dart new file mode 100644 index 000000000..26807c59f --- /dev/null +++ b/lib/src/screens/exchange/widgets/base_exchange_widget.dart @@ -0,0 +1,521 @@ +import 'dart:ui'; +import 'package:cake_wallet/src/domain/exchange/exchange_template.dart'; +import 'package:cake_wallet/src/widgets/template_tile.dart'; +import 'package:dotted_border/dotted_border.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; +import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart'; +import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart'; +import 'package:cake_wallet/src/stores/exchange/limits_state.dart'; +import 'package:cake_wallet/src/stores/wallet/wallet_store.dart'; +import 'package:cake_wallet/src/stores/exchange/exchange_store.dart'; +import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.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/top_panel.dart'; +import 'package:cake_wallet/src/stores/exchange_template/exchange_template_store.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; + +class BaseExchangeWidget extends StatefulWidget { + BaseExchangeWidget({ + @ required this.exchangeStore, + @ required this.walletStore, + @ required this.exchangeTemplateStore, + @ required this.isTemplate, + }); + + final ExchangeStore exchangeStore; + final WalletStore walletStore; + final ExchangeTemplateStore exchangeTemplateStore; + final bool isTemplate; + + @override + BaseExchangeWidgetState createState() => + BaseExchangeWidgetState( + exchangeStore: exchangeStore, + walletStore: walletStore, + exchangeTemplateStore: exchangeTemplateStore, + isTemplate: isTemplate + ); +} + +class BaseExchangeWidgetState extends State { + BaseExchangeWidgetState({ + @ required this.exchangeStore, + @ required this.walletStore, + @ required this.exchangeTemplateStore, + @ required this.isTemplate, + }); + + final ExchangeStore exchangeStore; + final WalletStore walletStore; + final ExchangeTemplateStore exchangeTemplateStore; + final bool isTemplate; + + final depositKey = GlobalKey(); + final receiveKey = GlobalKey(); + final _formKey = GlobalKey(); + var _isReactionsSet = false; + + final Image arrowBottomPurple = Image.asset( + 'assets/images/arrow_bottom_purple_icon.png', + color: Colors.white, + height: 8, + ); + final Image arrowBottomCakeGreen = Image.asset( + 'assets/images/arrow_bottom_cake_green.png', + color: Colors.white, + height: 8, + ); + + @override + Widget build(BuildContext context) { + + final depositWalletName = + exchangeStore.depositCurrency == CryptoCurrency.xmr + ? walletStore.name + : null; + final receiveWalletName = + exchangeStore.receiveCurrency == CryptoCurrency.xmr + ? walletStore.name + : null; + + WidgetsBinding.instance.addPostFrameCallback( + (_) => _setReactions(context, exchangeStore, walletStore)); + + return Container( + color: PaletteDark.historyPanel, + child: Form( + key: _formKey, + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.only(bottom: 24), + content: Column( + children: [ + TopPanel( + color: PaletteDark.menuList, + edgeInsets: EdgeInsets.only(bottom: 24), + widget: Column( + children: [ + TopPanel( + color: PaletteDark.walletCardSubAddressField, + widget: Observer( + builder: (_) => ExchangeCard( + key: depositKey, + title: S.of(context).you_will_send, + initialCurrency: exchangeStore.depositCurrency, + initialWalletName: depositWalletName, + initialAddress: + exchangeStore.depositCurrency == walletStore.type + ? walletStore.address + : exchangeStore.depositAddress, + initialIsAmountEditable: true, + initialIsAddressEditable: exchangeStore.isDepositAddressEnabled, + isAmountEstimated: false, + currencies: CryptoCurrency.all, + onCurrencySelected: (currency) => + exchangeStore.changeDepositCurrency(currency: currency), + imageArrow: arrowBottomPurple, + currencyButtonColor: PaletteDark.walletCardSubAddressField, + addressButtonsColor: PaletteDark.menuList, + currencyValueValidator: (value) { + exchangeStore.validateCryptoCurrency(value); + return exchangeStore.errorMessage; + }, + addressTextFieldValidator: (value) { + exchangeStore.validateAddress(value, + cryptoCurrency: exchangeStore.depositCurrency); + return exchangeStore.errorMessage; + }, + ), + ) + ), + Padding( + padding: EdgeInsets.only(top: 32, left: 24, right: 24), + child: Observer( + builder: (_) => ExchangeCard( + key: receiveKey, + title: S.of(context).you_will_get, + initialCurrency: exchangeStore.receiveCurrency, + initialWalletName: receiveWalletName, + initialAddress: + exchangeStore.receiveCurrency == walletStore.type + ? walletStore.address + : exchangeStore.receiveAddress, + initialIsAmountEditable: false, + initialIsAddressEditable: exchangeStore.isReceiveAddressEnabled, + isAmountEstimated: true, + currencies: CryptoCurrency.all, + onCurrencySelected: (currency) => exchangeStore + .changeReceiveCurrency(currency: currency), + imageArrow: arrowBottomCakeGreen, + currencyButtonColor: PaletteDark.menuList, + currencyValueValidator: (value) { + exchangeStore.validateCryptoCurrency(value); + return exchangeStore.errorMessage; + }, + addressTextFieldValidator: (value) { + exchangeStore.validateAddress(value, + cryptoCurrency: exchangeStore.receiveCurrency); + return exchangeStore.errorMessage; + }, + )), + ) + ], + ) + ), + isTemplate + ? Offstage() + : Padding( + padding: EdgeInsets.only( + top: 32, + left: 24, + bottom: 24 + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + S.of(context).send_templates, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: PaletteDark.walletCardText + ), + ) + ], + ), + ), + isTemplate + ? Offstage() + : Container( + height: 40, + width: double.infinity, + padding: EdgeInsets.only(left: 24), + child: Observer( + builder: (_) { + final itemCount = exchangeTemplateStore.templates.length + 1; + + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: itemCount, + itemBuilder: (context, index) { + + if (index == 0) { + return GestureDetector( + onTap: () => Navigator.of(context) + .pushNamed(Routes.exchangeTemplate), + child: Container( + padding: EdgeInsets.only(right: 10), + child: DottedBorder( + borderType: BorderType.RRect, + dashPattern: [8, 4], + color: PaletteDark.menuList, + strokeWidth: 2, + radius: Radius.circular(20), + child: Container( + height: 40, + width: 75, + padding: EdgeInsets.only(left: 10, right: 10), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20)), + color: Colors.transparent, + ), + child: Text( + S.of(context).send_new, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: PaletteDark.walletCardText + ), + ), + ) + ), + ), + ); + } + + index -= 1; + + final template = exchangeTemplateStore.templates[index]; + + return TemplateTile( + amount: template.amount, + from: template.depositCurrency, + to: template.receiveCurrency, + onTap: () { + applyTemplate(exchangeStore, template); + } + ); + } + ); + } + ), + ) + ], + ), + bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), + bottomSection: Column(children: [ + Padding( + padding: EdgeInsets.only(bottom: 15), + child: Observer(builder: (_) { + final description = + exchangeStore.provider is XMRTOExchangeProvider + ? S.of(context).amount_is_guaranteed + : S.of(context).amount_is_estimate; + return Center( + child: Text( + description, + style: TextStyle( + color: PaletteDark.walletCardText, + fontSize: 12 + ), + ), + ); + }), + ), + isTemplate + ? PrimaryButton( + onPressed: () { + if (_formKey.currentState.validate()) { + exchangeTemplateStore.addTemplate( + amount: exchangeStore.depositAmount, + depositCurrency: exchangeStore.depositCurrency.toString(), + receiveCurrency: exchangeStore.receiveCurrency.toString(), + provider: exchangeStore.provider.toString(), + depositAddress: exchangeStore.depositAddress, + receiveAddress: exchangeStore.receiveAddress + ); + exchangeTemplateStore.update(); + Navigator.of(context).pop(); + } + }, + text: S.of(context).save, + color: Colors.green, + textColor: Colors.white + ) + : Observer( + builder: (_) => LoadingPrimaryButton( + text: S.of(context).exchange, + onPressed: () { + if (_formKey.currentState.validate()) { + exchangeStore.createTrade(); + } + }, + color: Colors.blue, + textColor: Colors.white, + isLoading: exchangeStore.tradeState is TradeIsCreating, + )), + ]), + )), + ); + } + + void applyTemplate(ExchangeStore store, ExchangeTemplate template) { + store.changeDepositCurrency(currency: CryptoCurrency.fromString(template.depositCurrency)); + store.changeReceiveCurrency(currency: CryptoCurrency.fromString(template.receiveCurrency)); + + switch (template.provider) { + case 'XMR.TO': + store.changeProvider(provider: store.providerList[0]); + break; + case 'ChangeNOW': + store.changeProvider(provider: store.providerList[1]); + break; + case 'MorphToken': + store.changeProvider(provider: store.providerList[2]); + break; + } + + store.changeDepositAmount(amount: template.amount); + store.depositAddress = template.depositAddress; + store.receiveAddress = template.receiveAddress; + } + + void _setReactions( + BuildContext context, ExchangeStore store, WalletStore walletStore) { + if (_isReactionsSet) { + return; + } + + final depositAddressController = depositKey.currentState.addressController; + final depositAmountController = depositKey.currentState.amountController; + final receiveAddressController = receiveKey.currentState.addressController; + final receiveAmountController = receiveKey.currentState.amountController; + final limitsState = store.limitsState; + + if (limitsState is LimitsLoadedSuccessfully) { + final min = limitsState.limits.min != null + ? limitsState.limits.min.toString() + : null; + final max = limitsState.limits.max != null + ? limitsState.limits.max.toString() + : null; + final key = depositKey; + key.currentState.changeLimits(min: min, max: max); + } + + _onCurrencyChange(store.receiveCurrency, walletStore, receiveKey); + _onCurrencyChange(store.depositCurrency, walletStore, depositKey); + + reaction( + (_) => walletStore.name, + (String _) => _onWalletNameChange( + walletStore, store.receiveCurrency, receiveKey)); + + reaction( + (_) => walletStore.name, + (String _) => _onWalletNameChange( + walletStore, store.depositCurrency, depositKey)); + + reaction( + (_) => store.receiveCurrency, + (CryptoCurrency currency) => + _onCurrencyChange(currency, walletStore, receiveKey)); + + reaction( + (_) => store.depositCurrency, + (CryptoCurrency currency) => + _onCurrencyChange(currency, walletStore, depositKey)); + + reaction((_) => store.depositAmount, (String amount) { + if (depositKey.currentState.amountController.text != amount) { + depositKey.currentState.amountController.text = amount; + } + }); + + reaction((_) => store.depositAddress, (String address) { + if (depositKey.currentState.addressController.text != address) { + depositKey.currentState.addressController.text = address; + } + }); + + reaction((_) => store.isDepositAddressEnabled, (bool isEnabled) { + depositKey.currentState.isAddressEditable(isEditable: isEnabled); + }); + + reaction((_) => store.receiveAmount, (String amount) { + if (receiveKey.currentState.amountController.text != + store.receiveAmount) { + receiveKey.currentState.amountController.text = amount; + } + }); + + reaction((_) => store.receiveAddress, (String address) { + if (receiveKey.currentState.addressController.text != address) { + receiveKey.currentState.addressController.text = address; + } + }); + + reaction((_) => store.isReceiveAddressEnabled, (bool isEnabled) { + receiveKey.currentState.isAddressEditable(isEditable: isEnabled); + }); + + reaction((_) => store.tradeState, (ExchangeTradeState state) { + if (state is TradeIsCreatedFailure) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).error, + alertContent: state.error, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop() + ); + }); + }); + } + if (state is TradeIsCreatedSuccessfully) { + Navigator.of(context) + .pushNamed(Routes.exchangeConfirm, arguments: state.trade); + } + }); + + reaction((_) => store.limitsState, (LimitsState state) { + String min; + String max; + + if (state is LimitsLoadedSuccessfully) { + min = state.limits.min != null ? state.limits.min.toString() : null; + max = state.limits.max != null ? state.limits.max.toString() : null; + } + + if (state is LimitsLoadedFailure) { + min = '0'; + max = '0'; + } + + if (state is LimitsIsLoading) { + min = '...'; + max = '...'; + } + + depositKey.currentState.changeLimits(min: min, max: max); + receiveKey.currentState.changeLimits(min: null, max: null); + }); + + depositAddressController.addListener( + () => store.depositAddress = depositAddressController.text); + + depositAmountController.addListener(() { + if (depositAmountController.text != store.depositAmount) { + store.changeDepositAmount(amount: depositAmountController.text); + } + }); + + receiveAddressController.addListener( + () => store.receiveAddress = receiveAddressController.text); + + receiveAmountController.addListener(() { + if (receiveAmountController.text != store.receiveAmount) { + store.changeReceiveAmount(amount: receiveAmountController.text); + } + }); + + reaction((_) => walletStore.address, (String address) { + if (store.depositCurrency == CryptoCurrency.xmr) { + depositKey.currentState.changeAddress(address: address); + } + + if (store.receiveCurrency == CryptoCurrency.xmr) { + receiveKey.currentState.changeAddress(address: address); + } + }); + + _isReactionsSet = true; + } + + void _onCurrencyChange(CryptoCurrency currency, WalletStore walletStore, + GlobalKey key) { + final isCurrentTypeWallet = currency == walletStore.type; + + key.currentState.changeSelectedCurrency(currency); + key.currentState + .changeWalletName(isCurrentTypeWallet ? walletStore.name : null); + + key.currentState + .changeAddress(address: isCurrentTypeWallet ? walletStore.address : ''); + + key.currentState.changeAmount(amount: ''); + } + + void _onWalletNameChange(WalletStore walletStore, CryptoCurrency currency, + GlobalKey key) { + final isCurrentTypeWallet = currency == walletStore.type; + + if (isCurrentTypeWallet) { + key.currentState.changeWalletName(walletStore.name); + key.currentState.addressController.text = walletStore.address; + } else if (key.currentState.addressController.text == walletStore.address) { + key.currentState.changeWalletName(null); + key.currentState.addressController.text = null; + } + } +} \ No newline at end of file diff --git a/lib/src/screens/exchange/widgets/present_provider_picker.dart b/lib/src/screens/exchange/widgets/present_provider_picker.dart new file mode 100644 index 000000000..0424d6c32 --- /dev/null +++ b/lib/src/screens/exchange/widgets/present_provider_picker.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:cake_wallet/src/stores/exchange/exchange_store.dart'; +import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart'; +import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart'; +import 'package:cake_wallet/src/screens/exchange/widgets/provider_picker.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/palette.dart'; + +class PresentProviderPicker extends StatelessWidget { + PresentProviderPicker({@required this.exchangeStore}); + + final ExchangeStore exchangeStore; + + final Image arrowBottom = + Image.asset('assets/images/arrow_bottom_purple_icon.png', color: Colors.white, height: 6); + + @override + Widget build(BuildContext context) { + return FlatButton( + onPressed: () => _presentProviderPicker(context), + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text(S.of(context).exchange, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w400, + color: Colors.white)), + Observer( + builder: (_) => Text('${exchangeStore.provider.title}', + style: TextStyle( + fontSize: 10.0, + fontWeight: FontWeight.w400, + color:PaletteDark.walletCardText))) + ], + ), + SizedBox(width: 5), + Padding( + padding: EdgeInsets.only(top: 8), + child: arrowBottom, + ) + ], + ) + ); + } + + void _presentProviderPicker(BuildContext context) { + final items = exchangeStore.providersForCurrentPair(); + final selectedItem = items.indexOf(exchangeStore.provider); + final images = List(); + + for (ExchangeProvider provider in items) { + switch (provider.description) { + case ExchangeProviderDescription.xmrto: + images.add(Image.asset('assets/images/xmr_btc.png')); + break; + case ExchangeProviderDescription.changeNow: + images.add(Image.asset('assets/images/change_now.png')); + break; + case ExchangeProviderDescription.morphToken: + images.add(Image.asset('assets/images/morph_icon.png')); + break; + } + } + + showDialog( + builder: (_) => ProviderPicker( + items: items, + images: images, + selectedAtIndex: selectedItem, + title: S.of(context).change_exchange_provider, + onItemSelected: (ExchangeProvider provider) => + exchangeStore.changeProvider(provider: provider)), + context: context); + } +} \ No newline at end of file diff --git a/lib/src/stores/exchange/exchange_store.dart b/lib/src/stores/exchange/exchange_store.dart index 2d432299b..9ac6ef05c 100644 --- a/lib/src/stores/exchange/exchange_store.dart +++ b/lib/src/stores/exchange/exchange_store.dart @@ -33,6 +33,8 @@ abstract class ExchangeStoreBase with Store { provider = initialProvider; depositCurrency = initialDepositCurrency; receiveCurrency = initialReceiveCurrency; + isDepositAddressEnabled = !(depositCurrency == walletStore.type); + isReceiveAddressEnabled = !(receiveCurrency == walletStore.type); depositAmount = ''; receiveAmount = ''; depositAddress = ''; @@ -73,6 +75,12 @@ abstract class ExchangeStoreBase with Store { @observable String receiveAddress; + @observable + bool isDepositAddressEnabled; + + @observable + bool isReceiveAddressEnabled; + @observable bool isValid; @@ -99,12 +107,16 @@ abstract class ExchangeStoreBase with Store { void changeDepositCurrency({CryptoCurrency currency}) { depositCurrency = currency; _onPairChange(); + isDepositAddressEnabled = !(depositCurrency == walletStore.type); + isReceiveAddressEnabled = !(receiveCurrency == walletStore.type); } @action void changeReceiveCurrency({CryptoCurrency currency}) { receiveCurrency = currency; _onPairChange(); + isDepositAddressEnabled = !(depositCurrency == walletStore.type); + isReceiveAddressEnabled = !(receiveCurrency == walletStore.type); } @action @@ -224,12 +236,13 @@ abstract class ExchangeStoreBase with Store { void reset() { depositAmount = ''; receiveAmount = ''; - depositAddress = ''; - receiveAddress = ''; - provider = XMRTOExchangeProvider(); depositCurrency = CryptoCurrency.xmr; receiveCurrency = CryptoCurrency.btc; - loadLimits(); + depositAddress = depositCurrency == walletStore.type ? walletStore.address : ''; + receiveAddress = receiveCurrency == walletStore.type ? walletStore.address : ''; + isDepositAddressEnabled = !(depositCurrency == walletStore.type); + isReceiveAddressEnabled = !(receiveCurrency == walletStore.type); + _onPairChange(); } List providersForCurrentPair() { diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index 647dd80ba..766afefd2 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -124,6 +124,11 @@ class AddressTextField extends StatelessWidget { color: PaletteDark.walletCardSubAddressField, width: 1.0)) : InputBorder.none, + disabledBorder: isBorderExist + ? UnderlineInputBorder( + borderSide: + BorderSide(color: PaletteDark.walletCardSubAddressField, width: 1.0)) + : InputBorder.none, enabledBorder: isBorderExist ? UnderlineInputBorder( borderSide: diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 5323a3ec1..4b78f6af2 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -96,6 +96,7 @@ "expired" : "Abgelaufen", "time" : "${minutes}m ${seconds}s", "send_xmr" : "Senden XMR", + "exchange_new_template" : "Neue Vorlage", "faq" : "FAQ", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index abeb86c53..3f8ba3280 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -96,6 +96,7 @@ "expired" : "Expired", "time" : "${minutes}m ${seconds}s", "send_xmr" : "Send XMR", + "exchange_new_template" : "New template", "faq" : "FAQ", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 4c844351f..54acc7d85 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -96,6 +96,7 @@ "expired" : "Muerto", "time" : "${minutes}m ${seconds}s", "send_xmr" : "Enviar XMR", + "exchange_new_template" : "Nueva plantilla", "faq" : "FAQ", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 5e420358d..1751b594e 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -96,6 +96,7 @@ "expired" : "समय सीमा समाप्त", "time" : "${minutes}m ${seconds}s", "send_xmr" : "संदेश XMR", + "exchange_new_template" : "नया टेम्पलेट", "faq" : "FAQ", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index bf6378f48..6ea4b08be 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -96,6 +96,7 @@ "expired" : "期限切れ", "time" : "${minutes}m ${seconds}s", "send_xmr" : "送る XMR", + "exchange_new_template" : "新しいテンプレート", "faq" : "FAQ", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 03f5ada3d..1a89f243d 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -96,6 +96,7 @@ "expired" : "만료", "time" : "${minutes}m ${seconds}s", "send_xmr" : "보내다 XMR", + "exchange_new_template" : "새 템플릿", "faq" : "FAQ", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 8dcbb0227..079bcfd55 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -96,6 +96,7 @@ "expired" : "Verlopen", "time" : "${minutes}m ${seconds}s", "send_xmr" : "Sturen XMR", + "exchange_new_template" : "Nieuwe sjabloon", "faq" : "FAQ", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 86d54bdfc..10c2cdb75 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -96,6 +96,7 @@ "expired" : "Przedawniony", "time" : "${minutes}m ${seconds}s", "send_xmr" : "Wysłać XMR", + "exchange_new_template" : "Nowy szablon", "faq" : "FAQ", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 67187d360..2a0f779e6 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -96,6 +96,7 @@ "expired" : "Expirada", "time" : "${minutes}m ${seconds}s", "send_xmr" : "Enviar XMR", + "exchange_new_template" : "Novo modelo", "faq" : "FAQ", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index da73521ed..35d67247a 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -96,6 +96,7 @@ "expired" : "Истекает", "time" : "${minutes}мин ${seconds}сек", "send_xmr" : "Отправить XMR", + "exchange_new_template" : "Новый шаблон", "faq" : "FAQ", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index e055019fd..07464070f 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -96,6 +96,7 @@ "expired" : "Закінчується", "time" : "${minutes}хв ${seconds}сек", "send_xmr" : "Відправити XMR", + "exchange_new_template" : "Новий шаблон", "faq" : "FAQ", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 96d5df1f5..5c1c2c100 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -96,6 +96,7 @@ "expired" : "已过期", "time" : "${minutes}m ${seconds}s", "send_xmr" : "发送 XMR", + "exchange_new_template" : "新範本", "faq" : "FAQ",