diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/about/AboutUpdateDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/about/AboutUpdateDialog.kt index 0c46ddbe..f3e03ba5 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/about/AboutUpdateDialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/about/AboutUpdateDialog.kt @@ -22,11 +22,10 @@ fun AboutUpdateDialog( Dialog( title = stringResource(id = R.string.update_query, updateInfo?.tagName ?: ""), - imageVectorIcon = Icons.Default.Update, + icon = Icons.Default.Update, description = stringResource( id = R.string.update_app_description ), - actionText = stringResource(id = R.string.proceed), actionEnabled = true, disableOnClick = false, onDismiss = { dismissDialog(AboutEvent.OnDismissDialog) }, @@ -39,6 +38,6 @@ fun AboutUpdateDialog( ) dismissDialog(AboutEvent.OnDismissDialog) }, - withDivider = false + withContent = false ) } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/book_info/BookInfoDeleteDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/book_info/BookInfoDeleteDialog.kt index aa30e2bc..16fd1ceb 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/book_info/BookInfoDeleteDialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/book_info/BookInfoDeleteDialog.kt @@ -19,13 +19,12 @@ fun BookInfoDeleteDialog( Dialog( title = stringResource(id = R.string.delete_book), - imageVectorIcon = Icons.Outlined.DeleteOutline, + icon = Icons.Outlined.DeleteOutline, description = stringResource( id = R.string.delete_book_description ), - actionText = stringResource(id = R.string.delete), onDismiss = { dismissDialog(BookInfoEvent.OnDismissDialog) }, - withDivider = false, + withContent = false, actionEnabled = true, onAction = { actionDeleteDialog( diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/book_info/BookInfoMoveDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/book_info/BookInfoMoveDialog.kt index d4e36c15..dd6ac311 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/book_info/BookInfoMoveDialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/book_info/BookInfoMoveDialog.kt @@ -33,11 +33,10 @@ fun BookInfoMoveDialog( Dialog( title = stringResource(id = R.string.move_book), - imageVectorIcon = Icons.AutoMirrored.Outlined.DriveFileMove, + icon = Icons.AutoMirrored.Outlined.DriveFileMove, description = stringResource( id = R.string.move_book_description ), - actionText = stringResource(id = R.string.move), actionEnabled = true, onDismiss = { dismissDialog(BookInfoEvent.OnDismissDialog) }, onAction = { @@ -49,7 +48,7 @@ fun BookInfoMoveDialog( ) ) }, - withDivider = false, + withContent = true, items = { items(categories, key = { it.name }) { val category = when (it) { diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/browse/BrowseAddDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/browse/BrowseAddDialog.kt index 489e798f..f545689f 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/browse/BrowseAddDialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/browse/BrowseAddDialog.kt @@ -34,9 +34,8 @@ fun BrowseAddDialog( val context = LocalContext.current Dialog( title = stringResource(id = R.string.add_books), - imageVectorIcon = Icons.Default.AddChart, + icon = Icons.Default.AddChart, description = stringResource(id = R.string.add_books_description), - actionText = stringResource(id = R.string.add), actionEnabled = !loadingAddDialog && selectedBooksAddDialog.any { it.data is NullableBook.NotNull }, onDismiss = { dismissAddDialog(BrowseEvent.OnDismissAddDialog) }, onAction = { @@ -47,7 +46,7 @@ fun BrowseAddDialog( ) ) }, - withDivider = true, + withContent = true, items = { if (loadingAddDialog) { item { diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/browse/BrowsePermissionDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/browse/BrowsePermissionDialog.kt index 2306b93d..a8d92ded 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/browse/BrowsePermissionDialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/browse/BrowsePermissionDialog.kt @@ -22,9 +22,8 @@ fun BrowsePermissionDialog( Dialog( title = stringResource(id = R.string.storage_permission), - imageVectorIcon = Icons.Outlined.SdStorage, + icon = Icons.Outlined.SdStorage, description = stringResource(id = R.string.storage_permission_description), - actionText = stringResource(id = R.string.grant), actionEnabled = true, disableOnClick = false, onDismiss = { @@ -42,6 +41,6 @@ fun BrowsePermissionDialog( ) ) }, - withDivider = false + withContent = false ) } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/core/components/dialog/Dialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/core/components/dialog/Dialog.kt index 4a58eb5c..40c53889 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/core/components/dialog/Dialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/core/components/dialog/Dialog.kt @@ -1,6 +1,7 @@ package ua.acclorite.book_story.presentation.core.components.dialog import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row 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.size 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.material3.BasicAlertDialog import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -28,7 +26,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalView 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.DialogWindowProvider import ua.acclorite.book_story.R +import ua.acclorite.book_story.presentation.core.components.common.LazyColumnWithScrollbar @OptIn(ExperimentalMaterial3Api::class) @Composable fun Dialog( modifier: Modifier = Modifier, - drawableIcon: Painter? = null, - imageVectorIcon: ImageVector? = null, - backgroundTransparency: Float = 0.5f, + icon: ImageVector? = null, title: String, description: String?, - actionText: String?, disableOnClick: Boolean = true, actionEnabled: Boolean?, onDismiss: () -> Unit, onAction: () -> Unit, - withDivider: Boolean, + withContent: Boolean, items: (LazyListScope.() -> Unit) = {} ) { var actionClicked by remember { mutableStateOf(false) } @@ -74,25 +69,11 @@ fun Dialog( dismissOnClickOutside = !actionClicked ) ) { - (LocalView.current.parent as DialogWindowProvider).window.setDimAmount( - backgroundTransparency - ) + (LocalView.current.parent as DialogWindowProvider).window.setDimAmount(0.5f) Column { - if (drawableIcon != null) { + if (icon != null) { Icon( - painter = drawableIcon, - 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, + imageVector = icon, contentDescription = title, modifier = Modifier .align(Alignment.CenterHorizontally) @@ -106,85 +87,76 @@ fun Dialog( text = title, modifier = Modifier .align( - if (drawableIcon != null || imageVectorIcon != null) Alignment.CenterHorizontally + if (icon != null) Alignment.CenterHorizontally else Alignment.Start ) .padding(horizontal = 24.dp), - textAlign = if (drawableIcon != null || imageVectorIcon != null) TextAlign.Center + textAlign = if (icon != null) TextAlign.Center else TextAlign.Start, style = MaterialTheme.typography.headlineSmall, color = MaterialTheme.colorScheme.onSurface ) + if (description != null) { Spacer(modifier = Modifier.height(16.dp)) Text( text = description, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, - textAlign = TextAlign.Start, modifier = Modifier.padding(horizontal = 24.dp) ) } - if (withDivider) { - Spacer(modifier = Modifier.height(12.dp)) - HorizontalDivider( - modifier = Modifier.padding(horizontal = 24.dp), - color = MaterialTheme.colorScheme.outlineVariant - ) - Spacer(modifier = Modifier.height(12.dp)) - } else { - Spacer(modifier = Modifier.height(8.dp)) + + if (withContent) { + Spacer(modifier = Modifier.height(24.dp)) } - LazyColumn { + LazyColumnWithScrollbar( + modifier = Modifier.fillMaxWidth() + ) { items() item { - Column( + Spacer(modifier = Modifier.height(16.dp)) + + Row( modifier = Modifier .fillMaxWidth() + .padding(horizontal = 24.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.End) ) { - Spacer(modifier = Modifier.height(16.dp)) - Row( - modifier = Modifier - .align(Alignment.End) - .padding(horizontal = 24.dp) - ) { - TextButton( - onClick = { - if (disableOnClick) { - actionClicked = true - } - onDismiss() - }, - enabled = !actionClicked - ) { - Text( - text = stringResource(id = R.string.cancel), - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.primary - ) - } - if (actionText != null) { - Spacer(modifier = Modifier.width(4.dp)) - TextButton( - onClick = { - if (disableOnClick) { - actionClicked = true - } - onAction() - }, - enabled = actionEnabled == true && !actionClicked - ) { - Text( - text = actionText, - style = MaterialTheme.typography.labelLarge, - color = - if (actionEnabled == true) MaterialTheme.colorScheme.primary - else MaterialTheme.colorScheme.primary.copy(0.5f) - ) + TextButton( + onClick = { + if (disableOnClick) { + actionClicked = true } - } + onDismiss() + }, + enabled = !actionClicked + ) { + Text( + text = stringResource(id = R.string.cancel), + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.primary + ) + } + + TextButton( + onClick = { + if (disableOnClick) { + actionClicked = true + } + onAction() + }, + enabled = actionEnabled == true && !actionClicked + ) { + Text( + text = stringResource(id = R.string.ok), + style = MaterialTheme.typography.labelLarge, + color = + if (actionEnabled == true) MaterialTheme.colorScheme.primary + else MaterialTheme.colorScheme.primary.copy(0.5f) + ) } } } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/core/components/dialog/DialogWithTextField.kt b/app/src/main/java/ua/acclorite/book_story/presentation/core/components/dialog/DialogWithTextField.kt new file mode 100644 index 00000000..cd853bf7 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/core/components/dialog/DialogWithTextField.kt @@ -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(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 + ) + } + + } + ) + } + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/history/HistoryDeleteWholeHistoryDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/history/HistoryDeleteWholeHistoryDialog.kt index 40f272d1..f90c6fae 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/history/HistoryDeleteWholeHistoryDialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/history/HistoryDeleteWholeHistoryDialog.kt @@ -17,9 +17,8 @@ fun HistoryDeleteWholeHistoryDialog( val context = LocalContext.current Dialog( title = stringResource(id = R.string.delete_history), - imageVectorIcon = Icons.Outlined.DeleteOutline, + icon = Icons.Outlined.DeleteOutline, description = stringResource(id = R.string.delete_history_description), - actionText = stringResource(id = R.string.delete), actionEnabled = true, onDismiss = { dismissDialog(HistoryEvent.OnDismissDialog) @@ -31,6 +30,6 @@ fun HistoryDeleteWholeHistoryDialog( ) ) }, - withDivider = false + withContent = false ) } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryDeleteDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryDeleteDialog.kt index b67852ad..78d9a83f 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryDeleteDialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryDeleteDialog.kt @@ -19,12 +19,11 @@ fun LibraryDeleteDialog( Dialog( title = stringResource(id = R.string.delete_books), - imageVectorIcon = Icons.Outlined.DeleteOutline, + icon = Icons.Outlined.DeleteOutline, description = stringResource( id = R.string.delete_books_description, selectedItemsCount ), - actionText = stringResource(id = R.string.delete), actionEnabled = true, onDismiss = { dismissDialog(LibraryEvent.OnDismissDialog) @@ -36,6 +35,6 @@ fun LibraryDeleteDialog( ) ) }, - withDivider = false + withContent = false ) } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryMoveDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryMoveDialog.kt index 7e503021..cc75e7d7 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryMoveDialog.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryMoveDialog.kt @@ -46,12 +46,11 @@ fun LibraryMoveDialog( Dialog( title = stringResource(id = R.string.move_books), - imageVectorIcon = Icons.AutoMirrored.Outlined.DriveFileMove, + icon = Icons.AutoMirrored.Outlined.DriveFileMove, description = stringResource( id = R.string.move_books_description, selectedItemsCount ), - actionText = stringResource(id = R.string.move), actionEnabled = true, onDismiss = { dismissDialog(LibraryEvent.OnDismissDialog) @@ -65,7 +64,7 @@ fun LibraryMoveDialog( ) ) }, - withDivider = false, + withContent = true, items = { items(moveCategories.value) { category -> SelectableDialogItem( diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/settings/general/components/CheckForUpdatesOption.kt b/app/src/main/java/ua/acclorite/book_story/presentation/settings/general/components/CheckForUpdatesOption.kt index 67d41234..aea556b7 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/settings/general/components/CheckForUpdatesOption.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/settings/general/components/CheckForUpdatesOption.kt @@ -39,15 +39,14 @@ fun CheckForUpdatesOption() { Dialog( title = stringResource(id = R.string.enable_check_for_updates), description = stringResource(id = R.string.enable_check_for_updates_description), - actionText = stringResource(id = R.string.enable), - imageVectorIcon = Icons.Default.Security, + icon = Icons.Default.Security, actionEnabled = true, onDismiss = { showConfirmation.value = false }, onAction = { mainModel.onEvent(MainEvent.OnChangeCheckForUpdates(true)) showConfirmation.value = false }, - withDivider = false + withContent = false ) } diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 37b7d483..5d3bcae7 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -25,6 +25,7 @@ Перемістити книгу? Видалити історію читання? Увімнкути перевірку на оновлення? + Редагувати Нам потрібен дозвіл на сховище, щоб просканувати Ваш Девайс на наявність книг. Без цього дозволу ви не зможете додати книгу. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7dccf77d..a158be80 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,6 +32,7 @@ Move book? Delete reading history? Enable check for updates? + Edit @@ -143,6 +144,7 @@ Web search Share Proceed + OK Unknown