BookInfoScreen: Canceling BookInfoViewModel.onEvent + Resetting BookInfoState when exiting screen.

This commit is contained in:
acclorite 2024-07-08 14:35:39 +03:00
parent d6de5bc521
commit 4f521bcd1e
2 changed files with 714 additions and 679 deletions

View file

@ -37,6 +37,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
@ -92,6 +93,12 @@ fun BookInfoScreenRoot(screen: Screen.BookInfo) {
)
}
DisposableEffect(Unit) {
onDispose {
viewModel.clearViewModel()
}
}
BookInfoScreen(
state = state,
onNavigate = { navigator.it() },

View file

@ -1,3 +1,5 @@
@file:Suppress("LABEL_NAME_CLASH")
package ua.acclorite.book_story.presentation.screens.book_info.data
import android.content.ClipData
@ -11,6 +13,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
@ -56,10 +59,13 @@ class BookInfoViewModel @Inject constructor(
private val _state = MutableStateFlow(BookInfoState())
val state = _state.asStateFlow()
private var job: Job? = null
private var job2: Job? = null
private var eventJob = SupervisorJob()
private var snackBarJob: Job? = null
private var updateJob: Job? = null
fun onEvent(event: BookInfoEvent) {
viewModelScope.launch(eventJob + Dispatchers.Main) {
when (event) {
is BookInfoEvent.OnShowHideChangeCoverBottomSheet -> {
_state.update {
@ -70,7 +76,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnChangeCover -> {
viewModelScope.launch {
launch {
val image = event.context.contentResolver?.openInputStream(event.uri)?.use {
BitmapFactory.decodeStream(it)
} ?: return@launch
@ -97,7 +103,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnDeleteCover -> {
viewModelScope.launch {
launch {
if (_state.value.book.coverImage == null) {
return@launch
}
@ -120,7 +126,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnCheckCoverReset -> {
viewModelScope.launch(Dispatchers.IO) {
launch(Dispatchers.IO) {
_state.update {
it.copy(
canResetCover = canResetCover.execute(_state.value.book.id)
@ -130,7 +136,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnResetCoverImage -> {
viewModelScope.launch {
launch {
val result = resetCoverImage.execute(_state.value.book.id)
if (!result) {
@ -158,7 +164,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnShowHideEditTitle -> {
viewModelScope.launch(Dispatchers.IO) {
launch(Dispatchers.IO) {
val shouldHide = _state.value.editTitle
if (!shouldHide) {
@ -198,7 +204,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnShowHideEditAuthor -> {
viewModelScope.launch(Dispatchers.IO) {
launch(Dispatchers.IO) {
val shouldHide = _state.value.editAuthor
if (!shouldHide) {
@ -238,7 +244,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnShowHideEditDescription -> {
viewModelScope.launch(Dispatchers.IO) {
launch(Dispatchers.IO) {
val shouldHide = _state.value.editDescription
if (!shouldHide) {
@ -278,7 +284,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnUpdateData -> {
viewModelScope.launch {
launch {
val title = _state.value.titleValue.trim().replace("\n", "")
val author = _state.value.authorValue.trim().replace("\n", "")
val description = _state.value.descriptionValue.trim().replace("\n", "")
@ -332,7 +338,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnDeleteBook -> {
viewModelScope.launch {
launch {
_state.update {
it.copy(
showDeleteDialog = false
@ -365,7 +371,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnMoveBook -> {
viewModelScope.launch {
launch {
_state.update {
it.copy(
showMoveDialog = false
@ -416,12 +422,12 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnShowSnackbar -> {
viewModelScope.launch {
job?.cancel()
launch {
snackBarJob?.cancel()
event.snackbarState.currentSnackbarData?.dismiss()
if (event.durationMillis > 0) {
job = viewModelScope.launch(Dispatchers.IO) {
snackBarJob = launch(Dispatchers.IO) {
yield()
delay(event.durationMillis)
yield()
@ -444,11 +450,11 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnLoadUpdate -> {
onEvent(BookInfoEvent.OnCancelUpdate)
job2 = viewModelScope.launch(Dispatchers.IO) {
updateJob?.cancel()
updateJob = launch(Dispatchers.IO) {
_state.update {
it.copy(
showConfirmUpdateDialog = false,
isLoadingUpdate = true,
editTitle = false,
editAuthor = false,
@ -606,7 +612,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnConfirmUpdate -> {
viewModelScope.launch(Dispatchers.IO) {
launch(Dispatchers.IO) {
_state.update {
it.copy(
isRefreshing = true,
@ -769,7 +775,8 @@ class BookInfoViewModel @Inject constructor(
is BookInfoEvent.OnCancelUpdate -> {
_state.update {
job2?.cancel()
updateJob?.cancel()
it.copy(
showConfirmUpdateDialog = false,
isLoadingUpdate = false
@ -778,7 +785,7 @@ class BookInfoViewModel @Inject constructor(
}
is BookInfoEvent.OnNavigateToReaderScreen -> {
viewModelScope.launch {
launch {
onEvent(BookInfoEvent.OnCancelUpdate)
_state.value.book.id.let {
insertHistory.execute(
@ -800,9 +807,10 @@ class BookInfoViewModel @Inject constructor(
}
}
}
}
fun init(screen: Screen.BookInfo, onNavigate: OnNavigate) {
viewModelScope.launch {
viewModelScope.launch(Dispatchers.IO) {
val book = getBookById.execute(screen.bookId)
if (book == null) {
@ -817,7 +825,27 @@ class BookInfoViewModel @Inject constructor(
book = book
)
}
clear()
onEvent(BookInfoEvent.OnCheckCoverReset)
}
}
private suspend fun clear() {
eventJob.cancel()
eventJob.join()
eventJob = SupervisorJob()
}
fun clearViewModel() {
viewModelScope.launch(Dispatchers.Main) {
_state.update {
BookInfoState()
}
eventJob.cancel()
eventJob.join()
eventJob = SupervisorJob()
}
}
}