diff --git a/configuration-api-lib/build.gradle.kts b/configuration-api-lib/build.gradle.kts new file mode 100644 index 00000000..baa61298 --- /dev/null +++ b/configuration-api-lib/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + kotlin("multiplatform") + id("secant.kotlin-multiplatform-build-conventions") + id("secant.dependency-conventions") +} + +kotlin { + jvm() + sourceSets { + getByName("commonMain") { + dependencies { + api(libs.kotlinx.datetime) + api(libs.kotlinx.coroutines.core) + api(libs.kotlinx.immutable) + } + } + getByName("commonTest") { + dependencies { + implementation(kotlin("test")) + api(libs.kotlinx.coroutines.test) + } + } + getByName("jvmMain") { + dependencies { + } + } + getByName("jvmTest") { + dependencies { + implementation(kotlin("test")) + } + } + } +} diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/api/ConfigurationProvider.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/api/ConfigurationProvider.kt new file mode 100644 index 00000000..8532aacd --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/api/ConfigurationProvider.kt @@ -0,0 +1,25 @@ +package co.electriccoin.zcash.configuration.api + +import co.electriccoin.zcash.configuration.model.map.Configuration +import kotlinx.coroutines.flow.Flow + +/** + * Provides a remote config implementation. + */ +interface ConfigurationProvider { + + /** + * @return The configuration if it has been loaded already. If not loaded, returns an empty configuration. + */ + fun peekConfiguration(): Configuration + + /** + * @return A flow that provides snapshots of configuration updates. + */ + fun getConfigurationFlow(): Flow + + /** + * Signals to the configuration provider that now might be a good time to refresh. + */ + fun hintToRefresh() +} diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/api/MergingConfigurationProvider.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/api/MergingConfigurationProvider.kt new file mode 100644 index 00000000..6f11329b --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/api/MergingConfigurationProvider.kt @@ -0,0 +1,53 @@ +package co.electriccoin.zcash.configuration.api + +import co.electriccoin.zcash.configuration.model.entry.ConfigKey +import co.electriccoin.zcash.configuration.model.map.Configuration +import kotlinx.collections.immutable.PersistentList +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.datetime.Instant + +class MergingConfigurationProvider(private val configurationProviders: PersistentList) : ConfigurationProvider { + override fun peekConfiguration(): Configuration { + return MergingConfiguration(configurationProviders.map { it.peekConfiguration() }.toPersistentList()) + } + + override fun getConfigurationFlow(): Flow { + return combine(configurationProviders.map { it.getConfigurationFlow() }) { configurations -> + MergingConfiguration(configurations.toList()) + } + } + + override fun hintToRefresh() { + configurationProviders.forEach { it.hintToRefresh() } + } +} + +private data class MergingConfiguration(private val configurations: List) : Configuration { + override val updatedAt: Instant? + get() = configurations.mapNotNull { it.updatedAt }.maxOrNull() + + override fun hasKey(key: ConfigKey): Boolean { + return null != configurations.firstWithKey(key) + } + + override fun getBoolean(key: ConfigKey, defaultValue: Boolean): Boolean { + return configurations.firstWithKey(key)?.let { + return it.getBoolean(key, defaultValue) + } ?: defaultValue + } + + override fun getInt(key: ConfigKey, defaultValue: Int): Int { + return configurations.firstWithKey(key)?.let { + return it.getInt(key, defaultValue) + } ?: defaultValue + } + + override fun getString(key: ConfigKey, defaultValue: String): String { + return configurations.firstWithKey(key)?.let { + return it.getString(key, defaultValue) + } ?: defaultValue + } +} + +private fun List.firstWithKey(key: ConfigKey): Configuration? = firstOrNull { it.hasKey(key) } diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/BooleanConfigurationEntry.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/BooleanConfigurationEntry.kt new file mode 100644 index 00000000..15b6f1d8 --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/BooleanConfigurationEntry.kt @@ -0,0 +1,12 @@ +package co.electriccoin.zcash.configuration.model.entry + +import co.electriccoin.zcash.configuration.model.map.Configuration + +data class BooleanConfigurationEntry( + override val key: ConfigKey, + private val defaultValue: Boolean +) : DefaultEntry { + + override fun getValue(configuration: Configuration) = + configuration.getBoolean(key, defaultValue) +} diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/ConfigKey.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/ConfigKey.kt new file mode 100644 index 00000000..3c755aa2 --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/ConfigKey.kt @@ -0,0 +1,37 @@ +package co.electriccoin.zcash.configuration.model.entry + +/** + * Defines a configuration key. + * + * Different configuration providers have unique restrictions on keys. This attempts to find a + * least common denominator with some reasonable limits on what the keys can contain. + */ +@JvmInline +value class ConfigKey(val key: String) { + init { + requireKeyConstraints(key) + } + + companion object { + private const val MIN_KEY_LENGTH = 1 + private const val MAX_KEY_LENGTH = 256 + + private val REGEX = Regex("[a-zA-Z0-9_]*") + + /** + * Checks a configuration key against known constraints. + * + * @param key Key to check. + */ + private fun requireKeyConstraints(key: String) { + require(key.length in 1..MAX_KEY_LENGTH) { + "Invalid key $key. Length (${key.length}) is not in the range [$MIN_KEY_LENGTH, $MAX_KEY_LENGTH]." + } + + // This is a Firebase requirement + require(!key.first().isDigit()) { "Invalid key $key. Key must not start with a number." } + + require(REGEX.matches(key)) { "Invalid key $key. Key must contain only letter and numbers." } + } + } +} diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/DefaultEntry.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/DefaultEntry.kt new file mode 100644 index 00000000..8cd042d5 --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/DefaultEntry.kt @@ -0,0 +1,29 @@ +package co.electriccoin.zcash.configuration.model.entry + +import co.electriccoin.zcash.configuration.model.map.Configuration + +/** + * An entry represents a key and a default value for the configuration. By using an entry object, + * multiple parts of the code can fetch the same configuration without duplication or accidental + * variation in default value. Clients define the key and default value together, rather than just + * the key. + */ +/* + * API note: the default value is not available through the public interface in order to prevent + * clients from accidentally using the default value instead of the configuration value. + * + * Implementation note: although primitives would be nice, Objects don't increase memory usage much. + * The autoboxing cache solves Booleans, and Strings are already objects, so that just leaves Integers. + * Overall the number of Integer configuration entries is expected to be low compared to Booleans, + * and perhaps many Integer values will also fit within the autoboxing cache. + */ +interface DefaultEntry { + + val key: ConfigKey + + /** + * @param configuration Configuration mapping to check for the key given to this entry. + * @return The value in the configuration, or the default value if no mapping exists. + */ + fun getValue(configuration: Configuration): T +} diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/IntegerConfigurationEntry.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/IntegerConfigurationEntry.kt new file mode 100644 index 00000000..230c869f --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/IntegerConfigurationEntry.kt @@ -0,0 +1,11 @@ +package co.electriccoin.zcash.configuration.model.entry + +import co.electriccoin.zcash.configuration.model.map.Configuration + +data class IntegerConfigurationEntry( + override val key: ConfigKey, + private val defaultValue: Int +) : DefaultEntry { + + override fun getValue(configuration: Configuration) = configuration.getInt(key, defaultValue) +} diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/StringConfigurationEntry.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/StringConfigurationEntry.kt new file mode 100644 index 00000000..1baef519 --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/entry/StringConfigurationEntry.kt @@ -0,0 +1,11 @@ +package co.electriccoin.zcash.configuration.model.entry + +import co.electriccoin.zcash.configuration.model.map.Configuration + +data class StringConfigurationEntry( + override val key: ConfigKey, + private val defaultValue: String +) : DefaultEntry { + + override fun getValue(configuration: Configuration) = configuration.getString(key, defaultValue) +} diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/map/Configuration.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/map/Configuration.kt new file mode 100644 index 00000000..d6803524 --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/map/Configuration.kt @@ -0,0 +1,47 @@ +package co.electriccoin.zcash.configuration.model.map + +import co.electriccoin.zcash.configuration.model.entry.ConfigKey +import kotlinx.datetime.Instant + +/** + * An immutable snapshot of a key-value configuration. + */ +interface Configuration { + /** + * @return When the configuration was updated. Null indicates the configuration either doesn't refresh or has never been refreshed. + */ + val updatedAt: Instant? + + /** + * @param key Key to check. + * @return True if a mapping for `key` exists. + */ + fun hasKey(key: ConfigKey): Boolean + + /** + * @param key Key to use to retrieve the value. + * @param defaultValue Value to use if `key` doesn't exist in the + * configuration. Some implementations may not use strong types, and the default can also + * be returned if type coercion fails. + * @return boolean mapping for `key` or `defaultValue`. + */ + fun getBoolean(key: ConfigKey, defaultValue: Boolean): Boolean + + /** + * @param key Key to use to retrieve the value. + * @param defaultValue Value to use if `key` doesn't exist in the + * configuration. Some implementations may not use strong types, and the default can also + * be returned if type coercion fails. + * @return int mapping for `key` or `defaultValue`. + */ + fun getInt(key: ConfigKey, defaultValue: Int): Int + + /** + * @param key Key to use to retrieve the value. + * @param defaultValue Value to use if `key` doesn't exist in the + * configuration. Some implementations may not use strong types, and the default can also + * be returned if type coercion fails. + * @return String mapping for `key` or `defaultValue`. + */ + fun getString(key: ConfigKey, defaultValue: String): String +} diff --git a/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/map/StringConfiguration.kt b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/map/StringConfiguration.kt new file mode 100644 index 00000000..600ad6e3 --- /dev/null +++ b/configuration-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/configuration/model/map/StringConfiguration.kt @@ -0,0 +1,35 @@ +package co.electriccoin.zcash.configuration.model.map + +import co.electriccoin.zcash.configuration.model.entry.ConfigKey +import kotlinx.collections.immutable.PersistentMap +import kotlinx.datetime.Instant + +// The configurationMapping is intended to be a public API for configuration implementations rather +// than a public API for configuration clients. +data class StringConfiguration(val configurationMapping: PersistentMap, override val updatedAt: Instant?) : Configuration { + + override fun getBoolean( + key: ConfigKey, + defaultValue: Boolean + ) = configurationMapping[key.key]?.let { + try { + it.toBooleanStrict() + } catch (@Suppress("SwallowedException") e: IllegalArgumentException) { + // In the future, log coercion failure as this could mean someone made an error in the remote config console + defaultValue + } + } ?: defaultValue + + override fun getInt(key: ConfigKey, defaultValue: Int) = configurationMapping[key.key]?.let { + try { + it.toInt() + } catch (@Suppress("SwallowedException") e: NumberFormatException) { + // In the future, log coercion failure as this could mean someone made an error in the remote config console + defaultValue + } + } ?: defaultValue + + override fun getString(key: ConfigKey, defaultValue: String) = configurationMapping.getOrElse(key.key) { defaultValue } + + override fun hasKey(key: ConfigKey) = configurationMapping.containsKey(key.key) +} diff --git a/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/api/MergingConfigurationProviderTest.kt b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/api/MergingConfigurationProviderTest.kt new file mode 100644 index 00000000..ee5a6a63 --- /dev/null +++ b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/api/MergingConfigurationProviderTest.kt @@ -0,0 +1,75 @@ +package co.electriccoin.zcash.configuration.api + +import co.electriccoin.zcash.configuration.model.map.Configuration +import co.electriccoin.zcash.configuration.model.map.StringConfiguration +import co.electriccoin.zcash.configuration.test.fixture.BooleanDefaultEntryFixture +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import kotlinx.datetime.toInstant +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class MergingConfigurationProviderTest { + @Test + fun peek_ordering() { + val configurationProvider = MergingConfigurationProvider( + persistentListOf( + MockConfigurationProvider(StringConfiguration(persistentMapOf(BooleanDefaultEntryFixture.KEY.key to true.toString()), null)), + MockConfigurationProvider(StringConfiguration(persistentMapOf(BooleanDefaultEntryFixture.KEY.key to false.toString()), null)) + ) + ) + + assertTrue(BooleanDefaultEntryFixture.newTrueEntry().getValue(configurationProvider.peekConfiguration())) + } + + @Test + @OptIn(ExperimentalCoroutinesApi::class) + fun getFlow_ordering() = runTest { + val configurationProvider = MergingConfigurationProvider( + persistentListOf( + MockConfigurationProvider(StringConfiguration(persistentMapOf(BooleanDefaultEntryFixture.KEY.key to true.toString()), null)), + MockConfigurationProvider(StringConfiguration(persistentMapOf(BooleanDefaultEntryFixture.KEY.key to false.toString()), null)) + ) + ) + + assertTrue(BooleanDefaultEntryFixture.newTrueEntry().getValue(configurationProvider.getConfigurationFlow().first())) + } + + @Test + @OptIn(ExperimentalCoroutinesApi::class) + fun getUpdatedAt_newest() = runTest { + val older = "2023-01-15T08:38:45.415Z".toInstant() + val newer = "2023-01-17T08:38:45.415Z".toInstant() + + val configurationProvider = MergingConfigurationProvider( + persistentListOf( + MockConfigurationProvider(StringConfiguration(persistentMapOf(BooleanDefaultEntryFixture.KEY.key to true.toString()), older)), + MockConfigurationProvider(StringConfiguration(persistentMapOf(BooleanDefaultEntryFixture.KEY.key to false.toString()), newer)) + ) + ) + + val updatedAt = configurationProvider.getConfigurationFlow().first().updatedAt + assertEquals(newer, updatedAt) + } +} + +private class MockConfigurationProvider(private val configuration: Configuration) : ConfigurationProvider { + + override fun peekConfiguration(): Configuration { + return configuration + } + + override fun getConfigurationFlow(): Flow { + return flowOf(configuration) + } + + override fun hintToRefresh() { + // no-op + } +} diff --git a/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/BooleanDefaultEntryTest.kt b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/BooleanDefaultEntryTest.kt new file mode 100644 index 00000000..38e46a56 --- /dev/null +++ b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/BooleanDefaultEntryTest.kt @@ -0,0 +1,41 @@ +package co.electriccoin.zcash.configuration.model.entry + +import co.electriccoin.zcash.configuration.test.MockConfiguration +import co.electriccoin.zcash.configuration.test.fixture.BooleanDefaultEntryFixture +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class BooleanDefaultEntryTest { + @Test + fun key() { + assertEquals(BooleanDefaultEntryFixture.KEY, BooleanDefaultEntryFixture.newTrueEntry().key) + } + + @Test + fun value_default_true() { + val entry = BooleanDefaultEntryFixture.newTrueEntry() + assertTrue(entry.getValue(MockConfiguration())) + } + + @Test + fun value_default_false() { + val entry = BooleanDefaultEntryFixture.newFalseEntry() + assertFalse(entry.getValue(MockConfiguration())) + } + + @Test + fun value_from_config_false() { + val entry = BooleanDefaultEntryFixture.newTrueEntry() + val config = MockConfiguration(mapOf(BooleanDefaultEntryFixture.KEY.key to false.toString())) + assertFalse(entry.getValue(config)) + } + + @Test + fun value_from_config_true() { + val entry = BooleanDefaultEntryFixture.newTrueEntry() + val config = MockConfiguration(mapOf(BooleanDefaultEntryFixture.KEY.key to true.toString())) + assertTrue(entry.getValue(config)) + } +} diff --git a/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/IntegerDefaultEntryTest.kt b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/IntegerDefaultEntryTest.kt new file mode 100644 index 00000000..11e805af --- /dev/null +++ b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/IntegerDefaultEntryTest.kt @@ -0,0 +1,27 @@ +package co.electriccoin.zcash.configuration.model.entry + +import co.electriccoin.zcash.configuration.test.MockConfiguration +import co.electriccoin.zcash.configuration.test.fixture.IntegerDefaultEntryFixture +import kotlin.test.Test +import kotlin.test.assertEquals + +class IntegerDefaultEntryTest { + @Test + fun key() { + assertEquals(IntegerDefaultEntryFixture.KEY, IntegerDefaultEntryFixture.newEntry().key) + } + + @Test + fun value_default() { + val entry = IntegerDefaultEntryFixture.newEntry() + assertEquals(IntegerDefaultEntryFixture.DEFAULT_VALUE, entry.getValue(MockConfiguration())) + } + + @Test + fun value_override() { + val expected = IntegerDefaultEntryFixture.DEFAULT_VALUE + 5 + + val entry = IntegerDefaultEntryFixture.newEntry() + assertEquals(expected, entry.getValue(MockConfiguration(mapOf(IntegerDefaultEntryFixture.KEY.key to expected.toString())))) + } +} diff --git a/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/StringDefaultEntryTest.kt b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/StringDefaultEntryTest.kt new file mode 100644 index 00000000..65f76ce8 --- /dev/null +++ b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/model/entry/StringDefaultEntryTest.kt @@ -0,0 +1,25 @@ +package co.electriccoin.zcash.configuration.model.entry + +import co.electriccoin.zcash.configuration.test.MockConfiguration +import co.electriccoin.zcash.configuration.test.fixture.StringDefaultEntryFixture +import kotlin.test.Test +import kotlin.test.assertEquals + +class StringDefaultEntryTest { + @Test + fun key() { + assertEquals(StringDefaultEntryFixture.KEY, StringDefaultEntryFixture.newEntryEntry().key) + } + + @Test + fun value_default() { + val entry = StringDefaultEntryFixture.newEntryEntry() + assertEquals(StringDefaultEntryFixture.DEFAULT_VALUE, entry.getValue(MockConfiguration())) + } + + @Test + fun value_override() { + val entry = StringDefaultEntryFixture.newEntryEntry() + assertEquals("override", entry.getValue(MockConfiguration(mapOf(StringDefaultEntryFixture.KEY.key to "override")))) + } +} diff --git a/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/MockConfiguration.kt b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/MockConfiguration.kt new file mode 100644 index 00000000..c281ce59 --- /dev/null +++ b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/MockConfiguration.kt @@ -0,0 +1,41 @@ +package co.electriccoin.zcash.configuration.test + +import co.electriccoin.zcash.configuration.model.entry.ConfigKey +import co.electriccoin.zcash.configuration.model.map.Configuration +import kotlinx.datetime.Instant + +/** + * @param configurationMapping A mapping of key-value pairs to be returned + * by [.getString]. Note: this map is not defensively copied, allowing users of this class to + * mutate the configuration by mutating the original map. The mapping is stored in a val field + * though, making the initial mapping thread-safe. + */ +class MockConfiguration(private val configurationMapping: Map = emptyMap()) : Configuration { + + override val updatedAt: Instant? = null + + override fun getBoolean( + key: ConfigKey, + defaultValue: Boolean + ) = configurationMapping[key.key]?.let { + try { + it.toBooleanStrict() + } catch (@Suppress("SwallowedException") e: IllegalArgumentException) { + // In the future, log coercion failure as this could mean someone made an error in the remote config console + defaultValue + } + } ?: defaultValue + + override fun getInt(key: ConfigKey, defaultValue: Int) = configurationMapping[key.key]?.let { + try { + it.toInt() + } catch (@Suppress("SwallowedException") e: NumberFormatException) { + // In the future, log coercion failure as this could mean someone made an error in the remote config console + defaultValue + } + } ?: defaultValue + + override fun getString(key: ConfigKey, defaultValue: String) = configurationMapping.getOrElse(key.key) { defaultValue } + + override fun hasKey(key: ConfigKey) = configurationMapping.containsKey(key.key) +} diff --git a/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/BooleanDefaultEntryFixture.kt b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/BooleanDefaultEntryFixture.kt new file mode 100644 index 00000000..9144ee69 --- /dev/null +++ b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/BooleanDefaultEntryFixture.kt @@ -0,0 +1,13 @@ +package co.electriccoin.zcash.configuration.test.fixture + +import co.electriccoin.zcash.configuration.model.entry.BooleanConfigurationEntry +import co.electriccoin.zcash.configuration.model.entry.ConfigKey + +object BooleanDefaultEntryFixture { + + val KEY = ConfigKey("some_boolean_key") // $NON-NLS + + fun newTrueEntry() = BooleanConfigurationEntry(KEY, true) + + fun newFalseEntry() = BooleanConfigurationEntry(KEY, false) +} diff --git a/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/IntegerDefaultEntryFixture.kt b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/IntegerDefaultEntryFixture.kt new file mode 100644 index 00000000..c8ce150b --- /dev/null +++ b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/IntegerDefaultEntryFixture.kt @@ -0,0 +1,10 @@ +package co.electriccoin.zcash.configuration.test.fixture + +import co.electriccoin.zcash.configuration.model.entry.ConfigKey +import co.electriccoin.zcash.configuration.model.entry.IntegerConfigurationEntry + +object IntegerDefaultEntryFixture { + val KEY = ConfigKey("some_string_key") // $NON-NLS + const val DEFAULT_VALUE = 123 + fun newEntry(key: ConfigKey = KEY, value: Int = DEFAULT_VALUE) = IntegerConfigurationEntry(key, value) +} diff --git a/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/StringDefaultEntryFixture.kt b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/StringDefaultEntryFixture.kt new file mode 100644 index 00000000..76271876 --- /dev/null +++ b/configuration-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/configuration/test/fixture/StringDefaultEntryFixture.kt @@ -0,0 +1,10 @@ +package co.electriccoin.zcash.configuration.test.fixture + +import co.electriccoin.zcash.configuration.model.entry.ConfigKey +import co.electriccoin.zcash.configuration.model.entry.StringConfigurationEntry + +object StringDefaultEntryFixture { + val KEY = ConfigKey("some_string_key") // $NON-NLS + const val DEFAULT_VALUE = "some_default_value" // $NON-NLS + fun newEntryEntry(key: ConfigKey = KEY, value: String = DEFAULT_VALUE) = StringConfigurationEntry(key, value) +} diff --git a/docs/Architecture.md b/docs/Architecture.md index 91847fc0..21aada9a 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -26,6 +26,7 @@ The logical components of the app are implemented as a number of Gradle modules. * `app` — Compiles all the modules together into the final application. This module contains minimal actual code. Note that the Java package structure for this module is under `co.electriccoin.zcash.app` while the Android package name is `co.electriccoin.zcash`. * `build-info-lib` — Collects information from the build environment (e.g. Git SHA, Git commit count) and compiles them into the application. Can also be used for injection of API keys or other secrets. + * `configuration-api-lib` — Multiplatform interfaces for remote configuration. * crash — For collecting and reporting exceptions and crashes * `crash-lib` — Common crash collection logic for Kotlin and JVM. This is not fully-featured by itself, but the long-term plan is multiplatform support. * `crash-android-lib` — Android-specific crash collection logic, built on top of the common and JVM implementation in `crash-lib` diff --git a/gradle.properties b/gradle.properties index 832acccc..9b06eb4c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -144,6 +144,7 @@ JACOCO_VERSION=0.8.8 KOTLIN_VERSION=1.8.10 KOTLINX_COROUTINES_VERSION=1.6.4 KOTLINX_DATETIME_VERSION=0.4.0 +KOTLINX_IMMUTABLE_COLLECTIONS_VERSION=0.3.5 KOVER_VERSION=0.6.1 PLAY_APP_UPDATE_VERSION=2.0.1 PLAY_APP_UPDATE_KTX_VERSION=2.0.1 diff --git a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/api/PreferenceProvider.kt b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/api/PreferenceProvider.kt index edcec984..6b65280b 100644 --- a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/api/PreferenceProvider.kt +++ b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/api/PreferenceProvider.kt @@ -1,19 +1,15 @@ package co.electriccoin.zcash.preference.api -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey import kotlinx.coroutines.flow.Flow interface PreferenceProvider { - suspend fun hasKey(key: Key): Boolean + suspend fun hasKey(key: PreferenceKey): Boolean - suspend fun putString(key: Key, value: String?) + suspend fun putString(key: PreferenceKey, value: String?) - suspend fun getString(key: Key): String? + suspend fun getString(key: PreferenceKey): String? - /** - * @return Flow to observe potential changes to the value associated with the key in the preferences. - * Consumers of the flow will need to then query the value and determine whether it has changed. - */ - fun observe(key: Key): Flow + fun observe(key: PreferenceKey): Flow } diff --git a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/BooleanPreferenceDefault.kt b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/BooleanPreferenceDefault.kt index 0c596a0f..ec4675f2 100644 --- a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/BooleanPreferenceDefault.kt +++ b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/BooleanPreferenceDefault.kt @@ -3,7 +3,7 @@ package co.electriccoin.zcash.preference.model.entry import co.electriccoin.zcash.preference.api.PreferenceProvider data class BooleanPreferenceDefault( - override val key: Key, + override val key: PreferenceKey, private val defaultValue: Boolean ) : PreferenceDefault { diff --git a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/IntegerPreferenceDefault.kt b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/IntegerPreferenceDefault.kt index afb7fc92..f352734f 100644 --- a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/IntegerPreferenceDefault.kt +++ b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/IntegerPreferenceDefault.kt @@ -3,7 +3,7 @@ package co.electriccoin.zcash.preference.model.entry import co.electriccoin.zcash.preference.api.PreferenceProvider data class IntegerPreferenceDefault( - override val key: Key, + override val key: PreferenceKey, private val defaultValue: Int ) : PreferenceDefault { diff --git a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/PreferenceDefault.kt b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/PreferenceDefault.kt index 589c8d98..6f36fd57 100644 --- a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/PreferenceDefault.kt +++ b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/PreferenceDefault.kt @@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.map */ interface PreferenceDefault { - val key: Key + val key: PreferenceKey /** * @param preferenceProvider Provides actual preference values. diff --git a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/Key.kt b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/PreferenceKey.kt similarity index 95% rename from preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/Key.kt rename to preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/PreferenceKey.kt index 79cdf6f5..68f576fe 100644 --- a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/Key.kt +++ b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/PreferenceKey.kt @@ -9,7 +9,7 @@ import kotlin.jvm.JvmInline * find a least common denominator with some reasonable limits on what the keys can contain. */ @JvmInline -value class Key(val key: String) { +value class PreferenceKey(val key: String) { init { requireKeyConstraints(key) } diff --git a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/StringPreferenceDefault.kt b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/StringPreferenceDefault.kt index 08072a3f..caaf5921 100644 --- a/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/StringPreferenceDefault.kt +++ b/preference-api-lib/src/commonMain/kotlin/co/electriccoin/zcash/preference/model/entry/StringPreferenceDefault.kt @@ -3,7 +3,7 @@ package co.electriccoin.zcash.preference.model.entry import co.electriccoin.zcash.preference.api.PreferenceProvider data class StringPreferenceDefault( - override val key: Key, + override val key: PreferenceKey, private val defaultValue: String ) : PreferenceDefault { diff --git a/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/MockPreferenceProvider.kt b/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/MockPreferenceProvider.kt index 89a0dfe9..f0fbdc99 100644 --- a/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/MockPreferenceProvider.kt +++ b/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/MockPreferenceProvider.kt @@ -1,9 +1,9 @@ package co.electriccoin.zcash.preference.test import co.electriccoin.zcash.preference.api.PreferenceProvider -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flow /** * @param mutableMapFactory Emits a new mutable map. Thread safety depends on the factory implementation. @@ -12,14 +12,14 @@ class MockPreferenceProvider(mutableMapFactory: () -> MutableMap = flowOf(Unit) + override fun observe(key: PreferenceKey): Flow = flow { emit(getString(key)) } - override suspend fun hasKey(key: Key) = map.containsKey(key.key) + override suspend fun hasKey(key: PreferenceKey) = map.containsKey(key.key) - override suspend fun putString(key: Key, value: String?) { + override suspend fun putString(key: PreferenceKey, value: String?) { map[key.key] = value } } diff --git a/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/BooleanPreferenceDefaultFixture.kt b/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/BooleanPreferenceDefaultFixture.kt index 8b30a4bd..d3f99b93 100644 --- a/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/BooleanPreferenceDefaultFixture.kt +++ b/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/BooleanPreferenceDefaultFixture.kt @@ -1,10 +1,10 @@ package co.electriccoin.zcash.preference.test.fixture import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey object BooleanPreferenceDefaultFixture { - val KEY = Key("some_boolean_key") // $NON-NLS + val KEY = PreferenceKey("some_boolean_key") // $NON-NLS fun newTrue() = BooleanPreferenceDefault(KEY, true) fun newFalse() = BooleanPreferenceDefault(KEY, false) } diff --git a/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/IntegerPreferenceDefaultFixture.kt b/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/IntegerPreferenceDefaultFixture.kt index eae5bb56..9250e9aa 100644 --- a/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/IntegerPreferenceDefaultFixture.kt +++ b/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/IntegerPreferenceDefaultFixture.kt @@ -1,10 +1,10 @@ package co.electriccoin.zcash.preference.test.fixture import co.electriccoin.zcash.preference.model.entry.IntegerPreferenceDefault -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey object IntegerPreferenceDefaultFixture { - val KEY = Key("some_string_key") // $NON-NLS + val KEY = PreferenceKey("some_string_key") // $NON-NLS const val DEFAULT_VALUE = 123 - fun new(key: Key = KEY, value: Int = DEFAULT_VALUE) = IntegerPreferenceDefault(key, value) + fun new(preferenceKey: PreferenceKey = KEY, value: Int = DEFAULT_VALUE) = IntegerPreferenceDefault(preferenceKey, value) } diff --git a/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/StringDefaultPreferenceFixture.kt b/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/StringDefaultPreferenceFixture.kt index 168c241b..c402b1a0 100644 --- a/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/StringDefaultPreferenceFixture.kt +++ b/preference-api-lib/src/commonTest/kotlin/co/electriccoin/zcash/preference/test/fixture/StringDefaultPreferenceFixture.kt @@ -1,10 +1,10 @@ package co.electriccoin.zcash.preference.test.fixture -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey import co.electriccoin.zcash.preference.model.entry.StringPreferenceDefault object StringDefaultPreferenceFixture { - val KEY = Key("some_string_key") // $NON-NLS + val KEY = PreferenceKey("some_string_key") // $NON-NLS const val DEFAULT_VALUE = "some_default_value" // $NON-NLS - fun new(key: Key = KEY, value: String = DEFAULT_VALUE) = StringPreferenceDefault(key, value) + fun new(preferenceKey: PreferenceKey = KEY, value: String = DEFAULT_VALUE) = StringPreferenceDefault(preferenceKey, value) } diff --git a/preference-impl-android-lib/src/androidTest/java/co/electriccoin/zcash/preference/test/fixture/StringDefaultPreferenceFixture.kt b/preference-impl-android-lib/src/androidTest/java/co/electriccoin/zcash/preference/test/fixture/StringDefaultPreferenceFixture.kt index 168c241b..c402b1a0 100644 --- a/preference-impl-android-lib/src/androidTest/java/co/electriccoin/zcash/preference/test/fixture/StringDefaultPreferenceFixture.kt +++ b/preference-impl-android-lib/src/androidTest/java/co/electriccoin/zcash/preference/test/fixture/StringDefaultPreferenceFixture.kt @@ -1,10 +1,10 @@ package co.electriccoin.zcash.preference.test.fixture -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey import co.electriccoin.zcash.preference.model.entry.StringPreferenceDefault object StringDefaultPreferenceFixture { - val KEY = Key("some_string_key") // $NON-NLS + val KEY = PreferenceKey("some_string_key") // $NON-NLS const val DEFAULT_VALUE = "some_default_value" // $NON-NLS - fun new(key: Key = KEY, value: String = DEFAULT_VALUE) = StringPreferenceDefault(key, value) + fun new(preferenceKey: PreferenceKey = KEY, value: String = DEFAULT_VALUE) = StringPreferenceDefault(preferenceKey, value) } diff --git a/preference-impl-android-lib/src/main/java/co/electriccoin/zcash/preference/AndroidPreferenceProvider.kt b/preference-impl-android-lib/src/main/java/co/electriccoin/zcash/preference/AndroidPreferenceProvider.kt index 55319a3e..f1ff4958 100644 --- a/preference-impl-android-lib/src/main/java/co/electriccoin/zcash/preference/AndroidPreferenceProvider.kt +++ b/preference-impl-android-lib/src/main/java/co/electriccoin/zcash/preference/AndroidPreferenceProvider.kt @@ -6,14 +6,14 @@ import android.content.SharedPreferences import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKey import co.electriccoin.zcash.preference.api.PreferenceProvider -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext import java.util.concurrent.Executors @@ -35,12 +35,12 @@ class AndroidPreferenceProvider( private val dispatcher: CoroutineDispatcher ) : PreferenceProvider { - override suspend fun hasKey(key: Key) = withContext(dispatcher) { + override suspend fun hasKey(key: PreferenceKey) = withContext(dispatcher) { sharedPreferences.contains(key.key) } @SuppressLint("ApplySharedPref") - override suspend fun putString(key: Key, value: String?) = withContext(dispatcher) { + override suspend fun putString(key: PreferenceKey, value: String?) = withContext(dispatcher) { val editor = sharedPreferences.edit() editor.putString(key.key, value) @@ -50,12 +50,11 @@ class AndroidPreferenceProvider( Unit } - override suspend fun getString(key: Key) = withContext(dispatcher) { + override suspend fun getString(key: PreferenceKey) = withContext(dispatcher) { sharedPreferences.getString(key.key, null) } - @OptIn(ExperimentalCoroutinesApi::class) - override fun observe(key: Key): Flow = callbackFlow { + override fun observe(key: PreferenceKey): Flow = callbackFlow { val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, _ -> // Callback on main thread trySend(Unit) @@ -69,6 +68,7 @@ class AndroidPreferenceProvider( sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) } }.flowOn(dispatcher) + .map { getString(key) } companion object { suspend fun newStandard(context: Context, filename: String): PreferenceProvider { diff --git a/settings.gradle.kts b/settings.gradle.kts index 11093409..1dd0e29b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -174,6 +174,7 @@ dependencyResolutionManagement { val kotlinVersion = extra["KOTLIN_VERSION"].toString() val kotlinxDateTimeVersion = extra["KOTLINX_DATETIME_VERSION"].toString() val kotlinxCoroutinesVersion = extra["KOTLINX_COROUTINES_VERSION"].toString() + val kotlinxImmutableCollectionsVersion = extra["KOTLINX_IMMUTABLE_COLLECTIONS_VERSION"].toString() val playAppUpdateVersion = extra["PLAY_APP_UPDATE_VERSION"].toString() val playAppUpdateKtxVersion = extra["PLAY_APP_UPDATE_KTX_VERSION"].toString() val zcashBip39Version = extra["ZCASH_BIP39_VERSION"].toString() @@ -225,6 +226,7 @@ dependencyResolutionManagement { library("kotlinx-coroutines-core", "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") library("kotlinx-coroutines-guava", "org.jetbrains.kotlinx:kotlinx-coroutines-guava:$kotlinxCoroutinesVersion") library("kotlinx-datetime", "org.jetbrains.kotlinx:kotlinx-datetime:$kotlinxDateTimeVersion") + library("kotlinx-immutable", "org.jetbrains.kotlinx:kotlinx-collections-immutable:$kotlinxImmutableCollectionsVersion") library("play-update", "com.google.android.play:app-update:$playAppUpdateVersion") library("play-update-ktx", "com.google.android.play:app-update-ktx:$playAppUpdateKtxVersion") library("zcash-sdk", "cash.z.ecc.android:zcash-android-sdk:$zcashSdkVersion") @@ -307,6 +309,7 @@ includeBuild("build-conventions-secant") include("app") include("build-info-lib") +include("configuration-api-lib") include("crash-lib") include("crash-android-lib") include("preference-api-lib") diff --git a/test-lib/src/main/AndroidManifest.xml b/test-lib/src/main/AndroidManifest.xml index b0509b82..03ff19ac 100644 --- a/test-lib/src/main/AndroidManifest.xml +++ b/test-lib/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - + diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/EncryptedPreferenceKeys.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/EncryptedPreferenceKeys.kt index eb602183..0bb09a0e 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/EncryptedPreferenceKeys.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/EncryptedPreferenceKeys.kt @@ -1,8 +1,8 @@ package co.electriccoin.zcash.ui.preference -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey object EncryptedPreferenceKeys { - val PERSISTABLE_WALLET = PersistableWalletPreferenceDefault(Key("persistable_wallet")) + val PERSISTABLE_WALLET = PersistableWalletPreferenceDefault(PreferenceKey("persistable_wallet")) } diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/FiatCurrencyPreferenceDefault.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/FiatCurrencyPreferenceDefault.kt index 0b08f8b0..8e1aec19 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/FiatCurrencyPreferenceDefault.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/FiatCurrencyPreferenceDefault.kt @@ -2,11 +2,11 @@ package co.electriccoin.zcash.ui.preference import cash.z.ecc.android.sdk.model.FiatCurrency import co.electriccoin.zcash.preference.api.PreferenceProvider -import co.electriccoin.zcash.preference.model.entry.Key import co.electriccoin.zcash.preference.model.entry.PreferenceDefault +import co.electriccoin.zcash.preference.model.entry.PreferenceKey data class FiatCurrencyPreferenceDefault( - override val key: Key + override val key: PreferenceKey ) : PreferenceDefault { override suspend fun getValue(preferenceProvider: PreferenceProvider) = diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/PersistableWalletPreferenceDefault.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/PersistableWalletPreferenceDefault.kt index bcee7827..debba0a2 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/PersistableWalletPreferenceDefault.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/PersistableWalletPreferenceDefault.kt @@ -2,12 +2,12 @@ package co.electriccoin.zcash.ui.preference import cash.z.ecc.android.sdk.model.PersistableWallet import co.electriccoin.zcash.preference.api.PreferenceProvider -import co.electriccoin.zcash.preference.model.entry.Key import co.electriccoin.zcash.preference.model.entry.PreferenceDefault +import co.electriccoin.zcash.preference.model.entry.PreferenceKey import org.json.JSONObject data class PersistableWalletPreferenceDefault( - override val key: Key + override val key: PreferenceKey ) : PreferenceDefault { override suspend fun getValue(preferenceProvider: PreferenceProvider) = diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/StandardPreferenceKeys.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/StandardPreferenceKeys.kt index fd2d0c70..a1be24a3 100644 --- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/StandardPreferenceKeys.kt +++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/preference/StandardPreferenceKeys.kt @@ -1,24 +1,24 @@ package co.electriccoin.zcash.ui.preference import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault -import co.electriccoin.zcash.preference.model.entry.Key +import co.electriccoin.zcash.preference.model.entry.PreferenceKey object StandardPreferenceKeys { /** * Whether the user has completed the backup flow for a newly created wallet. */ - val IS_USER_BACKUP_COMPLETE = BooleanPreferenceDefault(Key("is_user_backup_complete"), false) + val IS_USER_BACKUP_COMPLETE = BooleanPreferenceDefault(PreferenceKey("is_user_backup_complete"), false) // Default to true until https://github.com/zcash/secant-android-wallet/issues/304 - val IS_ANALYTICS_ENABLED = BooleanPreferenceDefault(Key("is_analytics_enabled"), true) + val IS_ANALYTICS_ENABLED = BooleanPreferenceDefault(PreferenceKey("is_analytics_enabled"), true) - val IS_BACKGROUND_SYNC_ENABLED = BooleanPreferenceDefault(Key("is_background_sync_enabled"), true) + val IS_BACKGROUND_SYNC_ENABLED = BooleanPreferenceDefault(PreferenceKey("is_background_sync_enabled"), true) - val IS_KEEP_SCREEN_ON_DURING_SYNC = BooleanPreferenceDefault(Key("is_keep_screen_on_during_sync"), true) + val IS_KEEP_SCREEN_ON_DURING_SYNC = BooleanPreferenceDefault(PreferenceKey("is_keep_screen_on_during_sync"), true) /** * The fiat currency that the user prefers. */ - val PREFERRED_FIAT_CURRENCY = FiatCurrencyPreferenceDefault(Key("preferred_fiat_currency_code")) + val PREFERRED_FIAT_CURRENCY = FiatCurrencyPreferenceDefault(PreferenceKey("preferred_fiat_currency_code")) }