From 1c976bfaa12e6868b0773e7585992d014626a4a9 Mon Sep 17 00:00:00 2001 From: OleksandrSobol Date: Thu, 15 Apr 2021 20:10:23 +0300 Subject: [PATCH] CAKE-306 | applied _saveOrder() to buy_webview_page.dart; fixed moonpay_buy_provider.dart and wyre_buy_provider.dart; canceled timers on exchange_trade_page.dart, order_details_page.dart and trade_details_page.dart; reworked pre_order_page.dart --- lib/buy/moonpay/moonpay_buy_provider.dart | 9 +- lib/buy/wyre/wyre_buy_provider.dart | 3 +- lib/di.dart | 11 +- lib/router.dart | 5 +- lib/src/screens/buy/buy_webview_page.dart | 78 +++--- lib/src/screens/buy/pre_order_page.dart | 227 +++++++++--------- .../exchange_trade/exchange_trade_page.dart | 6 + .../order_details/order_details_page.dart | 29 ++- .../trade_details/trade_details_page.dart | 29 ++- lib/view_model/buy/buy_view_model.dart | 4 + .../exchange/exchange_trade_view_model.dart | 4 +- lib/view_model/trade_details_view_model.dart | 4 +- 12 files changed, 238 insertions(+), 171 deletions(-) diff --git a/lib/buy/moonpay/moonpay_buy_provider.dart b/lib/buy/moonpay/moonpay_buy_provider.dart index 5b2fd7326..240d6389e 100644 --- a/lib/buy/moonpay/moonpay_buy_provider.dart +++ b/lib/buy/moonpay/moonpay_buy_provider.dart @@ -23,6 +23,7 @@ class MoonPayBuyProvider extends BuyProvider { static const _currenciesSuffix = '/v3/currencies'; static const _quoteSuffix = '/buy_quote'; static const _transactionsSuffix = '/v1/transactions'; + static const _fiatCurrency = 'USD'; static const _apiKey = secrets.moonPayApiKey; @override @@ -35,9 +36,7 @@ class MoonPayBuyProvider extends BuyProvider { walletTypeToCryptoCurrency(walletType).title.toLowerCase(); @override - String get trackUrl => isTestEnvironment - ? '' - : ''; // FIXME + String get trackUrl => baseApiUrl + '/transaction_receipt?transactionId='; String baseApiUrl; @@ -103,8 +102,8 @@ class MoonPayBuyProvider extends BuyProvider { id: id, provider: description, transferId: id, - from: 'USD', //FIXME - to: 'BTC', //FIXME + from: _fiatCurrency, + to: currencyCode.toUpperCase(), state: state, createdAt: createdAt, amount: amount.toString(), diff --git a/lib/buy/wyre/wyre_buy_provider.dart b/lib/buy/wyre/wyre_buy_provider.dart index 3a09be0f6..77055c325 100644 --- a/lib/buy/wyre/wyre_buy_provider.dart +++ b/lib/buy/wyre/wyre_buy_provider.dart @@ -28,6 +28,7 @@ class WyreBuyProvider extends BuyProvider { static const _timeStampSuffix = '?timestamp='; static const _transferSuffix = '/v2/transfer/'; static const _trackSuffix = '/track'; + static const _countryCode = 'US'; static const _secretKey = secrets.wyreSecretKey; static const _accountId = secrets.wyreAccountId; @@ -86,7 +87,7 @@ class WyreBuyProvider extends BuyProvider { 'destCurrency': walletTypeToCryptoCurrency(walletType).title, 'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress, 'accountId': _accountId, - 'country': 'US' //FIXME + 'country': _countryCode }; final response = await post(quoteUrl, diff --git a/lib/di.dart b/lib/di.dart index 0b107fde4..2a33e6b11 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -544,9 +544,14 @@ Future setup( return PreOrderPage(buyViewModel: getIt.get()); }); - getIt.registerFactoryParam((String url, _) => - BuyWebViewPage(getIt.get(), - ordersStore: getIt.get(), url: url)); + getIt.registerFactoryParam( + (List args, _) { + final url = args.first as String; + final buyViewModel = args[1] as BuyViewModel; + + return BuyWebViewPage(buyViewModel: buyViewModel, + ordersStore: getIt.get(), url: url); + }); getIt.registerFactoryParam( (order, _) { diff --git a/lib/router.dart b/lib/router.dart index a3421fa69..e8650e34e 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -12,6 +12,7 @@ import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart'; import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart'; import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/store/settings_store.dart'; +import 'package:cake_wallet/view_model/buy/buy_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -304,9 +305,11 @@ Route createRoute(RouteSettings settings) { getIt.get()); case Routes.buyWebView: + final args = settings.arguments as List; + return MaterialPageRoute( builder: (_) => - getIt.get(param1: settings.arguments as String)); + getIt.get(param1: args)); case Routes.restoreWalletFromSeedDetails: final args = settings.arguments as List; diff --git a/lib/src/screens/buy/buy_webview_page.dart b/lib/src/screens/buy/buy_webview_page.dart index d5ab59482..9d2ba3698 100644 --- a/lib/src/screens/buy/buy_webview_page.dart +++ b/lib/src/screens/buy/buy_webview_page.dart @@ -12,8 +12,8 @@ import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class BuyWebViewPage extends BasePage { - BuyWebViewPage(this.buyViewModel, - {@required this.ordersStore, @required this.url}); + BuyWebViewPage({@required this.buyViewModel, + @required this.ordersStore, @required this.url}); final OrdersStore ordersStore; final String url; @@ -63,52 +63,11 @@ class BuyWebViewPageBodyState extends State { if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView(); if (_provider is WyreBuyProvider) { - _timer?.cancel(); - _timer = Timer.periodic(Duration(seconds: 1), (timer) async { - - try { - if (_webViewController == null || _isSaving) { - return; - } - - final url = await _webViewController.currentUrl(); - - if (url.contains('completed')) { - final urlParts = url.split('/'); - orderId = urlParts.last; - widget.ordersStore.orderId = orderId; - - if (orderId.isNotEmpty) { - _isSaving = true; - await widget.buyViewModel.saveOrder(orderId); - timer.cancel(); - } - } - } catch (e) { - _isSaving = false; - print(e); - } - }); + _saveOrder(keyword: 'completed', splitSymbol: '/'); } if (_provider is MoonPayBuyProvider) { - /*_timer?.cancel(); - _timer = Timer.periodic(Duration(seconds: 1), (timer) async { - - try { - if (_webViewController == null || _isSaving) { - return; - } - - final url = await _webViewController.currentUrl(); - print('MoonPay Url = $url'); - - timer.cancel(); - } catch (e) { - _isSaving = false; - print(e); - } - });*/ + _saveOrder(keyword: 'transactionId', splitSymbol: '='); } } @@ -121,4 +80,33 @@ class BuyWebViewPageBodyState extends State { onWebViewCreated: (WebViewController controller) => setState(() => _webViewController = controller)); } + + void _saveOrder({String keyword, String splitSymbol}) { + _timer?.cancel(); + _timer = Timer.periodic(Duration(seconds: 1), (timer) async { + + try { + if (_webViewController == null || _isSaving) { + return; + } + + final url = await _webViewController.currentUrl(); + + if (url.contains(keyword)) { + final urlParts = url.split(splitSymbol); + orderId = urlParts.last; + widget.ordersStore.orderId = orderId; + + if (orderId.isNotEmpty) { + _isSaving = true; + await widget.buyViewModel.saveOrder(orderId); + timer.cancel(); + } + } + } catch (e) { + _isSaving = false; + print(e); + } + }); + } } diff --git a/lib/src/screens/buy/pre_order_page.dart b/lib/src/screens/buy/pre_order_page.dart index 44162d7ec..dbe03b07e 100644 --- a/lib/src/screens/buy/pre_order_page.dart +++ b/lib/src/screens/buy/pre_order_page.dart @@ -27,9 +27,6 @@ class PreOrderPage extends BasePage { if (amount != buyViewModel.buyAmountViewModel.amount) { buyViewModel.buyAmountViewModel.amount = amount; - } - - if (buyViewModel.buyAmountViewModel.doubleAmount == 0.0) { buyViewModel.selectedProvider = null; } }); @@ -38,6 +35,12 @@ class PreOrderPage extends BasePage { if (_amountController.text != amount) { _amountController.text = amount; } + if (amount.isEmpty) { + buyViewModel.selectedProvider = null; + buyViewModel.isShowProviderButtons = false; + } else { + buyViewModel.isShowProviderButtons = true; + } }); } @@ -88,120 +91,123 @@ class PreOrderPage extends BasePage { color: Theme.of(context).backgroundColor, child: ScrollableWithBottomSection( contentPadding: EdgeInsets.only(bottom: 24), - content: Column( + content: Observer(builder: (_) => Column( children: [ Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), - bottomRight: Radius.circular(24)), - gradient: LinearGradient(colors: [ - Theme.of(context).primaryTextTheme.subhead.color, - Theme.of(context) - .primaryTextTheme - .subhead - .decorationColor, - ], begin: Alignment.topLeft, end: Alignment.bottomRight), - ), - child: Padding( - padding: EdgeInsets.only(top: 100, bottom: 65), - child: Center( - child: Container( - width: 165, - child: BaseTextFormField( - focusNode: _amountFocus, - controller: _amountController, - keyboardType: - TextInputType.numberWithOptions( - signed: false, decimal: true), - inputFormatters: [ - FilteringTextInputFormatter - .allow(RegExp(_amountPattern)) - ], - prefixIcon: Padding( - padding: EdgeInsets.only(top: 2), - child: - Text(buyViewModel.fiatCurrency.title + ': ', - style: TextStyle( - fontSize: 36, - fontWeight: FontWeight.w600, - color: Colors.white, - )), - ), - hintText: '0.00', - borderColor: Theme.of(context) - .primaryTextTheme - .body2 - .decorationColor, - borderWidth: 0.5, - textStyle: TextStyle( - fontSize: 36, - fontWeight: FontWeight.w500, - color: Colors.white), - placeholderTextStyle: TextStyle( - color: Theme.of(context) - .primaryTextTheme - .headline - .decorationColor, - fontWeight: FontWeight.w500, - fontSize: 36), - ) - ) - ) - ) - ), - Padding( - padding: EdgeInsets.only(top: 38, bottom: 18), - child: Text( - S.of(context).buy_with + ':', - textAlign: TextAlign.center, - style: TextStyle( - color: Theme.of(context).primaryTextTheme.title.color, - fontSize: 18, - fontWeight: FontWeight.bold + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), + bottomRight: Radius.circular(24)), + gradient: LinearGradient(colors: [ + Theme.of(context).primaryTextTheme.subhead.color, + Theme.of(context) + .primaryTextTheme + .subhead + .decorationColor, + ], begin: Alignment.topLeft, end: Alignment.bottomRight), ), - ) + child: Padding( + padding: EdgeInsets.only(top: 100, bottom: 65), + child: Center( + child: Container( + width: 165, + child: BaseTextFormField( + focusNode: _amountFocus, + controller: _amountController, + keyboardType: + TextInputType.numberWithOptions( + signed: false, decimal: true), + inputFormatters: [ + FilteringTextInputFormatter + .allow(RegExp(_amountPattern)) + ], + prefixIcon: Padding( + padding: EdgeInsets.only(top: 2), + child: + Text(buyViewModel.fiatCurrency.title + ': ', + style: TextStyle( + fontSize: 36, + fontWeight: FontWeight.w600, + color: Colors.white, + )), + ), + hintText: '0.00', + borderColor: Theme.of(context) + .primaryTextTheme + .body2 + .decorationColor, + borderWidth: 0.5, + textStyle: TextStyle( + fontSize: 36, + fontWeight: FontWeight.w500, + color: Colors.white), + placeholderTextStyle: TextStyle( + color: Theme.of(context) + .primaryTextTheme + .headline + .decorationColor, + fontWeight: FontWeight.w500, + fontSize: 36), + ) + ) + ) + ) ), - ...buyViewModel.items.map( - (item) => Observer(builder: (_) => FutureBuilder( - future: item.buyAmount, - builder: (context, AsyncSnapshot snapshot) { - double sourceAmount; - double destAmount; + if (buyViewModel.isShowProviderButtons) Padding( + padding: EdgeInsets.only(top: 38, bottom: 18), + child: Text( + S.of(context).buy_with + ':', + textAlign: TextAlign.center, + style: TextStyle( + color: Theme.of(context).primaryTextTheme.title.color, + fontSize: 18, + fontWeight: FontWeight.bold + ), + ) + ), + if (buyViewModel.isShowProviderButtons) + ...buyViewModel.items.map( + (item) => Observer(builder: (_) => FutureBuilder( + future: item.buyAmount, + builder: (context, AsyncSnapshot snapshot) { + double sourceAmount; + double destAmount; - if (snapshot.hasData) { - sourceAmount = snapshot.data.sourceAmount; - destAmount = snapshot.data.destAmount; - } else { - sourceAmount = 0.0; - destAmount = 0.0; + if (snapshot.hasData) { + sourceAmount = snapshot.data.sourceAmount; + destAmount = snapshot.data.destAmount; + } else { + sourceAmount = 0.0; + destAmount = 0.0; + } + + return Padding( + padding: + EdgeInsets.only(left: 15, top: 20, right: 15), + child: Observer(builder: (_) { + return BuyListItem( + selectedProvider: buyViewModel.selectedProvider, + provider: item.provider, + sourceAmount: sourceAmount, + sourceCurrency: buyViewModel.fiatCurrency, + destAmount: destAmount, + destCurrency: buyViewModel.cryptoCurrency, + onTap: + buyViewModel.buyAmountViewModel + .doubleAmount == 0.0 ? null : () { + buyViewModel.selectedProvider = item.provider; + sourceAmount > 0 + ? buyViewModel.isDisabled = false + : buyViewModel.isDisabled = true; + } + ); + }) + ); } - - return Padding( - padding: - EdgeInsets.only(left: 15, top: 20, right: 15), - child: Observer(builder: (_) => BuyListItem( - selectedProvider: buyViewModel.selectedProvider, - provider: item.provider, - sourceAmount: sourceAmount, - sourceCurrency: buyViewModel.fiatCurrency, - destAmount: destAmount, - destCurrency: buyViewModel.cryptoCurrency, - onTap: - buyViewModel.buyAmountViewModel - .doubleAmount == 0.0 ? null : () { - buyViewModel.selectedProvider = item.provider; - sourceAmount > 0 - ? buyViewModel.isDisabled = false - : buyViewModel.isDisabled = true; - } - )) - ); - } - ),) + )) ) ], - ), + )), bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), bottomSection: Observer(builder: (_) { @@ -214,7 +220,8 @@ class PreOrderPage extends BasePage { await buyViewModel.fetchUrl(); if (url.isNotEmpty) { await Navigator.of(context) - .pushNamed(Routes.buyWebView, arguments: url); + .pushNamed(Routes.buyWebView, + arguments: [url, buyViewModel]); buyViewModel.reset(); } buyViewModel.isRunning = false; diff --git a/lib/src/screens/exchange_trade/exchange_trade_page.dart b/lib/src/screens/exchange_trade/exchange_trade_page.dart index b4374cbb5..0a3b10e18 100644 --- a/lib/src/screens/exchange_trade/exchange_trade_page.dart +++ b/lib/src/screens/exchange_trade/exchange_trade_page.dart @@ -98,6 +98,12 @@ class ExchangeTradeState extends State { showInformation(widget.exchangeTradeViewModel, context); } + @override + void dispose() { + super.dispose(); + widget.exchangeTradeViewModel.timer?.cancel(); + } + @override Widget build(BuildContext context) { final copyImage = Image.asset('assets/images/copy_content.png', diff --git a/lib/src/screens/order_details/order_details_page.dart b/lib/src/screens/order_details/order_details_page.dart index 4122a1af5..293cf5e3d 100644 --- a/lib/src/screens/order_details/order_details_page.dart +++ b/lib/src/screens/order_details/order_details_page.dart @@ -19,7 +19,33 @@ class OrderDetailsPage extends BasePage { final OrderDetailsViewModel orderDetailsViewModel; @override - Widget body(BuildContext context) { + Widget body(BuildContext context) => + OrderDetailsPageBody(orderDetailsViewModel); +} + +class OrderDetailsPageBody extends StatefulWidget { + OrderDetailsPageBody(this.orderDetailsViewModel); + + final OrderDetailsViewModel orderDetailsViewModel; + + @override + OrderDetailsPageBodyState createState() => + OrderDetailsPageBodyState(orderDetailsViewModel); +} + +class OrderDetailsPageBodyState extends State { + OrderDetailsPageBodyState(this.orderDetailsViewModel); + + final OrderDetailsViewModel orderDetailsViewModel; + + @override + void dispose() { + super.dispose(); + orderDetailsViewModel.timer?.cancel(); + } + + @override + Widget build(BuildContext context) { return Observer(builder: (_) { return SectionStandardList( sectionCount: 1, @@ -44,4 +70,5 @@ class OrderDetailsPage extends BasePage { }); }); } + } \ No newline at end of file diff --git a/lib/src/screens/trade_details/trade_details_page.dart b/lib/src/screens/trade_details/trade_details_page.dart index e691e7f84..abf8e2873 100644 --- a/lib/src/screens/trade_details/trade_details_page.dart +++ b/lib/src/screens/trade_details/trade_details_page.dart @@ -19,7 +19,33 @@ class TradeDetailsPage extends BasePage { final TradeDetailsViewModel tradeDetailsViewModel; @override - Widget body(BuildContext context) { + Widget body(BuildContext context) => + TradeDetailsPageBody(tradeDetailsViewModel); +} + +class TradeDetailsPageBody extends StatefulWidget { + TradeDetailsPageBody(this.tradeDetailsViewModel); + + final TradeDetailsViewModel tradeDetailsViewModel; + + @override + TradeDetailsPageBodyState createState() => + TradeDetailsPageBodyState(tradeDetailsViewModel); +} + +class TradeDetailsPageBodyState extends State { + TradeDetailsPageBodyState(this.tradeDetailsViewModel); + + final TradeDetailsViewModel tradeDetailsViewModel; + + @override + void dispose() { + super.dispose(); + tradeDetailsViewModel.timer?.cancel(); + } + + @override + Widget build(BuildContext context) { return Observer(builder: (_) { return SectionStandardList( sectionCount: 1, @@ -44,4 +70,5 @@ class TradeDetailsPage extends BasePage { }); }); } + } diff --git a/lib/view_model/buy/buy_view_model.dart b/lib/view_model/buy/buy_view_model.dart index 10dd9a35a..70d1cc556 100644 --- a/lib/view_model/buy/buy_view_model.dart +++ b/lib/view_model/buy/buy_view_model.dart @@ -29,6 +29,7 @@ abstract class BuyViewModelBase with Store { .toList(); isRunning = false; isDisabled = true; + isShowProviderButtons = false; } final Box ordersSource; @@ -51,6 +52,9 @@ abstract class BuyViewModelBase with Store { @observable bool isDisabled; + @observable + bool isShowProviderButtons; + WalletType get type => wallet.type; double get doubleAmount => buyAmountViewModel.doubleAmount; diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart index a739b207f..7882c3dca 100644 --- a/lib/view_model/exchange/exchange_trade_view_model.dart +++ b/lib/view_model/exchange/exchange_trade_view_model.dart @@ -45,7 +45,7 @@ abstract class ExchangeTradeViewModelBase with Store { _updateTrade(); - _timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade()); + timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade()); } final WalletBase wallet; @@ -71,7 +71,7 @@ abstract class ExchangeTradeViewModelBase with Store { ExchangeProvider _provider; - Timer _timer; + Timer timer; @action Future confirmSending() async { diff --git a/lib/view_model/trade_details_view_model.dart b/lib/view_model/trade_details_view_model.dart index 9c88cb981..a367c17f4 100644 --- a/lib/view_model/trade_details_view_model.dart +++ b/lib/view_model/trade_details_view_model.dart @@ -39,7 +39,7 @@ abstract class TradeDetailsViewModelBase with Store { _updateTrade(); - _timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade()); + timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade()); } final Box trades; @@ -52,7 +52,7 @@ abstract class TradeDetailsViewModelBase with Store { ExchangeProvider _provider; - Timer _timer; + Timer timer; @action Future _updateTrade() async {