Преглед изворни кода

fix: improve manual sort drag visual feedback and selection handling

- Add isDragging parameter to ReorderableItem lambda
- Apply alpha(0.5f) during drag for visual feedback
- Fix modifier chain structure for longPressDraggableHandle
- Add import for androidx.compose.ui.draw.alpha
- Ensure selection state displays correctly in edit mode
shilimesfriend пре 4 месеци
родитељ
комит
ad4c5e7339
1 измењених фајлова са 8 додато и 1269 уклоњено
  1. 8 1269
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt

+ 8 - 1269
app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt

@@ -27,6 +27,7 @@ import androidx.compose.animation.scaleOut
 import androidx.compose.animation.shrinkVertically
 import androidx.compose.animation.shrinkVertically
 import androidx.compose.animation.togetherWith
 import androidx.compose.animation.togetherWith
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
 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
@@ -39,16 +40,19 @@ import androidx.compose.foundation.layout.WindowInsets
 import androidx.compose.foundation.layout.asPaddingValues
 import androidx.compose.foundation.layout.asPaddingValues
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.navigationBars
 import androidx.compose.foundation.layout.navigationBars
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.lazy.grid.GridCells
 import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyGridState
 import androidx.compose.foundation.lazy.grid.items
 import androidx.compose.foundation.lazy.grid.items
-import androidx.compose.foundation.lazy.grid.itemsIndexed
 import androidx.compose.foundation.lazy.grid.rememberLazyGridState
 import androidx.compose.foundation.lazy.grid.rememberLazyGridState
 import androidx.compose.foundation.pager.HorizontalPager
 import androidx.compose.foundation.pager.HorizontalPager
 import androidx.compose.foundation.pager.rememberPagerState
 import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.automirrored.filled.FormatListBulleted
 import androidx.compose.material.icons.automirrored.filled.FormatListBulleted
 import androidx.compose.material.icons.filled.Bookmarks
 import androidx.compose.material.icons.filled.Bookmarks
@@ -84,8 +88,10 @@ 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
+import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.hapticfeedback.HapticFeedbackType
 import androidx.compose.ui.hapticfeedback.HapticFeedbackType
 import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.platform.ClipEntry
 import androidx.compose.ui.platform.ClipEntry
 import androidx.compose.ui.platform.LocalClipboard
 import androidx.compose.ui.platform.LocalClipboard
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.platform.LocalConfiguration
@@ -144,1271 +150,4 @@ import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.launch
 import org.koin.androidx.compose.koinViewModel
 import org.koin.androidx.compose.koinViewModel
 import sh.calvin.reorderable.ReorderableItem
 import sh.calvin.reorderable.ReorderableItem
