Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Multiplatform Settings 1.0

Multiplatform Settings 1.0

Multiplatform Settings was one of the first mobile Kotlin Multiplatform libraries available for mobile apps. With Kotlin Multplatform Mobile approaching beta, Multiplatform Settings is having its 1.0 release. Let’s talk about it!

I’ll share insights from my journey as a first-time library developer, and talk about things I've been working on recently. We'll touch on things like API design choices, integration issues, and keeping up with a quickly-evolving ecosystem. You'll come away inspired to work on multiplatform libraries of your own.

Russell Wolf

June 03, 2022
Tweet

More Decks by Russell Wolf

Other Decks in Technology

Transcript

  1. expect class Settings { public fun getInt(key: String, defaultValue: Int

    = 0): Int } actual class Settings(private val delegate: SharedPreferences) { actual fun getInt(key: String, defaultValue: Int): Int = delegate.getInt(key, defaultValue) } actual class Settings(private val delegate: UserDefaultsWrapper) { actual fun getInt(key: String, defaultValue: Int): Int = if (hasKey(key)) delegate.integerForKey(key).toInt() else defaultValue }
  2. public interface Settings { public fun getInt(key: String, defaultValue: Int

    = 0): Int public fun getIntOrNull(key: String): Int? } public class AndroidSettings(private val delegate: SharedPreferences): ObservableSettings { public override fun getInt(key: String, defaultValue: Int): Int = delegate.getInt(key, defaultValue) public override fun getIntOrNull(key: String): Int? = if (delegate.contains(key)) delegate.getInt(key, 0) else null } public class AppleSettings(private val delegate: NSUserDefaults): ObservableSettings { public override fun getInt(key: String, defaultValue: Int): Int = if (hasKey(key)) delegate.integerForKey(key).toInt() else defaultValue public override fun getIntOrNull(key: String): Int? = if (hasKey(key)) delegate.intForKey(key) else null }
  3. public class AndroidSettings( .. . ): ObservableSettings public class AppleSettings(

    . .. ): ObservableSettings public class JsSettings( ... ): Settings public class JvmPropertiesSettings( .. . ): Settings public class JvmPreferencesSettings( . .. ): ObservableSettings public class WindowsSettings( .. . ): Settings public class KeychainSettings( . . . ): Settings public class MockSettings( . . . ): ObservableSettings
  4. public interface ObservableSettings : Settings { public fun addListener( key:

    String, callback: () -> Unit ): SettingsListener } public interface SettingsListener { public fun deactivate() } public inline fun ObservableSettings.addIntListener( key: String, defaultValue: Int = 0, crossinline callback: (Int) -> Unit ): SettingsListener = addListener(key) { callback(getInt(key, defaultValue)) }
  5. public interface Settings { public fun getInt(key: String, defaultValue: Int

    = 0): Int public fun getIntOrNull(key: String): Int? } public interface SuspendSettings { public suspend fun getInt(key: String, defaultValue: Int = 0): Int public suspend fun getIntOrNull(key: String): Int? } public interface FlowSettings : SuspendSettings { public fun getIntFlow(key: String, defaultValue: Int = 0): Flow<Int> public override suspend fun getInt(key: String, defaultValue: Int): Int = getIntFlow(key, defaultValue).first() public fun getIntOrNullFlow(key: String): Flow<Int?> public override suspend fun getIntOrNull(key: String): Int? = getIntOrNullFlow(key).first() }
  6. public fun <T> Settings.encodeValue( serializer: KSerializer<T>, key: String, value: T,

    serializersModule: SerializersModule = EmptySerializersModule ) { ... } public fun <T> Settings.decodeValue( serializer: KSerializer<T>, key: String, defaultValue: T, serializersModule: SerializersModule = EmptySerializersModule ): T { ... }
  7. public interface Settings { public fun getInt(key: String, defaultValue: Int

    = 0): Int public fun getIntOrNull(key: String): Int? } public class AndroidSettings (private val delegate: SharedPreferences): ObservableSettings { public override fun getInt(key: String, defaultValue: Int): Int = delegate.getInt(key, defaultValue) public override fun getIntOrNull(key: String): Int? = if (delegate.contains(key)) delegate.getInt(key, 0) else null } public class AppleSettings (private val delegate: NSUserDefaults): ObservableSettings { public override fun getInt(key: String, defaultValue: Int): Int = if (hasKey(key)) delegate.integerForKey(key).toInt() else defaultValue public override fun getIntOrNull(key: String): Int? = if (hasKey(key)) delegate.intForKey(key) else null }
  8. public interface Settings { public fun getInt(key: String, defaultValue: Int

    = 0): Int public fun getIntOrNull(key: String): Int? } public class SharedPreferencesSettings (private val delegate: SharedPreferences): ObservableSettings { public override fun getInt(key: String, defaultValue: Int): Int = delegate.getInt(key, defaultValue) public override fun getIntOrNull(key: String): Int? = if (delegate.contains(key)) delegate.getInt(key, 0) else null } public class NSUserDefaultsSettings (private val delegate: NSUserDefaults): ObservableSettings { public override fun getInt(key: String, defaultValue: Int): Int = if (hasKey(key)) delegate.integerForKey(key).toInt() else defaultValue public override fun getIntOrNull(key: String): Int? = if (hasKey(key)) delegate.intForKey(key) else null }
  9. public interface Settings { public fun getInt(key: String, defaultValue: Int):

    Int public fun getIntOrNull(key: String): Int? } public class SharedPreferencesSettings (private val delegate: SharedPreferences): ObservableSettings { public override fun getInt(key: String, defaultValue: Int): Int = delegate.getInt(key, defaultValue) public override fun getIntOrNull(key: String): Int? = if (delegate.contains(key)) delegate.getInt(key, 0) else null } public class NSUserDefaultsSettings (private val delegate: NSUserDefaults): ObservableSettings { public override fun getInt(key: String, defaultValue: Int): Int = if (hasKey(key)) delegate.integerForKey(key).toInt() else defaultValue public override fun getIntOrNull(key: String): Int? = if (hasKey(key)) delegate.intForKey(key) else null }
  10. public interface ObservableSettings : Settings { public fun addListener( key:

    String, callback: () -> Unit ): SettingsListener } public inline fun ObservableSettings.addIntListener( key: String, defaultValue: Int = 0 , crossinline callback: (Int) -> Unit ): SettingsListener = addListener(key) { callback(getInt(key, defaultValue)) }
  11. public interface ObservableSettings : Settings { public fun addListener( key:

    String, callback: () -> Unit ): SettingsListener } public inline fun ObservableSettings.addIntListener( key: String, defaultValue: Int , crossinline callback: (Int) -> Unit ): SettingsListener = addListener(key) { callback(getInt(key, defaultValue)) }
  12. public interface ObservableSettings : Settings { public fun addIntListener( key:

    String, defaultValue: Int , crossinline callback: (Int) - > Unit ): SettingsListener }