add AlertContent, add RouteNavigator
This commit is contained in:
@@ -12,8 +12,13 @@ kotlin {
|
||||
dependencies {
|
||||
implementation(libs.haze)
|
||||
implementation(libs.haze.materials)
|
||||
implementation(libs.ui.tooling.preview)
|
||||
}
|
||||
}
|
||||
}
|
||||
android { namespace = "ru.shadowsparky.ui" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
androidRuntimeClasspath(libs.ui.tooling)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package ru.shadowsparky.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.BasicAlertDialog
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.ModalBottomSheetProperties
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AlertContent(
|
||||
onDismissRequest: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
title: String? = null,
|
||||
canDismiss: Boolean = true,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
@Composable
|
||||
fun BaseDialogLayout() {
|
||||
Column(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp)
|
||||
) {
|
||||
title?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
content()
|
||||
}
|
||||
}
|
||||
if (isTv()) {
|
||||
BasicAlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
modifier = modifier,
|
||||
properties = DialogProperties(
|
||||
dismissOnBackPress = canDismiss,
|
||||
dismissOnClickOutside = canDismiss
|
||||
)
|
||||
) {
|
||||
Surface(
|
||||
shape = MaterialTheme.shapes.extraLarge,
|
||||
color = MaterialTheme.colorScheme.surface,
|
||||
tonalElevation = 6.dp
|
||||
) { BaseDialogLayout() }
|
||||
}
|
||||
} else {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = onDismissRequest,
|
||||
modifier = modifier,
|
||||
properties = ModalBottomSheetProperties(
|
||||
shouldDismissOnBackPress = canDismiss,
|
||||
shouldDismissOnClickOutside = canDismiss
|
||||
),
|
||||
shape = MaterialTheme.shapes.extraLarge
|
||||
) { BaseDialogLayout() }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
@Composable
|
||||
@@ -22,3 +23,9 @@ fun BackButton(doBack: () -> Unit) {
|
||||
)
|
||||
) { Icon(painterResource(Res.drawable.back), contentDescription = null) }
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun BackButtonPreview() {
|
||||
BackButton {}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@@ -139,3 +140,23 @@ fun ExpressiveCard(
|
||||
modifier = modifier.padding(horizontal = horizontalPadding, vertical = verticalSpacing)
|
||||
) { content() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun ExpressiveLazyColumnPreview() {
|
||||
ExpressiveLazyColumn {
|
||||
section {
|
||||
item {
|
||||
TextPreference(text = "item one")
|
||||
}
|
||||
item {
|
||||
TextPreference(text = "item two")
|
||||
}
|
||||
}
|
||||
section {
|
||||
item {
|
||||
TextPreference(text = "next section started")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
package ru.shadowsparky.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuAnchorType
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun <T> ListPreference(
|
||||
title: String,
|
||||
items: Map<T, String>,
|
||||
selectedItem: T,
|
||||
onItemSelected: (T) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
var expanded by rememberSaveable { mutableStateOf(false) }
|
||||
val entries = remember(items) { items.entries.toList() }
|
||||
val selectedLabel = remember(items, selectedItem) { items[selectedItem].orEmpty() }
|
||||
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = { if (enabled) expanded = !expanded },
|
||||
modifier = modifier
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = selectedLabel,
|
||||
onValueChange = {}, // readOnly
|
||||
readOnly = true,
|
||||
label = { Text(title) },
|
||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
||||
modifier = Modifier
|
||||
.menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable, enabled)
|
||||
.fillMaxWidth(),
|
||||
enabled = enabled,
|
||||
singleLine = true
|
||||
)
|
||||
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded && enabled,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
entries.forEach { (value, label) ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(label) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
if (value != selectedItem) onItemSelected(value)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import androidx.compose.material3.LoadingIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@@ -16,3 +17,9 @@ fun Loading(modifier: Modifier) {
|
||||
LoadingIndicator(Modifier.size(96.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun LoadingPreview() {
|
||||
Loading(Modifier)
|
||||
}
|
||||
|
||||
@@ -60,4 +60,3 @@ fun PasswordTextField(
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package ru.shadowsparky.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun PreferenceCategory(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
modifier = modifier
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
top = 24.dp,
|
||||
end = 16.dp,
|
||||
bottom = 8.dp,
|
||||
),
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
}
|
||||
@@ -3,5 +3,5 @@ package ru.shadowsparky.ui.nav
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
|
||||
interface ComponentFactory<T : Child, R : Route, BaseRoute : Route> {
|
||||
fun create(route: R, child: ComponentContext, root: BaseRootComponent<BaseRoute>): T
|
||||
fun create(route: R, child: ComponentContext, root: RouteNavigator<BaseRoute>): T
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import ru.shadowsparky.ui.theme.getColorScheme
|
||||
@OptIn(ExperimentalDecomposeApi::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun Nav(
|
||||
rootComponent: BaseRootComponent<*>,
|
||||
rootComponent: RootComponent<*>,
|
||||
process: @Composable (child: Child, route: Route) -> Unit
|
||||
) {
|
||||
Children(
|
||||
|
||||
+12
-22
@@ -18,18 +18,18 @@ import kotlinx.serialization.KSerializer
|
||||
import org.koin.core.Koin
|
||||
import org.koin.core.qualifier.named
|
||||
|
||||
abstract class BaseRootComponent<R : Route>(
|
||||
abstract class RootComponent<R : Route>(
|
||||
private val componentContext: ComponentContext,
|
||||
) : ComponentContext by componentContext, BackHandlerOwner {
|
||||
) : ComponentContext by componentContext, BackHandlerOwner, RouteNavigator<R> {
|
||||
|
||||
protected abstract val initStack: List<R>
|
||||
protected abstract val serializer: KSerializer<R>
|
||||
protected abstract val koin: Koin
|
||||
|
||||
private val scope = coroutineScope()
|
||||
|
||||
protected val nav = StackNavigation<R>()
|
||||
|
||||
protected val childStack by lazy {
|
||||
val childStack by lazy {
|
||||
childStack(
|
||||
source = nav,
|
||||
serializer = serializer,
|
||||
@@ -41,36 +41,26 @@ abstract class BaseRootComponent<R : Route>(
|
||||
private val _onFinish = MutableStateFlow<Unit?>(null)
|
||||
val onFinish = _onFinish.filterNotNull()
|
||||
|
||||
fun navReplace(vararg route: R) {
|
||||
override fun navReplace(vararg route: R) {
|
||||
nav.replaceAll(*route)
|
||||
}
|
||||
|
||||
fun nav(route: R, bringToFront: Boolean = false) {
|
||||
if (bringToFront) {
|
||||
nav.bringToFront(route)
|
||||
} else {
|
||||
nav.pushNew(route)
|
||||
}
|
||||
override fun nav(route: R, bringToFront: Boolean) {
|
||||
if (bringToFront) nav.bringToFront(route) else nav.pushNew(route)
|
||||
}
|
||||
|
||||
fun onBack() {
|
||||
nav.pop { popped ->
|
||||
if (!popped) finish()
|
||||
}
|
||||
override fun onBack() {
|
||||
nav.pop { popped -> if (!popped) finish() }
|
||||
}
|
||||
|
||||
fun finish() {
|
||||
override fun finish() {
|
||||
scope.launch { _onFinish.emit(Unit) }
|
||||
}
|
||||
|
||||
val valueChildStack: Value<ChildStack<*, Child>> by lazy { childStack }
|
||||
|
||||
protected open fun newChild(route: Route, ctx: ComponentContext): Child {
|
||||
val factory = route.provideFactory<Child, Route>(koin)
|
||||
return factory.create(route, ctx, this as BaseRootComponent<Route>)
|
||||
}
|
||||
|
||||
private fun <T : Child, R : Route> Route.provideFactory(koin: Koin): ComponentFactory<T, R, Route> {
|
||||
return koin.get<ComponentFactory<T, R, Route>>(named(routeId))
|
||||
val factory = koin.get<ComponentFactory<Child, Route, R>>(named(route.routeId))
|
||||
return factory.create(route, ctx, this as RouteNavigator<R>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ru.shadowsparky.ui.nav
|
||||
|
||||
interface RouteNavigator<out R : Route> {
|
||||
fun navReplace(vararg route: @UnsafeVariance R)
|
||||
fun nav(route: @UnsafeVariance R, bringToFront: Boolean = false)
|
||||
fun onBack()
|
||||
fun finish()
|
||||
}
|
||||
+87
-56
@@ -18,18 +18,14 @@ import androiddev.libs.updater.updater_client.generated.resources.updater_title_
|
||||
import androiddev.libs.updater.updater_client.generated.resources.updater_title_permission
|
||||
import androiddev.libs.updater.updater_client.generated.resources.updater_title_ready
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.BasicAlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -38,10 +34,10 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.components.AlertContent
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.updater.domain.UpdateState
|
||||
|
||||
@@ -55,50 +51,50 @@ fun UpdateDialog(
|
||||
val canDismiss = remember(state) { !component.isForceUpdate }
|
||||
val isVisible = remember(state) { state !is UpdateState.Idle }
|
||||
if (isVisible) {
|
||||
BasicAlertDialog(
|
||||
AlertContent(
|
||||
modifier = modifier,
|
||||
onDismissRequest = { component.reset() },
|
||||
properties = DialogProperties(
|
||||
canDismiss,
|
||||
canDismiss,
|
||||
),
|
||||
canDismiss = canDismiss,
|
||||
content = {
|
||||
Surface(shape = MaterialTheme.shapes.extraLarge) {
|
||||
Box(modifier = Modifier.padding(16.dp)) {
|
||||
when (val currentState = state) {
|
||||
is UpdateState.Checking -> UpdateCheckingContent()
|
||||
is UpdateState.UpdateAvailable -> UpdateAvailableContent(
|
||||
versionName = currentState.versionName,
|
||||
changeLog = currentState.changeLog,
|
||||
onDownloadClick = { component.downloadUpdate(currentState.url) }
|
||||
)
|
||||
is UpdateState.InstallPermissionRequired -> UpdatePermissionContent(
|
||||
onGrantClick = { component.requestPermission() }
|
||||
)
|
||||
is UpdateState.Downloading -> UpdateDownloadingContent(
|
||||
progress = currentState.progress,
|
||||
downloadedBytes = currentState.downloadedBytes,
|
||||
totalBytes = currentState.totalBytes
|
||||
)
|
||||
is UpdateState.ReadyToInstall -> UpdateReadyContent(
|
||||
onInstallClick = { component.installApk(currentState.filePath) }
|
||||
)
|
||||
is UpdateState.Error -> UpdateErrorContent(
|
||||
message = currentState.message,
|
||||
onRetryClick = { component.checkUpdates() }
|
||||
)
|
||||
is UpdateState.UpToDate -> {
|
||||
UpdateFinishedContent(onSkip = { component.reset() })
|
||||
}
|
||||
is UpdateState.Completed -> {
|
||||
UpdateFinishedContent(
|
||||
Res.string.updater_title_completed,
|
||||
onSkip = { component.reset() }
|
||||
)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
when (val currentState = state) {
|
||||
is UpdateState.Checking -> UpdateCheckingContent()
|
||||
is UpdateState.UpdateAvailable -> UpdateAvailableContent(
|
||||
versionName = currentState.versionName,
|
||||
changeLog = currentState.changeLog,
|
||||
onDownloadClick = { component.downloadUpdate(currentState.url) }
|
||||
)
|
||||
|
||||
is UpdateState.InstallPermissionRequired -> UpdatePermissionContent(
|
||||
onGrantClick = { component.requestPermission() }
|
||||
)
|
||||
|
||||
is UpdateState.Downloading -> UpdateDownloadingContent(
|
||||
progress = currentState.progress,
|
||||
downloadedBytes = currentState.downloadedBytes,
|
||||
totalBytes = currentState.totalBytes
|
||||
)
|
||||
|
||||
is UpdateState.ReadyToInstall -> UpdateReadyContent(
|
||||
onInstallClick = { component.installApk(currentState.filePath) }
|
||||
)
|
||||
|
||||
is UpdateState.Error -> UpdateErrorContent(
|
||||
message = currentState.message,
|
||||
onRetryClick = { component.checkUpdates() }
|
||||
)
|
||||
|
||||
is UpdateState.UpToDate -> {
|
||||
UpdateFinishedContent(onSkip = { component.reset() })
|
||||
}
|
||||
|
||||
is UpdateState.Completed -> {
|
||||
UpdateFinishedContent(
|
||||
Res.string.updater_title_completed,
|
||||
onSkip = { component.reset() }
|
||||
)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -138,7 +134,10 @@ private fun UpdateAvailableContent(
|
||||
)
|
||||
}
|
||||
Button(onClick = onDownloadClick, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(stringResource(Res.string.updater_btn_download), style = MaterialTheme.typography.labelLarge)
|
||||
Text(
|
||||
stringResource(Res.string.updater_btn_download),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,10 +152,19 @@ private fun UpdatePermissionContent(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Text(text = stringResource(Res.string.updater_title_permission), style = MaterialTheme.typography.titleLarge)
|
||||
Text(text = stringResource(Res.string.updater_desc_permission), style = MaterialTheme.typography.bodyMedium)
|
||||
Text(
|
||||
text = stringResource(Res.string.updater_title_permission),
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
Text(
|
||||
text = stringResource(Res.string.updater_desc_permission),
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Button(onClick = onGrantClick, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(stringResource(Res.string.updater_btn_grant), style = MaterialTheme.typography.labelLarge)
|
||||
Text(
|
||||
stringResource(Res.string.updater_btn_grant),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,14 +181,21 @@ private fun UpdateDownloadingContent(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Text(text = stringResource(Res.string.updater_title_downloading), style = MaterialTheme.typography.titleMedium)
|
||||
Text(
|
||||
text = stringResource(Res.string.updater_title_downloading),
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
LinearProgressIndicator(progress = { progress }, modifier = Modifier.fillMaxWidth())
|
||||
|
||||
val downloadedMb = ((downloadedBytes / (1024f * 1024f)) * 10).toInt() / 10.0
|
||||
val totalMb = ((totalBytes / (1024f * 1024f)) * 10).toInt() / 10.0
|
||||
|
||||
Text(
|
||||
text = stringResource(Res.string.updater_download_progress, downloadedMb.toString(), totalMb.toString()),
|
||||
text = stringResource(
|
||||
Res.string.updater_download_progress,
|
||||
downloadedMb.toString(),
|
||||
totalMb.toString()
|
||||
),
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
}
|
||||
@@ -196,9 +211,15 @@ private fun UpdateReadyContent(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Text(text = stringResource(Res.string.updater_title_ready), style = MaterialTheme.typography.titleLarge)
|
||||
Text(
|
||||
text = stringResource(Res.string.updater_title_ready),
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
Button(onClick = onInstallClick, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(stringResource(Res.string.updater_btn_install), style = MaterialTheme.typography.labelLarge)
|
||||
Text(
|
||||
stringResource(Res.string.updater_btn_install),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,7 +237,10 @@ private fun UpdateFinishedContent(
|
||||
) {
|
||||
Text(text = stringResource(text), style = MaterialTheme.typography.titleLarge)
|
||||
Button(onClick = onSkip, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(stringResource(Res.string.updater_btn_close), style = MaterialTheme.typography.labelLarge)
|
||||
Text(
|
||||
stringResource(Res.string.updater_btn_close),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,10 +256,17 @@ private fun UpdateErrorContent(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Text(text = stringResource(Res.string.updater_title_error), style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.error)
|
||||
Text(
|
||||
text = stringResource(Res.string.updater_title_error),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
Text(text = message, style = MaterialTheme.typography.bodyMedium)
|
||||
Button(onClick = onRetryClick, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(stringResource(Res.string.updater_btn_retry), style = MaterialTheme.typography.labelLarge)
|
||||
Text(
|
||||
stringResource(Res.string.updater_btn_retry),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user