🛠️ New dialog & update default

* Updated default dialog
* Added new dialog with text field
This commit is contained in:
Acclorite 2025-01-24 14:15:36 +02:00
parent 4f8da6ba8e
commit f232cd3688
13 changed files with 187 additions and 107 deletions

View file

@ -22,11 +22,10 @@ fun AboutUpdateDialog(
Dialog( Dialog(
title = stringResource(id = R.string.update_query, updateInfo?.tagName ?: ""), title = stringResource(id = R.string.update_query, updateInfo?.tagName ?: ""),
imageVectorIcon = Icons.Default.Update, icon = Icons.Default.Update,
description = stringResource( description = stringResource(
id = R.string.update_app_description id = R.string.update_app_description
), ),
actionText = stringResource(id = R.string.proceed),
actionEnabled = true, actionEnabled = true,
disableOnClick = false, disableOnClick = false,
onDismiss = { dismissDialog(AboutEvent.OnDismissDialog) }, onDismiss = { dismissDialog(AboutEvent.OnDismissDialog) },
@ -39,6 +38,6 @@ fun AboutUpdateDialog(
) )
dismissDialog(AboutEvent.OnDismissDialog) dismissDialog(AboutEvent.OnDismissDialog)
}, },
withDivider = false withContent = false
) )
} }

View file

