diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt index ed35d8c30..3e6395af7 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryPreviewScreen.kt @@ -32,8 +32,6 @@ import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.navigation.fragment.findNavController import androidx.paging.Pager @@ -70,10 +68,7 @@ import kotlinx.coroutines.launch import moe.tarsin.coroutines.runSuspendCatching import my.nanihadesuka.compose.LazyGridScrollbar -class VMStorage1 : ViewModel() - class GalleryPreviewScreen : Fragment() { - private val vm: VMStorage1 by viewModels() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = ComposeView(inflater.context).apply { setMD3Content { val galleryDetail = remember { requireArguments().getParcelableCompat(KEY_GALLERY_DETAIL)!! } @@ -128,7 +123,7 @@ class GalleryPreviewScreen : Fragment() { } override val jumpingSupported = true } - }.flow.cachedIn(vm.viewModelScope) + }.flow.cachedIn(viewModelScope) }.collectAsLazyPagingItems() Scaffold( diff --git a/app/src/main/java/com/hippo/ehviewer/ui/tools/RememberGlobally.kt b/app/src/main/java/com/hippo/ehviewer/ui/tools/RememberGlobally.kt index cd01c5008..d101eda54 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/tools/RememberGlobally.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/tools/RememberGlobally.kt @@ -2,54 +2,32 @@ package com.hippo.ehviewer.ui.tools import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.currentCompositeKeyHash import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.runtime.saveable.LocalSaveableStateRegistry +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewmodel.compose.viewModel -private val remembered = hashMapOf() +class StateMapViewModel : ViewModel() { + val states: MutableMap> = mutableMapOf() +} -// This works mostly like [rememberSaveable], but saves data in global hashmap, to avoid [TransactionTooLargeException] @Composable fun rememberMemorized( vararg inputs: Any?, - key: String? = null, - init: () -> T, + init: ViewModel.() -> T, ): T { - // key is the one provided by the user or the one generated by the compose runtime - val finalKey = if (!key.isNullOrEmpty()) { - key - } else { - // currentCompositeKeyHash is unreliable here - // Is this Composable inlined or its groups elided? - // Or a compose compiler bug? - init.javaClass.toString() - } - - val registry = LocalSaveableStateRegistry.current - // value is restored using the registry or created via [init] lambda + val vm: StateMapViewModel = viewModel() + val key = currentCompositeKeyHash val value = remember(*inputs) { + val states = vm.states[key] ?: ArrayDeque().also { vm.states[key] = it } @Suppress("UNCHECKED_CAST") - val restored = registry?.consumeRestored(finalKey)?.let { - remembered.remove(it as String) - } as T? - restored ?: init() + states.removeFirstOrNull() as T? ?: init(vm) } - - // re-register if the registry or key has been changed - if (registry != null) { - // we want to use the latest instances of saver and value in the valueProvider lambda - // without restarting DisposableEffect as it would cause re-registering the provider in - // the different order. so we use rememberUpdatedState. - val valueState = rememberUpdatedState(value) - - DisposableEffect(registry, finalKey) { - val valueProvider = { - finalKey.also { remembered[it] = valueState.value } - } - val entry = registry.registerProvider(finalKey, valueProvider) - onDispose { - entry.unregister() - } + val valueState = rememberUpdatedState(value) + DisposableEffect(key) { + onDispose { + vm.states[key]?.addFirst(valueState.value) } } return value