Updated on 2026-08-14

This commit is contained in:
Tangem 2023-02-10 15:29:38 +03:00
parent 0e1d6547d1
commit 79d823b94f
32 changed files with 156 additions and 110 deletions

View file

@ -12,10 +12,13 @@ import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
import com.tangem.core.analytics.Analytics
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.config.models.Config
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.config.FeaturesLocalLoader
import com.tangem.datasource.utils.AndroidAssetReader
import com.tangem.datasource.utils.AssetReader
import com.tangem.domain.DomainLayer
import com.tangem.domain.common.LogConfig
import com.tangem.tap.common.AndroidAssetReader
import com.tangem.tap.common.AssetReader
import com.tangem.tap.common.IntentHandler
import com.tangem.tap.common.analytics.AnalyticsFactory
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
@ -32,9 +35,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.common.shop.TangemShopService
import com.tangem.tap.domain.configurable.config.Config
import com.tangem.tap.domain.configurable.config.ConfigManager
import com.tangem.tap.domain.configurable.config.FeaturesLocalLoader
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.domain.tokens.UserTokensRepository
import com.tangem.tap.domain.totalBalance.TotalFiatBalanceCalculator
@ -114,6 +114,9 @@ class TapApplication : Application(), ImageLoaderFactory {
@Inject
lateinit var appStateHolder: AppStateHolder
@Inject
lateinit var configManager: ConfigManager
override fun onCreate() {
super.onCreate()
@ -139,7 +142,7 @@ class TapApplication : Application(), ImageLoaderFactory {
walletConnectRepository = WalletConnectRepository(this)
assetReader = AndroidAssetReader(this)
val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi)
val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi, BuildConfig.ENVIRONMENT)
initConfigManager(configLoader, ::initWithConfigDependency)
initWarningMessagesManager()
@ -162,7 +165,6 @@ class TapApplication : Application(), ImageLoaderFactory {
}
private fun initConfigManager(loader: FeaturesLocalLoader, onComplete: (Config) -> Unit) {
val configManager = ConfigManager()
configManager.load(loader) { config ->
store.dispatch(GlobalAction.SetConfigManager(configManager))
onComplete(config)

View file

@ -1,20 +0,0 @@
package com.tangem.tap.common
import android.content.Context
import com.tangem.tap.common.extensions.readAssetAsString
/**
[REDACTED_AUTHOR]
*/
interface AssetReader {
fun readAssetAsString(name: String): String
}
class AndroidAssetReader(
private val context: Context,
) : AssetReader {
override fun readAssetAsString(name: String): String {
return context.readAssetAsString(name)
}
}

View file

@ -4,7 +4,7 @@ import android.app.Application
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.core.analytics.api.AnalyticsHandler
import com.tangem.domain.common.AnalyticsHandlersLogConfig
import com.tangem.tap.domain.configurable.config.Config
import com.tangem.datasource.config.models.Config
interface AnalyticsHandlerBuilder {
fun build(data: Data): AnalyticsHandler?

View file

@ -17,10 +17,6 @@ fun Context.rewriteFile(content: String, fileName: String) {
}
}
fun Context.readAssetAsString(fileName: String): String {
return this.assets.open("$fileName.json").bufferedReader().readText()
}
fun Context.isPermissionGranted(permission: String): Boolean {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}

View file

@ -6,7 +6,7 @@ import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds
import com.tangem.tap.common.extensions.sendEmail
import com.tangem.tap.common.log.TangemLogCollector
import com.tangem.tap.common.zendesk.ZendeskConfig
import com.tangem.datasource.config.models.ZendeskConfig
import com.tangem.tap.foregroundActivityObserver
import com.tangem.tap.persistence.PreferencesStorage
import com.tangem.tap.withForegroundActivity

View file

@ -13,9 +13,9 @@ import com.tangem.tap.common.redux.ErrorAction
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.ToastNotificationAction
import com.tangem.tap.common.zendesk.ZendeskConfig
import com.tangem.datasource.config.models.ZendeskConfig
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.configurable.config.ConfigManager
import com.tangem.datasource.config.ConfigManager
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.features.details.redux.SecurityOption

View file

@ -6,7 +6,7 @@ import com.tangem.tap.common.feedback.FeedbackManager
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.domain.PayIdManager
import com.tangem.tap.domain.TapWalletManager
import com.tangem.tap.domain.configurable.config.ConfigManager
import com.tangem.datasource.config.ConfigManager
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.features.onboarding.OnboardingManager
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager

View file

@ -12,7 +12,7 @@ import com.tangem.tap.common.shop.data.TangemProduct
import com.tangem.tap.common.shop.data.TotalSum
import com.tangem.tap.common.shop.googlepay.GooglePayService
import com.tangem.tap.common.shop.shopify.ShopifyService
import com.tangem.tap.common.shop.shopify.ShopifyShop
import com.tangem.datasource.config.models.ShopifyShop
import com.tangem.tap.common.shop.shopify.data.CheckoutItem
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll

View file

@ -7,6 +7,7 @@ import com.shopify.buy3.RetryHandler
import com.shopify.buy3.Storefront.*
import com.shopify.graphql.support.ID
import com.shopify.graphql.support.Input
import com.tangem.datasource.config.models.ShopifyShop
import com.tangem.tap.common.shop.shopify.data.CheckoutItem
import com.tangem.tap.common.shop.shopify.data.checkoutFieldsFragment
import com.tangem.tap.common.shop.shopify.data.collectionFieldsFragment

View file

@ -1,12 +0,0 @@
package com.tangem.tap.common.shop.shopify
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ShopifyShop(
val domain: String,
@Json(name = "storefrontApiKeyAndroid")
val storefrontApiKey: String,
val merchantID: String,
)

View file

@ -1,18 +0,0 @@
package com.tangem.tap.common.zendesk
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ZendeskConfig(
@Json(name = "zendeskApiKey")
val apiKey: String,
@Json(name = "zendeskAppId")
val appId: String,
@Json(name = "zendeskClientId")
val clientId: String,
@Json(name = "zendeskAccountKey")
val accountKey: String,
@Json(name = "zendeskUrl")
val url: String,
)

View file

@ -18,7 +18,7 @@ import com.tangem.operations.attestation.Attestation
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.safeUpdate
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.configurable.config.ConfigManager
import com.tangem.datasource.config.ConfigManager
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
import com.tangem.tap.domain.extensions.makeWalletManagersForApp
import com.tangem.tap.domain.model.UserWallet
@ -181,16 +181,16 @@ class TapWalletManager {
val configManager = store.state.globalState.configManager
val blockchain = data.cardTypesResolver.getBlockchain()
if (data.cardTypesResolver.isStart2Coin()) {
configManager?.turnOff(ConfigManager.isSendingToPayIdEnabled)
configManager?.turnOff(ConfigManager.isTopUpEnabled)
configManager?.turnOff(ConfigManager.IS_SENDING_TO_PAY_ID_ENABLED)
configManager?.turnOff(ConfigManager.IS_TOP_UP_ENABLED)
} else if (blockchain == Blockchain.Bitcoin ||
data.walletData?.blockchain == Blockchain.Bitcoin.id
) {
configManager?.resetToDefault(ConfigManager.isSendingToPayIdEnabled)
configManager?.resetToDefault(ConfigManager.isTopUpEnabled)
configManager?.resetToDefault(ConfigManager.IS_SENDING_TO_PAY_ID_ENABLED)
configManager?.resetToDefault(ConfigManager.IS_TOP_UP_ENABLED)
} else {
configManager?.resetToDefault(ConfigManager.isSendingToPayIdEnabled)
configManager?.resetToDefault(ConfigManager.isTopUpEnabled)
configManager?.resetToDefault(ConfigManager.IS_SENDING_TO_PAY_ID_ENABLED)
configManager?.resetToDefault(ConfigManager.IS_TOP_UP_ENABLED)
}
}

View file

@ -1,16 +0,0 @@
package com.tangem.tap.domain.configurable
import com.tangem.wallet.BuildConfig
/**
[REDACTED_AUTHOR]
*/
interface Loader<T> {
fun load(onComplete: (T) -> Unit)
companion object {
const val featuresName = "features_${BuildConfig.ENVIRONMENT}"
const val configValuesName = "tangem-app-config/config_${BuildConfig.ENVIRONMENT}"
const val warnings = "warnings_${BuildConfig.ENVIRONMENT}"
}
}

View file

@ -1,125 +0,0 @@
package com.tangem.tap.domain.configurable.config
import com.tangem.blockchain.common.BlockchainSdkConfig
import com.tangem.blockchain.common.BlockchairCredentials
import com.tangem.blockchain.common.QuickNodeCredentials
import com.tangem.tap.common.shop.shopify.ShopifyShop
import com.tangem.tap.common.zendesk.ZendeskConfig
import com.tangem.tap.domain.configurable.Loader
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayConfig
/**
[REDACTED_AUTHOR]
*/
data class Config(
val coinMarketCapKey: String = "f6622117-c043-47a0-8975-9d673ce484de",
val moonPayApiKey: String = "pk_test_kc90oYTANy7UQdBavDKGfL4K9l6VEPE",
val moonPayApiSecretKey: String = "sk_test_V8w4M19LbDjjYOt170s0tGuvXAgyEb1C",
val mercuryoWidgetId: String = "",
val mercuryoSecret: String = "",
val appsFlyerDevKey: String = "",
val amplitudeApiKey: String = "",
val blockchainSdkConfig: BlockchainSdkConfig = BlockchainSdkConfig(),
val isSendingToPayIdEnabled: Boolean = true,
val isTopUpEnabled: Boolean = false,
@Deprecated("Not relevant since version 3.23")
val isCreatingTwinCardsAllowed: Boolean = false,
val shopify: ShopifyShop? = null,
val zendesk: ZendeskConfig? = null,
val saltPayConfig: SaltPayConfig? = null,
)
class ConfigManager {
var config: Config = Config()
private set
private var defaultConfig = Config()
fun load(configLoader: Loader<ConfigModel>, onComplete: ((config: Config) -> Unit)? = null) {
configLoader.load { configModel ->
setupFeature(configModel.features)
setupConfigValues(configModel.configValues)
onComplete?.invoke(config)
}
}
fun turnOff(name: String) {
when (name) {
isSendingToPayIdEnabled -> config = config.copy(isSendingToPayIdEnabled = false)
isTopUpEnabled -> config = config.copy(isTopUpEnabled = false)
isCreatingTwinCardsAllowed -> config = config.copy(isCreatingTwinCardsAllowed = false)
}
}
fun resetToDefault(name: String) {
when (name) {
isSendingToPayIdEnabled -> config =
config.copy(isSendingToPayIdEnabled = defaultConfig.isSendingToPayIdEnabled)
isTopUpEnabled -> config = config.copy(isTopUpEnabled = defaultConfig.isTopUpEnabled)
isCreatingTwinCardsAllowed -> config =
config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed)
}
}
private fun setupFeature(featureModel: FeatureModel?) {
val model = featureModel ?: return
config = config.copy(
isTopUpEnabled = model.isTopUpEnabled,
isSendingToPayIdEnabled = model.isSendingToPayIdEnabled,
isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed,
)
defaultConfig = defaultConfig.copy(
isTopUpEnabled = model.isTopUpEnabled,
isSendingToPayIdEnabled = model.isSendingToPayIdEnabled,
isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed,
)
}
private fun setupConfigValues(configValues: ConfigValueModel?) {
val values = configValues ?: return
config = createConfig(config, values)
defaultConfig = config.copy()
}
private fun createConfig(config: Config, configValues: ConfigValueModel): Config {
return config.copy(
coinMarketCapKey = configValues.coinMarketCapKey,
moonPayApiKey = configValues.moonPayApiKey,
moonPayApiSecretKey = configValues.moonPayApiSecretKey,
mercuryoWidgetId = configValues.mercuryoWidgetId,
mercuryoSecret = configValues.mercuryoSecret,
blockchainSdkConfig = BlockchainSdkConfig(
blockchairCredentials = BlockchairCredentials(
apiKey = configValues.blockchairApiKeys,
authToken = configValues.blockchairAuthorizationToken,
),
blockcypherTokens = configValues.blockcypherTokens,
quickNodeCredentials = QuickNodeCredentials(
apiKey = configValues.quiknodeApiKey,
subdomain = configValues.quiknodeSubdomain,
),
bscQuickNodeCredentials = QuickNodeCredentials(
apiKey = configValues.bscQuiknodeApiKey,
subdomain = configValues.bscQuiknodeSubdomain,
),
infuraProjectId = configValues.infuraProjectId,
tronGridApiKey = configValues.tronGridApiKey,
saltPayAuthToken = configValues.saltPay.credentials.token,
),
appsFlyerDevKey = configValues.appsFlyer.appsFlyerDevKey,
amplitudeApiKey = configValues.amplitudeApiKey,
shopify = configValues.shopifyShop,
zendesk = configValues.zendesk,
saltPayConfig = configValues.saltPay,
)
}
companion object {
const val isSendingToPayIdEnabled = "isSendingToPayIdEnabled"
const val isCreatingTwinCardsAllowed = "isCreatingTwinCardsAllowed"
const val isTopUpEnabled = "isTopUpEnabled"
}
}

View file

@ -1,32 +0,0 @@
package com.tangem.tap.domain.configurable.config
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.tangem.tap.common.AssetReader
import com.tangem.tap.domain.configurable.Loader
import timber.log.Timber
/**
[REDACTED_AUTHOR]
*/
class FeaturesLocalLoader(
private val assetReader: AssetReader,
private val moshi: Moshi,
) : Loader<ConfigModel> {
override fun load(onComplete: (ConfigModel) -> Unit) {
val config = try {
val featureAdapter: JsonAdapter<FeatureModel> = moshi.adapter(FeatureModel::class.java)
val valuesAdapter: JsonAdapter<ConfigValueModel> = moshi.adapter(ConfigValueModel::class.java)
val jsonFeatures = assetReader.readAssetAsString(Loader.featuresName)
val jsonConfigValues = assetReader.readAssetAsString(Loader.configValuesName)
ConfigModel(featureAdapter.fromJson(jsonFeatures), valuesAdapter.fromJson(jsonConfigValues))
} catch (ex: Exception) {
Timber.e(ex)
ConfigModel.empty()
}
onComplete(config)
}
}

View file

@ -1,53 +0,0 @@
package com.tangem.tap.domain.configurable.config
import com.tangem.tap.common.shop.shopify.ShopifyShop
import com.tangem.tap.common.zendesk.ZendeskConfig
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayConfig
/**
[REDACTED_AUTHOR]
*/
class FeatureModel(
val isWalletPayIdEnabled: Boolean,
val isTopUpEnabled: Boolean,
val isSendingToPayIdEnabled: Boolean,
val isCreatingTwinCardsAllowed: Boolean,
)
@Suppress("LongParameterList")
class ConfigValueModel(
val coinMarketCapKey: String,
val mercuryoWidgetId: String,
val mercuryoSecret: String,
val moonPayApiKey: String,
val moonPayApiSecretKey: String,
val blockchairApiKeys: List<String>,
val blockchairAuthorizationToken: String?,
val quiknodeSubdomain: String,
val quiknodeApiKey: String,
val bscQuiknodeSubdomain: String,
val bscQuiknodeApiKey: String,
val blockcypherTokens: Set<String>?,
val infuraProjectId: String?,
val appsFlyer: AppsFlyer,
val shopifyShop: ShopifyShop?,
val zendesk: ZendeskConfig?,
val saltPay: SaltPayConfig,
val tronGridApiKey: String,
val amplitudeApiKey: String,
)
data class AppsFlyer(
val appsFlyerDevKey: String,
val appsFlyerAppID: String,
)
class ConfigModel(
val features: FeatureModel?,
val configValues: ConfigValueModel?,
) {
companion object {
fun empty(): ConfigModel = ConfigModel(null, null)
}
}

View file

@ -7,7 +7,7 @@ import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.tap.common.AssetReader
import com.tangem.datasource.utils.AssetReader
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext

View file

@ -12,7 +12,7 @@ import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.common.AssetReader
import com.tangem.datasource.utils.AssetReader
import com.tangem.tap.tangemSdkManager
class TwinCardsManager(

View file

@ -4,7 +4,7 @@ import com.tangem.Message
import com.tangem.blockchain.common.WalletManager
import com.tangem.common.extensions.VoidCallback
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.AssetReader
import com.tangem.datasource.utils.AssetReader
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.twins.TwinCardsManager
import com.tangem.tap.features.onboarding.OnboardingWalletBalance

View file

@ -18,7 +18,7 @@ import com.tangem.core.ui.fragments.setStatusBarColor
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TwinCardNumber
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
import com.tangem.tap.common.AndroidAssetReader
import com.tangem.datasource.utils.AndroidAssetReader
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.beginDelayedTransition
import com.tangem.tap.common.extensions.getDrawableCompat

View file

@ -20,6 +20,8 @@ import com.tangem.datasource.api.paymentology.models.response.AttestationRespons
import com.tangem.datasource.api.paymentology.models.response.RegisterWalletResponse
import com.tangem.datasource.api.paymentology.models.response.RegistrationResponse
import com.tangem.datasource.api.paymentology.models.response.tryExtractError
import com.tangem.datasource.config.models.KYCProvider
import com.tangem.datasource.config.models.SaltPayConfig
import com.tangem.domain.common.extensions.successOr
import com.tangem.domain.common.util.UserWalletId
import com.tangem.operations.attestation.AttestWalletKeyResponse

View file

@ -1,37 +0,0 @@
package com.tangem.tap.features.onboarding.products.wallet.saltPay
import com.tangem.tap.common.zendesk.ZendeskConfig
import org.spongycastle.util.encoders.Base64.toBase64String
/**
[REDACTED_AUTHOR]
*/
data class SaltPayConfig(
val zendesk: ZendeskConfig,
val kycProvider: KYCProvider,
val credentials: Credentials,
) {
companion object {
fun stub(): SaltPayConfig {
return SaltPayConfig(
zendesk = ZendeskConfig("", "", "", "", ""),
kycProvider = KYCProvider("", "", "", ""),
credentials = Credentials("", ""),
)
}
}
}
data class KYCProvider(
val baseUrl: String,
val externalIdParameterKey: String,
val sidParameterKey: String,
val sidValue: String,
)
data class Credentials(
val user: String,
val password: String,
) {
val token: String by lazy { "Basic ${toBase64String("$user:$password".toByteArray())}" }
}

View file

@ -2,7 +2,7 @@ package com.tangem.tap.features.onboarding.products.wallet.saltPay.redux
import com.tangem.blockchain.common.Amount
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayActivationManager
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayConfig
import com.tangem.datasource.config.models.SaltPayConfig
import org.rekotlin.Action
import java.math.BigDecimal

View file

@ -10,9 +10,9 @@ import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.toggleWidget.WidgetState
import com.tangem.tap.domain.extensions.makeSaltPayWalletManager
import com.tangem.tap.features.onboarding.products.wallet.saltPay.GnosisRegistrator
import com.tangem.tap.features.onboarding.products.wallet.saltPay.KYCProvider
import com.tangem.datasource.config.models.KYCProvider
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayActivationManager
import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayConfig
import com.tangem.datasource.config.models.SaltPayConfig
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.store
import java.math.BigDecimal

View file

@ -31,13 +31,20 @@ class UserWalletManagerImpl(
private val walletManagerFactory: WalletManagerFactory,
) : UserWalletManager {
override suspend fun getUserTokens(networkId: String): List<Currency> {
override suspend fun getUserTokens(networkId: String, isExcludeCustom: Boolean): List<Currency> {
val card = appStateHolder.getActualCard()
val userTokensRepository =
requireNotNull(appStateHolder.userTokensRepository) { "userTokensRepository is null" }
return if (card != null) {
userTokensRepository.getUserTokens(card)
.filter { it.blockchain.toNetworkId() == networkId }
.filter {
val checkCustom = if (isExcludeCustom) {
!it.isCustomCurrency(null)
} else {
true
}
it.blockchain.toNetworkId() == networkId && checkCustom
}
.map {
if (it is com.tangem.tap.features.wallet.models.Currency.Token) {
NonNativeToken(