From 4773ed2485a075c35b87bc16503d00ae2cec0cf9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 23 Oct 2024 18:30:02 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/tap/ApplicationEntryPoint.kt | 6 ++ .../java/com/tangem/tap/TangemApplication.kt | 23 ++++-- .../local/preferences/PreferencesKeys.kt | 2 + .../utils/AppPreferencesStoreExt.kt | 6 ++ .../configs/excluded_blockchains_config.json | 8 +- .../blockchain/ExcludedBlockchainsManager.kt | 8 ++ .../MutableExcludedBlockchainsManager.kt | 10 +++ .../impl/DefaultExcludedBlockchainsManager.kt | 73 +++++++++++++++++++ .../di/ExcludedBlockchainsManagerModule.kt | 49 +++++++++++++ 9 files changed, 175 insertions(+), 10 deletions(-) create mode 100644 core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/ExcludedBlockchainsManager.kt create mode 100644 core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/MutableExcludedBlockchainsManager.kt create mode 100644 core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/impl/DefaultExcludedBlockchainsManager.kt create mode 100644 core/toggles/src/main/kotlin/com/tangem/core/toggle/di/ExcludedBlockchainsManagerModule.kt diff --git a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt index 4a7cf3ec44..ff04434dfa 100644 --- a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt +++ b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt @@ -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 } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index 0790e718b8..287f99d263 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -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 diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index 5fd333db8a..1f4b7caf2b 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -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") } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/utils/AppPreferencesStoreExt.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/utils/AppPreferencesStoreExt.kt index 0369cf22cd..ebfe3c221d 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/utils/AppPreferencesStoreExt.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/utils/AppPreferencesStoreExt.kt @@ -98,6 +98,12 @@ suspend inline fun AppPreferencesStore.storeObjectList(key: Preferen edit { it[key] = adapter.toJson(value) } } +/** Store set of data [value] by string [key] */ +suspend inline fun AppPreferencesStore.storeObjectSet(key: Preferences.Key, value: Set) { + val adapter = moshi.adapter>(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 AppPreferencesStore.getObjectList(key: Preferences.Key): Flow?> { val adapter = moshi.adapter>(Types.newParameterizedType(List::class.java, T::class.java)) diff --git a/core/toggles/src/main/assets/configs/excluded_blockchains_config.json b/core/toggles/src/main/assets/configs/excluded_blockchains_config.json index fe5273f780..4113610e04 100644 --- a/core/toggles/src/main/assets/configs/excluded_blockchains_config.json +++ b/core/toggles/src/main/assets/configs/excluded_blockchains_config.json @@ -1,10 +1,10 @@ [ { - "mainnet_id": "", - "excluded_till": "undefined" + "name": "", + "version": "undefined" }, { - "mainnet_id": "NEXA", - "excluded_till": "undefined" + "name": "NEXA", + "version": "undefined" } ] \ No newline at end of file diff --git a/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/ExcludedBlockchainsManager.kt b/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/ExcludedBlockchainsManager.kt new file mode 100644 index 0000000000..fd6c3a91ae --- /dev/null +++ b/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/ExcludedBlockchainsManager.kt @@ -0,0 +1,8 @@ +package com.tangem.core.toggle.blockchain + +interface ExcludedBlockchainsManager { + + val excludedBlockchainsIds: Set + + suspend fun init() +} \ No newline at end of file diff --git a/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/MutableExcludedBlockchainsManager.kt b/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/MutableExcludedBlockchainsManager.kt new file mode 100644 index 0000000000..7e2f28e33e --- /dev/null +++ b/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/MutableExcludedBlockchainsManager.kt @@ -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() +} \ No newline at end of file diff --git a/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/impl/DefaultExcludedBlockchainsManager.kt b/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/impl/DefaultExcludedBlockchainsManager.kt new file mode 100644 index 0000000000..1f1469773b --- /dev/null +++ b/core/toggles/src/main/kotlin/com/tangem/core/toggle/blockchain/impl/DefaultExcludedBlockchainsManager.kt @@ -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 + private lateinit var localExcludedBlockchainsIds: Set + + override val excludedBlockchainsIds: Set + 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( + 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, + ) + } +} \ No newline at end of file diff --git a/core/toggles/src/main/kotlin/com/tangem/core/toggle/di/ExcludedBlockchainsManagerModule.kt b/core/toggles/src/main/kotlin/com/tangem/core/toggle/di/ExcludedBlockchainsManagerModule.kt new file mode 100644 index 0000000000..7d8c5f5973 --- /dev/null +++ b/core/toggles/src/main/kotlin/com/tangem/core/toggle/di/ExcludedBlockchainsManagerModule.kt @@ -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 + } +} \ No newline at end of file