diff options
author | Allan Wang <me@allanwang.ca> | 2020-02-23 15:28:20 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-23 15:28:20 -0800 |
commit | 3fa13a3a84d34fd0d96f26d6c5dea0e0671dd6c4 (patch) | |
tree | 4e3f13ac9eafdfd02f4f0f78e0d7575f8bea0bf5 /core/src/main | |
parent | 0e4e82933001ab749538109210cb0940ea912db0 (diff) | |
parent | 0e7e43f7f778a206b0b30c6997c7c36494e6c142 (diff) | |
download | kau-3fa13a3a84d34fd0d96f26d6c5dea0e0671dd6c4.tar.gz kau-3fa13a3a84d34fd0d96f26d6c5dea0e0671dd6c4.tar.bz2 kau-3fa13a3a84d34fd0d96f26d6c5dea0e0671dd6c4.zip |
Merge pull request #248 from AllanWang/kpref
Kpref
Diffstat (limited to 'core/src/main')
5 files changed, 182 insertions, 62 deletions
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt index fc7a76a..7f75370 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt @@ -15,10 +15,7 @@ */ package ca.allanwang.kau.kpref -import android.content.Context -import android.content.SharedPreferences import ca.allanwang.kau.kotlin.ILazyResettable -import ca.allanwang.kau.logging.KL /** * Created by Allan Wang on 2017-06-07. @@ -32,38 +29,36 @@ import ca.allanwang.kau.logging.KL * Furthermore, all kprefs are held in the [prefMap], * so if you wish to reset a preference, you must also invalidate the kpref * from that map - * - * You may optionally override [deleteKeys]. This will be called on initialization - * And delete all keys returned from that method */ -open class KPref(builder: KPrefBuilder = KPrefBuilderAndroid) : KPrefBuilder by builder { - - lateinit var PREFERENCE_NAME: String - lateinit var sp: SharedPreferences +open class KPref private constructor( + val preferenceName: String, + val builder: KPrefBuilder +) : KPrefBuilder by builder { - fun initialize( - c: Context, - preferenceName: String, - sharedPrefs: SharedPreferences = c.applicationContext.getSharedPreferences(preferenceName, Context.MODE_PRIVATE) - ) { - PREFERENCE_NAME = preferenceName - sp = sharedPrefs - KL.d { "Shared Preference $preferenceName has been initialized" } - val toDelete = deleteKeys() - if (toDelete.isNotEmpty()) { - val edit = sp.edit() - toDelete.forEach { edit.remove(it) } - edit.apply() - } - } + constructor(preferenceName: String, factory: KPrefFactory) : this( + preferenceName, + factory.createBuilder(preferenceName) + ) internal val prefMap: MutableMap<String, ILazyResettable<*>> = mutableMapOf() + fun add(entry: KPrefDelegate<*>) { + if (prefMap.containsKey(entry.key)) + throw KPrefException("${entry.key} is already used elsewhere in preference $preferenceName") + prefMap[entry.key] = entry + } + fun reset() { prefMap.values.forEach { it.invalidate() } } operator fun get(key: String): ILazyResettable<*>? = prefMap[key] - open fun deleteKeys(): Array<String> = arrayOf() + /** + * Exposed key deletion function from builder. + * To avoid recursion, this type uses vararg + */ + fun deleteKeys(vararg keys: String) { + deleteKeys(keys) + } } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt index 8f6d0c5..7a35ac2 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt @@ -15,22 +15,44 @@ */ package ca.allanwang.kau.kpref +import android.content.SharedPreferences + interface KPrefBuilder { - fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit = {}): KPrefDelegate<Boolean> + fun KPref.kpref( + key: String, + fallback: Boolean, + postSetter: (value: Boolean) -> Unit = {} + ): KPrefDelegate<Boolean> - fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit = {}): KPrefDelegate<Float> + fun KPref.kpref( + key: String, + fallback: Float, + postSetter: (value: Float) -> Unit = {} + ): KPrefDelegate<Float> @Deprecated( "Double is not supported in SharedPreferences; cast to float yourself", ReplaceWith("kpref(key, fallback.toFloat(), postSetter)"), DeprecationLevel.WARNING ) - fun KPref.kpref(key: String, fallback: Double, postSetter: (value: Float) -> Unit = {}): KPrefDelegate<Float> = + fun KPref.kpref( + key: String, + fallback: Double, + postSetter: (value: Float) -> Unit = {} + ): KPrefDelegate<Float> = kpref(key, fallback.toFloat(), postSetter) - fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit = {}): KPrefDelegate<Int> + fun KPref.kpref( + key: String, + fallback: Int, + postSetter: (value: Int) -> Unit = {} + ): KPrefDelegate<Int> - fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit = {}): KPrefDelegate<Long> + fun KPref.kpref( + key: String, + fallback: Long, + postSetter: (value: Long) -> Unit = {} + ): KPrefDelegate<Long> fun KPref.kpref( key: String, @@ -38,32 +60,97 @@ interface KPrefBuilder { postSetter: (value: Set<String>) -> Unit = {} ): KPrefDelegate<Set<String>> - fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit = {}): KPrefDelegate<String> + fun KPref.kpref( + key: String, + fallback: String, + postSetter: (value: String) -> Unit = {} + ): KPrefDelegate<String> fun KPref.kprefSingle(key: String): KPrefSingleDelegate + + /** + * Remove keys from pref so they revert to the default + */ + fun KPref.deleteKeys(keys: Array<out String>) } -object KPrefBuilderAndroid : KPrefBuilder { +class KPrefBuilderAndroid(val sp: SharedPreferences) : KPrefBuilder { override fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefBooleanTransaction, postSetter) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefBooleanTransaction, + postSetter + ) override fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefFloatTransaction, postSetter) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefFloatTransaction, + postSetter + ) override fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefIntTransaction, postSetter) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefIntTransaction, + postSetter + ) override fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefLongTransaction, postSetter) - - override fun KPref.kpref(key: String, fallback: Set<String>, postSetter: (value: Set<String>) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefSetTransaction, postSetter) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefLongTransaction, + postSetter + ) + + override fun KPref.kpref( + key: String, + fallback: Set<String>, + postSetter: (value: Set<String>) -> Unit + ) = + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefSetTransaction, + postSetter + ) override fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefStringTransaction, postSetter) - - override fun KPref.kprefSingle(key: String) = KPrefSingleDelegateAndroid(key, this) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefStringTransaction, + postSetter + ) + + override fun KPref.kprefSingle(key: String) = + KPrefSingleDelegateAndroid(key, this, this@KPrefBuilderAndroid) + + override fun KPref.deleteKeys(keys: Array<out String>) { + // Remove pref listing + sp.edit().apply { + keys.forEach { remove(it) } + }.apply() + // Clear cached values + keys.forEach { prefMap[it]?.invalidate() } + } } object KPrefBuilderInMemory : KPrefBuilder { @@ -80,11 +167,20 @@ object KPrefBuilderInMemory : KPrefBuilder { override fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit) = KPrefDelegateInMemory(key, fallback, this, postSetter) - override fun KPref.kpref(key: String, fallback: Set<String>, postSetter: (value: Set<String>) -> Unit) = + override fun KPref.kpref( + key: String, + fallback: Set<String>, + postSetter: (value: Set<String>) -> Unit + ) = KPrefDelegateInMemory(key, fallback, this, postSetter) override fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit) = KPrefDelegateInMemory(key, fallback, this, postSetter) override fun KPref.kprefSingle(key: String) = KPrefSingleDelegateInMemory(key, this) + + override fun KPref.deleteKeys(keys: Array<out String>) { + // Clear cached values + keys.forEach { prefMap[it]?.invalidate() } + } } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt index 684b139..c17d3df 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt @@ -15,6 +15,7 @@ */ package ca.allanwang.kau.kpref +import android.content.SharedPreferences import ca.allanwang.kau.kotlin.ILazyResettable /** @@ -26,29 +27,31 @@ import ca.allanwang.kau.kotlin.ILazyResettable */ interface KPrefDelegate<T> : ILazyResettable<T> { + val key: String operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) } class KPrefException(message: String) : IllegalAccessException(message) class KPrefDelegateAndroid<T> internal constructor( - private val key: String, + override val key: String, private val fallback: T, private val pref: KPref, + private val prefBuilder: KPrefBuilderAndroid, private val transaction: KPrefTransaction<T>, private var postSetter: (value: T) -> Unit = {} ) : KPrefDelegate<T> { private object UNINITIALIZED + private val sp: SharedPreferences get() = prefBuilder.sp + @Volatile private var _value: Any? = UNINITIALIZED private val lock = this init { - if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") - pref.prefMap[key] = this@KPrefDelegateAndroid + pref.add(this) } override fun invalidate() { @@ -67,7 +70,7 @@ class KPrefDelegateAndroid<T> internal constructor( if (_v2 !== UNINITIALIZED) { _v2 as T } else { - _value = transaction.get(pref.sp, key, fallback) + _value = transaction.get(sp, key, fallback) _value as T } } @@ -75,11 +78,12 @@ class KPrefDelegateAndroid<T> internal constructor( override fun isInitialized(): Boolean = _value !== UNINITIALIZED - override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." + override fun toString(): String = + if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." override operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) { _value = t - val editor = pref.sp.edit() + val editor = sp.edit() transaction.set(editor, key, t) editor.apply() postSetter(t) @@ -87,7 +91,7 @@ class KPrefDelegateAndroid<T> internal constructor( } class KPrefDelegateInMemory<T> internal constructor( - private val key: String, + override val key: String, private val fallback: T, private val pref: KPref, private var postSetter: (value: T) -> Unit = {} @@ -100,13 +104,11 @@ class KPrefDelegateInMemory<T> internal constructor( private val lock = this init { - if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") - pref.prefMap[key] = this + pref.add(this) } override fun invalidate() { - // No op + _value = UNINITIALIZED } @Suppress("UNCHECKED_CAST") @@ -129,7 +131,8 @@ class KPrefDelegateInMemory<T> internal constructor( override fun isInitialized(): Boolean = _value !== UNINITIALIZED - override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." + override fun toString(): String = + if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." override operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) { _value = t diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefFactory.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefFactory.kt new file mode 100644 index 0000000..0c49b88 --- /dev/null +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefFactory.kt @@ -0,0 +1,22 @@ +package ca.allanwang.kau.kpref + +import android.content.Context + +interface KPrefFactory { + fun createBuilder(preferenceName: String): KPrefBuilder +} + +/** + * Default factory for Android preferences + */ +class KPrefFactoryAndroid(context: Context) : KPrefFactory { + + val context: Context = context.applicationContext + + override fun createBuilder(preferenceName: String): KPrefBuilder = + KPrefBuilderAndroid(context.getSharedPreferences(preferenceName, Context.MODE_PRIVATE)) +} + +object KPrefFactoryInMemory : KPrefFactory { + override fun createBuilder(preferenceName: String): KPrefBuilder = KPrefBuilderInMemory +}
\ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt index ae1f855..9d03a16 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt @@ -15,6 +15,7 @@ */ package ca.allanwang.kau.kpref +import android.content.SharedPreferences import ca.allanwang.kau.kotlin.ILazyResettable /** @@ -29,16 +30,19 @@ interface KPrefSingleDelegate : ILazyResettable<Boolean> class KPrefSingleDelegateAndroid internal constructor( private val key: String, - private val pref: KPref + private val pref: KPref, + private val prefBuilder: KPrefBuilderAndroid ) : KPrefSingleDelegate { @Volatile private var _value: Boolean? = null private val lock = this + private val sp: SharedPreferences get() = prefBuilder.sp + init { if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") + throw KPrefException("$key is already used elsewhere in preference ${pref.preferenceName}") pref.prefMap[key] = this } @@ -57,9 +61,9 @@ class KPrefSingleDelegateAndroid internal constructor( if (_v2 != null) { _v2 } else { - _value = pref.sp.getBoolean(key, true) + _value = sp.getBoolean(key, true) if (_value!!) { - pref.sp.edit().putBoolean(key, false).apply() + sp.edit().putBoolean(key, false).apply() _value = false true } else false @@ -82,7 +86,7 @@ class KPrefSingleDelegateInMemory internal constructor( init { if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") + throw KPrefException("$key is already used elsewhere in preference ${pref.preferenceName}") pref.prefMap[key] = this } |