package com.michatec.store.content import android.content.Context import android.content.SharedPreferences import android.content.res.Configuration import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.subjects.PublishSubject import com.michatec.store.R import com.michatec.store.entity.ProductItem import com.michatec.store.utility.extension.android.* import java.net.Proxy import androidx.core.content.edit object Preferences { private lateinit var preferences: SharedPreferences private val subject = PublishSubject.create>() private val keys = sequenceOf( Key.AutoSync, Key.IncompatibleVersions, Key.ProxyHost, Key.ProxyPort, Key.ProxyType, Key.SortOrder, Key.Theme, Key.UpdateNotify, Key.UpdateUnstable ).associateBy { it.name } private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, keyString -> keys[keyString]?.let(subject::onNext) } fun init(context: Context) { preferences = context.getSharedPreferences("${context.packageName}_preferences", Context.MODE_PRIVATE) preferences.registerOnSharedPreferenceChangeListener(listener) } val observable: Observable> get() = subject sealed class Value { abstract val value: T internal abstract fun get(preferences: SharedPreferences, key: String, defaultValue: Value): T internal abstract fun set(preferences: SharedPreferences, key: String, value: T) class BooleanValue(override val value: Boolean): Value() { override fun get(preferences: SharedPreferences, key: String, defaultValue: Value): Boolean { return preferences.getBoolean(key, defaultValue.value) } override fun set(preferences: SharedPreferences, key: String, value: Boolean) { preferences.edit(commit = true) { putBoolean(key, value) } } } class IntValue(override val value: Int): Value() { override fun get(preferences: SharedPreferences, key: String, defaultValue: Value): Int { return preferences.getInt(key, defaultValue.value) } override fun set(preferences: SharedPreferences, key: String, value: Int) { preferences.edit(commit = true) { putInt(key, value) } } } class StringValue(override val value: String): Value() { override fun get(preferences: SharedPreferences, key: String, defaultValue: Value): String { return preferences.getString(key, defaultValue.value) ?: defaultValue.value } override fun set(preferences: SharedPreferences, key: String, value: String) { preferences.edit(commit = true) { putString(key, value) } } } class EnumerationValue>(override val value: T): Value() { override fun get(preferences: SharedPreferences, key: String, defaultValue: Value): T { val value = preferences.getString(key, defaultValue.value.valueString) return defaultValue.value.values.find { it.valueString == value } ?: defaultValue.value } override fun set(preferences: SharedPreferences, key: String, value: T) { preferences.edit(commit = true) { putString(key, value.valueString) } } } } interface Enumeration { val values: List val valueString: String } sealed class Key(val name: String, val default: Value) { object AutoSync: Key("auto_sync", Value.EnumerationValue(Preferences.AutoSync.Wifi)) object IncompatibleVersions: Key("incompatible_versions", Value.BooleanValue(false)) object ProxyHost: Key("proxy_host", Value.StringValue("localhost")) object ProxyPort: Key("proxy_port", Value.IntValue(9050)) object ProxyType: Key("proxy_type", Value.EnumerationValue(Preferences.ProxyType.Direct)) object SortOrder: Key("sort_order", Value.EnumerationValue(Preferences.SortOrder.Update)) object Theme: Key("theme", Value.EnumerationValue(if (Android.sdk(29)) Preferences.Theme.System else Preferences.Theme.Light)) object UpdateNotify: Key("update_notify", Value.BooleanValue(true)) object UpdateUnstable: Key("update_unstable", Value.BooleanValue(false)) } sealed class AutoSync(override val valueString: String): Enumeration { override val values: List get() = listOf(Never, Wifi, Always) object Never: AutoSync("never") object Wifi: AutoSync("wifi") object Always: AutoSync("always") } sealed class ProxyType(override val valueString: String, val proxyType: Proxy.Type): Enumeration { override val values: List get() = listOf(Direct, Http, Socks) object Direct: ProxyType("direct", Proxy.Type.DIRECT) object Http: ProxyType("http", Proxy.Type.HTTP) object Socks: ProxyType("socks", Proxy.Type.SOCKS) } sealed class SortOrder(override val valueString: String, val order: ProductItem.Order): Enumeration { override val values: List get() = listOf(Name, Added, Update) object Name: SortOrder("name", ProductItem.Order.NAME) object Added: SortOrder("added", ProductItem.Order.DATE_ADDED) object Update: SortOrder("update", ProductItem.Order.LAST_UPDATE) } sealed class Theme(override val valueString: String): Enumeration { override val values: List get() = if (Android.sdk(29)) listOf(System, Light, Dark) else listOf(Light, Dark) abstract fun getResId(configuration: Configuration): Int object System: Theme("system") { override fun getResId(configuration: Configuration): Int { return if ((configuration.uiMode and Configuration.UI_MODE_NIGHT_YES) != 0) R.style.Theme_Main_Dark else R.style.Theme_Main_Light } } object Light: Theme("light") { override fun getResId(configuration: Configuration): Int = R.style.Theme_Main_Light } object Dark: Theme("dark") { override fun getResId(configuration: Configuration): Int = R.style.Theme_Main_Dark } } operator fun get(key: Key): T { return key.default.get(preferences, key.name, key.default) } operator fun set(key: Key, value: T) { key.default.set(preferences, key.name, value) } }