feat: select all books button in library
* Added "Select all books" button to the Library which selects all books in the current category
This commit is contained in:
parent
14cf04a8ce
commit
30ee74cfff
9 changed files with 54 additions and 10 deletions
|
|
@ -8,6 +8,7 @@ package ua.acclorite.book_story.presentation.library
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import ua.acclorite.book_story.domain.model.library.Category
|
import ua.acclorite.book_story.domain.model.library.Category
|
||||||
|
import ua.acclorite.book_story.presentation.library.model.SelectableBook
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
sealed class LibraryEvent {
|
sealed class LibraryEvent {
|
||||||
|
|
@ -35,6 +36,10 @@ sealed class LibraryEvent {
|
||||||
val select: Boolean? = null
|
val select: Boolean? = null
|
||||||
) : LibraryEvent()
|
) : LibraryEvent()
|
||||||
|
|
||||||
|
data class OnSelectBooks(
|
||||||
|
val books: List<SelectableBook>
|
||||||
|
) : LibraryEvent()
|
||||||
|
|
||||||
data object OnShowMoveDialog : LibraryEvent()
|
data object OnShowMoveDialog : LibraryEvent()
|
||||||
|
|
||||||
data class OnActionMoveDialog(
|
data class OnActionMoveDialog(
|
||||||
|
|
|
||||||
|
|
@ -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 -> {
|
is LibraryEvent.OnShowMoveDialog -> {
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,6 @@ object LibraryScreen : Screen, Parcelable {
|
||||||
state.value.books.any { book ->
|
state.value.books.any { book ->
|
||||||
book.data.categories.none { category -> category in categoryIds }
|
book.data.categories.none { category -> category in categoryIds }
|
||||||
} || categories.isEmpty() || settings.libraryShowDefaultTab.lastValue
|
} || categories.isEmpty() || settings.libraryShowDefaultTab.lastValue
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,6 +141,7 @@ object LibraryScreen : Screen, Parcelable {
|
||||||
requestFocus = screenModel::onEvent,
|
requestFocus = screenModel::onEvent,
|
||||||
searchQueryChange = screenModel::onEvent,
|
searchQueryChange = screenModel::onEvent,
|
||||||
search = screenModel::onEvent,
|
search = screenModel::onEvent,
|
||||||
|
selectBooks = screenModel::onEvent,
|
||||||
clearSelectedBooks = screenModel::onEvent,
|
clearSelectedBooks = screenModel::onEvent,
|
||||||
showMoveDialog = screenModel::onEvent,
|
showMoveDialog = screenModel::onEvent,
|
||||||
actionMoveDialog = screenModel::onEvent,
|
actionMoveDialog = screenModel::onEvent,
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ fun LibraryContent(
|
||||||
requestFocus: (LibraryEvent.OnRequestFocus) -> Unit,
|
requestFocus: (LibraryEvent.OnRequestFocus) -> Unit,
|
||||||
searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit,
|
searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit,
|
||||||
search: (LibraryEvent.OnSearch) -> Unit,
|
search: (LibraryEvent.OnSearch) -> Unit,
|
||||||
|
selectBooks: (LibraryEvent.OnSelectBooks) -> Unit,
|
||||||
clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit,
|
clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit,
|
||||||
showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit,
|
showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit,
|
||||||
showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit,
|
showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit,
|
||||||
|
|
@ -126,6 +127,7 @@ fun LibraryContent(
|
||||||
searchQueryChange = searchQueryChange,
|
searchQueryChange = searchQueryChange,
|
||||||
search = search,
|
search = search,
|
||||||
selectBook = selectBook,
|
selectBook = selectBook,
|
||||||
|
selectBooks = selectBooks,
|
||||||
clearSelectedBooks = clearSelectedBooks,
|
clearSelectedBooks = clearSelectedBooks,
|
||||||
showMoveDialog = showMoveDialog,
|
showMoveDialog = showMoveDialog,
|
||||||
showDeleteDialog = showDeleteDialog,
|
showDeleteDialog = showDeleteDialog,
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ fun LibraryScaffold(
|
||||||
requestFocus: (LibraryEvent.OnRequestFocus) -> Unit,
|
requestFocus: (LibraryEvent.OnRequestFocus) -> Unit,
|
||||||
searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit,
|
searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit,
|
||||||
search: (LibraryEvent.OnSearch) -> Unit,
|
search: (LibraryEvent.OnSearch) -> Unit,
|
||||||
|
selectBooks: (LibraryEvent.OnSelectBooks) -> Unit,
|
||||||
clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit,
|
clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit,
|
||||||
showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit,
|
showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit,
|
||||||
showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit,
|
showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit,
|
||||||
|
|
@ -90,6 +91,7 @@ fun LibraryScaffold(
|
||||||
requestFocus = requestFocus,
|
requestFocus = requestFocus,
|
||||||
searchQueryChange = searchQueryChange,
|
searchQueryChange = searchQueryChange,
|
||||||
search = search,
|
search = search,
|
||||||
|
selectBooks = selectBooks,
|
||||||
clearSelectedBooks = clearSelectedBooks,
|
clearSelectedBooks = clearSelectedBooks,
|
||||||
showMoveDialog = showMoveDialog,
|
showMoveDialog = showMoveDialog,
|
||||||
showDeleteDialog = showDeleteDialog,
|
showDeleteDialog = showDeleteDialog,
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,12 @@ import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ua.acclorite.book_story.domain.model.library.Category
|
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
|
import ua.acclorite.book_story.ui.common.components.common.StyledText
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibraryTabs(
|
fun LibraryTabs(
|
||||||
categoriesWithBookCount: List<Pair<Category, Int>>,
|
categoriesWithBooks: List<Pair<Category, List<SelectableBook>>>,
|
||||||
pagerState: PagerState,
|
pagerState: PagerState,
|
||||||
itemCountBackgroundColor: Color,
|
itemCountBackgroundColor: Color,
|
||||||
showBookCount: Boolean
|
showBookCount: Boolean
|
||||||
|
|
@ -70,7 +71,7 @@ fun LibraryTabs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
categoriesWithBookCount.forEachIndexed { index, tabItem ->
|
categoriesWithBooks.forEachIndexed { index, tabItem ->
|
||||||
Tab(
|
Tab(
|
||||||
selected = pagerState.currentPage == index,
|
selected = pagerState.currentPage == index,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
@ -91,7 +92,7 @@ fun LibraryTabs(
|
||||||
if (showBookCount) {
|
if (showBookCount) {
|
||||||
Spacer(modifier = Modifier.width(6.dp))
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
StyledText(
|
StyledText(
|
||||||
text = tabItem.second.toString(),
|
text = tabItem.second.size.toString(),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(
|
.background(
|
||||||
itemCountBackgroundColor,
|
itemCountBackgroundColor,
|
||||||
|
|
|
||||||
|
|
@ -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.Clear
|
||||||
import androidx.compose.material.icons.filled.FilterList
|
import androidx.compose.material.icons.filled.FilterList
|
||||||
import androidx.compose.material.icons.filled.Search
|
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.Delete
|
||||||
import androidx.compose.material.icons.outlined.MoveUp
|
import androidx.compose.material.icons.outlined.MoveUp
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
|
@ -72,13 +73,14 @@ fun LibraryTopBar(
|
||||||
requestFocus: (LibraryEvent.OnRequestFocus) -> Unit,
|
requestFocus: (LibraryEvent.OnRequestFocus) -> Unit,
|
||||||
searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit,
|
searchQueryChange: (LibraryEvent.OnSearchQueryChange) -> Unit,
|
||||||
search: (LibraryEvent.OnSearch) -> Unit,
|
search: (LibraryEvent.OnSearch) -> Unit,
|
||||||
|
selectBooks: (LibraryEvent.OnSelectBooks) -> Unit,
|
||||||
clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit,
|
clearSelectedBooks: (LibraryEvent.OnClearSelectedBooks) -> Unit,
|
||||||
showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit,
|
showMoveDialog: (LibraryEvent.OnShowMoveDialog) -> Unit,
|
||||||
showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit,
|
showDeleteDialog: (LibraryEvent.OnShowDeleteDialog) -> Unit,
|
||||||
showFilterBottomSheet: (LibraryEvent.OnShowFilterBottomSheet) -> Unit
|
showFilterBottomSheet: (LibraryEvent.OnShowFilterBottomSheet) -> Unit
|
||||||
) {
|
) {
|
||||||
val defaultCategory = stringResource(id = R.string.default_tab)
|
val defaultCategory = stringResource(id = R.string.default_tab)
|
||||||
val categoriesWithBookCount = remember(
|
val categoriesWithBooks = remember(
|
||||||
books,
|
books,
|
||||||
categories,
|
categories,
|
||||||
showDefaultCategory,
|
showDefaultCategory,
|
||||||
|
|
@ -86,7 +88,7 @@ fun LibraryTopBar(
|
||||||
) {
|
) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
categories.filterNot { it.id == -1 }.map { category ->
|
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 {
|
}.toMutableList().apply {
|
||||||
if (showDefaultCategory) {
|
if (showDefaultCategory) {
|
||||||
val categoryIds = categories.map { it.id }.toSet()
|
val categoryIds = categories.map { it.id }.toSet()
|
||||||
|
|
@ -95,7 +97,7 @@ fun LibraryTopBar(
|
||||||
Category(
|
Category(
|
||||||
id = -1,
|
id = -1,
|
||||||
title = defaultCategory
|
title = defaultCategory
|
||||||
) to books.count { book ->
|
) to books.filter { book ->
|
||||||
book.data.categories.none { category -> category in categoryIds }
|
book.data.categories.none { category -> category in categoryIds }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -103,9 +105,9 @@ fun LibraryTopBar(
|
||||||
}.toList()
|
}.toList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val currentCategory = remember(pagerState.currentPage, categoriesWithBookCount) {
|
val currentCategory = remember(pagerState.currentPage, categoriesWithBooks) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
categoriesWithBookCount.value[pagerState.currentPage]
|
categoriesWithBooks.value[pagerState.currentPage]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,6 +228,17 @@ fun LibraryTopBar(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
contentActions = {
|
contentActions = {
|
||||||
|
IconButton(
|
||||||
|
icon = Icons.Default.SelectAll,
|
||||||
|
contentDescription = R.string.select_all_books_content_desc,
|
||||||
|
disableOnClick = false,
|
||||||
|
) {
|
||||||
|
selectBooks(
|
||||||
|
LibraryEvent.OnSelectBooks(
|
||||||
|
books = currentCategory.value.second
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
IconButton(
|
IconButton(
|
||||||
icon = Icons.Outlined.MoveUp,
|
icon = Icons.Outlined.MoveUp,
|
||||||
contentDescription = R.string.move_books_content_desc,
|
contentDescription = R.string.move_books_content_desc,
|
||||||
|
|
@ -252,7 +265,7 @@ fun LibraryTopBar(
|
||||||
exit = shrinkVertically()
|
exit = shrinkVertically()
|
||||||
) {
|
) {
|
||||||
LibraryTabs(
|
LibraryTabs(
|
||||||
categoriesWithBookCount = categoriesWithBookCount.value,
|
categoriesWithBooks = categoriesWithBooks.value,
|
||||||
pagerState = pagerState,
|
pagerState = pagerState,
|
||||||
itemCountBackgroundColor = animatedItemCountBackgroundColor.value,
|
itemCountBackgroundColor = animatedItemCountBackgroundColor.value,
|
||||||
showBookCount = showBookCount
|
showBookCount = showBookCount
|
||||||
|
|
|
||||||
|
|
@ -475,6 +475,7 @@
|
||||||
<string name="clear_selected_items_content_desc">Очистити обрані предмети</string>
|
<string name="clear_selected_items_content_desc">Очистити обрані предмети</string>
|
||||||
<string name="add_files_content_desc">Додати файли</string>
|
<string name="add_files_content_desc">Додати файли</string>
|
||||||
<string name="select_all_files_content_desc">Вибрати всі файли</string>
|
<string name="select_all_files_content_desc">Вибрати всі файли</string>
|
||||||
|
<string name="select_all_books_content_desc">Вибрати всі книги</string>
|
||||||
<string name="exit_search_content_desc">Вийти з пошуку</string>
|
<string name="exit_search_content_desc">Вийти з пошуку</string>
|
||||||
<string name="delete_whole_history_content_desc">Видалити всю історію</string>
|
<string name="delete_whole_history_content_desc">Видалити всю історію</string>
|
||||||
<string name="move_books_content_desc">Перемістити обрані книги</string>
|
<string name="move_books_content_desc">Перемістити обрані книги</string>
|
||||||
|
|
|
||||||
|
|
@ -611,6 +611,7 @@
|
||||||
<string name="clear_selected_items_content_desc">Clear selected items</string>
|
<string name="clear_selected_items_content_desc">Clear selected items</string>
|
||||||
<string name="add_files_content_desc">Add files</string>
|
<string name="add_files_content_desc">Add files</string>
|
||||||
<string name="select_all_files_content_desc">Select all files</string>
|
<string name="select_all_files_content_desc">Select all files</string>
|
||||||
|
<string name="select_all_books_content_desc">Select all books</string>
|
||||||
<string name="exit_search_content_desc">Exit search</string>
|
<string name="exit_search_content_desc">Exit search</string>
|
||||||
<string name="delete_whole_history_content_desc">Delete whole history</string>
|
<string name="delete_whole_history_content_desc">Delete whole history</string>
|
||||||
<string name="move_books_content_desc">Move selected books</string>
|
<string name="move_books_content_desc">Move selected books</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue