v0.6.4
This commit is contained in:
1
core/datastore/.gitignore
vendored
Normal file
1
core/datastore/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
18
core/datastore/build.gradle.kts
Normal file
18
core/datastore/build.gradle.kts
Normal file
@@ -0,0 +1,18 @@
|
||||
plugins {
|
||||
alias(libs.plugins.looker.android.library)
|
||||
alias(libs.plugins.looker.hilt)
|
||||
alias(libs.plugins.looker.lint)
|
||||
alias(libs.plugins.looker.serialization)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.looker.core.datastore"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
modules(Modules.coreCommon, Modules.coreDI)
|
||||
implementation(libs.androidx.dataStore.core)
|
||||
implementation(libs.androidx.dataStore.proto)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package com.looker.core.datastore
|
||||
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.core.IOException
|
||||
import androidx.datastore.preferences.core.MutablePreferences
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.longPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringSetPreferencesKey
|
||||
import com.looker.core.common.Exporter
|
||||
import com.looker.core.common.extension.updateAsMutable
|
||||
import com.looker.core.datastore.model.AutoSync
|
||||
import com.looker.core.datastore.model.InstallerType
|
||||
import com.looker.core.datastore.model.ProxyPreference
|
||||
import com.looker.core.datastore.model.ProxyType
|
||||
import com.looker.core.datastore.model.SortOrder
|
||||
import com.looker.core.datastore.model.Theme
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
|
||||
class PreferenceSettingsRepository(
|
||||
private val dataStore: DataStore<Preferences>,
|
||||
private val exporter: Exporter<Settings>,
|
||||
) : SettingsRepository {
|
||||
override val data: Flow<Settings> = dataStore.data
|
||||
.catch { exception ->
|
||||
if (exception is IOException) {
|
||||
Log.e("TAG", "Error reading preferences.", exception)
|
||||
} else {
|
||||
throw exception
|
||||
}
|
||||
}.map(::mapSettings)
|
||||
|
||||
override suspend fun getInitial(): Settings {
|
||||
return data.first()
|
||||
}
|
||||
|
||||
override suspend fun export(target: Uri) {
|
||||
val currentSettings = getInitial()
|
||||
exporter.export(currentSettings, target)
|
||||
}
|
||||
|
||||
override suspend fun import(target: Uri) {
|
||||
val importedSettings = exporter.import(target)
|
||||
val updatedFavorites = importedSettings.favouriteApps +
|
||||
getInitial().favouriteApps
|
||||
val updatedSettings = importedSettings.copy(favouriteApps = updatedFavorites)
|
||||
dataStore.edit {
|
||||
it.setting(updatedSettings)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setLanguage(language: String) =
|
||||
LANGUAGE.update(language)
|
||||
|
||||
override suspend fun enableIncompatibleVersion(enable: Boolean) =
|
||||
INCOMPATIBLE_VERSIONS.update(enable)
|
||||
|
||||
override suspend fun enableNotifyUpdates(enable: Boolean) =
|
||||
NOTIFY_UPDATES.update(enable)
|
||||
|
||||
override suspend fun enableUnstableUpdates(enable: Boolean) =
|
||||
UNSTABLE_UPDATES.update(enable)
|
||||
|
||||
override suspend fun setIgnoreSignature(enable: Boolean) =
|
||||
IGNORE_SIGNATURE.update(enable)
|
||||
|
||||
override suspend fun setTheme(theme: Theme) =
|
||||
THEME.update(theme.name)
|
||||
|
||||
override suspend fun setDynamicTheme(enable: Boolean) =
|
||||
DYNAMIC_THEME.update(enable)
|
||||
|
||||
override suspend fun setInstallerType(installerType: InstallerType) =
|
||||
INSTALLER_TYPE.update(installerType.name)
|
||||
|
||||
override suspend fun setAutoUpdate(allow: Boolean) =
|
||||
AUTO_UPDATE.update(allow)
|
||||
|
||||
override suspend fun setAutoSync(autoSync: AutoSync) =
|
||||
AUTO_SYNC.update(autoSync.name)
|
||||
|
||||
override suspend fun setSortOrder(sortOrder: SortOrder) =
|
||||
SORT_ORDER.update(sortOrder.name)
|
||||
|
||||
override suspend fun setProxyType(proxyType: ProxyType) =
|
||||
PROXY_TYPE.update(proxyType.name)
|
||||
|
||||
override suspend fun setProxyHost(proxyHost: String) =
|
||||
PROXY_HOST.update(proxyHost)
|
||||
|
||||
override suspend fun setProxyPort(proxyPort: Int) =
|
||||
PROXY_PORT.update(proxyPort)
|
||||
|
||||
override suspend fun setCleanUpInterval(interval: Duration) =
|
||||
CLEAN_UP_INTERVAL.update(interval.inWholeHours)
|
||||
|
||||
override suspend fun setCleanupInstant() =
|
||||
LAST_CLEAN_UP.update(Clock.System.now().toEpochMilliseconds())
|
||||
|
||||
override suspend fun setHomeScreenSwiping(value: Boolean) =
|
||||
HOME_SCREEN_SWIPING.update(value)
|
||||
|
||||
override suspend fun toggleFavourites(packageName: String) {
|
||||
dataStore.edit { preference ->
|
||||
val currentSet = preference[FAVOURITE_APPS] ?: emptySet()
|
||||
val newSet = currentSet.updateAsMutable {
|
||||
if (!add(packageName)) remove(packageName)
|
||||
}
|
||||
preference[FAVOURITE_APPS] = newSet
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapSettings(preferences: Preferences): Settings {
|
||||
val defaultInstallerName = (InstallerType.Default).name
|
||||
|
||||
val language = preferences[LANGUAGE] ?: "system"
|
||||
val incompatibleVersions = preferences[INCOMPATIBLE_VERSIONS] ?: false
|
||||
val notifyUpdate = preferences[NOTIFY_UPDATES] ?: true
|
||||
val unstableUpdate = preferences[UNSTABLE_UPDATES] ?: false
|
||||
val ignoreSignature = preferences[IGNORE_SIGNATURE] ?: false
|
||||
val theme = Theme.valueOf(preferences[THEME] ?: Theme.SYSTEM.name)
|
||||
val dynamicTheme = preferences[DYNAMIC_THEME] ?: false
|
||||
val installerType =
|
||||
InstallerType.valueOf(preferences[INSTALLER_TYPE] ?: defaultInstallerName)
|
||||
val autoUpdate = preferences[AUTO_UPDATE] ?: false
|
||||
val autoSync = AutoSync.valueOf(preferences[AUTO_SYNC] ?: AutoSync.WIFI_ONLY.name)
|
||||
val sortOrder = SortOrder.valueOf(preferences[SORT_ORDER] ?: SortOrder.UPDATED.name)
|
||||
val type = ProxyType.valueOf(preferences[PROXY_TYPE] ?: ProxyType.DIRECT.name)
|
||||
val host = preferences[PROXY_HOST] ?: "localhost"
|
||||
val port = preferences[PROXY_PORT] ?: 9050
|
||||
val proxy = ProxyPreference(type = type, host = host, port = port)
|
||||
val cleanUpInterval = preferences[CLEAN_UP_INTERVAL]?.hours ?: 12L.hours
|
||||
val lastCleanup = preferences[LAST_CLEAN_UP]?.let { Instant.fromEpochMilliseconds(it) }
|
||||
val favouriteApps = preferences[FAVOURITE_APPS] ?: emptySet()
|
||||
val homeScreenSwiping = preferences[HOME_SCREEN_SWIPING] ?: true
|
||||
|
||||
return Settings(
|
||||
language = language,
|
||||
incompatibleVersions = incompatibleVersions,
|
||||
notifyUpdate = notifyUpdate,
|
||||
unstableUpdate = unstableUpdate,
|
||||
ignoreSignature = ignoreSignature,
|
||||
theme = theme,
|
||||
dynamicTheme = dynamicTheme,
|
||||
installerType = installerType,
|
||||
autoUpdate = autoUpdate,
|
||||
autoSync = autoSync,
|
||||
sortOrder = sortOrder,
|
||||
proxy = proxy,
|
||||
cleanUpInterval = cleanUpInterval,
|
||||
lastCleanup = lastCleanup,
|
||||
favouriteApps = favouriteApps,
|
||||
homeScreenSwiping = homeScreenSwiping,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend inline fun <T> Preferences.Key<T>.update(newValue: T) {
|
||||
dataStore.edit { preferences ->
|
||||
preferences[this] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
companion object PreferencesKeys {
|
||||
private val LANGUAGE = stringPreferencesKey("key_language")
|
||||
private val INCOMPATIBLE_VERSIONS = booleanPreferencesKey("key_incompatible_versions")
|
||||
private val NOTIFY_UPDATES = booleanPreferencesKey("key_notify_updates")
|
||||
private val UNSTABLE_UPDATES = booleanPreferencesKey("key_unstable_updates")
|
||||
private val IGNORE_SIGNATURE = booleanPreferencesKey("key_ignore_signature")
|
||||
private val THEME = stringPreferencesKey("key_theme")
|
||||
private val DYNAMIC_THEME = booleanPreferencesKey("key_dynamic_theme")
|
||||
private val INSTALLER_TYPE = stringPreferencesKey("key_installer_type")
|
||||
private val AUTO_UPDATE = booleanPreferencesKey("key_auto_updates")
|
||||
private val AUTO_SYNC = stringPreferencesKey("key_auto_sync")
|
||||
private val SORT_ORDER = stringPreferencesKey("key_sort_order")
|
||||
private val PROXY_TYPE = stringPreferencesKey("key_proxy_type")
|
||||
private val PROXY_HOST = stringPreferencesKey("key_proxy_host")
|
||||
private val PROXY_PORT = intPreferencesKey("key_proxy_port")
|
||||
private val CLEAN_UP_INTERVAL = longPreferencesKey("key_clean_up_interval")
|
||||
private val LAST_CLEAN_UP = longPreferencesKey("key_last_clean_up_time")
|
||||
private val FAVOURITE_APPS = stringSetPreferencesKey("key_favourite_apps")
|
||||
private val HOME_SCREEN_SWIPING = booleanPreferencesKey("key_home_swiping")
|
||||
|
||||
fun MutablePreferences.setting(settings: Settings): Preferences {
|
||||
set(LANGUAGE, settings.language)
|
||||
set(INCOMPATIBLE_VERSIONS, settings.incompatibleVersions)
|
||||
set(NOTIFY_UPDATES, settings.notifyUpdate)
|
||||
set(UNSTABLE_UPDATES, settings.unstableUpdate)
|
||||
set(THEME, settings.theme.name)
|
||||
set(DYNAMIC_THEME, settings.dynamicTheme)
|
||||
set(INSTALLER_TYPE, settings.installerType.name)
|
||||
set(AUTO_UPDATE, settings.autoUpdate)
|
||||
set(AUTO_SYNC, settings.autoSync.name)
|
||||
set(SORT_ORDER, settings.sortOrder.name)
|
||||
set(PROXY_TYPE, settings.proxy.type.name)
|
||||
set(PROXY_HOST, settings.proxy.host)
|
||||
set(PROXY_PORT, settings.proxy.port)
|
||||
set(CLEAN_UP_INTERVAL, settings.cleanUpInterval.inWholeHours)
|
||||
set(LAST_CLEAN_UP, settings.lastCleanup?.toEpochMilliseconds() ?: 0L)
|
||||
set(FAVOURITE_APPS, settings.favouriteApps)
|
||||
set(HOME_SCREEN_SWIPING, settings.homeScreenSwiping)
|
||||
return this.toPreferences()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.looker.core.datastore
|
||||
|
||||
import androidx.datastore.core.Serializer
|
||||
import com.looker.core.datastore.model.AutoSync
|
||||
import com.looker.core.datastore.model.InstallerType
|
||||
import com.looker.core.datastore.model.ProxyPreference
|
||||
import com.looker.core.datastore.model.SortOrder
|
||||
import com.looker.core.datastore.model.Theme
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
|
||||
@Serializable
|
||||
data class Settings(
|
||||
val language: String = "system",
|
||||
val incompatibleVersions: Boolean = false,
|
||||
val notifyUpdate: Boolean = true,
|
||||
val unstableUpdate: Boolean = false,
|
||||
val ignoreSignature: Boolean = false,
|
||||
val theme: Theme = Theme.SYSTEM,
|
||||
val dynamicTheme: Boolean = false,
|
||||
val installerType: InstallerType = InstallerType.Default,
|
||||
val autoUpdate: Boolean = false,
|
||||
val autoSync: AutoSync = AutoSync.WIFI_ONLY,
|
||||
val sortOrder: SortOrder = SortOrder.UPDATED,
|
||||
val proxy: ProxyPreference = ProxyPreference(),
|
||||
val cleanUpInterval: Duration = 12.hours,
|
||||
val lastCleanup: Instant? = null,
|
||||
val favouriteApps: Set<String> = emptySet(),
|
||||
val homeScreenSwiping: Boolean = true,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
object SettingsSerializer : Serializer<Settings> {
|
||||
|
||||
private val json = Json { encodeDefaults = true }
|
||||
|
||||
override val defaultValue: Settings = Settings()
|
||||
|
||||
override suspend fun readFrom(input: InputStream): Settings {
|
||||
return try {
|
||||
json.decodeFromStream(input)
|
||||
} catch (e: SerializationException) {
|
||||
e.printStackTrace()
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun writeTo(t: Settings, output: OutputStream) {
|
||||
try {
|
||||
json.encodeToStream(t, output)
|
||||
} catch (e: SerializationException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.looker.core.datastore
|
||||
|
||||
import android.net.Uri
|
||||
import com.looker.core.datastore.model.AutoSync
|
||||
import com.looker.core.datastore.model.InstallerType
|
||||
import com.looker.core.datastore.model.ProxyType
|
||||
import com.looker.core.datastore.model.SortOrder
|
||||
import com.looker.core.datastore.model.Theme
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlin.time.Duration
|
||||
|
||||
interface SettingsRepository {
|
||||
|
||||
val data: Flow<Settings>
|
||||
|
||||
suspend fun getInitial(): Settings
|
||||
|
||||
suspend fun export(target: Uri)
|
||||
|
||||
suspend fun import(target: Uri)
|
||||
|
||||
suspend fun setLanguage(language: String)
|
||||
|
||||
suspend fun enableIncompatibleVersion(enable: Boolean)
|
||||
|
||||
suspend fun enableNotifyUpdates(enable: Boolean)
|
||||
|
||||
suspend fun enableUnstableUpdates(enable: Boolean)
|
||||
|
||||
suspend fun setIgnoreSignature(enable: Boolean)
|
||||
|
||||
suspend fun setTheme(theme: Theme)
|
||||
|
||||
suspend fun setDynamicTheme(enable: Boolean)
|
||||
|
||||
suspend fun setInstallerType(installerType: InstallerType)
|
||||
|
||||
suspend fun setAutoUpdate(allow: Boolean)
|
||||
|
||||
suspend fun setAutoSync(autoSync: AutoSync)
|
||||
|
||||
suspend fun setSortOrder(sortOrder: SortOrder)
|
||||
|
||||
suspend fun setProxyType(proxyType: ProxyType)
|
||||
|
||||
suspend fun setProxyHost(proxyHost: String)
|
||||
|
||||
suspend fun setProxyPort(proxyPort: Int)
|
||||
|
||||
suspend fun setCleanUpInterval(interval: Duration)
|
||||
|
||||
suspend fun setCleanupInstant()
|
||||
|
||||
suspend fun setHomeScreenSwiping(value: Boolean)
|
||||
|
||||
suspend fun toggleFavourites(packageName: String)
|
||||
}
|
||||
|
||||
inline fun <T> SettingsRepository.get(crossinline block: suspend Settings.() -> T): Flow<T> {
|
||||
return data.map(block).distinctUntilChanged()
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.looker.core.datastore.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.core.DataStoreFactory
|
||||
import androidx.datastore.dataStoreFile
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||
import com.looker.core.common.Exporter
|
||||
import com.looker.core.datastore.PreferenceSettingsRepository
|
||||
import com.looker.core.datastore.Settings
|
||||
import com.looker.core.datastore.SettingsRepository
|
||||
import com.looker.core.datastore.SettingsSerializer
|
||||
import com.looker.core.datastore.exporter.SettingsExporter
|
||||
import com.looker.core.datastore.migration.ProtoToPreferenceMigration
|
||||
import com.looker.core.di.ApplicationScope
|
||||
import com.looker.core.di.IoDispatcher
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.serialization.json.Json
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val PREFERENCES = "settings_file"
|
||||
|
||||
private const val SETTINGS = "settings"
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object DatastoreModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideProtoDatastore(
|
||||
@ApplicationContext context: Context,
|
||||
): DataStore<Settings> = DataStoreFactory.create(
|
||||
serializer = SettingsSerializer,
|
||||
) {
|
||||
context.dataStoreFile(PREFERENCES)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun providePreferenceDatastore(
|
||||
@ApplicationContext context: Context,
|
||||
oldDatastore: DataStore<Settings>,
|
||||
): DataStore<Preferences> = PreferenceDataStoreFactory.create(
|
||||
migrations = listOf(
|
||||
ProtoToPreferenceMigration(oldDatastore)
|
||||
)
|
||||
) {
|
||||
context.preferencesDataStoreFile(SETTINGS)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSettingsExporter(
|
||||
@ApplicationContext context: Context,
|
||||
@ApplicationScope scope: CoroutineScope,
|
||||
@IoDispatcher dispatcher: CoroutineDispatcher
|
||||
): Exporter<Settings> = SettingsExporter(
|
||||
context = context,
|
||||
scope = scope,
|
||||
ioDispatcher = dispatcher,
|
||||
json = Json {
|
||||
encodeDefaults = true
|
||||
prettyPrint = true
|
||||
}
|
||||
)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSettingsRepository(
|
||||
dataStore: DataStore<Preferences>,
|
||||
exporter: Exporter<Settings>
|
||||
): SettingsRepository = PreferenceSettingsRepository(dataStore, exporter)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.looker.core.datastore.exporter
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.looker.core.common.Exporter
|
||||
import com.looker.core.datastore.Settings
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
import java.io.IOException
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
class SettingsExporter(
|
||||
private val context: Context,
|
||||
private val scope: CoroutineScope,
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
private val json: Json
|
||||
) : Exporter<Settings> {
|
||||
|
||||
override suspend fun export(item: Settings, target: Uri) {
|
||||
scope.launch(ioDispatcher) {
|
||||
try {
|
||||
context.contentResolver.openOutputStream(target).use {
|
||||
if (it != null) json.encodeToStream(item, it)
|
||||
}
|
||||
} catch (e: SerializationException) {
|
||||
e.printStackTrace()
|
||||
cancel()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun import(target: Uri): Settings = withContext(ioDispatcher) {
|
||||
try {
|
||||
context.contentResolver.openInputStream(target).use {
|
||||
checkNotNull(it) { "Null input stream for import file" }
|
||||
json.decodeFromStream(it)
|
||||
}
|
||||
} catch (e: SerializationException) {
|
||||
e.printStackTrace()
|
||||
throw IllegalStateException(e.message)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
throw IllegalStateException(e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.looker.core.datastore.extension
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import com.looker.core.common.R
|
||||
import com.looker.core.common.R.string as stringRes
|
||||
import com.looker.core.common.R.style as styleRes
|
||||
import com.looker.core.common.SdkCheck
|
||||
import com.looker.core.datastore.model.AutoSync
|
||||
import com.looker.core.datastore.model.InstallerType
|
||||
import com.looker.core.datastore.model.ProxyType
|
||||
import com.looker.core.datastore.model.SortOrder
|
||||
import com.looker.core.datastore.model.Theme
|
||||
import kotlin.time.Duration
|
||||
|
||||
fun Configuration.getThemeRes(theme: Theme, dynamicTheme: Boolean) = when (theme) {
|
||||
Theme.SYSTEM -> {
|
||||
if ((uiMode and Configuration.UI_MODE_NIGHT_YES) != 0) {
|
||||
if (SdkCheck.isSnowCake && dynamicTheme) {
|
||||
styleRes.Theme_Main_DynamicDark
|
||||
} else {
|
||||
styleRes.Theme_Main_Dark
|
||||
}
|
||||
} else {
|
||||
if (SdkCheck.isSnowCake && dynamicTheme) {
|
||||
styleRes.Theme_Main_DynamicLight
|
||||
} else {
|
||||
styleRes.Theme_Main_Light
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Theme.SYSTEM_BLACK -> {
|
||||
if ((uiMode and Configuration.UI_MODE_NIGHT_YES) != 0) {
|
||||
if (SdkCheck.isSnowCake && dynamicTheme) {
|
||||
styleRes.Theme_Main_DynamicAmoled
|
||||
} else {
|
||||
styleRes.Theme_Main_Amoled
|
||||
}
|
||||
} else {
|
||||
if (SdkCheck.isSnowCake && dynamicTheme) {
|
||||
styleRes.Theme_Main_DynamicLight
|
||||
} else {
|
||||
styleRes.Theme_Main_Light
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Theme.LIGHT -> if (SdkCheck.isSnowCake && dynamicTheme) {
|
||||
styleRes.Theme_Main_DynamicLight
|
||||
} else {
|
||||
styleRes.Theme_Main_Light
|
||||
}
|
||||
Theme.DARK -> if (SdkCheck.isSnowCake && dynamicTheme) {
|
||||
styleRes.Theme_Main_DynamicDark
|
||||
} else {
|
||||
styleRes.Theme_Main_Dark
|
||||
}
|
||||
Theme.AMOLED -> if (SdkCheck.isSnowCake && dynamicTheme) {
|
||||
styleRes.Theme_Main_DynamicAmoled
|
||||
} else {
|
||||
styleRes.Theme_Main_Amoled
|
||||
}
|
||||
}
|
||||
|
||||
fun Context?.toTime(duration: Duration): String {
|
||||
val time = duration.inWholeHours.toInt()
|
||||
val days = duration.inWholeDays.toInt()
|
||||
if (duration == Duration.INFINITE) return this?.getString(R.string.never) ?: ""
|
||||
return if (time >= 24) {
|
||||
"$days " + this?.resources?.getQuantityString(
|
||||
R.plurals.days,
|
||||
days
|
||||
)
|
||||
} else {
|
||||
"$time " + this?.resources?.getQuantityString(R.plurals.hours, time)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context?.themeName(theme: Theme) = this?.let {
|
||||
when (theme) {
|
||||
Theme.SYSTEM -> getString(stringRes.system)
|
||||
Theme.SYSTEM_BLACK -> getString(stringRes.system) + " " + getString(stringRes.amoled)
|
||||
Theme.LIGHT -> getString(stringRes.light)
|
||||
Theme.DARK -> getString(stringRes.dark)
|
||||
Theme.AMOLED -> getString(stringRes.amoled)
|
||||
}
|
||||
} ?: ""
|
||||
|
||||
fun Context?.sortOrderName(sortOrder: SortOrder) = this?.let {
|
||||
when (sortOrder) {
|
||||
SortOrder.UPDATED -> getString(stringRes.recently_updated)
|
||||
SortOrder.ADDED -> getString(stringRes.whats_new)
|
||||
SortOrder.NAME -> getString(stringRes.name)
|
||||
// SortOrder.SIZE -> getString(stringRes.size)
|
||||
}
|
||||
} ?: ""
|
||||
|
||||
fun Context?.autoSyncName(autoSync: AutoSync) = this?.let {
|
||||
when (autoSync) {
|
||||
AutoSync.NEVER -> getString(stringRes.never)
|
||||
AutoSync.WIFI_ONLY -> getString(stringRes.only_on_wifi)
|
||||
AutoSync.WIFI_PLUGGED_IN -> getString(stringRes.only_on_wifi_with_charging)
|
||||
AutoSync.ALWAYS -> getString(stringRes.always)
|
||||
}
|
||||
} ?: ""
|
||||
|
||||
fun Context?.proxyName(proxyType: ProxyType) = this?.let {
|
||||
when (proxyType) {
|
||||
ProxyType.DIRECT -> getString(stringRes.no_proxy)
|
||||
ProxyType.HTTP -> getString(stringRes.http_proxy)
|
||||
ProxyType.SOCKS -> getString(stringRes.socks_proxy)
|
||||
}
|
||||
} ?: ""
|
||||
|
||||
fun Context?.installerName(installerType: InstallerType) = this?.let {
|
||||
when (installerType) {
|
||||
InstallerType.LEGACY -> getString(stringRes.legacy_installer)
|
||||
InstallerType.SESSION -> getString(stringRes.session_installer)
|
||||
InstallerType.SHIZUKU -> getString(stringRes.shizuku_installer)
|
||||
InstallerType.ROOT -> getString(stringRes.root_installer)
|
||||
}
|
||||
} ?: ""
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.looker.core.datastore.migration
|
||||
|
||||
import androidx.datastore.core.DataMigration
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import com.looker.core.datastore.PreferenceSettingsRepository.PreferencesKeys.setting
|
||||
import com.looker.core.datastore.Settings
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
class ProtoToPreferenceMigration(
|
||||
private val oldDataStore: DataStore<Settings>
|
||||
) : DataMigration<Preferences> {
|
||||
override suspend fun cleanUp() {
|
||||
}
|
||||
|
||||
override suspend fun shouldMigrate(currentData: Preferences): Boolean {
|
||||
return currentData.asMap().isEmpty()
|
||||
}
|
||||
|
||||
override suspend fun migrate(currentData: Preferences): Preferences {
|
||||
val settings = oldDataStore.data.first()
|
||||
val preferences = currentData.toMutablePreferences()
|
||||
preferences.setting(settings)
|
||||
return preferences
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.looker.core.datastore.model
|
||||
|
||||
enum class AutoSync {
|
||||
ALWAYS,
|
||||
WIFI_ONLY,
|
||||
WIFI_PLUGGED_IN,
|
||||
NEVER
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.looker.core.datastore.model
|
||||
|
||||
import com.looker.core.common.device.Miui
|
||||
|
||||
enum class InstallerType {
|
||||
LEGACY,
|
||||
SESSION,
|
||||
SHIZUKU,
|
||||
ROOT;
|
||||
|
||||
companion object {
|
||||
val Default: InstallerType
|
||||
get() = if (Miui.isMiui) {
|
||||
if (Miui.isMiuiOptimizationDisabled()) SESSION else LEGACY
|
||||
} else {
|
||||
SESSION
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.looker.core.datastore.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ProxyPreference(
|
||||
val type: ProxyType = ProxyType.DIRECT,
|
||||
val host: String = "localhost",
|
||||
val port: Int = 9050
|
||||
) {
|
||||
fun update(
|
||||
newType: ProxyType? = null,
|
||||
newHost: String? = null,
|
||||
newPort: Int? = null
|
||||
): ProxyPreference = copy(
|
||||
type = newType ?: type,
|
||||
host = newHost ?: host,
|
||||
port = newPort ?: port
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.looker.core.datastore.model
|
||||
|
||||
enum class ProxyType {
|
||||
DIRECT,
|
||||
HTTP,
|
||||
SOCKS
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.looker.core.datastore.model
|
||||
|
||||
// todo: Add Support for sorting by size
|
||||
enum class SortOrder {
|
||||
UPDATED,
|
||||
ADDED,
|
||||
NAME
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.looker.core.datastore.model
|
||||
|
||||
enum class Theme {
|
||||
SYSTEM,
|
||||
SYSTEM_BLACK,
|
||||
LIGHT,
|
||||
DARK,
|
||||
AMOLED
|
||||
}
|
||||
Reference in New Issue
Block a user