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

View file

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