Make ExtensionStoresViewModel collect stores only while subscribed (#3717)
Assisted-by: Claude:claude-opus-5
This commit is contained in:
+2
-2
@@ -2,9 +2,9 @@ package eu.kanade.presentation.more.settings.screen.browse
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
@@ -27,7 +27,7 @@ class ExtensionStoresScreen(
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
val viewModel = viewModel<ExtensionStoresViewModel>()
|
||||
val state by viewModel.state.collectAsState()
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(url) {
|
||||
url?.let { viewModel.addFromDeeplink(url) }
|
||||
|
||||
+44
-66
@@ -1,12 +1,19 @@
|
||||
package eu.kanade.presentation.more.settings.screen.browse
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import mihon.core.viewmodel.StateViewModel
|
||||
import mihon.domain.extension.interactor.AddExtensionStore
|
||||
import mihon.domain.extension.interactor.GetExtensionStores
|
||||
import mihon.domain.extension.interactor.RemoveExtensionStore
|
||||
@@ -15,6 +22,7 @@ import mihon.domain.extension.model.ExtensionStore
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class ExtensionStoresViewModel(
|
||||
private val getExtensionStores: GetExtensionStores = Injekt.get(),
|
||||
@@ -22,32 +30,18 @@ class ExtensionStoresViewModel(
|
||||
private val removeExtensionStore: RemoveExtensionStore = Injekt.get(),
|
||||
private val updateExtensionStores: UpdateExtensionStores = Injekt.get(),
|
||||
private val extensionManager: ExtensionManager = Injekt.get(),
|
||||
) : StateViewModel<ExtensionStoreScreenState>(ExtensionStoreScreenState.Loading) {
|
||||
) : ViewModel() {
|
||||
|
||||
private inline fun updateSuccessState(
|
||||
func: (ExtensionStoreScreenState.Success) -> ExtensionStoreScreenState.Success,
|
||||
) {
|
||||
mutableState.update {
|
||||
when (it) {
|
||||
ExtensionStoreScreenState.Loading -> it
|
||||
is ExtensionStoreScreenState.Success -> func(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val dialog = MutableStateFlow<ExtensionStoreDialog?>(null)
|
||||
|
||||
init {
|
||||
viewModelScope.launchIO {
|
||||
getExtensionStores.subscribe()
|
||||
.collectLatest { stores ->
|
||||
mutableState.update {
|
||||
when (it) {
|
||||
ExtensionStoreScreenState.Loading -> ExtensionStoreScreenState.Success(stores = stores)
|
||||
is ExtensionStoreScreenState.Success -> it.copy(stores = stores)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val state: StateFlow<ExtensionStoreScreenState> = combine(
|
||||
getExtensionStores.subscribe(),
|
||||
dialog,
|
||||
) { stores, dialog ->
|
||||
ExtensionStoreScreenState.Success(stores = stores, dialog = dialog)
|
||||
}
|
||||
.flowOn(Dispatchers.IO)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), ExtensionStoreScreenState.Loading)
|
||||
|
||||
/**
|
||||
* Creates and adds a new repo to the database.
|
||||
@@ -56,14 +50,12 @@ class ExtensionStoresViewModel(
|
||||
*/
|
||||
fun createRepo(baseUrl: String) {
|
||||
viewModelScope.launch {
|
||||
updateSuccessState {
|
||||
it.copy(
|
||||
dialog = when (it.dialog) {
|
||||
is ExtensionStoreDialog.Create -> it.dialog.copy(processing = true)
|
||||
is ExtensionStoreDialog.Confirm -> it.dialog.copy(processing = true)
|
||||
else -> it.dialog
|
||||
},
|
||||
)
|
||||
dialog.update {
|
||||
when (it) {
|
||||
is ExtensionStoreDialog.Create -> it.copy(processing = true)
|
||||
is ExtensionStoreDialog.Confirm -> it.copy(processing = true)
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
addExtensionStore(baseUrl)
|
||||
.onSuccess {
|
||||
@@ -71,20 +63,18 @@ class ExtensionStoresViewModel(
|
||||
dismissDialog()
|
||||
}
|
||||
.onFailure { throwable ->
|
||||
updateSuccessState {
|
||||
it.copy(
|
||||
dialog = when (it.dialog) {
|
||||
is ExtensionStoreDialog.Create -> it.dialog.copy(
|
||||
processing = false,
|
||||
errorMessage = throwable.message ?: "unknown error",
|
||||
)
|
||||
is ExtensionStoreDialog.Confirm -> it.dialog.copy(
|
||||
processing = false,
|
||||
errorMessage = throwable.message ?: "unknown error",
|
||||
)
|
||||
else -> it.dialog
|
||||
},
|
||||
)
|
||||
dialog.update {
|
||||
when (it) {
|
||||
is ExtensionStoreDialog.Create -> it.copy(
|
||||
processing = false,
|
||||
errorMessage = throwable.message ?: "unknown error",
|
||||
)
|
||||
is ExtensionStoreDialog.Confirm -> it.copy(
|
||||
processing = false,
|
||||
errorMessage = throwable.message ?: "unknown error",
|
||||
)
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,12 +84,8 @@ class ExtensionStoresViewModel(
|
||||
* Refreshes information for each repository.
|
||||
*/
|
||||
fun refreshRepos() {
|
||||
val status = state.value
|
||||
|
||||
if (status is ExtensionStoreScreenState.Success) {
|
||||
viewModelScope.launchIO {
|
||||
updateExtensionStores()
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
updateExtensionStores()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,26 +100,18 @@ class ExtensionStoresViewModel(
|
||||
}
|
||||
|
||||
fun addFromDeeplink(storeIndexUrl: String) {
|
||||
updateSuccessState { state ->
|
||||
state.copy(
|
||||
dialog = ExtensionStoreDialog.Confirm(
|
||||
url = storeIndexUrl,
|
||||
alreadyExists = state.stores.any { it.indexUrl == storeIndexUrl },
|
||||
),
|
||||
)
|
||||
viewModelScope.launchIO {
|
||||
val alreadyExists = getExtensionStores.get().any { it.indexUrl == storeIndexUrl }
|
||||
dialog.update { ExtensionStoreDialog.Confirm(url = storeIndexUrl, alreadyExists = alreadyExists) }
|
||||
}
|
||||
}
|
||||
|
||||
fun showDialog(dialog: ExtensionStoreDialog) {
|
||||
updateSuccessState { state ->
|
||||
state.copy(dialog = dialog)
|
||||
}
|
||||
this.dialog.update { dialog }
|
||||
}
|
||||
|
||||
fun dismissDialog() {
|
||||
updateSuccessState {
|
||||
it.copy(dialog = null)
|
||||
}
|
||||
dialog.update { null }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user