🚀 BookInfo UI update
* Updated UI of BookInfo screen * Dialogs to update fields (title, author and description) * Simplified updating mechanism
This commit is contained in:
parent
f232cd3688
commit
cf4cb62061
44 changed files with 968 additions and 1253 deletions
|
|
@ -0,0 +1,34 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.domain.ui.UIText
|
||||
import ua.acclorite.book_story.presentation.core.components.dialog.DialogWithTextField
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoAuthorDialog(
|
||||
book: Book,
|
||||
actionAuthorDialog: (BookInfoEvent.OnActionAuthorDialog) -> Unit,
|
||||
dismissDialog: (BookInfoEvent.OnDismissDialog) -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
DialogWithTextField(
|
||||
initialValue = book.author.getAsString() ?: "",
|
||||
lengthLimit = 100,
|
||||
onDismiss = {
|
||||
dismissDialog(BookInfoEvent.OnDismissDialog)
|
||||
},
|
||||
onAction = {
|
||||
actionAuthorDialog(
|
||||
BookInfoEvent.OnActionAuthorDialog(
|
||||
author = if (it.isBlank()) UIText.StringResource(R.string.unknown_author)
|
||||
else UIText.StringValue(it.trim().replace("\n", "")),
|
||||
context = context
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -2,40 +2,12 @@ package ua.acclorite.book_story.presentation.book_info
|
|||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoBackHandler(
|
||||
editTitle: Boolean,
|
||||
editAuthor: Boolean,
|
||||
editDescription: Boolean,
|
||||
editTitleMode: (BookInfoEvent.OnEditTitleMode) -> Unit,
|
||||
editAuthorMode: (BookInfoEvent.OnEditAuthorMode) -> Unit,
|
||||
editDescriptionMode: (BookInfoEvent.OnEditDescriptionMode) -> Unit,
|
||||
navigateBack: () -> Unit
|
||||
) {
|
||||
BackHandler {
|
||||
var exitedEditMode = false
|
||||
|
||||
if (editTitle) {
|
||||
editTitleMode(BookInfoEvent.OnEditTitleMode(false))
|
||||
exitedEditMode = true
|
||||
}
|
||||
|
||||
if (editAuthor) {
|
||||
editAuthorMode(BookInfoEvent.OnEditAuthorMode(false))
|
||||
exitedEditMode = true
|
||||
}
|
||||
|
||||
if (editDescription) {
|
||||
editDescriptionMode(BookInfoEvent.OnEditDescriptionMode(false))
|
||||
exitedEditMode = true
|
||||
}
|
||||
|
||||
if (exitedEditMode) {
|
||||
return@BackHandler
|
||||
}
|
||||
|
||||
navigateBack()
|
||||
}
|
||||
}
|
||||
|
|
@ -15,10 +15,6 @@ fun BookInfoBottomSheet(
|
|||
resetCover: (BookInfoEvent.OnResetCover) -> Unit,
|
||||
deleteCover: (BookInfoEvent.OnDeleteCover) -> Unit,
|
||||
checkCoverReset: (BookInfoEvent.OnCheckCoverReset) -> Unit,
|
||||
copyToClipboard: (BookInfoEvent.OnCopyToClipboard) -> Unit,
|
||||
showDetailsBottomSheet: (BookInfoEvent.OnShowDetailsBottomSheet) -> Unit,
|
||||
showMoveDialog: (BookInfoEvent.OnShowMoveDialog) -> Unit,
|
||||
showDeleteDialog: (BookInfoEvent.OnShowDeleteDialog) -> Unit,
|
||||
dismissBottomSheet: (BookInfoEvent.OnDismissBottomSheet) -> Unit
|
||||
) {
|
||||
when (bottomSheet) {
|
||||
|
|
@ -34,19 +30,9 @@ fun BookInfoBottomSheet(
|
|||
)
|
||||
}
|
||||
|
||||
BookInfoScreen.MORE_BOTTOM_SHEET -> {
|
||||
BookInfoMoreBottomSheet(
|
||||
showDetailsBottomSheet = showDetailsBottomSheet,
|
||||
showDeleteDialog = showDeleteDialog,
|
||||
showMoveDialog = showMoveDialog,
|
||||
dismissBottomSheet = dismissBottomSheet
|
||||
)
|
||||
}
|
||||
|
||||
BookInfoScreen.DETAILS_BOTTOM_SHEET -> {
|
||||
BookInfoDetailsBottomSheet(
|
||||
book = book,
|
||||
copyToClipboard = copyToClipboard,
|
||||
dismissBottomSheet = dismissBottomSheet
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ fun BookInfoChangeCoverBottomSheet(
|
|||
dismissBottomSheet: (BookInfoEvent.OnDismissBottomSheet) -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val photoPicker = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.PickVisualMedia(),
|
||||
onResult = { uri ->
|
||||
|
|
|
|||
|
|
@ -16,24 +16,14 @@ fun BookInfoContent(
|
|||
dialog: Dialog?,
|
||||
listState: LazyListState,
|
||||
canResetCover: Boolean,
|
||||
editTitle: Boolean,
|
||||
titleValue: String,
|
||||
editAuthor: Boolean,
|
||||
authorValue: String,
|
||||
editDescription: Boolean,
|
||||
descriptionValue: String,
|
||||
editTitleMode: (BookInfoEvent.OnEditTitleMode) -> Unit,
|
||||
editTitleValueChange: (BookInfoEvent.OnEditTitleValueChange) -> Unit,
|
||||
editTitleRequestFocus: (BookInfoEvent.OnEditTitleRequestFocus) -> Unit,
|
||||
editAuthorMode: (BookInfoEvent.OnEditAuthorMode) -> Unit,
|
||||
editAuthorValueChange: (BookInfoEvent.OnEditAuthorValueChange) -> Unit,
|
||||
editAuthorRequestFocus: (BookInfoEvent.OnEditAuthorRequestFocus) -> Unit,
|
||||
editDescriptionMode: (BookInfoEvent.OnEditDescriptionMode) -> Unit,
|
||||
editDescriptionValueChange: (BookInfoEvent.OnEditDescriptionValueChange) -> Unit,
|
||||
editDescriptionRequestFocus: (BookInfoEvent.OnEditDescriptionRequestFocus) -> Unit,
|
||||
showChangeCoverBottomSheet: (BookInfoEvent.OnShowChangeCoverBottomSheet) -> Unit,
|
||||
showDetailsBottomSheet: (BookInfoEvent.OnShowDetailsBottomSheet) -> Unit,
|
||||
showMoreBottomSheet: (BookInfoEvent.OnShowMoreBottomSheet) -> Unit,
|
||||
showTitleDialog: (BookInfoEvent.OnShowTitleDialog) -> Unit,
|
||||
actionTitleDialog: (BookInfoEvent.OnActionTitleDialog) -> Unit,
|
||||
showAuthorDialog: (BookInfoEvent.OnShowAuthorDialog) -> Unit,
|
||||
actionAuthorDialog: (BookInfoEvent.OnActionAuthorDialog) -> Unit,
|
||||
showDescriptionDialog: (BookInfoEvent.OnShowDescriptionDialog) -> Unit,
|
||||
actionDescriptionDialog: (BookInfoEvent.OnActionDescriptionDialog) -> Unit,
|
||||
showMoveDialog: (BookInfoEvent.OnShowMoveDialog) -> Unit,
|
||||
showDeleteDialog: (BookInfoEvent.OnShowDeleteDialog) -> Unit,
|
||||
actionDeleteDialog: (BookInfoEvent.OnActionDeleteDialog) -> Unit,
|
||||
|
|
@ -44,8 +34,6 @@ fun BookInfoContent(
|
|||
checkCoverReset: (BookInfoEvent.OnCheckCoverReset) -> Unit,
|
||||
dismissDialog: (BookInfoEvent.OnDismissDialog) -> Unit,
|
||||
dismissBottomSheet: (BookInfoEvent.OnDismissBottomSheet) -> Unit,
|
||||
updateData: (BookInfoEvent.OnUpdateData) -> Unit,
|
||||
copyToClipboard: (BookInfoEvent.OnCopyToClipboard) -> Unit,
|
||||
navigateToReader: () -> Unit,
|
||||
navigateToLibrary: () -> Unit,
|
||||
navigateBack: () -> Unit
|
||||
|
|
@ -53,6 +41,9 @@ fun BookInfoContent(
|
|||
BookInfoDialog(
|
||||
dialog = dialog,
|
||||
book = book,
|
||||
actionTitleDialog = actionTitleDialog,
|
||||
actionAuthorDialog = actionAuthorDialog,
|
||||
actionDescriptionDialog = actionDescriptionDialog,
|
||||
actionDeleteDialog = actionDeleteDialog,
|
||||
actionMoveDialog = actionMoveDialog,
|
||||
dismissDialog = dismissDialog,
|
||||
|
|
@ -68,45 +59,24 @@ fun BookInfoContent(
|
|||
resetCover = resetCover,
|
||||
deleteCover = deleteCover,
|
||||
checkCoverReset = checkCoverReset,
|
||||
copyToClipboard = copyToClipboard,
|
||||
showDetailsBottomSheet = showDetailsBottomSheet,
|
||||
showMoveDialog = showMoveDialog,
|
||||
showDeleteDialog = showDeleteDialog,
|
||||
dismissBottomSheet = dismissBottomSheet
|
||||
)
|
||||
|
||||
BookInfoScaffold(
|
||||
book = book,
|
||||
listState = listState,
|
||||
editTitle = editTitle,
|
||||
titleValue = titleValue,
|
||||
editAuthor = editAuthor,
|
||||
authorValue = authorValue,
|
||||
editDescription = editDescription,
|
||||
descriptionValue = descriptionValue,
|
||||
editTitleMode = editTitleMode,
|
||||
editTitleValueChange = editTitleValueChange,
|
||||
editTitleRequestFocus = editTitleRequestFocus,
|
||||
editAuthorMode = editAuthorMode,
|
||||
editAuthorValueChange = editAuthorValueChange,
|
||||
editAuthorRequestFocus = editAuthorRequestFocus,
|
||||
editDescriptionMode = editDescriptionMode,
|
||||
editDescriptionValueChange = editDescriptionValueChange,
|
||||
editDescriptionRequestFocus = editDescriptionRequestFocus,
|
||||
showTitleDialog = showTitleDialog,
|
||||
showAuthorDialog = showAuthorDialog,
|
||||
showDescriptionDialog = showDescriptionDialog,
|
||||
showChangeCoverBottomSheet = showChangeCoverBottomSheet,
|
||||
showMoreBottomSheet = showMoreBottomSheet,
|
||||
updateData = updateData,
|
||||
showDetailsBottomSheet = showDetailsBottomSheet,
|
||||
showMoveDialog = showMoveDialog,
|
||||
showDeleteDialog = showDeleteDialog,
|
||||
navigateToReader = navigateToReader,
|
||||
navigateBack = navigateBack
|
||||
)
|
||||
|
||||
BookInfoBackHandler(
|
||||
editTitle = editTitle,
|
||||
editAuthor = editAuthor,
|
||||
editDescription = editDescription,
|
||||
editTitleMode = editTitleMode,
|
||||
editAuthorMode = editAuthorMode,
|
||||
editDescriptionMode = editDescriptionMode,
|
||||
navigateBack = navigateBack
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.components.dialog.DialogWithTextField
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoDescriptionDialog(
|
||||
book: Book,
|
||||
actionDescriptionDialog: (BookInfoEvent.OnActionDescriptionDialog) -> Unit,
|
||||
dismissDialog: (BookInfoEvent.OnDismissDialog) -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
DialogWithTextField(
|
||||
initialValue = book.description ?: "",
|
||||
lengthLimit = 5000,
|
||||
onDismiss = {
|
||||
dismissDialog(BookInfoEvent.OnDismissDialog)
|
||||
},
|
||||
onAction = {
|
||||
actionDescriptionDialog(
|
||||
BookInfoEvent.OnActionDescriptionDialog(
|
||||
description = if (it.isBlank()) null
|
||||
else it.trim().replace("\n", ""),
|
||||
context = context
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -1,17 +1,20 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.components.common.LazyColumnWithScrollbar
|
||||
import ua.acclorite.book_story.presentation.core.components.modal_bottom_sheet.ModalBottomSheet
|
||||
import ua.acclorite.book_story.presentation.settings.components.SettingsSubcategoryTitle
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
|
|
@ -21,40 +24,29 @@ import java.util.Locale
|
|||
@Composable
|
||||
fun BookInfoDetailsBottomSheet(
|
||||
book: Book,
|
||||
copyToClipboard: (BookInfoEvent.OnCopyToClipboard) -> Unit,
|
||||
dismissBottomSheet: (BookInfoEvent.OnDismissBottomSheet) -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val pattern = remember { SimpleDateFormat("HH:mm dd MMM yyyy", Locale.getDefault()) }
|
||||
val lastOpened = remember(book.lastOpened) { pattern.format(Date(book.lastOpened ?: 0)) }
|
||||
|
||||
val pattern = remember {
|
||||
SimpleDateFormat("HH:mm dd MMM yyyy", Locale.getDefault())
|
||||
}
|
||||
val lastOpened = remember {
|
||||
pattern.format(Date(book.lastOpened ?: 0))
|
||||
}
|
||||
|
||||
val sizeBytes = remember {
|
||||
val fileSize = remember(book.filePath) {
|
||||
val file = File(book.filePath)
|
||||
if (file.exists()) {
|
||||
file.length()
|
||||
} else 0
|
||||
val sizeBytes = file.length()
|
||||
val sizeKB = sizeBytes / 1024f
|
||||
val sizeMB = sizeKB / 1024f
|
||||
when {
|
||||
sizeMB >= 1f -> "%.2f MB".format(sizeMB)
|
||||
sizeKB > 0f -> "%.2f KB".format(sizeKB)
|
||||
else -> ""
|
||||
}
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
val fileSizeKB = remember {
|
||||
if (sizeBytes > 0) sizeBytes.toDouble() / 1024.0 else 0.0
|
||||
}
|
||||
val fileSizeMB = remember {
|
||||
if (sizeBytes > 0) fileSizeKB / 1024.0 else 0.0
|
||||
}
|
||||
|
||||
val fileSize = remember {
|
||||
if (fileSizeMB >= 1.0) "%.2f MB".format(fileSizeMB)
|
||||
else if (fileSizeMB > 0.0) "%.2f KB".format(fileSizeKB)
|
||||
else ""
|
||||
}
|
||||
|
||||
val fileName = remember {
|
||||
book.filePath.substringAfterLast(File.separatorChar)
|
||||
val fileExists = remember(book.filePath) {
|
||||
File(book.filePath).exists()
|
||||
}
|
||||
|
||||
ModalBottomSheet(
|
||||
|
|
@ -69,64 +61,39 @@ fun BookInfoDetailsBottomSheet(
|
|||
contentPadding = PaddingValues(bottom = 8.dp)
|
||||
) {
|
||||
item {
|
||||
BookInfoDetailsBottomSheetItem(
|
||||
title = stringResource(id = R.string.file_name),
|
||||
description = fileName
|
||||
) {
|
||||
copyToClipboard(
|
||||
BookInfoEvent.OnCopyToClipboard(
|
||||
text = fileName,
|
||||
context = context
|
||||
)
|
||||
)
|
||||
}
|
||||
SettingsSubcategoryTitle(
|
||||
title = stringResource(id = R.string.file_details),
|
||||
padding = 16.dp,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
}
|
||||
|
||||
item {
|
||||
BookInfoDetailsBottomSheetItem(
|
||||
title = stringResource(id = R.string.file_path),
|
||||
description = book.filePath
|
||||
) {
|
||||
copyToClipboard(
|
||||
BookInfoEvent.OnCopyToClipboard(
|
||||
text = book.filePath,
|
||||
context = context
|
||||
)
|
||||
)
|
||||
}
|
||||
label = stringResource(id = R.string.file_path),
|
||||
text = book.filePath,
|
||||
editable = false,
|
||||
showError = !fileExists,
|
||||
errorMessage = stringResource(id = R.string.error_no_file)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
BookInfoDetailsBottomSheetItem(
|
||||
title = stringResource(id = R.string.file_last_opened),
|
||||
description = if (book.lastOpened != null) lastOpened
|
||||
else stringResource(id = R.string.never)
|
||||
) {
|
||||
if (book.lastOpened != null) {
|
||||
copyToClipboard(
|
||||
BookInfoEvent.OnCopyToClipboard(
|
||||
text = lastOpened,
|
||||
context = context
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
label = stringResource(id = R.string.file_last_opened),
|
||||
text = if (book.lastOpened != null) lastOpened
|
||||
else stringResource(id = R.string.never),
|
||||
editable = false
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
BookInfoDetailsBottomSheetItem(
|
||||
title = stringResource(id = R.string.file_size),
|
||||
description = fileSize.ifBlank { stringResource(id = R.string.unknown) }
|
||||
) {
|
||||
if (fileSize.isNotBlank()) {
|
||||
copyToClipboard(
|
||||
BookInfoEvent.OnCopyToClipboard(
|
||||
text = fileSize,
|
||||
context = context
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
label = stringResource(id = R.string.file_size),
|
||||
text = fileSize.ifBlank { stringResource(id = R.string.unknown) },
|
||||
editable = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,70 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.focusable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.EditNote
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.core.components.common.IconButton
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BookInfoDetailsBottomSheetItem(
|
||||
title: String,
|
||||
description: String,
|
||||
onClick: () -> Unit
|
||||
label: String,
|
||||
text: String,
|
||||
editable: Boolean,
|
||||
showError: Boolean = false,
|
||||
errorMessage: String? = null,
|
||||
onEdit: () -> Unit = {}
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
onClick()
|
||||
}
|
||||
)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.Start
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
title,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
description,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.focusable(false),
|
||||
value = text,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
isError = showError,
|
||||
supportingText = if (!showError || errorMessage.isNullOrBlank()) null else {
|
||||
{
|
||||
Text(
|
||||
text = errorMessage,
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
},
|
||||
label = {
|
||||
Text(label)
|
||||
}
|
||||
)
|
||||
|
||||
if (editable) {
|
||||
IconButton(
|
||||
icon = Icons.Default.EditNote,
|
||||
contentDescription = R.string.edit_content_desc,
|
||||
disableOnClick = false,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(24.dp)
|
||||
) {
|
||||
onEdit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,9 @@ import ua.acclorite.book_story.ui.book_info.BookInfoScreen
|
|||
fun BookInfoDialog(
|
||||
dialog: Dialog?,
|
||||
book: Book,
|
||||
actionTitleDialog: (BookInfoEvent.OnActionTitleDialog) -> Unit,
|
||||
actionAuthorDialog: (BookInfoEvent.OnActionAuthorDialog) -> Unit,
|
||||
actionDescriptionDialog: (BookInfoEvent.OnActionDescriptionDialog) -> Unit,
|
||||
actionDeleteDialog: (BookInfoEvent.OnActionDeleteDialog) -> Unit,
|
||||
actionMoveDialog: (BookInfoEvent.OnActionMoveDialog) -> Unit,
|
||||
dismissDialog: (BookInfoEvent.OnDismissDialog) -> Unit,
|
||||
|
|
@ -33,5 +36,29 @@ fun BookInfoDialog(
|
|||
navigateToLibrary = navigateToLibrary
|
||||
)
|
||||
}
|
||||
|
||||
BookInfoScreen.TITLE_DIALOG -> {
|
||||
BookInfoTitleDialog(
|
||||
book = book,
|
||||
actionTitleDialog = actionTitleDialog,
|
||||
dismissDialog = dismissDialog
|
||||
)
|
||||
}
|
||||
|
||||
BookInfoScreen.AUTHOR_DIALOG -> {
|
||||
BookInfoAuthorDialog(
|
||||
book = book,
|
||||
actionAuthorDialog = actionAuthorDialog,
|
||||
dismissDialog = dismissDialog
|
||||
)
|
||||
}
|
||||
|
||||
BookInfoScreen.DESCRIPTION_DIALOG -> {
|
||||
BookInfoDescriptionDialog(
|
||||
book = book,
|
||||
actionDescriptionDialog = actionDescriptionDialog,
|
||||
dismissDialog = dismissDialog
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.animation.expandHorizontally
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkHorizontally
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.components.common.AnimatedVisibility
|
||||
|
||||
@Composable
|
||||
fun BoxScope.BookInfoFloatingActionButton(
|
||||
book: Book,
|
||||
listState: LazyListState,
|
||||
navigateToReader: () -> Unit
|
||||
) {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
navigateToReader()
|
||||
},
|
||||
shape = MaterialTheme.shapes.large,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomEnd)
|
||||
.padding(16.dp),
|
||||
elevation = FloatingActionButtonDefaults.elevation(),
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
content = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Spacer(modifier = Modifier.width(13.dp))
|
||||
Icon(
|
||||
imageVector = Icons.Filled.PlayArrow,
|
||||
contentDescription = stringResource(id = R.string.continue_reading_content_desc),
|
||||
Modifier.size(24.dp)
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = !listState.canScrollBackward,
|
||||
enter = fadeIn() + expandHorizontally(),
|
||||
exit = fadeOut() + shrinkHorizontally()
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(
|
||||
if (book.progress == 0f) R.string.start
|
||||
else R.string.continue_read
|
||||
),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
maxLines = 1,
|
||||
modifier = Modifier.padding(start = 8.dp)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -7,14 +7,14 @@ import androidx.compose.foundation.layout.Spacer
|
|||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.components.common.LazyColumnWithScrollbar
|
||||
import ua.acclorite.book_story.presentation.core.constants.Constants
|
||||
import ua.acclorite.book_story.presentation.core.constants.providePrimaryScrollbar
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
|
|
@ -22,39 +22,25 @@ fun BookInfoLayout(
|
|||
book: Book,
|
||||
listState: LazyListState,
|
||||
paddingValues: PaddingValues,
|
||||
editTitle: Boolean,
|
||||
titleValue: String,
|
||||
editAuthor: Boolean,
|
||||
authorValue: String,
|
||||
editDescription: Boolean,
|
||||
descriptionValue: String,
|
||||
editTitleMode: (BookInfoEvent.OnEditTitleMode) -> Unit,
|
||||
editTitleValueChange: (BookInfoEvent.OnEditTitleValueChange) -> Unit,
|
||||
editTitleRequestFocus: (BookInfoEvent.OnEditTitleRequestFocus) -> Unit,
|
||||
editAuthorMode: (BookInfoEvent.OnEditAuthorMode) -> Unit,
|
||||
editAuthorValueChange: (BookInfoEvent.OnEditAuthorValueChange) -> Unit,
|
||||
editAuthorRequestFocus: (BookInfoEvent.OnEditAuthorRequestFocus) -> Unit,
|
||||
editDescriptionMode: (BookInfoEvent.OnEditDescriptionMode) -> Unit,
|
||||
editDescriptionValueChange: (BookInfoEvent.OnEditDescriptionValueChange) -> Unit,
|
||||
editDescriptionRequestFocus: (BookInfoEvent.OnEditDescriptionRequestFocus) -> Unit,
|
||||
showChangeCoverBottomSheet: (BookInfoEvent.OnShowChangeCoverBottomSheet) -> Unit
|
||||
showChangeCoverBottomSheet: (BookInfoEvent.OnShowChangeCoverBottomSheet) -> Unit,
|
||||
showTitleDialog: (BookInfoEvent.OnShowTitleDialog) -> Unit,
|
||||
showAuthorDialog: (BookInfoEvent.OnShowAuthorDialog) -> Unit,
|
||||
showDescriptionDialog: (BookInfoEvent.OnShowDescriptionDialog) -> Unit,
|
||||
showMoveDialog: (BookInfoEvent.OnShowMoveDialog) -> Unit,
|
||||
showDeleteDialog: (BookInfoEvent.OnShowDeleteDialog) -> Unit,
|
||||
navigateToReader: () -> Unit
|
||||
) {
|
||||
val backgroundCoverImageHeight = remember {
|
||||
derivedStateOf {
|
||||
paddingValues.calculateTopPadding() + 12.dp + 195.dp
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
Modifier
|
||||
.fillMaxSize(),
|
||||
state = listState
|
||||
LazyColumnWithScrollbar(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = listState,
|
||||
scrollbarSettings = Constants.providePrimaryScrollbar(false),
|
||||
contentPadding = PaddingValues(bottom = 18.dp)
|
||||
) {
|
||||
item {
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
if (book.coverImage != null) {
|
||||
BookInfoLayoutBackground(
|
||||
height = backgroundCoverImageHeight.value,
|
||||
height = paddingValues.calculateTopPadding() + 232.dp,
|
||||
image = book.coverImage
|
||||
)
|
||||
}
|
||||
|
|
@ -63,16 +49,8 @@ fun BookInfoLayout(
|
|||
Spacer(modifier = Modifier.height(paddingValues.calculateTopPadding() + 12.dp))
|
||||
BookInfoLayoutInfo(
|
||||
book = book,
|
||||
editTitle = editTitle,
|
||||
titleValue = titleValue,
|
||||
editAuthor = editAuthor,
|
||||
authorValue = authorValue,
|
||||
editTitleMode = editTitleMode,
|
||||
editTitleValueChange = editTitleValueChange,
|
||||
editTitleRequestFocus = editTitleRequestFocus,
|
||||
editAuthorMode = editAuthorMode,
|
||||
editAuthorValueChange = editAuthorValueChange,
|
||||
editAuthorRequestFocus = editAuthorRequestFocus,
|
||||
showTitleDialog = showTitleDialog,
|
||||
showAuthorDialog = showAuthorDialog,
|
||||
showChangeCoverBottomSheet = showChangeCoverBottomSheet
|
||||
)
|
||||
}
|
||||
|
|
@ -80,19 +58,26 @@ fun BookInfoLayout(
|
|||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BookInfoLayoutStatistic(book = book)
|
||||
Spacer(Modifier.height(18.dp))
|
||||
BookInfoLayoutActions(
|
||||
showMoveDialog = showMoveDialog,
|
||||
showDeleteDialog = showDeleteDialog
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(Modifier.height(18.dp))
|
||||
BookInfoLayoutDescription(
|
||||
book = book,
|
||||
editDescription = editDescription,
|
||||
descriptionValue = descriptionValue,
|
||||
editDescriptionMode = editDescriptionMode,
|
||||
editDescriptionValueChange = editDescriptionValueChange,
|
||||
editDescriptionRequestFocus = editDescriptionRequestFocus
|
||||
showDescriptionDialog = showDescriptionDialog
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(Modifier.height(18.dp))
|
||||
BookInfoLayoutButton(
|
||||
book = book,
|
||||
navigateToReader = navigateToReader
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.MoveUp
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoLayoutActions(
|
||||
showMoveDialog: (BookInfoEvent.OnShowMoveDialog) -> Unit,
|
||||
showDeleteDialog: (BookInfoEvent.OnShowDeleteDialog) -> Unit
|
||||
) {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 18.dp)
|
||||
.clip(MaterialTheme.shapes.large),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
BookInfoLayoutActionsItem(
|
||||
modifier = Modifier.weight(1f),
|
||||
alignmentStart = true,
|
||||
title = stringResource(id = R.string.move),
|
||||
icon = Icons.Default.MoveUp,
|
||||
onClick = {
|
||||
showMoveDialog(BookInfoEvent.OnShowMoveDialog)
|
||||
}
|
||||
)
|
||||
|
||||
BookInfoLayoutActionsItem(
|
||||
modifier = Modifier.weight(1f),
|
||||
alignmentStart = false,
|
||||
title = stringResource(id = R.string.delete),
|
||||
icon = Icons.Default.Delete,
|
||||
onClick = {
|
||||
showDeleteDialog(BookInfoEvent.OnShowDeleteDialog)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun BookInfoLayoutActionsItem(
|
||||
modifier: Modifier = Modifier,
|
||||
alignmentStart: Boolean,
|
||||
title: String,
|
||||
icon: ImageVector,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val shape = remember(alignmentStart) {
|
||||
when (alignmentStart) {
|
||||
true -> RoundedCornerShape(
|
||||
topEnd = 4.dp,
|
||||
bottomEnd = 4.dp
|
||||
)
|
||||
|
||||
false -> RoundedCornerShape(
|
||||
topStart = 4.dp,
|
||||
bottomStart = 4.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier
|
||||
.clip(shape)
|
||||
.background(MaterialTheme.colorScheme.surfaceContainerLow)
|
||||
.clickable { onClick() }
|
||||
.padding(vertical = 18.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.util.calculateProgress
|
||||
|
||||
@Composable
|
||||
fun BookInfoLayoutButton(
|
||||
book: Book,
|
||||
navigateToReader: () -> Unit
|
||||
) {
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 18.dp),
|
||||
shape = CircleShape,
|
||||
onClick = {
|
||||
if (book.id != -1) {
|
||||
navigateToReader()
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
if (book.progress == 0f) stringResource(id = R.string.start_reading)
|
||||
else stringResource(
|
||||
id = R.string.continue_reading_query,
|
||||
"${book.progress.calculateProgress(1)}%"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,37 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
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.graphics.SolidColor
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
|
|
@ -29,62 +41,83 @@ import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
|||
@Composable
|
||||
fun BookInfoLayoutDescription(
|
||||
book: Book,
|
||||
editDescription: Boolean,
|
||||
descriptionValue: String,
|
||||
editDescriptionMode: (BookInfoEvent.OnEditDescriptionMode) -> Unit,
|
||||
editDescriptionValueChange: (BookInfoEvent.OnEditDescriptionValueChange) -> Unit,
|
||||
editDescriptionRequestFocus: (BookInfoEvent.OnEditDescriptionRequestFocus) -> Unit,
|
||||
showDescriptionDialog: (BookInfoEvent.OnShowDescriptionDialog) -> Unit
|
||||
) {
|
||||
val descriptionFocusRequester = remember { FocusRequester() }
|
||||
val expand = remember { mutableStateOf(false) }
|
||||
val expandable = remember(book.description) { (book.description?.length ?: 0) > 50 }
|
||||
|
||||
if (!editDescription) {
|
||||
Text(
|
||||
if (book.description?.isNotBlank() == true) book.description
|
||||
else stringResource(id = R.string.error_no_description),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Start,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp)
|
||||
.noRippleClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
editDescriptionMode(BookInfoEvent.OnEditDescriptionMode(true))
|
||||
}
|
||||
),
|
||||
val backgroundColor = MaterialTheme.colorScheme.surface
|
||||
val gradientAnimation = animateColorAsState(
|
||||
targetValue = if (expand.value || !expandable) {
|
||||
backgroundColor.copy(alpha = 0f)
|
||||
} else backgroundColor,
|
||||
animationSpec = spring(stiffness = Spring.StiffnessMedium)
|
||||
)
|
||||
val arrowAnimation = animateFloatAsState(
|
||||
if (expand.value) -1f
|
||||
else 1f,
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioMediumBouncy,
|
||||
stiffness = Spring.StiffnessMediumLow
|
||||
)
|
||||
} else {
|
||||
BasicTextField(
|
||||
value = descriptionValue,
|
||||
textStyle = MaterialTheme.typography.bodyLarge.copy(
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
),
|
||||
onValueChange = {
|
||||
if (it.length < 5000 || it.length < descriptionValue.length) {
|
||||
editDescriptionValueChange(BookInfoEvent.OnEditDescriptionValueChange(it))
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.noRippleClickable(
|
||||
onClick = {
|
||||
if (expandable) expand.value = !expand.value
|
||||
},
|
||||
onLongClick = {
|
||||
showDescriptionDialog(BookInfoEvent.OnShowDescriptionDialog)
|
||||
}
|
||||
},
|
||||
)
|
||||
.padding(horizontal = 18.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp)
|
||||
.focusRequester(descriptionFocusRequester)
|
||||
.onGloballyPositioned {
|
||||
editDescriptionRequestFocus(
|
||||
BookInfoEvent.OnEditDescriptionRequestFocus(
|
||||
descriptionFocusRequester
|
||||
.fillMaxWidth()
|
||||
.animateContentSize()
|
||||
.heightIn(0.dp, if (!expand.value && expandable) 60.dp else Dp.Unspecified)
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
drawRect(
|
||||
brush = Brush.verticalGradient(
|
||||
0f to Color.Transparent,
|
||||
0.95f to gradientAnimation.value
|
||||
)
|
||||
)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(KeyboardCapitalization.Sentences),
|
||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
) { innerText ->
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
innerText()
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
if (!book.description.isNullOrBlank()) book.description
|
||||
else stringResource(id = R.string.error_no_description),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = expandable,
|
||||
enter = expandVertically() + fadeIn(),
|
||||
exit = shrinkVertically() + fadeOut()
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.KeyboardArrowDown,
|
||||
contentDescription = stringResource(
|
||||
id = if (expand.value) R.string.show_less_content_desc
|
||||
else R.string.show_more_content_desc
|
||||
),
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.scale(
|
||||
scaleX = 1f,
|
||||
scaleY = arrowAnimation.value
|
||||
),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(96.dp))
|
||||
}
|
||||
|
|
@ -1,216 +1,54 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Image
|
||||
import androidx.compose.material.icons.outlined.Person
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
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.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.components.common.AsyncCoverImage
|
||||
import ua.acclorite.book_story.presentation.core.util.noRippleClickable
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun BookInfoLayoutInfo(
|
||||
book: Book,
|
||||
editTitle: Boolean,
|
||||
titleValue: String,
|
||||
editAuthor: Boolean,
|
||||
authorValue: String,
|
||||
editTitleMode: (BookInfoEvent.OnEditTitleMode) -> Unit,
|
||||
editTitleValueChange: (BookInfoEvent.OnEditTitleValueChange) -> Unit,
|
||||
editTitleRequestFocus: (BookInfoEvent.OnEditTitleRequestFocus) -> Unit,
|
||||
editAuthorMode: (BookInfoEvent.OnEditAuthorMode) -> Unit,
|
||||
editAuthorValueChange: (BookInfoEvent.OnEditAuthorValueChange) -> Unit,
|
||||
editAuthorRequestFocus: (BookInfoEvent.OnEditAuthorRequestFocus) -> Unit,
|
||||
showTitleDialog: (BookInfoEvent.OnShowTitleDialog) -> Unit,
|
||||
showAuthorDialog: (BookInfoEvent.OnShowAuthorDialog) -> Unit,
|
||||
showChangeCoverBottomSheet: (BookInfoEvent.OnShowChangeCoverBottomSheet) -> Unit
|
||||
) {
|
||||
val titleFocusRequester = remember { FocusRequester() }
|
||||
val authorFocusRequester = remember { FocusRequester() }
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp)
|
||||
.padding(horizontal = 18.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(195.dp)
|
||||
.width(130.dp)
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceContainerLow,
|
||||
MaterialTheme.shapes.medium
|
||||
)
|
||||
.noRippleClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
showChangeCoverBottomSheet(BookInfoEvent.OnShowChangeCoverBottomSheet)
|
||||
}
|
||||
)
|
||||
BookInfoLayoutInfoCover(
|
||||
book = book,
|
||||
showChangeCoverBottomSheet = showChangeCoverBottomSheet
|
||||
)
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
if (book.coverImage != null) {
|
||||
AsyncCoverImage(
|
||||
uri = book.coverImage,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Image,
|
||||
contentDescription = stringResource(id = R.string.cover_image_not_found_content_desc),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.fillMaxWidth(0.7f)
|
||||
.aspectRatio(1f),
|
||||
tint = MaterialTheme.colorScheme.surfaceContainerHigh
|
||||
)
|
||||
}
|
||||
}
|
||||
BookInfoLayoutInfoTitle(
|
||||
book = book,
|
||||
showTitleDialog = showTitleDialog
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
BookInfoLayoutInfoAuthor(
|
||||
book = book,
|
||||
showAuthorDialog = showAuthorDialog
|
||||
)
|
||||
|
||||
Column(verticalArrangement = Arrangement.Center) {
|
||||
if (!editTitle) {
|
||||
Text(
|
||||
book.title,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.noRippleClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
editTitleMode(BookInfoEvent.OnEditTitleMode(true))
|
||||
}
|
||||
),
|
||||
maxLines = 4,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
} else {
|
||||
BasicTextField(
|
||||
maxLines = 4,
|
||||
value = titleValue,
|
||||
textStyle = MaterialTheme.typography.headlineSmall.copy(
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
),
|
||||
onValueChange = {
|
||||
if (it.length < 100 || it.length < titleValue.length) {
|
||||
editTitleValueChange(BookInfoEvent.OnEditTitleValueChange(it))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.focusRequester(titleFocusRequester)
|
||||
.onGloballyPositioned {
|
||||
editTitleRequestFocus(
|
||||
BookInfoEvent.OnEditTitleRequestFocus(
|
||||
titleFocusRequester
|
||||
)
|
||||
)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(KeyboardCapitalization.Words),
|
||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
) { innerText ->
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
innerText()
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Person,
|
||||
contentDescription = stringResource(id = R.string.author),
|
||||
modifier = Modifier.size(18.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
|
||||
if (!editAuthor) {
|
||||
Text(
|
||||
book.author.asString(),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.noRippleClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
editAuthorMode(BookInfoEvent.OnEditAuthorMode(true))
|
||||
}
|
||||
),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
} else {
|
||||
BasicTextField(
|
||||
singleLine = true,
|
||||
value = authorValue,
|
||||
textStyle = MaterialTheme.typography.bodyLarge.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
),
|
||||
onValueChange = {
|
||||
if (it.length < 50 || it.length < authorValue.length) {
|
||||
editAuthorValueChange(BookInfoEvent.OnEditAuthorValueChange(it))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.focusRequester(authorFocusRequester)
|
||||
.onGloballyPositioned {
|
||||
editAuthorRequestFocus(
|
||||
BookInfoEvent.OnEditAuthorRequestFocus(
|
||||
authorFocusRequester
|
||||
)
|
||||
)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(KeyboardCapitalization.Words),
|
||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
) { innerText ->
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
innerText()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BookInfoLayoutInfoProgress(
|
||||
book = book
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Person
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.util.noRippleClickable
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoLayoutInfoAuthor(
|
||||
book: Book,
|
||||
showAuthorDialog: (BookInfoEvent.OnShowAuthorDialog) -> Unit
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Person,
|
||||
contentDescription = stringResource(id = R.string.author),
|
||||
modifier = Modifier.size(18.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Text(
|
||||
book.author.asString(),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.noRippleClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
showAuthorDialog(BookInfoEvent.OnShowAuthorDialog)
|
||||
}
|
||||
),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Image
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.components.common.AsyncCoverImage
|
||||
import ua.acclorite.book_story.presentation.core.util.noRippleClickable
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoLayoutInfoCover(
|
||||
book: Book,
|
||||
showChangeCoverBottomSheet: (BookInfoEvent.OnShowChangeCoverBottomSheet) -> Unit
|
||||
) {
|
||||
val height = remember { 220.dp }
|
||||
val width = remember(height) { height * 0.66f }
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(height)
|
||||
.width(width)
|
||||
.clip(MaterialTheme.shapes.large)
|
||||
.background(MaterialTheme.colorScheme.surfaceContainerLow)
|
||||
.noRippleClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
showChangeCoverBottomSheet(BookInfoEvent.OnShowChangeCoverBottomSheet)
|
||||
}
|
||||
)
|
||||
) {
|
||||
if (book.coverImage != null) {
|
||||
AsyncCoverImage(
|
||||
uri = book.coverImage,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Image,
|
||||
contentDescription = stringResource(id = R.string.cover_image_not_found_content_desc),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.fillMaxWidth(0.7f)
|
||||
.aspectRatio(1f),
|
||||
tint = MaterialTheme.colorScheme.surfaceContainerHigh
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.LinearWavyProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.util.calculateProgress
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun BookInfoLayoutInfoProgress(
|
||||
book: Book
|
||||
) {
|
||||
val progress = remember(book.progress) {
|
||||
"${book.progress.calculateProgress(1)}%"
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
LinearWavyProgressIndicator(
|
||||
progress = { book.progress.coerceIn(0f, 1f) },
|
||||
trackColor = MaterialTheme.colorScheme.secondaryContainer.copy(0.7f),
|
||||
modifier = Modifier.weight(1f),
|
||||
amplitude = { 0.5f },
|
||||
wavelength = 80.dp,
|
||||
waveSpeed = 15.dp
|
||||
)
|
||||
Text(
|
||||
text = progress,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.util.noRippleClickable
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoLayoutInfoTitle(
|
||||
book: Book,
|
||||
showTitleDialog: (BookInfoEvent.OnShowTitleDialog) -> Unit
|
||||
) {
|
||||
Text(
|
||||
book.title,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.noRippleClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
showTitleDialog(BookInfoEvent.OnShowTitleDialog)
|
||||
}
|
||||
),
|
||||
maxLines = 4,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
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.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.LinearWavyProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.util.calculateProgress
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun BookInfoLayoutStatistic(
|
||||
book: Book
|
||||
) {
|
||||
val progress = remember(book.progress) {
|
||||
derivedStateOf {
|
||||
"${book.progress.calculateProgress(1)}%"
|
||||
}
|
||||
}
|
||||
val description = stringResource(
|
||||
if (book.progress == 1f) R.string.read_done
|
||||
else if (book.progress > 0.2f) R.string.read_keep
|
||||
else R.string.read_more
|
||||
)
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp)
|
||||
) {
|
||||
Text(
|
||||
text = progress.value,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
)
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
|
||||
LinearWavyProgressIndicator(
|
||||
progress = { book.progress.coerceIn(0f, 1f) },
|
||||
trackColor = MaterialTheme.colorScheme.secondaryContainer.copy(0.7f),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
amplitude = { 0.5f },
|
||||
wavelength = 80.dp,
|
||||
waveSpeed = 15.dp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
Text(
|
||||
text = description,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.Position
|
||||
import ua.acclorite.book_story.presentation.core.components.modal_bottom_sheet.ModalBottomSheet
|
||||
import ua.acclorite.book_story.presentation.navigator.NavigatorBottomSheetItem
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoMoreBottomSheet(
|
||||
showDetailsBottomSheet: (BookInfoEvent.OnShowDetailsBottomSheet) -> Unit,
|
||||
showMoveDialog: (BookInfoEvent.OnShowMoveDialog) -> Unit,
|
||||
showDeleteDialog: (BookInfoEvent.OnShowDeleteDialog) -> Unit,
|
||||
dismissBottomSheet: (BookInfoEvent.OnDismissBottomSheet) -> Unit,
|
||||
) {
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onDismissRequest = {
|
||||
dismissBottomSheet(BookInfoEvent.OnDismissBottomSheet)
|
||||
},
|
||||
sheetGesturesEnabled = true
|
||||
) {
|
||||
LazyColumn(modifier = Modifier.fillMaxWidth()) {
|
||||
item {
|
||||
NavigatorBottomSheetItem(
|
||||
title = stringResource(id = R.string.details_book),
|
||||
primary = false,
|
||||
position = Position.SOLO
|
||||
) {
|
||||
showDetailsBottomSheet(BookInfoEvent.OnShowDetailsBottomSheet)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(Modifier.height(18.dp))
|
||||
}
|
||||
|
||||
item {
|
||||
NavigatorBottomSheetItem(
|
||||
title = stringResource(id = R.string.delete_this_book),
|
||||
primary = true,
|
||||
position = Position.TOP
|
||||
) {
|
||||
showDeleteDialog(BookInfoEvent.OnShowDeleteDialog)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
NavigatorBottomSheetItem(
|
||||
title = stringResource(id = R.string.move_this_book),
|
||||
primary = true,
|
||||
position = Position.BOTTOM
|
||||
) {
|
||||
showMoveDialog(BookInfoEvent.OnShowMoveDialog)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
|
|
@ -20,24 +19,13 @@ import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
|||
fun BookInfoScaffold(
|
||||
book: Book,
|
||||
listState: LazyListState,
|
||||
editTitle: Boolean,
|
||||
titleValue: String,
|
||||
editAuthor: Boolean,
|
||||
authorValue: String,
|
||||
editDescription: Boolean,
|
||||
descriptionValue: String,
|
||||
editTitleMode: (BookInfoEvent.OnEditTitleMode) -> Unit,
|
||||
editTitleValueChange: (BookInfoEvent.OnEditTitleValueChange) -> Unit,
|
||||
editTitleRequestFocus: (BookInfoEvent.OnEditTitleRequestFocus) -> Unit,
|
||||
editAuthorMode: (BookInfoEvent.OnEditAuthorMode) -> Unit,
|
||||
editAuthorValueChange: (BookInfoEvent.OnEditAuthorValueChange) -> Unit,
|
||||
editAuthorRequestFocus: (BookInfoEvent.OnEditAuthorRequestFocus) -> Unit,
|
||||
editDescriptionMode: (BookInfoEvent.OnEditDescriptionMode) -> Unit,
|
||||
editDescriptionValueChange: (BookInfoEvent.OnEditDescriptionValueChange) -> Unit,
|
||||
editDescriptionRequestFocus: (BookInfoEvent.OnEditDescriptionRequestFocus) -> Unit,
|
||||
showChangeCoverBottomSheet: (BookInfoEvent.OnShowChangeCoverBottomSheet) -> Unit,
|
||||
showMoreBottomSheet: (BookInfoEvent.OnShowMoreBottomSheet) -> Unit,
|
||||
updateData: (BookInfoEvent.OnUpdateData) -> Unit,
|
||||
showDetailsBottomSheet: (BookInfoEvent.OnShowDetailsBottomSheet) -> Unit,
|
||||
showTitleDialog: (BookInfoEvent.OnShowTitleDialog) -> Unit,
|
||||
showAuthorDialog: (BookInfoEvent.OnShowAuthorDialog) -> Unit,
|
||||
showDescriptionDialog: (BookInfoEvent.OnShowDescriptionDialog) -> Unit,
|
||||
showMoveDialog: (BookInfoEvent.OnShowMoveDialog) -> Unit,
|
||||
showDeleteDialog: (BookInfoEvent.OnShowDeleteDialog) -> Unit,
|
||||
navigateToReader: () -> Unit,
|
||||
navigateBack: () -> Unit
|
||||
) {
|
||||
|
|
@ -51,49 +39,22 @@ fun BookInfoScaffold(
|
|||
BookInfoTopBar(
|
||||
book = book,
|
||||
listState = listState,
|
||||
editTitle = editTitle,
|
||||
titleValue = titleValue,
|
||||
editAuthor = editAuthor,
|
||||
authorValue = authorValue,
|
||||
editDescription = editDescription,
|
||||
descriptionValue = descriptionValue,
|
||||
editTitleMode = editTitleMode,
|
||||
editAuthorMode = editAuthorMode,
|
||||
editDescriptionMode = editDescriptionMode,
|
||||
updateData = updateData,
|
||||
showMoreBottomSheet = showMoreBottomSheet,
|
||||
showDetailsBottomSheet = showDetailsBottomSheet,
|
||||
navigateBack = navigateBack
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
BookInfoLayout(
|
||||
book = book,
|
||||
listState = listState,
|
||||
paddingValues = paddingValues,
|
||||
editTitle = editTitle,
|
||||
titleValue = titleValue,
|
||||
editAuthor = editAuthor,
|
||||
authorValue = authorValue,
|
||||
editDescription = editDescription,
|
||||
descriptionValue = descriptionValue,
|
||||
editTitleMode = editTitleMode,
|
||||
editTitleValueChange = editTitleValueChange,
|
||||
editTitleRequestFocus = editTitleRequestFocus,
|
||||
editAuthorMode = editAuthorMode,
|
||||
editAuthorValueChange = editAuthorValueChange,
|
||||
editAuthorRequestFocus = editAuthorRequestFocus,
|
||||
editDescriptionMode = editDescriptionMode,
|
||||
editDescriptionValueChange = editDescriptionValueChange,
|
||||
editDescriptionRequestFocus = editDescriptionRequestFocus,
|
||||
showChangeCoverBottomSheet = showChangeCoverBottomSheet
|
||||
)
|
||||
|
||||
BookInfoFloatingActionButton(
|
||||
book = book,
|
||||
listState = listState,
|
||||
navigateToReader = navigateToReader
|
||||
)
|
||||
}
|
||||
BookInfoLayout(
|
||||
book = book,
|
||||
listState = listState,
|
||||
paddingValues = paddingValues,
|
||||
showTitleDialog = showTitleDialog,
|
||||
showAuthorDialog = showAuthorDialog,
|
||||
showDescriptionDialog = showDescriptionDialog,
|
||||
showChangeCoverBottomSheet = showChangeCoverBottomSheet,
|
||||
showMoveDialog = showMoveDialog,
|
||||
showDeleteDialog = showDeleteDialog,
|
||||
navigateToReader = navigateToReader
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.components.dialog.DialogWithTextField
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
|
||||
@Composable
|
||||
fun BookInfoTitleDialog(
|
||||
book: Book,
|
||||
actionTitleDialog: (BookInfoEvent.OnActionTitleDialog) -> Unit,
|
||||
dismissDialog: (BookInfoEvent.OnDismissDialog) -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
DialogWithTextField(
|
||||
initialValue = book.title,
|
||||
lengthLimit = 100,
|
||||
onDismiss = {
|
||||
dismissDialog(BookInfoEvent.OnDismissDialog)
|
||||
},
|
||||
onAction = {
|
||||
if (it.isBlank()) return@DialogWithTextField
|
||||
actionTitleDialog(
|
||||
BookInfoEvent.OnActionTitleDialog(
|
||||
title = it.trim().replace("\n", ""),
|
||||
context = context
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
package ua.acclorite.book_story.presentation.book_info
|
||||
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.outlined.Done
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -16,32 +12,19 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.library.book.Book
|
||||
import ua.acclorite.book_story.presentation.core.components.common.AnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.core.components.common.IconButton
|
||||
import ua.acclorite.book_story.presentation.core.components.top_bar.TopAppBar
|
||||
import ua.acclorite.book_story.presentation.core.components.top_bar.TopAppBarData
|
||||
import ua.acclorite.book_story.presentation.navigator.NavigatorBackIconButton
|
||||
import ua.acclorite.book_story.presentation.navigator.NavigatorIconButton
|
||||
import ua.acclorite.book_story.ui.book_info.BookInfoEvent
|
||||
import ua.acclorite.book_story.ui.theme.DefaultTransition
|
||||
import ua.acclorite.book_story.ui.theme.Transitions
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BookInfoTopBar(
|
||||
book: Book,
|
||||
listState: LazyListState,
|
||||
editTitle: Boolean,
|
||||
titleValue: String,
|
||||
editAuthor: Boolean,
|
||||
authorValue: String,
|
||||
editDescription: Boolean,
|
||||
descriptionValue: String,
|
||||
editTitleMode: (BookInfoEvent.OnEditTitleMode) -> Unit,
|
||||
editAuthorMode: (BookInfoEvent.OnEditAuthorMode) -> Unit,
|
||||
editDescriptionMode: (BookInfoEvent.OnEditDescriptionMode) -> Unit,
|
||||
updateData: (BookInfoEvent.OnUpdateData) -> Unit,
|
||||
showMoreBottomSheet: (BookInfoEvent.OnShowMoreBottomSheet) -> Unit,
|
||||
showDetailsBottomSheet: (BookInfoEvent.OnShowDetailsBottomSheet) -> Unit,
|
||||
navigateBack: () -> Unit
|
||||
) {
|
||||
val firstVisibleItemIndex = remember {
|
||||
|
|
@ -50,12 +33,6 @@ fun BookInfoTopBar(
|
|||
}
|
||||
}
|
||||
|
||||
val titleChanged = titleValue.isNotBlank()
|
||||
&& titleValue.trim() != book.title.trim()
|
||||
val authorChanged = authorValue.isNotBlank()
|
||||
&& authorValue.trim() != book.author.getAsString()?.trim()
|
||||
val descriptionChanged = descriptionValue.trim() != (book.description?.trim() ?: "")
|
||||
|
||||
TopAppBar(
|
||||
containerColor = MaterialTheme.colorScheme.surface.copy(0f),
|
||||
scrollBehavior = null,
|
||||
|
|
@ -66,36 +43,12 @@ fun BookInfoTopBar(
|
|||
TopAppBarData(
|
||||
contentID = 0,
|
||||
contentNavigationIcon = {
|
||||
if (
|
||||
editTitle ||
|
||||
editAuthor ||
|
||||
editDescription
|
||||
) {
|
||||
IconButton(
|
||||
icon = Icons.AutoMirrored.Outlined.ArrowBack,
|
||||
contentDescription = R.string.exit_editing_content_desc,
|
||||
disableOnClick = true
|
||||
) {
|
||||
if (editTitle) {
|
||||
editTitleMode(BookInfoEvent.OnEditTitleMode(false))
|
||||
}
|
||||
|
||||
if (editAuthor) {
|
||||
editAuthorMode(BookInfoEvent.OnEditAuthorMode(false))
|
||||
}
|
||||
|
||||
if (editDescription) {
|
||||
editDescriptionMode(BookInfoEvent.OnEditDescriptionMode(false))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NavigatorBackIconButton {
|
||||
navigateBack()
|
||||
}
|
||||
NavigatorBackIconButton {
|
||||
navigateBack()
|
||||
}
|
||||
},
|
||||
contentTitle = {
|
||||
DefaultTransition(firstVisibleItemIndex.value > 0 && !editTitle) {
|
||||
DefaultTransition(firstVisibleItemIndex.value > 0) {
|
||||
Text(
|
||||
book.title,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
|
|
@ -106,41 +59,14 @@ fun BookInfoTopBar(
|
|||
}
|
||||
},
|
||||
contentActions = {
|
||||
Box {
|
||||
DefaultTransition(
|
||||
visible = !editTitle &&
|
||||
!editAuthor &&
|
||||
!editDescription
|
||||
) {
|
||||
NavigatorIconButton {
|
||||
showMoreBottomSheet(BookInfoEvent.OnShowMoreBottomSheet)
|
||||
}
|
||||
IconButton(
|
||||
icon = Icons.Outlined.Info,
|
||||
contentDescription = R.string.file_details,
|
||||
disableOnClick = false,
|
||||
onClick = {
|
||||
showDetailsBottomSheet(BookInfoEvent.OnShowDetailsBottomSheet)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = editTitle ||
|
||||
editAuthor ||
|
||||
editDescription,
|
||||
enter = Transitions.DefaultTransitionIn,
|
||||
exit = fadeOut(tween(200))
|
||||
) {
|
||||
IconButton(
|
||||
icon = Icons.Outlined.Done,
|
||||
contentDescription = R.string.apply_changes_content_desc,
|
||||
disableOnClick = true,
|
||||
enabled = titleChanged ||
|
||||
authorChanged ||
|
||||
descriptionChanged,
|
||||
color = if (
|
||||
titleChanged ||
|
||||
authorChanged ||
|
||||
descriptionChanged
|
||||
) MaterialTheme.colorScheme.onSurface
|
||||
else MaterialTheme.colorScheme.onSurfaceVariant
|
||||
) {
|
||||
updateData(BookInfoEvent.OnUpdateData)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ 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.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
|
|
@ -16,19 +16,18 @@ 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.KeyboardCapitalization
|
||||
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?
|
||||
onAction: (String) -> Unit
|
||||
) {
|
||||
val state = remember(initialValue) {
|
||||
mutableStateOf(
|
||||
|
|
@ -41,9 +40,6 @@ fun DialogWithTextField(
|
|||
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,
|
||||
|
|
@ -51,14 +47,13 @@ fun DialogWithTextField(
|
|||
actionEnabled = true,
|
||||
disableOnClick = false,
|
||||
onAction = {
|
||||
if (state.value.text.isBlank()) {
|
||||
if (state.value.text == initialValue) {
|
||||
onDismiss()
|
||||
return@Dialog
|
||||
}
|
||||
error.value = onAction(state.value.text)
|
||||
|
||||
showError.value = error.value != null
|
||||
if (!showError.value) onDismiss()
|
||||
onAction(state.value.text)
|
||||
onDismiss()
|
||||
},
|
||||
withContent = true,
|
||||
items = {
|
||||
|
|
@ -68,10 +63,9 @@ fun DialogWithTextField(
|
|||
onValueChange = {
|
||||
if (it.text.length < lengthLimit || it.text.length < state.value.text.length) {
|
||||
state.value = it
|
||||
showError.value = false
|
||||
}
|
||||
},
|
||||
isError = showError.value,
|
||||
keyboardOptions = KeyboardOptions(KeyboardCapitalization.Sentences),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp)
|
||||
.fillMaxWidth()
|
||||
|
|
@ -95,17 +89,6 @@ fun DialogWithTextField(
|
|||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
},
|
||||
supportingText = {
|
||||
ExpandingTransition(
|
||||
visible = showError.value && error.value != null
|
||||
) {
|
||||
Text(
|
||||
error.value!!.asString(),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,54 +3,13 @@ package ua.acclorite.book_story.ui.book_info
|
|||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import ua.acclorite.book_story.domain.library.category.Category
|
||||
import ua.acclorite.book_story.domain.ui.UIText
|
||||
|
||||
@Immutable
|
||||
sealed class BookInfoEvent {
|
||||
|
||||
data class OnCopyToClipboard(
|
||||
val text: String,
|
||||
val context: Context,
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditTitleMode(
|
||||
val edit: Boolean
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditTitleRequestFocus(
|
||||
val focusRequester: FocusRequester
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditTitleValueChange(
|
||||
val value: String
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditAuthorMode(
|
||||
val edit: Boolean
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditAuthorRequestFocus(
|
||||
val focusRequester: FocusRequester
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditAuthorValueChange(
|
||||
val value: String
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditDescriptionMode(
|
||||
val edit: Boolean
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditDescriptionRequestFocus(
|
||||
val focusRequester: FocusRequester
|
||||
) : BookInfoEvent()
|
||||
|
||||
data class OnEditDescriptionValueChange(
|
||||
val value: String
|
||||
) : BookInfoEvent()
|
||||
|
||||
data object OnUpdateData : BookInfoEvent()
|
||||
data object OnShowDetailsBottomSheet : BookInfoEvent()
|
||||
|
||||
data object OnShowChangeCoverBottomSheet : BookInfoEvent()
|
||||
|
||||
|
|
@ -69,12 +28,29 @@ sealed class BookInfoEvent {
|
|||
|
||||
data object OnCheckCoverReset : BookInfoEvent()
|
||||
|
||||
data object OnShowMoreBottomSheet : BookInfoEvent()
|
||||
|
||||
data object OnShowDetailsBottomSheet : BookInfoEvent()
|
||||
|
||||
data object OnDismissBottomSheet : BookInfoEvent()
|
||||
|
||||
data object OnShowTitleDialog : BookInfoEvent()
|
||||
|
||||
data class OnActionTitleDialog(
|
||||
val title: String,
|
||||
val context: Context
|
||||
) : BookInfoEvent()
|
||||
|
||||
data object OnShowAuthorDialog : BookInfoEvent()
|
||||
|
||||
data class OnActionAuthorDialog(
|
||||
val author: UIText,
|
||||
val context: Context
|
||||
) : BookInfoEvent()
|
||||
|
||||
data object OnShowDescriptionDialog : BookInfoEvent()
|
||||
|
||||
data class OnActionDescriptionDialog(
|
||||
val description: String?,
|
||||
val context: Context
|
||||
) : BookInfoEvent()
|
||||
|
||||
data object OnShowDeleteDialog : BookInfoEvent()
|
||||
|
||||
data class OnActionDeleteDialog(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
package ua.acclorite.book_story.ui.book_info
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context.CLIPBOARD_SERVICE
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Build
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -21,7 +17,6 @@ import kotlinx.coroutines.withContext
|
|||
import kotlinx.coroutines.yield
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.library.category.Category
|
||||
import ua.acclorite.book_story.domain.ui.UIText
|
||||
import ua.acclorite.book_story.domain.use_case.book.CanResetCover
|
||||
import ua.acclorite.book_story.domain.use_case.book.DeleteBooks
|
||||
import ua.acclorite.book_story.domain.use_case.book.GetBookById
|
||||
|
|
@ -56,181 +51,14 @@ class BookInfoModel @Inject constructor(
|
|||
fun onEvent(event: BookInfoEvent) {
|
||||
viewModelScope.launch(eventJob + Dispatchers.Main) {
|
||||
when (event) {
|
||||
is BookInfoEvent.OnCopyToClipboard -> {
|
||||
val clipboardManager =
|
||||
event.context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
||||
clipboardManager.setPrimaryClip(ClipData.newPlainText(null, event.text))
|
||||
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
withContext(Dispatchers.Main) {
|
||||
event.context.getString(R.string.copied)
|
||||
.showToast(context = event.context, longToast = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditTitleMode -> {
|
||||
launch(Dispatchers.IO) {
|
||||
if (event.edit) {
|
||||
_state.update {
|
||||
it.copy(
|
||||
titleValue = it.book.title,
|
||||
hasTitleFocused = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_state.update {
|
||||
it.copy(
|
||||
editTitle = event.edit
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditTitleRequestFocus -> {
|
||||
if (!_state.value.hasTitleFocused) {
|
||||
event.focusRequester.requestFocus()
|
||||
_state.update {
|
||||
it.copy(
|
||||
hasTitleFocused = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditTitleValueChange -> {
|
||||
is BookInfoEvent.OnShowDetailsBottomSheet -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
titleValue = event.value
|
||||
bottomSheet = BookInfoScreen.DETAILS_BOTTOM_SHEET
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditAuthorMode -> {
|
||||
launch(Dispatchers.IO) {
|
||||
if (event.edit) {
|
||||
_state.update {
|
||||
it.copy(
|
||||
authorValue = it.book.author.getAsString() ?: "",
|
||||
hasAuthorFocused = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_state.update {
|
||||
it.copy(
|
||||
editAuthor = event.edit
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditAuthorRequestFocus -> {
|
||||
if (!_state.value.hasAuthorFocused) {
|
||||
event.focusRequester.requestFocus()
|
||||
_state.update {
|
||||
it.copy(
|
||||
hasAuthorFocused = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditAuthorValueChange -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
authorValue = event.value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditDescriptionMode -> {
|
||||
launch(Dispatchers.IO) {
|
||||
if (event.edit) {
|
||||
_state.update {
|
||||
it.copy(
|
||||
descriptionValue = it.book.description ?: "",
|
||||
hasDescriptionFocused = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_state.update {
|
||||
it.copy(
|
||||
editDescription = event.edit
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditDescriptionRequestFocus -> {
|
||||
if (!_state.value.hasDescriptionFocused) {
|
||||
event.focusRequester.requestFocus()
|
||||
_state.update {
|
||||
it.copy(
|
||||
hasDescriptionFocused = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnEditDescriptionValueChange -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
descriptionValue = event.value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnUpdateData -> {
|
||||
launch {
|
||||
val title = _state.value.titleValue.trim().replace("\n", "")
|
||||
val author = _state.value.authorValue.trim().replace("\n", "")
|
||||
val description = _state.value.descriptionValue.trim().replace("\n", "")
|
||||
|
||||
val titleChanged = title != _state.value.book.title
|
||||
&& _state.value.editTitle
|
||||
&& title.isNotBlank()
|
||||
val authorChanged = author != _state.value.book.author.getAsString()
|
||||
&& _state.value.editAuthor
|
||||
&& author.isNotBlank()
|
||||
val descriptionChanged = description != _state.value.book.description
|
||||
&& _state.value.editDescription
|
||||
|
||||
val book = _state.value.book.copy(
|
||||
title = if (titleChanged) title else _state.value.book.title,
|
||||
author = if (authorChanged) UIText.StringValue(author)
|
||||
else _state.value.book.author,
|
||||
description = if (descriptionChanged) description
|
||||
else _state.value.book.description
|
||||
)
|
||||
|
||||
updateBook.execute(book)
|
||||
_state.update {
|
||||
it.copy(
|
||||
book = book
|
||||
)
|
||||
}
|
||||
|
||||
LibraryScreen.refreshListChannel.trySend(0)
|
||||
HistoryScreen.refreshListChannel.trySend(0)
|
||||
|
||||
if (_state.value.editTitle) {
|
||||
onEvent(BookInfoEvent.OnEditTitleMode(false))
|
||||
}
|
||||
|
||||
if (_state.value.editAuthor) {
|
||||
onEvent(BookInfoEvent.OnEditAuthorMode(false))
|
||||
}
|
||||
|
||||
if (_state.value.editDescription) {
|
||||
onEvent(BookInfoEvent.OnEditDescriptionMode(false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnShowChangeCoverBottomSheet -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
|
|
@ -357,22 +185,6 @@ class BookInfoModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnShowMoreBottomSheet -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
bottomSheet = BookInfoScreen.MORE_BOTTOM_SHEET
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnShowDetailsBottomSheet -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
bottomSheet = BookInfoScreen.DETAILS_BOTTOM_SHEET
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnDismissBottomSheet -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
|
|
@ -381,6 +193,93 @@ class BookInfoModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnShowTitleDialog -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
dialog = BookInfoScreen.TITLE_DIALOG
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnActionTitleDialog -> {
|
||||
launch {
|
||||
_state.update {
|
||||
it.copy(
|
||||
book = it.book.copy(
|
||||
title = event.title
|
||||
)
|
||||
)
|
||||
}
|
||||
updateBook.execute(_state.value.book)
|
||||
|
||||
LibraryScreen.refreshListChannel.trySend(0)
|
||||
HistoryScreen.refreshListChannel.trySend(0)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
event.context.getString(R.string.title_changed)
|
||||
.showToast(context = event.context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnShowAuthorDialog -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
dialog = BookInfoScreen.AUTHOR_DIALOG
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnActionAuthorDialog -> {
|
||||
launch {
|
||||
_state.update {
|
||||
it.copy(
|
||||
book = it.book.copy(
|
||||
author = event.author
|
||||
)
|
||||
)
|
||||
}
|
||||
updateBook.execute(_state.value.book)
|
||||
|
||||
LibraryScreen.refreshListChannel.trySend(0)
|
||||
HistoryScreen.refreshListChannel.trySend(0)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
event.context.getString(R.string.author_changed)
|
||||
.showToast(context = event.context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnShowDescriptionDialog -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
dialog = BookInfoScreen.DESCRIPTION_DIALOG
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnActionDescriptionDialog -> {
|
||||
launch {
|
||||
_state.update {
|
||||
it.copy(
|
||||
book = it.book.copy(
|
||||
description = event.description
|
||||
)
|
||||
)
|
||||
}
|
||||
updateBook.execute(_state.value.book)
|
||||
|
||||
LibraryScreen.refreshListChannel.trySend(0)
|
||||
HistoryScreen.refreshListChannel.trySend(0)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
event.context.getString(R.string.description_changed)
|
||||
.showToast(context = event.context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is BookInfoEvent.OnShowDeleteDialog -> {
|
||||
_state.update {
|
||||
it.copy(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package ua.acclorite.book_story.ui.book_info
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
|
@ -22,9 +25,11 @@ data class BookInfoScreen(val bookId: Int) : Screen, Parcelable {
|
|||
companion object {
|
||||
const val DELETE_DIALOG = "delete_dialog"
|
||||
const val MOVE_DIALOG = "move_dialog"
|
||||
const val TITLE_DIALOG = "title_dialog"
|
||||
const val AUTHOR_DIALOG = "author_dialog"
|
||||
const val DESCRIPTION_DIALOG = "description_dialog"
|
||||
|
||||
const val CHANGE_COVER_BOTTOM_SHEET = "change_cover_bottom_sheet"
|
||||
const val MORE_BOTTOM_SHEET = "more_bottom_sheet"
|
||||
const val DETAILS_BOTTOM_SHEET = "details_bottom_sheet"
|
||||
}
|
||||
|
||||
|
|
@ -52,58 +57,50 @@ data class BookInfoScreen(val bookId: Int) : Screen, Parcelable {
|
|||
}
|
||||
}
|
||||
|
||||
BookInfoContent(
|
||||
book = state.value.book,
|
||||
bottomSheet = state.value.bottomSheet,
|
||||
dialog = state.value.dialog,
|
||||
listState = listState,
|
||||
canResetCover = state.value.canResetCover,
|
||||
editTitle = state.value.editTitle,
|
||||
titleValue = state.value.titleValue,
|
||||
editAuthor = state.value.editAuthor,
|
||||
authorValue = state.value.authorValue,
|
||||
editDescription = state.value.editDescription,
|
||||
descriptionValue = state.value.descriptionValue,
|
||||
editTitleMode = screenModel::onEvent,
|
||||
editTitleValueChange = screenModel::onEvent,
|
||||
editTitleRequestFocus = screenModel::onEvent,
|
||||
editAuthorMode = screenModel::onEvent,
|
||||
editAuthorValueChange = screenModel::onEvent,
|
||||
editAuthorRequestFocus = screenModel::onEvent,
|
||||
editDescriptionMode = screenModel::onEvent,
|
||||
editDescriptionValueChange = screenModel::onEvent,
|
||||
editDescriptionRequestFocus = screenModel::onEvent,
|
||||
checkCoverReset = screenModel::onEvent,
|
||||
changeCover = screenModel::onEvent,
|
||||
resetCover = screenModel::onEvent,
|
||||
deleteCover = screenModel::onEvent,
|
||||
dismissBottomSheet = screenModel::onEvent,
|
||||
dismissDialog = screenModel::onEvent,
|
||||
showChangeCoverBottomSheet = screenModel::onEvent,
|
||||
showDetailsBottomSheet = screenModel::onEvent,
|
||||
showMoreBottomSheet = screenModel::onEvent,
|
||||
showMoveDialog = screenModel::onEvent,
|
||||
actionMoveDialog = screenModel::onEvent,
|
||||
showDeleteDialog = screenModel::onEvent,
|
||||
actionDeleteDialog = screenModel::onEvent,
|
||||
updateData = screenModel::onEvent,
|
||||
copyToClipboard = screenModel::onEvent,
|
||||
navigateToReader = {
|
||||
if (state.value.book.id != -1) {
|
||||
HistoryScreen.insertHistoryChannel.trySend(state.value.book.id)
|
||||
navigator.push(ReaderScreen(state.value.book.id))
|
||||
Box(Modifier.fillMaxSize())
|
||||
|
||||
if (state.value.book.id == bookId) {
|
||||
BookInfoContent(
|
||||
book = state.value.book,
|
||||
bottomSheet = state.value.bottomSheet,
|
||||
dialog = state.value.dialog,
|
||||
listState = listState,
|
||||
canResetCover = state.value.canResetCover,
|
||||
showTitleDialog = screenModel::onEvent,
|
||||
actionTitleDialog = screenModel::onEvent,
|
||||
showAuthorDialog = screenModel::onEvent,
|
||||
actionAuthorDialog = screenModel::onEvent,
|
||||
showDescriptionDialog = screenModel::onEvent,
|
||||
actionDescriptionDialog = screenModel::onEvent,
|
||||
checkCoverReset = screenModel::onEvent,
|
||||
changeCover = screenModel::onEvent,
|
||||
resetCover = screenModel::onEvent,
|
||||
deleteCover = screenModel::onEvent,
|
||||
dismissBottomSheet = screenModel::onEvent,
|
||||
dismissDialog = screenModel::onEvent,
|
||||
showChangeCoverBottomSheet = screenModel::onEvent,
|
||||
showDetailsBottomSheet = screenModel::onEvent,
|
||||
showMoveDialog = screenModel::onEvent,
|
||||
actionMoveDialog = screenModel::onEvent,
|
||||
showDeleteDialog = screenModel::onEvent,
|
||||
actionDeleteDialog = screenModel::onEvent,
|
||||
navigateToReader = {
|
||||
if (state.value.book.id != -1) {
|
||||
HistoryScreen.insertHistoryChannel.trySend(state.value.book.id)
|
||||
navigator.push(ReaderScreen(state.value.book.id))
|
||||
}
|
||||
},
|
||||
navigateToLibrary = {
|
||||
navigator.push(
|
||||
LibraryScreen,
|
||||
popping = true,
|
||||
saveInBackStack = false
|
||||
)
|
||||
},
|
||||
navigateBack = {
|
||||
navigator.pop()
|
||||
}
|
||||
},
|
||||
navigateToLibrary = {
|
||||
navigator.push(
|
||||
LibraryScreen,
|
||||
popping = true,
|
||||
saveInBackStack = false
|
||||
)
|
||||
},
|
||||
navigateBack = {
|
||||
navigator.pop()
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,18 +11,6 @@ import ua.acclorite.book_story.presentation.core.constants.provideEmptyBook
|
|||
data class BookInfoState(
|
||||
val book: Book = Constants.provideEmptyBook(),
|
||||
|
||||
val editTitle: Boolean = false,
|
||||
val hasTitleFocused: Boolean = false,
|
||||
val titleValue: String = "",
|
||||
|
||||
val editAuthor: Boolean = false,
|
||||
val hasAuthorFocused: Boolean = false,
|
||||
val authorValue: String = "",
|
||||
|
||||
val editDescription: Boolean = false,
|
||||
val hasDescriptionFocused: Boolean = false,
|
||||
val descriptionValue: String = "",
|
||||
|
||||
val canResetCover: Boolean = false,
|
||||
|
||||
val dialog: Dialog? = null,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
<string name="get_help">أحتاج المساعدة</string>
|
||||
<string name="add">أضف</string>
|
||||
<string name="add_book">أضف كتابا˝</string>
|
||||
<string name="start">ابدأ</string>
|
||||
<string name="continue_read">استمرار</string>
|
||||
<string name="never">أبدا˝</string>
|
||||
<string name="go_back">عودة</string>
|
||||
|
|
@ -168,10 +167,6 @@
|
|||
<string name="credits_updates">إدارة التحديثات الجديدة</string>
|
||||
<string name="alignment_start">ابدأ</string>
|
||||
<string name="alignment_center">المركز</string>
|
||||
<string name="move_this_book">نقل</string>
|
||||
<string name="delete_this_book">حذف</string>
|
||||
<string name="details_book">التفاصيل</string>
|
||||
<string name="file_name">اسم الملف</string>
|
||||
<string name="file_path">مسار الملف</string>
|
||||
<string name="app_version_option_desc_2">انقر للتحقق من وجود تحديثات</string>
|
||||
<string name="report_bug_option">الإبلاغ عن خطأ</string>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
<string name="marsh_theme">Pluto</string>
|
||||
<string name="library_empty">Čtěte vaše oblíbené knihy a třiďte je do kategorií</string>
|
||||
<string name="updates_notification_action">Stáhnout</string>
|
||||
<string name="file_name">Název souboru</string>
|
||||
<string name="language_option">Jazyk aplikace</string>
|
||||
<string name="pink_theme">Saturn</string>
|
||||
<string name="yes_go_to_help">Ano, přejít na pomoc</string>
|
||||
|
|
@ -54,7 +53,6 @@
|
|||
<string name="credits_fonts">Fonty</string>
|
||||
<string name="theme_contrast_standard">Standardní</string>
|
||||
<string name="browse_sort_order_name">Abecedně</string>
|
||||
<string name="details_book">Detaily</string>
|
||||
<string name="file_path">Cesta k souboru</string>
|
||||
<string name="books_added">Všechny vybrané knihy byly úspěšně přidány.</string>
|
||||
<string name="book_moved">Tato kniha byla úspěšně přesunuta.</string>
|
||||
|
|
@ -115,7 +113,6 @@
|
|||
<string name="delete">Smazat</string>
|
||||
<string name="green_color">Zelená</string>
|
||||
<string name="copied">Zkopírováno</string>
|
||||
<string name="delete_this_book">Smazat</string>
|
||||
<string name="fullscreen_option">Celá obrazovka</string>
|
||||
<string name="check_for_updates_option">Hledat aktualizace</string>
|
||||
<string name="double_click_translation_option">Překlad na dvojité kliknutí</string>
|
||||
|
|
@ -153,7 +150,6 @@
|
|||
<string name="error_something_went_wrong">Něco se pokazilo.</string>
|
||||
<string name="grant">Povolit</string>
|
||||
<string name="add_book">Přidat knihu</string>
|
||||
<string name="start">Začít</string>
|
||||
<string name="go_back">Zpět</string>
|
||||
<string name="copy">Kopírovat</string>
|
||||
<string name="translate">Přeložit</string>
|
||||
|
|
@ -201,7 +197,6 @@
|
|||
<string name="pink2_theme">Ganymede</string>
|
||||
<string name="cover_image_changed">Obálka byla úspěšně změněna.</string>
|
||||
<string name="history_deleted">Historie byla úspěšně smazána.</string>
|
||||
<string name="move_this_book">Přesunout</string>
|
||||
<string name="slava_ukraini">Sláva Ukrajině!</string>
|
||||
<string name="credits_design">Design</string>
|
||||
<string name="credits_translation">Překlad</string>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
<string name="add">Hinzufügen</string>
|
||||
<string name="add_book">Buch hinzufügen</string>
|
||||
<string name="move">Verschieben</string>
|
||||
<string name="start">Starten</string>
|
||||
<string name="continue_read">Fortfahren</string>
|
||||
<string name="never">Niemals</string>
|
||||
<string name="go_back">Zurück gehen</string>
|
||||
|
|
@ -109,10 +108,7 @@
|
|||
<string name="no_updates">Die neuste Version der App ist bereits installiert.</string>
|
||||
<string name="cover_reset">Das Titelbild wurde erfolgreich zurückgesetzt.</string>
|
||||
<string name="history_element_deleted">Das Verlaufselement wurde erfolgreich gelöscht.</string>
|
||||
<string name="move_this_book">Verschieben</string>
|
||||
<string name="delete_this_book">Löschen</string>
|
||||
<string name="dynamic_theme">Quecksilber</string>
|
||||
<string name="details_book">Details</string>
|
||||
<string name="file_path">Dateipfad</string>
|
||||
<string name="file_last_opened">Zuletzt geöffnete Datei</string>
|
||||
<string name="file_size">Dateigröße</string>
|
||||
|
|
@ -203,7 +199,6 @@
|
|||
<string name="theme_contrast_high">Hoch</string>
|
||||
<string name="font_style_normal">Normal</string>
|
||||
<string name="font_style_italic">Kursiv</string>
|
||||
<string name="file_name">Dateiname</string>
|
||||
<string name="unknown">Unbekannt</string>
|
||||
<string name="app_version_option_desc_2">Klicken Sie hier, um nach Updates zu suchen</string>
|
||||
<string name="whats_new_option">Was ist neu</string>
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@
|
|||
<string name="browse_empty">Expanda la colección de libros de la biblioteca con sus descargas</string>
|
||||
<string name="library_empty">Lea sus libros favoritos y ordénelos en categorías</string>
|
||||
<string name="history_empty">Deje que su último libro leído abra las páginas de una nueva gran historia en su viaje de lectura</string>
|
||||
<string name="start">Iniciar</string>
|
||||
<string name="translate">Traducir</string>
|
||||
<string name="update_query">Actualizar %1$s</string>
|
||||
<string name="grant_permission">Conceder permiso</string>
|
||||
|
|
@ -158,8 +157,6 @@
|
|||
<string name="color_preset_placeholder">Nombrar un preajuste…</string>
|
||||
<string name="book_moved">Este libro se movió correctamente.</string>
|
||||
<string name="history_element_deleted">El elemento del historial se eliminó correctamente.</string>
|
||||
<string name="details_book">Detalles</string>
|
||||
<string name="file_name">Nombre del archivo</string>
|
||||
<string name="file_last_opened">Último archivo abierto</string>
|
||||
<string name="file_size">Tamaño del archivo</string>
|
||||
<string name="unknown">Desconocido</string>
|
||||
|
|
@ -180,8 +177,6 @@
|
|||
<string name="help_desc_how_to_edit_book_2">Biblioteca</string>
|
||||
<string name="help_desc_how_to_edit_book_3">y haz clic en la imagen de la portada del libro para ver los detalles del libro. Ahora puedes mantener presionado el título, el autor o la descripción del libro para editarlo o la imagen de la portada para cambiarla, restablecerla o eliminarla.</string>
|
||||
<string name="help_title_how_to_customize_reader">¿Cómo personalizo el lector?</string>
|
||||
<string name="move_this_book">Mover</string>
|
||||
<string name="delete_this_book">Borrar</string>
|
||||
<string name="file_path">Ruta del archivo</string>
|
||||
<string name="help_desc_how_to_add_books_2">Navegar</string>
|
||||
<string name="whats_new_option">Novedades</string>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
<string name="color_preset_selected_query">Sélectionné « %1$s »</string>
|
||||
<string name="move">Déplacer</string>
|
||||
<string name="delete">Supprimer</string>
|
||||
<string name="start">Commencer</string>
|
||||
<string name="continue_read">Continuer</string>
|
||||
<string name="never">Jamais</string>
|
||||
<string name="go_back">Retour</string>
|
||||
|
|
@ -268,10 +267,6 @@
|
|||
<string name="pure_dark_off">Désactivé</string>
|
||||
<string name="browse_sort_order_file_format">Format de fichier</string>
|
||||
<string name="browse_sort_order_name">Alphabétiquement</string>
|
||||
<string name="move_this_book">Déplacer</string>
|
||||
<string name="delete_this_book">Supprimer</string>
|
||||
<string name="details_book">Détails</string>
|
||||
<string name="file_name">Nom du fichier</string>
|
||||
<string name="app_version_option">Version de l\'application</string>
|
||||
<string name="credits_design">Design</string>
|
||||
<string name="credits_translation">Traduction</string>
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@
|
|||
<string name="color_preset_query">प्रीसेट %1$s</string>
|
||||
<string name="move">हटाना</string>
|
||||
<string name="delete">मिटाना</string>
|
||||
<string name="start">शुरू</string>
|
||||
<string name="reset_cover">कवर छवि रीसेट करें</string>
|
||||
<string name="change_cover">कवर छवि बदलें</string>
|
||||
<string name="dark_theme_option">डार्क थीम</string>
|
||||
|
|
@ -205,9 +204,6 @@
|
|||
<string name="red_color">लाल</string>
|
||||
<string name="no_updates">ऐप का नवीनतम संस्करण पहले से इंस्टॉल है।</string>
|
||||
<string name="cover_reset">कवर छवि सफलतापूर्वक रीसेट कर दी गई।</string>
|
||||
<string name="move_this_book">कदम</string>
|
||||
<string name="delete_this_book">मिटाना</string>
|
||||
<string name="details_book">विवरण</string>
|
||||
<string name="file_path">दस्तावेज पथ</string>
|
||||
<string name="file_last_opened">फ़ाइल अंतिम बार खोली गई</string>
|
||||
<string name="file_size">फ़ाइल का साइज़</string>
|
||||
|
|
@ -235,7 +231,6 @@
|
|||
<string name="help_desc_how_to_add_books_2">ब्राउज़</string>
|
||||
<string name="help_desc_how_to_add_books_4">पुस्तकालय</string>
|
||||
<string name="history_element_deleted">इतिहास तत्व सफलतापूर्वक हटा दिया गया।</string>
|
||||
<string name="file_name">फ़ाइल का नाम</string>
|
||||
<string name="unknown">अज्ञात</string>
|
||||
<string name="report_bug_option">एक बग रिपोर्ट करो</string>
|
||||
<string name="credits_updates">नए अपडेट का प्रबंधन</string>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
<string name="fullscreen_option">Schermo intero</string>
|
||||
<string name="dark_theme_follow_system">Sistema</string>
|
||||
<string name="browse_layout_grid">Griglia</string>
|
||||
<string name="move_this_book">Sposta</string>
|
||||
<string name="no_chapters">Nessun capitolo</string>
|
||||
<string name="chapters">Capitoli</string>
|
||||
<string name="licenses_option">Licenze open source</string>
|
||||
|
|
@ -47,7 +46,6 @@
|
|||
<string name="red_theme">Marte</string>
|
||||
<string name="next">Prossimo</string>
|
||||
<string name="delete">Elimina</string>
|
||||
<string name="start">Inizia</string>
|
||||
<string name="continue_read">Continua</string>
|
||||
<string name="go_back">Indietro</string>
|
||||
<string name="enable">Abilita</string>
|
||||
|
|
@ -101,8 +99,6 @@
|
|||
<string name="browse_sort_order_file_format">Formato file</string>
|
||||
<string name="books_deleted">Tutti i libri selezionati sono stati eliminati correttamente.</string>
|
||||
<string name="screen_orientation_portrait">Ritratto</string>
|
||||
<string name="delete_this_book">Elimina</string>
|
||||
<string name="details_book">Dettagli</string>
|
||||
<string name="books_added">Tutti i libri selezionati sono stati aggiunti correttamente.</string>
|
||||
<string name="delete_book_description">Eliminerà questo libro dal database. Non eliminerà questo libro dal tuo dispositivo.</string>
|
||||
<string name="add_books_description">Puoi scegliere quali libri vuoi aggiungere. È possibile modificare il titolo e l\'immagine di copertina in seguito. Il processo di caricamento può richiedere fino a diversi minuti.</string>
|
||||
|
|
@ -208,7 +204,6 @@
|
|||
<string name="browse_grid_size_per_row">per riga</string>
|
||||
<string name="history_deleted">La cronologia è stata eliminata correttamente.</string>
|
||||
<string name="press_again_toast">Premere di nuovo Indietro per uscire</string>
|
||||
<string name="file_name">Nome del file</string>
|
||||
<string name="file_size">Dimensione del file</string>
|
||||
<string name="help_desc_how_to_add_books_2">Sfoglia</string>
|
||||
<string name="already_read_tab">Già letto</string>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
<string name="cancel">Anuluj</string>
|
||||
<string name="grant">Udziel</string>
|
||||
<string name="delete">Usuń</string>
|
||||
<string name="start">Rozpocznij</string>
|
||||
<string name="add">Dodaj</string>
|
||||
<string name="sort_browse_settings">Sortuj</string>
|
||||
<string name="red_color">Czerwony</string>
|
||||
|
|
@ -179,7 +178,6 @@
|
|||
<string name="help_desc_how_to_read_book_1">Idź do</string>
|
||||
<string name="help_desc_how_to_use_tooltip_1">Większość przycisków ikon ma podpowiedzi, mogą ci pomóc, jeśli nie wiesz, co robi przycisk ikon. Aby wyświetlić podpowiedź, możesz przytrzymać przycisk ikony.</string>
|
||||
<string name="copied">Skopiowano</string>
|
||||
<string name="file_name">Nazwa pliku</string>
|
||||
<string name="file_path">Ścieżka pliku</string>
|
||||
<string name="credits_updates">Zarządzanie nowymi aktualizacjami</string>
|
||||
<string name="credits_fonts">Czcionki</string>
|
||||
|
|
@ -189,7 +187,6 @@
|
|||
<string name="help_desc_how_to_customize_app_3">Możesz to zrobić z poziomu ekranu Biblioteka, Historia i Przeglądaj, klikając trzy kropki w prawym górnym rogu i wybierając « Ustawienia » z menu rozwijanego. Następnie zobaczysz wszystkie dostępne ustawienia tej aplikacji. Eksperymentuj z nimi!</string>
|
||||
<string name="continue_reading_content_desc">Kontynuuj czytanie</string>
|
||||
<string name="github_profile_content_desc">Profil GitHub</string>
|
||||
<string name="move_this_book">Przenieś</string>
|
||||
<string name="help_desc_how_to_customize_reader_1">Zacznij czytać książkę (patrz: Jak mogę przeczytać książkę?), A następnie przynieś górne i dolne paski, klikając w dowolnym miejscu na ekranie. Następnie kliknij ikonę zębatki w prawym górnym rogu. Spowoduje to wyświetlenie wszystkich ustawień Czytnika. Drugim sposobem jest przejście do</string>
|
||||
<string name="color_preset_placeholder">Nazwij ustawienie…</string>
|
||||
<string name="browse_grid_size_option">Rozmiar siatki</string>
|
||||
|
|
@ -265,12 +262,10 @@
|
|||
<string name="app_version_option_desc_2">Kliknij, aby sprawdzić aktualizacje</string>
|
||||
<string name="help_desc_how_to_add_books_3">Jeśli nie widzisz pobranych książek, spróbuj odświeżyć listę, przeciągając ją w dół. Upewnij się, że Twoje książki posiadają obsługiwany format pliku. Następnie kliknij książkę, aby ją wybrać lub przytrzymaj, aby pokazać jej lokalizację. Po wybraniu wszystkich książek, które chcesz, kliknij ikonę znacznika wyboru w prawym górnym rogu, poczekaj na załadowanie wszystkich książek i kliknij « Dodaj ». Teraz powinieneś zobaczyć wszystkie książki, które dodałeś do</string>
|
||||
<string name="history_content_desc">Historia czytania</string>
|
||||
<string name="delete_this_book">Usuń</string>
|
||||
<string name="exit_search_content_desc">Opuść wyszukiwanie</string>
|
||||
<string name="books_moved">Wszystkie wybrane książki zostały pomyślnie przeniesione.</string>
|
||||
<string name="delete_whole_history_content_desc">Usuń całą historię</string>
|
||||
<string name="help_desc_how_to_add_books_2">Przeglądaj</string>
|
||||
<string name="details_book">Szczegóły</string>
|
||||
<string name="help_desc_how_to_add_books_4">Biblioteka</string>
|
||||
<string name="help_desc_how_to_customize_app_1">Idź do</string>
|
||||
<string name="help_desc_how_to_customize_app_2">Ustawienia</string>
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@
|
|||
<string name="updates_notification_title">Novo update do Book\'s Story!</string>
|
||||
<string name="add_books">Adicionar livros?</string>
|
||||
<string name="storage_permission_description">Precisamos de permissão de acesso ao armazenamento para procurar livros no seu dispositivo. Sem essa permissão, você não será capaz de adicionar um livro.</string>
|
||||
<string name="start">Começar</string>
|
||||
<string name="delete">Apagar</string>
|
||||
<string name="undo">Desfazer</string>
|
||||
<string name="sort_tab">Organizar</string>
|
||||
|
|
@ -92,8 +91,6 @@
|
|||
<string name="marsh_theme">Plutão</string>
|
||||
<string name="yellow_theme">Vênus</string>
|
||||
<string name="aqua_theme">Urano</string>
|
||||
<string name="move_this_book">Mover</string>
|
||||
<string name="delete_this_book">Apague</string>
|
||||
<string name="unknown">Desconhecido</string>
|
||||
<string name="credits_option">Créditos</string>
|
||||
<string name="chapters">Capítulos</string>
|
||||
|
|
@ -119,7 +116,6 @@
|
|||
<string name="move_books_description">Escolha a categoria da qual você quer mover todos os livros selecionados(%1$s). Todos os livros selecionados serão movidos para essa categoria.</string>
|
||||
<string name="delete_books_description">Isto irá apagar todos os livros selecionados(%1$s) da base de dados. Isso não irá apagar os livros do seu dispositivo.</string>
|
||||
<string name="alignment_center">Centro</string>
|
||||
<string name="details_book">Detalhes</string>
|
||||
<string name="help_desc_how_to_customize_reader_2">Configurações</string>
|
||||
<string name="revert_content_desc">Reverter</string>
|
||||
<string name="start_permissions_granted">Permitir</string>
|
||||
|
|
@ -142,7 +138,6 @@
|
|||
<string name="delete_history_description">Isto irá deletar todo o histórico da base de dados. Após deletá-lo, a ordem dos livros será restaurada.</string>
|
||||
<string name="paragraph_indentation_option">Recuo de parágrafo</string>
|
||||
<string name="letter_spacing_option">Espaçamento das letras</string>
|
||||
<string name="file_name">Nome do arquivo</string>
|
||||
<string name="color_preset_query">Padrão %1$s</string>
|
||||
<string name="go_back">Voltar</string>
|
||||
<string name="proceed">Proceder</string>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
<string name="book_deleted">இந்த நூல் வெற்றிகரமாக நீக்கப்பட்டது.</string>
|
||||
<string name="book_moved">இந்த நூல் வெற்றிகரமாக நகர்த்தப்பட்டது.</string>
|
||||
<string name="copied">நகலெடுக்கப்பட்டது</string>
|
||||
<string name="move_this_book">நகர்த்தவும்</string>
|
||||
<string name="history_element_deleted">வரலாற்று உறுப்பு வெற்றிகரமாக நீக்கப்பட்டது.</string>
|
||||
<string name="credits_translation">மொழிபெயர்ப்பு</string>
|
||||
<string name="credits_contribution">பங்களிப்பு</string>
|
||||
|
|
@ -101,12 +100,10 @@
|
|||
<string name="continue_read">தொடரவும்</string>
|
||||
<string name="history_empty">நீங்கள் படித்த உங்கள் கடைசி நூல் உங்கள் வாசிப்பு பயணத்தின் புதிய சிறந்த கதையின் பக்கங்களைத் திறக்கட்டும்</string>
|
||||
<string name="share">பங்கு</string>
|
||||
<string name="start">தொடங்கு</string>
|
||||
<string name="start_permissions_preferences">அனுமதிகள்</string>
|
||||
<string name="never">ஒருபோதும்</string>
|
||||
<string name="browse_layout_option">காட்சி முறை</string>
|
||||
<string name="browse_sort_order_file_format">கோப்பு வடிவம்</string>
|
||||
<string name="delete_this_book">நீக்கு</string>
|
||||
<string name="default_string">இயல்புநிலை</string>
|
||||
<string name="delete_history">வாசிப்பு வரலாற்றை நீக்கவா?</string>
|
||||
<string name="enable_check_for_updates_description">செயல்படுத்துவதன் மூலம் «புதுப்பிப்புகளைச் சரிபார்க்கவும்» பயன்பாடு தொடங்கும் ஒவ்வொரு முறையும் «api.github.com இருந்து இலிருந்து அண்மைக் கால வெளியீட்டு தகவல்களை மீட்டெடுக்கும். நீங்கள் தொடர விரும்புகிறீர்களா «புதுப்பிப்புகளை சரிபார்க்கவும்»?</string>
|
||||
|
|
@ -273,8 +270,6 @@
|
|||
<string name="history_deleted">வரலாறு வெற்றிகரமாக நீக்கப்பட்டது.</string>
|
||||
<string name="no_updates">பயன்பாட்டின் அண்மைக் கால பதிப்பு ஏற்கனவே நிறுவப்பட்டுள்ளது.</string>
|
||||
<string name="cover_reset">கவர் படம் வெற்றிகரமாக மீட்டமைக்கப்பட்டது.</string>
|
||||
<string name="details_book">விவரங்கள்</string>
|
||||
<string name="file_name">கோப்பு பெயர்</string>
|
||||
<string name="file_path">கோப்பு பாதை</string>
|
||||
<string name="file_last_opened">கோப்பு கடைசியாக திறக்கப்பட்டது</string>
|
||||
<string name="file_size">கோப்பு அளவு</string>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@
|
|||
<string name="add_book">Kitap ekle</string>
|
||||
<string name="move">Taşı</string>
|
||||
<string name="delete">Sil</string>
|
||||
<string name="start">Başla</string>
|
||||
<string name="continue_read">Devam Et</string>
|
||||
<string name="never">Asla</string>
|
||||
<string name="go_back">Geri Dön</string>
|
||||
|
|
@ -180,10 +179,6 @@
|
|||
<string name="no_updates">Uygulamanın en son sürümü zaten yüklü.</string>
|
||||
<string name="cover_reset">Kapak resmi başarıyla sıfırlandı.</string>
|
||||
<string name="history_element_deleted">Geçmiş öğesi başarıyla silindi.</string>
|
||||
<string name="move_this_book">Taşı</string>
|
||||
<string name="delete_this_book">Sil</string>
|
||||
<string name="details_book">Ayrıntılar</string>
|
||||
<string name="file_name">Dosya adı</string>
|
||||
<string name="file_path">Dosya yolu</string>
|
||||
<string name="file_last_opened">Son açılma tarihi</string>
|
||||
<string name="file_size">Dosya boyutu</string>
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
<string name="error_check_internet">Щось пішло не так. Спробуйте пізніше.</string>
|
||||
<string name="error_could_not_reset_cover">Не вдалося скинути обкладинку.</string>
|
||||
<string name="error_closed_source">Закритий код</string>
|
||||
<string name="error_no_file">Файла не існує</string>
|
||||
|
||||
<!-- Is Empty messages -->
|
||||
<string name="search_field_empty">Пошук…</string>
|
||||
|
|
@ -72,7 +73,6 @@
|
|||
<string name="add_book">Додати книгу</string>
|
||||
<string name="move">Перемістити</string>
|
||||
<string name="delete">Видалити</string>
|
||||
<string name="start">Почати</string>
|
||||
<string name="continue_read">Продовжити</string>
|
||||
<string name="never">Ніколи</string>
|
||||
<string name="go_back">Назад</string>
|
||||
|
|
@ -88,6 +88,7 @@
|
|||
<string name="web_search">Веб-пошук</string>
|
||||
<string name="share">Поділитися</string>
|
||||
<string name="proceed">Продовжити</string>
|
||||
<string name="ok">ОК</string>
|
||||
|
||||
<!-- Book -->
|
||||
<string name="unknown_author">Невідомий</string>
|
||||
|
|
@ -320,20 +321,21 @@
|
|||
<string name="history_deleted">Історія була успішно видалена.</string>
|
||||
<string name="no_updates">Остання версія застосунка вже встановлена.</string>
|
||||
<string name="cover_reset">Обкладинка була успішно скинута.</string>
|
||||
<string name="title_changed">Назва була успішно змінена.</string>
|
||||
<string name="author_changed">Автор був успішно змінений.</string>
|
||||
<string name="description_changed">Опис був успішно змінений.</string>
|
||||
|
||||
<!-- Snackbar messages -->
|
||||
<string name="history_element_deleted">Елемент історії був успішно видалений.</string>
|
||||
|
||||
<!-- DropDown properties -->
|
||||
<string name="move_this_book">Перемістити</string>
|
||||
<string name="delete_this_book">Видалити</string>
|
||||
<string name="details_book">Подробиці</string>
|
||||
|
||||
<!-- BookInfo details -->
|
||||
<string name="file_name">Ім\'я файлу</string>
|
||||
<string name="file_path">Шлях до файлу</string>
|
||||
<string name="file_last_opened">Останнє відкриття файлу</string>
|
||||
<string name="file_size">Розмір файлу</string>
|
||||
<!-- BookInfo -->
|
||||
<string name="start_reading">Почати</string>
|
||||
<string name="continue_reading_query">Продовжити з %1$s</string>
|
||||
<string name="file_details">Подробиці файла</string>
|
||||
<string name="file_path">Шлях</string>
|
||||
<string name="file_last_opened">Останнє відкриття</string>
|
||||
<string name="file_size">Розмір</string>
|
||||
<string name="unknown">Невідомо</string>
|
||||
|
||||
<!-- Browse -->
|
||||
|
|
@ -475,5 +477,8 @@
|
|||
<string name="chapters_content_desc">Розділи</string>
|
||||
<string name="more_content_desc">Більше</string>
|
||||
<string name="pin_content_desc">Закріпити</string>
|
||||
<string name="show_less_content_desc">Показати менше</string>
|
||||
<string name="show_more_content_desc">Показати більше</string>
|
||||
<string name="edit_content_desc">Редагувати поле</string>
|
||||
|
||||
</resources>
|
||||
|
|
@ -74,7 +74,6 @@
|
|||
<string name="translate">翻译</string>
|
||||
<string name="copy">复制</string>
|
||||
<string name="selected_items_count_query">已选择 %1$s</string>
|
||||
<string name="start">开始</string>
|
||||
<string name="enable_check_for_updates">启用检查更新?</string>
|
||||
<string name="delete_books">删除书籍?</string>
|
||||
<string name="updates_notification_channel">新更新</string>
|
||||
|
|
@ -204,8 +203,6 @@
|
|||
<string name="cover_image_changed">成功更改了封面图片。</string>
|
||||
<string name="history_element_deleted">成功删除了历史元素。</string>
|
||||
<string name="books_moved">成功移动所有已选择的书。</string>
|
||||
<string name="move_this_book">移动</string>
|
||||
<string name="file_name">文件名</string>
|
||||
<string name="no_chapters">无章节</string>
|
||||
<string name="chapters">章节</string>
|
||||
<string name="app_version_option">应用版本</string>
|
||||
|
|
@ -231,10 +228,8 @@
|
|||
<string name="credits_translation">翻译</string>
|
||||
<string name="help_desc_how_to_add_books_3">如果你没有看见已下载的书可以尝试下拉刷新列表。确保你的书拥有所支持的文件格式。点击书来选择它或者按住来显示它的位置。当你选择了所有想选择的书之后,点击右上角的对勾图标,等待所有的书加载好后点击“添加”。所有你已经添加的书都应该显示在</string>
|
||||
<string name="file_size">文件大小</string>
|
||||
<string name="details_book">详细</string>
|
||||
<string name="whats_new_option">新内容</string>
|
||||
<string name="licenses_option">开源许可证</string>
|
||||
<string name="delete_this_book">删除</string>
|
||||
<string name="pure_dark_power_saver">保存</string>
|
||||
<string name="custom_screen_brightness_option">自定义亮度</string>
|
||||
<string name="screen_brightness_option">亮度</string>
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@
|
|||
</string>
|
||||
<string name="error_could_not_reset_cover">Could not reset cover image.</string>
|
||||
<string name="error_closed_source">Closed source</string>
|
||||
<string name="error_no_file">File does not exist</string>
|
||||
|
||||
<!-- Is Empty messages -->
|
||||
<string name="search_field_empty">
|
||||
|
|
@ -128,7 +129,6 @@
|
|||
<string name="add_book">Add a book</string>
|
||||
<string name="move">Move</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="start">Start</string>
|
||||
<string name="continue_read">Continue</string>
|
||||
<string name="never">Never</string>
|
||||
<string name="go_back">Go back</string>
|
||||
|
|
@ -379,20 +379,20 @@
|
|||
<string name="history_deleted">History was successfully deleted.</string>
|
||||
<string name="no_updates">The latest version of the app is already installed.</string>
|
||||
<string name="cover_reset">Cover image was successfully reset.</string>
|
||||
<string name="title_changed">Title was successfully changed.</string>
|
||||
<string name="author_changed">Author was successfully changed.</string>
|
||||
<string name="description_changed">Description was successfully changed.</string>
|
||||
|
||||
<!-- Snackbar messages -->
|
||||
<string name="history_element_deleted">History element was successfully deleted.</string>
|
||||
|
||||
<!-- DropDown properties -->
|
||||
<string name="move_this_book">Move</string>
|
||||
<string name="delete_this_book">Delete</string>
|
||||
<string name="details_book">Details</string>
|
||||
|
||||
<!-- BookInfo details -->
|
||||
<string name="file_name">File name</string>
|
||||
<string name="file_path">File path</string>
|
||||
<string name="file_last_opened">File last opened</string>
|
||||
<string name="file_size">File size</string>
|
||||
<!-- BookInfo -->
|
||||
<string name="start_reading">Start</string>
|
||||
<string name="continue_reading_query">Continue from %1$s</string>
|
||||
<string name="file_details">File details</string>
|
||||
<string name="file_path">Path</string>
|
||||
<string name="file_last_opened">Last opened</string>
|
||||
<string name="file_size">Size</string>
|
||||
<string name="unknown">Unknown</string>
|
||||
|
||||
<!-- Reader -->
|
||||
|
|
@ -637,5 +637,8 @@
|
|||
<string name="chapters_content_desc">Chapters</string>
|
||||
<string name="more_content_desc">More</string>
|
||||
<string name="pin_content_desc">Pin</string>
|
||||
<string name="show_less_content_desc">Show less</string>
|
||||
<string name="show_more_content_desc">Show more</string>
|
||||
<string name="edit_content_desc">Edit field</string>
|
||||
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue