Introduce rememberInDataStore
This commit is contained in:
1 parent
fae2b1f416
commit
959da21b9d
1 file changed
+43
-2
@@ -3,11 +3,17 @@ package com.hippo.ehviewer.ui.tools
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisallowComposableCalls
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.currentCompositeKeyHash
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.datastore.dataStoreFile
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import androidx.datastore.preferences.core.byteArrayPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.emptyPreferences
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@@ -15,21 +21,32 @@ import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.cbor.Cbor
|
||||
import kotlinx.serialization.decodeFromByteArray
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import splitties.init.appCtx
|
||||
|
||||
val dataStoreScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
val dataStore = PreferenceDataStoreFactory.create { appCtx.dataStoreFile("Remembered") }
|
||||
val dataStateFlow = dataStore.data.stateIn(dataStoreScope, SharingStarted.Eagerly, emptyPreferences())
|
||||
|
||||
class StateMapViewModel : ViewModel() {
|
||||
val statesMap = mutableMapOf<Int, ArrayDeque<Any>>()
|
||||
}
|
||||
|
||||
@Composable
|
||||
inline fun <T : Any> rememberInVM(
|
||||
inline fun <reified T : Any> rememberInVM(
|
||||
vararg inputs: Any?,
|
||||
crossinline init: @DisallowComposableCalls ViewModel.() -> T,
|
||||
) = with(viewModel<StateMapViewModel>()) {
|
||||
val key = currentCompositeKeyHash
|
||||
remember(*inputs) {
|
||||
val states = statesMap[key] ?: ArrayDeque<Any>().also { statesMap[key] = it }
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
states.removeLastOrNull() as T? ?: init()
|
||||
}.also { value ->
|
||||
val valueState by rememberUpdatedState(value)
|
||||
@@ -41,6 +58,30 @@ inline fun <T : Any> rememberInVM(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
inline fun <reified T : MutableState<T>> rememberInDataStore(
|
||||
key: String,
|
||||
crossinline defaultValue: @DisallowComposableCalls () -> MutableState<T>,
|
||||
) = with(dataStateFlow) {
|
||||
remember {
|
||||
val keyObj = byteArrayPreferencesKey(key)
|
||||
value[keyObj]?.let { bytes ->
|
||||
mutableStateOf(Cbor.decodeFromByteArray(bytes))
|
||||
} ?: defaultValue()
|
||||
}.also { value ->
|
||||
DisposableEffect(key) {
|
||||
onDispose {
|
||||
dataStoreScope.launch {
|
||||
val keyObj = byteArrayPreferencesKey(key)
|
||||
dataStore.edit { p ->
|
||||
p[keyObj] = Cbor.encodeToByteArray(value.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun launchInVM(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
|
||||
Reference in new issue
Block a user