@ -19,13 +19,12 @@ fun BookInfoDeleteDialog(
Dialog( Dialog(
title = stringResource(id = R.string.delete_book), title = stringResource(id = R.string.delete_book),
imageVectorIcon = Icons.Outlined.DeleteOutline, icon = Icons.Outlined.DeleteOutline,
description = stringResource( description = stringResource(
id = R.string.delete_book_description id = R.string.delete_book_description
), ),
actionText = stringResource(id = R.string.delete),
onDismiss = { dismissDialog(BookInfoEvent.OnDismissDialog) }, onDismiss = { dismissDialog(BookInfoEvent.OnDismissDialog) },
withDivider = false, withContent = false,
actionEnabled = true, actionEnabled = true,
onAction = { onAction = {
actionDeleteDialog( actionDeleteDialog(

View file

@ -33,11 +33,10 @@ fun BookInfoMoveDialog(
Dialog( Dialog(
title = stringResource(id = R.string.move_book), title = stringResource(id = R.string.move_book),
imageVectorIcon = Icons.AutoMirrored.Outlined.DriveFileMove, icon = Icons.AutoMirrored.Outlined.DriveFileMove,
description = stringResource( description = stringResource(
id = R.string.move_book_description id = R.string.move_book_description
), ),
actionText = stringResource(id = R.string.move),
actionEnabled = true, actionEnabled = true,
onDismiss = { dismissDialog(BookInfoEvent.OnDismissDialog) }, onDismiss = { dismissDialog(BookInfoEvent.OnDismissDialog) },
onAction = { onAction = {
@ -49,7 +48,7 @@ fun BookInfoMoveDialog(
) )
) )
}, },
withDivider = false, withContent = true,
items = { items = {
items(categories, key = { it.name }) { items(categories, key = { it.name }) {
val category = when (it) { val category = when (it) {

View file

@ -34,9 +34,8 @@ fun BrowseAddDialog(
val context = LocalContext.current val context = LocalContext.current
Dialog( Dialog(
title = stringResource(id = R.string.add_books), title = stringResource(id = R.string.add_books),
imageVectorIcon = Icons.Default.AddChart, icon = Icons.Default.AddChart,
description = stringResource(id = R.string.add_books_description), description = stringResource(id = R.string.add_books_description),
actionText = stringResource(id = R.string.add),
actionEnabled = !loadingAddDialog && selectedBooksAddDialog.any { it.data is NullableBook.NotNull }, actionEnabled = !loadingAddDialog && selectedBooksAddDialog.any { it.data is NullableBook.NotNull },
onDismiss = { dismissAddDialog(BrowseEvent.OnDismissAddDialog) }, onDismiss = { dismissAddDialog(BrowseEvent.OnDismissAddDialog) },
onAction = { onAction = {
@ -47,7 +46,7 @@ fun BrowseAddDialog(
) )
) )
}, },
withDivider = true, withContent = true,
items = { items = {
if (loadingAddDialog) { if (loadingAddDialog) {
item { item {

View file

@ -22,9 +22,8 @@ fun BrowsePermissionDialog(
Dialog( Dialog(
title = stringResource(id = R.string.storage_permission), title = stringResource(id = R.string.storage_permission),
imageVectorIcon = Icons.Outlined.SdStorage, icon = Icons.Outlined.SdStorage,
description = stringResource(id = R.string.storage_permission_description), description = stringResource(id = R.string.storage_permission_description),
actionText = stringResource(id = R.string.grant),
actionEnabled = true, actionEnabled = true,
disableOnClick = false, disableOnClick = false,
onDismiss = { onDismiss = {
@ -42,6 +41,6 @@ fun BrowsePermissionDialog(
) )
) )
}, },
withDivider = false withContent = false
) )
} }

View file

@ -1,6 +1,7 @@
package ua.acclorite.book_story.presentation.core.components.dialog package ua.acclorite.book_story.presentation.core.components.dialog
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -10,12 +11,9 @@ import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.BasicAlertDialog import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -28,7 +26,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -37,23 +34,21 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.DialogWindowProvider import androidx.compose.ui.window.DialogWindowProvider
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.core.components.common.LazyColumnWithScrollbar
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun Dialog( fun Dialog(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
drawableIcon: Painter? = null, icon: ImageVector? = null,
imageVectorIcon: ImageVector? = null,
backgroundTransparency: Float = 0.5f,
title: String, title: String,
description: String?, description: String?,
actionText: String?,
disableOnClick: Boolean = true, disableOnClick: Boolean = true,
actionEnabled: Boolean?, actionEnabled: Boolean?,
onDismiss: () -> Unit, onDismiss: () -> Unit,
onAction: () -> Unit, onAction: () -> Unit,
withDivider: Boolean, withContent: Boolean,
items: (LazyListScope.() -> Unit) = {} items: (LazyListScope.() -> Unit) = {}
) { ) {
var actionClicked by remember { mutableStateOf(false) } var actionClicked by remember { mutableStateOf(false) }
@ -74,25 +69,11 @@ fun Dialog(
dismissOnClickOutside = !actionClicked dismissOnClickOutside = !actionClicked
) )
) { ) {
(LocalView.current.parent as DialogWindowProvider).window.setDimAmount( (LocalView.current.parent as DialogWindowProvider).window.setDimAmount(0.5f)
backgroundTransparency
)
Column { Column {
if (drawableIcon != null) { if (icon != null) {
Icon( Icon(
painter = drawableIcon, imageVector = icon,
contentDescription = title,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.size(24.dp),
tint = MaterialTheme.colorScheme.secondary
)
Spacer(modifier = Modifier.height(16.dp))
}
if (imageVectorIcon != null) {
Icon(
imageVector = imageVectorIcon,
contentDescription = title, contentDescription = title,
modifier = Modifier modifier = Modifier
.align(Alignment.CenterHorizontally) .align(Alignment.CenterHorizontally)
@ -106,49 +87,43 @@ fun Dialog(
text = title, text = title,
modifier = Modifier modifier = Modifier
.align( .align(
if (drawableIcon != null || imageVectorIcon != null) Alignment.CenterHorizontally if (icon != null) Alignment.CenterHorizontally
else Alignment.Start else Alignment.Start
) )
.padding(horizontal = 24.dp), .padding(horizontal = 24.dp),
textAlign = if (drawableIcon != null || imageVectorIcon != null) TextAlign.Center textAlign = if (icon != null) TextAlign.Center
else TextAlign.Start, else TextAlign.Start,
style = MaterialTheme.typography.headlineSmall, style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onSurface color = MaterialTheme.colorScheme.onSurface
) )
if (description != null) { if (description != null) {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Text( Text(
text = description, text = description,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Start,
modifier = Modifier.padding(horizontal = 24.dp) modifier = Modifier.padding(horizontal = 24.dp)
) )
} }
if (withDivider) {
Spacer(modifier = Modifier.height(12.dp)) if (withContent) {
HorizontalDivider( Spacer(modifier = Modifier.height(24.dp))
modifier = Modifier.padding(horizontal = 24.dp),
color = MaterialTheme.colorScheme.outlineVariant
)
Spacer(modifier = Modifier.height(12.dp))
} else {
Spacer(modifier = Modifier.height(8.dp))
} }
LazyColumn { LazyColumnWithScrollbar(
modifier = Modifier.fillMaxWidth()
) {
items() items()
item { item {
Column(
modifier = Modifier
.fillMaxWidth()
) {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Row( Row(
modifier = Modifier modifier = Modifier
.align(Alignment.End) .fillMaxWidth()
.padding(horizontal = 24.dp) .padding(horizontal = 24.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.End)
) { ) {
TextButton( TextButton(
onClick = { onClick = {
@ -165,8 +140,7 @@ fun Dialog(
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )
} }
if (actionText != null) {
Spacer(modifier = Modifier.width(4.dp))
TextButton( TextButton(
onClick = { onClick = {
if (disableOnClick) { if (disableOnClick) {
@ -177,7 +151,7 @@ fun Dialog(
enabled = actionEnabled == true && !actionClicked enabled = actionEnabled == true && !actionClicked
) { ) {
Text( Text(
text = actionText, text = stringResource(id = R.string.ok),
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = color =
if (actionEnabled == true) MaterialTheme.colorScheme.primary if (actionEnabled == true) MaterialTheme.colorScheme.primary
@ -189,6 +163,4 @@ fun Dialog(
} }
} }
} }
}
}
} }

View file

@ -0,0 +1,114 @@
package ua.acclorite.book_story.presentation.core.components.dialog
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextOverflow
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.ui.theme.ExpandingTransition
@Composable
fun DialogWithTextField(
initialValue: String,
lengthLimit: Int = Int.MAX_VALUE,
onDismiss: () -> Unit,
onAction: (String) -> UIText?
) {
val state = remember(initialValue) {
mutableStateOf(
TextFieldValue(
text = initialValue,
selection = TextRange(0, initialValue.length)
)
)
}
val focusRequester = remember { FocusRequester() }
val focused = remember { mutableStateOf(false) }
val showError = remember { mutableStateOf(false) }
val error = remember { mutableStateOf<UIText?>(null) }
Dialog(
title = stringResource(id = R.string.edit),
description = null,
onDismiss = { onDismiss() },
actionEnabled = true,
disableOnClick = false,
onAction = {
if (state.value.text.isBlank()) {
onDismiss()
return@Dialog
}
error.value = onAction(state.value.text)
showError.value = error.value != null
if (!showError.value) onDismiss()
},
withContent = true,
items = {
item {
OutlinedTextField(
value = state.value,
onValueChange = {
if (it.text.length < lengthLimit || it.text.length < state.value.text.length) {
state.value = it
showError.value = false
}
},
isError = showError.value,
modifier = Modifier
.padding(horizontal = 24.dp)
.fillMaxWidth()
.focusRequester(focusRequester)
.onGloballyPositioned {
if (!focused.value) {
focusRequester.requestFocus()
focused.value = true
}
},
colors = TextFieldDefaults.colors(
errorContainerColor = Color.Transparent,
focusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent
),
singleLine = true,
placeholder = {
Text(
text = initialValue,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
},
supportingText = {
ExpandingTransition(
visible = showError.value && error.value != null
) {
Text(
error.value!!.asString(),
color = MaterialTheme.colorScheme.error
)
}
}
)
}
}
)
}

View file

@ -17,9 +17,8 @@ fun HistoryDeleteWholeHistoryDialog(
val context = LocalContext.current val context = LocalContext.current
Dialog( Dialog(
title = stringResource(id = R.string.delete_history), title = stringResource(id = R.string.delete_history),
imageVectorIcon = Icons.Outlined.DeleteOutline, icon = Icons.Outlined.DeleteOutline,
description = stringResource(id = R.string.delete_history_description), description = stringResource(id = R.string.delete_history_description),
actionText = stringResource(id = R.string.delete),
actionEnabled = true, actionEnabled = true,
onDismiss = { onDismiss = {
dismissDialog(HistoryEvent.OnDismissDialog) dismissDialog(HistoryEvent.OnDismissDialog)
@ -31,6 +30,6 @@ fun HistoryDeleteWholeHistoryDialog(
) )
) )
}, },
withDivider = false withContent = false
) )
} }

View file

@ -19,12 +19,11 @@ fun LibraryDeleteDialog(
Dialog( Dialog(
title = stringResource(id = R.string.delete_books), title = stringResource(id = R.string.delete_books),
imageVectorIcon = Icons.Outlined.DeleteOutline, icon = Icons.Outlined.DeleteOutline,
description = stringResource( description = stringResource(
id = R.string.delete_books_description, id = R.string.delete_books_description,
selectedItemsCount selectedItemsCount
), ),
actionText = stringResource(id = R.string.delete),
actionEnabled = true, actionEnabled = true,
onDismiss = { onDismiss = {
dismissDialog(LibraryEvent.OnDismissDialog) dismissDialog(LibraryEvent.OnDismissDialog)
@ -36,6 +35,6 @@ fun LibraryDeleteDialog(
) )
) )
}, },
withDivider = false withContent = false
) )
} }

View file

@ -46,12 +46,11 @@ fun LibraryMoveDialog(
Dialog( Dialog(
title = stringResource(id = R.string.move_books), title = stringResource(id = R.string.move_books),
imageVectorIcon = Icons.AutoMirrored.Outlined.DriveFileMove, icon = Icons.AutoMirrored.Outlined.DriveFileMove,
description = stringResource( description = stringResource(
id = R.string.move_books_description, id = R.string.move_books_description,
selectedItemsCount selectedItemsCount
), ),
actionText = stringResource(id = R.string.move),
actionEnabled = true, actionEnabled = true,
onDismiss = { onDismiss = {
dismissDialog(LibraryEvent.OnDismissDialog) dismissDialog(LibraryEvent.OnDismissDialog)
@ -65,7 +64,7 @@ fun LibraryMoveDialog(
) )
) )
}, },
withDivider = false, withContent = true,
items = { items = {
items(moveCategories.value) { category -> items(moveCategories.value) { category ->
SelectableDialogItem( SelectableDialogItem(

View file

@ -39,15 +39,14 @@ fun CheckForUpdatesOption() {
Dialog( Dialog(
title = stringResource(id = R.string.enable_check_for_updates), title = stringResource(id = R.string.enable_check_for_updates),
description = stringResource(id = R.string.enable_check_for_updates_description), description = stringResource(id = R.string.enable_check_for_updates_description),
actionText = stringResource(id = R.string.enable), icon = Icons.Default.Security,
imageVectorIcon = Icons.Default.Security,
actionEnabled = true, actionEnabled = true,
onDismiss = { showConfirmation.value = false }, onDismiss = { showConfirmation.value = false },
onAction = { onAction = {
mainModel.onEvent(MainEvent.OnChangeCheckForUpdates(true)) mainModel.onEvent(MainEvent.OnChangeCheckForUpdates(true))
showConfirmation.value = false showConfirmation.value = false
}, },
withDivider = false withContent = false
) )
} }

View file

@ -25,6 +25,7 @@
<string name="move_book">Перемістити книгу?</string> <string name="move_book">Перемістити книгу?</string>
<string name="delete_history">Видалити історію читання?</string> <string name="delete_history">Видалити історію читання?</string>
<string name="enable_check_for_updates">Увімнкути перевірку на оновлення?</string> <string name="enable_check_for_updates">Увімнкути перевірку на оновлення?</string>
<string name="edit">Редагувати</string>
<!-- Dialog Descriptions --> <!-- Dialog Descriptions -->
<string name="storage_permission_description">Нам потрібен дозвіл на сховище, щоб просканувати Ваш Девайс на наявність книг. Без цього дозволу ви не зможете додати книгу.</string> <string name="storage_permission_description">Нам потрібен дозвіл на сховище, щоб просканувати Ваш Девайс на наявність книг. Без цього дозволу ви не зможете додати книгу.</string>

View file

@ -32,6 +32,7 @@
<string name="move_book">Move book?</string> <string name="move_book">Move book?</string>
<string name="delete_history">Delete reading history?</string> <string name="delete_history">Delete reading history?</string>
<string name="enable_check_for_updates">Enable check for updates?</string> <string name="enable_check_for_updates">Enable check for updates?</string>
<string name="edit">Edit</string>
<!-- Dialog Descriptions --> <!-- Dialog Descriptions -->
<string name="storage_permission_description"> <string name="storage_permission_description">
@ -143,6 +144,7 @@
<string name="web_search">Web search</string> <string name="web_search">Web search</string>
<string name="share">Share</string> <string name="share">Share</string>
<string name="proceed">Proceed</string> <string name="proceed">Proceed</string>
<string name="ok">OK</string>
<!-- Book --> <!-- Book -->
<string name="unknown_author">Unknown</string> <string name="unknown_author">Unknown</string>