Skip to content

Commit

Permalink
Merge pull request #82 from russhwolf/0.7.4
Browse files Browse the repository at this point in the history
Version 0.7.4
  • Loading branch information
russhwolf authored Mar 14, 2021
2 parents e5c0eec + 0ce7938 commit 95bcdca
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 66 deletions.
10 changes: 9 additions & 1 deletion .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog #

## v0.7.4 *(2021-03-14)* ##

- Update to Kotlin 1.4.31
- Update `multiplatform-settings-datastore` to use DataStore version 1.0.0-alpha08
- Add `CoroutineDispatcher` parameter to `Settings.toSuspendSettings()` and `ObservableSettings().toFlowSettings()`
extension functions in `multiplatform-settings-coroutines` module

## v0.7.3 *(2021-02-20)* ##

- Fix remaining crash in `KeychainSettings.clear()` (issue #79)
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Then, simply add the dependency to your common source-set dependencies
commonMain {
dependencies {
// ...
implementation("com.russhwolf:multiplatform-settings:0.7.3")
implementation("com.russhwolf:multiplatform-settings:0.7.4")
}
}
```
Expand Down Expand Up @@ -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.3")
implementation("com.russhwolf:multiplatform-settings-no-arg:0.7.4")
```

Then from common code, you can write
Expand Down Expand Up @@ -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.3")
implementation("com.russhwolf:multiplatform-settings-test:0.7.4")
```

This includes a `MockSettings` implementation of the `Settings` interface, which is backed by an in-memory `MutableMap` on all platforms.
Expand Down Expand Up @@ -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.3")
implementation("com.russhwolf:multiplatform-settings-serialization:0.7.4")
```

This essentially uses the `Settings` store as a serialization format. Thus for a serializable class
Expand Down Expand Up @@ -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.3")
implementation("com.russhwolf:multiplatform-settings-coroutines:0.7.4")

// Or, if you use native-mt coroutines release
implementation("com.russhwolf:multiplatform-settings-coroutines-native-mt:0.7.3")
implementation("com.russhwolf:multiplatform-settings-coroutines-native-mt:0.7.4")
```

This adds flow extensions for all types which use the listener APIs internally.
Expand Down Expand Up @@ -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-datastore:0.7.3")
implementation("com.russhwolf:multiplatform-settings-datastore:0.7.4")
```

This provides a `DataStoreSettings` class
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

plugins {
kotlin("jvm") version "1.4.30"
kotlin("jvm") version "1.4.31"
}

repositories {
Expand Down
12 changes: 6 additions & 6 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@
@file:Suppress("KDocMissingDocumentation")

object Versions {
const val multiplatformSettings = "0.7.3"
const val multiplatformSettings = "0.7.4"

const val minSdk = 15
const val compileSdk = 30

const val androidxDatastore = "1.0.0-alpha06"
const val androidxDatastore = "1.0.0-alpha08"
const val androidxPreference = "1.1.1"
const val androidxStartup = "1.0.0"
const val androidxTest = "1.3.0"
const val androidxTestExt = "1.1.2"
const val binaryCompatibilityValidator = "0.2.4"
const val coroutines = "1.4.2"
const val coroutinesNativeMt = "1.4.2-native-mt"
const val junit = "4.13.1"
const val robolectric = "4.4"
const val serializationPlugin = "1.4.30"
const val junit = "4.13.2"
const val robolectric = "4.5.1"
const val serializationPlugin = "1.4.31"
const val serializationRuntime = "1.1.0"
const val turbine = "0.3.0"
const val turbine = "0.4.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,97 +19,158 @@ package com.russhwolf.settings.coroutines
import com.russhwolf.settings.ExperimentalSettingsApi
import com.russhwolf.settings.ObservableSettings
import com.russhwolf.settings.Settings
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.withContext

/**
* Wraps this [Settings] in the [SuspendSettings] interface.
*/
@ExperimentalSettingsApi
public fun Settings.toSuspendSettings(): SuspendSettings = SuspendSettingsWrapper(this)
public fun Settings.toSuspendSettings(
dispatcher: CoroutineDispatcher = Dispatchers.Default
): SuspendSettings =
SuspendSettingsWrapper(this, dispatcher)

/**
* Wraps this [ObservableSettings] in the [FlowSettings] interface.
*/
@ExperimentalSettingsApi
@ExperimentalCoroutinesApi
public fun ObservableSettings.toFlowSettings(): FlowSettings = FlowSettingsWrapper(this)
public fun ObservableSettings.toFlowSettings(
dispatcher: CoroutineDispatcher = Dispatchers.Default
): FlowSettings =
FlowSettingsWrapper(this, dispatcher)

@ExperimentalSettingsApi
private open class SuspendSettingsWrapper(private val delegate: Settings) : SuspendSettings {
public override suspend fun keys(): Set<String> = delegate.keys
public override suspend fun size(): Int = delegate.size
public override suspend fun clear() = delegate.clear()
public override suspend fun remove(key: String) = delegate.remove(key)
public override suspend fun hasKey(key: String): Boolean = delegate.hasKey(key)

public override suspend fun putInt(key: String, value: Int) = delegate.putInt(key, value)
public override suspend fun getInt(key: String, defaultValue: Int): Int = delegate.getInt(key, defaultValue)
public override suspend fun getIntOrNull(key: String): Int? = delegate.getIntOrNull(key)

public override suspend fun putLong(key: String, value: Long) = delegate.putLong(key, value)
public override suspend fun getLong(key: String, defaultValue: Long): Long =
private open class SuspendSettingsWrapper(
private val delegate: Settings,
private val dispatcher: CoroutineDispatcher
) : SuspendSettings {
public override suspend fun keys(): Set<String> = withContext(dispatcher) { delegate.keys }
public override suspend fun size(): Int = withContext(dispatcher) { delegate.size }
public override suspend fun clear() = withContext(dispatcher) { delegate.clear() }
public override suspend fun remove(key: String) = withContext(dispatcher) { delegate.remove(key) }
public override suspend fun hasKey(key: String): Boolean = withContext(dispatcher) { delegate.hasKey(key) }

public override suspend fun putInt(key: String, value: Int) = withContext(dispatcher) {
delegate.putInt(key, value)
}

public override suspend fun getInt(key: String, defaultValue: Int): Int = withContext(dispatcher) {
delegate.getInt(key, defaultValue)
}

public override suspend fun getIntOrNull(key: String): Int? = withContext(dispatcher) {
delegate.getIntOrNull(key)
}

public override suspend fun putLong(key: String, value: Long) = withContext(dispatcher) {
delegate.putLong(key, value)
}

public override suspend fun getLong(key: String, defaultValue: Long): Long = withContext(dispatcher) {
delegate.getLong(key, defaultValue)
}

public override suspend fun getLongOrNull(key: String): Long? = delegate.getLongOrNull(key)
public override suspend fun getLongOrNull(key: String): Long? = withContext(dispatcher) {
delegate.getLongOrNull(key)
}

public override suspend fun putString(key: String, value: String) = delegate.putString(key, value)
public override suspend fun getString(key: String, defaultValue: String): String =
public override suspend fun putString(key: String, value: String) = withContext(dispatcher) {
delegate.putString(key, value)
}

public override suspend fun getString(key: String, defaultValue: String): String = withContext(dispatcher) {
delegate.getString(key, defaultValue)
}

public override suspend fun getStringOrNull(key: String): String? = delegate.getStringOrNull(key)
public override suspend fun getStringOrNull(key: String): String? = withContext(dispatcher) {
delegate.getStringOrNull(key)
}

public override suspend fun putFloat(key: String, value: Float) = delegate.putFloat(key, value)
public override suspend fun getFloat(key: String, defaultValue: Float): Float =
public override suspend fun putFloat(key: String, value: Float) = withContext(dispatcher) {
delegate.putFloat(key, value)
}

public override suspend fun getFloat(key: String, defaultValue: Float): Float = withContext(dispatcher) {
delegate.getFloat(key, defaultValue)
}

public override suspend fun getFloatOrNull(key: String): Float? = delegate.getFloatOrNull(key)
public override suspend fun getFloatOrNull(key: String): Float? = withContext(dispatcher) {
delegate.getFloatOrNull(key)
}

public override suspend fun putDouble(key: String, value: Double) = delegate.putDouble(key, value)
public override suspend fun getDouble(key: String, defaultValue: Double): Double =
public override suspend fun putDouble(key: String, value: Double) = withContext(dispatcher) {
delegate.putDouble(key, value)
}

public override suspend fun getDouble(key: String, defaultValue: Double): Double = withContext(dispatcher) {
delegate.getDouble(key, defaultValue)
}

public override suspend fun getDoubleOrNull(key: String): Double? = delegate.getDoubleOrNull(key)
public override suspend fun getDoubleOrNull(key: String): Double? = withContext(dispatcher) {
delegate.getDoubleOrNull(key)
}

public override suspend fun putBoolean(key: String, value: Boolean) = delegate.putBoolean(key, value)
public override suspend fun getBoolean(key: String, defaultValue: Boolean): Boolean =
public override suspend fun putBoolean(key: String, value: Boolean) = withContext(dispatcher) {
delegate.putBoolean(key, value)
}

public override suspend fun getBoolean(key: String, defaultValue: Boolean): Boolean = withContext(dispatcher) {
delegate.getBoolean(key, defaultValue)
}

public override suspend fun getBooleanOrNull(key: String): Boolean? = delegate.getBooleanOrNull(key)
public override suspend fun getBooleanOrNull(key: String): Boolean? = withContext(dispatcher) {
delegate.getBooleanOrNull(key)
}
}

@ExperimentalSettingsApi
@ExperimentalCoroutinesApi
private class FlowSettingsWrapper(private val delegate: ObservableSettings) :
SuspendSettingsWrapper(delegate), FlowSettings {
private class FlowSettingsWrapper(
private val delegate: ObservableSettings,
private val dispatcher: CoroutineDispatcher
) : SuspendSettingsWrapper(delegate, dispatcher), FlowSettings {

public override fun getIntFlow(key: String, defaultValue: Int): Flow<Int> =
delegate.getIntFlow(key, defaultValue).flowOn(dispatcher)

public override fun getIntFlow(key: String, defaultValue: Int): Flow<Int> = delegate.getIntFlow(key, defaultValue)
public override fun getIntOrNullFlow(key: String): Flow<Int?> = delegate.getIntOrNullFlow(key)
public override fun getIntOrNullFlow(key: String): Flow<Int?> =
delegate.getIntOrNullFlow(key).flowOn(dispatcher)

public override fun getLongFlow(key: String, defaultValue: Long): Flow<Long> =
delegate.getLongFlow(key, defaultValue)
delegate.getLongFlow(key, defaultValue).flowOn(dispatcher)

public override fun getLongOrNullFlow(key: String): Flow<Long?> = delegate.getLongOrNullFlow(key)
public override fun getLongOrNullFlow(key: String): Flow<Long?> =
delegate.getLongOrNullFlow(key).flowOn(dispatcher)

public override fun getStringFlow(key: String, defaultValue: String): Flow<String> =
delegate.getStringFlow(key, defaultValue)
delegate.getStringFlow(key, defaultValue).flowOn(dispatcher)

public override fun getStringOrNullFlow(key: String): Flow<String?> = delegate.getStringOrNullFlow(key)
public override fun getStringOrNullFlow(key: String): Flow<String?> =
delegate.getStringOrNullFlow(key).flowOn(dispatcher)

public override fun getFloatFlow(key: String, defaultValue: Float): Flow<Float> =
delegate.getFloatFlow(key, defaultValue)
delegate.getFloatFlow(key, defaultValue).flowOn(dispatcher)

public override fun getFloatOrNullFlow(key: String): Flow<Float?> = delegate.getFloatOrNullFlow(key)
public override fun getFloatOrNullFlow(key: String): Flow<Float?> =
delegate.getFloatOrNullFlow(key).flowOn(dispatcher)

public override fun getDoubleFlow(key: String, defaultValue: Double): Flow<Double> =
delegate.getDoubleFlow(key, defaultValue)
delegate.getDoubleFlow(key, defaultValue).flowOn(dispatcher)

public override fun getDoubleOrNullFlow(key: String): Flow<Double?> = delegate.getDoubleOrNullFlow(key)
public override fun getDoubleOrNullFlow(key: String): Flow<Double?> =
delegate.getDoubleOrNullFlow(key).flowOn(dispatcher)

public override fun getBooleanFlow(key: String, defaultValue: Boolean): Flow<Boolean> =
delegate.getBooleanFlow(key, defaultValue)
delegate.getBooleanFlow(key, defaultValue).flowOn(dispatcher)

public override fun getBooleanOrNullFlow(key: String): Flow<Boolean?> = delegate.getBooleanOrNullFlow(key)
public override fun getBooleanOrNullFlow(key: String): Flow<Boolean?> =
delegate.getBooleanOrNullFlow(key).flowOn(dispatcher)

// Prefer the SuspendSettingsWrapper implementation to the FlowSettings one which calls getXXXFlow().first()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.russhwolf.settings.ExperimentalSettingsApi
import com.russhwolf.settings.MockSettings
import com.russhwolf.settings.ObservableSettings
import com.russhwolf.settings.Settings
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi

// TODO we should have test-cases specific to SuspendSettings and FlowSettings, but until we do we test things by
Expand All @@ -34,7 +35,9 @@ private val mockSettingsFactory = MockSettings.Factory()
class ToSuspendSettingsTest : BaseSettingsTest(
platformFactory = object : Settings.Factory {
override fun create(name: String?): Settings {
return mockSettingsFactory.create(name).toSuspendSettings().toBlockingSettings()
return mockSettingsFactory.create(name)
.toSuspendSettings(Dispatchers.Unconfined)
.toBlockingSettings()
}
},
hasListeners = false
Expand All @@ -44,7 +47,9 @@ class ToSuspendSettingsTest : BaseSettingsTest(
class ToFlowSettingsTest : BaseSettingsTest(
platformFactory = object : Settings.Factory {
override fun create(name: String?): Settings {
return (mockSettingsFactory.create(name) as ObservableSettings).toFlowSettings().toBlockingSettings()
return (mockSettingsFactory.create(name) as ObservableSettings)
.toFlowSettings(Dispatchers.Unconfined)
.toBlockingSettings()
}
},
hasListeners = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ public final class com/russhwolf/settings/coroutines/BlockingConvertersKt {
}

public final class com/russhwolf/settings/coroutines/ConvertersKt {
public static final fun toFlowSettings (Lcom/russhwolf/settings/ObservableSettings;)Lcom/russhwolf/settings/coroutines/FlowSettings;
public static final fun toSuspendSettings (Lcom/russhwolf/settings/Settings;)Lcom/russhwolf/settings/coroutines/SuspendSettings;
public static final fun toFlowSettings (Lcom/russhwolf/settings/ObservableSettings;Lkotlinx/coroutines/CoroutineDispatcher;)Lcom/russhwolf/settings/coroutines/FlowSettings;
public static synthetic fun toFlowSettings$default (Lcom/russhwolf/settings/ObservableSettings;Lkotlinx/coroutines/CoroutineDispatcher;ILjava/lang/Object;)Lcom/russhwolf/settings/coroutines/FlowSettings;
public static final fun toSuspendSettings (Lcom/russhwolf/settings/Settings;Lkotlinx/coroutines/CoroutineDispatcher;)Lcom/russhwolf/settings/coroutines/SuspendSettings;
public static synthetic fun toSuspendSettings$default (Lcom/russhwolf/settings/Settings;Lkotlinx/coroutines/CoroutineDispatcher;ILjava/lang/Object;)Lcom/russhwolf/settings/coroutines/SuspendSettings;
}

public final class com/russhwolf/settings/coroutines/CoroutineExtensionsKt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ public final class com/russhwolf/settings/coroutines/BlockingConvertersKt {
}

public final class com/russhwolf/settings/coroutines/ConvertersKt {
public static final fun toFlowSettings (Lcom/russhwolf/settings/ObservableSettings;)Lcom/russhwolf/settings/coroutines/FlowSettings;
public static final fun toSuspendSettings (Lcom/russhwolf/settings/Settings;)Lcom/russhwolf/settings/coroutines/SuspendSettings;
public static final fun toFlowSettings (Lcom/russhwolf/settings/ObservableSettings;Lkotlinx/coroutines/CoroutineDispatcher;)Lcom/russhwolf/settings/coroutines/FlowSettings;
public static synthetic fun toFlowSettings$default (Lcom/russhwolf/settings/ObservableSettings;Lkotlinx/coroutines/CoroutineDispatcher;ILjava/lang/Object;)Lcom/russhwolf/settings/coroutines/FlowSettings;
public static final fun toSuspendSettings (Lcom/russhwolf/settings/Settings;Lkotlinx/coroutines/CoroutineDispatcher;)Lcom/russhwolf/settings/coroutines/SuspendSettings;
public static synthetic fun toSuspendSettings$default (Lcom/russhwolf/settings/Settings;Lkotlinx/coroutines/CoroutineDispatcher;ILjava/lang/Object;)Lcom/russhwolf/settings/coroutines/SuspendSettings;
}

public final class com/russhwolf/settings/coroutines/CoroutineExtensionsKt {
Expand Down
Loading

0 comments on commit 95bcdca

Please sign in to comment.