onramper order

This commit is contained in:
Serhii 2024-02-12 13:21:46 +02:00
parent 39a73b2058
commit 3b71b679bb
21 changed files with 361 additions and 342 deletions

View file

@ -1,6 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/buy/buy_provider_description.dart';
class BuyException implements Exception {
BuyException({required this.title, required this.content});

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/buy/buy_amount.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:flutter/material.dart';
@ -20,6 +21,10 @@ abstract class BuyProvider {
String get darkIcon;
ProviderType get providerType;
String get trackUrl;
@override
String toString() => title;

View file

@ -1,21 +0,0 @@
import 'package:cw_core/enumerable_item.dart';
class BuyProviderDescription extends EnumerableItem<int>
with Serializable<int> {
const BuyProviderDescription({required String title, required int raw})
: super(title: title, raw: raw);
static const wyre = BuyProviderDescription(title: 'Wyre', raw: 0);
static const moonPay = BuyProviderDescription(title: 'MoonPay', raw: 1);
static BuyProviderDescription deserialize({required int raw}) {
switch (raw) {
case 0:
return wyre;
case 1:
return moonPay;
default:
throw Exception('Incorrect token $raw for BuyProviderDescription deserialize');
}
}
}

View file

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
@ -23,7 +24,10 @@ class DFXBuyProvider extends BuyProvider {
static const walletName = 'CakeWallet';
@override
String get title => 'DFX Connect';
ProviderType get providerType => ProviderType.dfx;
@override
String get title => providerType.title;
@override
String get providerDescription => S.current.dfx_option_description;
@ -34,6 +38,9 @@ class DFXBuyProvider extends BuyProvider {
@override
String get darkIcon => 'assets/images/dfx_dark.png';
@override
String get trackUrl => 'https://dash.dfx.swiss/track/';
String get assetOut {
switch (wallet.type) {
case WalletType.bitcoin:
@ -186,7 +193,7 @@ class DFXBuyProvider extends BuyProvider {
if (await canLaunchUrl(uri)) {
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [title, uri]);
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [uri, providerType]);
} else {
await launchUrl(uri, mode: LaunchMode.externalApplication);
}

View file

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

View file

@ -1,4 +1,5 @@
import 'dart:convert';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
@ -12,7 +13,6 @@ import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/buy/buy_amount.dart';
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:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
@ -36,11 +36,14 @@ class MoonPaySellProvider extends BuyProvider {
static const _baseProductUrl = 'sell.moonpay.com';
@override
String get providerDescription =>
'MoonPay offers a fast and simple way to buy and sell cryptocurrencies';
ProviderType get providerType => ProviderType.moonpaySell;
@override
String get title => 'MoonPay';
String get title => providerType.title;
@override
String get providerDescription =>
'MoonPay offers a fast and simple way to buy and sell cryptocurrencies';
@override
String get lightIcon => 'assets/images/moonpay_light.png';
@ -48,6 +51,9 @@ class MoonPaySellProvider extends BuyProvider {
@override
String get darkIcon => 'assets/images/moonpay_dark.png';
@override
String get trackUrl => '';
static String themeToMoonPayTheme(ThemeBase theme) {
switch (theme.type) {
case ThemeType.bright:
@ -113,7 +119,7 @@ class MoonPaySellProvider extends BuyProvider {
if (await canLaunchUrl(uri)) {
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: ['MoonPay', uri]);
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [uri]);
} else {
await launchUrl(uri, mode: LaunchMode.externalApplication);
}
@ -152,7 +158,10 @@ class MoonPayBuyProvider extends BuyProvider {
static const _secretKey = secrets.moonPaySecretKey;
@override
String get title => 'MoonPay';
ProviderType get providerType => ProviderType.moonpaySell;
@override
String get title => providerType.name;
@override
String get providerDescription =>
@ -247,7 +256,7 @@ class MoonPayBuyProvider extends BuyProvider {
return Order(
id: id,
provider: BuyProviderDescription.moonPay,
provider: ProviderType.moonpaySell,
transferId: id,
state: state,
createdAt: createdAt,

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/store/settings_store.dart';
@ -9,18 +10,32 @@ import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:collection/collection.dart';
enum OnRamperPartner {
guardarian,
paybis,
}
class OnRamperBuyProvider extends BuyProvider {
OnRamperBuyProvider(this._settingsStore,
{required WalletBase wallet, bool isTestEnvironment = false})
OnRamperBuyProvider({this.settingsStore,this.partner,
required WalletBase wallet, bool isTestEnvironment = false})
: super(wallet: wallet, isTestEnvironment: isTestEnvironment);
static const _baseUrl = 'buy.onramper.com';
final SettingsStore _settingsStore;
static OnRamperPartner? fromRaw(int? raw) =>
OnRamperPartner.values.firstWhereOrNull((e) => e.index == raw);
final SettingsStore? settingsStore;
OnRamperPartner? partner;
@override
String get title => 'Onramper';
ProviderType get providerType => ProviderType.onramper;
@override
String get title => providerType.title;
@override
String get providerDescription => S.current.onramper_option_description;
@ -31,6 +46,17 @@ class OnRamperBuyProvider extends BuyProvider {
@override
String get darkIcon => 'assets/images/onramper_dark.png';
String get trackUrl {
switch (partner) {
case OnRamperPartner.guardarian:
return "https://payments.guardarian.com/checkout?tid=";
case OnRamperPartner.paybis:
return "https://widget.paybis.com/?requestId=";
default:
return '';
}
}
String get _apiKey => secrets.onramperApiKey;
String get _normalizeCryptoCurrency {
@ -69,8 +95,10 @@ class OnRamperBuyProvider extends BuyProvider {
containerColor = getColorStr(Theme.of(context).colorScheme.background);
cardColor = getColorStr(Theme.of(context).cardColor);
if (_settingsStore.currentTheme.title == S.current.high_contrast_theme) {
cardColor = getColorStr(Colors.white);
if (settingsStore != null) {
if (settingsStore!.currentTheme.title == S.current.high_contrast_theme) {
cardColor = getColorStr(Colors.white);
}
}
final networkName =
@ -96,7 +124,7 @@ class OnRamperBuyProvider extends BuyProvider {
final uri = requestOnramperUrl(context, isBuyAction);
if (DeviceInfo.instance.isMobile) {
Navigator.of(context)
.pushNamed(Routes.webViewPage, arguments: [title, uri]);
.pushNamed(Routes.webViewPage, arguments:[uri, providerType]);
} else {
await launchUrl(uri);
}

View file

@ -1,31 +1,60 @@
import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'dart:convert';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cw_core/format_amount.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
import 'onramper/onramper_buy_provider.dart';
part 'order.g.dart';
@HiveType(typeId: Order.typeId)
class Order extends HiveObject {
Order(
{required this.id,
required this.transferId,
required this.createdAt,
required this.amount,
required this.receiveAddress,
required this.walletId,
BuyProviderDescription? provider,
TradeState? state,
this.from,
this.to}) {
if (provider != null) {
providerRaw = provider.raw;
}
if (state != null) {
stateRaw = state.raw;
}
required this.transferId,
required this.createdAt,
required this.amount,
required this.receiveAddress,
required this.walletId,
ProviderType? provider,
OnRamperPartner? onramperPartner,
TradeState? state,
this.from,
this.to}) {
if (provider != null) {
providerRaw = ProvidersHelper.serialize(provider);
}
if (onramperPartner != null) {
onramperPartnerRaw = onramperPartner.index;
}
if (state != null) {
stateRaw = state.raw;
}
}
factory Order.fromJSON(String jsonSource) {
final decoded = json.decode(jsonSource) as Map<String, dynamic>;
final providerRaw = decoded['providerRaw'] as int?;
final onramperPartnerRaw = decoded['onramperPartnerRaw'] as int?;
return Order(
id: decoded['id'] as String,
transferId: decoded['transferId'] as String? ?? '',
createdAt: DateTime.parse(decoded['createdAt'] as String),
amount: decoded['amount'] as String? ?? '',
receiveAddress: decoded['receiveAddress'] as String? ?? '',
walletId: decoded['walletId'] as String? ?? '',
provider: providerRaw != null ? ProvidersHelper.deserialize(raw: providerRaw) : null,
onramperPartner:
onramperPartnerRaw != null ? OnRamperBuyProvider.fromRaw(onramperPartnerRaw) : null,
state: TradeState.created,
from: decoded['from'] as String?,
to: decoded['to'] as String?,
);
}
static const typeId = ORDER_TYPE_ID;
static const boxName = 'Orders';
@ -44,9 +73,7 @@ class Order extends HiveObject {
String? to;
@HiveField(4, defaultValue: '')
late String stateRaw;
TradeState get state => TradeState.deserialize(raw: stateRaw);
String? stateRaw;
@HiveField(5)
DateTime createdAt;
@ -60,11 +87,19 @@ class Order extends HiveObject {
@HiveField(8, defaultValue: '')
String walletId;
@HiveField(9, defaultValue: 0)
late int providerRaw;
@HiveField(9)
int? providerRaw;
BuyProviderDescription get provider =>
BuyProviderDescription.deserialize(raw: providerRaw);
@HiveField(10)
int? onramperPartnerRaw;
TradeState? get state => stateRaw != null ? TradeState.deserialize(raw: stateRaw!) : null;
ProviderType? get provider =>
providerRaw != null ? ProvidersHelper.deserialize(raw: providerRaw!) : null;
OnRamperPartner? get onramperPartner =>
onramperPartnerRaw != null ? OnRamperBuyProvider.fromRaw(onramperPartnerRaw!) : null;
String amountFormatted() => formatAmount(amount);
}

View file

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
@ -19,7 +20,10 @@ class RobinhoodBuyProvider extends BuyProvider {
static const _cIdBaseUrl = 'exchange-helper.cakewallet.com';
@override
String get title => 'Robinhood Connect';
ProviderType get providerType => ProviderType.robinhood;
@override
String get title => providerType.title;
@override
String get providerDescription => S.current.robinhood_option_description;
@ -30,6 +34,9 @@ class RobinhoodBuyProvider extends BuyProvider {
@override
String get darkIcon => 'assets/images/robinhood_dark.png';
@override
String get trackUrl => '';
String get _applicationId => secrets.robinhoodApplicationId;
String get _apiSecret => secrets.robinhoodCIdApiSecret;

View file

@ -1,10 +1,10 @@
import 'dart:convert';
import 'package:cake_wallet/buy/buy_exception.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/buy/buy_amount.dart';
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:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
@ -30,17 +30,21 @@ class WyreBuyProvider extends BuyProvider {
static const _secretKey = secrets.wyreSecretKey;
static const _accountId = secrets.wyreAccountId;
@override
String get title => 'Wyre';
ProviderType get providerType => ProviderType.wyre;
@override
String get title => providerType.title;
@override
String get providerDescription => '';
@override
String get lightIcon => 'assets/images/robinhood_light.png';
String get lightIcon => 'assets/images/wyre-icon.png';
@override
String get darkIcon => 'assets/images/robinhood_dark.png';
String get darkIcon => 'assets/images/wyre-icon.png';
String get trackUrl => isTestEnvironment ? _trackTestUrl : _trackProductUrl;
@ -138,7 +142,7 @@ class WyreBuyProvider extends BuyProvider {
return Order(
id: id,
provider: BuyProviderDescription.wyre,
provider: ProviderType.wyre,
transferId: transferId,
from: from,
to: to,

View file

@ -120,7 +120,6 @@ import 'package:cake_wallet/exchange/trade.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/edit_backup_password_page.dart';
import 'package:cake_wallet/src/screens/buy/buy_webview_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/exchange_trade/exchange_confirm_page.dart';
@ -231,6 +230,7 @@ import 'package:cake_wallet/entities/qr_view_data.dart';
import 'buy/dfx/dfx_buy_provider.dart';
import 'core/totp_request_details.dart';
import 'entities/provider_types.dart';
import 'src/screens/settings/desktop_settings/desktop_settings_page.dart';
final getIt = GetIt.instance;
@ -808,11 +808,16 @@ Future<void> setup({
settingsStore: getIt.get<AppStore>().settingsStore, wallet: getIt.get<AppStore>().wallet!));
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
getIt.get<AppStore>().settingsStore,
settingsStore: getIt.get<AppStore>().settingsStore,
wallet: getIt.get<AppStore>().wallet!,
));
getIt.registerFactoryParam<WebViewPage, String, Uri>((title, uri) => WebViewPage(title, uri));
getIt.registerFactoryParam<WebViewPage,List<dynamic>, void>((args, _) {
final uri = args.first as Uri;
final type = args.length > 1 ? args[1] as ProviderType? : null;
return WebViewPage(uri, type, buyViewModel: getIt.get<BuyViewModel>());
});
getIt.registerFactory<PayfuraBuyProvider>(() => PayfuraBuyProvider(
settingsStore: getIt.get<AppStore>().settingsStore,
@ -954,21 +959,14 @@ Future<void> setup({
getIt.registerFactoryParam<BuySellOptionsPage, bool, void>(
(isBuyOption, _) => BuySellOptionsPage(getIt.get<DashboardViewModel>(), isBuyOption));
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;
getIt.registerFactory(() => BuyViewModel(
_ordersSource,
getIt.get<OrdersStore>(),
getIt.get<SettingsStore>(),
getIt.get<BuyAmountViewModel>(),
wallet: getIt.get<AppStore>().wallet!));
return BuyViewModel(_ordersSource, getIt.get<OrdersStore>(), getIt.get<SettingsStore>(),
getIt.get<BuyAmountViewModel>(),
wallet: wallet!);
});
getIt.registerFactoryParam<BuyWebViewPage, List<dynamic>, void>((List<dynamic> 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, _) {
final wallet = getIt.get<AppStore>().wallet;

View file

@ -3,6 +3,7 @@ import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
import 'package:cake_wallet/di.dart';
import 'package:cw_core/wallet_type.dart';
@ -12,6 +13,7 @@ enum ProviderType {
dfx,
onramper,
moonpaySell,
wyre,
}
extension ProviderTypeName on ProviderType {
@ -27,6 +29,8 @@ extension ProviderTypeName on ProviderType {
return 'Onramper';
case ProviderType.moonpaySell:
return 'MoonPay';
case ProviderType.wyre:
return 'Wyre';
}
}
@ -42,6 +46,8 @@ extension ProviderTypeName on ProviderType {
return 'onramper_provider';
case ProviderType.moonpaySell:
return 'moonpay_provider';
case ProviderType.wyre:
return 'wyre_provider';
}
}
}
@ -105,10 +111,50 @@ class ProvidersHelper {
return getIt.get<DFXBuyProvider>();
case ProviderType.onramper:
return getIt.get<OnRamperBuyProvider>();
case ProviderType.askEachTime:
return null;
case ProviderType.moonpaySell:
return getIt.get<MoonPaySellProvider>();
case ProviderType.wyre:
return getIt.get<WyreBuyProvider>();
case ProviderType.askEachTime:
return null;
}
}
static int serialize(ProviderType type) {
switch (type) {
case ProviderType.askEachTime:
return 0;
case ProviderType.robinhood:
return 1;
case ProviderType.dfx:
return 2;
case ProviderType.onramper:
return 3;
case ProviderType.moonpaySell:
return 4;
case ProviderType.wyre:
return 5;
default:
throw Exception('Incorrect token $type for ProviderType serialize');
}
}
static ProviderType deserialize({required int raw}) {
switch (raw) {
case 0:
return ProviderType.askEachTime;
case 1:
return ProviderType.robinhood;
case 2:
return ProviderType.dfx;
case 3:
return ProviderType.onramper;
case 4:
return ProviderType.moonpaySell;
case 5:
return ProviderType.wyre;
default:
throw Exception('Incorrect token $raw for ProviderType deserialize');
}
}
}

View file

@ -10,7 +10,6 @@ import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dar
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/buy/buy_options_page.dart';
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
import 'package:cake_wallet/src/screens/buy/webview_page.dart';
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
@ -396,12 +395,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
return MaterialPageRoute<void>(
builder: (_) => getIt.get<BuySellOptionsPage>(param1: args));
case Routes.buyWebView:
final args = settings.arguments as List;
return MaterialPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<BuyWebViewPage>(param1: args));
case Routes.exchange:
return CupertinoPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<ExchangePage>());
@ -526,10 +519,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.webViewPage:
final args = settings.arguments as List;
final title = args.first as String;
final url = args[1] as Uri;
return CupertinoPageRoute<void>(
builder: (_) => getIt.get<WebViewPage>(param1: title, param2: url));
builder: (_) => getIt.get<WebViewPage>(param1: args));
case Routes.advancedPrivacySettings:
final type = settings.arguments as WalletType;

View file

@ -42,7 +42,7 @@ class BuySellOptionsPage extends BasePage {
padding: EdgeInsets.only(top: 24),
child: OptionTile(
image: icon,
title: provider.toString(),
title: provider.title,
description: provider.providerDescription,
onPressed: () => provider.launchProvider(context, isBuyAction),
),

View file

@ -1,110 +0,0 @@
import 'dart:async';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
import 'package:cake_wallet/generated/i18n.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:flutter_inappwebview/flutter_inappwebview.dart';
class BuyWebViewPage extends BasePage {
BuyWebViewPage({required 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
Widget body(BuildContext context) =>
BuyWebViewPageBody(buyViewModel, ordersStore: ordersStore, url: url);
}
class BuyWebViewPageBody extends StatefulWidget {
BuyWebViewPageBody(this.buyViewModel, {required this.ordersStore, this.url});
final OrdersStore ordersStore;
final String? url;
final BuyViewModel buyViewModel;
@override
BuyWebViewPageBodyState createState() => BuyWebViewPageBodyState();
}
class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
BuyWebViewPageBodyState()
: _webViewkey = GlobalKey(),
_isSaving = false,
orderId = '';
String orderId;
InAppWebViewController? _webViewController;
GlobalKey _webViewkey;
Timer? _timer;
bool _isSaving;
@override
void initState() {
super.initState();
_webViewkey = GlobalKey();
_isSaving = false;
widget.ordersStore.orderId = '';
if (widget.buyViewModel.selectedProvider is WyreBuyProvider) {
_saveOrder(keyword: 'completed', splitSymbol: '/');
}
if (widget.buyViewModel.selectedProvider is MoonPayBuyProvider) {
_saveOrder(keyword: 'transactionId', splitSymbol: '=');
}
}
@override
Widget build(BuildContext context) {
return InAppWebView(
key: _webViewkey,
initialSettings: InAppWebViewSettings(
transparentBackground: true,
),
initialUrlRequest: URLRequest(url: WebUri(widget.url ?? '')),
onWebViewCreated: (InAppWebViewController controller) =>
setState(() => _webViewController = controller));
}
void _saveOrder({required String keyword, required String splitSymbol}) {
_timer?.cancel();
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
try {
if (_webViewController == null || _isSaving) {
return;
}
final url = (await _webViewController!.getUrl())?.toString();
if (url == null) {
throw Exception('_saveOrder: Url is null');
}
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

@ -1,31 +1,39 @@
import 'dart:async';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:permission_handler/permission_handler.dart';
class WebViewPage extends BasePage {
WebViewPage(this._title, this._url);
WebViewPage(this._url, this._providerType, {required this.buyViewModel}) {
buyViewModel.selectedProviderType = _providerType;
}
final String _title;
final Uri _url;
final ProviderType? _providerType;
final BuyViewModel buyViewModel;
@override
String get title => _title;
String get title => _providerType?.title ?? '';
@override
Widget body(BuildContext context) {
return WebViewPageBody(_title, _url);
return WebViewPageBody(title, _url, buyViewModel);
}
}
class WebViewPageBody extends StatefulWidget {
WebViewPageBody(this.title, this.uri);
WebViewPageBody(this.title, this.uri, this.buyViewModel);
final String title;
final Uri uri;
final BuyViewModel buyViewModel;
@override
WebViewPageBodyState createState() => WebViewPageBodyState();
@ -41,6 +49,12 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
transparentBackground: true,
),
initialUrlRequest: URLRequest(url: WebUri.uri(widget.uri)),
onWebViewCreated: (InAppWebViewController controller) =>
setState(() => controller),
onLoadStart: (controller, url) async {
if (widget.buyViewModel.selectedProviderType == null) return;
widget.buyViewModel.processProviderUrl(urlStr: url.toString());
},
onPermissionRequest: (controller, request) async {
bool permissionGranted = await Permission.camera.status == PermissionStatus.granted;
if (!permissionGranted) {
@ -70,9 +84,8 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
return PermissionResponse(
resources: request.resources,
action: permissionGranted
? PermissionResponseAction.GRANT
: PermissionResponseAction.DENY,
action:
permissionGranted ? PermissionResponseAction.GRANT : PermissionResponseAction.DENY,
);
},
);

View file

@ -1,5 +1,4 @@
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/get_buy_provider_icon.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/palette.dart';

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/anonpay_transaction_row.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/order_row.dart';
import 'package:cake_wallet/themes/extensions/placeholder_theme.dart';
@ -47,7 +48,6 @@ class TransactionsPage extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(24, 0, 24, 8),
child: DashBoardRoundedCardWidget(
onTap: () => Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [
'',
Uri.parse(
'https://guides.cakewallet.com/docs/FAQ/why_are_my_funds_not_appearing/')
]),
@ -127,12 +127,13 @@ class TransactionsPage extends StatelessWidget {
if (item is OrderListItem) {
final order = item.order;
if (order.provider == null) return null;
return Observer(
builder: (_) => OrderRow(
onTap: () => Navigator.of(context)
.pushNamed(Routes.orderDetails, arguments: order),
provider: order.provider,
provider: ProvidersHelper.getProviderByType(order.provider!)!,
from: order.from!,
to: order.to!,
createdAtFormattedDate:

View file

@ -1,7 +1,6 @@
import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/buy/get_buy_provider_icon.dart';
import 'package:cake_wallet/themes/extensions/order_theme.dart';
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
@ -14,7 +13,7 @@ class OrderRow extends StatelessWidget {
this.onTap,
this.formattedAmount});
final VoidCallback? onTap;
final BuyProviderDescription provider;
final BuyProvider provider;
final String from;
final String to;
final String createdAtFormattedDate;
@ -22,10 +21,8 @@ class OrderRow extends StatelessWidget {
@override
Widget build(BuildContext context) {
final iconColor =
Theme.of(context).extension<OrderTheme>()!.iconColor;
final isLightMode = Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
final providerIcon = getBuyProviderIcon(provider, iconColor: iconColor);
return InkWell(
onTap: onTap,
@ -36,10 +33,12 @@ class OrderRow extends StatelessWidget {
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (providerIcon != null) Padding(
padding: EdgeInsets.only(right: 12),
child: providerIcon,
Container(
height: 36,
width: 36,
child: Image.asset(isLightMode ? provider.lightIcon : provider.darkIcon),
),
SizedBox(width: 12),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,

View file

@ -1,16 +1,19 @@
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
import 'package:cw_core/crypto_currency.dart';
import 'dart:async';
import 'dart:convert';
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/buy/buy_item.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';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'buy_amount_view_model.dart';
part 'buy_view_model.g.dart';
@ -18,14 +21,13 @@ part 'buy_view_model.g.dart';
class BuyViewModel = BuyViewModelBase with _$BuyViewModel;
abstract class BuyViewModelBase with Store {
BuyViewModelBase(this.ordersSource, this.ordersStore, this.settingsStore,
this.buyAmountViewModel, {required this.wallet})
: isRunning = false,
isDisabled = true,
isShowProviderButtons = false,
items = <BuyItem>[] {
_fetchBuyItems();
}
BuyViewModelBase(this.ordersSource, this.ordersStore, this.settingsStore, this.buyAmountViewModel,
{required this.wallet})
: isRunning = false,
orderId = '',
isDisabled = true,
isShowProviderButtons = false,
items = <BuyItem>[] {}
final Box<Order> ordersSource;
final OrdersStore ordersStore;
@ -33,8 +35,9 @@ abstract class BuyViewModelBase with Store {
final BuyAmountViewModel buyAmountViewModel;
final WalletBase wallet;
@observable
BuyProvider? selectedProvider;
String orderId;
ProviderType? selectedProviderType;
@observable
List<BuyItem> items;
@ -57,23 +60,24 @@ abstract class BuyViewModelBase with Store {
CryptoCurrency get cryptoCurrency => walletTypeToCryptoCurrency(type);
Future <String> fetchUrl() async {
String _url = '';
Future<void> saveOrder(String orderId, {int? onRamperPartnerRaw}) async {
try {
_url = await selectedProvider!.requestUrl(doubleAmount.toString(), fiatCurrency.title);
} catch (e) {
print(e.toString());
}
final String jsonSource = json.encode({
'id': orderId,
'transferId': orderId,
'createdAt': DateTime.now().toIso8601String(),
'amount': doubleAmount.toString(),
'receiveAddress': 'address123',
'walletId': wallet.id,
'providerRaw': ProvidersHelper.serialize(selectedProviderType ?? ProviderType.askEachTime),
'onramperPartnerRaw': onRamperPartnerRaw,
'stateRaw': 'created',
'from': fiatCurrency.title,
'to': cryptoCurrency.title,
}).toString();
return _url;
}
final order = Order.fromJSON(jsonSource);
Future<void> saveOrder(String orderId) async {
try {
final order = await selectedProvider!.findOrderById(orderId);
order.from = fiatCurrency.title;
order.to = cryptoCurrency.title;
await ordersSource.add(order);
ordersStore.setOrder(order);
} catch (e) {
@ -81,32 +85,80 @@ abstract class BuyViewModelBase with Store {
}
}
void reset() {
buyAmountViewModel.amount = '';
selectedProvider = null;
String? extractInfoFromUrl(String url, ProviderType providerType) {
final config = providerUrlConfigs[providerType];
if (config == null) return null;
for (var entry in config.parameterKeywords.entries) {
final keyword = entry.value;
final paramIndex = url.indexOf('$keyword=');
if (paramIndex != -1) {
final start = paramIndex + keyword.length + 1;
int end = config.splitSymbol != null ? url.indexOf(config.splitSymbol!, start) : url.length;
end = end == -1 ? url.length : end;
return url.substring(start, end);
}
}
return null;
}
Future<void> _fetchBuyItems() async {
final List<BuyProvider> _providerList = [];
void processProviderUrl({required String urlStr}) async {
if (selectedProviderType == null) return;
if (wallet.type == WalletType.bitcoin) {
_providerList.add(WyreBuyProvider(wallet: wallet));
final orderId = extractInfoFromUrl(urlStr, selectedProviderType!);
final onRamperPartner = determineOnRamperPartner(urlStr); // Determine the partner
final onRamperPartnerRaw = onRamperPartner != null ? onRamperPartner.index : null; // Serialize the partner for storage
if (orderId != null && orderId.isNotEmpty && orderId != this.orderId) {
this.orderId = orderId;
await saveOrder(orderId, onRamperPartnerRaw: onRamperPartnerRaw); // Pass the partner information
}
var isMoonPayEnabled = false;
try {
isMoonPayEnabled = await MoonPayBuyProvider.onEnabled();
} catch (e) {
isMoonPayEnabled = false;
print(e.toString());
}
if (isMoonPayEnabled) {
_providerList.add(MoonPayBuyProvider(wallet: wallet));
}
items = _providerList.map((provider) =>
BuyItem(provider: provider, buyAmountViewModel: buyAmountViewModel))
.toList();
}
}
OnRamperPartner? determineOnRamperPartner(String url) {
if (url.contains('guardarian')) {
return OnRamperPartner.guardarian;
} else if (url.contains('paybis')) {
return OnRamperPartner.paybis;
}
// Add more partners as needed
return null;
}
final Map<ProviderType, ProviderUrlConfig> providerUrlConfigs = {
ProviderType.onramper: ProviderUrlConfig(
name: ProviderType.onramper.title,
parameterKeywords: {
'guardarian': 'tid',
'paybis': 'requestId',
},
splitSymbol: '&',
),
ProviderType.dfx: ProviderUrlConfig(
name: ProviderType.dfx.title,
parameterKeywords: {
'transaction': 'id', // Adjust based on actual URL scheme.
},
),
ProviderType.robinhood: ProviderUrlConfig(
name: ProviderType.robinhood.title,
parameterKeywords: {
'order': 'ref', // Adjust based on actual URL scheme.
},
),
// Add more providers as necessary, using their titles.
};
}
class ProviderUrlConfig {
final String name;
final Map<String, String> parameterKeywords;
final String? splitSymbol;
ProviderUrlConfig({required this.name, required this.parameterKeywords, this.splitSymbol});
}

View file

@ -1,7 +1,8 @@
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/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/utils/date_formatter.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -9,8 +10,6 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.d
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
part 'order_details_view_model.g.dart';
@ -21,17 +20,11 @@ abstract class OrderDetailsViewModelBase with Store {
OrderDetailsViewModelBase({required WalletBase wallet, required Order orderForDetails})
: items = ObservableList<StandartListItem>(),
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;
}
if (order.provider != null) {
order.provider == ProviderType.onramper
? _provider = OnRamperBuyProvider(wallet: wallet, partner: order.onramperPartner)
: _provider = ProvidersHelper.getProviderByType(order.provider!);
}
_updateItems();
_updateOrder();
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateOrder());
@ -50,20 +43,16 @@ abstract class OrderDetailsViewModelBase with Store {
@action
Future<void> _updateOrder() async {
try {
if (_provider != null && (_provider is MoonPayBuyProvider || _provider is WyreBuyProvider)) {
final updatedOrder = _provider is MoonPayBuyProvider
? await (_provider as MoonPayBuyProvider).findOrderById(order.id)
: await (_provider as WyreBuyProvider).findOrderById(order.id);
final updatedOrder = await _provider!.findOrderById(order.transferId);
updatedOrder.from = order.from;
updatedOrder.to = order.to;
updatedOrder.receiveAddress = order.receiveAddress;
updatedOrder.walletId = order.walletId;
if (order.provider != null) {
updatedOrder.providerRaw = order.provider.raw;
}
updatedOrder.providerRaw = order.provider != null
? ProvidersHelper.serialize(order.provider!) : null;
order = updatedOrder;
_updateItems();
}
} catch (e) {
print(e.toString());
}
@ -86,24 +75,19 @@ abstract class OrderDetailsViewModelBase with Store {
items.add(
StandartListItem(
title: 'Buy provider',
value: order.provider.title)
value: order.provider?.title ?? '')
);
if (_provider != null && (_provider is MoonPayBuyProvider || _provider is WyreBuyProvider)) {
final trackUrl = _provider is MoonPayBuyProvider
? (_provider as MoonPayBuyProvider).trackUrl
: (_provider as WyreBuyProvider).trackUrl;
if (trackUrl.isNotEmpty ?? false) {
final buildURL = trackUrl + '${order.transferId}';
if(_provider != null) {
if(_provider!.trackUrl.isNotEmpty && order.transferId.isNotEmpty) {
final buildURL = _provider!.trackUrl + '${order.transferId}';
items.add(
TrackTradeListItem(
title: 'Track',
value: buildURL,
onTap: () {
try {
launch(buildURL);
launchUrl(Uri.parse(buildURL));
} catch (e) {}
}
)