CAKE-306 | applied buy_webview_page.dart to the app; fixed order_details_view_model.dart and order_row.dart; applied localization to the pre_order_page.dart; deleted unused files

This commit is contained in:
OleksandrSobol 2021-04-13 21:40:44 +03:00
parent 346a034d0a
commit 19ffffa6cc
31 changed files with 310 additions and 398 deletions

View file

@ -12,6 +12,7 @@ abstract class BuyProvider {
String get title; String get title;
BuyProviderDescription get description; BuyProviderDescription get description;
String get trackUrl;
WalletType get walletType => wallet.type; WalletType get walletType => wallet.type;
String get walletAddress => wallet.address; String get walletAddress => wallet.address;

View file

@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/buy/buy_provider_description.dart';
Image getBuyProviderIcon(BuyProviderDescription providerDescription) {
final _wyreIcon =
Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
final _moonPayIcon =
Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
if (providerDescription != null) {
switch (providerDescription) {
case BuyProviderDescription.wyre:
return _wyreIcon;
case BuyProviderDescription.moonPay:
//return _moonPayIcon;
return null;
default:
return null;
}
} else {
return null;
}
}

View file

@ -34,6 +34,11 @@ class MoonPayBuyProvider extends BuyProvider {
String get currencyCode => String get currencyCode =>
walletTypeToCryptoCurrency(walletType).title.toLowerCase(); walletTypeToCryptoCurrency(walletType).title.toLowerCase();
@override
String get trackUrl => isTestEnvironment
? ''
: ''; // FIXME
String baseApiUrl; String baseApiUrl;
@override @override

View file

@ -16,9 +16,6 @@ class WyreBuyProvider extends BuyProvider {
baseApiUrl = isTestEnvironment baseApiUrl = isTestEnvironment
? _baseTestApiUrl ? _baseTestApiUrl
: _baseProductApiUrl; : _baseProductApiUrl;
trackUrl = isTestEnvironment
? _trackTestUrl
: _trackProductUrl;
} }
static const _baseTestApiUrl = 'https://api.testwyre.com'; static const _baseTestApiUrl = 'https://api.testwyre.com';
@ -40,8 +37,12 @@ class WyreBuyProvider extends BuyProvider {
@override @override
BuyProviderDescription get description => BuyProviderDescription.wyre; BuyProviderDescription get description => BuyProviderDescription.wyre;
@override
String get trackUrl => isTestEnvironment
? _trackTestUrl
: _trackProductUrl;
String baseApiUrl; String baseApiUrl;
String trackUrl;
@override @override
Future<String> requestUrl(String amount, String sourceCurrency) async { Future<String> requestUrl(String amount, String sourceCurrency) async {

View file

@ -7,7 +7,6 @@ import 'package:cake_wallet/entities/load_current_wallet.dart';
import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/entities/transaction_info.dart'; import 'package:cake_wallet/entities/transaction_info.dart';
import 'package:cake_wallet/entities/wyre_service.dart';
import 'package:cake_wallet/monero/monero_wallet_service.dart'; import 'package:cake_wallet/monero/monero_wallet_service.dart';
import 'package:cake_wallet/entities/contact.dart'; import 'package:cake_wallet/entities/contact.dart';
import 'package:cake_wallet/entities/node.dart'; import 'package:cake_wallet/entities/node.dart';
@ -15,6 +14,7 @@ import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/reactions/on_authentication_state_change.dart'; import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
import 'package:cake_wallet/src/screens/backup/backup_page.dart'; import 'package:cake_wallet/src/screens/backup/backup_page.dart';
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart'; import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
import 'package:cake_wallet/src/screens/buy/pre_order_page.dart'; import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart'; import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
import 'package:cake_wallet/src/screens/contact/contact_page.dart'; import 'package:cake_wallet/src/screens/contact/contact_page.dart';
@ -42,7 +42,6 @@ import 'package:cake_wallet/src/screens/transaction_details/transaction_details_
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.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_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart'; import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
import 'package:cake_wallet/src/screens/wyre/wyre_page.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart'; import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:cake_wallet/store/node_list_store.dart'; import 'package:cake_wallet/store/node_list_store.dart';
import 'package:cake_wallet/store/secret_store.dart'; import 'package:cake_wallet/store/secret_store.dart';
@ -91,7 +90,6 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart'; import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
import 'package:cake_wallet/view_model/wallet_seed_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:cake_wallet/view_model/exchange/exchange_view_model.dart';
import 'package:cake_wallet/view_model/wyre_view_model.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@ -241,8 +239,7 @@ Future setup(
transactionFilterStore: getIt.get<TransactionFilterStore>(), transactionFilterStore: getIt.get<TransactionFilterStore>(),
settingsStore: settingsStore, settingsStore: settingsStore,
ordersSource: _ordersSource, ordersSource: _ordersSource,
ordersStore: getIt.get<OrdersStore>(), ordersStore: getIt.get<OrdersStore>()));
wyreViewModel: getIt.get<WyreViewModel>()));
getIt.registerFactory<AuthService>(() => AuthService( getIt.registerFactory<AuthService>(() => AuthService(
secureStorage: getIt.get<FlutterSecureStorage>(), secureStorage: getIt.get<FlutterSecureStorage>(),
@ -534,20 +531,6 @@ Future setup(
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>((Trade trade, _) => getIt.registerFactoryParam<TradeDetailsPage, Trade, void>((Trade trade, _) =>
TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade))); TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;
return WyreService(wallet: wallet);
});
getIt.registerFactory(() {
return WyreViewModel(ordersSource, getIt.get<OrdersStore>(),
wyreService: getIt.get<WyreService>());
});
getIt.registerFactoryParam<WyrePage, String, void>((String url, _) =>
WyrePage(getIt.get<WyreViewModel>(),
ordersStore: getIt.get<OrdersStore>(), url: url));
getIt.registerFactory(() => BuyAmountViewModel()); getIt.registerFactory(() => BuyAmountViewModel());
getIt.registerFactory(() { getIt.registerFactory(() {
@ -561,10 +544,18 @@ Future setup(
return PreOrderPage(buyViewModel: getIt.get<BuyViewModel>()); 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<OrderDetailsViewModel, Order, void>( getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>(
(order, _) => OrderDetailsViewModel( (order, _) {
wyreViewModel: getIt.get<WyreViewModel>(), final wallet = getIt.get<AppStore>().wallet;
orderForDetails: order));
return OrderDetailsViewModel(
wallet: wallet,
orderForDetails: order);
});
getIt.registerFactoryParam<OrderDetailsPage, Order, void>((Order order, _) => getIt.registerFactoryParam<OrderDetailsPage, Order, void>((Order order, _) =>
OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order))); OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order)));

View file

@ -1,8 +0,0 @@
class WyreException implements Exception {
WyreException(this.description);
String description;
@override
String toString() => description;
}

View file

@ -1,151 +0,0 @@
import 'dart:convert';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/entities/wyre_exception.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
class WyreService {
WyreService({
@required this.wallet,
this.isTestEnvironment = false}) {
baseApiUrl = isTestEnvironment
? _baseTestApiUrl
: _baseProductApiUrl;
trackUrl = isTestEnvironment
? _trackTestUrl
: _trackProductUrl;
}
static const _baseTestApiUrl = 'https://api.testwyre.com';
static const _baseProductApiUrl = 'https://api.sendwyre.com';
static const _trackTestUrl = 'https://dash.testwyre.com/track/';
static const _trackProductUrl = 'https://dash.sendwyre.com/track/';
static const _ordersSuffix = '/v3/orders';
static const _reserveSuffix = '/reserve';
static const _quoteSuffix = '/quote/partner';
static const _timeStampSuffix = '?timestamp=';
static const _transferSuffix = '/v2/transfer/';
static const _trackSuffix = '/track';
final bool isTestEnvironment;
final WalletBase wallet;
WalletType get walletType => wallet.type;
String get walletAddress => wallet.address;
String get walletId => wallet.id;
String baseApiUrl;
String trackUrl;
Future<String> getWyreUrl() async {
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
final url = baseApiUrl + _ordersSuffix + _reserveSuffix +
_timeStampSuffix + timestamp;
final secretKey = secrets.wyreSecretKey;
final accountId = secrets.wyreAccountId;
final body = {
'amount': '1',
'sourceCurrency': 'USD',
'destCurrency': walletTypeToCryptoCurrency(walletType).title,
'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
'referrerAccountId': accountId,
'lockFields': ['amount', 'sourceCurrency', 'destCurrency', 'dest']
};
final response = await post(url,
headers: {
'Authorization': 'Bearer $secretKey',
'Content-Type': 'application/json',
'cache-control': 'no-cache'
},
body: json.encode(body));
if (response.statusCode != 200) {
throw WyreException('Url $url is not found!');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final urlFromResponse = responseJSON['url'] as String;
return urlFromResponse;
}
Future<Order> findOrderById(String id) async {
final orderUrl = baseApiUrl + _ordersSuffix + '/$id';
final orderResponse = await get(orderUrl);
if (orderResponse.statusCode != 200) {
throw WyreException('Order $id is not found!');
}
final orderResponseJSON =
json.decode(orderResponse.body) as Map<String, dynamic>;
final transferId = orderResponseJSON['transferId'] as String;
final from = orderResponseJSON['sourceCurrency'] as String;
final to = orderResponseJSON['destCurrency'] as String;
final status = orderResponseJSON['status'] as String;
final state = TradeState.deserialize(raw: status.toLowerCase());
final createdAtRaw = orderResponseJSON['createdAt'] as int;
final createdAt =
DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal();
final transferUrl =
baseApiUrl + _transferSuffix + transferId + _trackSuffix;
final transferResponse = await get(transferUrl);
if (transferResponse.statusCode != 200) {
throw WyreException('Transfer $transferId is not found!');
}
final transferResponseJSON =
json.decode(transferResponse.body) as Map<String, dynamic>;
final amount = transferResponseJSON['destAmount'] as double;
return Order(
id: id,
transferId: transferId,
from: from,
to: to,
state: state,
createdAt: createdAt,
amount: amount.toString(),
receiveAddress: walletAddress,
walletId: walletId
);
}
Future<double> getAmount() async {
final quoteUrl = baseApiUrl + _ordersSuffix + _quoteSuffix;
final secretKey = secrets.wyreSecretKey;
final accountId = secrets.wyreAccountId;
final body = {
'amount': '1',
'sourceCurrency': 'USD',
'destCurrency': walletTypeToCryptoCurrency(walletType).title,
'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
'accountId': accountId,
'country': 'US'
};
final response = await post(quoteUrl,
headers: {
'Authorization': 'Bearer $secretKey',
'Content-Type': 'application/json',
'cache-control': 'no-cache'
},
body: json.encode(body));
if (response.statusCode != 200) {
throw WyreException('Quote is not found! ');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final amount = responseJSON['destAmount'] as double;
return amount;
}
}

View file

@ -3,6 +3,7 @@ import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/src/screens/backup/backup_page.dart'; import 'package:cake_wallet/src/screens/backup/backup_page.dart';
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart'; import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
import 'package:cake_wallet/src/screens/buy/pre_order_page.dart'; import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart'; import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
@ -10,7 +11,6 @@ import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart'; 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/src/screens/wyre/wyre_page.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.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';
@ -303,10 +303,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => builder: (_) =>
getIt.get<PreOrderPage>()); getIt.get<PreOrderPage>());
case Routes.wyre: case Routes.buyWebView:
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
builder: (_) => builder: (_) =>
getIt.get<WyrePage>(param1: settings.arguments as String)); getIt.get<BuyWebViewPage>(param1: settings.arguments as String));
case Routes.restoreWalletFromSeedDetails: case Routes.restoreWalletFromSeedDetails:
final args = settings.arguments as List; final args = settings.arguments as List;

View file

@ -53,6 +53,6 @@ class Routes {
static const restoreFromBackup = '/restore_from_backup'; static const restoreFromBackup = '/restore_from_backup';
static const support = '/support'; static const support = '/support';
static const orderDetails = '/order_details'; static const orderDetails = '/order_details';
static const wyre = '/wyre';
static const preOrder = '/pre_order'; static const preOrder = '/pre_order';
static const buyWebView = '/buy_web_view';
} }

