修复分组下拉加载设置不同时,互相滑动会卡住的问题
This commit is contained in:
@@ -19,19 +19,21 @@ import androidx.compose.animation.core.FastOutSlowInEasing
|
|||||||
import androidx.compose.animation.core.SeekableTransitionState
|
import androidx.compose.animation.core.SeekableTransitionState
|
||||||
import androidx.compose.animation.core.rememberTransition
|
import androidx.compose.animation.core.rememberTransition
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.expandVertically
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.scaleIn
|
import androidx.compose.animation.scaleIn
|
||||||
import androidx.compose.animation.scaleOut
|
import androidx.compose.animation.scaleOut
|
||||||
import androidx.compose.animation.slideInVertically
|
import androidx.compose.animation.shrinkVertically
|
||||||
import androidx.compose.animation.slideOutVertically
|
|
||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
@@ -57,14 +59,15 @@ import androidx.compose.material.icons.filled.Edit
|
|||||||
import androidx.compose.material.icons.filled.GridView
|
import androidx.compose.material.icons.filled.GridView
|
||||||
import androidx.compose.material.icons.filled.History
|
import androidx.compose.material.icons.filled.History
|
||||||
import androidx.compose.material.icons.filled.Link
|
import androidx.compose.material.icons.filled.Link
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
import androidx.compose.material.icons.filled.Save
|
import androidx.compose.material.icons.filled.Save
|
||||||
import androidx.compose.material.icons.filled.SelectAll
|
import androidx.compose.material.icons.filled.SelectAll
|
||||||
import androidx.compose.material.icons.filled.UploadFile
|
import androidx.compose.material.icons.filled.UploadFile
|
||||||
import androidx.compose.material.icons.filled.Wifi
|
import androidx.compose.material.icons.filled.Wifi
|
||||||
|
import androidx.compose.material.icons.outlined.ViewCarousel
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
@@ -73,9 +76,11 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.rememberUpdatedState
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -90,7 +95,6 @@ import androidx.compose.ui.semantics.contentDescription
|
|||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.zIndex
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.base.BaseRuleEvent
|
import io.legado.app.base.BaseRuleEvent
|
||||||
@@ -104,18 +108,19 @@ import io.legado.app.ui.main.bookCoverSharedElementKey
|
|||||||
import io.legado.app.ui.theme.LegadoTheme
|
import io.legado.app.ui.theme.LegadoTheme
|
||||||
import io.legado.app.ui.theme.ThemeResolver
|
import io.legado.app.ui.theme.ThemeResolver
|
||||||
import io.legado.app.ui.theme.adaptiveContentPaddingBookshelf
|
import io.legado.app.ui.theme.adaptiveContentPaddingBookshelf
|
||||||
|
import io.legado.app.ui.theme.adaptiveHorizontalPadding
|
||||||
import io.legado.app.ui.theme.adaptiveHorizontalPaddingTab
|
import io.legado.app.ui.theme.adaptiveHorizontalPaddingTab
|
||||||
import io.legado.app.ui.widget.components.ActionItem
|
|
||||||
import io.legado.app.ui.widget.components.AppPullToRefresh
|
import io.legado.app.ui.widget.components.AppPullToRefresh
|
||||||
import io.legado.app.ui.widget.components.AppScaffold
|
import io.legado.app.ui.widget.components.AppScaffold
|
||||||
import io.legado.app.ui.widget.components.EmptyMessage
|
import io.legado.app.ui.widget.components.EmptyMessage
|
||||||
import io.legado.app.ui.widget.components.SelectionBottomBar
|
import io.legado.app.ui.widget.components.SearchBar
|
||||||
import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
||||||
import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton
|
import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton
|
||||||
import io.legado.app.ui.widget.components.card.NormalCard
|
import io.legado.app.ui.widget.components.card.NormalCard
|
||||||
import io.legado.app.ui.widget.components.card.TextCard
|
import io.legado.app.ui.widget.components.card.TextCard
|
||||||
import io.legado.app.ui.widget.components.divider.PillHeaderDivider
|
import io.legado.app.ui.widget.components.divider.PillHeaderDivider
|
||||||
import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
|
import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
|
||||||
|
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||||
import io.legado.app.ui.widget.components.icon.AppIcons
|
import io.legado.app.ui.widget.components.icon.AppIcons
|
||||||
import io.legado.app.ui.widget.components.importComponents.SourceInputDialog
|
import io.legado.app.ui.widget.components.importComponents.SourceInputDialog
|
||||||
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyVerticalGrid
|
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyVerticalGrid
|
||||||
@@ -125,8 +130,9 @@ import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
|||||||
import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator
|
import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator
|
||||||
import io.legado.app.ui.widget.components.tabRow.AppTabRow
|
import io.legado.app.ui.widget.components.tabRow.AppTabRow
|
||||||
import io.legado.app.ui.widget.components.text.AppText
|
import io.legado.app.ui.widget.components.text.AppText
|
||||||
import io.legado.app.ui.widget.components.topbar.DynamicTopAppBar
|
import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
|
||||||
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
|
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
|
||||||
|
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarScrollBehavior
|
||||||
import io.legado.app.ui.widget.components.topbar.TopBarActionButton
|
import io.legado.app.ui.widget.components.topbar.TopBarActionButton
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
@@ -158,7 +164,7 @@ fun BookshelfScreen(
|
|||||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
ReportDrawnWhen { uiState.groups.isNotEmpty() }
|
ReportDrawnWhen { !uiState.isInitialLoading }
|
||||||
|
|
||||||
val clipboardManager = LocalClipboard.current
|
val clipboardManager = LocalClipboard.current
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
@@ -206,6 +212,13 @@ fun BookshelfScreen(
|
|||||||
|
|
||||||
if (uiState.groups.isEmpty()) {
|
if (uiState.groups.isEmpty()) {
|
||||||
val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
|
val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
|
||||||
|
val onSearchClick = {
|
||||||
|
if (BookshelfConfig.bookshelfSearchActionDirectToSearchState.value) {
|
||||||
|
onNavigateToSearch(uiState.searchKey.trim())
|
||||||
|
} else {
|
||||||
|
viewModel.setSearchMode(!uiState.isSearch)
|
||||||
|
}
|
||||||
|
}
|
||||||
AppScaffold(
|
AppScaffold(
|
||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
contentWindowInsets = WindowInsets(0),
|
contentWindowInsets = WindowInsets(0),
|
||||||
@@ -222,16 +235,17 @@ fun BookshelfScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
topBar = {
|
topBar = {
|
||||||
DynamicTopAppBar(
|
BookshelfTopBar(
|
||||||
title = uiState.title.ifEmpty { stringResource(R.string.bookshelf) },
|
uiState = uiState,
|
||||||
subtitle = uiState.subtitle,
|
|
||||||
state = uiState,
|
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
showSearchAction = true,
|
onSearchClick = onSearchClick,
|
||||||
onSearchToggle = { viewModel.setSearchMode(it) },
|
|
||||||
onSearchQueryChange = { viewModel.setSearchKey(it) },
|
onSearchQueryChange = { viewModel.setSearchKey(it) },
|
||||||
onClearSelection = { viewModel.clearSelection() },
|
onSearchSubmit = { rawQuery ->
|
||||||
searchPlaceholder = "搜索...",
|
rawQuery.trim()
|
||||||
|
.takeIf { it.isNotEmpty() }
|
||||||
|
?.let(onNavigateToSearch)
|
||||||
|
},
|
||||||
|
onClearSearch = { viewModel.setSearchKey("") }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
@@ -288,7 +302,7 @@ fun BookshelfScreen(
|
|||||||
|
|
||||||
val currentTabGroupId by remember {
|
val currentTabGroupId by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
uiState.groups.getOrNull(pagerState.currentPage)?.groupId ?: BookGroup.IdAll
|
uiState.groups.getOrNull(pagerState.settledPage)?.groupId ?: BookGroup.IdAll
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val searchGroupExists by remember {
|
val searchGroupExists by remember {
|
||||||
@@ -351,37 +365,19 @@ fun BookshelfScreen(
|
|||||||
|
|
||||||
val configuration = LocalConfiguration.current
|
val configuration = LocalConfiguration.current
|
||||||
val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
val bookshelfLayoutMode by remember {
|
val bookshelfFolderLayoutMode by remember(isLandscape) {
|
||||||
derivedStateOf {
|
|
||||||
if (isLandscape) BookshelfConfig.bookshelfLayoutModeLandscapeState.value
|
|
||||||
else BookshelfConfig.bookshelfLayoutModePortraitState.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val bookshelfLayoutGrid by remember {
|
|
||||||
derivedStateOf {
|
|
||||||
if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscapeState.value
|
|
||||||
else BookshelfConfig.bookshelfLayoutGridPortraitState.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val bookshelfLayoutList by remember {
|
|
||||||
derivedStateOf {
|
|
||||||
if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscapeState.value
|
|
||||||
else BookshelfConfig.bookshelfLayoutListPortraitState.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val bookshelfFolderLayoutMode by remember {
|
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutModeLandscapeState.value
|
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutModeLandscapeState.value
|
||||||
else BookshelfConfig.bookshelfFolderLayoutModePortraitState.value
|
else BookshelfConfig.bookshelfFolderLayoutModePortraitState.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val bookshelfFolderLayoutGrid by remember {
|
val bookshelfFolderLayoutGrid by remember(isLandscape) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutGridLandscapeState.value
|
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutGridLandscapeState.value
|
||||||
else BookshelfConfig.bookshelfFolderLayoutGridPortraitState.value
|
else BookshelfConfig.bookshelfFolderLayoutGridPortraitState.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val bookshelfFolderLayoutList by remember {
|
val bookshelfFolderLayoutList by remember(isLandscape) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutListLandscapeState.value
|
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutListLandscapeState.value
|
||||||
else BookshelfConfig.bookshelfFolderLayoutListPortraitState.value
|
else BookshelfConfig.bookshelfFolderLayoutListPortraitState.value
|
||||||
@@ -392,12 +388,12 @@ fun BookshelfScreen(
|
|||||||
}
|
}
|
||||||
val editStickySummary by remember {
|
val editStickySummary by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (isEditMode) {
|
if (uiState.isEditMode) {
|
||||||
BookshelfEditStickySummary(
|
BookshelfEditStickySummary(
|
||||||
selectedCount = selectedBookUrls.size,
|
selectedCount = uiState.selectedBookUrls.size,
|
||||||
currentGroupTotalCount = currentGroupBookCount,
|
currentGroupTotalCount = currentGroupBookCount,
|
||||||
groupName = currentGroupName,
|
groupName = currentGroupName,
|
||||||
showGroupName = bookGroupStyle != 0
|
showGroupName = uiState.bookGroupStyle != 0
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@@ -406,6 +402,18 @@ fun BookshelfScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
|
val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
|
||||||
|
var showTopBarMenu by remember { mutableStateOf(false) }
|
||||||
|
val onSearchClick = {
|
||||||
|
if (BookshelfConfig.bookshelfSearchActionDirectToSearchState.value) {
|
||||||
|
onNavigateToSearch(uiState.searchKey.trim())
|
||||||
|
} else {
|
||||||
|
val active = !uiState.isSearch
|
||||||
|
viewModel.setSearchMode(active)
|
||||||
|
if (!active && uiState.selectedGroupId != currentTabGroupId) {
|
||||||
|
viewModel.changeGroup(currentTabGroupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AppScaffold(
|
AppScaffold(
|
||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
@@ -422,42 +430,18 @@ fun BookshelfScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
topBar = {
|
topBar = {
|
||||||
DynamicTopAppBar(
|
BookshelfTopBar(
|
||||||
title = uiState.title.ifEmpty { stringResource(R.string.bookshelf) },
|
uiState = uiState,
|
||||||
subtitle = uiState.subtitle,
|
|
||||||
state = uiState,
|
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
onBackClick = if (isEditMode) exitEditMode else null,
|
onSearchClick = onSearchClick,
|
||||||
backNavigationIcon = AppIcons.Close,
|
|
||||||
showSearchAction = true,
|
|
||||||
onSearchToggle = { active ->
|
|
||||||
if (BookshelfConfig.bookshelfSearchActionDirectToSearchState.value) {
|
|
||||||
onNavigateToSearch(uiState.searchKey.trim())
|
|
||||||
} else {
|
|
||||||
viewModel.setSearchMode(active)
|
|
||||||
if (!active && uiState.selectedGroupId != currentTabGroupId) {
|
|
||||||
viewModel.changeGroup(currentTabGroupId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onSearchQueryChange = { viewModel.setSearchKey(it) },
|
onSearchQueryChange = { viewModel.setSearchKey(it) },
|
||||||
onSearchSubmit = { rawQuery ->
|
onSearchSubmit = { rawQuery ->
|
||||||
rawQuery.trim()
|
rawQuery.trim()
|
||||||
.takeIf { it.isNotEmpty() }
|
.takeIf { it.isNotEmpty() }
|
||||||
?.let(onNavigateToSearch)
|
?.let(onNavigateToSearch)
|
||||||
},
|
},
|
||||||
searchTrailingIcon = {
|
onClearSearch = { viewModel.setSearchKey("") },
|
||||||
if (uiState.searchKey.isNotEmpty()) {
|
actions = {
|
||||||
TopBarActionButton(
|
|
||||||
onClick = { viewModel.setSearchKey("") },
|
|
||||||
imageVector = AppIcons.Close,
|
|
||||||
contentDescription = stringResource(R.string.clear)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
searchPlaceholder = "搜索...",
|
|
||||||
onClearSelection = { viewModel.clearSelection() },
|
|
||||||
topBarActions = {
|
|
||||||
AnimatedVisibility(visible = isEditMode) {
|
AnimatedVisibility(visible = isEditMode) {
|
||||||
TopBarActionButton(
|
TopBarActionButton(
|
||||||
onClick = { viewModel.selectAllVisible() },
|
onClick = { viewModel.selectAllVisible() },
|
||||||
@@ -494,212 +478,230 @@ fun BookshelfScreen(
|
|||||||
contentDescription = stringResource(R.string.move_to_group)
|
contentDescription = stringResource(R.string.move_to_group)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
dropDownMenuContent = if (!isEditMode) {
|
if (!isEditMode) {
|
||||||
{ dismiss ->
|
Box {
|
||||||
RoundDropdownMenuItem(
|
TopBarActionButton(
|
||||||
text = stringResource(R.string.add_remote_book),
|
onClick = { showTopBarMenu = true },
|
||||||
onClick = { onNavigateToRemoteImport(); dismiss() },
|
imageVector = Icons.Default.MoreVert,
|
||||||
leadingIcon = { Icon(Icons.Default.Wifi, null) }
|
contentDescription = stringResource(R.string.more_menu)
|
||||||
)
|
)
|
||||||
RoundDropdownMenuItem(
|
RoundDropdownMenu(
|
||||||
text = stringResource(R.string.book_local),
|
expanded = showTopBarMenu,
|
||||||
onClick = { onNavigateToLocalImport(); dismiss() },
|
onDismissRequest = { showTopBarMenu = false }
|
||||||
leadingIcon = { Icon(Icons.Default.Save, null) }
|
) { dismiss ->
|
||||||
)
|
RoundDropdownMenuItem(
|
||||||
RoundDropdownMenuItem(
|
text = stringResource(R.string.add_remote_book),
|
||||||
text = stringResource(R.string.update_toc),
|
onClick = { onNavigateToRemoteImport(); dismiss() },
|
||||||
onClick = { viewModel.upToc(uiState.items); dismiss() },
|
leadingIcon = { Icon(Icons.Default.Wifi, null) }
|
||||||
leadingIcon = { Icon(Icons.Default.Refresh, null) }
|
)
|
||||||
)
|
RoundDropdownMenuItem(
|
||||||
RoundDropdownMenuItem(
|
text = stringResource(R.string.book_local),
|
||||||
text = stringResource(R.string.layout_setting),
|
onClick = { onNavigateToLocalImport(); dismiss() },
|
||||||
onClick = {
|
leadingIcon = { Icon(Icons.Default.Save, null) }
|
||||||
viewModel.showOverlay(BookshelfOverlay.ConfigSheet)
|
)
|
||||||
dismiss()
|
RoundDropdownMenuItem(
|
||||||
},
|
text = stringResource(R.string.update_toc),
|
||||||
leadingIcon = { Icon(Icons.Default.GridView, null) }
|
onClick = { viewModel.upToc(uiState.items); dismiss() },
|
||||||
)
|
leadingIcon = { Icon(Icons.Default.Refresh, null) }
|
||||||
RoundDropdownMenuItem(
|
)
|
||||||
text = stringResource(R.string.group_manage),
|
RoundDropdownMenuItem(
|
||||||
onClick = {
|
text = stringResource(R.string.layout_setting),
|
||||||
viewModel.showOverlay(BookshelfOverlay.GroupManageSheet)
|
onClick = {
|
||||||
dismiss()
|
viewModel.showOverlay(BookshelfOverlay.ConfigSheet)
|
||||||
},
|
dismiss()
|
||||||
leadingIcon = { Icon(Icons.Default.Edit, null) }
|
},
|
||||||
)
|
leadingIcon = { Icon(Icons.Default.GridView, null) }
|
||||||
RoundDropdownMenuItem(
|
)
|
||||||
text = stringResource(R.string.add_url),
|
RoundDropdownMenuItem(
|
||||||
onClick = {
|
text = stringResource(R.string.group_manage),
|
||||||
viewModel.showOverlay(BookshelfOverlay.AddUrlDialog)
|
onClick = {
|
||||||
dismiss()
|
viewModel.showOverlay(BookshelfOverlay.GroupManageSheet)
|
||||||
},
|
dismiss()
|
||||||
leadingIcon = { Icon(Icons.Default.Link, null) }
|
},
|
||||||
)
|
leadingIcon = { Icon(Icons.Outlined.ViewCarousel, null) }
|
||||||
RoundDropdownMenuItem(
|
)
|
||||||
text = stringResource(R.string.edit),
|
RoundDropdownMenuItem(
|
||||||
onClick = {
|
text = stringResource(R.string.add_url),
|
||||||
toggleEditMode()
|
onClick = {
|
||||||
dismiss()
|
viewModel.showOverlay(BookshelfOverlay.AddUrlDialog)
|
||||||
},
|
dismiss()
|
||||||
leadingIcon = { Icon(Icons.Default.Edit, null) }
|
},
|
||||||
)
|
leadingIcon = { Icon(Icons.Default.Link, null) }
|
||||||
RoundDropdownMenuItem(
|
)
|
||||||
text = stringResource(R.string.bookshelf_management),
|
RoundDropdownMenuItem(
|
||||||
onClick = {
|
text = "选择模式",
|
||||||
val groupId =
|
onClick = {
|
||||||
uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L
|
toggleEditMode()
|
||||||
onNavigateToCache(groupId)
|
dismiss()
|
||||||
dismiss()
|
},
|
||||||
},
|
leadingIcon = { Icon(Icons.Default.Edit, null) }
|
||||||
leadingIcon = { Icon(Icons.Default.Bookmarks, null) }
|
)
|
||||||
)
|
RoundDropdownMenuItem(
|
||||||
RoundDropdownMenuItem(
|
text = stringResource(R.string.bookshelf_management),
|
||||||
text = stringResource(R.string.export_bookshelf),
|
onClick = {
|
||||||
onClick = {
|
val groupId =
|
||||||
viewModel.showOverlay(BookshelfOverlay.ExportSheet)
|
uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId
|
||||||
dismiss()
|
?: -1L
|
||||||
},
|
onNavigateToCache(groupId)
|
||||||
leadingIcon = { Icon(Icons.Default.UploadFile, null) }
|
dismiss()
|
||||||
)
|
},
|
||||||
RoundDropdownMenuItem(
|
leadingIcon = { Icon(Icons.Default.Bookmarks, null) }
|
||||||
text = stringResource(R.string.import_bookshelf),
|
)
|
||||||
onClick = {
|
RoundDropdownMenuItem(
|
||||||
viewModel.showOverlay(BookshelfOverlay.ImportSheet)
|
text = stringResource(R.string.export_bookshelf),
|
||||||
dismiss()
|
onClick = {
|
||||||
},
|
viewModel.showOverlay(BookshelfOverlay.ExportSheet)
|
||||||
leadingIcon = { Icon(Icons.Default.CloudDownload, null) }
|
dismiss()
|
||||||
)
|
},
|
||||||
RoundDropdownMenuItem(
|
leadingIcon = { Icon(Icons.Default.UploadFile, null) }
|
||||||
text = stringResource(R.string.log),
|
)
|
||||||
onClick = {
|
RoundDropdownMenuItem(
|
||||||
viewModel.showOverlay(BookshelfOverlay.LogSheet)
|
text = stringResource(R.string.import_bookshelf),
|
||||||
dismiss()
|
onClick = {
|
||||||
},
|
viewModel.showOverlay(BookshelfOverlay.ImportSheet)
|
||||||
leadingIcon = { Icon(Icons.Default.History, null) }
|
dismiss()
|
||||||
)
|
},
|
||||||
|
leadingIcon = { Icon(Icons.Default.CloudDownload, null) }
|
||||||
|
)
|
||||||
|
RoundDropdownMenuItem(
|
||||||
|
text = stringResource(R.string.log),
|
||||||
|
onClick = {
|
||||||
|
viewModel.showOverlay(BookshelfOverlay.LogSheet)
|
||||||
|
dismiss()
|
||||||
|
},
|
||||||
|
leadingIcon = { Icon(Icons.Default.History, null) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else null,
|
},
|
||||||
bottomContent = if (bookGroupStyle == 0) {
|
bottomContent = {
|
||||||
{
|
if (bookGroupStyle == 0 && uiState.groups.isNotEmpty()) {
|
||||||
if (uiState.groups.isNotEmpty()) {
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.adaptiveHorizontalPaddingTab(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
val selectedTabIndex =
|
val selectedTabIndex =
|
||||||
pagerState.currentPage.coerceIn(0, uiState.groups.size - 1)
|
pagerState.currentPage.coerceIn(0, uiState.groups.size - 1)
|
||||||
Row(
|
val tabTitles = remember(uiState.groups) {
|
||||||
modifier = Modifier
|
uiState.groups.map { it.groupName }
|
||||||
.fillMaxWidth()
|
}
|
||||||
.adaptiveHorizontalPaddingTab(),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
val tabTitles = remember(uiState.groups) {
|
|
||||||
uiState.groups.map { it.groupName }
|
|
||||||
}
|
|
||||||
|
|
||||||
AppTabRow(
|
AppTabRow(
|
||||||
tabTitles = tabTitles,
|
tabTitles = tabTitles,
|
||||||
selectedTabIndex = selectedTabIndex,
|
selectedTabIndex = selectedTabIndex,
|
||||||
onTabSelected = { index ->
|
onTabSelected = { index ->
|
||||||
scope.launch { pagerState.animateScrollToPage(index) }
|
scope.launch { pagerState.animateScrollToPage(index) }
|
||||||
},
|
},
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
|
|
||||||
val showExpandButton by BookshelfConfig.shouldShowExpandButtonState
|
val showExpandButton by BookshelfConfig.shouldShowExpandButtonState
|
||||||
if (showExpandButton) {
|
if (showExpandButton) {
|
||||||
Box(modifier = Modifier) {
|
Box(modifier = Modifier) {
|
||||||
SmallOutlinedIconToggleButton(
|
SmallOutlinedIconToggleButton(
|
||||||
checked = showGroupMenu,
|
checked = showGroupMenu,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
if (it) {
|
if (it) {
|
||||||
viewModel.showOverlay(BookshelfOverlay.GroupMenu)
|
viewModel.showOverlay(BookshelfOverlay.GroupMenu)
|
||||||
} else {
|
} else {
|
||||||
viewModel.dismissOverlay()
|
viewModel.dismissOverlay()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
imageVector = Icons.AutoMirrored.Filled.FormatListBulleted,
|
imageVector = Icons.AutoMirrored.Filled.FormatListBulleted,
|
||||||
contentDescription = stringResource(R.string.group_manage)
|
contentDescription = stringResource(R.string.group_manage)
|
||||||
)
|
)
|
||||||
RoundDropdownMenu(
|
RoundDropdownMenu(
|
||||||
expanded = showGroupMenu,
|
expanded = showGroupMenu,
|
||||||
onDismissRequest = { viewModel.dismissOverlay() }
|
onDismissRequest = { viewModel.dismissOverlay() }
|
||||||
) { dismiss ->
|
) { dismiss ->
|
||||||
uiState.groups.forEachIndexed { index, group ->
|
uiState.groups.forEachIndexed { index, group ->
|
||||||
RoundDropdownMenuItem(
|
RoundDropdownMenuItem(
|
||||||
text = group.groupName,
|
text = group.groupName,
|
||||||
onClick = {
|
onClick = {
|
||||||
if (uiState.isSearch) {
|
if (uiState.isSearch) {
|
||||||
viewModel.changeGroup(group.groupId)
|
viewModel.changeGroup(group.groupId)
|
||||||
}
|
|
||||||
scope.launch { pagerState.animateScrollToPage(index) }
|
|
||||||
dismiss()
|
|
||||||
},
|
|
||||||
trailingIcon = {
|
|
||||||
val isSelected = if (uiState.isSearch) {
|
|
||||||
uiState.selectedGroupId == group.groupId
|
|
||||||
} else {
|
|
||||||
selectedTabIndex == index
|
|
||||||
}
|
|
||||||
if (isSelected) {
|
|
||||||
Icon(
|
|
||||||
Icons.Default.Check,
|
|
||||||
null,
|
|
||||||
modifier = Modifier.size(18.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(
|
||||||
|
index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
val isSelected = if (uiState.isSearch) {
|
||||||
|
uiState.selectedGroupId == group.groupId
|
||||||
|
} else {
|
||||||
|
selectedTabIndex == index
|
||||||
|
}
|
||||||
|
if (isSelected) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Check,
|
||||||
|
null,
|
||||||
|
modifier = Modifier.size(18.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uiState.isSearch) {
|
||||||
|
val allGroup = uiState.allGroups.firstOrNull {
|
||||||
|
it.groupId == BookGroup.IdAll
|
||||||
|
}
|
||||||
|
val hiddenGroups = uiState.allGroups.filter {
|
||||||
|
!it.show && it.groupId != BookGroup.IdAll
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uiState.isSearch) {
|
if (allGroup != null || hiddenGroups.isNotEmpty()) {
|
||||||
val allGroup = uiState.allGroups.firstOrNull {
|
PillHeaderDivider(
|
||||||
it.groupId == BookGroup.IdAll
|
title = "${stringResource(R.string.all)} / ${
|
||||||
}
|
stringResource(
|
||||||
val hiddenGroups = uiState.allGroups.filter {
|
R.string.hide
|
||||||
!it.show && it.groupId != BookGroup.IdAll
|
)
|
||||||
}
|
}"
|
||||||
|
)
|
||||||
|
|
||||||
if (allGroup != null || hiddenGroups.isNotEmpty()) {
|
allGroup?.let { group ->
|
||||||
PillHeaderDivider(
|
RoundDropdownMenuItem(
|
||||||
title = "${stringResource(R.string.all)} / ${stringResource(R.string.hide)}"
|
text = group.groupName,
|
||||||
|
onClick = {
|
||||||
|
viewModel.changeGroup(group.groupId)
|
||||||
|
dismiss()
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
if (uiState.selectedGroupId == group.groupId) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Check,
|
||||||
|
null,
|
||||||
|
modifier = Modifier.size(18.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
allGroup?.let { group ->
|
hiddenGroups.forEach { group ->
|
||||||
RoundDropdownMenuItem(
|
RoundDropdownMenuItem(
|
||||||
text = group.groupName,
|
text = group.groupName,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.changeGroup(group.groupId)
|
viewModel.changeGroup(group.groupId)
|
||||||
dismiss()
|
dismiss()
|
||||||
},
|
},
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
if (uiState.selectedGroupId == group.groupId) {
|
if (uiState.selectedGroupId == group.groupId) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.Check,
|
Icons.Default.Check,
|
||||||
null,
|
null,
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
hiddenGroups.forEach { group ->
|
|
||||||
RoundDropdownMenuItem(
|
|
||||||
text = group.groupName,
|
|
||||||
onClick = {
|
|
||||||
viewModel.changeGroup(group.groupId)
|
|
||||||
dismiss()
|
|
||||||
},
|
|
||||||
trailingIcon = {
|
|
||||||
if (uiState.selectedGroupId == group.groupId) {
|
|
||||||
Icon(
|
|
||||||
Icons.Default.Check,
|
|
||||||
null,
|
|
||||||
modifier = Modifier.size(18.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -708,7 +710,7 @@ fun BookshelfScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else null
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
@@ -717,7 +719,7 @@ fun BookshelfScreen(
|
|||||||
if (uiState.isSearch) {
|
if (uiState.isSearch) {
|
||||||
uiState.allGroups.firstOrNull { it.groupId == currentGroupId }
|
uiState.allGroups.firstOrNull { it.groupId == currentGroupId }
|
||||||
} else {
|
} else {
|
||||||
uiState.groups.getOrNull(pagerState.currentPage)
|
uiState.groups.getOrNull(pagerState.settledPage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -851,7 +853,6 @@ fun BookshelfScreen(
|
|||||||
onDragStarted = {},
|
onDragStarted = {},
|
||||||
onMoveBook = { _, _, _ -> },
|
onMoveBook = { _, _, _ -> },
|
||||||
onDragFinished = {},
|
onDragFinished = {},
|
||||||
onSyncDragState = { _, _ -> },
|
|
||||||
onGlobalSearch = { onNavigateToSearch(uiState.searchKey.trim()) },
|
onGlobalSearch = { onNavigateToSearch(uiState.searchKey.trim()) },
|
||||||
onBookClick = onBookClick,
|
onBookClick = onBookClick,
|
||||||
onBookLongClick = onBookLongClick,
|
onBookLongClick = onBookLongClick,
|
||||||
@@ -911,11 +912,6 @@ fun BookshelfScreen(
|
|||||||
onDragFinished = {
|
onDragFinished = {
|
||||||
if (isSelectedGroup) viewModel.finishDraggingBooks()
|
if (isSelectedGroup) viewModel.finishDraggingBooks()
|
||||||
},
|
},
|
||||||
onSyncDragState = { currentBooks, canReorder ->
|
|
||||||
if (isSelectedGroup) {
|
|
||||||
viewModel.syncDragState(currentBooks, canReorder)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onGlobalSearch = { onNavigateToSearch(uiState.searchKey.trim()) },
|
onGlobalSearch = { onNavigateToSearch(uiState.searchKey.trim()) },
|
||||||
onBookClick = onBookClick,
|
onBookClick = onBookClick,
|
||||||
onBookLongClick = onBookLongClick,
|
onBookLongClick = onBookLongClick,
|
||||||
@@ -1031,44 +1027,6 @@ fun BookshelfScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible = isEditMode && selectedBookUrls.isNotEmpty(),
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.BottomCenter)
|
|
||||||
.padding(
|
|
||||||
bottom = 16.dp + ScreenOffset + WindowInsets.navigationBars
|
|
||||||
.asPaddingValues()
|
|
||||||
.calculateBottomPadding()
|
|
||||||
)
|
|
||||||
.zIndex(1f),
|
|
||||||
enter = slideInVertically { it } + fadeIn(),
|
|
||||||
exit = slideOutVertically { it } + fadeOut()
|
|
||||||
) {
|
|
||||||
SelectionBottomBar(
|
|
||||||
onSelectAll = { viewModel.selectAllVisible() },
|
|
||||||
onSelectInvert = { viewModel.invertVisibleSelection() },
|
|
||||||
primaryAction = ActionItem(
|
|
||||||
text = stringResource(R.string.action_download),
|
|
||||||
icon = Icons.Default.Download,
|
|
||||||
onClick = {
|
|
||||||
if (selectedBookUrls.isNotEmpty()) {
|
|
||||||
viewModel.showOverlay(BookshelfOverlay.BatchDownloadConfirmDialog)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
secondaryActions = listOf(
|
|
||||||
ActionItem(
|
|
||||||
text = stringResource(R.string.move_to_group),
|
|
||||||
icon = Icons.Default.Bookmarks,
|
|
||||||
onClick = {
|
|
||||||
if (selectedBookUrls.isNotEmpty()) {
|
|
||||||
viewModel.showOverlay(BookshelfOverlay.GroupSelectSheet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1083,6 +1041,70 @@ fun BookshelfScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun BookshelfTopBar(
|
||||||
|
uiState: BookshelfUiState,
|
||||||
|
scrollBehavior: GlassTopAppBarScrollBehavior,
|
||||||
|
onSearchClick: () -> Unit,
|
||||||
|
onSearchQueryChange: (String) -> Unit,
|
||||||
|
onSearchSubmit: (String) -> Unit,
|
||||||
|
onClearSearch: () -> Unit,
|
||||||
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
|
bottomContent: @Composable ColumnScope.() -> Unit = {}
|
||||||
|
) {
|
||||||
|
val searchContentDescription = stringResource(R.string.search)
|
||||||
|
GlassMediumFlexibleTopAppBar(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
title = if (uiState.isLoading) {
|
||||||
|
stringResource(R.string.loading)
|
||||||
|
} else {
|
||||||
|
uiState.title.ifEmpty { stringResource(R.string.bookshelf) }
|
||||||
|
},
|
||||||
|
useCharMode = uiState.isLoading,
|
||||||
|
subtitle = uiState.subtitle,
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
actions = {
|
||||||
|
TopBarActionButton(
|
||||||
|
onClick = onSearchClick,
|
||||||
|
imageVector = AppIcons.Search,
|
||||||
|
contentDescription = searchContentDescription
|
||||||
|
)
|
||||||
|
actions()
|
||||||
|
},
|
||||||
|
bottomContent = {
|
||||||
|
AnimatedVisibility(
|
||||||
|
modifier = Modifier.adaptiveHorizontalPadding(),
|
||||||
|
visible = uiState.isSearch,
|
||||||
|
enter = expandVertically() + fadeIn(),
|
||||||
|
exit = shrinkVertically() + fadeOut()
|
||||||
|
) {
|
||||||
|
SearchBar(
|
||||||
|
query = uiState.searchKey,
|
||||||
|
onQueryChange = onSearchQueryChange,
|
||||||
|
onSearch = onSearchSubmit,
|
||||||
|
placeholder = stringResource(R.string.input_search_key),
|
||||||
|
leadingIcon = {
|
||||||
|
AppIcon(
|
||||||
|
imageVector = AppIcons.Search,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
if (uiState.searchKey.isNotEmpty()) {
|
||||||
|
TopBarActionButton(
|
||||||
|
onClick = onClearSearch,
|
||||||
|
imageVector = AppIcons.Close,
|
||||||
|
contentDescription = stringResource(R.string.clear)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
bottomContent()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun BookshelfOverlays(
|
private fun BookshelfOverlays(
|
||||||
activeOverlay: BookshelfOverlay?,
|
activeOverlay: BookshelfOverlay?,
|
||||||
@@ -1229,7 +1251,6 @@ fun BookshelfPage(
|
|||||||
onDragStarted: (ImmutableList<BookShelfItem>) -> Unit,
|
onDragStarted: (ImmutableList<BookShelfItem>) -> Unit,
|
||||||
onMoveBook: (fromIndex: Int, toIndex: Int, currentBooks: ImmutableList<BookShelfItem>) -> Unit,
|
onMoveBook: (fromIndex: Int, toIndex: Int, currentBooks: ImmutableList<BookShelfItem>) -> Unit,
|
||||||
onDragFinished: () -> Unit,
|
onDragFinished: () -> Unit,
|
||||||
onSyncDragState: (books: ImmutableList<BookShelfItem>, canReorderBooks: Boolean) -> Unit,
|
|
||||||
onGlobalSearch: () -> Unit,
|
onGlobalSearch: () -> Unit,
|
||||||
onBookClick: (BookShelfItem) -> Unit,
|
onBookClick: (BookShelfItem) -> Unit,
|
||||||
onBookLongClick: (BookShelfItem) -> Unit,
|
onBookLongClick: (BookShelfItem) -> Unit,
|
||||||
@@ -1267,19 +1288,19 @@ fun BookshelfPage(
|
|||||||
|
|
||||||
val configuration = LocalConfiguration.current
|
val configuration = LocalConfiguration.current
|
||||||
val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
val bookshelfLayoutMode by remember {
|
val bookshelfLayoutMode by remember(isLandscape) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (isLandscape) BookshelfConfig.bookshelfLayoutModeLandscapeState.value
|
if (isLandscape) BookshelfConfig.bookshelfLayoutModeLandscapeState.value
|
||||||
else BookshelfConfig.bookshelfLayoutModePortraitState.value
|
else BookshelfConfig.bookshelfLayoutModePortraitState.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val bookshelfLayoutGrid by remember {
|
val bookshelfLayoutGrid by remember(isLandscape) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscapeState.value
|
if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscapeState.value
|
||||||
else BookshelfConfig.bookshelfLayoutGridPortraitState.value
|
else BookshelfConfig.bookshelfLayoutGridPortraitState.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val bookshelfLayoutList by remember {
|
val bookshelfLayoutList by remember(isLandscape) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscapeState.value
|
if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscapeState.value
|
||||||
else BookshelfConfig.bookshelfLayoutListPortraitState.value
|
else BookshelfConfig.bookshelfLayoutListPortraitState.value
|
||||||
@@ -1304,9 +1325,6 @@ fun BookshelfPage(
|
|||||||
val gridInnerHorizontalPadding = totalHorizontalPadding / 2
|
val gridInnerHorizontalPadding = totalHorizontalPadding / 2
|
||||||
val hapticFeedback = LocalHapticFeedback.current
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
val displayBooks = draggingBooks ?: pendingSavedBooks ?: books
|
val displayBooks = draggingBooks ?: pendingSavedBooks ?: books
|
||||||
LaunchedEffect(books, pendingSavedBooks, canReorderBooks) {
|
|
||||||
onSyncDragState(books, canReorderBooks)
|
|
||||||
}
|
|
||||||
val gridState = rememberLazyGridState()
|
val gridState = rememberLazyGridState()
|
||||||
val reorderableState = rememberReorderableLazyGridState(gridState) { from, to ->
|
val reorderableState = rememberReorderableLazyGridState(gridState) { from, to ->
|
||||||
if (canReorderBooks) {
|
if (canReorderBooks) {
|
||||||
|
|||||||
@@ -238,6 +238,18 @@ class BookshelfViewModel(
|
|||||||
filterBooks(books, searchKey, isSearchMode)
|
filterBooks(books, searchKey, isSearchMode)
|
||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
|
|
||||||
|
private val selectedGroupCanReorderFlow = combine(
|
||||||
|
isEditModeFlow,
|
||||||
|
searchModeFlow,
|
||||||
|
groupIdFlow,
|
||||||
|
groupsFlow,
|
||||||
|
sortConfigFlow
|
||||||
|
) { isEditMode, isSearchMode, groupId, groups, sortConfig ->
|
||||||
|
val group = groups.find { it.groupId == groupId }
|
||||||
|
val bookSort = group?.bookSort?.takeIf { it >= 0 } ?: sortConfig.sort
|
||||||
|
isEditMode && !isSearchMode && bookSort == 3
|
||||||
|
}.distinctUntilChanged()
|
||||||
|
|
||||||
private val selectedVisibleBookUrlsFlow = combine(
|
private val selectedVisibleBookUrlsFlow = combine(
|
||||||
selectedBookUrlsFlow,
|
selectedBookUrlsFlow,
|
||||||
visibleBooksFlow
|
visibleBooksFlow
|
||||||
@@ -510,6 +522,13 @@ class BookshelfViewModel(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
allGroupBooksImmutableFlow.collect { allGroupBooksStateFlow.value = it }
|
allGroupBooksImmutableFlow.collect { allGroupBooksStateFlow.value = it }
|
||||||
}
|
}
|
||||||
|
viewModelScope.launch {
|
||||||
|
combine(booksFlow, selectedGroupCanReorderFlow) { books, canReorderBooks ->
|
||||||
|
books to canReorderBooks
|
||||||
|
}.collect { (books, canReorderBooks) ->
|
||||||
|
syncDragState(books, canReorderBooks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
isInitialLoadingFlow.filter { !it }.collect {
|
isInitialLoadingFlow.filter { !it }.collect {
|
||||||
@@ -765,7 +784,7 @@ class BookshelfViewModel(
|
|||||||
saveBookOrder(reorderedBooks)
|
saveBookOrder(reorderedBooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun syncDragState(books: List<BookShelfItem>, canReorderBooks: Boolean) {
|
private fun syncDragState(books: List<BookShelfItem>, canReorderBooks: Boolean) {
|
||||||
if (!canReorderBooks) {
|
if (!canReorderBooks) {
|
||||||
clearDragState()
|
clearDragState()
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user