diff --git a/android/app/build.gradle b/android/app/build.gradle index 74cd0f8f7..00cef6393 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -46,7 +46,7 @@ android { defaultConfig { applicationId appProperties['id'] minSdkVersion 21 - targetSdkVersion 30 + targetSdkVersion 31 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/android/app/src/main/AndroidManifestBase.xml b/android/app/src/main/AndroidManifestBase.xml index f43b0369b..22278d5f1 100644 --- a/android/app/src/main/AndroidManifestBase.xml +++ b/android/app/src/main/AndroidManifestBase.xml @@ -21,7 +21,8 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" - android:screenOrientation="portrait"> + android:screenOrientation="portrait" + android:exported="true"> _onClickExchangeButton(BuildContext context) async { - await Navigator.of(context).pushNamed(Routes.exchange); + if (walletViewModel.isEnabledExchangeAction) { + await Navigator.of(context).pushNamed(Routes.exchange); + } } } diff --git a/lib/src/screens/receive/widgets/qr_painter.dart b/lib/src/screens/receive/widgets/qr_painter.dart index 90dba73ac..e4af59f1a 100644 --- a/lib/src/screens/receive/widgets/qr_painter.dart +++ b/lib/src/screens/receive/widgets/qr_painter.dart @@ -9,7 +9,6 @@ class QrPainter extends CustomPainter { this.errorCorrectionLevel, ) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) { _p.color = this.color; - _qr.addData(data); _qrImage = QrImage(_qr); } diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 2b3105a34..534ea67e9 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -30,6 +30,7 @@ abstract class SettingsStoreBase with Store { required BalanceDisplayMode initialBalanceDisplayMode, required bool initialSaveRecipientAddress, required bool initialAllowBiometricalAuthentication, + required bool initialExchangeEnabled, required ThemeBase initialTheme, required int initialPinLength, required String initialLanguageCode, @@ -47,6 +48,7 @@ abstract class SettingsStoreBase with Store { balanceDisplayMode = initialBalanceDisplayMode, shouldSaveRecipientAddress = initialSaveRecipientAddress, allowBiometricalAuthentication = initialAllowBiometricalAuthentication, + disableExchange = initialExchangeEnabled, currentTheme = initialTheme, pinCodeLength = initialPinLength, languageCode = initialLanguageCode, @@ -143,6 +145,9 @@ abstract class SettingsStoreBase with Store { @observable bool allowBiometricalAuthentication; + @observable + bool disableExchange; + @observable ThemeBase currentTheme; @@ -221,6 +226,8 @@ abstract class SettingsStoreBase with Store { final allowBiometricalAuthentication = sharedPreferences .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? false; + final disableExchange = sharedPreferences + .getBool(PreferencesKey.disableExchangeKey) ?? false; final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) ? ThemeType.dark.index @@ -284,6 +291,7 @@ abstract class SettingsStoreBase with Store { initialBalanceDisplayMode: currentBalanceDisplayMode, initialSaveRecipientAddress: shouldSaveRecipientAddress, initialAllowBiometricalAuthentication: allowBiometricalAuthentication, + initialExchangeEnabled: disableExchange, initialTheme: savedTheme, actionlistDisplayMode: actionListDisplayMode, initialPinLength: pinLength, diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index 49dd2437a..7f11b0c2f 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -53,7 +53,6 @@ abstract class DashboardViewModelBase with Store { hasBuyAction = false, isEnabledBuyAction = false, hasExchangeAction = false, - isEnabledExchangeAction = false, isShowFirstYatIntroduction = false, isShowSecondYatIntroduction = false, isShowThirdYatIntroduction = false, @@ -249,8 +248,8 @@ abstract class DashboardViewModelBase with Store { void furtherShowYatPopup(bool shouldShow) => settingsStore.shouldShowYatPopup = shouldShow; - @observable - bool isEnabledExchangeAction; + @computed + bool get isEnabledExchangeAction => !settingsStore.disableExchange; @observable bool hasExchangeAction; @@ -365,7 +364,6 @@ abstract class DashboardViewModelBase with Store { } void updateActions() { - isEnabledExchangeAction = true; hasExchangeAction = !isHaven; isEnabledBuyAction = wallet.type != WalletType.haven && wallet.type != WalletType.monero; diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index e7e73855b..725208324 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -7,7 +7,6 @@ import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart' import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart'; import 'package:cake_wallet/view_model/settings/settings_view_model.dart'; -import 'package:cw_core/transaction_priority.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/crypto_currency.dart'; @@ -375,96 +374,105 @@ abstract class ExchangeViewModelBase with Store { TradeRequest? request; String amount = ''; - for (var provider in _sortedAvailableProviders.values) { - if (!(await provider.checkIsAvailable())) { - continue; - } + try { + for (var provider in _sortedAvailableProviders.values) { + if (!(await provider.checkIsAvailable())) { + continue; + } - if (provider is SideShiftExchangeProvider) { - request = SideShiftRequest( - depositMethod: depositCurrency, - settleMethod: receiveCurrency, - depositAmount: depositAmount.replaceAll(',', '.'), - settleAddress: receiveAddress, - refundAddress: depositAddress, - ); - amount = depositAmount; - } + if (provider is SideShiftExchangeProvider) { + request = SideShiftRequest( + depositMethod: depositCurrency, + settleMethod: receiveCurrency, + depositAmount: depositAmount.replaceAll(',', '.'), + settleAddress: receiveAddress, + refundAddress: depositAddress, + ); + amount = depositAmount; + } - if (provider is SimpleSwapExchangeProvider) { - request = SimpleSwapRequest( - from: depositCurrency, - to: receiveCurrency, - amount: depositAmount.replaceAll(',', '.'), - address: receiveAddress, - refundAddress: depositAddress, - ); - amount = depositAmount; - } - - if (provider is XMRTOExchangeProvider) { - request = XMRTOTradeRequest( + if (provider is SimpleSwapExchangeProvider) { + request = SimpleSwapRequest( from: depositCurrency, to: receiveCurrency, amount: depositAmount.replaceAll(',', '.'), - receiveAmount: receiveAmount.replaceAll(',', '.'), address: receiveAddress, refundAddress: depositAddress, - isBTCRequest: isReceiveAmountEntered); - amount = depositAmount; - } + ); + amount = depositAmount; + } - if (provider is ChangeNowExchangeProvider) { - request = ChangeNowRequest( - from: depositCurrency, - to: receiveCurrency, - fromAmount: depositAmount.replaceAll(',', '.'), - toAmount: receiveAmount.replaceAll(',', '.'), - refundAddress: depositAddress, - address: receiveAddress, - isReverse: isReverse); - amount = isReverse ? receiveAmount : depositAmount; - } + if (provider is XMRTOExchangeProvider) { + request = XMRTOTradeRequest( + from: depositCurrency, + to: receiveCurrency, + amount: depositAmount.replaceAll(',', '.'), + receiveAmount: receiveAmount.replaceAll(',', '.'), + address: receiveAddress, + refundAddress: depositAddress, + isBTCRequest: isReceiveAmountEntered); + amount = depositAmount; + } - if (provider is MorphTokenExchangeProvider) { - request = MorphTokenRequest( - from: depositCurrency, - to: receiveCurrency, - amount: depositAmount.replaceAll(',', '.'), - refundAddress: depositAddress, - address: receiveAddress); - amount = depositAmount; - } + if (provider is ChangeNowExchangeProvider) { + request = ChangeNowRequest( + from: depositCurrency, + to: receiveCurrency, + fromAmount: depositAmount.replaceAll(',', '.'), + toAmount: receiveAmount.replaceAll(',', '.'), + refundAddress: depositAddress, + address: receiveAddress, + isReverse: isReverse); + amount = isReverse ? receiveAmount : depositAmount; + } - amount = amount.replaceAll(',', '.'); + if (provider is MorphTokenExchangeProvider) { + request = MorphTokenRequest( + from: depositCurrency, + to: receiveCurrency, + amount: depositAmount.replaceAll(',', '.'), + refundAddress: depositAddress, + address: receiveAddress); + amount = depositAmount; + } - if (limitsState is LimitsLoadedSuccessfully) { - if (double.parse(amount) < limits.min!) { - continue; - } else if (limits.max != null && double.parse(amount) > limits.max!) { - continue; - } else { - try { - tradeState = TradeIsCreating(); - final trade = await provider.createTrade( - request: request!, isFixedRateMode: isFixedRateMode); - trade.walletId = wallet.id; - tradesStore.setTrade(trade); - await trades.add(trade); - tradeState = TradeIsCreatedSuccessfully(trade: trade); - /// return after the first successful trade - return; - } catch (e) { + amount = amount.replaceAll(',', '.'); + + if (limitsState is LimitsLoadedSuccessfully) { + if (double.parse(amount) < limits.min!) { continue; + } else if (limits.max != null && double.parse(amount) > limits.max!) { + continue; + } else { + try { + tradeState = TradeIsCreating(); + final trade = await provider.createTrade( + request: request!, isFixedRateMode: isFixedRateMode); + trade.walletId = wallet.id; + tradesStore.setTrade(trade); + await trades.add(trade); + tradeState = TradeIsCreatedSuccessfully(trade: trade); + /// return after the first successful trade + return; + } catch (e) { + continue; + } } } } - } - /// if the code reached here then none of the providers succeeded - tradeState = TradeIsCreatedFailure( - title: S.current.trade_not_created, - error: S.current.none_of_selected_providers_can_exchange); + /// if the code reached here then none of the providers succeeded + tradeState = TradeIsCreatedFailure( + title: S.current.trade_not_created, + error: S.current.none_of_selected_providers_can_exchange); + } on ConcurrentModificationError { + /// if create trade happened at the exact same time of the scheduled rate update + /// then delay the create trade a bit and try again + /// + /// this is because the limitation of the SplayTreeMap that + /// you can't modify it while iterating through it + Future.delayed(Duration(milliseconds: 500), createTrade); + } } @action diff --git a/lib/view_model/settings/settings_view_model.dart b/lib/view_model/settings/settings_view_model.dart index 1f34d5374..d5de8be67 100644 --- a/lib/view_model/settings/settings_view_model.dart +++ b/lib/view_model/settings/settings_view_model.dart @@ -3,15 +3,9 @@ import 'package:cake_wallet/store/yat/yat_store.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cake_wallet/store/settings_store.dart'; -import 'package:cake_wallet/entities/biometric_auth.dart'; import 'package:cw_core/wallet_type.dart'; -import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; -import 'package:cw_core/node.dart'; -import 'package:cake_wallet/monero/monero.dart'; -import 'package:cake_wallet/haven/haven.dart'; import 'package:cake_wallet/entities/action_list_display_mode.dart'; -import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/balance.dart'; import 'package:cw_core/transaction_info.dart'; diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index cea889b15..e4854066b 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -655,5 +655,6 @@ "privacy_settings": "Datenschutzeinstellungen", "privacy": "Datenschutz", "display_settings": "Anzeigeeinstellungen", - "other_settings": "Andere Einstellungen" + "other_settings": "Andere Einstellungen", + "disable_exchange": "Exchange deaktivieren" } diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index e764a0b90..29d4777b7 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -658,5 +658,6 @@ "privacy_settings": "Privacy settings", "privacy": "Privacy", "display_settings": "Display settings", - "other_settings": "Other settings" + "other_settings": "Other settings", + "disable_exchange": "Disable exchange" } diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index bd43abe58..456f23dec 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -655,5 +655,6 @@ "privacy_settings": "Configuración de privacidad", "privacy": "Privacidad", "display_settings": "Configuración de pantalla", - "other_settings": "Otras configuraciones" + "other_settings": "Otras configuraciones", + "disable_exchange": "Deshabilitar intercambio" } diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index df43f41a6..daae787b9 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -653,5 +653,6 @@ "privacy_settings": "Paramètres de confidentialité", "privacy": "Confidentialité", "display_settings": "Paramètres d'affichage", - "other_settings": "Autres paramètres" + "other_settings": "Autres paramètres", + "disable_exchange": "Désactiver l'échange" } diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 06d95d3b2..532e8ede4 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -655,5 +655,6 @@ "privacy_settings": "गोपनीयता सेटिंग्स", "privacy": "गोपनीयता", "display_settings": "प्रदर्शन सेटिंग्स", - "other_settings": "अन्य सेटिंग्स" + "other_settings": "अन्य सेटिंग्स", + "disable_exchange": "एक्सचेंज अक्षम करें" } diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 7c25928e5..e5c8598e1 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -655,5 +655,6 @@ "privacy_settings": "Postavke privatnosti", "privacy": "Privatnost", "display_settings": "Postavke zaslona", - "other_settings": "Ostale postavke" + "other_settings": "Ostale postavke", + "disable_exchange": "Onemogući exchange" } diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 45d9d8164..0a557ebb1 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -655,5 +655,6 @@ "privacy_settings": "Impostazioni privacy", "privacy": "Privacy", "display_settings": "Impostazioni di visualizzazione", - "other_settings": "Altre impostazioni" + "other_settings": "Altre impostazioni", + "disable_exchange": "Disabilita scambio" } diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index ffb2cbb71..16d88db49 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -655,5 +655,6 @@ "privacy_settings": "プライバシー設定", "privacy": "プライバシー", "display_settings": "表示設定", - "other_settings": "その他の設定" + "other_settings": "その他の設定", + "disable_exchange": "交換を無効にする" } diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 598fe2f56..99fe560ed 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -655,5 +655,6 @@ "privacy_settings": "개인정보 설정", "privacy": "프라이버시", "display_settings": "디스플레이 설정", - "other_settings": "기타 설정" + "other_settings": "기타 설정", + "disable_exchange": "교환 비활성화" } diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 12e2f5569..cc4c6bbb1 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -655,5 +655,6 @@ "privacy_settings": "Privacy-instellingen", "privacy": "Privacy", "display_settings": "Weergave-instellingen", - "other_settings": "Andere instellingen" + "other_settings": "Andere instellingen", + "disable_exchange": "Uitwisseling uitschakelen" } diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index fd092d332..0d0159f7a 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -655,5 +655,6 @@ "privacy_settings": "Ustawienia prywatności", "privacy": "Prywatność", "display_settings": "Ustawienia wyświetlania", - "other_settings": "Inne ustawienia" + "other_settings": "Inne ustawienia", + "disable_exchange": "Wyłącz wymianę" } diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index e4d7ef647..6d87183ee 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -655,5 +655,6 @@ "privacy_settings": "Configurações de privacidade", "privacy": "Privacidade", "display_settings": "Configurações de exibição", - "other_settings": "Outras configurações" + "other_settings": "Outras configurações", + "disable_exchange": "Desativar troca" } diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 786f11e36..d2ec428c8 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -655,5 +655,6 @@ "privacy_settings": "Настройки конфиденциальности", "privacy": "Конфиденциальность", "display_settings": "Настройки отображения", - "other_settings": "Другие настройки" + "other_settings": "Другие настройки", + "disable_exchange": "Отключить обмен" } diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 48951e806..42170382e 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -654,6 +654,6 @@ "privacy_settings": "Налаштування конфіденційності", "privacy": "Конфіденційність", "display_settings": "Налаштування дисплея", - "other_settings": "Інші налаштування" - + "other_settings": "Інші налаштування", + "disable_exchange": "Вимкнути exchange" } diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 29d7351d5..8ffa37def 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -653,5 +653,6 @@ "privacy_settings": "隐私设置", "privacy":"隐私", "display_settings": "显示设置", - "other_settings": "其他设置" + "other_settings": "其他设置", + "disable_exchange": "禁用交换" } diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index 54ad0b4d4..d361c8dfa 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.2.0" -MONERO_COM_BUILD_NUMBER=28 +MONERO_COM_VERSION="1.2.1" +MONERO_COM_BUILD_NUMBER=32 MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_PACKAGE="com.monero.app" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.5.0" -CAKEWALLET_BUILD_NUMBER=132 +CAKEWALLET_VERSION="4.5.1" +CAKEWALLET_BUILD_NUMBER=136 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index c7ecaa60b..8bb945680 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.2.0" -MONERO_COM_BUILD_NUMBER=28 +MONERO_COM_VERSION="1.2.1" +MONERO_COM_BUILD_NUMBER=29 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.5.0" -CAKEWALLET_BUILD_NUMBER=132 +CAKEWALLET_VERSION="4.5.1" +CAKEWALLET_BUILD_NUMBER=133 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven"