HapeLee 6 сар өмнө
parent
commit
f6b4ecbe88

+ 15 - 0
.claude/settings.local.json

@@ -0,0 +1,15 @@
+{
+  "permissions": {
+    "allow": [
+      "Bash(./gradlew compileAppDebugKotlin)",
+      "Bash(./gradlew test *)",
+      "Bash(./gradlew :app:compileAppDebugUnitTestKotlin)",
+      "Bash(head -n 508 \"app/src/main/java/io/legado/app/model/CacheBook.kt\")",
+      "Bash(mv /tmp/cachebook_tmp.kt \"app/src/main/java/io/legado/app/model/CacheBook.kt\")",
+      "Bash(./gradlew :app:cleanCompileAppDebugKotlin)",
+      "Bash(./gradlew :app:compileAppDebugKotlin --rerun-tasks)",
+      "Bash(./gradlew :app:compileAppDebugKotlin)",
+      "Bash(./gradlew :app:cleanCompileAppDebugKotlin :app:compileAppDebugKotlin)"
+    ]
+  }
+}

+ 2 - 2
app/src/main/java/io/legado/app/ui/main/MainScreen.kt

@@ -37,7 +37,6 @@ import androidx.compose.material3.WideNavigationRailValue
 import androidx.compose.material3.rememberWideNavigationRailState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -51,6 +50,7 @@ import androidx.compose.ui.platform.LocalHapticFeedback
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.kyant.backdrop.backdrops.layerBackdrop
 import com.kyant.backdrop.backdrops.rememberLayerBackdrop
 import dev.chrisbanes.haze.HazeState
@@ -102,7 +102,7 @@ fun MainScreen(
     val coroutineScope = rememberCoroutineScope()
 
     val bookshelfViewModel: BookshelfViewModel = koinViewModel()
-    val bookshelfUiState by bookshelfViewModel.uiState.collectAsState()
+    val bookshelfUiState by bookshelfViewModel.uiState.collectAsStateWithLifecycle()
 
     val hazeState = remember { HazeState() }
     val floatingBarSurfaceColor = MaterialTheme.colorScheme.surface

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

@@ -55,7 +55,6 @@ import androidx.compose.material3.pulltorefresh.pullToRefresh
 import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -73,6 +72,7 @@ import androidx.compose.ui.platform.LocalHapticFeedback
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.Dialog
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import io.legado.app.R
 import io.legado.app.base.BaseRuleEvent
 import io.legado.app.data.entities.BookGroup
@@ -127,7 +127,7 @@ fun BookshelfScreen(
     onNavigateToCache: (Long) -> Unit
 ) {
     val context = LocalContext.current
-    val uiState by viewModel.uiState.collectAsState()
+    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
     val scope = rememberCoroutineScope()
 
     var showAddUrlDialog by remember { mutableStateOf(false) }
@@ -721,7 +721,7 @@ fun BookshelfScreen(
                         HorizontalPager(
                             state = pagerState,
                             modifier = Modifier.fillMaxSize(),
-                            beyondViewportPageCount = 3,
+                            beyondViewportPageCount = 1,
                             key = { if (it < uiState.groups.size) uiState.groups[it].groupId else it }
                         ) { pageIndex ->
                             val group = uiState.groups.getOrNull(pageIndex)
@@ -729,7 +729,7 @@ fun BookshelfScreen(
                                 val booksFlow = remember(group.groupId) {
                                     viewModel.getBooksFlow(group.groupId)
                                 }
-                                val books by booksFlow.collectAsState(emptyList())
+                                val books by booksFlow.collectAsStateWithLifecycle(emptyList())
                                 BookshelfPage(
                                     paddingValues = paddingValues,
                                     books = books,

+ 54 - 0
app/src/test/java/io/legado/app/domain/usecase/SearchBooksUseCaseTest.kt

@@ -0,0 +1,54 @@
+package io.legado.app.domain.usecase
+
+import io.legado.app.data.entities.BookSource
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class SearchBooksUseCaseTest {
+
+    @Test
+    fun `search url without dynamic page does not support next page`() {
+        val source = BookSource(
+            searchUrl = "https://example.com/search?keyword={{key}}&page=1"
+        )
+
+        assertFalse(source.supportsSearchPage())
+    }
+
+    @Test
+    fun `search url with page group supports next page`() {
+        val source = BookSource(
+            searchUrl = "https://example.com/search/{{key}}/<1,2,3>"
+        )
+
+        assertTrue(source.supportsSearchPage())
+    }
+
+    @Test
+    fun `search url with page inner rule supports next page`() {
+        val source = BookSource(
+            searchUrl = "https://example.com/search?keyword={{key}}&page={{page}}"
+        )
+
+        assertTrue(source.supportsSearchPage())
+    }
+
+    @Test
+    fun `search url with page js supports next page`() {
+        val source = BookSource(
+            searchUrl = "<js>baseUrl + '/search?keyword=' + key + '&page=' + page</js>"
+        )
+
+        assertTrue(source.supportsSearchPage())
+    }
+
+    @Test
+    fun `search url with js but without page does not support next page`() {
+        val source = BookSource(
+            searchUrl = "<js>baseUrl + '/search?keyword=' + key</js>"
+        )
+
+        assertFalse(source.supportsSearchPage())
+    }
+}