Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-30 15:07:29 +04:00
parent 3723229539
commit c6e06b1eb9
61 changed files with 132 additions and 139 deletions

View file

@ -7,7 +7,7 @@ plugins {
}
android {
namespace = "com.tangem.core.toggles"
namespace = "com.tangem.core.configtoggle"
}
dependencies {

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.blockchain
package com.tangem.core.configtoggle.blockchain
interface ExcludedBlockchainsManager {

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.blockchain
package com.tangem.core.configtoggle.blockchain
interface MutableExcludedBlockchainsManager : ExcludedBlockchainsManager {

View file

@ -1,13 +1,13 @@
package com.tangem.core.toggle.blockchain.impl
package com.tangem.core.configtoggle.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.core.configtoggle.blockchain.MutableExcludedBlockchainsManager
import com.tangem.core.configtoggle.storage.TogglesStorage
import com.tangem.core.configtoggle.utils.associateToggles
import com.tangem.core.configtoggle.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
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
import com.tangem.datasource.local.preferences.utils.store
internal class DefaultExcludedBlockchainsManager(
private val localTogglesStorage: TogglesStorage,
@ -30,8 +30,9 @@ internal class DefaultExcludedBlockchainsManager(
override suspend fun init() {
localTogglesStorage.populate(path = "configs/excluded_blockchains_config")
val storedExcludedBlockchainsIds = appPreferencesStore.getObjectSetSync<String>(
val storedExcludedBlockchainsIds = appPreferencesStore.getSyncOrDefault(
key = PreferencesKeys.EXCLUDED_BLOCKCHAINS_KEY,
default = emptySet(),
)
localExcludedBlockchainsIds = localTogglesStorage.toggles
@ -65,7 +66,7 @@ internal class DefaultExcludedBlockchainsManager(
}
private suspend fun storeCurrent() {
appPreferencesStore.storeObjectSet(
appPreferencesStore.store(
PreferencesKeys.EXCLUDED_BLOCKCHAINS_KEY,
currentExcludedBlockchainsIds,
)

View file

@ -1,12 +1,12 @@
package com.tangem.core.toggle.di
package com.tangem.core.configtoggle.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.core.configtoggle.BuildConfig
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
import com.tangem.core.configtoggle.blockchain.MutableExcludedBlockchainsManager
import com.tangem.core.configtoggle.blockchain.impl.DefaultExcludedBlockchainsManager
import com.tangem.core.configtoggle.storage.LocalTogglesStorage
import com.tangem.core.configtoggle.version.DefaultVersionProvider
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.local.preferences.AppPreferencesStore
import dagger.Module

View file

@ -1,12 +1,12 @@
package com.tangem.core.toggle.di
package com.tangem.core.configtoggle.di
import android.content.Context
import com.tangem.core.toggle.feature.FeatureTogglesManager
import com.tangem.core.toggle.feature.impl.DevFeatureTogglesManager
import com.tangem.core.toggle.feature.impl.ProdFeatureTogglesManager
import com.tangem.core.toggle.storage.LocalTogglesStorage
import com.tangem.core.toggle.version.DefaultVersionProvider
import com.tangem.core.toggles.BuildConfig
import com.tangem.core.configtoggle.BuildConfig
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.core.configtoggle.feature.impl.DevFeatureTogglesManager
import com.tangem.core.configtoggle.feature.impl.ProdFeatureTogglesManager
import com.tangem.core.configtoggle.storage.LocalTogglesStorage
import com.tangem.core.configtoggle.version.DefaultVersionProvider
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.local.preferences.AppPreferencesStore
import dagger.Module

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.feature
package com.tangem.core.configtoggle.feature
/**
* Component for getting information about the availability of feature toggles

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.feature
package com.tangem.core.configtoggle.feature
/**
* Component for change information about the availability of feature toggles

View file

@ -1,10 +1,10 @@
package com.tangem.core.toggle.feature.impl
package com.tangem.core.configtoggle.feature.impl
import androidx.annotation.VisibleForTesting
import com.tangem.core.toggle.feature.MutableFeatureTogglesManager
import com.tangem.core.toggle.storage.TogglesStorage
import com.tangem.core.toggle.utils.associateToggles
import com.tangem.core.toggle.version.VersionProvider
import com.tangem.core.configtoggle.feature.MutableFeatureTogglesManager
import com.tangem.core.configtoggle.storage.TogglesStorage
import com.tangem.core.configtoggle.utils.associateToggles
import com.tangem.core.configtoggle.version.VersionProvider
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.feature.impl
package com.tangem.core.configtoggle.feature.impl
internal object FeatureTogglesConstants {

View file

@ -1,10 +1,10 @@
package com.tangem.core.toggle.feature.impl
package com.tangem.core.configtoggle.feature.impl
import androidx.annotation.VisibleForTesting
import com.tangem.core.toggle.feature.FeatureTogglesManager
import com.tangem.core.toggle.storage.TogglesStorage
import com.tangem.core.toggle.utils.associateToggles
import com.tangem.core.toggle.version.VersionProvider
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.core.configtoggle.storage.TogglesStorage
import com.tangem.core.configtoggle.utils.associateToggles
import com.tangem.core.configtoggle.version.VersionProvider
import kotlin.properties.Delegates
/**

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.storage
package com.tangem.core.configtoggle.storage
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@ -7,14 +7,14 @@ import com.squareup.moshi.JsonClass
* Data model with information about config toggle
*
* @property name toggle name
* @property version version number in which the feature will be included
* @property version version in which the toggle will be enabled
*
* IMPORTANT: if the version is "undefined", it means that toggle is disabled!
*
[REDACTED_AUTHOR]
*/
@JsonClass(generateAdapter = true)
internal data class Toggle(
internal data class ConfigToggle(
@Json(name = "name") val name: String,
@Json(name = "version") val version: String,
)

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.storage
package com.tangem.core.configtoggle.storage
import com.tangem.datasource.asset.loader.AssetLoader
import kotlin.properties.Delegates
@ -15,10 +15,10 @@ internal class LocalTogglesStorage(
private val assetLoader: AssetLoader,
) : TogglesStorage {
override var toggles: List<Toggle> by Delegates.notNull()
override var toggles: List<ConfigToggle> by Delegates.notNull()
private set
override suspend fun populate(path: String) {
toggles = assetLoader.loadList<Toggle>(path)
toggles = assetLoader.loadList<ConfigToggle>(path)
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.storage
package com.tangem.core.configtoggle.storage
/**
* Component that initializes and stores a list of feature toggles
@ -8,7 +8,7 @@ package com.tangem.core.toggle.storage
internal interface TogglesStorage {
/** List of feature toggles */
val toggles: List<Toggle>
val toggles: List<ConfigToggle>
/** Populate the storage with toggles */
suspend fun populate(path: String)

View file

@ -0,0 +1,13 @@
package com.tangem.core.configtoggle.utils
import com.tangem.core.configtoggle.storage.ConfigToggle
import com.tangem.core.configtoggle.version.VersionAvailabilityContract
internal fun List<ConfigToggle>.associateToggles(currentVersion: String): Map<String, Boolean> {
return associate { localToggle ->
Pair(
first = localToggle.name,
second = VersionAvailabilityContract(currentVersion, localToggle.version),
)
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.version
package com.tangem.core.configtoggle.version
import android.content.Context
import android.content.pm.PackageManager

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.version
package com.tangem.core.configtoggle.version
import androidx.annotation.VisibleForTesting
import timber.log.Timber

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.version
package com.tangem.core.configtoggle.version
/**
* Version contract to evaluate availability of feature toggle

View file

@ -1,4 +1,4 @@
package com.tangem.core.toggle.version
package com.tangem.core.configtoggle.version
/** Application version provider */
internal interface VersionProvider {

View file

@ -1,7 +1,7 @@
package com.tangem.core.toggle.contract
package com.tangem.core.configtoggle.contract
import com.google.common.truth.Truth
import com.tangem.core.toggle.version.VersionAvailabilityContract
import com.tangem.core.configtoggle.version.VersionAvailabilityContract
import org.junit.Test
/**

View file

@ -1,7 +1,7 @@
package com.tangem.core.toggle.contract
package com.tangem.core.configtoggle.contract
import com.google.common.truth.Truth
import com.tangem.core.toggle.version.Version
import com.tangem.core.configtoggle.version.Version
import org.junit.Test
/**

View file

@ -1,13 +1,13 @@
package com.tangem.core.toggle.manager
package com.tangem.core.configtoggle.manager
import android.annotation.SuppressLint
import com.google.common.truth.Truth
import com.tangem.core.toggle.feature.impl.DevFeatureTogglesManager
import com.tangem.core.toggle.feature.impl.FeatureTogglesConstants
import com.tangem.core.toggle.storage.Toggle
import com.tangem.core.toggle.storage.TogglesStorage
import com.tangem.core.toggle.utils.associateToggles
import com.tangem.core.toggle.version.VersionProvider
import com.tangem.core.configtoggle.feature.impl.DevFeatureTogglesManager
import com.tangem.core.configtoggle.feature.impl.FeatureTogglesConstants
import com.tangem.core.configtoggle.storage.ConfigToggle
import com.tangem.core.configtoggle.storage.TogglesStorage
import com.tangem.core.configtoggle.utils.associateToggles
import com.tangem.core.configtoggle.version.VersionProvider
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
@ -224,8 +224,8 @@ internal class DevTogglesManagerTest {
)
val localFeatureToggles = listOf(
Toggle(name = "INACTIVE_TEST_FEATURE_ENABLED", version = "undefined"),
Toggle(name = "ACTIVE2_TEST_FEATURE_ENABLED", version = "1.0.0"),
ConfigToggle(name = "INACTIVE_TEST_FEATURE_ENABLED", version = "undefined"),
ConfigToggle(name = "ACTIVE2_TEST_FEATURE_ENABLED", version = "1.0.0"),
)
}
}

View file

@ -1,13 +1,13 @@
package com.tangem.core.toggle.manager
package com.tangem.core.configtoggle.manager
import android.content.pm.PackageManager
import com.google.common.truth.Truth
import com.tangem.core.toggle.feature.impl.FeatureTogglesConstants
import com.tangem.core.toggle.feature.impl.ProdFeatureTogglesManager
import com.tangem.core.toggle.storage.Toggle
import com.tangem.core.toggle.storage.TogglesStorage
import com.tangem.core.toggle.utils.associateToggles
import com.tangem.core.toggle.version.VersionProvider
import com.tangem.core.configtoggle.feature.impl.FeatureTogglesConstants
import com.tangem.core.configtoggle.feature.impl.ProdFeatureTogglesManager
import com.tangem.core.configtoggle.storage.ConfigToggle
import com.tangem.core.configtoggle.storage.TogglesStorage
import com.tangem.core.configtoggle.utils.associateToggles
import com.tangem.core.configtoggle.version.VersionProvider
import io.mockk.*
import kotlinx.coroutines.test.runTest
import org.junit.Test
@ -124,8 +124,8 @@ internal class ProdTogglesManagerTest {
private companion object {
val localFeatureToggles = listOf(
Toggle(name = "INACTIVE_TEST_FEATURE_ENABLED", version = "undefined"),
Toggle(name = "ACTIVE2_TEST_FEATURE_ENABLED", version = "1.0.0"),
ConfigToggle(name = "INACTIVE_TEST_FEATURE_ENABLED", version = "undefined"),
ConfigToggle(name = "ACTIVE2_TEST_FEATURE_ENABLED", version = "1.0.0"),
)
val disabledFeatureToggles = mapOf(

View file

@ -1,11 +1,11 @@
package com.tangem.core.toggle.storage
package com.tangem.core.configtoggle.storage
import android.annotation.SuppressLint
import com.google.common.truth.Truth
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.tangem.core.toggle.feature.impl.FeatureTogglesConstants
import com.tangem.core.configtoggle.feature.impl.FeatureTogglesConstants
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.asset.reader.AssetReader
import io.mockk.*
@ -21,7 +21,7 @@ internal class LocalTogglesStorageTest {
private val assetReader = mockk<AssetReader>()
private val moshi = mockk<Moshi>()
private val jsonAdapter = mockk<JsonAdapter<List<Toggle>>>()
private val jsonAdapter = mockk<JsonAdapter<List<ConfigToggle>>>()
// Impossible to mockk AssetLoader because it implement inline functions
private val assetLoader = AssetLoader(assetReader = assetReader, moshi = moshi)
@ -57,7 +57,7 @@ internal class LocalTogglesStorageTest {
jsonAdapter.fromJson(json)
}
Truth.assertThat(storage.toggles).containsExactlyElementsIn(emptyList<Toggle>())
Truth.assertThat(storage.toggles).containsExactlyElementsIn(emptyList<ConfigToggle>())
}
@Test
@ -69,14 +69,14 @@ internal class LocalTogglesStorageTest {
coVerifyOrder { assetReader.read(CONFIG_FILE_NAME) }
verifyAll(inverse = true) { jsonAdapter.fromJson(any<String>()) }
Truth.assertThat(storage.toggles).containsExactlyElementsIn(emptyList<Toggle>())
Truth.assertThat(storage.toggles).containsExactlyElementsIn(emptyList<ConfigToggle>())
}
private fun everyReadingJson() = coEvery { assetReader.read(CONFIG_FILE_NAME) }
private fun everyCreatingMoshiAdapter() = every {
val types = Types.newParameterizedType(List::class.java, Toggle::class.java)
moshi.adapter<List<Toggle>>(types)
val types = Types.newParameterizedType(List::class.java, ConfigToggle::class.java)
moshi.adapter<List<ConfigToggle>>(types)
}
private fun everyMappingJson() = every { jsonAdapter.fromJson(json) }
@ -98,8 +98,8 @@ internal class LocalTogglesStorageTest {
""".trimIndent()
val featureToggles = listOf(
Toggle(name = "INACTIVE_TEST_FEATURE_ENABLED", version = "undefined"),
Toggle(name = "ACTIVE2_TEST_FEATURE_ENABLED", version = "1.0.0"),
ConfigToggle(name = "INACTIVE_TEST_FEATURE_ENABLED", version = "undefined"),
ConfigToggle(name = "ACTIVE2_TEST_FEATURE_ENABLED", version = "1.0.0"),
)
}
}

View file

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

View file

@ -98,12 +98,6 @@ 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,13 +0,0 @@
package com.tangem.core.toggle.utils
import com.tangem.core.toggle.storage.Toggle
import com.tangem.core.toggle.version.VersionAvailabilityContract
internal fun List<Toggle>.associateToggles(currentVersion: String): Map<String, Boolean> {
return associate { localToggle ->
Pair(
first = localToggle.name,
second = VersionAvailabilityContract(currentVersion, localToggle.version),
)
}
}