View file

@ -0,0 +1,108 @@
import 'dart:async';
import 'dart:io';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
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});
final OrdersStore ordersStore;
final String url;
final BuyViewModel buyViewModel;
@override
String get title => S.current.buy;
@override
Color get backgroundDarkColor => Colors.white;
@override
Color get titleColor => Palette.darkBlueCraiola;
@override
Widget body(BuildContext context) =>
BuyWebViewPageBody(buyViewModel, ordersStore: ordersStore, url: url);
}
class BuyWebViewPageBody extends StatefulWidget {
BuyWebViewPageBody(this.buyViewModel, {this.ordersStore, this.url});
final OrdersStore ordersStore;
final String url;
final BuyViewModel buyViewModel;
@override
BuyWebViewPageBodyState createState() => BuyWebViewPageBodyState();
}
class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
String orderId;
WebViewController _webViewController;
GlobalKey _webViewkey;
Timer _timer;
bool _isSaving;
BuyProvider _provider;
@override
void initState() {
super.initState();
_webViewkey = GlobalKey();
_isSaving = false;
widget.ordersStore.orderId = '';
_provider = widget.buyViewModel.selectedProvider;
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);
}
});
}
if (_provider is MoonPayBuyProvider) {
// FIXME: fetch orderId
}
}
@override
Widget build(BuildContext context) {
return WebView(
key: _webViewkey,
initialUrl: widget.url,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController controller) =>
setState(() => _webViewController = controller));
}
}

