🚀 Improve ErrorPlaceholder in Reader

* Disabled onClick actions when error is shown
* Better structure
This commit is contained in:
Acclorite 2025-01-04 20:37:17 +02:00
parent cd2718b8d3
commit e93eeea497
7 changed files with 152 additions and 143 deletions

View file

@ -91,6 +91,7 @@ fun ReaderContent(
dismissBottomSheet = dismissBottomSheet dismissBottomSheet = dismissBottomSheet
) )
if (isLoading || errorMessage == null) {
ReaderScaffold( ReaderScaffold(
book = book, book = book,
text = text, text = text,
@ -103,7 +104,6 @@ fun ReaderContent(
perceptionExpanderThickness = perceptionExpanderThickness, perceptionExpanderThickness = perceptionExpanderThickness,
currentChapterProgress = currentChapterProgress, currentChapterProgress = currentChapterProgress,
isLoading = isLoading, isLoading = isLoading,
errorMessage = errorMessage,
checkpoint = checkpoint, checkpoint = checkpoint,
showMenu = showMenu, showMenu = showMenu,
lockMenu = lockMenu, lockMenu = lockMenu,
@ -145,6 +145,13 @@ fun ReaderContent(
navigateBack = navigateBack, navigateBack = navigateBack,
navigateToBookInfo = navigateToBookInfo navigateToBookInfo = navigateToBookInfo
) )
} else {
ReaderErrorPlaceholder(
errorMessage = errorMessage,
leave = leave,
navigateBack = navigateBack
)
}
ReaderDrawer( ReaderDrawer(
drawer = drawer, drawer = drawer,

View file

@ -0,0 +1,47 @@
package ua.acclorite.book_story.presentation.reader
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.ui.UIText
import ua.acclorite.book_story.presentation.core.components.placeholder.ErrorPlaceholder
import ua.acclorite.book_story.presentation.core.util.LocalActivity
import ua.acclorite.book_story.ui.reader.ReaderEvent
@Composable
fun ReaderErrorPlaceholder(
errorMessage: UIText,
leave: (ReaderEvent.OnLeave) -> Unit,
navigateBack: () -> Unit
) {
val activity = LocalActivity.current
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface),
contentAlignment = Alignment.Center
) {
ErrorPlaceholder(
errorMessage = errorMessage.asString(),
icon = painterResource(id = R.drawable.error),
actionTitle = stringResource(id = R.string.go_back),
action = {
leave(
ReaderEvent.OnLeave(
activity = activity,
navigate = {
navigateBack()
}
)
)
}
)
}
}

View file

@ -1,61 +0,0 @@
package ua.acclorite.book_story.presentation.reader
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.ui.UIText
import ua.acclorite.book_story.presentation.core.components.placeholder.ErrorPlaceholder
import ua.acclorite.book_story.presentation.core.components.progress_indicator.CircularProgressIndicator
import ua.acclorite.book_story.presentation.core.util.LocalActivity
import ua.acclorite.book_story.ui.reader.ReaderEvent
@Composable
fun ReaderLoadingIndicator(
isLoading: Boolean,
errorMessage: UIText?,
leave: (ReaderEvent.OnLeave) -> Unit,
navigateBack: () -> Unit
) {
val activity = LocalActivity.current
if (isLoading || errorMessage != null) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface),
contentAlignment = Alignment.Center
) {
if (!isLoading) {
ErrorPlaceholder(
errorMessage = errorMessage!!.asString(),
icon = painterResource(id = R.drawable.error),
actionTitle = stringResource(id = R.string.go_back),
action = {
leave(
ReaderEvent.OnLeave(
activity = activity,
navigate = {
navigateBack()
}
)
)
}
)
} else {
CircularProgressIndicator(
modifier = Modifier.size(48.dp),
strokeWidth = 4.5.dp
)
}
}
}
}

View file

@ -0,0 +1,27 @@
package ua.acclorite.book_story.presentation.reader
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.presentation.core.components.progress_indicator.CircularProgressIndicator
@Composable
fun ReaderLoadingPlaceholder() {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(
modifier = Modifier.size(48.dp),
strokeWidth = 4.5.dp
)
}
}

View file