-import sh.calvin.reorderable.rememberReorderableLazyGridState
-
-@OptIn(
-    ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
-    ExperimentalMaterial3ExpressiveApi::class, ExperimentalSharedTransitionApi::class,
-    ExperimentalAnimationApi::class
-)
-@Composable
-fun BookshelfScreen(
-    viewModel: BookshelfViewModel = koinViewModel(),
-    onBookClick: (BookShelfItem) -> Unit,
-    onBookLongClick: (book: BookShelfItem, sharedCoverKey: String?) -> Unit,
-    onNavigateToSearch: (String) -> Unit,
-    onNavigateToRemoteImport: () -> Unit,
-    onNavigateToLocalImport: () -> Unit,
-    onNavigateToCache: (Long) -> Unit,
-    sharedTransitionScope: SharedTransitionScope? = null,
-    animatedVisibilityScope: AnimatedVisibilityScope? = null,
-) {
-    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
-    val scope = rememberCoroutineScope()
-
-    ReportDrawnWhen { !uiState.isInitialLoading }
-
-    val clipboardManager = LocalClipboard.current
-    val snackbarHostState = remember { SnackbarHostState() }
-
-    LaunchedEffect(Unit) {
-        viewModel.events.collect { event ->
-            when (event) {
-                is BaseRuleEvent.ShowSnackbar -> {
-                    val result = snackbarHostState.showSnackbar(
-                        message = event.message,
-                        actionLabel = event.actionLabel,
-                        withDismissAction = true
-                    )
-                    if (result == SnackbarResult.ActionPerformed && event.url != null) {
-                        clipboardManager.setClipEntry(
-                            ClipEntry(
-                                ClipData.newPlainText(
-                                    "url",
-                                    event.url
-                                )
-                            )
-                        )
-                    }
-                }
-            }
-        }
-    }
-
-    val importLauncher = rememberLauncherForActivityResult(
-        contract = ActivityResultContracts.OpenDocument(),
-        onResult = { uri ->
-            uri?.let {
-                val groupId = uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId ?: -1L
-                viewModel.importBookshelf(it, groupId)
-            }
-        }
-    )
-
-    val exportLauncher = rememberLauncherForActivityResult(
-        contract = ActivityResultContracts.CreateDocument("application/json"),
-        onResult = { uri ->
-            uri?.let { viewModel.exportToUri(it, uiState.items) }
-        }
-    )
-
-    val activeOverlay = uiState.activeOverlay
-    val showGroupMenu = activeOverlay == BookshelfOverlay.GroupMenu
-    val isEditMode = uiState.isEditMode
-    val selectedBookUrls = uiState.selectedBookUrls
-    val isInFolderRoot = uiState.isInFolderRoot
-    val bookGroupStyle = uiState.bookGroupStyle
-
-    val transitionState = remember { SeekableTransitionState(isInFolderRoot) }
-    val folderTransition = rememberTransition(transitionState, label = "FolderTransition")
-    LaunchedEffect(isInFolderRoot) {
-        if (transitionState.targetState != isInFolderRoot) {
-            transitionState.animateTo(isInFolderRoot)
-        }
-    }
-
-    val pagerState = rememberPagerState(
-        initialPage = uiState.selectedGroupIndex.coerceAtLeast(0),
-        pageCount = { uiState.groups.size }
-    )
-    val latestGroups by rememberUpdatedState(uiState.groups)
-    val latestSelectedGroupId by rememberUpdatedState(uiState.selectedGroupId)
-
-    LaunchedEffect(uiState.selectedGroupIndex, uiState.groups.size) {
-        if (uiState.groups.isNotEmpty()
-            && uiState.selectedGroupIndex in uiState.groups.indices
-            && pagerState.currentPage != uiState.selectedGroupIndex
-        ) {
-            pagerState.scrollToPage(uiState.selectedGroupIndex)
-        }
-    }
-
-    LaunchedEffect(pagerState) {
-        snapshotFlow { pagerState.settledPage }
-            .distinctUntilChanged()
-            .collect { page ->
-                val groups = latestGroups
-                if (groups.isNotEmpty() && page in groups.indices) {
-                    val targetGroupId = groups[page].groupId
-                    if (latestSelectedGroupId != targetGroupId) {
-                        viewModel.changeGroup(targetGroupId)
-                    }
-                }
-            }
-    }
-
-    val currentTabGroupId by remember {
-        derivedStateOf {
-            uiState.groups.getOrNull(pagerState.settledPage)?.groupId ?: BookGroup.IdAll
-        }
-    }
-    val searchGroupExists by remember {
-        derivedStateOf { uiState.allGroups.any { it.groupId == uiState.selectedGroupId } }
-    }
-    val currentGroupId by remember {
-        derivedStateOf {
-            if (uiState.isSearch && searchGroupExists) {
-                uiState.selectedGroupId
-            } else {
-                currentTabGroupId
-            }
-        }
-    }
-    val isUsingStandaloneSearchGroup by remember {
-        derivedStateOf {
-            uiState.isSearch && uiState.groups.none { it.groupId == currentGroupId }
-        }
-    }
-    val currentGroupBookCount by remember { derivedStateOf { uiState.currentGroupBookCount } }
-
-    val clearSelection = {
-        viewModel.clearSelection()
-    }
-    val exitEditMode = {
-        viewModel.exitEditMode()
-    }
-    val toggleEditMode = {
-        viewModel.toggleEditMode()
-    }
-    val toggleBookSelection: (String) -> Unit = { bookUrl ->
-        viewModel.toggleBookSelection(bookUrl)
-    }
-
-    LaunchedEffect(pagerState.currentPage, isInFolderRoot) {
-        clearSelection()
-    }
-
-    BackHandler(enabled = isEditMode) {
-        if (selectedBookUrls.isNotEmpty()) {
-            clearSelection()
-        } else {
-            exitEditMode()
-        }
-    }
-
-    val currentGroupName by remember { derivedStateOf { uiState.currentGroupName } }
-
-    PredictiveBackHandler(enabled = bookGroupStyle == 2 && !isInFolderRoot && !isEditMode) { progress ->
-        try {
-            progress.collect { backEvent ->
-                transitionState.seekTo(backEvent.progress, targetState = true)
-            }
-            viewModel.setInFolderRoot(true)
-            transitionState.animateTo(true)
-        } catch (e: CancellationException) {
-            transitionState.animateTo(false)
-        }
-    }
-
-    val configuration = LocalConfiguration.current
-    val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
-    val bookshelfFolderLayoutMode by remember(isLandscape) {
-        derivedStateOf {
-            if (isLandscape) BookshelfConfig.bookshelfFolderLayoutModeLandscapeState.value
-            else BookshelfConfig.bookshelfFolderLayoutModePortraitState.value
-        }
-    }
-    val bookshelfFolderLayoutGrid by remember(isLandscape) {
-        derivedStateOf {
-            if (isLandscape) BookshelfConfig.bookshelfFolderLayoutGridLandscapeState.value
-            else BookshelfConfig.bookshelfFolderLayoutGridPortraitState.value
-        }
-    }
-    val bookshelfFolderLayoutList by remember(isLandscape) {
-        derivedStateOf {
-            if (isLandscape) BookshelfConfig.bookshelfFolderLayoutListLandscapeState.value
-            else BookshelfConfig.bookshelfFolderLayoutListPortraitState.value
-        }
-    }
-    val currentMenuGroupId by remember {
-        derivedStateOf { if (uiState.isSearch) uiState.selectedGroupId else currentTabGroupId }
-    }
-    val editStickySummary by remember {
-        derivedStateOf {
-            if (uiState.isEditMode) {
-                BookshelfEditStickySummary(
-                    selectedCount = uiState.selectedBookUrls.size,
-                    currentGroupTotalCount = currentGroupBookCount,
-                    groupName = currentGroupName,
-                    showGroupName = uiState.bookGroupStyle != 0
-                )
-            } else {
-                null
-            }
-        }
-    }
-
-    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(
-        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
-        contentWindowInsets = WindowInsets(0),
-        snackbarHost = {
-            SnackbarHost(
-                hostState = snackbarHostState,
-                modifier = Modifier
-                    .padding(
-                        bottom = 72.dp + WindowInsets.navigationBars
-                            .asPaddingValues()
-                            .calculateBottomPadding()
-                    )
-            )
-        },
-        topBar = {
-            BookshelfTopBar(
-                uiState = uiState,
-                scrollBehavior = scrollBehavior,
-                onSearchClick = onSearchClick,
-                onSearchQueryChange = { viewModel.setSearchKey(it) },
-                onSearchSubmit = { rawQuery ->
-                    rawQuery.trim()
-                        .takeIf { it.isNotEmpty() }
-                        ?.let(onNavigateToSearch)
-                },
-                onClearSearch = { viewModel.setSearchKey("") },
-                actions = {
-                    AnimatedVisibility(visible = isEditMode) {
-                        TopBarActionButton(
-                            onClick = { viewModel.selectAllVisible() },
-                            imageVector = Icons.Default.SelectAll,
-                            contentDescription = stringResource(R.string.select_all)
-                        )
-                    }
-                    AnimatedVisibility(visible = isEditMode) {
-                        TopBarActionButton(
-                            onClick = { viewModel.invertVisibleSelection() },
-                            imageVector = Icons.Default.Refresh,
-                            contentDescription = stringResource(R.string.revert_selection)
-                        )
-                    }
-                    AnimatedVisibility(visible = isEditMode) {
-                        TopBarActionButton(
-                            onClick = {
-                                if (selectedBookUrls.isNotEmpty()) {
-                                    viewModel.showOverlay(BookshelfOverlay.BatchDownloadConfirmDialog)
-                                }
-                            },
-                            imageVector = Icons.Default.Download,
-                            contentDescription = stringResource(R.string.action_download)
-                        )
-                    }
-                    AnimatedVisibility(visible = isEditMode) {
-                        TopBarActionButton(
-                            onClick = {
-                                if (selectedBookUrls.isNotEmpty()) {
-                                    viewModel.showOverlay(BookshelfOverlay.GroupSelectSheet)
-                                }
-                            },
-                            imageVector = Icons.Default.Bookmarks,
-                            contentDescription = stringResource(R.string.move_to_group)
-                        )
-                    }
-
-                    if (!isEditMode) {
-                        Box {
-                            TopBarActionButton(
-                                onClick = { showTopBarMenu = true },
-                                imageVector = Icons.Default.MoreVert,
-                                contentDescription = stringResource(R.string.more_menu)
-                            )
-                            RoundDropdownMenu(
-                                expanded = showTopBarMenu,
-                                onDismissRequest = { showTopBarMenu = false }
-                            ) { dismiss ->
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.add_remote_book),
-                                    onClick = { onNavigateToRemoteImport(); dismiss() },
-                                    leadingIcon = { Icon(Icons.Default.Wifi, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.book_local),
-                                    onClick = { onNavigateToLocalImport(); dismiss() },
-                                    leadingIcon = { Icon(Icons.Default.Save, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.update_toc),
-                                    onClick = { viewModel.upToc(uiState.items); dismiss() },
-                                    leadingIcon = { Icon(Icons.Default.Refresh, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.layout_setting),
-                                    onClick = {
-                                        viewModel.showOverlay(BookshelfOverlay.ConfigSheet)
-                                        dismiss()
-                                    },
-                                    leadingIcon = { Icon(Icons.Default.GridView, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.group_manage),
-                                    onClick = {
-                                        viewModel.showOverlay(BookshelfOverlay.GroupManageSheet)
-                                        dismiss()
-                                    },
-                                    leadingIcon = { Icon(Icons.Outlined.ViewCarousel, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.add_url),
-                                    onClick = {
-                                        viewModel.showOverlay(BookshelfOverlay.AddUrlDialog)
-                                        dismiss()
-                                    },
-                                    leadingIcon = { Icon(Icons.Default.Link, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = "选择模式",
-                                    onClick = {
-                                        toggleEditMode()
-                                        dismiss()
-                                    },
-                                    leadingIcon = { Icon(Icons.Default.Edit, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.bookshelf_management),
-                                    onClick = {
-                                        val groupId =
-                                            uiState.groups.getOrNull(uiState.selectedGroupIndex)?.groupId
-                                                ?: -1L
-                                        onNavigateToCache(groupId)
-                                        dismiss()
-                                    },
-                                    leadingIcon = { Icon(Icons.Default.Bookmarks, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.export_bookshelf),
-                                    onClick = {
-                                        viewModel.showOverlay(BookshelfOverlay.ExportSheet)
-                                        dismiss()
-                                    },
-                                    leadingIcon = { Icon(Icons.Default.UploadFile, null) }
-                                )
-                                RoundDropdownMenuItem(
-                                    text = stringResource(R.string.import_bookshelf),
-                                    onClick = {
-                                        viewModel.showOverlay(BookshelfOverlay.ImportSheet)
-                                        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) }
-                                )
-                            }
-                        }
-                    }
-                },
-                bottomContent = {
-                    if (bookGroupStyle == 0 && uiState.groups.isNotEmpty()) {
-                        Row(
-                            modifier = Modifier
-                                .fillMaxWidth()
-                                .adaptiveHorizontalPaddingTab(),
-                            verticalAlignment = Alignment.CenterVertically
-                        ) {
-                            val selectedTabIndex =
-                                pagerState.currentPage.coerceIn(0, uiState.groups.size - 1)
-                            val tabTitles = remember(uiState.groups) {
-                                uiState.groups.map { it.groupName }
-                            }
-
-                            AppTabRow(
-                                tabTitles = tabTitles,
-                                selectedTabIndex = selectedTabIndex,
-                                onTabSelected = { index ->
-                                    scope.launch { pagerState.animateScrollToPage(index) }
-                                },
-                                modifier = Modifier.weight(1f)
-                            )
-
-                            val showExpandButton by BookshelfConfig.shouldShowExpandButtonState
-                            if (showExpandButton) {
-                                Box(modifier = Modifier) {
-                                    SmallToggleButton(
-                                        checked = showGroupMenu,
-                                        onCheckedChange = {
-                                            if (it) {
-                                                viewModel.showOverlay(BookshelfOverlay.GroupMenu)
-                                            } else {
-                                                viewModel.dismissOverlay()
-                                            }
-                                        },
-                                        style = ToggleStyle.Outlined,
-                                        icon = Icons.AutoMirrored.Filled.FormatListBulleted,
-                                        contentDescription = stringResource(R.string.group_manage)
-                                    )
-                                    RoundDropdownMenu(
-                                        expanded = showGroupMenu,
-                                        onDismissRequest = { viewModel.dismissOverlay() }
-                                    ) { dismiss ->
-                                        uiState.groups.forEachIndexed { index, group ->
-                                            RoundDropdownMenuItem(
-                                                text = group.groupName,
-                                                onClick = {
-                                                    if (uiState.isSearch) {
-                                                        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)
-                                                        )
-                                                    }
-                                                }
-                                            )
-                                        }
-
-                                        if (uiState.isSearch) {
-                                            val allGroup = uiState.allGroups.firstOrNull {
-                                                it.groupId == BookGroup.IdAll
-                                            }
-                                            val hiddenGroups = uiState.allGroups.filter {
-                                                !it.show && it.groupId != BookGroup.IdAll
-                                            }
-
-                                            if (allGroup != null || hiddenGroups.isNotEmpty()) {
-                                                PillHeaderDivider(
-                                                    title = "${stringResource(R.string.all)} / ${
-                                                        stringResource(
-                                                            R.string.hide
-                                                        )
-                                                    }"
-                                                )
-
-                                                allGroup?.let { 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)
-                                                                )
-                                                            }
-                                                        }
-                                                    )
-                                                }
-
-                                                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)
-                                                                )
-                                                            }
-                                                        }
-                                                    )
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            )
-        }
-    ) { paddingValues ->
-        val currentGroup by remember {
-            derivedStateOf {
-                if (uiState.isSearch) {
-                    uiState.allGroups.firstOrNull { it.groupId == currentGroupId }
-                } else {
-                    uiState.groups.getOrNull(pagerState.settledPage)
-                }
-            }
-        }
-        val pullToRefreshEnabled by remember {
-            derivedStateOf { (currentGroup?.enableRefresh ?: true) && !isEditMode }
-        }
-
-        Box(Modifier.fillMaxSize()) {
-            AppPullToRefresh(
-                isRefreshing = uiState.isRefreshing,
-                onRefresh = { viewModel.refreshBooks(uiState.items) },
-                enabled = pullToRefreshEnabled,
-                topPadding = paddingValues.calculateTopPadding()
-            ) {
-                folderTransition.AnimatedContent(
-                transitionSpec = {
-                    val easing = FastOutSlowInEasing
-                    val duration = 480
-                    if (targetState) {
-                        (fadeIn(animationSpec = tween(duration, easing = easing)) +
-                                scaleIn(
-                                    initialScale = 1.2f,
-                                    animationSpec = tween(duration, easing = easing)
-                                ))
-                            .togetherWith(fadeOut(animationSpec = tween(duration, easing = easing)) +
-                                    scaleOut(
-                                        targetScale = 0.8f,
-                                        animationSpec = tween(duration, easing = easing)
-                                    )
-                            )
-                    } else {
-                        (fadeIn(animationSpec = tween(duration, easing = easing)) +
-                                scaleIn(
-                                    initialScale = 0.8f,
-                                    animationSpec = tween(duration, easing = easing)
-                                ))
-                            .togetherWith(fadeOut(animationSpec = tween(duration, easing = easing)) +
-                                    scaleOut(
-                                        targetScale = 1.2f,
-                                        animationSpec = tween(duration, easing = easing)
-                                    )
-                            )
-                    }
-                }
-            ) { isRoot ->
-                if (uiState.groups.isEmpty() && !uiState.isSearch) {
-                    if (!uiState.isInitialLoading) {
-                        EmptyMessage(
-                            modifier = Modifier
-                                .fillMaxSize()
-                                .padding(
-                                    top = paddingValues.calculateTopPadding(),
-                                    bottom = 120.dp
-                                ),
-                            messageResId = R.string.bookshelf_empty
-                        )
-                    }
-                } else if (bookGroupStyle == 2 && isRoot && !isUsingStandaloneSearchGroup) {
-                    val folderColumns =
-                        if (bookshelfFolderLayoutMode == 0) bookshelfFolderLayoutList else bookshelfFolderLayoutGrid
-                    val isGridMode = bookshelfFolderLayoutMode != 0
-                    FastScrollLazyVerticalGrid(
-                        columns = GridCells.Fixed(folderColumns.coerceAtLeast(1)),
-                        modifier = Modifier
-                            .fillMaxSize()
-                            .then(
-                                with(sharedTransitionScope) {
-                                    if (this != null) Modifier.skipToLookaheadSize() else Modifier
-                                }
-                            ),
-                        contentPadding = adaptiveContentPaddingBookshelf(
-                            top = paddingValues.calculateTopPadding(),
-                            bottom = if (ThemeConfig.useFloatingBottomBar || ThemeConfig.enableBlur) 120.dp else 8.dp,
-                            horizontal = 4.dp
-                        ),
-                        verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
-                        horizontalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
-                        showFastScroll = BookshelfConfig.showBookshelfFastScrollerState.value
-                    ) {
-                        itemsIndexed(
-                            uiState.groups,
-                            key = { _, it -> it.groupId }) { index, group ->
-                            val countText = if (BookshelfConfig.showBookCountState.value) {
-                                uiState.groupBookCounts[group.groupId]?.let {
-                                    stringResource(R.string.book_count, it)
-                                }
-                            } else {
-                                null
-                            }
-                            if (bookshelfFolderLayoutMode == 0) {
-                                BookGroupItemList(
-                                    group = group,
-                                    previewBooks = uiState.groupPreviews[group.groupId]
-                                        ?: emptyList(),
-                                    countText = countText,
-                                    isCompact = BookshelfConfig.bookshelfLayoutCompactState.value,
-                                    titleSmallFont = BookshelfConfig.bookshelfTitleSmallFontState.value,
-                                    titleCenter = BookshelfConfig.bookshelfTitleCenterState.value,
-                                    titleMaxLines = BookshelfConfig.bookshelfTitleMaxLinesState.value,
-                                    coverShadow = BookshelfConfig.bookshelfCoverShadowState.value,
-                                    onClick = {
-                                        scope.launch { pagerState.scrollToPage(index) }
-                                        viewModel.setInFolderRoot(false)
-                                    },
-                                    onLongClick = {
-                                        viewModel.showOverlay(BookshelfOverlay.GroupEditSheet(group.groupId))
-                                    },
-                                    onBookClick = onBookClick
-                                )
-                            } else {
-                                BookGroupItemGrid(
-                                    group = group,
-                                    previewBooks = uiState.groupPreviews[group.groupId]
-                                        ?: emptyList(),
-                                    countText = countText,
-                                    gridStyle = BookshelfConfig.bookshelfGridLayoutState.value,
-                                    titleSmallFont = BookshelfConfig.bookshelfTitleSmallFontState.value,
-                                    titleCenter = BookshelfConfig.bookshelfTitleCenterState.value,
-                                    titleMaxLines = BookshelfConfig.bookshelfTitleMaxLinesState.value,
-                                    coverShadow = BookshelfConfig.bookshelfCoverShadowState.value,
-                                    onClick = {
-                                        scope.launch { pagerState.scrollToPage(index) }
-                                        viewModel.setInFolderRoot(false)
-                                    },
-                                    onLongClick = {
-                                        viewModel.showOverlay(BookshelfOverlay.GroupEditSheet(group.groupId))
-                                    }
-                                )
-                            }
-                        }
-                    }
-                } else {
-                    if (isUsingStandaloneSearchGroup) {
-                        BookshelfPage(
-                            paddingValues = paddingValues,
-                            books = uiState.items,
-                            uiState = uiState,
-                            selectedBookUrls = selectedBookUrls,
-                            canReorderBooks = false,
-                            onToggleBookSelection = { toggleBookSelection(it.book.bookUrl) },
-                            draggingBooks = null,
-                            pendingSavedBooks = null,
-                            onDragStarted = {},
-                            onMoveBook = { _, _, _ -> },
-                            onDragFinished = {},
-                            onGlobalSearch = { onNavigateToSearch(uiState.searchKey.trim()) },
-                            onBookClick = onBookClick,
-                            onBookLongClick = onBookLongClick,
-                            isCurrentPage = true,
-                            sharedTransitionScope = sharedTransitionScope,
-                            animatedVisibilityScope = animatedVisibilityScope,
-                        )
-                    } else {
-                        HorizontalPager(
-                            state = pagerState,
-                            modifier = Modifier
-                                .fillMaxSize()
-                                .then(
-                                    with(sharedTransitionScope) {
-                                        if (this != null) Modifier.skipToLookaheadSize() else Modifier
-                                    }
-                                ),
-                            beyondViewportPageCount = 0,
-                            key = { if (it < uiState.groups.size) uiState.groups[it].groupId else it }
-                        ) { pageIndex ->
-                            val group = uiState.groups.getOrNull(pageIndex)
-                            if (group != null) {
-                                val isSelectedGroup = group.groupId == uiState.selectedGroupId
-                                val books = uiState.allGroupBooks[group.groupId]
-                                    ?: if (isSelectedGroup) uiState.items
-                                    else persistentListOf()
-                                val canReorderBooks = isEditMode &&
-                                        !uiState.isSearch &&
-                                        (group.bookSort.takeIf { it >= 0 }
-                                            ?: uiState.bookshelfSort) == 3 &&
-                                        isSelectedGroup
-                                BookshelfPage(
-                                    paddingValues = paddingValues,
-                                    books = books,
-                                    uiState = uiState,
-                                    selectedBookUrls = selectedBookUrls,
-                                    canReorderBooks = canReorderBooks,
-                                    onToggleBookSelection = { toggleBookSelection(it.book.bookUrl) },
-                                    draggingBooks = if (isSelectedGroup) {
-                                        uiState.draggingBooks
-                                    } else {
-                                        null
-                                    },
-                                    pendingSavedBooks = if (isSelectedGroup) {
-                                        uiState.pendingSavedBooks
-                                    } else {
-                                        null
-                                    },
-                                    onDragStarted = {
-                                        if (isSelectedGroup) viewModel.startDraggingBooks(it)
-                                    },
-                                    onMoveBook = { from, to, currentBooks ->
-                                        if (isSelectedGroup) {
-                                            viewModel.moveDraggingBook(from, to, currentBooks)
-                                        }
-                                    },
-                                    onDragFinished = {
-                                        if (isSelectedGroup) viewModel.finishDraggingBooks()
-                                    },
-                                    onGlobalSearch = { onNavigateToSearch(uiState.searchKey.trim()) },
-                                    onBookClick = onBookClick,
-                                    onBookLongClick = onBookLongClick,
-                                    isCurrentPage = isSelectedGroup,
-                                    sharedTransitionScope = sharedTransitionScope,
-                                    animatedVisibilityScope = animatedVisibilityScope,
-                                )
-                            }
-                        }
-                    }
-                }
-            }
-            }
-
-            TopFloatingStickyItem(
-                item = editStickySummary,
-                modifier = Modifier
-                    .align(Alignment.TopCenter)
-                    .padding(top = paddingValues.calculateTopPadding() + 6.dp),
-            ) { summary ->
-                Box {
-                    NormalCard(
-                        cornerRadius = 32.dp,
-                        containerColor = LegadoTheme.colorScheme.surfaceContainer,
-                        contentColor = LegadoTheme.colorScheme.onCardContainer
-                    ) {
-                        Row(
-                            modifier = Modifier.padding(all = 8.dp),
-                            verticalAlignment = Alignment.CenterVertically
-                        ) {
-                            TextCard(
-                                icon = AppIcons.Close,
-                                backgroundColor = LegadoTheme.colorScheme.surfaceContainerHighest,
-                                cornerRadius = 16.dp,
-                                verticalPadding = 8.dp,
-                                horizontalPadding = 8.dp,
-                                onClick = exitEditMode
-                            )
-                            Spacer(modifier = Modifier.width(8.dp))
-                            AppText(
-                                text = stringResource(
-                                    R.string.bookshelf_selected_count,
-                                    summary.selectedCount
-                                ),
-                                style = LegadoTheme.typography.labelSmallEmphasized
-                            )
-                            AppText(
-                                text = " · ${
-                                    stringResource(
-                                        R.string.bookshelf_total_count,
-                                        summary.currentGroupTotalCount
-                                    )
-                                }",
-                                style = LegadoTheme.typography.labelSmallEmphasized
-                            )
-                            Spacer(modifier = Modifier.width(8.dp))
-                            if (summary.showGroupName && !summary.groupName.isNullOrBlank()) {
-                                TextCard(
-                                    text = summary.groupName,
-                                    textStyle = LegadoTheme.typography.labelSmallEmphasized,
-                                    backgroundColor = LegadoTheme.colorScheme.surfaceContainerHighest,
-                                    cornerRadius = 16.dp,
-                                    verticalPadding = 8.dp,
-                                    horizontalPadding = 12.dp,
-                                    onClick = {
-                                        viewModel.showOverlay(BookshelfOverlay.GroupMenu)
-                                    }
-                                )
-                            }
-                        }
-                    }
-
-
-                    if (summary.showGroupName) {
-                        RoundDropdownMenu(
-                            expanded = showGroupMenu,
-                            onDismissRequest = { viewModel.dismissOverlay() }
-                        ) { dismiss ->
-                            uiState.groups.forEach { group ->
-                                RoundDropdownMenuItem(
-                                    text = group.groupName,
-                                    onClick = {
-                                        val targetIndex =
-                                            uiState.groups.indexOfFirst { it.groupId == group.groupId }
-                                        if (targetIndex >= 0) {
-                                            scope.launch {
-                                                if (pagerState.currentPage != targetIndex) {
-                                                    pagerState.animateScrollToPage(targetIndex)
-                                                }
-                                            }
-                                        }
-                                        if (uiState.isSearch || uiState.selectedGroupId != group.groupId) {
-                                            viewModel.changeGroup(group.groupId)
-                                        }
-                                        if (bookGroupStyle == 2) {
-                                            viewModel.setInFolderRoot(false)
-                                        }
-                                        dismiss()
-                                    },
-                                    trailingIcon = {
-                                        if (currentMenuGroupId == group.groupId) {
-                                            Icon(
-                                                Icons.Default.Check,
-                                                null,
-                                                modifier = Modifier.size(18.dp)
-                                            )
-                                        }
-                                    }
-                                )
-                            }
-                        }
-                    }
-                }
-            }
-
-        }
-    }
-
-    BookshelfOverlays(
-        activeOverlay = activeOverlay,
-        uiState = uiState,
-        viewModel = viewModel,
-        selectedBookUrls = selectedBookUrls,
-        importLauncher = importLauncher,
-        exportLauncher = exportLauncher,
-        clearSelection = clearSelection
-    )
-}
-
-@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()) {
-                            SmallPlainButton(
-                                modifier = Modifier.padding(start = 12.dp),
-                                onClick = onClearSearch,
-                                icon = AppIcons.Close,
-                                contentDescription = stringResource(R.string.clear)
-                            )
-                        }
-                    }
-                )
-            }
-            bottomContent()
-        }
-    )
-}
-
-@Composable
-private fun BookshelfOverlays(
-    activeOverlay: BookshelfOverlay?,
-    uiState: BookshelfUiState,
-    viewModel: BookshelfViewModel,
-    selectedBookUrls: Set<String>,
-    importLauncher: ManagedActivityResultLauncher<Array<String>, Uri?>,
-    exportLauncher: ManagedActivityResultLauncher<String, Uri?>,
-    clearSelection: () -> Unit
-) {
-    BookshelfConfigSheet(
-        show = activeOverlay == BookshelfOverlay.ConfigSheet,
-        onDismissRequest = { viewModel.dismissOverlay() }
-    )
-
-    GroupManageSheet(
-        show = activeOverlay == BookshelfOverlay.GroupManageSheet,
-        onDismissRequest = { viewModel.dismissOverlay() }
-    )
-
-    val groups by viewModel.allGroupsFlow.collectAsStateWithLifecycle()
-
-    if (activeOverlay is BookshelfOverlay.GroupEditSheet) {
-        val editGroup = groups.firstOrNull { it.groupId == activeOverlay.groupId }
-        if (editGroup != null) {
-            GroupEditSheet(
-                show = true,
-                group = editGroup,
-                onDismissRequest = { viewModel.dismissOverlay() }
-            )
-        }
-    }
-
-    GroupSelectSheet(
-        show = activeOverlay == BookshelfOverlay.GroupSelectSheet,
-        groups = groups.filter { it.groupId > 0 },
-        currentGroupId = 0L,
-        onDismissRequest = { viewModel.dismissOverlay() },
-        onConfirm = { groupId ->
-            viewModel.moveBooksToGroup(selectedBookUrls, groupId)
-            viewModel.dismissOverlay()
-            clearSelection()
-        }
-    )
-
-    SourceInputDialog(
-        show = activeOverlay == BookshelfOverlay.AddUrlDialog,
-        title = stringResource(R.string.add_book_url),
-        onDismissRequest = { viewModel.dismissOverlay() },
-        onConfirm = { url ->
-            viewModel.addBookByUrl(url)
-            viewModel.dismissOverlay()
-        }
-    )
-
-    FilePickerSheet(
-        show = activeOverlay == BookshelfOverlay.ImportSheet,
-        onDismissRequest = { viewModel.dismissOverlay() },
-        title = stringResource(R.string.import_bookshelf),
-        onSelectSysFile = { types ->
-            importLauncher.launch(types)
-            viewModel.dismissOverlay()
-        },
-        onManualInput = {
-            viewModel.showOverlay(BookshelfOverlay.AddUrlDialog)
-        },
-        allowExtensions = arrayOf("json", "txt")
-    )
-
-    FilePickerSheet(
-        show = activeOverlay == BookshelfOverlay.ExportSheet,
-        onDismissRequest = { viewModel.dismissOverlay() },
-        title = stringResource(R.string.export_bookshelf),
-        onSelectSysDir = {
-            viewModel.dismissOverlay()
-            exportLauncher.launch("bookshelf.json")
-        },
-        onUpload = {
-            viewModel.dismissOverlay()
-            viewModel.uploadBookshelf(uiState.items)
-        }
-    )
-
-    AppLogSheet(
-        show = activeOverlay == BookshelfOverlay.LogSheet,
-        onDismissRequest = { viewModel.dismissOverlay() }
-    )
-
-    AppAlertDialog(
-        show = activeOverlay == BookshelfOverlay.BatchDownloadConfirmDialog,
-        onDismissRequest = { viewModel.dismissOverlay() },
-        title = stringResource(R.string.draw),
-        text = stringResource(R.string.sure_cache_book),
-        confirmText = stringResource(android.R.string.ok),
-        onConfirm = {
-            viewModel.dismissOverlay()
-            viewModel.downloadBooks(selectedBookUrls)
-        },
-        dismissText = stringResource(android.R.string.cancel),
-        onDismiss = { viewModel.dismissOverlay() }
-    )
-
-    if (uiState.isLoading) {
-        Dialog(onDismissRequest = {}) {
-            NormalCard(
-                cornerRadius = 12.dp,
-                containerColor = LegadoTheme.colorScheme.surfaceContainerHigh
-            ) {
-                Column(
-                    modifier = Modifier.padding(24.dp),
-                    horizontalAlignment = Alignment.CenterHorizontally
-                ) {
-                    AppCircularProgressIndicator()
-                    uiState.loadingText?.let {
-                        AppText(
-                            text = it,
-                            modifier = Modifier.padding(top = 16.dp),
-                            style = LegadoTheme.typography.bodyMedium
-                        )
-                    }
-                }
-            }
-        }
-    }
-}
-
-private data class BookshelfEditStickySummary(
-    val selectedCount: Int,
-    val currentGroupTotalCount: Int,
-    val groupName: String?,
-    val showGroupName: Boolean,
-)
-
-@Composable
-fun BookshelfPage(
-    paddingValues: PaddingValues,
-    books: ImmutableList<BookUiItem>,
-    uiState: BookshelfUiState,
-    selectedBookUrls: ImmutableSet<String>,
-    canReorderBooks: Boolean,
-    onToggleBookSelection: (BookUiItem) -> Unit,
-    draggingBooks: ImmutableList<BookUiItem>?,
-    pendingSavedBooks: ImmutableList<BookUiItem>?,
-    onDragStarted: (ImmutableList<BookUiItem>) -> Unit,
-    onMoveBook: (fromIndex: Int, toIndex: Int, currentBooks: ImmutableList<BookUiItem>) -> Unit,
-    onDragFinished: () -> Unit,
-    onGlobalSearch: () -> Unit,
-    onBookClick: (BookShelfItem) -> Unit,
-    onBookLongClick: (BookShelfItem, String?) -> Unit,
-    isCurrentPage: Boolean = true,
-    sharedTransitionScope: SharedTransitionScope? = null,
-    animatedVisibilityScope: AnimatedVisibilityScope? = null,
-) {
-    if (books.isEmpty()) {
-        if (!isCurrentPage) return
-        if (uiState.isSearch) {
-            EmptyMessage(
-                modifier = Modifier
-                    .fillMaxSize()
-                    .padding(
-                        top = paddingValues.calculateTopPadding(),
-                        bottom = 120.dp
-                    ),
-                message = stringResource(R.string.bookshelf_empty_global_search),
-                buttonText = stringResource(R.string.global_search),
-                onButtonClick = onGlobalSearch
-            )
-        } else if (!uiState.isInitialLoading) {
-            EmptyMessage(
-                modifier = Modifier
-                    .fillMaxSize()
-                    .padding(
-                        top = paddingValues.calculateTopPadding(),
-                        bottom = 120.dp
-                    ),
-                messageResId = R.string.bookshelf_empty
-            )
-        }
-        return
-    }
-
-    val configuration = LocalConfiguration.current
-    val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
-    val bookshelfLayoutMode by remember(isLandscape) {
-        derivedStateOf {
-            if (isLandscape) BookshelfConfig.bookshelfLayoutModeLandscapeState.value
-            else BookshelfConfig.bookshelfLayoutModePortraitState.value
-        }
-    }
-    val bookshelfLayoutGrid by remember(isLandscape) {
-        derivedStateOf {
-            if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscapeState.value
-            else BookshelfConfig.bookshelfLayoutGridPortraitState.value
-        }
-    }
-    val bookshelfLayoutList by remember(isLandscape) {
-        derivedStateOf {
-            if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscapeState.value
-            else BookshelfConfig.bookshelfLayoutListPortraitState.value
-        }
-    }
-    val columns by remember {
-        derivedStateOf {
-            if (bookshelfLayoutMode == 0) bookshelfLayoutList else bookshelfLayoutGrid
-        }
-    }
-    val isGridMode by remember { derivedStateOf { bookshelfLayoutMode != 0 } }
-    val bookItemGridStyle by BookshelfConfig.bookshelfGridLayoutState
-    val bookItemIsCompact by BookshelfConfig.bookshelfLayoutCompactState
-    val bookItemTitleSmallFont by BookshelfConfig.bookshelfTitleSmallFontState
-    val bookItemTitleCenter by BookshelfConfig.bookshelfTitleCenterState
-    val bookItemTitleMaxLines by BookshelfConfig.bookshelfTitleMaxLinesState
-    val bookItemCoverShadow by BookshelfConfig.bookshelfCoverShadowState
-    val showFastScroll by BookshelfConfig.showBookshelfFastScrollerState
-    val totalHorizontalPadding =
-        if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) 12.dp else 16.dp
-    val gridContentHorizontalPadding = totalHorizontalPadding / 2
-    val gridInnerHorizontalPadding = totalHorizontalPadding / 2
-    val hapticFeedback = LocalHapticFeedback.current
-    val displayBooks = draggingBooks ?: pendingSavedBooks ?: books
-    val gridState = rememberLazyGridState()
-    val reorderableState = rememberReorderableLazyGridState(gridState) { from, to ->
-        if (canReorderBooks) {
-            onMoveBook(from.index, to.index, displayBooks)
-            hapticFeedback.performHapticFeedback(HapticFeedbackType.SegmentFrequentTick)
-        }
-    }
-    LaunchedEffect(reorderableState.isAnyItemDragging) {
-        if (!reorderableState.isAnyItemDragging) {
-            onDragFinished()
-        }
-    }
-
-    Box(
-        modifier = Modifier
-            .fillMaxSize()
-            .then(
-                with(sharedTransitionScope) {
-                    if (this != null) Modifier.skipToLookaheadSize() else Modifier
-                }
-            )
-    ) {
-        FastScrollLazyVerticalGrid(
-            columns = GridCells.Fixed(columns.coerceAtLeast(1)),
-            state = gridState,
-            modifier = Modifier
-                .fillMaxSize()
-                .semantics(mergeDescendants = true) { contentDescription = "bookshelf_list" }
-                .then(
-                    with(sharedTransitionScope) {
-                        if (this != null) Modifier.skipToLookaheadSize() else Modifier
-                    }
-                ),
-            contentPadding = adaptiveContentPaddingBookshelf(
-                top = paddingValues.calculateTopPadding(),
-                bottom = if (ThemeConfig.useFloatingBottomBar || ThemeConfig.enableBlur) 120.dp else 8.dp,
-                horizontal = 8.dp
-            ),
-            verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
-            horizontalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
-            showFastScroll = showFastScroll
-        ) {
-            items(displayBooks, key = { it.book.bookUrl }) { bookUi ->
-                val isSelected = selectedBookUrls.contains(bookUi.book.bookUrl)
-                val sharedCoverKey = if (isCurrentPage) {
-                    bookCoverSharedElementKey(
-                        bookUi.book.bookUrl,
-                        "bookshelf:${uiState.selectedGroupId}"
-                    )
-                } else {
-                    null
-                }
-                ReorderableItem(
-                    state = reorderableState,
-                    key = bookUi.book.bookUrl,
-                    enabled = canReorderBooks
-                ) {
-                    BookItem(
-                        bookUi = bookUi,
-                        modifier = Modifier.then(
-                            if (canReorderBooks) {
-                                Modifier.longPressDraggableHandle(
-                                    onDragStarted = {
-                                        onDragStarted(displayBooks)
-                                        hapticFeedback.performHapticFeedback(
-                                            HapticFeedbackType.GestureThresholdActivate
-                                        )
-                                    },
-                                    onDragStopped = {
-                                        hapticFeedback.performHapticFeedback(
-                                            HapticFeedbackType.GestureEnd
-                                        )
-                                    }
-                                )
-                            } else {
-                                Modifier
-                            }
-                        ),
-                        layoutMode = bookshelfLayoutMode,
-                        isSelected = isSelected,
-                        gridStyle = bookItemGridStyle,
-                        isCompact = bookItemIsCompact,
-                        isUpdating = uiState.updatingBooks.contains(bookUi.book.bookUrl),
-                        titleSmallFont = bookItemTitleSmallFont,
-                        titleCenter = bookItemTitleCenter,
-                        titleMaxLines = bookItemTitleMaxLines,
-                        coverShadow = bookItemCoverShadow,
-                        isSearchMode = uiState.isSearch,
-                        searchKey = uiState.searchKey,
-                        sharedTransitionScope = sharedTransitionScope,
-                        animatedVisibilityScope = animatedVisibilityScope,
-                        sharedCoverKey = sharedCoverKey,
-                        onClick = {
-                            if (uiState.isEditMode) {
-                                onToggleBookSelection(bookUi)
-                            } else {
-                                onBookClick(bookUi.book)
-                            }
-                        },
-                        onLongClick = if (canReorderBooks) {
-                            null
-                        } else {
-                            {
-                                if (uiState.isEditMode) {
-                                    onToggleBookSelection(bookUi)
-                                } else {
-                                    onBookLongClick(bookUi.book, sharedCoverKey)
-                                }
-                            }
-                        }
-                    )
-                }
-            }
-        }
-    }
-}
+import sh.calvin.reorderable.rememberReorderableLazyGridState