Created
October 14, 2021 06:32
-
-
Save yoonseopshin/85ca969241113f58b570c083e09cdc63 to your computer and use it in GitHub Desktop.
Preference Usage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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