diff --git a/app/build.gradle b/app/build.gradle index 583846af6b..6598828e88 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,6 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' apply plugin: 'com.google.firebase.crashlytics' -//apply plugin: 'com.google.firebase.firebase-perf' apply plugin: 'com.google.gms.google-services' android { @@ -25,6 +24,7 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debug + buildConfigField 'String', 'CONFIG_ENVIRONMENT', '\"prod\"' } debug { debuggable true @@ -34,11 +34,13 @@ android { firebaseCrashlytics { mappingFileUploadEnabled false } + buildConfigField 'String', 'CONFIG_ENVIRONMENT', '\"dev\"' } debug_beta { initWith debug versionNameSuffix "-beta" applicationIdSuffix ".debug" + buildConfigField 'String', 'CONFIG_ENVIRONMENT', '\"dev\"' } } kotlinOptions { diff --git a/app/src/main/assets/dev_config_values.json b/app/src/main/assets/dev_config_values.json deleted file mode 100644 index dec5d88c02..0000000000 --- a/app/src/main/assets/dev_config_values.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "name": "coinMarketCapKey", - "value": "f6622117-c043-47a0-8975-9d673ce484de" - }, - { - "name": "moonPayApiKey", - "value": "pk_test_kc90oYTANy7UQdBavDKGfL4K9l6VEPE" - }, - { - "name": "moonPayApiSecretKey", - "value": "sk_test_V8w4M19LbDjjYOt170s0tGuvXAgyEb1C" - } -] \ No newline at end of file diff --git a/app/src/main/assets/dev_features.json b/app/src/main/assets/dev_features.json deleted file mode 100644 index 450d65ba07..0000000000 --- a/app/src/main/assets/dev_features.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "name": "payIdIsEnabled", - "value": true - }, - { - "name": "usePayId", - "value": true - }, - { - "name": "useTopUp", - "value": false - } -] \ No newline at end of file diff --git a/app/src/main/assets/features_dev.json b/app/src/main/assets/features_dev.json new file mode 100644 index 0000000000..e932f5787b --- /dev/null +++ b/app/src/main/assets/features_dev.json @@ -0,0 +1,10 @@ +[ + { + "name": "isPayIdCreationEnabled", + "value": false + }, + { + "name": "isTopUpEnabled", + "value": false + } +] \ No newline at end of file diff --git a/app/src/main/assets/features_prod.json b/app/src/main/assets/features_prod.json new file mode 100644 index 0000000000..e932f5787b --- /dev/null +++ b/app/src/main/assets/features_prod.json @@ -0,0 +1,10 @@ +[ + { + "name": "isPayIdCreationEnabled", + "value": false + }, + { + "name": "isTopUpEnabled", + "value": false + } +] \ No newline at end of file diff --git a/app/src/main/assets/prod_features.json b/app/src/main/assets/prod_features.json deleted file mode 100644 index 450d65ba07..0000000000 --- a/app/src/main/assets/prod_features.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "name": "payIdIsEnabled", - "value": true - }, - { - "name": "usePayId", - "value": true - }, - { - "name": "useTopUp", - "value": false - } -] \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index cea8c04e12..5e43828af0 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -9,7 +9,6 @@ import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.appReducer import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.config.ConfigManager -import com.tangem.tap.domain.config.ConfigNameResolver import com.tangem.tap.domain.config.LocalLoader import com.tangem.tap.domain.config.RemoteLoader import com.tangem.tap.network.NetworkConnectivity @@ -51,10 +50,8 @@ class TapApplication : Application() { private fun loadConfigs() { val moshi = createMoshi() - val nameResolver = ConfigNameResolver.get() - - val localLoader = LocalLoader(this, nameResolver, moshi) - val remoteLoader = RemoteLoader(nameResolver, moshi) + val localLoader = LocalLoader(this, moshi) + val remoteLoader = RemoteLoader(moshi) val configManager = ConfigManager(localLoader, remoteLoader) configManager.load { store.dispatch(GlobalAction.SetConfigManager(configManager)) } } diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index a6ad3b9777..8b92e9604e 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -1,5 +1,6 @@ package com.tangem.tap.domain +import TapWorkarounds import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.common.WalletManager import com.tangem.commands.CardStatus @@ -10,6 +11,7 @@ import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler import com.tangem.tap.common.redux.global.CryptoCurrencyName import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.common.redux.global.GlobalAction +import com.tangem.tap.domain.config.ConfigManager import com.tangem.tap.domain.extensions.amountToCreateAccount import com.tangem.tap.domain.extensions.isNoAccountError import com.tangem.tap.domain.tasks.ScanNoteResponse @@ -25,6 +27,7 @@ import java.math.BigDecimal class TapWalletManager { private val payIdManager = PayIdManager() private val coinMarketCapService = CoinMarketCapService() + private var tapWorkarounds: TapWorkarounds? = null suspend fun loadWalletData() { val walletManager = store.state.globalState.scanNoteResponse?.walletManager @@ -82,7 +85,12 @@ class TapWalletManager { if (addAnalyticsEvent) { FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.CARD_IS_SCANNED, data.card) } - store.state.globalState.configManager?.onCardScanned(data.card) + tapWorkarounds = TapWorkarounds(data.card) + if (tapWorkarounds!!.isStart2Coin) { + store.state.globalState.configManager?.turnOf(ConfigManager.isPayIdCreationEnabled) + } else { + store.state.globalState.configManager?.resetToDefault(ConfigManager.isPayIdCreationEnabled) + } withContext(Dispatchers.Main) { store.dispatch(WalletAction.ResetState) store.dispatch(GlobalAction.SaveScanNoteResponse(data)) @@ -99,11 +107,11 @@ class TapWalletManager { store.dispatch(WalletAction.LoadData.Failure(TapError.NoInternetConnection)) return@withContext } - val config = store.state.globalState.configManager?.config?: return@withContext + val config = store.state.globalState.configManager?.config ?: return@withContext store.dispatch(WalletAction.LoadWallet( data.walletManager.wallet, data.verifyResponse?.artworkInfo?.id, - !config.isStart2Coin && config.useTopUp + tapWorkarounds?.isStart2Coin == false && config.isTopUpEnabled )) store.dispatch(WalletAction.LoadArtwork(data.card, artworkId)) store.dispatch(WalletAction.LoadFiatRate) @@ -150,10 +158,9 @@ class TapWalletManager { private suspend fun loadPayIdIfNeeded(): Result? { - val config = store.state.globalState.configManager?.config val scanNoteResponse = store.state.globalState.scanNoteResponse - if (config?.usePayId == false || - scanNoteResponse?.walletManager?.wallet?.blockchain?.isPayIdSupported() == false) { + if (store.state.globalState.configManager?.config?.isPayIdCreationEnabled == false + || scanNoteResponse?.walletManager?.wallet?.blockchain?.isPayIdSupported() == false) { return null } val cardId = scanNoteResponse?.card?.cardId @@ -168,12 +175,12 @@ class TapWalletManager { withContext(Dispatchers.Main) { when (result) { is Result.Success -> { - val config = store.state.globalState.configManager?.config?: return@withContext - val payId = result.data - if (!config.payIdIsEnabled) { + val config = store.state.globalState.configManager?.config + if (config?.isPayIdCreationEnabled == false) { store.dispatch(WalletAction.DisablePayId) return@withContext } + val payId = result.data if (payId == null) { store.dispatch(WalletAction.LoadPayId.NotCreated) } else { diff --git a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt index e69de29bb2..0438f0d810 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWorkarounds.kt @@ -0,0 +1,15 @@ +import com.tangem.commands.Card + +class TapWorkarounds(val card: Card) { + + val isStart2Coin: Boolean = card.cardData?.issuerName == START_2_COIN_ISSUER + + fun isPayisPayIdEnabled(): Boolean { + if (isStart2Coin) return false + return true + } + + companion object { + const val START_2_COIN_ISSUER = "start2coin" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt b/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt index d8ba2a3a96..60bb343e02 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt @@ -1,6 +1,7 @@ package com.tangem.tap.domain.config import android.content.Context +import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.ktx.Firebase import com.google.firebase.remoteconfig.ktx.remoteConfig import com.squareup.moshi.JsonAdapter @@ -14,40 +15,16 @@ import timber.log.Timber */ interface ConfigLoader { fun loadConfig(onComplete: (ConfigModel) -> Unit) -} - -interface NameResolver { - fun getFeaturesName(): String - fun getConfigValuesName(): String -} - -class ConfigNameResolver { companion object { - fun get(): NameResolver = if (BuildConfig.DEBUG) dev() else prod() - - private fun dev(): NameResolver { - return object : NameResolver { - override fun getFeaturesName(): String = "dev_features" - override fun getConfigValuesName(): String = "dev_config_values" - } - } - - private fun prod(): NameResolver { - return object : NameResolver { - override fun getFeaturesName(): String = "prod_features" - override fun getConfigValuesName(): String = "prod_config_values" - - } - } + const val featuresName = "features_${BuildConfig.CONFIG_ENVIRONMENT}" + const val configValuesName = "config_${BuildConfig.CONFIG_ENVIRONMENT}" } } -class KeyValueModel(val name: String, value: T?) class LocalLoader( private val context: Context, - private val nameResolver: NameResolver, private val moshi: Moshi ) : ConfigLoader { @@ -58,8 +35,8 @@ class LocalLoader( val valuesType = Types.newParameterizedType(List::class.java, ConfigValueModel::class.java) val valuesAdapter: JsonAdapter> = moshi.adapter(valuesType) - val jsonFeatures = readAssetAsString(nameResolver.getFeaturesName()) - val jsonConfigValues = readAssetAsString(nameResolver.getConfigValuesName()) + val jsonFeatures = readAssetAsString(ConfigLoader.featuresName) + val jsonConfigValues = readAssetAsString(ConfigLoader.configValuesName) ConfigModel(featureAdapter.fromJson(jsonFeatures) ?: listOf(), valuesAdapter.fromJson(jsonConfigValues) ?: listOf()) @@ -76,7 +53,6 @@ class LocalLoader( } class RemoteLoader( - private val nameResolver: NameResolver, private val moshi: Moshi ) : ConfigLoader { @@ -85,7 +61,7 @@ class RemoteLoader( val remoteConfig = Firebase.remoteConfig remoteConfig.fetchAndActivate().addOnCompleteListener { if (it.isSuccessful) { - val config = remoteConfig.getValue(nameResolver.getFeaturesName()) + val config = remoteConfig.getValue(ConfigLoader.featuresName) val jsonConfig = config.asString() if (jsonConfig.isEmpty()) { onComplete(emptyConfig) @@ -98,7 +74,7 @@ class RemoteLoader( onComplete(emptyConfig) } }.addOnFailureListener { - Timber.e(it) + FirebaseCrashlytics.getInstance().recordException(it) onComplete(emptyConfig) } } diff --git a/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt index 37fe46cc58..b9b05b49fe 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt @@ -1,68 +1,90 @@ package com.tangem.tap.domain.config -import com.tangem.commands.Card import com.tangem.tangem_sdk_new.ui.animation.VoidCallback -import java.util.* /** [REDACTED_AUTHOR] */ -data class ConfigState( +data class Config( val coinMarketCapKey: String = "f6622117-c043-47a0-8975-9d673ce484de", val moonPayApiKey: String = "pk_test_kc90oYTANy7UQdBavDKGfL4K9l6VEPE", val moonPayApiSecretKey: String = "sk_test_V8w4M19LbDjjYOt170s0tGuvXAgyEb1C", - val payIdIsEnabled: Boolean = true, - val usePayId: Boolean = true, - val useTopUp: Boolean = false, - val isStart2Coin: Boolean = false + val isPayIdCreationEnabled: Boolean = true, + val isTopUpEnabled: Boolean = false, ) class ConfigManager( private val localLoader: ConfigLoader, private val remoteLoader: ConfigLoader ) { - private val usePayId = "usePayId" - private val payIdIsEnabled = "payIdIsEnabled" - private val useTopUp = "useTopUp" - private val isStart2Coin = "isStart2Coin" - private val coinMarketCapKey = "coinMarketCapKey" - private val moonPayApiKey = "moonPayApiKey" - private val moonPayApiSecretKey = "moonPayApiSecretKey" - var config: ConfigState = ConfigState() + var config: Config = Config() private set + private var defaultConfig = Config() + fun load(onComplete: VoidCallback? = null) { - localLoader.loadConfig {config -> - config.features?.forEach { updateFeature(it.name, it.value) } - config.configValues?.forEach { updateKeys(it.name, it.value) } + localLoader.loadConfig { config -> + config.features?.forEach { setupFeature(it.name, it.value) } + config.configValues?.forEach { setupKey(it.name, it.value) } } - remoteLoader.loadConfig { - it.features?.forEach { feature -> updateFeature(feature.name, feature.value) } + remoteLoader.loadConfig { config -> + config.features?.forEach { setupFeature(it.name, it.value) } onComplete?.invoke() } } - fun onCardScanned(card: Card) { - updateFeature(isStart2Coin, card.cardData?.issuerName?.toLowerCase(Locale.US) == "start2coin") + fun turnOf(name: String) { + when (name) { + isPayIdCreationEnabled -> config = config.copy(isPayIdCreationEnabled = false) + isTopUpEnabled -> config = config.copy(isTopUpEnabled = false) + } } - private fun updateFeature(name: String, value: Boolean?) { + fun resetToDefault(name: String) { + when (name) { + isPayIdCreationEnabled -> config = config.copy(isPayIdCreationEnabled = defaultConfig.isPayIdCreationEnabled) + isTopUpEnabled -> config = config.copy(isTopUpEnabled = defaultConfig.isTopUpEnabled) + } + } + + private fun setupFeature(name: String, value: Boolean) { val newValue = value ?: return when (name) { - usePayId -> config = config.copy(usePayId = newValue) - payIdIsEnabled -> config = config.copy(payIdIsEnabled = newValue) - useTopUp -> config = config.copy(useTopUp = newValue) - isStart2Coin -> config = config.copy(isStart2Coin = newValue) + isPayIdCreationEnabled -> { + config = config.copy(isPayIdCreationEnabled = newValue) + defaultConfig = defaultConfig.copy(isPayIdCreationEnabled = newValue) + } + isTopUpEnabled -> { + config = config.copy(isTopUpEnabled = newValue) + defaultConfig = defaultConfig.copy(isTopUpEnabled = newValue) + } } } - private fun updateKeys(name: String, value: String) { + private fun setupKey(name: String, value: String) { when (name) { - coinMarketCapKey -> config = config.copy(coinMarketCapKey = value) - moonPayApiKey -> config = config.copy(moonPayApiKey = value) - moonPayApiSecretKey -> config = config.copy(moonPayApiSecretKey = value) + coinMarketCapKey -> { + config = config.copy(coinMarketCapKey = value) + defaultConfig = defaultConfig.copy(coinMarketCapKey = value) + } + moonPayApiKey -> { + config = config.copy(moonPayApiKey = value) + defaultConfig = defaultConfig.copy(moonPayApiKey = value) + } + moonPayApiSecretKey -> { + config = config.copy(moonPayApiSecretKey = value) + defaultConfig = defaultConfig.copy(moonPayApiSecretKey = value) + } } } + + companion object { + const val isPayIdCreationEnabled = "isPayIdCreationEnabled" + const val isTopUpEnabled = "useTopUp" + const val coinMarketCapKey = "coinMarketCapKey" + const val moonPayApiKey = "moonPayApiKey" + const val moonPayApiSecretKey = "moonPayApiSecretKey" + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt b/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt index be99fff956..1b7272765b 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt @@ -11,7 +11,7 @@ interface BaseConfigModel { class FeatureModel( override val name: String, - override val value: Boolean? + override val value: Boolean ) : BaseConfigModel class ConfigValueModel(