Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-23 18:30:02 +04:00
parent 6dbd7bd861
commit 4773ed2485
9 changed files with 175 additions and 10 deletions

View file

@ -7,6 +7,7 @@ import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.filter.OneTimeEventFilter
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.toggle.blockchain.ExcludedBlockchainsManager
import com.tangem.core.toggle.feature.FeatureTogglesManager
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
@ -34,6 +35,7 @@ import com.tangem.tap.common.log.TangemAppLoggerInitializer
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
import com.tangem.tap.features.home.featuretoggles.HomeFeatureToggles
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@ -52,6 +54,8 @@ interface ApplicationEntryPoint {
fun getFeatureTogglesManager(): FeatureTogglesManager
fun getExcludedBlockchainsManager(): ExcludedBlockchainsManager
fun getNetworkConnectionManager(): NetworkConnectionManager
fun getCardScanningFeatureToggles(): CardScanningFeatureToggles
@ -113,4 +117,6 @@ interface ApplicationEntryPoint {
fun getOnrampFeatureToggles(): OnrampFeatureToggles
fun getOnboardingV2FeatureToggles(): OnboardingV2FeatureToggles
fun getCoroutineDispatcherProvider(): CoroutineDispatcherProvider
}

View file

@ -17,6 +17,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.analytics.models.Basic.TransactionSent.WalletForm
import com.tangem.core.toggle.blockchain.ExcludedBlockchainsManager
import com.tangem.core.toggle.feature.FeatureTogglesManager
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
@ -57,9 +58,11 @@ import com.tangem.tap.domain.tasks.product.DerivationsFinder
import com.tangem.tap.features.home.featuretoggles.HomeFeatureToggles
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.wallet.BuildConfig
import dagger.hilt.EntryPoints
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import org.rekotlin.Store
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository as WalletConnect2Repository
@ -88,6 +91,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
private val featureTogglesManager: FeatureTogglesManager
get() = entryPoint.getFeatureTogglesManager()
private val excludedBlockchainsManager: ExcludedBlockchainsManager
get() = entryPoint.getExcludedBlockchainsManager()
private val networkConnectionManager: NetworkConnectionManager
get() = entryPoint.getNetworkConnectionManager()
@ -180,6 +186,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles
get() = entryPoint.getOnboardingV2FeatureToggles()
private val dispatchers: CoroutineDispatcherProvider
get() = entryPoint.getCoroutineDispatcherProvider()
// endregion
override fun onCreate() {
@ -199,10 +208,12 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
// TODO: Try to performance and user experience.
// [REDACTED_JIRA]
runBlocking {
featureTogglesManager.init()
initWithConfigDependency(environmentConfig = environmentConfigStorage.initialize())
runBlocking(dispatchers.io) {
awaitAll(
async { featureTogglesManager.init() },
async { excludedBlockchainsManager.init() },
async { initWithConfigDependency(environmentConfig = environmentConfigStorage.initialize()) },
)
}
loadNativeLibraries()
@ -216,7 +227,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
derivationsFinder = DerivationsFinder(
appPreferencesStore = appPreferencesStore,
dispatchers = AppCoroutineDispatcherProvider(),
dispatchers = dispatchers,
)
appStateHolder.mainStore = store

View file

@ -55,6 +55,8 @@ object PreferencesKeys {
val FEATURE_TOGGLES_KEY by lazy { stringPreferencesKey(name = "featureToggles") }
val EXCLUDED_BLOCKCHAINS_KEY by lazy { stringPreferencesKey(name = "excludedBlockchains") }
val WAS_TWINS_ONBOARDING_SHOWN by lazy { booleanPreferencesKey(name = "twinsOnboardingShown") }
val IS_TANGEM_TOS_ACCEPTED_KEY by lazy { booleanPreferencesKey(name = "tangem_tos_accepted") }

View file

@ -98,6 +98,12 @@ suspend inline fun <reified T> AppPreferencesStore.storeObjectList(key: Preferen
edit { it[key] = adapter.toJson(value) }
}
/** Store set of data [value] by string [key] */
suspend inline fun <reified T> AppPreferencesStore.storeObjectSet(key: Preferences.Key<String>, value: Set<T>) {
val adapter = moshi.adapter<Set<T>>(Types.newParameterizedType(Set::class.java, T::class.java))
edit { it[key] = adapter.toJson(value) }
}
/** Get flow of list of data [T] by string [key]. If data is not found, it returns `null` */
inline fun <reified T> AppPreferencesStore.getObjectList(key: Preferences.Key<String>): Flow<List<T>?> {
val adapter = moshi.adapter<List<T>>(Types.newParameterizedType(List::class.java, T::class.java))

View file

@ -1,10 +1,10 @@
[
{
"mainnet_id": "",
"excluded_till": "undefined"
"name": "",
"version": "undefined"
},
{
"mainnet_id": "NEXA",
"excluded_till": "undefined"
"name": "NEXA",
"version": "undefined"
}
]

View file

@ -0,0 +1,8 @@
package com.tangem.core.toggle.blockchain
interface ExcludedBlockchainsManager {
val excludedBlockchainsIds: Set<String>
suspend fun init()
}

View file

@ -0,0 +1,10 @@
package com.tangem.core.toggle.blockchain
interface MutableExcludedBlockchainsManager : ExcludedBlockchainsManager {
suspend fun excludeBlockchain(mainnetId: String, isExcluded: Boolean)
fun isMatchLocalConfig(): Boolean
suspend fun recoverLocalConfig()
}

View file

@ -0,0 +1,73 @@
package com.tangem.core.toggle.blockchain.impl
import com.tangem.core.toggle.blockchain.MutableExcludedBlockchainsManager
import com.tangem.core.toggle.storage.TogglesStorage
import com.tangem.core.toggle.utils.associateToggles
import com.tangem.core.toggle.version.VersionProvider
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSetSync
import com.tangem.datasource.local.preferences.utils.storeObjectSet
internal class DefaultExcludedBlockchainsManager(
private val localTogglesStorage: TogglesStorage,
private val appPreferencesStore: AppPreferencesStore,
private val versionProvider: VersionProvider,
) : MutableExcludedBlockchainsManager {
private var isInitialized: Boolean = false
private lateinit var currentExcludedBlockchainsIds: Set<String>
private lateinit var localExcludedBlockchainsIds: Set<String>
override val excludedBlockchainsIds: Set<String>
get() {
if (!isInitialized) error("ExcludedBlockchainsManager is not initialized")
return currentExcludedBlockchainsIds
}
override suspend fun init() {
localTogglesStorage.populate(path = "configs/excluded_blockchains_config")
val storedExcludedBlockchainsIds = appPreferencesStore.getObjectSetSync<String>(
key = PreferencesKeys.EXCLUDED_BLOCKCHAINS_KEY,
)
localExcludedBlockchainsIds = localTogglesStorage.toggles
.associateToggles(currentVersion = versionProvider.get().orEmpty())
.filterValues { isIncluded -> !isIncluded }
.keys
currentExcludedBlockchainsIds = localExcludedBlockchainsIds + storedExcludedBlockchainsIds
isInitialized = true
}
override suspend fun excludeBlockchain(mainnetId: String, isExcluded: Boolean) {
if (isExcluded) {
currentExcludedBlockchainsIds += mainnetId
} else {
currentExcludedBlockchainsIds -= mainnetId
}
storeCurrent()
}
override fun isMatchLocalConfig(): Boolean {
return currentExcludedBlockchainsIds == localExcludedBlockchainsIds
}
override suspend fun recoverLocalConfig() {
currentExcludedBlockchainsIds = localExcludedBlockchainsIds
storeCurrent()
}
private suspend fun storeCurrent() {
appPreferencesStore.storeObjectSet(
PreferencesKeys.EXCLUDED_BLOCKCHAINS_KEY,
currentExcludedBlockchainsIds,
)
}
}

View file

@ -0,0 +1,49 @@
package com.tangem.core.toggle.di
import android.content.Context
import com.tangem.core.toggle.blockchain.ExcludedBlockchainsManager
import com.tangem.core.toggle.blockchain.MutableExcludedBlockchainsManager
import com.tangem.core.toggle.blockchain.impl.DefaultExcludedBlockchainsManager
import com.tangem.core.toggle.storage.LocalTogglesStorage
import com.tangem.core.toggle.version.DefaultVersionProvider
import com.tangem.core.toggles.BuildConfig
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.local.preferences.AppPreferencesStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object ExcludedBlockchainsManagerModule {
@Provides
@Singleton
fun provideExcludedBlockchainsManager(
@ApplicationContext context: Context,
assetLoader: AssetLoader,
appPreferencesStore: AppPreferencesStore,
): ExcludedBlockchainsManager {
val localTogglesStorage = LocalTogglesStorage(assetLoader)
val versionProvider = DefaultVersionProvider(context)
return DefaultExcludedBlockchainsManager(
localTogglesStorage,
appPreferencesStore,
versionProvider,
)
}
@Provides
@Singleton
fun provideMutableExcludedBlockchainsManager(
manager: ExcludedBlockchainsManager,
): MutableExcludedBlockchainsManager? {
if (!BuildConfig.TESTER_MENU_ENABLED) return null
return manager as MutableExcludedBlockchainsManager
}
}