@ -26,7 +26,6 @@ import ua.acclorite.book_story.domain.reader.ReaderHorizontalGesture
import ua.acclorite.book_story.domain.reader.ReaderText import ua.acclorite.book_story.domain.reader.ReaderText
import ua.acclorite.book_story.domain.reader.ReaderText.Chapter import ua.acclorite.book_story.domain.reader.ReaderText.Chapter
import ua.acclorite.book_story.domain.reader.ReaderTextAlignment import ua.acclorite.book_story.domain.reader.ReaderTextAlignment
import ua.acclorite.book_story.domain.ui.UIText
import ua.acclorite.book_story.presentation.core.components.common.AnimatedVisibility import ua.acclorite.book_story.presentation.core.components.common.AnimatedVisibility
import ua.acclorite.book_story.ui.reader.ReaderEvent import ua.acclorite.book_story.ui.reader.ReaderEvent
import ua.acclorite.book_story.ui.settings.SettingsEvent import ua.acclorite.book_story.ui.settings.SettingsEvent
@ -45,7 +44,6 @@ fun ReaderScaffold(
perceptionExpanderThickness: Dp, perceptionExpanderThickness: Dp,
currentChapterProgress: Float, currentChapterProgress: Float,
isLoading: Boolean, isLoading: Boolean,
errorMessage: UIText?,
checkpoint: Checkpoint, checkpoint: Checkpoint,
showMenu: Boolean, showMenu: Boolean,
lockMenu: Boolean, lockMenu: Boolean,
@ -178,11 +176,8 @@ fun ReaderScaffold(
perceptionExpanderColor = fontColor perceptionExpanderColor = fontColor
) )
ReaderLoadingIndicator( if (isLoading) {
isLoading = isLoading, ReaderLoadingPlaceholder()
errorMessage = errorMessage, }
leave = leave,
navigateBack = navigateBack
)
} }
} }

View file

@ -1,6 +1,5 @@
package ua.acclorite.book_story.ui.reader package ua.acclorite.book_story.ui.reader
import android.content.Context
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import ua.acclorite.book_story.domain.reader.ReaderText.Chapter import ua.acclorite.book_story.domain.reader.ReaderText.Chapter
@ -8,9 +7,7 @@ import ua.acclorite.book_story.domain.reader.ReaderText.Chapter
@Immutable @Immutable
sealed class ReaderEvent { sealed class ReaderEvent {
data class OnLoadText( data object OnLoadText : ReaderEvent()
val context: Context
) : ReaderEvent()
data class OnMenuVisibility( data class OnMenuVisibility(
val show: Boolean, val show: Boolean,

View file

@ -140,8 +140,7 @@ class ReaderModel @Inject constructor(
yield() yield()
systemBarsVisibility( systemBarsVisibility(
show = shouldShow, show = shouldShow || !event.fullscreenMode,
fullscreenMode = event.fullscreenMode,
activity = event.activity activity = event.activity
) )
_state.update { _state.update {
@ -482,11 +481,7 @@ class ReaderModel @Inject constructor(
activity = activity activity = activity
) )
) )
onEvent( onEvent(ReaderEvent.OnLoadText)
ReaderEvent.OnLoadText(
context = activity
)
)
} }
} }
@ -599,20 +594,22 @@ class ReaderModel @Inject constructor(
} }
} }
private fun systemBarsVisibility( private suspend fun systemBarsVisibility(
show: Boolean, show: Boolean,
fullscreenMode: Boolean,
activity: ComponentActivity activity: ComponentActivity
) { ) {
withContext(Dispatchers.Main) {
WindowCompat.getInsetsController( WindowCompat.getInsetsController(
activity.window, activity.window,
activity.window.decorView activity.window.decorView
).apply { ).apply {
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE systemBarsBehavior =
if (show || !fullscreenMode) show(WindowInsetsCompat.Type.systemBars()) WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
if (show) show(WindowInsetsCompat.Type.systemBars())
else hide(WindowInsetsCompat.Type.systemBars()) else hide(WindowInsetsCompat.Type.systemBars())
} }
} }
}
fun resetScreen() { fun resetScreen() {
resetJob = viewModelScope.launch(Dispatchers.Main) { resetJob = viewModelScope.launch(Dispatchers.Main) {