View file

@ -14,6 +14,7 @@ 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/scollable_with_bottom_section.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:mobx/mobx.dart';
class PreOrderPage extends BasePage { class PreOrderPage extends BasePage {
PreOrderPage({@required this.buyViewModel}) PreOrderPage({@required this.buyViewModel})
@ -31,14 +32,22 @@ class PreOrderPage extends BasePage {
buyViewModel.selectedProvider = null; buyViewModel.selectedProvider = null;
} }
}); });
reaction((_) => buyViewModel.buyAmountViewModel.amount, (String amount) {
if (_amountController.text != amount) {
_amountController.text = amount;
}
});
} }
static const _amountPattern = '^([0-9]+([.\,][0-9]{0,2})?|[.\,][0-9]{1,2})\$';
final BuyViewModel buyViewModel; final BuyViewModel buyViewModel;
final FocusNode _amountFocus; final FocusNode _amountFocus;
final TextEditingController _amountController; final TextEditingController _amountController;
@override @override
String get title => 'Buy Bitcoin'; String get title => S.current.buy_bitcoin;
@override @override
Color get titleColor => Colors.white; Color get titleColor => Colors.white;
@ -96,7 +105,7 @@ class PreOrderPage extends BasePage {
signed: false, decimal: true), signed: false, decimal: true),
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter FilteringTextInputFormatter
.allow(RegExp('^([0-9]+([.\,][0-9]{0,2})?|[.\,][0-9]{1,2})\$')) .allow(RegExp(_amountPattern))
], ],
prefixIcon: Padding( prefixIcon: Padding(
padding: EdgeInsets.only(top: 2), padding: EdgeInsets.only(top: 2),
@ -130,7 +139,7 @@ class PreOrderPage extends BasePage {
Padding( Padding(
padding: EdgeInsets.only(top: 38, bottom: 18), padding: EdgeInsets.only(top: 38, bottom: 18),
child: Text( child: Text(
'Buy with:', S.of(context).buy_with + ':',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: Theme.of(context).primaryTextTheme.title.color, color: Theme.of(context).primaryTextTheme.title.color,
@ -185,16 +194,21 @@ class PreOrderPage extends BasePage {
return LoadingPrimaryButton( return LoadingPrimaryButton(
onPressed: buyViewModel.isRunning onPressed: buyViewModel.isRunning
? null ? null
: () { : () async {
buyViewModel.isRunning = true; buyViewModel.isRunning = true;
final url =
// FIXME: Start WebView await buyViewModel.fetchUrl();
if (url.isNotEmpty) {
await Navigator.of(context)
.pushNamed(Routes.buyWebView, arguments: url);
buyViewModel.reset();
}
buyViewModel.isRunning = false; buyViewModel.isRunning = false;
}, },
text: buyViewModel.selectedProvider == null text: buyViewModel.selectedProvider == null
? 'Buy' ? S.of(context).buy
: 'Buy with ${buyViewModel.selectedProvider : S.of(context).buy_with +
' ${buyViewModel.selectedProvider
.description.title}', .description.title}',
color: Theme.of(context).accentTextTheme.body2.color, color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white, textColor: Colors.white,

View file

@ -1,5 +1,5 @@
import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:cake_wallet/buy/buy_provider.dart'; import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/get_buy_provider_icon.dart';
import 'package:cake_wallet/entities/crypto_currency.dart'; import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/palette.dart';
@ -16,11 +16,6 @@ class BuyListItem extends StatelessWidget {
@required this.onTap @required this.onTap
}); });
final _wyreIcon =
Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
final _mooonPayIcon =
Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
final BuyProvider selectedProvider; final BuyProvider selectedProvider;
final BuyProvider provider; final BuyProvider provider;
final double sourceAmount; final double sourceAmount;
@ -31,7 +26,7 @@ class BuyListItem extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final providerIcon = _getProviderIcon(provider.description); final providerIcon = getBuyProviderIcon(provider.description);
final backgroundColor = selectedProvider != null final backgroundColor = selectedProvider != null
? selectedProvider.description == provider.description ? selectedProvider.description == provider.description
@ -116,16 +111,4 @@ class BuyListItem extends StatelessWidget {
) )
); );
} }
Image _getProviderIcon(BuyProviderDescription providerDescription) {
switch (providerDescription) {
case BuyProviderDescription.wyre:
return _wyreIcon;
case BuyProviderDescription.moonPay:
//return _mooonPayIcon;
return null;
default:
return null;
}
}
} }

