From 36361ef329fb7ae988d3e4e48b4109b7b98cc836 Mon Sep 17 00:00:00 2001 From: Serhii Date: Fri, 17 Nov 2023 01:23:34 +0200 Subject: [PATCH] CW-526-Add-Trocador-providers-option-in-privacy-settings (#1177) * Trocador settings page UI * add trocador providers states * add settings icon * minor fix * Revert "minor fix" This reverts commit e59d9dfdaf9bd1c13a17ae5012db80a8f973a4d4. * fixes * PR fixes * remove trocador menu icon --- lib/di.dart | 6 +++ .../provider/trocador_exchange_provider.dart | 43 +++++++++++++++++-- lib/router.dart | 5 +++ lib/routes.dart | 1 + lib/src/screens/settings/privacy_page.dart | 4 ++ .../settings/trocador_providers_page.dart | 37 ++++++++++++++++ lib/store/settings_store.dart | 19 ++++++++ .../exchange/exchange_view_model.dart | 3 +- .../trocador_providers_view_model.dart | 21 +++++++++ 9 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 lib/src/screens/settings/trocador_providers_page.dart create mode 100644 lib/view_model/settings/trocador_providers_view_model.dart diff --git a/lib/di.dart b/lib/di.dart index 10662d816..8cc393510 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -45,6 +45,7 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart'; import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart'; +import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart'; @@ -92,6 +93,7 @@ import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart'; import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; +import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; @@ -699,6 +701,8 @@ Future setup({ return PrivacySettingsViewModel(getIt.get(), getIt.get().wallet!); }); + getIt.registerFactory(() => TrocadorProvidersViewModel(getIt.get())); + getIt.registerFactory(() { return OtherSettingsViewModel(getIt.get(), getIt.get().wallet!); }); @@ -752,6 +756,8 @@ Future setup({ getIt.registerFactory(() => PrivacyPage(getIt.get())); + getIt.registerFactory(() => TrocadorProvidersPage(getIt.get())); + getIt.registerFactory(() => DomainLookupsPage(getIt.get())); getIt.registerFactory(() => DisplaySettingsPage(getIt.get())); diff --git a/lib/exchange/provider/trocador_exchange_provider.dart b/lib/exchange/provider/trocador_exchange_provider.dart index 3d08bbd37..52e38ecc8 100644 --- a/lib/exchange/provider/trocador_exchange_provider.dart +++ b/lib/exchange/provider/trocador_exchange_provider.dart @@ -12,11 +12,27 @@ import 'package:cw_core/crypto_currency.dart'; import 'package:http/http.dart'; class TrocadorExchangeProvider extends ExchangeProvider { - TrocadorExchangeProvider({this.useTorOnly = false}) - : _lastUsedRateId = '', + TrocadorExchangeProvider({this.useTorOnly = false, this.providerStates = const {}}) + : _lastUsedRateId = '', _provider = [], super(pairList: supportedPairs(_notSupported)); bool useTorOnly; + final Map providerStates; + + static const List availableProviders = [ + 'Swapter', + 'StealthEx', + 'Simpleswap', + 'Swapuz' + 'ChangeNow', + 'Changehero', + 'FixedFloat', + 'LetsExchange', + 'Exolix', + 'Godex', + 'Exch', + 'CoinCraddle' + ]; static const List _notSupported = [ CryptoCurrency.stx, @@ -33,6 +49,7 @@ class TrocadorExchangeProvider extends ExchangeProvider { static const coinPath = 'api/coin'; String _lastUsedRateId; + List _provider; @override String get title => 'Trocador'; @@ -105,7 +122,6 @@ class TrocadorExchangeProvider extends ExchangeProvider { 'payment': isFixedRateMode ? 'True' : 'False', 'min_kycrating': 'C', 'markup': markup, - 'best_only': 'True', }; final uri = await _getUri(newRatePath, params); @@ -115,6 +131,9 @@ class TrocadorExchangeProvider extends ExchangeProvider { final toAmount = double.parse(responseJSON['amount_to'].toString()); final rateId = responseJSON['trade_id'] as String? ?? ''; + var quotes = responseJSON['quotes']['quotes'] as List; + _provider = quotes.map((quote) => quote['provider']).toList(); + if (rateId.isNotEmpty) _lastUsedRateId = rateId; return isReceiveAmount ? (amount / fromAmount) : (toAmount / amount); @@ -126,6 +145,7 @@ class TrocadorExchangeProvider extends ExchangeProvider { @override Future createTrade({required TradeRequest request, required bool isFixedRateMode}) async { + final params = { 'api_key': apiKey, 'ticker_from': _normalizeCurrency(request.fromCurrency), @@ -135,7 +155,6 @@ class TrocadorExchangeProvider extends ExchangeProvider { 'payment': isFixedRateMode ? 'True' : 'False', 'min_kycrating': 'C', 'markup': markup, - 'best_only': 'True', if (!isFixedRateMode) 'amount_from': request.fromAmount, if (isFixedRateMode) 'amount_to': request.toAmount, 'address': request.toAddress, @@ -153,6 +172,22 @@ class TrocadorExchangeProvider extends ExchangeProvider { params['id'] = _lastUsedRateId; } + + String firstAvailableProvider = ''; + + for (var provider in _provider) { + if (providerStates.containsKey(provider) && providerStates[provider] == true) { + firstAvailableProvider = provider as String; + break; + } + } + + if (firstAvailableProvider.isEmpty) { + throw Exception('No available provider is enabled'); + } + + params['provider'] = firstAvailableProvider; + final uri = await _getUri(createTradePath, params); final response = await get(uri); diff --git a/lib/router.dart b/lib/router.dart index 1211bbcb6..dc2d8f8ab 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -42,6 +42,7 @@ 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/seed/pre_seed_page.dart'; import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart'; +import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart'; @@ -323,6 +324,10 @@ Route createRoute(RouteSettings settings) { return CupertinoPageRoute( fullscreenDialog: true, builder: (_) => getIt.get()); + case Routes.trocadorProvidersPage: + return CupertinoPageRoute( + fullscreenDialog: true, builder: (_) => getIt.get()); + case Routes.domainLookupsPage: return CupertinoPageRoute( fullscreenDialog: true, builder: (_) => getIt.get()); diff --git a/lib/routes.dart b/lib/routes.dart index 0b4e8817d..8b521247a 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -81,6 +81,7 @@ class Routes { static const connectionSync = '/connection_sync_page'; static const securityBackupPage = '/security_and_backup_page'; static const privacyPage = '/privacy_page'; + static const trocadorProvidersPage = '/trocador_providers_page'; static const domainLookupsPage = '/domain_lookups_page'; static const displaySettingsPage = '/display_settings_page'; static const otherSettingsPage = '/other_settings_page'; diff --git a/lib/src/screens/settings/privacy_page.dart b/lib/src/screens/settings/privacy_page.dart index 8e71b6020..7a8671224 100644 --- a/lib/src/screens/settings/privacy_page.dart +++ b/lib/src/screens/settings/privacy_page.dart @@ -90,6 +90,10 @@ class PrivacyPage extends BasePage { title: S.current.domain_looks_up, handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage), ), + SettingsCellWithArrow( + title: 'Trocador providers', + handler: (context) => Navigator.of(context).pushNamed(Routes.trocadorProvidersPage), + ), ], ); }), diff --git a/lib/src/screens/settings/trocador_providers_page.dart b/lib/src/screens/settings/trocador_providers_page.dart new file mode 100644 index 000000000..b972c22d5 --- /dev/null +++ b/lib/src/screens/settings/trocador_providers_page.dart @@ -0,0 +1,37 @@ +import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; +import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; + +class TrocadorProvidersPage extends BasePage { + TrocadorProvidersPage(this.trocadorProvidersViewModel); + + @override + String get title => 'Trocador Providers'; + + final TrocadorProvidersViewModel trocadorProvidersViewModel; + + @override + Widget body(BuildContext context) { + final availableProviders = TrocadorExchangeProvider.availableProviders; + final providerStates = trocadorProvidersViewModel.providerStates; + return Container( + padding: EdgeInsets.only(top: 10), + child: ListView.builder( + itemCount: availableProviders.length, + itemBuilder: (_, index) { + String provider = availableProviders[index]; + return Observer( + builder: (_) => SettingsSwitcherCell( + title: provider, + value: providerStates[provider] ?? false, + onValueChange: (BuildContext _, bool value) { + trocadorProvidersViewModel.toggleProviderState(provider); + })); + }, + ), + ); + } +} diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index cb9df3d1d..3c9ba36d5 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -10,6 +10,7 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/sort_balance_types.dart'; +import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart'; import 'package:cake_wallet/view_model/settings/sync_mode.dart'; import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; @@ -161,6 +162,8 @@ abstract class SettingsStoreBase with Store { priority[WalletType.bitcoinCash] = initialBitcoinCashTransactionPriority; } + initializeTrocadorProviderStates(); + reaction( (_) => fiatCurrency, (FiatCurrency fiatCurrency) => sharedPreferences.setString( @@ -515,6 +518,9 @@ abstract class SettingsStoreBase with Store { @observable ObservableMap priority; + @observable + ObservableMap trocadorProviderStates = ObservableMap(); + @observable SortBalanceBy sortBalanceBy; @@ -1059,6 +1065,19 @@ abstract class SettingsStoreBase with Store { powNodes[walletType] = node; } + void initializeTrocadorProviderStates() { + for (var provider in TrocadorExchangeProvider.availableProviders) { + final savedState = _sharedPreferences.getBool(provider) ?? true; + trocadorProviderStates[provider] = savedState; + } + } + + void saveTrocadorProviderState(String providerName, bool state) { + _sharedPreferences.setBool(providerName, state); + trocadorProviderStates[providerName] = state; + } + + static Future _getDeviceName() async { String? deviceName = ''; final deviceInfoPlugin = DeviceInfoPlugin(); diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 1a6b118f8..80c331ab2 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -146,7 +146,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with ChangeNowExchangeProvider(settingsStore: _settingsStore), SideShiftExchangeProvider(), SimpleSwapExchangeProvider(), - TrocadorExchangeProvider(useTorOnly: _useTorOnly), + TrocadorExchangeProvider(useTorOnly: _useTorOnly, + providerStates: _settingsStore.trocadorProviderStates), if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(), ]; diff --git a/lib/view_model/settings/trocador_providers_view_model.dart b/lib/view_model/settings/trocador_providers_view_model.dart new file mode 100644 index 000000000..19204d1f9 --- /dev/null +++ b/lib/view_model/settings/trocador_providers_view_model.dart @@ -0,0 +1,21 @@ +import 'package:cake_wallet/store/settings_store.dart'; +import 'package:mobx/mobx.dart'; + +part 'trocador_providers_view_model.g.dart'; + +class TrocadorProvidersViewModel = TrocadorProvidersViewModelBase with _$TrocadorProvidersViewModel; + +abstract class TrocadorProvidersViewModelBase with Store { + TrocadorProvidersViewModelBase(this._settingsStore); + + final SettingsStore _settingsStore; + + @computed + Map get providerStates => _settingsStore.trocadorProviderStates; + + @action + void toggleProviderState(String providerName) { + final currentState = providerStates[providerName] ?? false; + _settingsStore.saveTrocadorProviderState(providerName, !currentState); + } +} \ No newline at end of file