HapeLee 2 месяцев назад
Родитель
Сommit
c9c3e48b27

+ 0 - 1
app/src/main/java/io/legado/app/ui/book/manga/MangaReaderContract.kt

@@ -241,7 +241,6 @@ sealed interface MangaReaderIntent {
         val itemIndex: Int,
         val firstItemIndex: Int = itemIndex,
         val lastItemIndex: Int = itemIndex,
-        val currentChapterVisible: Boolean,
         val navigationId: Long,
     ) : MangaReaderIntent
     data class PagerScrollChanged(val inProgress: Boolean) : MangaReaderIntent

+ 20 - 14
app/src/main/java/io/legado/app/ui/book/manga/MangaReaderInteraction.kt

@@ -40,14 +40,23 @@ internal fun nextMangaClickAction(action: Int): Int = when (action) {
     else -> -1
 }
 
-internal fun mangaPageStepTarget(
+/**
+ * 找 [direction] 方向上的下一个「真实页」:跳过 ChapterTransition/ChapterEdge 等非页项。
+ *
+ * 直接以相邻下标做 PageStep 时,目标落在过渡页上既无法推进,scrollRequest 也因过渡页非
+ * Page 而永远不清除(Pager 卡在章节边界)。保证步进永远落在实际页面。
+ */
+internal fun nextPageItemIndex(
+    items: List<MangaReaderItemUi>,
     currentIndex: Int,
-    itemCount: Int,
     direction: Int,
 ): Int? {
-    if (itemCount <= 0) return null
-    val target = (currentIndex + direction).coerceIn(0, itemCount - 1)
-    return target.takeIf { it != currentIndex }
+    var index = currentIndex + direction
+    while (index in items.indices) {
+        if (items[index] is MangaReaderItemUi.Page) return index
+        index += direction
+    }
+    return null
 }
 
 internal fun shouldExposeMangaPages(currentChapterFinished: Boolean): Boolean =
@@ -56,20 +65,17 @@ internal fun shouldExposeMangaPages(currentChapterFinished: Boolean): Boolean =
 enum class MangaChapterSwitch { NONE, NEXT, PREVIOUS }
 
 /**
- * 决定可见页是否触发章节切换:只有当前章节已完全滑出视口时,
- * 才允许沿可见页的章节方向自动切章;否则只是停留在当前章记录进度。
+ * 决定聚焦页是否触发章节切换:只认「用户当前聚焦的那一页」所在章节。
+ *
+ * 焦点页由阅读器上报(Webtoon 为视口底部页、Pager 为当前页/跨页),因此不依赖
+ * 「本章是否仍可见」这类在窗口重建/定位期间会闪断的启发式,避免误切。
  */
 internal fun mangaChapterSwitchDecision(
     currentChapterIndex: Int,
     visibleChapterIndex: Int,
-    currentChapterVisible: Boolean,
 ): MangaChapterSwitch = when {
-    currentChapterIndex < visibleChapterIndex ->
-        if (currentChapterVisible) MangaChapterSwitch.NONE else MangaChapterSwitch.NEXT
-
-    currentChapterIndex > visibleChapterIndex ->
-        if (currentChapterVisible) MangaChapterSwitch.NONE else MangaChapterSwitch.PREVIOUS
-
+    currentChapterIndex < visibleChapterIndex -> MangaChapterSwitch.NEXT
+    currentChapterIndex > visibleChapterIndex -> MangaChapterSwitch.PREVIOUS
     else -> MangaChapterSwitch.NONE
 }
 

+ 0 - 24
app/src/main/java/io/legado/app/ui/book/manga/MangaReaderOverlays.kt

@@ -40,11 +40,9 @@ import androidx.compose.material.icons.automirrored.filled.ArrowForward
 import androidx.compose.material.icons.automirrored.filled.MenuBook
 import androidx.compose.material.icons.filled.AutoMode
 import androidx.compose.material.icons.filled.CloudDownload
-import androidx.compose.material.icons.filled.FilterAlt
 import androidx.compose.material.icons.filled.MoreVert
 import androidx.compose.material.icons.filled.Refresh
 import androidx.compose.material.icons.filled.SwapHoriz
-import androidx.compose.material.icons.filled.TouchApp
 import androidx.compose.material.icons.filled.Tune
 import androidx.compose.material3.Button
 import androidx.compose.material3.CircularProgressIndicator
@@ -539,28 +537,6 @@ private fun MangaMenuBottomBar(
                                         )
                                     )
                                 })