View file

@ -1,22 +1,26 @@
import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:cake_wallet/buy/get_buy_provider_icon.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class OrderRow extends StatelessWidget { class OrderRow extends StatelessWidget {
OrderRow({ OrderRow({
@required this.onTap, @required this.onTap,
@required this.provider,
this.from, this.from,
this.to, this.to,
this.createdAtFormattedDate, this.createdAtFormattedDate,
this.formattedAmount}); this.formattedAmount});
final VoidCallback onTap; final VoidCallback onTap;
final BuyProviderDescription provider;
final String from; final String from;
final String to; final String to;
final String createdAtFormattedDate; final String createdAtFormattedDate;
final String formattedAmount; final String formattedAmount;
final wyreImage =
Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final providerIcon = getBuyProviderIcon(provider);
return InkWell( return InkWell(
onTap: onTap, onTap: onTap,
child: Container( child: Container(
@ -26,7 +30,7 @@ class OrderRow extends StatelessWidget {
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
wyreImage, providerIcon ?? Offstage(),
SizedBox(width: 12), SizedBox(width: 12),
Expanded( Expanded(
child: Column( child: Column(

View file

@ -84,6 +84,7 @@ class TransactionsPage extends StatelessWidget {
onTap: () => Navigator.of(context).pushNamed( onTap: () => Navigator.of(context).pushNamed(
Routes.orderDetails, Routes.orderDetails,
arguments: order), arguments: order),
provider: order.provider,
from: order.from, from: order.from,
to: order.to, to: order.to,
createdAtFormattedDate: createdAtFormattedDate:

View file

@ -1,97 +0,0 @@
import 'dart:async';
import 'dart:io';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:cake_wallet/view_model/wyre_view_model.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WyrePage extends BasePage {
WyrePage(this.wyreViewModel,
{@required this.ordersStore, @required this.url});
final OrdersStore ordersStore;
final String url;
final WyreViewModel wyreViewModel;
@override
String get title => S.current.buy;
@override
Color get backgroundDarkColor => Colors.white;
@override
Color get titleColor => Palette.darkBlueCraiola;
@override
Widget body(BuildContext context) =>
WyrePageBody(wyreViewModel, ordersStore: ordersStore, url: url);
}
class WyrePageBody extends StatefulWidget {
WyrePageBody(this.wyreViewModel, {this.ordersStore, this.url});
final OrdersStore ordersStore;
final String url;
final WyreViewModel wyreViewModel;
@override
WyrePageBodyState createState() => WyrePageBodyState();
}
class WyrePageBodyState extends State<WyrePageBody> {
String orderId;
WebViewController _webViewController;
GlobalKey _webViewkey;
Timer _timer;
bool _isSaving;
@override
void initState() {
super.initState();
_webViewkey = GlobalKey();
_isSaving = false;
widget.ordersStore.orderId = '';
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
_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.wyreViewModel.saveOrder(orderId);
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));
}
}

View file

@ -59,14 +59,17 @@ abstract class BuyViewModelBase with Store {
CryptoCurrency get cryptoCurrency => walletTypeToCryptoCurrency(type); CryptoCurrency get cryptoCurrency => walletTypeToCryptoCurrency(type);
Future createOrder() async { Future <String> fetchUrl() async {
String _url = '';
try { try {
final url = await selectedProvider _url = await selectedProvider
?.requestUrl(doubleAmount?.toString(), fiatCurrency.title); ?.requestUrl(doubleAmount?.toString(), fiatCurrency.title);
// FIXME: Start WebView
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
} }
return _url;
} }
Future<void> saveOrder(String orderId) async { Future<void> saveOrder(String orderId) async {
@ -78,4 +81,9 @@ abstract class BuyViewModelBase with Store {
print(e.toString()); print(e.toString());
} }
} }
void reset() {
buyAmountViewModel.amount = '';
selectedProvider = null;
}
} }

View file

@ -28,7 +28,6 @@ import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_display_mode.dart'; import 'package:cake_wallet/view_model/dashboard/action_list_display_mode.dart';
import 'package:cake_wallet/view_model/wyre_view_model.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@ -59,8 +58,7 @@ abstract class DashboardViewModelBase with Store {
this.transactionFilterStore, this.transactionFilterStore,
this.settingsStore, this.settingsStore,
this.ordersSource, this.ordersSource,
this.ordersStore, this.ordersStore}) {
this.wyreViewModel}) {
filterItems = { filterItems = {
S.current.transactions: [ S.current.transactions: [
FilterItem( FilterItem(
@ -230,8 +228,6 @@ abstract class DashboardViewModelBase with Store {
TransactionFilterStore transactionFilterStore; TransactionFilterStore transactionFilterStore;
WyreViewModel wyreViewModel;
Map<String, List<FilterItem>> filterItems; Map<String, List<FilterItem>> filterItems;
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled; bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;

View file

@ -1,12 +1,16 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/utils/date_formatter.dart'; import 'package:cake_wallet/utils/date_formatter.dart';
import 'package:cake_wallet/view_model/wyre_view_model.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart'; import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
part 'order_details_view_model.g.dart'; part 'order_details_view_model.g.dart';
@ -14,16 +18,27 @@ class OrderDetailsViewModel = OrderDetailsViewModelBase
with _$OrderDetailsViewModel; with _$OrderDetailsViewModel;
abstract class OrderDetailsViewModelBase with Store { abstract class OrderDetailsViewModelBase with Store {
OrderDetailsViewModelBase({this.wyreViewModel, Order orderForDetails}) { OrderDetailsViewModelBase({WalletBase wallet, Order orderForDetails}) {
order = orderForDetails; order = orderForDetails;
if (order.provider != null) {
switch (order.provider) {
case BuyProviderDescription.wyre:
_provider = WyreBuyProvider(wallet: wallet);
break;
case BuyProviderDescription.moonPay:
_provider = MoonPayBuyProvider(wallet: wallet);
break;
}
}
items = ObservableList<StandartListItem>(); items = ObservableList<StandartListItem>();
_updateItems(); _updateItems();
_updateOrder(); _updateOrder();
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateOrder()); timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateOrder());
} }
@observable @observable
@ -32,21 +47,20 @@ abstract class OrderDetailsViewModelBase with Store {
@observable @observable
ObservableList<StandartListItem> items; ObservableList<StandartListItem> items;
WyreViewModel wyreViewModel; BuyProvider _provider;
Timer _timer; Timer timer;
@action @action
Future<void> _updateOrder() async { Future<void> _updateOrder() async {
try { try {
final updatedOrder = if (_provider != null) {
await wyreViewModel.wyreService.findOrderById(order.id); final updatedOrder = await _provider.findOrderById(order.id);
updatedOrder.receiveAddress = order.receiveAddress;
updatedOrder.receiveAddress = order.receiveAddress; updatedOrder.walletId = order.walletId;
updatedOrder.walletId = order.walletId; order = updatedOrder;
order = updatedOrder; _updateItems();
}
_updateItems();
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
} }
@ -54,8 +68,6 @@ abstract class OrderDetailsViewModelBase with Store {
void _updateItems() { void _updateItems() {
final dateFormat = DateFormatter.withCurrentLocal(); final dateFormat = DateFormatter.withCurrentLocal();
final buildURL =
wyreViewModel.trackUrl + '${order.transferId}';
items?.clear(); items?.clear();
@ -68,18 +80,37 @@ abstract class OrderDetailsViewModelBase with Store {
value: order.state != null value: order.state != null
? order.state.toString() ? order.state.toString()
: S.current.trade_details_fetching), : S.current.trade_details_fetching),
TrackTradeListItem(
title: 'Track',
value: buildURL,
onTap: () {
launch(buildURL);
}),
StandartListItem(
title: S.current.trade_details_created_at,
value: dateFormat.format(order.createdAt).toString()),
StandartListItem(
title: S.current.trade_details_pair,
value: '${order.from}${order.to}')
]); ]);
if (order.provider != null) {
items.add(
StandartListItem(
title: 'Buy provider',
value: order.provider.title)
);
}
if (_provider.trackUrl.isNotEmpty) {
final buildURL = _provider.trackUrl + '${order.transferId}';
items.add(
TrackTradeListItem(
title: 'Track',
value: buildURL,
onTap: () => launch(buildURL)
)
);
}
items.add(
StandartListItem(
title: S.current.trade_details_created_at,
value: dateFormat.format(order.createdAt).toString())
);
items.add(
StandartListItem(
title: S.current.trade_details_pair,
value: '${order.from}${order.to}')
);
} }
} }

View file

@ -1,34 +0,0 @@
import 'package:cake_wallet/entities/wyre_service.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:mobx/mobx.dart';
part 'wyre_view_model.g.dart';
class WyreViewModel = WyreViewModelBase with _$WyreViewModel;
abstract class WyreViewModelBase with Store {
WyreViewModelBase(this.ordersSource, this.ordersStore,
{@required this.wyreService});
Future<String> get wyreUrl => wyreService.getWyreUrl();
String get trackUrl => wyreService.trackUrl;
final Box<Order> ordersSource;
final OrdersStore ordersStore;
final WyreService wyreService;
Future<void> saveOrder(String orderId) async {
try {
final order = await wyreService.findOrderById(orderId);
await ordersSource.add(order);
ordersStore.setOrder(order);
} catch (e) {
print(e.toString());
}
}
}

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Unbestätigt", "unconfirmed" : "Unbestätigt",
"displayable" : "Anzeigebar", "displayable" : "Anzeigebar",
"submit_request" : "Einen Antrag stellen" "submit_request" : "Einen Antrag stellen",
"buy_bitcoin" : "Bitcoin kaufen",
"buy_with" : "Kaufen mit"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Unconfirmed", "unconfirmed" : "Unconfirmed",
"displayable" : "Displayable", "displayable" : "Displayable",
"submit_request" : "submit a request" "submit_request" : "submit a request",
"buy_bitcoin" : "Buy Bitcoin",
"buy_with" : "Buy with"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Inconfirmado", "unconfirmed" : "Inconfirmado",
"displayable" : "Visualizable", "displayable" : "Visualizable",
"submit_request" : "presentar una solicitud" "submit_request" : "presentar una solicitud",
"buy_bitcoin" : "Comprar Bitcoin",
"buy_with" : "Compra con"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "अपुष्ट", "unconfirmed" : "अपुष्ट",
"displayable" : "प्रदर्शन योग्य", "displayable" : "प्रदर्शन योग्य",
"submit_request" : "एक अनुरोध सबमिट करें" "submit_request" : "एक अनुरोध सबमिट करें",
"buy_bitcoin" : "बिटकॉइन खरीदें",
"buy_with" : "के साथ खरीदें"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "未確認", "unconfirmed" : "未確認",
"displayable" : "表示可能", "displayable" : "表示可能",
"submit_request" : "リクエストを送信する" "submit_request" : "リクエストを送信する",
"buy_bitcoin" : "ビットコインを購入する",
"buy_with" : "で購入"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "미확인", "unconfirmed" : "미확인",
"displayable" : "표시 가능", "displayable" : "표시 가능",
"submit_request" : "요청을 제출" "submit_request" : "요청을 제출",
"buy_bitcoin" : "비트 코인 구매",
"buy_with" : "구매"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Niet bevestigd", "unconfirmed" : "Niet bevestigd",
"displayable" : "Weer te geven", "displayable" : "Weer te geven",
"submit_request" : "een verzoek indienen" "submit_request" : "een verzoek indienen",
"buy_bitcoin" : "Koop Bitcoin",
"buy_with" : "Koop met"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Niepotwierdzony", "unconfirmed" : "Niepotwierdzony",
"displayable" : "Wyświetlane", "displayable" : "Wyświetlane",
"submit_request" : "złożyć wniosek" "submit_request" : "złożyć wniosek",
"buy_bitcoin" : "Kup Bitcoin",
"buy_with" : "Kup za pomocą"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Não confirmado", "unconfirmed" : "Não confirmado",
"displayable" : "Exibível", "displayable" : "Exibível",
"submit_request" : "enviar um pedido" "submit_request" : "enviar um pedido",
"buy_bitcoin" : "Compre Bitcoin",
"buy_with" : "Compre com"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Неподтвержденный", "unconfirmed" : "Неподтвержденный",
"displayable" : "Отображаемый", "displayable" : "Отображаемый",
"submit_request" : "отправить запрос" "submit_request" : "отправить запрос",
"buy_bitcoin" : "Купить Bitcoin",
"buy_with" : "Купить с помощью"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Непідтверджений", "unconfirmed" : "Непідтверджений",
"displayable" : "Відображуваний", "displayable" : "Відображуваний",
"submit_request" : "надіслати запит" "submit_request" : "надіслати запит",
"buy_bitcoin" : "Купити Bitcoin",
"buy_with" : "Купити за допомогою"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "未经证实", "unconfirmed" : "未经证实",
"displayable" : "可显示", "displayable" : "可显示",
"submit_request" : "提交請求" "submit_request" : "提交請求",
"buy_bitcoin" : "購買比特幣",
"buy_with" : "與一起購買"
} }