update error content

This commit is contained in:
2026-08-19 19:37:13 +03:00
parent 1d609f88d2
commit a14a659876
11 changed files with 71 additions and 50 deletions
@@ -3,7 +3,6 @@ package ru.shadowsparky.vbox.shared.presentation.list
import androiddev.apps.vbox.client.shared.generated.resources.Res
import androiddev.apps.vbox.client.shared.generated.resources.not_found
import androiddev.apps.vbox.client.shared.generated.resources.recommendations
import androiddev.apps.vbox.client.shared.generated.resources.retry
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -102,8 +101,7 @@ fun VideoScreenContent(
if (error != null) {
ErrorContent(
error,
modifier = Modifier.fillMaxSize(),
buttonText = stringResource(Res.string.retry)
modifier = Modifier.fillMaxSize()
) { onRefresh() }
} else if (items != null) {
AnimatedContent(
@@ -8,7 +8,6 @@ import androiddev.apps.vbox.client.shared.generated.resources.details_serial
import androiddev.apps.vbox.client.shared.generated.resources.more
import androiddev.apps.vbox.client.shared.generated.resources.offline_remove
import androiddev.apps.vbox.client.shared.generated.resources.offline_save
import androiddev.apps.vbox.client.shared.generated.resources.retry
import androiddev.apps.vbox.client.shared.generated.resources.share
import androiddev.apps.vbox.client.shared.generated.resources.star
import androiddev.apps.vbox.client.shared.generated.resources.star_unchecked
@@ -98,8 +97,7 @@ fun OverviewScreen(component: OverviewComponent) {
errorState != null -> ErrorContent(
errorState!!,
modifier = Modifier.fillMaxSize(),
buttonText = stringResource(Res.string.retry)
modifier = Modifier.fillMaxSize()
) { component.loadDetailsIfNeeded() }
details != null -> DetailsInfo(
@@ -7,7 +7,6 @@ import androiddev.apps.vbox.client.shared.generated.resources.episodes_overview
import androiddev.apps.vbox.client.shared.generated.resources.eye
import androiddev.apps.vbox.client.shared.generated.resources.folder_check
import androiddev.apps.vbox.client.shared.generated.resources.pending
import androiddev.apps.vbox.client.shared.generated.resources.retry
import androiddev.apps.vbox.client.shared.generated.resources.save_as
import androiddev.apps.vbox.client.shared.generated.resources.select_all
import androidx.compose.foundation.ExperimentalFoundationApi
@@ -174,8 +173,7 @@ fun EpisodesOverviewList(
if (errorCode != null) {
ErrorContent(
errorCode,
modifier = Modifier.fillMaxSize(),
buttonText = stringResource(Res.string.retry)
modifier = Modifier.fillMaxSize()
) { loadLinks() }
} else if (episodes != null) {
val lazyListState = rememberLazyListState()
@@ -1,7 +1,6 @@
package ru.shadowsparky.vbox.shared.presentation.overview.season
import androiddev.apps.vbox.client.shared.generated.resources.Res
import androiddev.apps.vbox.client.shared.generated.resources.retry
import androiddev.apps.vbox.client.shared.generated.resources.seasons_overview
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.PaddingValues
@@ -38,8 +37,7 @@ fun SeasonOverviewScreen(component: SeasonOverviewComponent) {
if (err.value != null) {
ErrorContent(
err.value!!,
modifier = Modifier.fillMaxSize(),
buttonText = stringResource(Res.string.retry)
modifier = Modifier.fillMaxSize()
) { component.load() }
} else if (seasons.value != null) {
SeasonsInfo(
@@ -2,13 +2,13 @@ package ru.shadowsparky.vbox.shared.presentation.player
import androiddev.apps.vbox.client.shared.generated.resources.Res
import androiddev.apps.vbox.client.shared.generated.resources.next_episode
import androiddev.apps.vbox.client.shared.generated.resources.retry
import androiddev.apps.vbox.client.shared.generated.resources.start_from
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
@@ -24,6 +24,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.stringResource
@@ -49,14 +50,13 @@ fun PlayerScreen(component: PlayerComponent) {
is PlayerEvent.Error -> {
ErrorContent(
state.message,
modifier = Modifier.fillMaxSize().padding(it),
buttonText = stringResource(Res.string.retry),
modifier = Modifier.fillMaxSize().padding(it)
) { component.load() }
}
is PlayerEvent.Ended -> component.requestNextEpisode()
is PlayerEvent.Playing -> {
Box(modifier = Modifier.fillMaxSize()) {
Box(modifier = Modifier.fillMaxSize().background(Color.Black)) {
VideoPlayer(
component.playerController,
Modifier.fillMaxSize(),
@@ -282,17 +282,17 @@ fun AppBarWithSearch(
navigationIcon = {},
inputField = {
Surface(
modifier = Modifier
.fillMaxWidth()
.clickable(enabled = !isDefault) { onEdit() },
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
color = Color.Transparent
) {
Row(modifier = Modifier, verticalAlignment = Alignment.CenterVertically) {
BackButton { onBack() }
Box(modifier = Modifier.weight(1f).clickable(enabled = !isDefault) { onEdit() }) {
Text(text = title, maxLines = 1)
}
}
}
}
)
}
@@ -2,9 +2,7 @@ package ru.shadowsparky.chat.presentation
import androiddev.feature.chat.chat_client.generated.resources.Res
import androiddev.feature.chat.chat_client.generated.resources.chat_input_placeholder
import androiddev.feature.chat.chat_client.generated.resources.chat_load_error
import androiddev.feature.chat.chat_client.generated.resources.chat_ok
import androiddev.feature.chat.chat_client.generated.resources.chat_retry_button
import androiddev.feature.chat.chat_client.generated.resources.send
import androidx.compose.foundation.focusable
import androidx.compose.foundation.gestures.animateScrollBy
@@ -79,6 +77,7 @@ import ru.shadowsparky.chat.domain.ChatRoles
import ru.shadowsparky.chat.domain.Message
import ru.shadowsparky.chat.domain.TextToken
import ru.shadowsparky.ui.components.AlertContent
import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.IconButton
import ru.shadowsparky.ui.components.LazyColumn
import ru.shadowsparky.ui.components.Loading
@@ -107,16 +106,7 @@ fun ChatContent(component: ChatComponent, paddingValues: PaddingValues, state: C
}
is ChatState.Error -> {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = stringResource(Res.string.chat_load_error),
color = MaterialTheme.colorScheme.error
)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = { component.loadInitialMessages() }) {
Text(stringResource(Res.string.chat_retry_button))
}
}
ErrorContent(message = state.message) { component.clearSendError() }
}
is ChatState.Data -> {
ChatContent(
@@ -29,10 +29,14 @@ import androidx.compose.material3.LinearWavyProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.withFrameNanos
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.subscribeAsState
@@ -58,16 +62,19 @@ fun UpdateDialog(
onDismissRequest = { component.reset() },
canDismiss = canDismiss,
content = {
val focusRequester = remember { FocusRequester() }
when (val currentState = state) {
is UpdateState.Checking -> UpdateCheckingContent()
is UpdateState.UpdateAvailable -> UpdateAvailableContent(
versionName = currentState.versionName,
changeLog = currentState.changeLog,
onDownloadClick = { component.downloadUpdate(currentState.url) }
onDownloadClick = { component.downloadUpdate(currentState.url) },
focusRequester = focusRequester
)
is UpdateState.InstallPermissionRequired -> UpdatePermissionContent(
onGrantClick = { component.requestPermission() }
onGrantClick = { component.requestPermission() },
focusRequester = focusRequester
)
is UpdateState.Downloading -> UpdateDownloadingContent(
@@ -77,12 +84,14 @@ fun UpdateDialog(
)
is UpdateState.ReadyToInstall -> UpdateReadyContent(
onInstallClick = { component.installApk(currentState.filePath) }
onInstallClick = { component.installApk(currentState.filePath) },
focusRequester = focusRequester
)
is UpdateState.Error -> UpdateErrorContent(
message = currentState.message,
onRetryClick = { component.checkUpdates() }
onRetryClick = { component.checkUpdates() },
focusRequester = focusRequester
)
is UpdateState.UpToDate -> {
@@ -98,6 +107,10 @@ fun UpdateDialog(
else -> Unit
}
LaunchedEffect(state) {
withFrameNanos {}
focusRequester.requestFocus()
}
}
)
}
@@ -113,6 +126,7 @@ private fun UpdateAvailableContent(
versionName: String,
changeLog: String?,
onDownloadClick: () -> Unit,
focusRequester: FocusRequester,
modifier: Modifier = Modifier
) {
Column(
@@ -141,7 +155,10 @@ private fun UpdateAvailableContent(
)
}
item {
Button(onClick = onDownloadClick, modifier = Modifier.fillMaxWidth()) {
Button(
onClick = onDownloadClick,
modifier = Modifier.focusRequester(focusRequester).fillMaxWidth()
) {
Text(
stringResource(Res.string.updater_btn_download),
style = MaterialTheme.typography.labelLarge
@@ -155,6 +172,7 @@ private fun UpdateAvailableContent(
@Composable
private fun UpdatePermissionContent(
onGrantClick: () -> Unit,
focusRequester: FocusRequester,
modifier: Modifier = Modifier
) {
Column(
@@ -170,7 +188,10 @@ private fun UpdatePermissionContent(
text = stringResource(Res.string.updater_desc_permission),
style = MaterialTheme.typography.bodyMedium
)
Button(onClick = onGrantClick, modifier = Modifier.fillMaxWidth()) {
Button(
onClick = onGrantClick,
modifier = Modifier.focusRequester(focusRequester).fillMaxWidth()
) {
Text(
stringResource(Res.string.updater_btn_grant),
style = MaterialTheme.typography.labelLarge
@@ -215,6 +236,7 @@ private fun UpdateDownloadingContent(
@Composable
private fun UpdateReadyContent(
onInstallClick: () -> Unit,
focusRequester: FocusRequester,
modifier: Modifier = Modifier
) {
Column(
@@ -226,7 +248,10 @@ private fun UpdateReadyContent(
text = stringResource(Res.string.updater_title_ready),
style = MaterialTheme.typography.titleLarge
)
Button(onClick = onInstallClick, modifier = Modifier.fillMaxWidth()) {
Button(
onClick = onInstallClick,
modifier = Modifier.focusRequester(focusRequester).fillMaxWidth()
) {
Text(
stringResource(Res.string.updater_btn_install),
style = MaterialTheme.typography.labelLarge
@@ -260,6 +285,7 @@ private fun UpdateFinishedContent(
private fun UpdateErrorContent(
message: String,
onRetryClick: () -> Unit,
focusRequester: FocusRequester,
modifier: Modifier = Modifier
) {
Column(
@@ -273,7 +299,10 @@ private fun UpdateErrorContent(
color = MaterialTheme.colorScheme.error
)
Text(text = message, style = MaterialTheme.typography.bodyMedium)
Button(onClick = onRetryClick, modifier = Modifier.fillMaxWidth()) {
Button(
onClick = onRetryClick,
modifier = Modifier.focusRequester(focusRequester).fillMaxWidth()
) {
Text(
stringResource(Res.string.updater_btn_retry),
style = MaterialTheme.typography.labelLarge
@@ -289,7 +318,8 @@ private fun UpdateAvailablePreview() {
UpdateAvailableContent(
versionName = "v1.4.0",
changeLog = "- Добавили темную тему\n- Исправили падение на главном экране\n- Повысили стабильность",
onDownloadClick = {}
onDownloadClick = {},
focusRequester = FocusRequester()
)
}
}
@@ -310,7 +340,10 @@ private fun UpdateDownloadingPreview() {
@Composable
private fun UpdatePermissionPreview() {
MaterialTheme {
UpdatePermissionContent(onGrantClick = {})
UpdatePermissionContent(
onGrantClick = {},
focusRequester = FocusRequester()
)
}
}
@@ -318,6 +351,10 @@ private fun UpdatePermissionPreview() {
@Composable
private fun UpdateErrorPreview() {
MaterialTheme {
UpdateErrorContent(message = "Http status 503: Service Unavailable", onRetryClick = {})
UpdateErrorContent(
message = "Http status 503: Service Unavailable",
onRetryClick = {},
focusRequester = FocusRequester()
)
}
}
@@ -114,7 +114,7 @@ fun VideoPlayer(
)
}
Box(modifier = rootModifier.fillMaxSize().background(Color.Black)) {
Box(modifier = rootModifier.fillMaxSize()) {
VideoCanvas(
controller = controller,
modifier = rootModifier.fillMaxSize(),
@@ -1,4 +1,5 @@
<resources>
<string name="error_title">Произошла ошибка</string>
<string name="ok">Понятно</string>
<string name="retry">Повторить</string>
</resources>
@@ -3,6 +3,7 @@ package ru.shadowsparky.ui.components
import androiddev.libs.ui.generated.resources.Res
import androiddev.libs.ui.generated.resources.error_title
import androiddev.libs.ui.generated.resources.ok
import androiddev.libs.ui.generated.resources.retry
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -25,9 +26,10 @@ fun ErrorContent(
message: String,
modifier: Modifier = Modifier,
buttonModifier: Modifier = Modifier,
buttonText: String = stringResource(Res.string.ok),
retry: Boolean = true,
onClick: () -> Unit
) {
val buttonTextRes = if (retry) Res.string.retry else Res.string.ok
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
@@ -35,10 +37,10 @@ fun ErrorContent(
) {
Text(
text = stringResource(Res.string.error_title),
style = MaterialTheme.typography.titleMedium,
style = MaterialTheme.typography.titleLarge,
textAlign = TextAlign.Center
)
Spacer(Modifier.height(2.dp))
Spacer(Modifier.height(4.dp))
Text(
text = message,
style = MaterialTheme.typography.bodyMedium,
@@ -47,7 +49,7 @@ fun ErrorContent(
Spacer(Modifier.height(8.dp))
Button(modifier = buttonModifier, onClick = { onClick() }) {
Text(
text = buttonText,
text = stringResource(buttonTextRes),
style = MaterialTheme.typography.bodyMedium
)
}
@@ -57,7 +59,6 @@ fun ErrorContent(
@Composable
fun ErrorAlert(
message: String,
buttonText: String = stringResource(Res.string.ok),
onClick: () -> Unit,
onSkip: () -> Unit = onClick
) {
@@ -66,7 +67,7 @@ fun ErrorAlert(
message,
Modifier,
Modifier.fillMaxWidth(),
buttonText,
false,
onClick
)
}