Skip to content

Instantly share code, notes, and snippets.

@yoonseopshin
Created October 14, 2021 06:32
Show Gist options
  • Save yoonseopshin/85ca969241113f58b570c083e09cdc63 to your computer and use it in GitHub Desktop.
Save yoonseopshin/85ca969241113f58b570c083e09cdc63 to your computer and use it in GitHub Desktop.
Preference Usage
import android.content.SharedPreferences
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
internal const val PREF_DEFAULT_STRING = ""
internal const val PREF_DEFAULT_INT = 0
internal const val PREF_DEFAULT_BOOLEAN = false
abstract class Preference<T>(
open val preferences: SharedPreferences,
open val key: String,
) : ReadWriteProperty<Any, T>
class EncryptedStringPreference(
override val preferences: SharedPreferences,
override val key: String,
private val defaultValue: String = PREF_DEFAULT_STRING,
) : Preference<String>(preferences, key) {
override fun getValue(thisRef: Any, property: KProperty<*>): String =
CipherUtils.decrypt(
preferences.getString(CipherUtils.encrypt(key), defaultValue) ?: defaultValue
)
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) =
preferences.edit().putString(CipherUtils.encrypt(key), CipherUtils.encrypt(value)).apply()
}
class IntPreference(
override val preferences: SharedPreferences,
override val key: String,
private val defaultValue: Int = PREF_DEFAULT_INT,
) : Preference<Int>(preferences, key) {
override fun getValue(thisRef: Any, property: KProperty<*>): Int =
preferences.getInt(key, defaultValue)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) =
preferences.edit().putInt(key, value).apply()
}
class BooleanPreference(
override val preferences: SharedPreferences,
override val key: String,
private val defaultValue: Boolean = PREF_DEFAULT_BOOLEAN,
) : Preference<Boolean>(preferences, key) {
override fun getValue(thisRef: Any, property: KProperty<*>): Boolean =
preferences.getBoolean(CipherUtils.encrypt(key), defaultValue)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Boolean) =
preferences.edit().putBoolean(CipherUtils.encrypt(key), value).apply()
}
internal fun <T> Preference<T>.asFlow(): Flow<T> = PreferenceFlow(this)
private class PreferenceFlow<T>(private val preference: Preference<T>) : Flow<T> {
private val delegateValue: T by preference
private val channel = Channel<T>(Channel.CONFLATED)
private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
if (preference.key == key) {
channel.trySend(delegateValue)
}
}
@InternalCoroutinesApi
override suspend fun collect(collector: FlowCollector<T>) {
withContext(Dispatchers.Main.immediate) {
preference.preferences.registerOnSharedPreferenceChangeListener(listener)
}
try {
for (value in channel) {
collector.emit(value)
}
} finally {
GlobalScope.launch(Dispatchers.Main.immediate) {
preference.preferences.unregisterOnSharedPreferenceChangeListener(listener)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment