From 3b71b679bb22e3cb92e25c37a5f23f007a61eef0 Mon Sep 17 00:00:00 2001 From: Serhii Date: Mon, 12 Feb 2024 13:21:46 +0200 Subject: [PATCH] onramper order --- lib/buy/buy_exception.dart | 3 - lib/buy/buy_provider.dart | 5 + lib/buy/buy_provider_description.dart | 21 --- lib/buy/dfx/dfx_buy_provider.dart | 11 +- lib/buy/get_buy_provider_icon.dart | 25 --- lib/buy/moonpay/moonpay_provider.dart | 23 ++- lib/buy/onramper/onramper_buy_provider.dart | 42 ++++- lib/buy/order.dart | 81 ++++++--- lib/buy/robinhood/robinhood_buy_provider.dart | 9 +- lib/buy/wyre/wyre_buy_provider.dart | 14 +- lib/di.dart | 30 ++-- lib/entities/provider_types.dart | 50 +++++- lib/router.dart | 11 +- lib/src/screens/buy/buy_options_page.dart | 2 +- lib/src/screens/buy/buy_webview_page.dart | 110 ------------ lib/src/screens/buy/webview_page.dart | 29 ++- .../screens/buy/widgets/buy_list_item.dart | 1 - .../dashboard/pages/transactions_page.dart | 5 +- .../screens/dashboard/widgets/order_row.dart | 19 +- lib/view_model/buy/buy_view_model.dart | 166 ++++++++++++------ lib/view_model/order_details_view_model.dart | 46 ++--- 21 files changed, 361 insertions(+), 342 deletions(-) delete mode 100644 lib/buy/buy_provider_description.dart delete mode 100644 lib/buy/get_buy_provider_icon.dart delete mode 100644 lib/src/screens/buy/buy_webview_page.dart diff --git a/lib/buy/buy_exception.dart b/lib/buy/buy_exception.dart index c201b3b2d..76fc7086a 100644 --- a/lib/buy/buy_exception.dart +++ b/lib/buy/buy_exception.dart @@ -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}); diff --git a/lib/buy/buy_provider.dart b/lib/buy/buy_provider.dart index 4e4c113f4..75db01f96 100644 --- a/lib/buy/buy_provider.dart +++ b/lib/buy/buy_provider.dart @@ -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; diff --git a/lib/buy/buy_provider_description.dart b/lib/buy/buy_provider_description.dart deleted file mode 100644 index 07c7ff08b..000000000 --- a/lib/buy/buy_provider_description.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:cw_core/enumerable_item.dart'; - -class BuyProviderDescription extends EnumerableItem - with Serializable { - 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'); - } - } -} \ No newline at end of file diff --git a/lib/buy/dfx/dfx_buy_provider.dart b/lib/buy/dfx/dfx_buy_provider.dart index 8e2d58d11..c4e104992 100644 --- a/lib/buy/dfx/dfx_buy_provider.dart +++ b/lib/buy/dfx/dfx_buy_provider.dart @@ -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); } diff --git a/lib/buy/get_buy_provider_icon.dart b/lib/buy/get_buy_provider_icon.dart deleted file mode 100644 index c755d9615..000000000 --- a/lib/buy/get_buy_provider_icon.dart +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/lib/buy/moonpay/moonpay_provider.dart b/lib/buy/moonpay/moonpay_provider.dart index 0ccb73e1c..b85b04771 100644 --- a/lib/buy/moonpay/moonpay_provider.dart +++ b/lib/buy/moonpay/moonpay_provider.dart @@ -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, diff --git a/lib/buy/onramper/onramper_buy_provider.dart b/lib/buy/onramper/onramper_buy_provider.dart index 3819f074d..3c4df5c1c 100644 --- a/lib/buy/onramper/onramper_buy_provider.dart +++ b/lib/buy/onramper/onramper_buy_provider.dart @@ -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); } diff --git a/lib/buy/order.dart b/lib/buy/order.dart index 5a677d291..27147d14d 100644 --- a/lib/buy/order.dart +++ b/lib/buy/order.dart @@ -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; + 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); } diff --git a/lib/buy/robinhood/robinhood_buy_provider.dart b/lib/buy/robinhood/robinhood_buy_provider.dart index 47c3ab1ea..ba65fe117 100644 --- a/lib/buy/robinhood/robinhood_buy_provider.dart +++ b/lib/buy/robinhood/robinhood_buy_provider.dart @@ -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; diff --git a/lib/buy/wyre/wyre_buy_provider.dart b/lib/buy/wyre/wyre_buy_provider.dart index 4dd091c33..0442f439a 100644 --- a/lib/buy/wyre/wyre_buy_provider.dart +++ b/lib/buy/wyre/wyre_buy_provider.dart @@ -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, diff --git a/lib/di.dart b/lib/di.dart index 05019a562..7edcffa73 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -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 setup({ settingsStore: getIt.get().settingsStore, wallet: getIt.get().wallet!)); getIt.registerFactory(() => OnRamperBuyProvider( - getIt.get().settingsStore, + settingsStore: getIt.get().settingsStore, wallet: getIt.get().wallet!, )); - getIt.registerFactoryParam((title, uri) => WebViewPage(title, uri)); + getIt.registerFactoryParam, 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()); + }); + getIt.registerFactory(() => PayfuraBuyProvider( settingsStore: getIt.get().settingsStore, @@ -954,21 +959,14 @@ Future setup({ getIt.registerFactoryParam( (isBuyOption, _) => BuySellOptionsPage(getIt.get(), isBuyOption)); - getIt.registerFactory(() { - final wallet = getIt.get().wallet; + getIt.registerFactory(() => BuyViewModel( + _ordersSource, + getIt.get(), + getIt.get(), + getIt.get(), + wallet: getIt.get().wallet!)); - return BuyViewModel(_ordersSource, getIt.get(), getIt.get(), - getIt.get(), - wallet: wallet!); - }); - getIt.registerFactoryParam, void>((List args, _) { - final url = args.first as String; - final buyViewModel = args[1] as BuyViewModel; - - return BuyWebViewPage( - buyViewModel: buyViewModel, ordersStore: getIt.get(), url: url); - }); getIt.registerFactoryParam((order, _) { final wallet = getIt.get().wallet; diff --git a/lib/entities/provider_types.dart b/lib/entities/provider_types.dart index ed688590c..39ba32e7d 100644 --- a/lib/entities/provider_types.dart +++ b/lib/entities/provider_types.dart @@ -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(); case ProviderType.onramper: return getIt.get(); - case ProviderType.askEachTime: - return null; case ProviderType.moonpaySell: return getIt.get(); + case ProviderType.wyre: + return getIt.get(); + 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'); } } } diff --git a/lib/router.dart b/lib/router.dart index b7b7c9a8e..fa8f5480c 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -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 createRoute(RouteSettings settings) { return MaterialPageRoute( builder: (_) => getIt.get(param1: args)); - case Routes.buyWebView: - final args = settings.arguments as List; - - return MaterialPageRoute( - fullscreenDialog: true, builder: (_) => getIt.get(param1: args)); - case Routes.exchange: return CupertinoPageRoute( fullscreenDialog: true, builder: (_) => getIt.get()); @@ -526,10 +519,8 @@ Route 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( - builder: (_) => getIt.get(param1: title, param2: url)); + builder: (_) => getIt.get(param1: args)); case Routes.advancedPrivacySettings: final type = settings.arguments as WalletType; diff --git a/lib/src/screens/buy/buy_options_page.dart b/lib/src/screens/buy/buy_options_page.dart index 50f041d2e..12f248b15 100644 --- a/lib/src/screens/buy/buy_options_page.dart +++ b/lib/src/screens/buy/buy_options_page.dart @@ -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), ), diff --git a/lib/src/screens/buy/buy_webview_page.dart b/lib/src/screens/buy/buy_webview_page.dart deleted file mode 100644 index 829bff3d9..000000000 --- a/lib/src/screens/buy/buy_webview_page.dart +++ /dev/null @@ -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 { - 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); - } - }); - } -} diff --git a/lib/src/screens/buy/webview_page.dart b/lib/src/screens/buy/webview_page.dart index 0af5952c4..be4f92e07 100644 --- a/lib/src/screens/buy/webview_page.dart +++ b/lib/src/screens/buy/webview_page.dart @@ -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 { 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 { return PermissionResponse( resources: request.resources, - action: permissionGranted - ? PermissionResponseAction.GRANT - : PermissionResponseAction.DENY, + action: + permissionGranted ? PermissionResponseAction.GRANT : PermissionResponseAction.DENY, ); }, ); diff --git a/lib/src/screens/buy/widgets/buy_list_item.dart b/lib/src/screens/buy/widgets/buy_list_item.dart index d8c457ac0..d41325ce8 100644 --- a/lib/src/screens/buy/widgets/buy_list_item.dart +++ b/lib/src/screens/buy/widgets/buy_list_item.dart @@ -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'; diff --git a/lib/src/screens/dashboard/pages/transactions_page.dart b/lib/src/screens/dashboard/pages/transactions_page.dart index c983b1c37..20e909b51 100644 --- a/lib/src/screens/dashboard/pages/transactions_page.dart +++ b/lib/src/screens/dashboard/pages/transactions_page.dart @@ -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: diff --git a/lib/src/screens/dashboard/widgets/order_row.dart b/lib/src/screens/dashboard/widgets/order_row.dart index 8adc6e0d5..a4f526039 100644 --- a/lib/src/screens/dashboard/widgets/order_row.dart +++ b/lib/src/screens/dashboard/widgets/order_row.dart @@ -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()!.iconColor; + final isLightMode = Theme.of(context).extension()?.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, diff --git a/lib/view_model/buy/buy_view_model.dart b/lib/view_model/buy/buy_view_model.dart index d73396e1b..1f81e0f62 100644 --- a/lib/view_model/buy/buy_view_model.dart +++ b/lib/view_model/buy/buy_view_model.dart @@ -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 = [] { - _fetchBuyItems(); - } + BuyViewModelBase(this.ordersSource, this.ordersStore, this.settingsStore, this.buyAmountViewModel, + {required this.wallet}) + : isRunning = false, + orderId = '', + isDisabled = true, + isShowProviderButtons = false, + items = [] {} final Box 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 items; @@ -57,23 +60,24 @@ abstract class BuyViewModelBase with Store { CryptoCurrency get cryptoCurrency => walletTypeToCryptoCurrency(type); - Future fetchUrl() async { - String _url = ''; - + Future 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 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 _fetchBuyItems() async { - final List _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(); } -} \ No newline at end of file + + 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 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 parameterKeywords; + final String? splitSymbol; + + ProviderUrlConfig({required this.name, required this.parameterKeywords, this.splitSymbol}); +} + + diff --git a/lib/view_model/order_details_view_model.dart b/lib/view_model/order_details_view_model.dart index 9b00bbb46..f85093a79 100644 --- a/lib/view_model/order_details_view_model.dart +++ b/lib/view_model/order_details_view_model.dart @@ -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(), 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 _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) {} } )