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

This commit is contained in:
OleksandrSobol 2021-04-15 20:10:23 +03:00
parent 697fc7f5a5
commit 1c976bfaa1
12 changed files with 238 additions and 171 deletions

View file

@ -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(),

View file

@ -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,

View file

@ -544,9 +544,14 @@ Future setup(
return PreOrderPage(buyViewModel: getIt.get<BuyViewModel>());
});
getIt.registerFactoryParam<BuyWebViewPage, String, void>((String url, _) =>
BuyWebViewPage(getIt.get<BuyViewModel>(),
ordersStore: getIt.get<OrdersStore>(), url: url));
getIt.registerFactoryParam<BuyWebViewPage, List, void>(
(List args, _) {
final url = args.first as String;
final buyViewModel = args[1] as BuyViewModel;
return BuyWebViewPage(buyViewModel: buyViewModel,
ordersStore: getIt.get<OrdersStore>(), url: url);
});
getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>(
(order, _) {

View file

@ -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<dynamic> createRoute(RouteSettings settings) {
getIt.get<PreOrderPage>());
case Routes.buyWebView:
final args = settings.arguments as List;
return MaterialPageRoute<void>(
builder: (_) =>
getIt.get<BuyWebViewPage>(param1: settings.arguments as String));
getIt.get<BuyWebViewPage>(param1: args));
case Routes.restoreWalletFromSeedDetails:
final args = settings.arguments as List;

View file

@ -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<BuyWebViewPageBody> {
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<BuyWebViewPageBody> {
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);
}
});
}
}

View file

@ -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<BuyAmount>(
future: item.buyAmount,
builder: (context, AsyncSnapshot<BuyAmount> 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<BuyAmount>(
future: item.buyAmount,
builder: (context, AsyncSnapshot<BuyAmount> 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;

View file

@ -98,6 +98,12 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
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',

View file

@ -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<OrderDetailsPageBody> {
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 {
});
});
}
}

View file

@ -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<TradeDetailsPageBody> {
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 {
});
});
}
}

View file

@ -29,6 +29,7 @@ abstract class BuyViewModelBase with Store {
.toList();
isRunning = false;
isDisabled = true;
isShowProviderButtons = false;
}
final Box<Order> 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;

View file

@ -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 {

View file

@ -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<Trade> trades;
@ -52,7 +52,7 @@ abstract class TradeDetailsViewModelBase with Store {
ExchangeProvider _provider;
Timer _timer;
Timer timer;
@action
Future<void> _updateTrade() async {