-                                add(
-                                ReaderMenuAction(
-                                    Icons.Filled.FilterAlt,
-                                    stringResource(R.string.manga_reader_filter_short)
-                                ) {
-                                    onIntent(
-                                        MangaReaderIntent.OpenSettings(
-                                            MangaReaderSettingsCategory.FILTER
-                                        )
-                                    )
-                                })
-                                add(
-                                ReaderMenuAction(
-                                    Icons.Filled.TouchApp,
-                                    stringResource(R.string.manga_reader_click_area_short)
-                                ) {
-                                    onIntent(
-                                        MangaReaderIntent.OpenSettings(
-                                            MangaReaderSettingsCategory.CLICK_ACTIONS
-                                        )
-                                    )
-                                })
                             },
                             glassEnabled = glassOnControls,
                             backdrop = backdrop,

+ 33 - 23
app/src/main/java/io/legado/app/ui/book/manga/MangaReaderScreen.kt

@@ -472,19 +472,19 @@ private fun WebtoonMangaList(
     LaunchedEffect(listState, state.pages, state.navigationId) {
         snapshotFlow {
             val visibleItems = listState.layoutInfo.visibleItemsInfo
-            val currentChapterVisible = visibleItems.any { item ->
-                (state.pages.getOrNull(item.index) as? MangaReaderItemUi.Page)?.chapterIndex == state.chapterIndex
-            }
             val firstItemIndex = visibleItems.firstOrNull()?.index
-            if (firstItemIndex == null) null else firstItemIndex to currentChapterVisible
+            val focusedItemIndex = visibleItems.lastOrNull()?.index
+            if (firstItemIndex == null || focusedItemIndex == null) null
+            else focusedItemIndex to firstItemIndex
         }
             .distinctUntilChanged()
             .collect { entry ->
-                entry?.let { (index, stillVisible) ->
-                    when (val item = state.pages.getOrNull(index)) {
+                entry?.let { (focusedIndex, firstIndex) ->
+                    when (val item = state.pages.getOrNull(focusedIndex)) {
                         is MangaReaderItemUi.Page -> onIntent(MangaReaderIntent.VisibleItemChanged(
-                            itemIndex = index,
-                            currentChapterVisible = stillVisible,
+                            itemIndex = focusedIndex,
+                            firstItemIndex = firstIndex,
+                            lastItemIndex = focusedIndex,
                             navigationId = state.navigationId,
                         ))
                         is MangaReaderItemUi.ChapterTransition -> Unit
@@ -693,18 +693,20 @@ private fun HorizontalMangaPager(
             val indices = spread?.itemIndices.orEmpty()
             val itemIndex = state.scrollRequest?.itemIndex?.takeIf { it in indices }
                 ?: indices.firstOrNull()
-            val page = itemIndex?.let(state.pages::getOrNull) as? MangaReaderItemUi.Page
-            if (!spreadLayoutReady) null else Triple(indices, itemIndex, page?.chapterIndex == state.chapterIndex)
+            if (!spreadLayoutReady) null
+            // 滚动中不切章:随 fling 越过章节边界时延迟到落定再上报,避免窗口重建期误切。
+            // 把 isScrollInProgress 并入快照,滚动结束会产生新值从而重发聚焦页。
+            else Triple(pagerState.isScrollInProgress, indices, itemIndex)
         }.distinctUntilChanged()
             .collect { entry ->
-                val (indices, itemIndex, stillVisible) = entry ?: return@collect
+                val (isScrolling, indices, itemIndex) = entry ?: return@collect
+                if (isScrolling) return@collect
                 itemIndex?.let { index ->
                     when (val item = state.pages.getOrNull(index)) {
                         is MangaReaderItemUi.Page -> onIntent(MangaReaderIntent.VisibleItemChanged(
                             itemIndex = index,
                             firstItemIndex = indices.first(),
                             lastItemIndex = indices.last(),
-                            currentChapterVisible = stillVisible,
                             navigationId = state.navigationId,
                         ))
                         is MangaReaderItemUi.ChapterTransition -> Unit
@@ -951,13 +953,14 @@ private fun VerticalMangaPager(
     LaunchedEffect(pagerState, state.pages, state.navigationId) {
         snapshotFlow {
             val item = state.pages.getOrNull(pagerState.currentPage)
-            Triple(pagerState.currentPage, item, (item as? MangaReaderItemUi.Page)?.chapterIndex == state.chapterIndex)
+            // 滚动中不切章:把 isScrollInProgress 并入快照,滚动结束产生新值从而重发聚焦页。
+            Triple(pagerState.isScrollInProgress, pagerState.currentPage, item)
         }.distinctUntilChanged()
-            .collect { (page, item, stillVisible) ->
+            .collect { (isScrolling, page, item) ->
+                if (isScrolling) return@collect
                 when (item) {
                     is MangaReaderItemUi.Page -> onIntent(MangaReaderIntent.VisibleItemChanged(
                         itemIndex = page,
-                        currentChapterVisible = stillVisible,
                         navigationId = state.navigationId,
                     ))
                     is MangaReaderItemUi.ChapterTransition -> Unit
@@ -1323,13 +1326,15 @@ private fun MangaImageLoadOverlay(
     onRetryChapter: () -> Unit,
 ) {
     if (loadState is MangaPageLoadState.Ready) return
-    Box(
-        modifier = Modifier
-            .fillMaxSize()
-            .background(Color.Black.copy(alpha = 0.55f)),
-        contentAlignment = Alignment.Center,
-    ) {
-        if (loadState is MangaPageLoadState.Failed) {
+    if (loadState is MangaPageLoadState.Failed) {
+        // 失败态保留深色底便于重试按钮可读;加载/排队态不再整页压黑罩,
+        // 避免已解码淡入的图被一层「阴影」盖住(#2082)。
+        Box(
+            modifier = Modifier
+                .fillMaxSize()
+                .background(Color.Black.copy(alpha = 0.55f)),
+            contentAlignment = Alignment.Center,
+        ) {
             Column(horizontalAlignment = Alignment.CenterHorizontally) {
                 MediumOutlinedButton(onClick = onRetry, text = stringResource(R.string.retry))
                 MediumOutlinedButton(
@@ -1337,7 +1342,12 @@ private fun MangaImageLoadOverlay(
                     text = stringResource(R.string.manga_reader_retry_failed_chapter),
                 )
             }
-        } else {
+        }
+    } else {
+        Box(
+            modifier = Modifier.fillMaxSize(),
+            contentAlignment = Alignment.Center,
+        ) {
             androidx.compose.material3.CircularProgressIndicator()
         }
     }

+ 72 - 34
app/src/main/java/io/legado/app/ui/book/manga/MangaReaderViewModel.kt

@@ -262,7 +262,6 @@ class MangaReaderViewModel(
                 intent.itemIndex,
                 intent.firstItemIndex,
                 intent.lastItemIndex,
-                intent.currentChapterVisible,
                 intent.navigationId,
             )
             is MangaReaderIntent.PagerScrollChanged -> {
@@ -381,6 +380,9 @@ class MangaReaderViewModel(
         val current = session.currentChapter
         if (current !is MangaChapterState.Ready) {
             if (pendingExplicitChapterIndex == session.chapterIndex) {
+                // 显式跳章失败后立即放开门闩:否则目标页一直不可见时,
+                // 之后对该章的目录/上一章点击会被 openChapter 静默吞掉。
+                if (current is MangaChapterState.Failed) pendingExplicitChapterIndex = null
                 showExplicitChapterPlaceholder(
                     chapterIndex = session.chapterIndex,
                     pageIndex = session.pageIndex,
@@ -500,21 +502,29 @@ class MangaReaderViewModel(
             )
             }
         }
-        fun makePreviousItems(chapter: MangaChapterState): List<MangaReaderItemUi> = when (chapter) {
-            is MangaChapterState.Ready -> chapterItems(chapter.chapter) + chapterTransition(
-                chapter, "prev", session.chapterIndex - 1,
-                appCtx.getString(R.string.manga_reader_loading_prev),
-            )
-            else -> chapterTransition(
+        // 「隐藏章节首尾提示」开启时不再插入 ChapterTransition 过渡页:相邻章节已就绪则
+        // 无缝衔接,未就绪则列表自然终止,待其加载完成后再补齐。
+        val hideEdgePrompts = latestMangaSettings.hideTitle
+        fun makePreviousItems(chapter: MangaChapterState): List<MangaReaderItemUi> {
+            val prevItems = if (chapter is MangaChapterState.Ready) {
+                chapterItems(chapter.chapter)
+            } else emptyList()
+            val transition = if (hideEdgePrompts) emptyList() else chapterTransition(
                 chapter, "prev", session.chapterIndex - 1,
                 appCtx.getString(R.string.manga_reader_loading_prev),
             )
+            return prevItems + transition
         }
-        fun makeNextItems(chapter: MangaChapterState): List<MangaReaderItemUi> =
-            chapterTransition(
+
+        fun makeNextItems(chapter: MangaChapterState): List<MangaReaderItemUi> {
+            val transition = if (hideEdgePrompts) emptyList() else chapterTransition(
                 chapter, "next", session.chapterIndex + 1,
                 appCtx.getString(R.string.manga_reader_loading_next),
-            ) + if (chapter is MangaChapterState.Ready) chapterItems(chapter.chapter) else emptyList()
+            )
+            return transition + if (chapter is MangaChapterState.Ready) {
+                chapterItems(chapter.chapter)
+            } else emptyList()
+        }
 
         refreshContentJob?.cancel()
         refreshContentJob = viewModelScope.launch {
@@ -532,6 +542,25 @@ class MangaReaderViewModel(
                 pendingExplicitChapterIndex = pendingExplicitChapterIndex,
                 targetChapterIndex = session.chapterIndex,
             )
+            // 锚点按 (章节, 页码) 定位,不依赖含图片 URL 的 item key:URL/页数变化导致 key
+            // 失效后不再回退到旧裸索引(否则会把阅读器滚到错章并触发连环误切),而是按
+            // 会话当前页码重算安全位置并主动复位。
+            val oldCurrentItem = oldState.pages.getOrNull(oldState.currentItemIndex)
+            val anchoredIndex = if (shouldPosition) null else oldCurrentItem?.let { anchor ->
+                if (anchor is MangaReaderItemUi.Page) {
+                    items.indexOfFirst {
+                        it is MangaReaderItemUi.Page &&
+                                it.chapterIndex == anchor.chapterIndex &&
+                                it.pageIndex == anchor.pageIndex
+                    }.takeIf { it >= 0 }
+                } else null
+            }
+            // 旧 key 仍存在于新列表时 LazyColumn/Pager 能按 key 保住滚动位置;key 失效
+            // (如图片 URL 变化)时必须主动复位到锚点,否则列表停在旧偏移上会串到邻章。
+            val keyPreserved =
+                oldCurrentItem?.let { old -> items.any { it.key == old.key } } == true
+            val targetIndex = anchoredIndex ?: safePosition
+            val positionChanged = shouldPosition || anchoredIndex == null || !keyPreserved
             _uiState.update { old ->
                 old.copy(
                     bookName = book.name,
@@ -546,14 +575,9 @@ class MangaReaderViewModel(
                     sourceType = book.sourceType,
                     inBookshelf = book.inBookshelf,
                     pages = items,
-                    currentItemIndex = if (shouldPosition) safePosition else {
-                        val anchorKey = old.pages.getOrNull(old.currentItemIndex)?.key
-                        anchorKey?.let { key ->
-                            items.indexOfFirst { it.key == key }.takeIf { it >= 0 }
-                        } ?: old.currentItemIndex.coerceIn(0, (items.size - 1).coerceAtLeast(0))
-                    },
-                    currentPage = if (shouldPosition) session.pageIndex else old.currentPage,
-                    pageCount = if (shouldPosition) current.chapter.pages.size else old.pageCount,
+                    currentItemIndex = targetIndex,
+                    currentPage = if (positionChanged) session.pageIndex else old.currentPage,
+                    pageCount = if (positionChanged) current.chapter.pages.size else old.pageCount,
                     chapterIndex = session.chapterIndex,
                     chapterCount = session.chapterCount,
                     cacheAvailable = !book.isLocal,
@@ -562,20 +586,19 @@ class MangaReaderViewModel(
                     pendingChapterIndex = null,
                     errorMessage = null,
                     settings = readSettings(latestMangaSettings),
-                    scrollRequest = if (shouldPosition) {
+                    scrollRequest = if (positionChanged) {
                         MangaScrollRequest(
                             id = System.nanoTime(),
-                            itemIndex = safePosition,
+                            itemIndex = targetIndex,
                             animated = false,
                         )
                     } else old.scrollRequest,
                 )
             }
-            if (shouldPosition && pendingExplicitChapterIndex != session.chapterIndex) updateVisibleItem(
-                itemIndex = safePosition,
-                firstItemIndex = safePosition,
-                lastItemIndex = safePosition,
-                currentChapterVisible = true,
+            if (positionChanged && pendingExplicitChapterIndex != session.chapterIndex) updateVisibleItem(
+                itemIndex = targetIndex,
+                firstItemIndex = targetIndex,
+                lastItemIndex = targetIndex,
                 navigationId = _uiState.value.navigationId,
             )
         }
@@ -764,10 +787,14 @@ class MangaReaderViewModel(
                 it.copy(reverseVolumeKeyPage = enabled)
             }
             MangaReaderSettingKey.HIDE_MANGA_TITLE -> {
-                updateMangaPreference { it.copy(hideTitle = enabled) }
-                executeSession(
-                    MangaSessionCommand.RetryChapter(readerSession.state.value.chapterIndex)
-                )
+                // atomicUpdate 同步更新 overlay,写后 currentSettings 即为新值;显式同步
+                // latestMangaSettings 再重排,避免 settings 流收集器与 refreshContent 竞态
+                // 导致过渡页开关不生效。
+                viewModelScope.launch(start = CoroutineStart.UNDISPATCHED) {
+                    mangaSettingsGateway.update { it.copy(hideTitle = enabled) }
+                    latestMangaSettings = mangaSettingsGateway.currentSettings
+                    refreshContent()
+                }
             }
             MangaReaderSettingKey.ENABLE_GRAY -> {
                 updateMangaPreference {
@@ -1032,9 +1059,9 @@ class MangaReaderViewModel(
         val state = _uiState.value
         val range = visibleItemRange?.takeIf { state.currentItemIndex in it }
             ?: (state.currentItemIndex..state.currentItemIndex)
-        val target = mangaPageStepTarget(
+        val target = nextPageItemIndex(
+            items = state.pages,
             currentIndex = if (direction > 0) range.last else range.first,
-            itemCount = state.pages.size,
             direction = direction,
         )
         if (target == null) {
@@ -1063,13 +1090,22 @@ class MangaReaderViewModel(
         itemIndex: Int,
         firstItemIndex: Int,
         lastItemIndex: Int,
-        currentChapterVisible: Boolean,
         navigationId: Long,
     ) {
         val state = _uiState.value
         if (navigationId != state.navigationId) return
         if (state.isLoading) return
-        val item = state.pages.getOrNull(itemIndex) as? MangaReaderItemUi.Page ?: return
+        val item = state.pages.getOrNull(itemIndex)
+        if (item !is MangaReaderItemUi.Page) {
+            // 过渡页/边缘项:只维护可见区间并清掉指向它的 scrollRequest(防御性兜底,
+            // PageStep 已保证目标为真实页;此处保证 seek/遗留请求落在过渡页时不卡死)。
+            visibleItemRange = firstItemIndex.coerceAtMost(lastItemIndex)..
+                    lastItemIndex.coerceAtLeast(firstItemIndex)
+            if (state.scrollRequest?.itemIndex == itemIndex) {
+                _uiState.update { it.copy(scrollRequest = null) }
+            }
+            return
+        }
         val requestedItem = state.scrollRequest?.itemIndex
             ?.let(state.pages::getOrNull) as? MangaReaderItemUi.Page
         if (requestedItem != null && item.chapterIndex != requestedItem.chapterIndex) return
@@ -1081,7 +1117,6 @@ class MangaReaderViewModel(
         when (mangaChapterSwitchDecision(
             currentChapterIndex = readerSession.state.value.chapterIndex,
             visibleChapterIndex = item.chapterIndex,
-            currentChapterVisible = currentChapterVisible,
         )) {
             MangaChapterSwitch.NEXT,
             MangaChapterSwitch.PREVIOUS -> executeSession(
@@ -1112,6 +1147,9 @@ class MangaReaderViewModel(
             val index = state.pages.indexOfFirst { it.key == key }
             val page =
                 state.pages.getOrNull(index) as? MangaReaderItemUi.Page ?: return@update state
+            // 已就绪的页不被重新入队/预取触发 onStart 而降级回 Loading,避免已显示的图被
+            // 遮罩/转圈闪一下;重试走 retryPage 显式置回 Queued,不受此限制。
+            if (page.loadState == MangaPageLoadState.Ready) return@update state
             if (page.loadState == loadState) return@update state
             state.copy(
                 pages = state.pages.mapIndexed { itemIndex, item ->

+ 48 - 37
app/src/test/java/io/legado/app/ui/book/manga/MangaReaderInteractionTest.kt

@@ -82,16 +82,54 @@ class MangaReaderInteractionTest {
     }
 
     @Test
-    fun `page step returns item target inside chapter`() {
-        assertEquals(4, mangaPageStepTarget(currentIndex = 3, itemCount = 8, direction = 1))
-        assertEquals(2, mangaPageStepTarget(currentIndex = 3, itemCount = 8, direction = -1))
+    fun `page step returns next real page target`() {
+        val items = listOf(page(0), page(1), page(2))
+        assertEquals(1, nextPageItemIndex(items, 0, 1))
+        assertEquals(2, nextPageItemIndex(items, 1, 1))
+        assertEquals(1, nextPageItemIndex(items, 2, -1))
+    }
+
+    @Test
+    fun `page step skips transition pages onto the next real page`() {
+        val items = listOf(
+            page(0),
+            MangaReaderItemUi.ChapterTransition(
+                key = "transition",
+                direction = MangaChapterTransitionDirection.NEXT,
+                targetChapterIndex = 1,
+                currentChapterName = "chapter",
+                targetChapterName = "chapter2",
+                targetStatus = MangaChapterTransitionStatus.READY,
+            ),
+            page(0, 1),
+        )
+        // 当前章最后一页向后一步:跳过过渡页,落在下一章第一页
+        assertEquals(2, nextPageItemIndex(items, 0, 1))
+        // 下一章第一页向前一步:跳过过渡页,回到上一章最后一页
+        assertEquals(0, nextPageItemIndex(items, 2, -1))
     }
 
     @Test
     fun `page step delegates to chapter navigation at list boundaries`() {
-        assertNull(mangaPageStepTarget(currentIndex = 0, itemCount = 8, direction = -1))
-        assertNull(mangaPageStepTarget(currentIndex = 7, itemCount = 8, direction = 1))
-        assertNull(mangaPageStepTarget(currentIndex = 0, itemCount = 0, direction = 1))
+        assertNull(nextPageItemIndex(emptyList(), 0, 1))
+        assertNull(nextPageItemIndex(listOf(page(0)), 0, -1))
+        assertNull(nextPageItemIndex(listOf(page(0)), 0, 1))
+        // 越过过渡页后仍无真实页 → 交给章节切换
+        assertNull(
+            nextPageItemIndex(
+                listOf(
+                    page(0),
+                    MangaReaderItemUi.ChapterEdge(
+                        "edge",
+                        "loading",
+                        loading = true,
+                        fullScreen = true
+                    ),
+                ),
+                0,
+                1,
+            )
+        )
     }
 
     @Test
@@ -101,61 +139,34 @@ class MangaReaderInteractionTest {
     }
 
     @Test
-    fun `chapter switch stays put while current chapter is still visible`() {
+    fun `chapter switch moves forward when focused page belongs to a later chapter`() {
         assertEquals(
-            MangaChapterSwitch.NONE,
+            MangaChapterSwitch.NEXT,
             mangaChapterSwitchDecision(
                 currentChapterIndex = 5,
                 visibleChapterIndex = 6,
-                currentChapterVisible = true,
-            ),
-        )
-        assertEquals(
-            MangaChapterSwitch.NONE,
-            mangaChapterSwitchDecision(
-                currentChapterIndex = 5,
-                visibleChapterIndex = 4,
-                currentChapterVisible = true,
             ),
         )
     }
 
     @Test
-    fun `chapter switch fires only when current chapter fully off-screen`() {
-        assertEquals(
-            MangaChapterSwitch.NEXT,
-            mangaChapterSwitchDecision(
-                currentChapterIndex = 5,
-                visibleChapterIndex = 6,
-                currentChapterVisible = false,
-            ),
-        )
+    fun `chapter switch moves backward when focused page belongs to an earlier chapter`() {
         assertEquals(
             MangaChapterSwitch.PREVIOUS,
             mangaChapterSwitchDecision(
                 currentChapterIndex = 5,
                 visibleChapterIndex = 4,
-                currentChapterVisible = false,
             ),
         )
     }
 
     @Test
-    fun `same chapter never switches regardless of visibility`() {
-        assertEquals(
-            MangaChapterSwitch.NONE,
-            mangaChapterSwitchDecision(
-                currentChapterIndex = 5,
-                visibleChapterIndex = 5,
-                currentChapterVisible = true,
-            ),
-        )
+    fun `same chapter never switches`() {
         assertEquals(
             MangaChapterSwitch.NONE,
             mangaChapterSwitchDecision(
                 currentChapterIndex = 5,
                 visibleChapterIndex = 5,
-                currentChapterVisible = false,
             ),
         )
     }