diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryEvent.kt index 432712e8..5c800cab 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryEvent.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryEvent.kt @@ -8,6 +8,7 @@ package ua.acclorite.book_story.presentation.library import androidx.compose.runtime.Immutable import ua.acclorite.book_story.domain.model.library.Category +import ua.acclorite.book_story.presentation.library.model.SelectableBook @Immutable sealed class LibraryEvent { @@ -35,6 +36,10 @@ sealed class LibraryEvent { val select: Boolean? = null ) : LibraryEvent() + data class OnSelectBooks( + val books: List + ) : LibraryEvent() + data object OnShowMoveDialog : LibraryEvent() data class OnActionMoveDialog( diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryModel.kt index 44ae6c10..1a1ecf88 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryModel.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryModel.kt @@ -191,6 +191,25 @@ class LibraryModel @Inject constructor( } } + is LibraryEvent.OnSelectBooks -> { + withContext(Dispatchers.Default) { + val editedList = _state.value.books.map { book -> + if (event.books.any { book.data.id == it.data.id }) book.copy( + selected = if (event.books.size > 1) true else !book.selected + ) + else book + } + + _state.update { + it.copy( + books = editedList, + selectedItemsCount = editedList.filter { book -> book.selected }.size, + hasSelectedItems = editedList.any { book -> book.selected } + ) + } + } + } + is LibraryEvent.OnShowMoveDialog -> { _state.update { it.copy( diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryScreen.kt b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryScreen.kt index c5c3d18b..6e1fb218 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryScreen.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/library/LibraryScreen.kt @@ -71,7 +71,6 @@ object LibraryScreen : Screen, Parcelable { state.value.books.any { book -> book.data.categories.none { category -> category in categoryIds } } || categories.isEmpty() || settings.libraryShowDefaultTab.lastValue - } } @@ -142,6 +141,7 @@ object LibraryScreen : Screen, Parcelable { requestFocus = screenModel::onEvent, searchQueryChange = screenModel::onEvent, search = screenModel::onEvent, + selectBooks = screenModel::onEvent, clearSelectedBooks = screenModel::onEvent, showMoveDialog = screenModel::onEvent, actionMoveDialog = screenModel::onEvent, diff --git a/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryContent.kt b/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryContent.kt index 1eb00027..13548dfe 100644 --- a/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryContent.kt +++ b/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryContent.kt @@ -59,6 +59,7 @@ fun LibraryContent( requestFocus: (LibraryEvent.OnRequestFocus) -> Unit, searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit, search: (LibraryEvent.OnSearch) -> Unit, + selectBooks: (LibraryEvent.OnSelectBooks) -> Unit, clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit, showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit, showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit, @@ -126,6 +127,7 @@ fun LibraryContent( searchQueryChange = searchQueryChange, search = search, selectBook = selectBook, + selectBooks = selectBooks, clearSelectedBooks = clearSelectedBooks, showMoveDialog = showMoveDialog, showDeleteDialog = showDeleteDialog, diff --git a/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryScaffold.kt b/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryScaffold.kt index 63824699..0aeab026 100644 --- a/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryScaffold.kt +++ b/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryScaffold.kt @@ -57,6 +57,7 @@ fun LibraryScaffold( requestFocus: (LibraryEvent.OnRequestFocus) -> Unit, searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit, search: (LibraryEvent.OnSearch) -> Unit, + selectBooks: (LibraryEvent.OnSelectBooks) -> Unit, clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit, showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit, showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit, @@ -90,6 +91,7 @@ fun LibraryScaffold( requestFocus = requestFocus, searchQueryChange = searchQueryChange, search = search, + selectBooks = selectBooks, clearSelectedBooks = clearSelectedBooks, showMoveDialog = showMoveDialog, showDeleteDialog = showDeleteDialog, diff --git a/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryTabs.kt b/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryTabs.kt index 9ea5a29b..ee8b679d 100644 --- a/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryTabs.kt +++ b/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryTabs.kt @@ -30,11 +30,12 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch import ua.acclorite.book_story.domain.model.library.Category +import ua.acclorite.book_story.presentation.library.model.SelectableBook import ua.acclorite.book_story.ui.common.components.common.StyledText @Composable fun LibraryTabs( - categoriesWithBookCount: List>, + categoriesWithBooks: List>>, pagerState: PagerState, itemCountBackgroundColor: Color, showBookCount: Boolean @@ -70,7 +71,7 @@ fun LibraryTabs( } } ) { - categoriesWithBookCount.forEachIndexed { index, tabItem -> + categoriesWithBooks.forEachIndexed { index, tabItem -> Tab( selected = pagerState.currentPage == index, onClick = { @@ -91,7 +92,7 @@ fun LibraryTabs( if (showBookCount) { Spacer(modifier = Modifier.width(6.dp)) StyledText( - text = tabItem.second.toString(), + text = tabItem.second.size.toString(), modifier = Modifier .background( itemCountBackgroundColor, diff --git a/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryTopBar.kt b/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryTopBar.kt index 79ee45c8..70bea7df 100644 --- a/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryTopBar.kt +++ b/app/src/main/java/ua/acclorite/book_story/ui/library/LibraryTopBar.kt @@ -23,6 +23,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.FilterList import androidx.compose.material.icons.filled.Search +import androidx.compose.material.icons.filled.SelectAll import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.MoveUp import androidx.compose.material3.ExperimentalMaterial3Api @@ -72,13 +73,14 @@ fun LibraryTopBar( requestFocus: (LibraryEvent.OnRequestFocus) -> Unit, searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit, search: (LibraryEvent.OnSearch) -> Unit, + selectBooks: (LibraryEvent.OnSelectBooks) -> Unit, clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit, showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit, showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit, showFilterBottomSheet: (LibraryEvent.OnShowFilterBottomSheet) -> Unit ) { val defaultCategory = stringResource(id = R.string.default_tab) - val categoriesWithBookCount = remember( + val categoriesWithBooks = remember( books, categories, showDefaultCategory, @@ -86,7 +88,7 @@ fun LibraryTopBar( ) { derivedStateOf { categories.filterNot { it.id == -1 }.map { category -> - category to books.count { it.data.categories.any { it == category.id } } + category to books.filter { it.data.categories.any { it == category.id } } }.toMutableList().apply { if (showDefaultCategory) { val categoryIds = categories.map { it.id }.toSet() @@ -95,7 +97,7 @@ fun LibraryTopBar( Category( id = -1, title = defaultCategory - ) to books.count { book -> + ) to books.filter { book -> book.data.categories.none { category -> category in categoryIds } } ) @@ -103,9 +105,9 @@ fun LibraryTopBar( }.toList() } } - val currentCategory = remember(pagerState.currentPage, categoriesWithBookCount) { + val currentCategory = remember(pagerState.currentPage, categoriesWithBooks) { derivedStateOf { - categoriesWithBookCount.value[pagerState.currentPage] + categoriesWithBooks.value[pagerState.currentPage] } } @@ -226,6 +228,17 @@ fun LibraryTopBar( ) }, contentActions = { + IconButton( + icon = Icons.Default.SelectAll, + contentDescription = R.string.select_all_books_content_desc, + disableOnClick = false, + ) { + selectBooks( + LibraryEvent.OnSelectBooks( + books = currentCategory.value.second + ) + ) + } IconButton( icon = Icons.Outlined.MoveUp, contentDescription = R.string.move_books_content_desc, @@ -252,7 +265,7 @@ fun LibraryTopBar( exit = shrinkVertically() ) { LibraryTabs( - categoriesWithBookCount = categoriesWithBookCount.value, + categoriesWithBooks = categoriesWithBooks.value, pagerState = pagerState, itemCountBackgroundColor = animatedItemCountBackgroundColor.value, showBookCount = showBookCount diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index ea16e25b..9e1c29ae 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -475,6 +475,7 @@ Очистити обрані предмети Додати файли Вибрати всі файли + Вибрати всі книги Вийти з пошуку Видалити всю історію Перемістити обрані книги diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d431b9e5..70915486 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -611,6 +611,7 @@ Clear selected items Add files Select all files + Select all books Exit search Delete whole history Move selected books