diff --git a/assets/images/2.0x/eye_menu.png b/assets/images/2.0x/eye_menu.png new file mode 100644 index 000000000..82e097023 Binary files /dev/null and b/assets/images/2.0x/eye_menu.png differ diff --git a/assets/images/2.0x/key_menu.png b/assets/images/2.0x/key_menu.png new file mode 100644 index 000000000..dc69ce578 Binary files /dev/null and b/assets/images/2.0x/key_menu.png differ diff --git a/assets/images/2.0x/monero_menu.png b/assets/images/2.0x/monero_menu.png new file mode 100644 index 000000000..b92733a16 Binary files /dev/null and b/assets/images/2.0x/monero_menu.png differ diff --git a/assets/images/2.0x/nodes_menu.png b/assets/images/2.0x/nodes_menu.png new file mode 100644 index 000000000..bb07fcd82 Binary files /dev/null and b/assets/images/2.0x/nodes_menu.png differ diff --git a/assets/images/2.0x/open_book_menu.png b/assets/images/2.0x/open_book_menu.png new file mode 100644 index 000000000..9f7c2c0f6 Binary files /dev/null and b/assets/images/2.0x/open_book_menu.png differ diff --git a/assets/images/2.0x/reconnect_menu.png b/assets/images/2.0x/reconnect_menu.png new file mode 100644 index 000000000..17a08ecdc Binary files /dev/null and b/assets/images/2.0x/reconnect_menu.png differ diff --git a/assets/images/2.0x/settings_menu.png b/assets/images/2.0x/settings_menu.png new file mode 100644 index 000000000..9456a57c0 Binary files /dev/null and b/assets/images/2.0x/settings_menu.png differ diff --git a/assets/images/2.0x/wallet_menu.png b/assets/images/2.0x/wallet_menu.png new file mode 100644 index 000000000..c5b622fed Binary files /dev/null and b/assets/images/2.0x/wallet_menu.png differ diff --git a/assets/images/3.0x/eye_menu.png b/assets/images/3.0x/eye_menu.png new file mode 100644 index 000000000..cae06bb91 Binary files /dev/null and b/assets/images/3.0x/eye_menu.png differ diff --git a/assets/images/3.0x/key_menu.png b/assets/images/3.0x/key_menu.png new file mode 100644 index 000000000..9b423d7c4 Binary files /dev/null and b/assets/images/3.0x/key_menu.png differ diff --git a/assets/images/3.0x/monero_menu.png b/assets/images/3.0x/monero_menu.png new file mode 100644 index 000000000..7d81566f5 Binary files /dev/null and b/assets/images/3.0x/monero_menu.png differ diff --git a/assets/images/3.0x/nodes_menu.png b/assets/images/3.0x/nodes_menu.png new file mode 100644 index 000000000..d97ca64e1 Binary files /dev/null and b/assets/images/3.0x/nodes_menu.png differ diff --git a/assets/images/3.0x/open_book_menu.png b/assets/images/3.0x/open_book_menu.png new file mode 100644 index 000000000..3e7c79133 Binary files /dev/null and b/assets/images/3.0x/open_book_menu.png differ diff --git a/assets/images/3.0x/reconnect_menu.png b/assets/images/3.0x/reconnect_menu.png new file mode 100644 index 000000000..ebc7672cf Binary files /dev/null and b/assets/images/3.0x/reconnect_menu.png differ diff --git a/assets/images/3.0x/settings_menu.png b/assets/images/3.0x/settings_menu.png new file mode 100644 index 000000000..2da43a238 Binary files /dev/null and b/assets/images/3.0x/settings_menu.png differ diff --git a/assets/images/3.0x/wallet_menu.png b/assets/images/3.0x/wallet_menu.png new file mode 100644 index 000000000..7884a4e23 Binary files /dev/null and b/assets/images/3.0x/wallet_menu.png differ diff --git a/assets/images/eye_menu.png b/assets/images/eye_menu.png new file mode 100644 index 000000000..7676b4dbc Binary files /dev/null and b/assets/images/eye_menu.png differ diff --git a/assets/images/key_menu.png b/assets/images/key_menu.png new file mode 100644 index 000000000..929f15391 Binary files /dev/null and b/assets/images/key_menu.png differ diff --git a/assets/images/monero_menu.png b/assets/images/monero_menu.png new file mode 100644 index 000000000..2bb420a80 Binary files /dev/null and b/assets/images/monero_menu.png differ diff --git a/assets/images/nodes_menu.png b/assets/images/nodes_menu.png new file mode 100644 index 000000000..b743f9107 Binary files /dev/null and b/assets/images/nodes_menu.png differ diff --git a/assets/images/open_book_menu.png b/assets/images/open_book_menu.png new file mode 100644 index 000000000..34721682e Binary files /dev/null and b/assets/images/open_book_menu.png differ diff --git a/assets/images/reconnect_menu.png b/assets/images/reconnect_menu.png new file mode 100644 index 000000000..d94a875e7 Binary files /dev/null and b/assets/images/reconnect_menu.png differ diff --git a/assets/images/settings_menu.png b/assets/images/settings_menu.png new file mode 100644 index 000000000..35ef51aee Binary files /dev/null and b/assets/images/settings_menu.png differ diff --git a/assets/images/wallet_menu.png b/assets/images/wallet_menu.png new file mode 100644 index 000000000..47f968193 Binary files /dev/null and b/assets/images/wallet_menu.png differ diff --git a/lib/core/amount_validator.dart b/lib/core/amount_validator.dart index 0aa0aba23..8ed81e0a6 100644 --- a/lib/core/amount_validator.dart +++ b/lib/core/amount_validator.dart @@ -3,10 +3,11 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart'; class AmountValidator extends TextValidator { - AmountValidator({WalletType type}) + AmountValidator({WalletType type, bool isAutovalidate = false}) : super( errorMessage: S.current.error_text_amount, pattern: _pattern(type), + isAutovalidate: isAutovalidate, minLength: 0, maxLength: 0); diff --git a/lib/core/validator.dart b/lib/core/validator.dart index 312c7f356..fa867c1d6 100644 --- a/lib/core/validator.dart +++ b/lib/core/validator.dart @@ -16,18 +16,20 @@ class TextValidator extends Validator { this.maxLength, this.pattern, this.length, + this.isAutovalidate = false, String errorMessage}) : super(errorMessage: errorMessage); final int minLength; final int maxLength; final List length; + final bool isAutovalidate; String pattern; @override bool isValid(String value) { if (value == null || value.isEmpty) { - return false; + return isAutovalidate ? true : false; } return value.length > (minLength ?? 0) && diff --git a/lib/di.dart b/lib/di.dart index 56e5eeb3a..fff785d99 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -10,6 +10,8 @@ import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart'; import 'package:cake_wallet/src/screens/send/send_template_page.dart'; import 'package:cake_wallet/src/screens/settings/settings.dart'; import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart'; +import 'package:cake_wallet/src/screens/exchange/exchange_page.dart'; +import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart'; import 'package:cake_wallet/store/contact_list_store.dart'; import 'package:cake_wallet/store/node_list_store.dart'; import 'package:cake_wallet/store/settings_store.dart'; @@ -42,6 +44,7 @@ import 'package:cake_wallet/view_model/settings/settings_view_model.dart'; import 'package:cake_wallet/view_model/wallet_keys_view_model.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_seed_view_model.dart'; +import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart'; import 'package:flutter/foundation.dart'; import 'package:get_it/get_it.dart'; import 'package:hive/hive.dart'; @@ -299,4 +302,17 @@ Future setup( getIt.registerFactory( () => NodeCreateOrEditPage(getIt.get())); + + getIt.registerFactory(() => + ExchangeViewModel( + wallet: getIt.get().wallet, + exchangeTemplateStore: getIt.get(), + trades: tradesSource + )); + + getIt.registerFactory(() => + ExchangePage(getIt.get())); + + getIt.registerFactory(() => + ExchangeTemplatePage(getIt.get())); } diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 261e73f6d..7dcdbd306 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -135,6 +135,7 @@ class S implements WidgetsLocalizations { String get reconnect => "Reconnect"; String get reconnect_alert_text => "Are you sure to reconnect?"; String get reconnection => "Reconnection"; + String get refund_address => "Refund address"; String get remove => "Remove"; String get remove_node => "Remove node"; String get remove_node_message => "Are you sure that you want to remove selected node?"; @@ -372,6 +373,8 @@ class $de extends S { @override String get trade_state_underpaid => "Unterbezahlt"; @override + String get refund_address => "Rückerstattungsadresse"; + @override String get welcome => "Willkommen zu"; @override String get share_address => "Adresse teilen "; @@ -998,6 +1001,8 @@ class $hi extends S { @override String get trade_state_underpaid => "के तहत भुगतान किया"; @override + String get refund_address => "वापसी का पता"; + @override String get welcome => "स्वागत हे सेवा मेरे"; @override String get share_address => "पता साझा करें"; @@ -1624,6 +1629,8 @@ class $ru extends S { @override String get trade_state_underpaid => "Недоплаченная"; @override + String get refund_address => "Адрес возврата"; + @override String get welcome => "Приветствуем в"; @override String get share_address => "Поделиться адресом"; @@ -2250,6 +2257,8 @@ class $ko extends S { @override String get trade_state_underpaid => "미지급"; @override + String get refund_address => "환불 주소"; + @override String get welcome => "환영 에"; @override String get share_address => "주소 공유"; @@ -2876,6 +2885,8 @@ class $pt extends S { @override String get trade_state_underpaid => "Parcialmente paga"; @override + String get refund_address => "Endereço de reembolso"; + @override String get welcome => "Bem-vindo ao"; @override String get share_address => "Compartilhar endereço"; @@ -3502,6 +3513,8 @@ class $uk extends S { @override String get trade_state_underpaid => "Недоплачена"; @override + String get refund_address => "Адреса повернення коштів"; + @override String get welcome => "Вітаємо в"; @override String get share_address => "Поділитися адресою"; @@ -4128,6 +4141,8 @@ class $ja extends S { @override String get trade_state_underpaid => "支払不足"; @override + String get refund_address => "払い戻し住所"; + @override String get welcome => "ようこそ に"; @override String get share_address => "住所を共有する"; @@ -4758,6 +4773,8 @@ class $pl extends S { @override String get trade_state_underpaid => "Niedopłacone"; @override + String get refund_address => "Adres zwrotu"; + @override String get welcome => "Witamy w"; @override String get share_address => "Udostępnij adres"; @@ -5384,6 +5401,8 @@ class $es extends S { @override String get trade_state_underpaid => "Poco pagado"; @override + String get refund_address => "Dirección de reembolso"; + @override String get welcome => "Bienvenido"; @override String get share_address => "Compartir dirección"; @@ -6010,6 +6029,8 @@ class $nl extends S { @override String get trade_state_underpaid => "Slecht betaald"; @override + String get refund_address => "Adres voor terugbetaling"; + @override String get welcome => "Welkom bij"; @override String get share_address => "Deel adres"; @@ -6636,6 +6657,8 @@ class $zh extends S { @override String get trade_state_underpaid => "支付不足"; @override + String get refund_address => "退款地址"; + @override String get welcome => "歡迎來到"; @override String get share_address => "分享地址"; diff --git a/lib/palette.dart b/lib/palette.dart index 02b135319..f5f3becc1 100644 --- a/lib/palette.dart +++ b/lib/palette.dart @@ -23,8 +23,8 @@ class PaletteDark { static const Color lightDistantBlue = Color.fromRGBO(81, 96, 147, 1.0); // borderCardColor static const Color gray = Color.fromRGBO(140, 153, 201, 1.0); // walletCardText static const Color violetBlue = Color.fromRGBO(51, 63, 104, 1.0); // walletCardAddressField - static const Color moderateBlue = Color.fromRGBO(63, 77, 122, 1.0); // walletCardSubAddressField - static const Color darkNightBlue = Color.fromRGBO(33, 43, 73, 1.0); // historyPanel + //static const Color moderateBlue = Color.fromRGBO(63, 77, 122, 1.0); // walletCardSubAddressField + //static const Color darkNightBlue = Color.fromRGBO(33, 43, 73, 1.0); // historyPanel static const Color pigeonBlue = Color.fromRGBO(91, 112, 146, 1.0); // historyPanelText static const Color moderateNightBlue = Color.fromRGBO(39, 53, 96, 1.0); // historyPanelButton static const Color headerNightBlue = Color.fromRGBO(41, 52, 84, 1.0); // menuHeader @@ -46,6 +46,12 @@ class PaletteDark { static const Color lightBlueGrey = Color.fromRGBO(125, 141, 183, 1.0); static const Color lightVioletBlue = Color.fromRGBO(56, 71, 109, 1.0); static const Color darkVioletBlue = Color.fromRGBO(49, 60, 96, 1.0); + static const Color wildVioletBlue = Color.fromRGBO(45, 60, 97, 1.0); + static const Color darkNightBlue = Color.fromRGBO(33, 45, 76, 1.0); + static const Color blueGrey = Color.fromRGBO(87, 98, 138, 1.0); + static const Color moderateBlue = Color.fromRGBO(60, 73, 118, 1.0); + static const Color deepPurpleBlue = Color.fromRGBO(19, 29, 56, 1.0); + static const Color lightOceanBlue = Color.fromRGBO(30, 42, 73, 1.0); // FIXME: Rename. static const Color eee = Color.fromRGBO(236, 239, 245, 1.0); diff --git a/lib/router.dart b/lib/router.dart index 974c6caa3..6c03dc1dd 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -411,45 +411,12 @@ class Router { walletRestorationFromSeedVM: walletRestorationFromSeedVM)); case Routes.exchange: - return MaterialPageRoute( - builder: (_) => MultiProvider(providers: [ - Provider(create: (_) { - final xmrtoprovider = XMRTOExchangeProvider(); - - return ExchangeStore( - initialProvider: xmrtoprovider, - initialDepositCurrency: CryptoCurrency.xmr, - initialReceiveCurrency: CryptoCurrency.btc, - trades: trades, - providerList: [ - xmrtoprovider, - ChangeNowExchangeProvider(), - MorphTokenExchangeProvider(trades: trades) - ], - walletStore: walletStore); - }), - ], child: ExchangePage())); + return CupertinoPageRoute( + builder: (_) => getIt.get()); case Routes.exchangeTemplate: - return MaterialPageRoute( - builder: (_) => Provider( - create: (_) { - final xmrtoprovider = XMRTOExchangeProvider(); - - return ExchangeStore( - initialProvider: xmrtoprovider, - initialDepositCurrency: CryptoCurrency.xmr, - initialReceiveCurrency: CryptoCurrency.btc, - trades: trades, - providerList: [ - xmrtoprovider, - ChangeNowExchangeProvider(), - MorphTokenExchangeProvider(trades: trades) - ], - walletStore: walletStore); - }, - child: ExchangeTemplatePage(), - )); + return CupertinoPageRoute( + builder: (_) => getIt.get()); case Routes.settings: return MaterialPageRoute( diff --git a/lib/src/screens/base_page.dart b/lib/src/screens/base_page.dart index e4eacd21c..30136815d 100644 --- a/lib/src/screens/base_page.dart +++ b/lib/src/screens/base_page.dart @@ -19,10 +19,14 @@ abstract class BasePage extends StatelessWidget { bool get resizeToAvoidBottomPadding => true; + Widget get endDrawer => null; + AppBarStyle get appBarStyle => AppBarStyle.regular; Widget Function(BuildContext, Widget) get rootWrapper => null; + final GlobalKey _scaffoldKey = GlobalKey(); + final _backArrowImage = Image.asset('assets/images/back_arrow.png', color: Colors.white); final _backArrowImageDarkTheme = @@ -32,6 +36,8 @@ abstract class BasePage extends StatelessWidget { final _closeButtonImageDarkTheme = Image.asset('assets/images/close_button_dark_theme.png'); + void onOpenEndDrawer() => _scaffoldKey.currentState.openEndDrawer(); + void onClose(BuildContext context) => Navigator.of(context).pop(); Widget leading(BuildContext context) { @@ -123,9 +129,11 @@ abstract class BasePage extends StatelessWidget { final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme; final root = Scaffold( + key: _scaffoldKey, backgroundColor: _isDarkTheme ? backgroundDarkColor : backgroundLightColor, resizeToAvoidBottomPadding: resizeToAvoidBottomPadding, + endDrawer: endDrawer, appBar: appBar(context), body: body(context), //SafeArea(child: ), floatingActionButton: floatingActionButton(context)); diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index b32b72e64..5b7939c92 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -23,6 +23,12 @@ class DashboardPage extends BasePage { @override Color get backgroundDarkColor => PaletteDark.backgroundColor; + @override + Widget get endDrawer => MenuWidget( + name: walletViewModel.name, + subname: walletViewModel.subname, + type: walletViewModel.type); + @override Widget middle(BuildContext context) { return SyncIndicator(dashboardViewModel: walletViewModel); @@ -40,14 +46,7 @@ class DashboardPage extends BasePage { highlightColor: Colors.transparent, splashColor: Colors.transparent, padding: EdgeInsets.all(0), - onPressed: () async { - await showDialog( - builder: (_) => MenuWidget( - name: walletViewModel.name, - subname: walletViewModel.subname, - type: walletViewModel.type), - context: context); - }, + onPressed: () => onOpenEndDrawer(), child: menuButton ) ); diff --git a/lib/src/screens/dashboard/wallet_menu.dart b/lib/src/screens/dashboard/wallet_menu.dart index 2190a8d34..a3c4666f0 100644 --- a/lib/src/screens/dashboard/wallet_menu.dart +++ b/lib/src/screens/dashboard/wallet_menu.dart @@ -20,13 +20,13 @@ class WalletMenu { ]; final List images = [ - Image.asset('assets/images/reconnect.png'), - Image.asset('assets/images/wallet.png'), - Image.asset('assets/images/nodes.png'), - Image.asset('assets/images/eye.png'), - Image.asset('assets/images/key.png'), - Image.asset('assets/images/open_book.png'), - Image.asset('assets/images/settings.png'), + Image.asset('assets/images/reconnect_menu.png', height: 16, width: 16), + Image.asset('assets/images/wallet_menu.png', height: 16, width: 16), + Image.asset('assets/images/nodes_menu.png', height: 16, width: 16), + Image.asset('assets/images/eye_menu.png', height: 16, width: 16), + Image.asset('assets/images/key_menu.png', height: 16, width: 16), + Image.asset('assets/images/open_book_menu.png', height: 16, width: 16), + Image.asset('assets/images/settings_menu.png', height: 16, width: 16), ]; final BuildContext context; diff --git a/lib/src/screens/dashboard/widgets/menu_widget.dart b/lib/src/screens/dashboard/widgets/menu_widget.dart index fdd9a704c..9a461c085 100644 --- a/lib/src/screens/dashboard/widgets/menu_widget.dart +++ b/lib/src/screens/dashboard/widgets/menu_widget.dart @@ -1,4 +1,5 @@ import 'dart:ui'; +import 'package:cake_wallet/palette.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart'; import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart'; @@ -15,7 +16,7 @@ class MenuWidget extends StatefulWidget { } class MenuWidgetState extends State { - final moneroIcon = Image.asset('assets/images/monero.png'); + final moneroIcon = Image.asset('assets/images/monero_menu.png'); final bitcoinIcon = Image.asset('assets/images/bitcoin.png'); final largeScreen = 731; @@ -36,10 +37,10 @@ class MenuWidgetState extends State { screenHeight = 0; opacity = 0; - headerHeight = 120; + headerHeight = 125; tileHeight = 75; fromTopEdge = 50; - fromBottomEdge = 30; + fromBottomEdge = 21;//30; super.initState(); WidgetsBinding.instance.addPostFrameCallback(afterLayout); @@ -66,189 +67,139 @@ class MenuWidgetState extends State { @override Widget build(BuildContext context) { final walletMenu = WalletMenu(context); -// final walletStore = Provider.of(context); final itemCount = walletMenu.items.length; - return Row( - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( + return SafeArea( + child: Row( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( padding: EdgeInsets.only(left: 24), child: Container( height: 60, width: 4, decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(2)), - color: Theme.of(context).hintColor), + borderRadius: BorderRadius.all(Radius.circular(2)), + color: Theme.of(context).hintColor), )), - SizedBox(width: 12), - Expanded( - child: GestureDetector( - onTap: () => null, - child: Container( - width: menuWidth, - height: double.infinity, - decoration: BoxDecoration( + SizedBox(width: 12), + Expanded( + child: ClipRRect( borderRadius: BorderRadius.only( - topLeft: Radius.circular(24), - bottomLeft: Radius.circular(24)), - color: Theme.of(context).primaryTextTheme.display1.color), - child: ClipRRect( - borderRadius: BorderRadius.only( topLeft: Radius.circular(24), bottomLeft: Radius.circular(24)), - child: ListView.separated( - itemBuilder: (_, index) { - if (index == 0) { - return Container( - height: headerHeight, - padding: EdgeInsets.only( - left: 24, - top: fromTopEdge, - right: 24, - bottom: fromBottomEdge), - decoration: BoxDecoration( - borderRadius: - BorderRadius.only(topLeft: Radius.circular(24)), - color: Theme.of(context) - .primaryTextTheme - .display2 - .color), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - _iconFor(type: widget.type), - SizedBox(width: 16), - Expanded( - child: Container( - height: 40, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: widget.subname != null - ? MainAxisAlignment.spaceBetween - : MainAxisAlignment.center, - children: [ - Text( - widget.name, - style: TextStyle( - color: Theme.of(context) - .primaryTextTheme - .title - .color, - decoration: TextDecoration.none, - fontFamily: 'Avenir Next', - fontSize: 20, - fontWeight: FontWeight.bold), - ), - if (widget.subname != null) - Text( - widget.subname, - style: TextStyle( - color: Theme.of(context) - .primaryTextTheme - .caption - .color, - decoration: TextDecoration.none, - fontFamily: 'Avenir Next', - fontSize: 12), - ) - ], - ), - )) - ], + child: Container( + width: menuWidth, + height: double.infinity, + color: PaletteDark.deepPurpleBlue, + child: SingleChildScrollView( + child: Column( + children: [ + Container( + height: headerHeight, + padding: EdgeInsets.only( + left: 24, + top: fromTopEdge, + right: 24, + bottom: fromBottomEdge), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + _iconFor(type: widget.type), + SizedBox(width: 12), + Expanded( + child: Container( + height: 42, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: widget.subname != null + ? MainAxisAlignment.spaceBetween + : MainAxisAlignment.center, + children: [ + Text( + widget.name, + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold), + ), + if (widget.subname != null) + Text( + widget.subname, + style: TextStyle( + color: PaletteDark.darkCyanBlue, + fontWeight: FontWeight.w500, + fontSize: 12), + ) + ], + ), + )) + ], + ), ), - ); - } + Container( + height: 1, + color: PaletteDark.lightOceanBlue, + ), + ListView.separated( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (_, index) { - index -= 1; - final item = walletMenu.items[index]; - final image = walletMenu.images[index] ?? Offstage(); + final item = walletMenu.items[index]; + final image = walletMenu.images[index] ?? Offstage(); + final isLastTile = index == itemCount - 1; - return GestureDetector( - onTap: () { - Navigator.of(context).pop(); - walletMenu.action(index); - }, - child: index == itemCount - 1 - ? Container( - height: headerHeight, - padding: EdgeInsets.only( - left: 24, - right: 24, - top: fromBottomEdge, - bottom: fromTopEdge), - alignment: Alignment.topLeft, - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24)), - color: Theme.of(context) - .primaryTextTheme - .display1 - .color, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image, - SizedBox(width: 16), - Expanded( - child: Text( - item, - style: TextStyle( - decoration: TextDecoration.none, - color: Theme.of(context) - .primaryTextTheme - .title - .color, - fontFamily: 'Avenir Next', - fontSize: 20, - fontWeight: FontWeight.bold), - )) - ], - ), - ) - : Container( - height: tileHeight, - padding: EdgeInsets.only(left: 24, right: 24), - color: Theme.of(context) - .primaryTextTheme - .display1 - .color, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image, - SizedBox(width: 16), - Expanded( - child: Text( - item, - style: TextStyle( - decoration: TextDecoration.none, - color: Theme.of(context) - .primaryTextTheme - .title - .color, - fontFamily: 'Avenir Next', - fontSize: 20, - fontWeight: FontWeight.bold), - )) - ], - ), + return GestureDetector( + onTap: () { + Navigator.of(context).pop(); + walletMenu.action(index); + }, + child: Container( + height: isLastTile + ? headerHeight + : tileHeight, + padding: isLastTile + ? EdgeInsets.only( + left: 24, + right: 24, + top: fromBottomEdge, + bottom: fromTopEdge) + : EdgeInsets.only(left: 24, right: 24), + alignment: isLastTile ? Alignment.topLeft : null, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 16), + Expanded( + child: Text( + item, + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold), + )) + ], + ), + ) + ); + }, + separatorBuilder: (_, index) => Container( + height: 1, + color: PaletteDark.lightOceanBlue, ), - ); - }, - separatorBuilder: (_, index) => Container( - height: 1, - color: Theme.of(context).dividerColor, - ), - itemCount: itemCount + 1), - ), - ), - )) - ], + itemCount: itemCount) + ], + ), + ), + ), + ) + ) + ], + ) ); } diff --git a/lib/src/screens/exchange/exchange_page.dart b/lib/src/screens/exchange/exchange_page.dart index c5226e8f7..cc47033b4 100644 --- a/lib/src/screens/exchange/exchange_page.dart +++ b/lib/src/screens/exchange/exchange_page.dart @@ -1,66 +1,40 @@ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/generated/i18n.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/stores/exchange_template/exchange_template_store.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'; import 'package:cake_wallet/src/widgets/trail_button.dart'; +import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart'; class ExchangePage extends BasePage { + ExchangePage(this.exchangeViewModel); + + final ExchangeViewModel exchangeViewModel; + @override String get title => S.current.exchange; @override - Color get backgroundLightColor => Palette.darkLavender; + Color get backgroundLightColor => PaletteDark.wildVioletBlue; @override - Color get backgroundDarkColor => PaletteDark.moderateBlue; + Color get backgroundDarkColor => PaletteDark.wildVioletBlue; @override - Widget middle(BuildContext context) { - final exchangeStore = Provider.of(context); - - return PresentProviderPicker(exchangeStore: exchangeStore); - } + Widget middle(BuildContext context) => + PresentProviderPicker(exchangeViewModel: exchangeViewModel); @override - Widget trailing(BuildContext context) { - final exchangeStore = Provider.of(context); - - return TrailButton( - caption: S.of(context).reset, - onPressed: () => exchangeStore.reset() - ); - } + Widget trailing(BuildContext context) => + TrailButton( + caption: S.of(context).reset, + onPressed: () => exchangeViewModel.reset() + ); @override - Widget body(BuildContext context) => ExchangeForm(); -} - -class ExchangeForm extends StatefulWidget { - @override - State createState() => ExchangeFormState(); -} - -class ExchangeFormState extends State { - - @override - Widget build(BuildContext context) { - final exchangeStore = Provider.of(context); - final walletStore = Provider.of(context); - final exchangeTemplateStore = Provider.of(context); - - return BaseExchangeWidget( - exchangeStore: exchangeStore, - walletStore: walletStore, - exchangeTemplateStore: exchangeTemplateStore, - isTemplate: false - ); - } + Widget body(BuildContext context) => + BaseExchangeWidget(exchangeViewModel: exchangeViewModel); } diff --git a/lib/src/screens/exchange/exchange_template_page.dart b/lib/src/screens/exchange/exchange_template_page.dart index db2a6965b..139a1e4cd 100644 --- a/lib/src/screens/exchange/exchange_template_page.dart +++ b/lib/src/screens/exchange/exchange_template_page.dart @@ -1,55 +1,32 @@ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:cake_wallet/palette.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/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'; +import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart'; class ExchangeTemplatePage extends BasePage { + ExchangeTemplatePage(this.exchangeViewModel); + + final ExchangeViewModel exchangeViewModel; + @override String get title => S.current.exchange_new_template; @override - Color get backgroundLightColor => Palette.darkLavender; + Color get backgroundLightColor => PaletteDark.wildVioletBlue; @override - Color get backgroundDarkColor => PaletteDark.moderateBlue; + Color get backgroundDarkColor => PaletteDark.wildVioletBlue; @override - Widget trailing(BuildContext context) { - final exchangeStore = Provider.of(context); - - return PresentProviderPicker(exchangeStore: exchangeStore); - } + Widget trailing(BuildContext context) => + PresentProviderPicker(exchangeViewModel: exchangeViewModel); @override - Widget body(BuildContext context) => ExchangeTemplateForm(); -} - -class ExchangeTemplateForm extends StatefulWidget{ - @override - ExchangeTemplateFormState createState() => ExchangeTemplateFormState(); -} - -class ExchangeTemplateFormState extends State { - - @override - Widget build(BuildContext context) { - final exchangeStore = Provider.of(context); - final walletStore = Provider.of(context); - final exchangeTemplateStore = Provider.of(context); - - return BaseExchangeWidget( - exchangeStore: exchangeStore, - walletStore: walletStore, - exchangeTemplateStore: exchangeTemplateStore, - isTemplate: true - ); - } + Widget body(BuildContext context) => + BaseExchangeWidget(exchangeViewModel: exchangeViewModel, isTemplate: true); } \ 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 index 5500ffda7..57a24a162 100644 --- a/lib/src/screens/exchange/widgets/base_exchange_widget.dart +++ b/lib/src/screens/exchange/widgets/base_exchange_widget.dart @@ -1,5 +1,7 @@ import 'dart:ui'; +import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/src/domain/exchange/exchange_template.dart'; +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/template_tile.dart'; import 'package:dotted_border/dotted_border.dart'; import 'package:flutter/cupertino.dart'; @@ -12,49 +14,37 @@ 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'; +import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart'; class BaseExchangeWidget extends StatefulWidget { BaseExchangeWidget({ - @ required this.exchangeStore, - @ required this.walletStore, - @ required this.exchangeTemplateStore, - @ required this.isTemplate, + @ required this.exchangeViewModel, + this.isTemplate = false, }); - final ExchangeStore exchangeStore; - final WalletStore walletStore; - final ExchangeTemplateStore exchangeTemplateStore; + final ExchangeViewModel exchangeViewModel; final bool isTemplate; @override BaseExchangeWidgetState createState() => BaseExchangeWidgetState( - exchangeStore: exchangeStore, - walletStore: walletStore, - exchangeTemplateStore: exchangeTemplateStore, + exchangeViewModel: exchangeViewModel, isTemplate: isTemplate ); } class BaseExchangeWidgetState extends State { BaseExchangeWidgetState({ - @ required this.exchangeStore, - @ required this.walletStore, - @ required this.exchangeTemplateStore, + @ required this.exchangeViewModel, @ required this.isTemplate, }); - final ExchangeStore exchangeStore; - final WalletStore walletStore; - final ExchangeTemplateStore exchangeTemplateStore; + final ExchangeViewModel exchangeViewModel; final bool isTemplate; final depositKey = GlobalKey(); @@ -64,31 +54,31 @@ class BaseExchangeWidgetState extends State { @override Widget build(BuildContext context) { - final Image arrowBottomPurple = Image.asset( + final arrowBottomPurple = Image.asset( 'assets/images/arrow_bottom_purple_icon.png', - color: Theme.of(context).primaryTextTheme.title.color, + color: Colors.white, height: 8, ); - final Image arrowBottomCakeGreen = Image.asset( + final arrowBottomCakeGreen = Image.asset( 'assets/images/arrow_bottom_cake_green.png', - color: Theme.of(context).primaryTextTheme.title.color, + color: Colors.white, height: 8, ); final depositWalletName = - exchangeStore.depositCurrency == CryptoCurrency.xmr - ? walletStore.name + exchangeViewModel.depositCurrency == CryptoCurrency.xmr + ? exchangeViewModel.wallet.name : null; final receiveWalletName = - exchangeStore.receiveCurrency == CryptoCurrency.xmr - ? walletStore.name + exchangeViewModel.receiveCurrency == CryptoCurrency.xmr + ? exchangeViewModel.wallet.name : null; WidgetsBinding.instance.addPostFrameCallback( - (_) => _setReactions(context, exchangeStore, walletStore)); + (_) => _setReactions(context, exchangeViewModel)); return Container( - color: Theme.of(context).backgroundColor, + color: PaletteDark.backgroundColor, child: Form( key: _formKey, child: ScrollableWithBottomSection( @@ -96,73 +86,60 @@ class BaseExchangeWidgetState extends State { content: Column( children: [ TopPanel( - color: Theme.of(context).accentTextTheme.title.backgroundColor, - edgeInsets: EdgeInsets.only(bottom: 24), + color: PaletteDark.darkNightBlue, + edgeInsets: EdgeInsets.only(bottom: 32), widget: Column( children: [ TopPanel( - color: Theme.of(context).accentTextTheme.title.color, + edgeInsets: EdgeInsets.fromLTRB(24, 29, 24, 32), + color: PaletteDark.wildVioletBlue, widget: Observer( builder: (_) => ExchangeCard( key: depositKey, title: S.of(context).you_will_send, - initialCurrency: exchangeStore.depositCurrency, + initialCurrency: exchangeViewModel.depositCurrency, initialWalletName: depositWalletName, initialAddress: - exchangeStore.depositCurrency == walletStore.type - ? walletStore.address - : exchangeStore.depositAddress, + exchangeViewModel.depositCurrency == exchangeViewModel.wallet.currency + ? exchangeViewModel.wallet.address + : exchangeViewModel.depositAddress, initialIsAmountEditable: true, - initialIsAddressEditable: exchangeStore.isDepositAddressEnabled, + initialIsAddressEditable: exchangeViewModel.isDepositAddressEnabled, isAmountEstimated: false, currencies: CryptoCurrency.all, onCurrencySelected: (currency) => - exchangeStore.changeDepositCurrency(currency: currency), + exchangeViewModel.changeDepositCurrency(currency: currency), imageArrow: arrowBottomPurple, - currencyButtonColor: Theme.of(context).accentTextTheme.title.color, - addressButtonsColor: Theme.of(context).accentTextTheme.title.backgroundColor, - currencyValueValidator: (value) { - exchangeStore.validateCryptoCurrency(value); - return exchangeStore.errorMessage; - }, - addressTextFieldValidator: (value) { - exchangeStore.validateAddress(value, - cryptoCurrency: exchangeStore.depositCurrency); - return exchangeStore.errorMessage; - }, + currencyButtonColor: PaletteDark.wildVioletBlue, + addressButtonsColor: PaletteDark.moderateBlue, + currencyValueValidator: exchangeViewModel.amountValidator, + addressTextFieldValidator: exchangeViewModel.addressValidator, ), ) ), Padding( - padding: EdgeInsets.only(top: 32, left: 24, right: 24), + padding: EdgeInsets.only(top: 29, left: 24, right: 24), child: Observer( builder: (_) => ExchangeCard( key: receiveKey, title: S.of(context).you_will_get, - initialCurrency: exchangeStore.receiveCurrency, + initialCurrency: exchangeViewModel.receiveCurrency, initialWalletName: receiveWalletName, initialAddress: - exchangeStore.receiveCurrency == walletStore.type - ? walletStore.address - : exchangeStore.receiveAddress, + exchangeViewModel.receiveCurrency == exchangeViewModel.wallet.currency + ? exchangeViewModel.wallet.address + : exchangeViewModel.receiveAddress, initialIsAmountEditable: false, - initialIsAddressEditable: exchangeStore.isReceiveAddressEnabled, + initialIsAddressEditable: exchangeViewModel.isReceiveAddressEnabled, isAmountEstimated: true, currencies: CryptoCurrency.all, - onCurrencySelected: (currency) => exchangeStore + onCurrencySelected: (currency) => exchangeViewModel .changeReceiveCurrency(currency: currency), imageArrow: arrowBottomCakeGreen, - currencyButtonColor: Theme.of(context).accentTextTheme.title.backgroundColor, - addressButtonsColor: Theme.of(context).accentTextTheme.title.color, - currencyValueValidator: (value) { - exchangeStore.validateCryptoCurrency(value); - return exchangeStore.errorMessage; - }, - addressTextFieldValidator: (value) { - exchangeStore.validateAddress(value, - cryptoCurrency: exchangeStore.receiveCurrency); - return exchangeStore.errorMessage; - }, + currencyButtonColor: PaletteDark.darkNightBlue, + addressButtonsColor: PaletteDark.moderateBlue, + currencyValueValidator: exchangeViewModel.amountValidator, + addressTextFieldValidator: exchangeViewModel.addressValidator, )), ) ], @@ -172,7 +149,7 @@ class BaseExchangeWidgetState extends State { ? Offstage() : Padding( padding: EdgeInsets.only( - top: 32, + top: 30, left: 24, bottom: 24 ), @@ -184,7 +161,7 @@ class BaseExchangeWidgetState extends State { style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, - color: Theme.of(context).primaryTextTheme.caption.color + color: PaletteDark.darkCyanBlue ), ) ], @@ -196,66 +173,90 @@ class BaseExchangeWidgetState extends State { 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: Theme.of(context).accentTextTheme.title.backgroundColor, - 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: Theme.of(context).primaryTextTheme.caption.color - ), - ), - ) + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + GestureDetector( + onTap: () => Navigator.of(context) + .pushNamed(Routes.exchangeTemplate), + child: Container( + padding: EdgeInsets.only(left: 1, right: 10), + child: DottedBorder( + borderType: BorderType.RRect, + dashPattern: [6, 4], + color: PaletteDark.darkCyanBlue, + strokeWidth: 2, + radius: Radius.circular(20), + child: Container( + height: 34, + 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.darkCyanBlue ), ), - ); - } + ) + ), + ), + ), + Observer( + builder: (_) { + final templates = exchangeViewModel.templates; + final itemCount = exchangeViewModel.templates.length; - index -= 1; + return ListView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: itemCount, + itemBuilder: (context, index) { + final template = templates[index]; - final template = exchangeTemplateStore.templates[index]; - - return TemplateTile( - amount: template.amount, - from: template.depositCurrency, - to: template.receiveCurrency, - onTap: () { - applyTemplate(exchangeStore, template); + return TemplateTile( + key: UniqueKey(), + amount: template.amount, + from: template.depositCurrency, + to: template.receiveCurrency, + onTap: () { + applyTemplate(exchangeViewModel, template); + }, + onRemove: () { + showDialog( + context: context, + builder: (dialogContext) { + return AlertWithTwoActions( + alertTitle: S.of(context).template, + alertContent: S.of(context).confirm_delete_template, + leftButtonText: S.of(context).delete, + rightButtonText: S.of(context).cancel, + actionLeftButton: () { + Navigator.of(dialogContext).pop(); + exchangeViewModel.exchangeTemplateStore.remove(template: template); + exchangeViewModel.exchangeTemplateStore.update(); + }, + actionRightButton: () => Navigator.of(dialogContext).pop() + ); + } + ); + }, + ); } ); } - ); - } - ), + ), + ], + ) + ) ) ], ), @@ -265,14 +266,15 @@ class BaseExchangeWidgetState extends State { padding: EdgeInsets.only(bottom: 15), child: Observer(builder: (_) { final description = - exchangeStore.provider is XMRTOExchangeProvider + exchangeViewModel.provider is XMRTOExchangeProvider ? S.of(context).amount_is_guaranteed : S.of(context).amount_is_estimate; return Center( child: Text( description, style: TextStyle( - color: Theme.of(context).primaryTextTheme.caption.color, + color: PaletteDark.darkCyanBlue, + fontWeight: FontWeight.w500, fontSize: 12 ), ), @@ -283,15 +285,15 @@ class BaseExchangeWidgetState extends State { ? 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 + exchangeViewModel.exchangeTemplateStore.addTemplate( + amount: exchangeViewModel.depositAmount, + depositCurrency: exchangeViewModel.depositCurrency.toString(), + receiveCurrency: exchangeViewModel.receiveCurrency.toString(), + provider: exchangeViewModel.provider.toString(), + depositAddress: exchangeViewModel.depositAddress, + receiveAddress: exchangeViewModel.receiveAddress ); - exchangeTemplateStore.update(); + exchangeViewModel.exchangeTemplateStore.update(); Navigator.of(context).pop(); } }, @@ -304,41 +306,47 @@ class BaseExchangeWidgetState extends State { text: S.of(context).exchange, onPressed: () { if (_formKey.currentState.validate()) { - exchangeStore.createTrade(); + exchangeViewModel.createTrade(); } }, color: Colors.blue, textColor: Colors.white, - isLoading: exchangeStore.tradeState is TradeIsCreating, + isLoading: exchangeViewModel.tradeState is TradeIsCreating, )), ]), )), ); } - void applyTemplate(ExchangeStore store, ExchangeTemplate template) { - store.changeDepositCurrency(currency: CryptoCurrency.fromString(template.depositCurrency)); - store.changeReceiveCurrency(currency: CryptoCurrency.fromString(template.receiveCurrency)); + void applyTemplate(ExchangeViewModel exchangeViewModel, + ExchangeTemplate template) { + exchangeViewModel.changeDepositCurrency( + currency: CryptoCurrency.fromString(template.depositCurrency)); + exchangeViewModel.changeReceiveCurrency( + currency: CryptoCurrency.fromString(template.receiveCurrency)); switch (template.provider) { case 'XMR.TO': - store.changeProvider(provider: store.providerList[0]); + exchangeViewModel.changeProvider( + provider: exchangeViewModel.providerList[0]); break; case 'ChangeNOW': - store.changeProvider(provider: store.providerList[1]); + exchangeViewModel.changeProvider( + provider: exchangeViewModel.providerList[1]); break; case 'MorphToken': - store.changeProvider(provider: store.providerList[2]); + exchangeViewModel.changeProvider( + provider: exchangeViewModel.providerList[2]); break; } - store.changeDepositAmount(amount: template.amount); - store.depositAddress = template.depositAddress; - store.receiveAddress = template.receiveAddress; + exchangeViewModel.changeDepositAmount(amount: template.amount); + exchangeViewModel.depositAddress = template.depositAddress; + exchangeViewModel.receiveAddress = template.receiveAddress; } void _setReactions( - BuildContext context, ExchangeStore store, WalletStore walletStore) { + BuildContext context, ExchangeViewModel exchangeViewModel) { if (_isReactionsSet) { return; } @@ -347,7 +355,7 @@ class BaseExchangeWidgetState extends State { final depositAmountController = depositKey.currentState.amountController; final receiveAddressController = receiveKey.currentState.addressController; final receiveAmountController = receiveKey.currentState.amountController; - final limitsState = store.limitsState; + final limitsState = exchangeViewModel.limitsState; if (limitsState is LimitsLoadedSuccessfully) { final min = limitsState.limits.min != null @@ -360,63 +368,62 @@ class BaseExchangeWidgetState extends State { key.currentState.changeLimits(min: min, max: max); } - _onCurrencyChange(store.receiveCurrency, walletStore, receiveKey); - _onCurrencyChange(store.depositCurrency, walletStore, depositKey); + _onCurrencyChange(exchangeViewModel.receiveCurrency, exchangeViewModel, receiveKey); + _onCurrencyChange(exchangeViewModel.depositCurrency, exchangeViewModel, depositKey); reaction( - (_) => walletStore.name, + (_) => exchangeViewModel.wallet.name, (String _) => _onWalletNameChange( - walletStore, store.receiveCurrency, receiveKey)); + exchangeViewModel, exchangeViewModel.receiveCurrency, receiveKey)); reaction( - (_) => walletStore.name, + (_) => exchangeViewModel.wallet.name, (String _) => _onWalletNameChange( - walletStore, store.depositCurrency, depositKey)); + exchangeViewModel, exchangeViewModel.depositCurrency, depositKey)); reaction( - (_) => store.receiveCurrency, + (_) => exchangeViewModel.receiveCurrency, (CryptoCurrency currency) => - _onCurrencyChange(currency, walletStore, receiveKey)); + _onCurrencyChange(currency, exchangeViewModel, receiveKey)); reaction( - (_) => store.depositCurrency, + (_) => exchangeViewModel.depositCurrency, (CryptoCurrency currency) => - _onCurrencyChange(currency, walletStore, depositKey)); + _onCurrencyChange(currency, exchangeViewModel, depositKey)); - reaction((_) => store.depositAmount, (String amount) { + reaction((_) => exchangeViewModel.depositAmount, (String amount) { if (depositKey.currentState.amountController.text != amount) { depositKey.currentState.amountController.text = amount; } }); - reaction((_) => store.depositAddress, (String address) { + reaction((_) => exchangeViewModel.depositAddress, (String address) { if (depositKey.currentState.addressController.text != address) { depositKey.currentState.addressController.text = address; } }); - reaction((_) => store.isDepositAddressEnabled, (bool isEnabled) { + reaction((_) => exchangeViewModel.isDepositAddressEnabled, (bool isEnabled) { depositKey.currentState.isAddressEditable(isEditable: isEnabled); }); - reaction((_) => store.receiveAmount, (String amount) { - if (receiveKey.currentState.amountController.text != - store.receiveAmount) { + reaction((_) => exchangeViewModel.receiveAmount, (String amount) { + if (receiveKey.currentState.amountController.text != amount) { receiveKey.currentState.amountController.text = amount; } }); - reaction((_) => store.receiveAddress, (String address) { + reaction((_) => exchangeViewModel.receiveAddress, (String address) { if (receiveKey.currentState.addressController.text != address) { receiveKey.currentState.addressController.text = address; } }); - reaction((_) => store.isReceiveAddressEnabled, (bool isEnabled) { + reaction((_) => exchangeViewModel.isReceiveAddressEnabled, (bool isEnabled) { receiveKey.currentState.isAddressEditable(isEditable: isEnabled); }); - reaction((_) => store.tradeState, (ExchangeTradeState state) { + reaction((_) => exchangeViewModel.tradeState, (ExchangeTradeState state) { if (state is TradeIsCreatedFailure) { WidgetsBinding.instance.addPostFrameCallback((_) { showDialog( @@ -437,7 +444,7 @@ class BaseExchangeWidgetState extends State { } }); - reaction((_) => store.limitsState, (LimitsState state) { + reaction((_) => exchangeViewModel.limitsState, (LimitsState state) { String min; String max; @@ -461,29 +468,29 @@ class BaseExchangeWidgetState extends State { }); depositAddressController.addListener( - () => store.depositAddress = depositAddressController.text); + () => exchangeViewModel.depositAddress = depositAddressController.text); depositAmountController.addListener(() { - if (depositAmountController.text != store.depositAmount) { - store.changeDepositAmount(amount: depositAmountController.text); + if (depositAmountController.text != exchangeViewModel.depositAmount) { + exchangeViewModel.changeDepositAmount(amount: depositAmountController.text); } }); receiveAddressController.addListener( - () => store.receiveAddress = receiveAddressController.text); + () => exchangeViewModel.receiveAddress = receiveAddressController.text); receiveAmountController.addListener(() { - if (receiveAmountController.text != store.receiveAmount) { - store.changeReceiveAmount(amount: receiveAmountController.text); + if (receiveAmountController.text != exchangeViewModel.receiveAmount) { + exchangeViewModel.changeReceiveAmount(amount: receiveAmountController.text); } }); - reaction((_) => walletStore.address, (String address) { - if (store.depositCurrency == CryptoCurrency.xmr) { + reaction((_) => exchangeViewModel.wallet.address, (String address) { + if (exchangeViewModel.depositCurrency == CryptoCurrency.xmr) { depositKey.currentState.changeAddress(address: address); } - if (store.receiveCurrency == CryptoCurrency.xmr) { + if (exchangeViewModel.receiveCurrency == CryptoCurrency.xmr) { receiveKey.currentState.changeAddress(address: address); } }); @@ -491,28 +498,33 @@ class BaseExchangeWidgetState extends State { _isReactionsSet = true; } - void _onCurrencyChange(CryptoCurrency currency, WalletStore walletStore, + void _onCurrencyChange(CryptoCurrency currency, + ExchangeViewModel exchangeViewModel, GlobalKey key) { - final isCurrentTypeWallet = currency == walletStore.type; + final isCurrentTypeWallet = currency == exchangeViewModel.wallet.currency; key.currentState.changeSelectedCurrency(currency); key.currentState - .changeWalletName(isCurrentTypeWallet ? walletStore.name : null); + .changeWalletName(isCurrentTypeWallet + ? exchangeViewModel.wallet.name : null); key.currentState - .changeAddress(address: isCurrentTypeWallet ? walletStore.address : ''); + .changeAddress(address: isCurrentTypeWallet + ? exchangeViewModel.wallet.address : ''); key.currentState.changeAmount(amount: ''); } - void _onWalletNameChange(WalletStore walletStore, CryptoCurrency currency, + void _onWalletNameChange(ExchangeViewModel exchangeViewModel, + CryptoCurrency currency, GlobalKey key) { - final isCurrentTypeWallet = currency == walletStore.type; + final isCurrentTypeWallet = currency == exchangeViewModel.wallet.currency; if (isCurrentTypeWallet) { - key.currentState.changeWalletName(walletStore.name); - key.currentState.addressController.text = walletStore.address; - } else if (key.currentState.addressController.text == walletStore.address) { + key.currentState.changeWalletName(exchangeViewModel.wallet.name); + key.currentState.addressController.text = exchangeViewModel.wallet.address; + } else if (key.currentState.addressController.text == + exchangeViewModel.wallet.address) { key.currentState.changeWalletName(null); key.currentState.addressController.text = null; } diff --git a/lib/src/screens/exchange/widgets/exchange_card.dart b/lib/src/screens/exchange/widgets/exchange_card.dart index 308784f3c..548383176 100644 --- a/lib/src/screens/exchange/widgets/exchange_card.dart +++ b/lib/src/screens/exchange/widgets/exchange_card.dart @@ -5,6 +5,7 @@ import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; import 'package:cake_wallet/src/widgets/address_text_field.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/palette.dart'; class ExchangeCard extends StatefulWidget { ExchangeCard( @@ -57,6 +58,10 @@ class ExchangeCardState extends State { bool _isAddressEditable; bool _isAmountEstimated; + final copyImage = Image.asset('assets/images/copy_content.png', + height: 16, width: 16, + color: Colors.white); + @override void initState() { _title = widget.title; @@ -114,6 +119,7 @@ class ExchangeCardState extends State { width: double.infinity, color: Colors.transparent, child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, @@ -123,13 +129,13 @@ class ExchangeCardState extends State { style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, - color: Theme.of(context).primaryTextTheme.caption.color + color: PaletteDark.lightBlueGrey ), ) ], ), Padding( - padding: EdgeInsets.only(top: 10), + padding: EdgeInsets.only(top: 20), child: Stack( children: [ BaseTextFormField( @@ -143,7 +149,20 @@ class ExchangeCardState extends State { RegExp('[\\-|\\ |\\,]')) ], hintText: '0.0000', - validator: widget.currencyValueValidator + borderColor: PaletteDark.blueGrey, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.white + ), + placeholderTextStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: PaletteDark.lightBlueGrey + ), + validator: _isAmountEditable + ? widget.currencyValueValidator + : null ), Positioned( top: 8, @@ -163,7 +182,7 @@ class ExchangeCardState extends State { style: TextStyle( fontWeight: FontWeight.w600, fontSize: 16, - color: Theme.of(context).primaryTextTheme.title.color)), + color: Colors.white)), Padding( padding: EdgeInsets.only(left: 5), child: widget.imageArrow, @@ -181,45 +200,96 @@ class ExchangeCardState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ _min != null - ? Text( + ? Text( S.of(context).min_value( _min, _selectedCurrency.toString()), style: TextStyle( fontSize: 10, height: 1.2, - color: Theme.of(context).primaryTextTheme.caption.color), + color: PaletteDark.lightBlueGrey), ) - : Offstage(), + : Offstage(), _min != null ? SizedBox(width: 10) : Offstage(), _max != null - ? Text( + ? Text( S.of(context).max_value( _max, _selectedCurrency.toString()), style: TextStyle( fontSize: 10, height: 1.2, - color: Theme.of(context).primaryTextTheme.caption.color)) - : Offstage(), + color: PaletteDark.lightBlueGrey)) + : Offstage(), ]), ), Padding( - padding: EdgeInsets.only(top: 10), - child: AddressTextField( + padding: EdgeInsets.only(top: 20), + child: Text( + _isAddressEditable + ? S.of(context).widgets_address + : S.of(context).refund_address, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: PaletteDark.lightBlueGrey + ), + ) + ), + _isAddressEditable + ? AddressTextField( controller: addressController, - isActive: _isAddressEditable, - options: _isAddressEditable - ? _walletName != null - ? [] - : [ + options: [ + AddressTextFieldOption.paste, AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook, - ] - : [], + ], + placeholder: '', isBorderExist: false, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.white), buttonColor: widget.addressButtonsColor, validator: widget.addressTextFieldValidator, - ), ) + : Padding( + padding: EdgeInsets.only(top: 10), + child: Builder( + builder: (context) => GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData( + text: addressController.text)); + Scaffold.of(context).showSnackBar(SnackBar( + content: Text( + S.of(context).copied_to_clipboard, + style: TextStyle(color: Colors.white), + ), + backgroundColor: Colors.green, + duration: Duration(milliseconds: 500), + )); + }, + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Text( + addressController.text, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.white), + ), + ), + Padding( + padding: EdgeInsets.only(left: 16), + child: copyImage, + ) + ], + ), + ) + ), + ), ]), ); } diff --git a/lib/src/screens/exchange/widgets/present_provider_picker.dart b/lib/src/screens/exchange/widgets/present_provider_picker.dart index 1d3a7953d..79fbb80cd 100644 --- a/lib/src/screens/exchange/widgets/present_provider_picker.dart +++ b/lib/src/screens/exchange/widgets/present_provider_picker.dart @@ -1,21 +1,22 @@ 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:flutter_mobx/flutter_mobx.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/picker.dart'; +import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart'; +import 'package:cake_wallet/palette.dart'; class PresentProviderPicker extends StatelessWidget { - PresentProviderPicker({@required this.exchangeStore}); + PresentProviderPicker({@required this.exchangeViewModel}); - final ExchangeStore exchangeStore; + final ExchangeViewModel exchangeViewModel; @override Widget build(BuildContext context) { - final Image arrowBottom = + final arrowBottom = Image.asset('assets/images/arrow_bottom_purple_icon.png', - color: Theme.of(context).primaryTextTheme.title.color, + color: Colors.white, height: 6); return FlatButton( @@ -33,19 +34,19 @@ class PresentProviderPicker extends StatelessWidget { Text(S.of(context).exchange, style: TextStyle( fontSize: 16.0, - fontWeight: FontWeight.w400, - color: Theme.of(context).primaryTextTheme.title.color)), + fontWeight: FontWeight.w600, + color: Colors.white)), Observer( - builder: (_) => Text('${exchangeStore.provider.title}', + builder: (_) => Text('${exchangeViewModel.provider.title}', style: TextStyle( fontSize: 10.0, - fontWeight: FontWeight.w400, - color: Theme.of(context).primaryTextTheme.caption.color))) + fontWeight: FontWeight.w500, + color: PaletteDark.lightBlueGrey))) ], ), SizedBox(width: 5), Padding( - padding: EdgeInsets.only(top: 8), + padding: EdgeInsets.only(top: 12), child: arrowBottom, ) ], @@ -54,11 +55,11 @@ class PresentProviderPicker extends StatelessWidget { } void _presentProviderPicker(BuildContext context) { - final items = exchangeStore.providersForCurrentPair(); - final selectedItem = items.indexOf(exchangeStore.provider); - final images = List(); + final items = exchangeViewModel.providersForCurrentPair(); + final selectedItem = items.indexOf(exchangeViewModel.provider); + final images = []; - for (ExchangeProvider provider in items) { + for (var provider in items) { switch (provider.description) { case ExchangeProviderDescription.xmrto: images.add(Image.asset('assets/images/xmr_btc.png')); @@ -79,7 +80,7 @@ class PresentProviderPicker extends StatelessWidget { selectedAtIndex: selectedItem, title: S.of(context).change_exchange_provider, onItemSelected: (ExchangeProvider provider) => - exchangeStore.changeProvider(provider: provider)), + exchangeViewModel.changeProvider(provider: provider)), context: context); } } \ No newline at end of file diff --git a/lib/src/screens/receive/receive_page.dart b/lib/src/screens/receive/receive_page.dart index 19cc6fecc..47608b59c 100644 --- a/lib/src/screens/receive/receive_page.dart +++ b/lib/src/screens/receive/receive_page.dart @@ -125,7 +125,7 @@ class ReceivePage extends BasePage { .headline5 .color .withOpacity(0.4), - validator: AmountValidator(), + validator: AmountValidator(isAutovalidate: true), autovalidate: true, placeholderTextStyle: TextStyle( color: Theme.of(context) diff --git a/lib/src/widgets/base_text_form_field.dart b/lib/src/widgets/base_text_form_field.dart index e8b77c22c..b3931a92d 100644 --- a/lib/src/widgets/base_text_form_field.dart +++ b/lib/src/widgets/base_text_form_field.dart @@ -72,6 +72,10 @@ class BaseTextFormField extends StatelessWidget { borderSide: BorderSide( color: borderColor ?? Theme.of(context).dividerColor, width: 1.0)), + disabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: borderColor ?? Theme.of(context).dividerColor, + width: 1.0)), enabledBorder: UnderlineInputBorder( borderSide: BorderSide( color: borderColor ?? Theme.of(context).dividerColor, diff --git a/lib/src/widgets/nav_bar.dart b/lib/src/widgets/nav_bar.dart index b5274d9b4..0d51c8e72 100644 --- a/lib/src/widgets/nav_bar.dart +++ b/lib/src/widgets/nav_bar.dart @@ -71,6 +71,8 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget { EdgeInsetsDirectional.only(bottom: _paddingBottom, top: paddingTop), child: CupertinoNavigationBar( leading: leading, + automaticallyImplyLeading: false, + automaticallyImplyMiddle: false, middle: middle, trailing: trailing, backgroundColor: backgroundColor, diff --git a/lib/src/widgets/trail_button.dart b/lib/src/widgets/trail_button.dart index d9752e410..65cfc14dc 100644 --- a/lib/src/widgets/trail_button.dart +++ b/lib/src/widgets/trail_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:cake_wallet/palette.dart'; class TrailButton extends StatelessWidget { TrailButton({ @@ -21,7 +22,7 @@ class TrailButton extends StatelessWidget { child: Text( caption, style: TextStyle( - color: Theme.of(context).primaryTextTheme.caption.color, + color: PaletteDark.lightBlueGrey, fontWeight: FontWeight.w500, fontSize: 14), ), diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart new file mode 100644 index 000000000..0383338e8 --- /dev/null +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -0,0 +1,306 @@ +import 'package:cake_wallet/core/address_validator.dart'; +import 'package:cake_wallet/core/amount_validator.dart'; +import 'package:cake_wallet/core/template_validator.dart'; +import 'package:cake_wallet/core/validator.dart'; +import 'package:cake_wallet/core/wallet_base.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/limits.dart'; +import 'package:cake_wallet/src/domain/exchange/trade.dart'; +import 'package:cake_wallet/src/stores/exchange/limits_state.dart'; +import 'package:intl/intl.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:hive/hive.dart'; +import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart'; +import 'package:cake_wallet/src/domain/exchange/changenow/changenow_exchange_provider.dart'; +import 'package:cake_wallet/src/domain/exchange/changenow/changenow_request.dart'; +import 'package:cake_wallet/src/domain/exchange/trade_request.dart'; +import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart'; +import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_trade_request.dart'; +import 'package:cake_wallet/src/domain/exchange/morphtoken/morphtoken_exchange_provider.dart'; +import 'package:cake_wallet/src/domain/exchange/morphtoken/morphtoken_request.dart'; +import 'package:cake_wallet/store/templates/exchange_template_store.dart'; +import 'package:cake_wallet/src/domain/exchange/exchange_template.dart'; + +part 'exchange_view_model.g.dart'; + +class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel; + +abstract class ExchangeViewModelBase with Store { + ExchangeViewModelBase({this.wallet, this.trades, this.exchangeTemplateStore}) { + providerList = [ + XMRTOExchangeProvider(), + ChangeNowExchangeProvider(), + MorphTokenExchangeProvider(trades: trades) + ]; + + provider = providerList[ 0 ]; + + depositCurrency = CryptoCurrency.xmr; + receiveCurrency = CryptoCurrency.btc; + isDepositAddressEnabled = !(depositCurrency == wallet.currency); + isReceiveAddressEnabled = !(receiveCurrency == wallet.currency); + depositAmount = ''; + receiveAmount = ''; + depositAddress = ''; + receiveAddress = ''; + limitsState = LimitsInitialState(); + tradeState = ExchangeTradeStateInitial(); + _cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12; + loadLimits(); + } + + final WalletBase wallet; + final Box trades; + final ExchangeTemplateStore exchangeTemplateStore; + + @observable + ExchangeProvider provider; + + @observable + List providerList; + + @observable + CryptoCurrency depositCurrency; + + @observable + CryptoCurrency receiveCurrency; + + @observable + LimitsState limitsState; + + @observable + ExchangeTradeState tradeState; + + @observable + String depositAmount; + + @observable + String receiveAmount; + + @observable + String depositAddress; + + @observable + String receiveAddress; + + @observable + bool isDepositAddressEnabled; + + @observable + bool isReceiveAddressEnabled; + + @observable + bool isValid; + + @observable + String errorMessage; + + Limits limits; + + NumberFormat _cryptoNumberFormat; + + Validator get amountValidator => AmountValidator(type: wallet.type); + + Validator get addressValidator => AddressValidator(type: wallet.currency); + + Validator get templateValidator => TemplateValidator(); + + @computed + ObservableList get templates => + exchangeTemplateStore.templates; + + @action + void changeProvider({ExchangeProvider provider}) { + this.provider = provider; + depositAmount = ''; + receiveAmount = ''; + loadLimits(); + } + + @action + void changeDepositCurrency({CryptoCurrency currency}) { + depositCurrency = currency; + _onPairChange(); + isDepositAddressEnabled = !(depositCurrency == wallet.currency); + isReceiveAddressEnabled = !(receiveCurrency == wallet.currency); + } + + @action + void changeReceiveCurrency({CryptoCurrency currency}) { + receiveCurrency = currency; + _onPairChange(); + isDepositAddressEnabled = !(depositCurrency == wallet.currency); + isReceiveAddressEnabled = !(receiveCurrency == wallet.currency); + } + + @action + void changeReceiveAmount({String amount}) { + receiveAmount = amount; + + if (amount == null || amount.isEmpty) { + depositAmount = ''; + receiveAmount = ''; + return; + } + + final _amount = double.parse(amount) ?? 0; + + provider + .calculateAmount( + from: depositCurrency, to: receiveCurrency, amount: _amount) + .then((amount) => _cryptoNumberFormat.format(amount).toString().replaceAll(RegExp("\\,"), "")) + .then((amount) => depositAmount = amount); + } + + @action + void changeDepositAmount({String amount}) { + depositAmount = amount; + + if (amount == null || amount.isEmpty) { + depositAmount = ''; + receiveAmount = ''; + return; + } + + final _amount = double.parse(amount); + provider + .calculateAmount( + from: depositCurrency, to: receiveCurrency, amount: _amount) + .then((amount) => _cryptoNumberFormat.format(amount).toString().replaceAll(RegExp("\\,"), "")) + .then((amount) => receiveAmount = amount); + } + + @action + Future loadLimits() async { + limitsState = LimitsIsLoading(); + + try { + limits = await provider.fetchLimits( + from: depositCurrency, to: receiveCurrency); + limitsState = LimitsLoadedSuccessfully(limits: limits); + } catch (e) { + limitsState = LimitsLoadedFailure(error: e.toString()); + } + } + + @action + Future createTrade() async { + TradeRequest request; + String amount; + CryptoCurrency currency; + + if (provider is XMRTOExchangeProvider) { + request = XMRTOTradeRequest( + from: depositCurrency, + to: receiveCurrency, + amount: depositAmount, + address: receiveAddress, + refundAddress: depositAddress); + amount = depositAmount; + currency = depositCurrency; + } + + if (provider is ChangeNowExchangeProvider) { + request = ChangeNowRequest( + from: depositCurrency, + to: receiveCurrency, + amount: depositAmount, + refundAddress: depositAddress, + address: receiveAddress); + amount = depositAmount; + currency = depositCurrency; + } + + if (provider is MorphTokenExchangeProvider) { + request = MorphTokenRequest( + from: depositCurrency, + to: receiveCurrency, + amount: depositAmount, + refundAddress: depositAddress, + address: receiveAddress); + amount = depositAmount; + currency = depositCurrency; + } + + if (limitsState is LimitsLoadedSuccessfully && amount != null) { + if (double.parse(amount) < limits.min) { + tradeState = TradeIsCreatedFailure(error: S.current.error_text_minimal_limit('${provider.description}', + '${limits.min}', currency.toString())); + } else if (limits.max != null && double.parse(amount) > limits.max) { + tradeState = TradeIsCreatedFailure(error: S.current.error_text_maximum_limit('${provider.description}', + '${limits.max}', currency.toString())); + } else { + try { + tradeState = TradeIsCreating(); + final trade = await provider.createTrade(request: request); + trade.walletId = wallet.id; + await trades.add(trade); + tradeState = TradeIsCreatedSuccessfully(trade: trade); + } catch (e) { + tradeState = TradeIsCreatedFailure(error: e.toString()); + } + } + } else { + tradeState = TradeIsCreatedFailure(error: S.current.error_text_limits_loading_failed("${provider.description}")); + } + + } + + @action + void reset() { + depositAmount = ''; + receiveAmount = ''; + depositCurrency = CryptoCurrency.xmr; + receiveCurrency = CryptoCurrency.btc; + depositAddress = depositCurrency == wallet.currency ? wallet.address : ''; + receiveAddress = receiveCurrency == wallet.currency ? wallet.address : ''; + isDepositAddressEnabled = !(depositCurrency == wallet.currency); + isReceiveAddressEnabled = !(receiveCurrency == wallet.currency); + _onPairChange(); + } + + List providersForCurrentPair() { + return _providersForPair(from: depositCurrency, to: receiveCurrency); + } + + List _providersForPair( + {CryptoCurrency from, CryptoCurrency to}) { + final providers = providerList + .where((provider) => provider.pairList + .where((pair) => + pair.from == depositCurrency && pair.to == receiveCurrency) + .isNotEmpty) + .toList(); + + return providers; + } + + void _onPairChange() { + final isPairExist = provider.pairList + .where((pair) => + pair.from == depositCurrency && pair.to == receiveCurrency) + .isNotEmpty; + + if (!isPairExist) { + final provider = + _providerForPair(from: depositCurrency, to: receiveCurrency); + + if (provider != null) { + changeProvider(provider: provider); + } + } + + depositAmount = ''; + receiveAmount = ''; + + loadLimits(); + } + + ExchangeProvider _providerForPair({CryptoCurrency from, CryptoCurrency to}) { + final providers = _providersForPair(from: from, to: to); + return providers.isNotEmpty ? providers[0] : null; + } + +} \ No newline at end of file diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 20c7988bd..0724a9577 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -61,6 +61,7 @@ "exchange" : "Austausch", "clear" : "klar", + "refund_address" : "Rückerstattungsadresse", "change_exchange_provider" : "Wechseln Sie den Exchange-Anbieter", "you_will_send" : "Du wirst senden", "you_will_get" : "Sie erhalten", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 4048513a2..ff0c481c0 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -61,6 +61,7 @@ "exchange" : "Exchange", "clear" : "Clear", + "refund_address" : "Refund address", "change_exchange_provider" : "Change Exchange Provider", "you_will_send" : "You will send", "you_will_get" : "You will get", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 625d93254..9f0ea478a 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -61,6 +61,7 @@ "exchange" : "Intercambiar", "clear" : "Claro", + "refund_address" : "Dirección de reembolso", "change_exchange_provider" : "Cambiar proveedor de intercambio", "you_will_send" : "Enviarás", "you_will_get" : "Conseguirás", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 5a5ee3551..1a915a1d0 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -61,6 +61,7 @@ "exchange" : "अदला बदली", "clear" : "स्पष्ट", + "refund_address" : "वापसी का पता", "change_exchange_provider" : "एक्सचेंज प्रदाता बदलें", "you_will_send" : "तुम भेजोगे", "you_will_get" : "आपको मिल जायेगा", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index c8fb80b86..5f45c0949 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -61,6 +61,7 @@ "exchange" : "交換する", "clear" : "クリア", + "refund_address" : "払い戻し住所", "change_exchange_provider" : "Exchangeプロバイダーの変更", "you_will_send" : "送ります", "you_will_get" : "あなたが取得します", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 061016ecd..74430e1a2 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -61,6 +61,7 @@ "exchange" : "교환", "clear" : "명확한", + "refund_address" : "환불 주소", "change_exchange_provider" : "교환 공급자 변경", "you_will_send" : "보내드립니다", "you_will_get" : "당신은 얻을 것이다", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index ca10484da..78e3b77f6 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -61,6 +61,7 @@ "exchange" : "Uitwisseling", "clear" : "Duidelijk", + "refund_address" : "Adres voor terugbetaling", "change_exchange_provider" : "Wijzig Exchange Provider", "you_will_send" : "Je zal versturen", "you_will_get" : "Je zult krijgen", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 3319d6745..0647fd32c 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -61,6 +61,7 @@ "exchange" : "Wymieniać się", "clear" : "Wyczyść", + "refund_address" : "Adres zwrotu", "change_exchange_provider" : "Zmień dostawcę programu Exchange", "you_will_send" : "Wyślesz", "you_will_get" : "Dostaniesz", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index c1f4e110a..04b12862c 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -61,6 +61,7 @@ "exchange" : "Trocar", "clear" : "Limpar", + "refund_address" : "Endereço de reembolso", "change_exchange_provider" : "Alterar o provedor de troca", "you_will_send" : "Você enviará", "you_will_get" : "Você receberá", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 22d77e0be..441ff68a0 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -61,6 +61,7 @@ "exchange" : "Обмен", "clear" : "Очистить", + "refund_address" : "Адрес возврата", "change_exchange_provider" : "Изменить провайдера обмена", "you_will_send" : "Вы отправите", "you_will_get" : "Вы получите", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 326ec25ec..648bd8e70 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -61,6 +61,7 @@ "exchange" : "Обмін", "clear" : "Очистити", + "refund_address" : "Адреса повернення коштів", "change_exchange_provider" : "Змінити провайдера обміну", "you_will_send" : "Ви відправите", "you_will_get" : "Ви отримаєте", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index bf1b410a9..bf0523f96 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -61,6 +61,7 @@ "exchange" : "交换", "clear" : "明确", + "refund_address" : "退款地址", "change_exchange_provider" : "更改交易所提供商", "you_will_send" : "您将发送", "you_will_get" : "你会得到",