diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d52cad..a6b05dfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog # +## v0.7.1 *(2021-01-17)* ## + +- Update `multiplatform-settings-datastore` to use DataStore version 1.0.0-alpha06 + ## v0.7 *(2020-12-26)* ## + - Kotlin 1.4.21 and other dependency updates - New typed update listeners - `addIntListener { int: Int -> ... }` in addition to `addListener { ... }` diff --git a/README.md b/README.md index 7b818cae..9362436d 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Then, simply add the dependency to your common source-set dependencies commonMain { dependencies { // ... - implementation("com.russhwolf:multiplatform-settings:0.7") + implementation("com.russhwolf:multiplatform-settings:0.7.1") } } ``` @@ -144,7 +144,7 @@ val factory: Settings.Factory = AppleSettings.Factory() To create a `Settings` instance from common without needing to pass platform-specific dependencies, add the `multiplatform-settings-no-arg` gradle dependency. This exports `multiplatform-settings` as an API dependency, so you can use it as a replacement for that default dependency. ```kotlin -implementation("com.russhwolf:multiplatform-settings-no-arg:0.7") +implementation("com.russhwolf:multiplatform-settings-no-arg:0.7.1") ``` Then from common code, you can write @@ -238,7 +238,7 @@ Note that for the `AppleSettings` implementation, some entries are unremovable a A testing dependency is available to aid in testing code that interacts with this library. ```kotlin -implementation("com.russhwolf:multiplatform-settings-test:0.7") +implementation("com.russhwolf:multiplatform-settings-test:0.7.1") ``` This includes a `MockSettings` implementation of the `Settings` interface, which is backed by an in-memory `MutableMap` on all platforms. @@ -309,7 +309,7 @@ On Apple platforms, the `AppleSettings` listeners are designed to work within th A `kotlinx-serialization` integration exists so it's easier to save non-primitive data ```kotlin -implementation("com.russhwolf:multiplatform-settings-serialization:0.7") +implementation("com.russhwolf:multiplatform-settings-serialization:0.7.1") ``` This essentially uses the `Settings` store as a serialization format. Thus for a serializable class @@ -346,10 +346,10 @@ Usage requires accepting both the `@ExperimentalSettingsApi` and `@ExperimentalS A separate `multiplatform-settings-coroutines` dependency includes various coroutine APIs. ```kotlin -implementation("com.russhwolf:multiplatform-settings-coroutines:0.7") +implementation("com.russhwolf:multiplatform-settings-coroutines:0.7.1") // Or, if you use native-mt coroutines release -implementation("com.russhwolf:multiplatform-settings-coroutines-native-mt:0.7") +implementation("com.russhwolf:multiplatform-settings-coroutines-native-mt:0.7.1") ``` This adds flow extensions for all types which use the listener APIs internally. @@ -389,7 +389,7 @@ val blockingSettings: Settings = suspendSettings.toBlockingSettings() An implementation of `FlowSettings` on the Android exists in the `multiplatform-settings-datastore` dependency, based on [Jetpack DataStore](https://developer.android.com/jetpack/androidx/releases/datastore) ```kotlin -implementation("com.russhwolf:multiplatform-settings-coroutines:0.7") +implementation("com.russhwolf:multiplatform-settings-coroutines:0.7.1") ``` This provides a `DataStoreSettings` class diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 3e5d47ce..0c3bc2ab 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -17,12 +17,12 @@ @file:Suppress("KDocMissingDocumentation") object Versions { - const val multiplatformSettings = "0.7" + const val multiplatformSettings = "0.7.1" const val minSdk = 15 const val compileSdk = 30 - const val androidxDatastore = "1.0.0-alpha05" + const val androidxDatastore = "1.0.0-alpha06" const val androidxPreference = "1.1.1" const val androidxStartup = "1.0.0" const val androidxTest = "1.3.0" diff --git a/multiplatform-settings-datastore/src/androidMain/kotlin/com/russhwolf/settings/datastore/DataStoreSettings.kt b/multiplatform-settings-datastore/src/androidMain/kotlin/com/russhwolf/settings/datastore/DataStoreSettings.kt index 6853ee5b..4f187cda 100644 --- a/multiplatform-settings-datastore/src/androidMain/kotlin/com/russhwolf/settings/datastore/DataStoreSettings.kt +++ b/multiplatform-settings-datastore/src/androidMain/kotlin/com/russhwolf/settings/datastore/DataStoreSettings.kt @@ -18,9 +18,14 @@ package com.russhwolf.settings.datastore import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.doublePreferencesKey import androidx.datastore.preferences.core.edit -import androidx.datastore.preferences.core.preferencesKey -import androidx.datastore.preferences.core.remove +import androidx.datastore.preferences.core.floatPreferencesKey +import androidx.datastore.preferences.core.intPreferencesKey +import androidx.datastore.preferences.core.longPreferencesKey +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.core.stringSetPreferencesKey import com.russhwolf.settings.ExperimentalSettingsApi import com.russhwolf.settings.ExperimentalSettingsImplementation import com.russhwolf.settings.coroutines.FlowSettings @@ -39,64 +44,69 @@ public class DataStoreSettings(private val datastore: DataStore) : public override suspend fun clear(): Unit = keys().forEach { remove(it) } public override suspend fun remove(key: String) { - datastore.edit { it.remove(preferencesKey(key)) } + datastore.edit { it.remove(stringSetPreferencesKey(key)) } } public override suspend fun hasKey(key: String): Boolean = - datastore.data.first().contains(preferencesKey(key)) + datastore.data.first().contains(stringSetPreferencesKey(key)) public override suspend fun putInt(key: String, value: Int) { - datastore.edit { it[preferencesKey(key)] = value } + datastore.edit { it[intPreferencesKey(key)] = value } } public override fun getIntFlow(key: String, defaultValue: Int): Flow = - datastore.data.map { it[preferencesKey(key)] ?: defaultValue } + datastore.data.map { it[intPreferencesKey(key)] ?: defaultValue } - public override fun getIntOrNullFlow(key: String): Flow = datastore.data.map { it[preferencesKey(key)] } + public override fun getIntOrNullFlow(key: String): Flow = + datastore.data.map { it[intPreferencesKey(key)] } public override suspend fun putLong(key: String, value: Long) { - datastore.edit { it[preferencesKey(key)] = value } + datastore.edit { it[longPreferencesKey(key)] = value } } public override fun getLongFlow(key: String, defaultValue: Long): Flow = - datastore.data.map { it[preferencesKey(key)] ?: defaultValue } + datastore.data.map { it[longPreferencesKey(key)] ?: defaultValue } - public override fun getLongOrNullFlow(key: String): Flow = datastore.data.map { it[preferencesKey(key)] } + public override fun getLongOrNullFlow(key: String): Flow = + datastore.data.map { it[longPreferencesKey(key)] } public override suspend fun putString(key: String, value: String) { - datastore.edit { it[preferencesKey(key)] = value } + datastore.edit { it[stringPreferencesKey(key)] = value } } public override fun getStringFlow(key: String, defaultValue: String): Flow = - datastore.data.map { it[preferencesKey(key)] ?: defaultValue } + datastore.data.map { it[stringPreferencesKey(key)] ?: defaultValue } - public override fun getStringOrNullFlow(key: String): Flow = datastore.data.map { it[preferencesKey(key)] } + public override fun getStringOrNullFlow(key: String): Flow = + datastore.data.map { it[stringPreferencesKey(key)] } public override suspend fun putFloat(key: String, value: Float) { - datastore.edit { it[preferencesKey(key)] = value } + datastore.edit { it[floatPreferencesKey(key)] = value } } public override fun getFloatFlow(key: String, defaultValue: Float): Flow = - datastore.data.map { it[preferencesKey(key)] ?: defaultValue } + datastore.data.map { it[floatPreferencesKey(key)] ?: defaultValue } - public override fun getFloatOrNullFlow(key: String): Flow = datastore.data.map { it[preferencesKey(key)] } + public override fun getFloatOrNullFlow(key: String): Flow = + datastore.data.map { it[floatPreferencesKey(key)] } public override suspend fun putDouble(key: String, value: Double) { - datastore.edit { it[preferencesKey(key)] = value } + datastore.edit { it[doublePreferencesKey(key)] = value } } public override fun getDoubleFlow(key: String, defaultValue: Double): Flow = - datastore.data.map { it[preferencesKey(key)] ?: defaultValue } + datastore.data.map { it[doublePreferencesKey(key)] ?: defaultValue } - public override fun getDoubleOrNullFlow(key: String): Flow = datastore.data.map { it[preferencesKey(key)] } + public override fun getDoubleOrNullFlow(key: String): Flow = + datastore.data.map { it[doublePreferencesKey(key)] } public override suspend fun putBoolean(key: String, value: Boolean) { - datastore.edit { it[preferencesKey(key)] = value } + datastore.edit { it[booleanPreferencesKey(key)] = value } } public override fun getBooleanFlow(key: String, defaultValue: Boolean): Flow = - datastore.data.map { it[preferencesKey(key)] ?: defaultValue } + datastore.data.map { it[booleanPreferencesKey(key)] ?: defaultValue } public override fun getBooleanOrNullFlow(key: String): Flow = - datastore.data.map { it[preferencesKey(key)] } + datastore.data.map { it[booleanPreferencesKey(key)] } } diff --git a/multiplatform-settings-datastore/src/androidTest/kotlin/com/russhwolf/settings/datastore/DataStoreSettingsTest.kt b/multiplatform-settings-datastore/src/androidTest/kotlin/com/russhwolf/settings/datastore/DataStoreSettingsTest.kt index e55b2fd5..0b0e421b 100644 --- a/multiplatform-settings-datastore/src/androidTest/kotlin/com/russhwolf/settings/datastore/DataStoreSettingsTest.kt +++ b/multiplatform-settings-datastore/src/androidTest/kotlin/com/russhwolf/settings/datastore/DataStoreSettingsTest.kt @@ -21,8 +21,13 @@ package com.russhwolf.settings.datastore import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.doublePreferencesKey import androidx.datastore.preferences.core.edit -import androidx.datastore.preferences.core.preferencesKey +import androidx.datastore.preferences.core.floatPreferencesKey +import androidx.datastore.preferences.core.intPreferencesKey +import androidx.datastore.preferences.core.longPreferencesKey +import androidx.datastore.preferences.core.stringPreferencesKey import com.russhwolf.settings.BaseSettingsTest import com.russhwolf.settings.ExperimentalSettingsApi import com.russhwolf.settings.ExperimentalSettingsImplementation @@ -52,6 +57,7 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import java.io.File import kotlin.test.assertEquals +import kotlin.test.fail private val temporaryFolder = TemporaryFolder() private val testScope = TestCoroutineScope() @@ -79,7 +85,7 @@ class DataStoreSettingsTest : BaseSettingsTest( val dataStore = PreferenceDataStoreFactory.create { File(temporaryFolder.root, "settings.preferences_pb") } val settings = DataStoreSettings(dataStore) - dataStore.edit { it[preferencesKey("a")] = 3 } + dataStore.edit { it[intPreferencesKey("a")] = 3 } assertEquals(3, settings.getInt("a")) } @@ -110,6 +116,19 @@ private class BlockingDataStoreSettings( private inline fun flowOrNull(): Flow = dataStore.data.map { it[preferencesKey(key)] }.catch {} + private inline fun preferencesKey(key: String): Preferences.Key { + @Suppress("UNCHECKED_CAST") + return when (T::class) { + Int::class -> intPreferencesKey(key) + Long::class -> longPreferencesKey(key) + String::class -> stringPreferencesKey(key) + Float::class -> floatPreferencesKey(key) + Double::class -> doublePreferencesKey(key) + Int::class -> booleanPreferencesKey(key) + else -> fail("invalid type") + } as Preferences.Key + } + private val scope = CoroutineScope(testScope.coroutineContext + SupervisorJob(testScope.coroutineContext[Job])) init {