mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-17 01:37:40 +00:00
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:
parent
697fc7f5a5
commit
1c976bfaa1
12 changed files with 238 additions and 171 deletions
|
@ -23,6 +23,7 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||||
static const _currenciesSuffix = '/v3/currencies';
|
static const _currenciesSuffix = '/v3/currencies';
|
||||||
static const _quoteSuffix = '/buy_quote';
|
static const _quoteSuffix = '/buy_quote';
|
||||||
static const _transactionsSuffix = '/v1/transactions';
|
static const _transactionsSuffix = '/v1/transactions';
|
||||||
|
static const _fiatCurrency = 'USD';
|
||||||
static const _apiKey = secrets.moonPayApiKey;
|
static const _apiKey = secrets.moonPayApiKey;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -35,9 +36,7 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||||
walletTypeToCryptoCurrency(walletType).title.toLowerCase();
|
walletTypeToCryptoCurrency(walletType).title.toLowerCase();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get trackUrl => isTestEnvironment
|
String get trackUrl => baseApiUrl + '/transaction_receipt?transactionId=';
|
||||||
? ''
|
|
||||||
: ''; // FIXME
|
|
||||||
|
|
||||||
String baseApiUrl;
|
String baseApiUrl;
|
||||||
|
|
||||||
|
@ -103,8 +102,8 @@ class MoonPayBuyProvider extends BuyProvider {
|
||||||
id: id,
|
id: id,
|
||||||
provider: description,
|
provider: description,
|
||||||
transferId: id,
|
transferId: id,
|
||||||
from: 'USD', //FIXME
|
from: _fiatCurrency,
|
||||||
to: 'BTC', //FIXME
|
to: currencyCode.toUpperCase(),
|
||||||
state: state,
|
state: state,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
amount: amount.toString(),
|
amount: amount.toString(),
|
||||||
|
|
|
@ -28,6 +28,7 @@ class WyreBuyProvider extends BuyProvider {
|
||||||
static const _timeStampSuffix = '?timestamp=';
|
static const _timeStampSuffix = '?timestamp=';
|
||||||
static const _transferSuffix = '/v2/transfer/';
|
static const _transferSuffix = '/v2/transfer/';
|
||||||
static const _trackSuffix = '/track';
|
static const _trackSuffix = '/track';
|
||||||
|
static const _countryCode = 'US';
|
||||||
static const _secretKey = secrets.wyreSecretKey;
|
static const _secretKey = secrets.wyreSecretKey;
|
||||||
static const _accountId = secrets.wyreAccountId;
|
static const _accountId = secrets.wyreAccountId;
|
||||||
|
|
||||||
|
@ -86,7 +87,7 @@ class WyreBuyProvider extends BuyProvider {
|
||||||
'destCurrency': walletTypeToCryptoCurrency(walletType).title,
|
'destCurrency': walletTypeToCryptoCurrency(walletType).title,
|
||||||
'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
|
'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
|
||||||
'accountId': _accountId,
|
'accountId': _accountId,
|
||||||
'country': 'US' //FIXME
|
'country': _countryCode
|
||||||
};
|
};
|
||||||
|
|
||||||
final response = await post(quoteUrl,
|
final response = await post(quoteUrl,
|
||||||
|
|
11
lib/di.dart
11
lib/di.dart
|
@ -544,9 +544,14 @@ Future setup(
|
||||||
return PreOrderPage(buyViewModel: getIt.get<BuyViewModel>());
|
return PreOrderPage(buyViewModel: getIt.get<BuyViewModel>());
|
||||||
});
|
});
|
||||||
|
|
||||||
getIt.registerFactoryParam<BuyWebViewPage, String, void>((String url, _) =>
|
getIt.registerFactoryParam<BuyWebViewPage, List, void>(
|
||||||
BuyWebViewPage(getIt.get<BuyViewModel>(),
|
(List args, _) {
|
||||||
ordersStore: getIt.get<OrdersStore>(), url: url));
|
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>(
|
getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>(
|
||||||
(order, _) {
|
(order, _) {
|
||||||
|
|
|
@ -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/seed/pre_seed_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.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:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -304,9 +305,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
getIt.get<PreOrderPage>());
|
getIt.get<PreOrderPage>());
|
||||||
|
|
||||||
case Routes.buyWebView:
|
case Routes.buyWebView:
|
||||||
|
final args = settings.arguments as List;
|
||||||
|
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
builder: (_) =>
|
builder: (_) =>
|
||||||
getIt.get<BuyWebViewPage>(param1: settings.arguments as String));
|
getIt.get<BuyWebViewPage>(param1: args));
|
||||||
|
|
||||||
case Routes.restoreWalletFromSeedDetails:
|
case Routes.restoreWalletFromSeedDetails:
|
||||||
final args = settings.arguments as List;
|
final args = settings.arguments as List;
|
||||||
|
|
|
@ -12,8 +12,8 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
class BuyWebViewPage extends BasePage {
|
class BuyWebViewPage extends BasePage {
|
||||||
BuyWebViewPage(this.buyViewModel,
|
BuyWebViewPage({@required this.buyViewModel,
|
||||||
{@required this.ordersStore, @required this.url});
|
@required this.ordersStore, @required this.url});
|
||||||
|
|
||||||
final OrdersStore ordersStore;
|
final OrdersStore ordersStore;
|
||||||
final String url;
|
final String url;
|
||||||
|
@ -63,6 +63,25 @@ class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
||||||
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
|
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
|
||||||
|
|
||||||
if (_provider is WyreBuyProvider) {
|
if (_provider is WyreBuyProvider) {
|
||||||
|
_saveOrder(keyword: 'completed', splitSymbol: '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_provider is MoonPayBuyProvider) {
|
||||||
|
_saveOrder(keyword: 'transactionId', splitSymbol: '=');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return WebView(
|
||||||
|
key: _webViewkey,
|
||||||
|
initialUrl: widget.url,
|
||||||
|
javascriptMode: JavascriptMode.unrestricted,
|
||||||
|
onWebViewCreated: (WebViewController controller) =>
|
||||||
|
setState(() => _webViewController = controller));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _saveOrder({String keyword, String splitSymbol}) {
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
||||||
|
|
||||||
|
@ -73,8 +92,8 @@ class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
||||||
|
|
||||||
final url = await _webViewController.currentUrl();
|
final url = await _webViewController.currentUrl();
|
||||||
|
|
||||||
if (url.contains('completed')) {
|
if (url.contains(keyword)) {
|
||||||
final urlParts = url.split('/');
|
final urlParts = url.split(splitSymbol);
|
||||||
orderId = urlParts.last;
|
orderId = urlParts.last;
|
||||||
widget.ordersStore.orderId = orderId;
|
widget.ordersStore.orderId = orderId;
|
||||||
|
|
||||||
|
@ -90,35 +109,4 @@ class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return WebView(
|
|
||||||
key: _webViewkey,
|
|
||||||
initialUrl: widget.url,
|
|
||||||
javascriptMode: JavascriptMode.unrestricted,
|
|
||||||
onWebViewCreated: (WebViewController controller) =>
|
|
||||||
setState(() => _webViewController = controller));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,6 @@ class PreOrderPage extends BasePage {
|
||||||
|
|
||||||
if (amount != buyViewModel.buyAmountViewModel.amount) {
|
if (amount != buyViewModel.buyAmountViewModel.amount) {
|
||||||
buyViewModel.buyAmountViewModel.amount = amount;
|
buyViewModel.buyAmountViewModel.amount = amount;
|
||||||
}
|
|
||||||
|
|
||||||
if (buyViewModel.buyAmountViewModel.doubleAmount == 0.0) {
|
|
||||||
buyViewModel.selectedProvider = null;
|
buyViewModel.selectedProvider = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -38,6 +35,12 @@ class PreOrderPage extends BasePage {
|
||||||
if (_amountController.text != amount) {
|
if (_amountController.text != amount) {
|
||||||
_amountController.text = amount;
|
_amountController.text = amount;
|
||||||
}
|
}
|
||||||
|
if (amount.isEmpty) {
|
||||||
|
buyViewModel.selectedProvider = null;
|
||||||
|
buyViewModel.isShowProviderButtons = false;
|
||||||
|
} else {
|
||||||
|
buyViewModel.isShowProviderButtons = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +91,7 @@ class PreOrderPage extends BasePage {
|
||||||
color: Theme.of(context).backgroundColor,
|
color: Theme.of(context).backgroundColor,
|
||||||
child: ScrollableWithBottomSection(
|
child: ScrollableWithBottomSection(
|
||||||
contentPadding: EdgeInsets.only(bottom: 24),
|
contentPadding: EdgeInsets.only(bottom: 24),
|
||||||
content: Column(
|
content: Observer(builder: (_) => Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -150,7 +153,7 @@ class PreOrderPage extends BasePage {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Padding(
|
if (buyViewModel.isShowProviderButtons) Padding(
|
||||||
padding: EdgeInsets.only(top: 38, bottom: 18),
|
padding: EdgeInsets.only(top: 38, bottom: 18),
|
||||||
child: Text(
|
child: Text(
|
||||||
S.of(context).buy_with + ':',
|
S.of(context).buy_with + ':',
|
||||||
|
@ -162,6 +165,7 @@ class PreOrderPage extends BasePage {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
if (buyViewModel.isShowProviderButtons)
|
||||||
...buyViewModel.items.map(
|
...buyViewModel.items.map(
|
||||||
(item) => Observer(builder: (_) => FutureBuilder<BuyAmount>(
|
(item) => Observer(builder: (_) => FutureBuilder<BuyAmount>(
|
||||||
future: item.buyAmount,
|
future: item.buyAmount,
|
||||||
|
@ -180,7 +184,8 @@ class PreOrderPage extends BasePage {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding:
|
padding:
|
||||||
EdgeInsets.only(left: 15, top: 20, right: 15),
|
EdgeInsets.only(left: 15, top: 20, right: 15),
|
||||||
child: Observer(builder: (_) => BuyListItem(
|
child: Observer(builder: (_) {
|
||||||
|
return BuyListItem(
|
||||||
selectedProvider: buyViewModel.selectedProvider,
|
selectedProvider: buyViewModel.selectedProvider,
|
||||||
provider: item.provider,
|
provider: item.provider,
|
||||||
sourceAmount: sourceAmount,
|
sourceAmount: sourceAmount,
|
||||||
|
@ -195,13 +200,14 @@ class PreOrderPage extends BasePage {
|
||||||
? buyViewModel.isDisabled = false
|
? buyViewModel.isDisabled = false
|
||||||
: buyViewModel.isDisabled = true;
|
: buyViewModel.isDisabled = true;
|
||||||
}
|
}
|
||||||
))
|
);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
),)
|
))
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
)),
|
||||||
bottomSectionPadding:
|
bottomSectionPadding:
|
||||||
EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
bottomSection: Observer(builder: (_) {
|
bottomSection: Observer(builder: (_) {
|
||||||
|
@ -214,7 +220,8 @@ class PreOrderPage extends BasePage {
|
||||||
await buyViewModel.fetchUrl();
|
await buyViewModel.fetchUrl();
|
||||||
if (url.isNotEmpty) {
|
if (url.isNotEmpty) {
|
||||||
await Navigator.of(context)
|
await Navigator.of(context)
|
||||||
.pushNamed(Routes.buyWebView, arguments: url);
|
.pushNamed(Routes.buyWebView,
|
||||||
|
arguments: [url, buyViewModel]);
|
||||||
buyViewModel.reset();
|
buyViewModel.reset();
|
||||||
}
|
}
|
||||||
buyViewModel.isRunning = false;
|
buyViewModel.isRunning = false;
|
||||||
|
|
|
@ -98,6 +98,12 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
showInformation(widget.exchangeTradeViewModel, context);
|
showInformation(widget.exchangeTradeViewModel, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
widget.exchangeTradeViewModel.timer?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final copyImage = Image.asset('assets/images/copy_content.png',
|
final copyImage = Image.asset('assets/images/copy_content.png',
|
||||||
|
|
|
@ -19,7 +19,33 @@ class OrderDetailsPage extends BasePage {
|
||||||
final OrderDetailsViewModel orderDetailsViewModel;
|
final OrderDetailsViewModel orderDetailsViewModel;
|
||||||
|
|
||||||
@override
|
@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 Observer(builder: (_) {
|
||||||
return SectionStandardList(
|
return SectionStandardList(
|
||||||
sectionCount: 1,
|
sectionCount: 1,
|
||||||
|
@ -44,4 +70,5 @@ class OrderDetailsPage extends BasePage {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -19,7 +19,33 @@ class TradeDetailsPage extends BasePage {
|
||||||
final TradeDetailsViewModel tradeDetailsViewModel;
|
final TradeDetailsViewModel tradeDetailsViewModel;
|
||||||
|
|
||||||
@override
|
@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 Observer(builder: (_) {
|
||||||
return SectionStandardList(
|
return SectionStandardList(
|
||||||
sectionCount: 1,
|
sectionCount: 1,
|
||||||
|
@ -44,4 +70,5 @@ class TradeDetailsPage extends BasePage {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ abstract class BuyViewModelBase with Store {
|
||||||
.toList();
|
.toList();
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
isDisabled = true;
|
isDisabled = true;
|
||||||
|
isShowProviderButtons = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Box<Order> ordersSource;
|
final Box<Order> ordersSource;
|
||||||
|
@ -51,6 +52,9 @@ abstract class BuyViewModelBase with Store {
|
||||||
@observable
|
@observable
|
||||||
bool isDisabled;
|
bool isDisabled;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool isShowProviderButtons;
|
||||||
|
|
||||||
WalletType get type => wallet.type;
|
WalletType get type => wallet.type;
|
||||||
|
|
||||||
double get doubleAmount => buyAmountViewModel.doubleAmount;
|
double get doubleAmount => buyAmountViewModel.doubleAmount;
|
||||||
|
|
|
@ -45,7 +45,7 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
|
|
||||||
_updateTrade();
|
_updateTrade();
|
||||||
|
|
||||||
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
|
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletBase wallet;
|
final WalletBase wallet;
|
||||||
|
@ -71,7 +71,7 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
|
|
||||||
ExchangeProvider _provider;
|
ExchangeProvider _provider;
|
||||||
|
|
||||||
Timer _timer;
|
Timer timer;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future confirmSending() async {
|
Future confirmSending() async {
|
||||||
|
|
|
@ -39,7 +39,7 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||||
|
|
||||||
_updateTrade();
|
_updateTrade();
|
||||||
|
|
||||||
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
|
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
|
||||||
}
|
}
|
||||||
|
|
||||||
final Box<Trade> trades;
|
final Box<Trade> trades;
|
||||||
|
@ -52,7 +52,7 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||||
|
|
||||||
ExchangeProvider _provider;
|
ExchangeProvider _provider;
|
||||||
|
|
||||||
Timer _timer;
|
Timer timer;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> _updateTrade() async {
|
Future<void> _updateTrade() async {
|
||||||
|
|
Loading…
Reference in a new issue