HapeLee vor 5 Monaten
Ursprung
Commit
02dca3edc1

+ 2 - 1
app/src/main/java/io/legado/app/ui/main/homepage/HomepageLayoutSheet.kt

@@ -9,6 +9,7 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.R
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
+import io.legado.app.ui.widget.components.settingItem.CompactDropdownSettingItem
 import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
 import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
 
 
 @Composable
 @Composable
@@ -39,7 +40,7 @@ fun <T> HomepageLayoutSheet(
         title = stringResource(R.string.homepage_layout_settings),
         title = stringResource(R.string.homepage_layout_settings),
     ) {
     ) {
         Column {
         Column {
-            DropdownListSettingItem(
+            CompactDropdownSettingItem(
                 title = stringResource(R.string.homepage_layout_mode),
                 title = stringResource(R.string.homepage_layout_mode),
                 selectedValue = layoutMode.toString(),
                 selectedValue = layoutMode.toString(),
                 displayEntries = arrayOf(
                 displayEntries = arrayOf(

+ 16 - 7
app/src/main/java/io/legado/app/ui/main/homepage/HomepageScreen.kt

@@ -72,7 +72,9 @@ import io.legado.app.ui.main.homepage.modules.GridRankingModule
 import io.legado.app.ui.main.homepage.modules.HomepageModuleSkeleton
 import io.legado.app.ui.main.homepage.modules.HomepageModuleSkeleton
 import io.legado.app.ui.main.homepage.modules.RankingModule
 import io.legado.app.ui.main.homepage.modules.RankingModule
 import io.legado.app.ui.main.homepage.modules.WaterfallItem
 import io.legado.app.ui.main.homepage.modules.WaterfallItem
+import io.legado.app.ui.config.themeConfig.ThemeConfig
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.adaptiveContentPaddingBookshelf
 import io.legado.app.ui.widget.components.AppPullToRefresh
 import io.legado.app.ui.widget.components.AppPullToRefresh
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.LoadMoreFooter
 import io.legado.app.ui.widget.components.LoadMoreFooter
@@ -84,6 +86,7 @@ import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.icon.AppIcon
 import io.legado.app.ui.widget.components.icon.AppIcon
 import io.legado.app.ui.widget.components.tabRow.AppTabRow
 import io.legado.app.ui.widget.components.tabRow.AppTabRow
 import io.legado.app.ui.widget.components.EmptyMessage
 import io.legado.app.ui.widget.components.EmptyMessage
+import io.legado.app.ui.widget.components.icon.AppIcons
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
 import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
 import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
 import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
@@ -171,12 +174,12 @@ fun HomepageScreen(
                 actions = {
                 actions = {
                     TopBarActionButton(
                     TopBarActionButton(
                         onClick = { viewModel.toggleConfigMode() },
                         onClick = { viewModel.toggleConfigMode() },
-                        imageVector = Icons.Default.GridView,
+                        imageVector = AppIcons.MoreCircle,
                         contentDescription = "Layout Settings",
                         contentDescription = "Layout Settings",
                     )
                     )
                     TopBarActionButton(
                     TopBarActionButton(
                         onClick = { viewModel.toggleManageMode() },
                         onClick = { viewModel.toggleManageMode() },
-                        imageVector = Icons.Default.Settings,
+                        imageVector = AppIcons.Settings,
                         contentDescription = "Manage Modules",
                         contentDescription = "Manage Modules",
                     )
                     )
                 },
                 },
@@ -200,14 +203,14 @@ fun HomepageScreen(
         AppPullToRefresh(
         AppPullToRefresh(
             isRefreshing = uiState.isRefreshing,
             isRefreshing = uiState.isRefreshing,
             onRefresh = { viewModel.onRefresh() },
             onRefresh = { viewModel.onRefresh() },
-            modifier = Modifier
-                .fillMaxSize()
-                .padding(paddingValues),
+            modifier = Modifier.fillMaxSize(),
         ) {
         ) {
             if (selectedSets.isEmpty()) {
             if (selectedSets.isEmpty()) {
                 EmptyMessage(
                 EmptyMessage(
                     messageResId = R.string.homepage_no_source_sets_selected,
                     messageResId = R.string.homepage_no_source_sets_selected,
-                    modifier = Modifier.fillMaxSize(),
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .padding(paddingValues),
                 )
                 )
             } else {
             } else {
                 HorizontalPager(
                 HorizontalPager(
@@ -231,6 +234,7 @@ fun HomepageScreen(
                         modules = sourceModules,
                         modules = sourceModules,
                         viewModel = viewModel,
                         viewModel = viewModel,
                         modifier = Modifier.fillMaxSize(),
                         modifier = Modifier.fillMaxSize(),
+                        paddingValues = paddingValues,
                         onErrorClick = { errorMsg = it },
                         onErrorClick = { errorMsg = it },
                         sharedTransitionScope = sharedTransitionScope,
                         sharedTransitionScope = sharedTransitionScope,
                         animatedVisibilityScope = animatedVisibilityScope,
                         animatedVisibilityScope = animatedVisibilityScope,
@@ -344,6 +348,7 @@ private fun ModuleList(
     modules: List<HomepageModuleUi>,
     modules: List<HomepageModuleUi>,
     viewModel: HomepageViewModel,
     viewModel: HomepageViewModel,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
+    paddingValues: PaddingValues = PaddingValues(0.dp),
     gridState: LazyStaggeredGridState = rememberLazyStaggeredGridState(),
     gridState: LazyStaggeredGridState = rememberLazyStaggeredGridState(),
     sharedTransitionScope: SharedTransitionScope? = null,
     sharedTransitionScope: SharedTransitionScope? = null,
     animatedVisibilityScope: AnimatedVisibilityScope? = null,
     animatedVisibilityScope: AnimatedVisibilityScope? = null,
@@ -381,7 +386,11 @@ private fun ModuleList(
             modifier = modifier,
             modifier = modifier,
             verticalItemSpacing = 16.dp,
             verticalItemSpacing = 16.dp,
             horizontalArrangement = Arrangement.spacedBy(12.dp),
             horizontalArrangement = Arrangement.spacedBy(12.dp),
-            contentPadding = PaddingValues(start = 16.dp, end = 16.dp, bottom = 80.dp),
+            contentPadding = adaptiveContentPaddingBookshelf(
+                top = paddingValues.calculateTopPadding(),
+                bottom = if (ThemeConfig.useFloatingBottomBar || ThemeConfig.enableBlur) 120.dp else 8.dp,
+                horizontal = 4.dp
+            ),
         ) {
         ) {
             processedModules.forEach { moduleUi ->
             processedModules.forEach { moduleUi ->
                 // 1. 头部 (全宽)
                 // 1. 头部 (全宽)

+ 40 - 23
app/src/main/java/io/legado/app/ui/main/homepage/HomepageViewModel.kt

@@ -104,9 +104,6 @@ class HomepageViewModel(
     private val _layoutConfigCache = MutableStateFlow<Map<String, Map<String, String>>>(emptyMap())
     private val _layoutConfigCache = MutableStateFlow<Map<String, Map<String, String>>>(emptyMap())
     private val _pendingEnabled = MutableStateFlow<Map<String, Boolean>>(emptyMap())
     private val _pendingEnabled = MutableStateFlow<Map<String, Boolean>>(emptyMap())
     private val _pendingUserModules = MutableStateFlow<List<ModuleItem>>(emptyList())
     private val _pendingUserModules = MutableStateFlow<List<ModuleItem>>(emptyList())
-    private val _exploreKindsCache =
-        MutableStateFlow<Map<String, List<Pair<String, String>>>>(emptyMap())
-
     // 2. 数据库同步流
     // 2. 数据库同步流
     private val localModulesFlow = gateway.flowEnabled()
     private val localModulesFlow = gateway.flowEnabled()
     val allModulesCache =
     val allModulesCache =
@@ -228,27 +225,44 @@ class HomepageViewModel(
         rawModulesFlow,
         rawModulesFlow,
         _bookshelf
         _bookshelf
     ) { modules, bookshelf ->
     ) { modules, bookshelf ->
-        modules.map { module ->
-            val state = module.state
-            if (state is ModuleLoadState.Loaded) {
-                module.copy(
-                    state = state.copy(
+        if (bookshelf.isEmpty()) {
+            modules.map { module ->
+                val state = module.state
+                if (state is ModuleLoadState.Loaded) {
+                    module.copy(state = state.copy(
                         books = state.books.map { item ->
                         books = state.books.map { item ->
-                            item.copy(
-                                shelfState = resolveBookShelfStateUseCase.execute(
-                                    name = item.book.name,
-                                    author = item.book.author,
-                                    url = item.book.bookUrl,
-                                    shelf = bookshelf
-                                )
-                            )
+                            if (item.shelfState == BookShelfState.NOT_IN_SHELF) item
+                            else item.copy(shelfState = BookShelfState.NOT_IN_SHELF)
                         }.toImmutableList()
                         }.toImmutableList()
-                    )
-                )
-            } else {
-                module
+                    ))
+                } else module
+            }.toImmutableList()
+        } else {
+            val exactKeys = HashSet<Triple<String, String, String?>>(bookshelf.size)
+            val nameAuthorKeys = HashSet<Pair<String, String>>(bookshelf.size)
+            for (key in bookshelf) {
+                exactKeys.add(Triple(key.name, key.author, key.url))
+                nameAuthorKeys.add(key.name to key.author)
             }
             }
-        }.toImmutableList()
+            modules.map { module ->
+                val state = module.state
+                if (state is ModuleLoadState.Loaded) {
+                    module.copy(state = state.copy(
+                        books = state.books.map { item ->
+                            val bookTriple = Triple(item.book.name, item.book.author, item.book.bookUrl)
+                            val newShelfState = when {
+                                bookTriple in exactKeys -> BookShelfState.IN_SHELF
+                                (item.book.name to item.book.author) in nameAuthorKeys ->
+                                    BookShelfState.SAME_NAME_AUTHOR
+                                else -> BookShelfState.NOT_IN_SHELF
+                            }
+                            if (item.shelfState == newShelfState) item
+                            else item.copy(shelfState = newShelfState)
+                        }.toImmutableList()
+                    ))
+                } else module
+            }.toImmutableList()
+        }
     }
     }
 
 
     // 5. 最终 UI 状态
     // 5. 最终 UI 状态
@@ -308,6 +322,10 @@ class HomepageViewModel(
             allModulesCache.collect { modules ->
             allModulesCache.collect { modules ->
                 val dbIds = modules.map { it.id }.toSet()
                 val dbIds = modules.map { it.id }.toSet()
                 _pendingUserModules.update { pending -> pending.filter { it.id !in dbIds } }
                 _pendingUserModules.update { pending -> pending.filter { it.id !in dbIds } }
+                _moduleContentStates.update { states ->
+                    if (states.keys.any { it !in dbIds }) states.filterKeys { it in dbIds }
+                    else states
+                }
             }
             }
         }
         }
 
 
@@ -614,8 +632,7 @@ class HomepageViewModel(
         }
         }
     }
     }
 
 
-    fun getSourceExploreKinds(sourceUrl: String): List<Pair<String, String>> =
-        _exploreKindsCache.value[sourceUrl].orEmpty()
+    fun getSourceExploreKinds(sourceUrl: String): List<Pair<String, String>> = emptyList()
 
 
     fun updateModule(globalId: String, def: ModuleDef) {
     fun updateModule(globalId: String, def: ModuleDef) {
         viewModelScope.launch {
         viewModelScope.launch {

+ 7 - 0
app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt

@@ -13,6 +13,7 @@ import androidx.compose.material.icons.filled.FilterList
 import androidx.compose.material.icons.filled.History
 import androidx.compose.material.icons.filled.History
 import androidx.compose.material.icons.filled.Home
 import androidx.compose.material.icons.filled.Home
 import androidx.compose.material.icons.filled.LocationSearching
 import androidx.compose.material.icons.filled.LocationSearching
+import androidx.compose.material.icons.filled.MoreHoriz
 import androidx.compose.material.icons.filled.MoreVert
 import androidx.compose.material.icons.filled.MoreVert
 import androidx.compose.material.icons.filled.MyLocation
 import androidx.compose.material.icons.filled.MyLocation
 import androidx.compose.material.icons.filled.Person
 import androidx.compose.material.icons.filled.Person
@@ -40,6 +41,7 @@ import top.yukonga.miuix.kmp.icon.extended.Edit
 import top.yukonga.miuix.kmp.icon.extended.Favorites
 import top.yukonga.miuix.kmp.icon.extended.Favorites
 import top.yukonga.miuix.kmp.icon.extended.Filter
 import top.yukonga.miuix.kmp.icon.extended.Filter
 import top.yukonga.miuix.kmp.icon.extended.More
 import top.yukonga.miuix.kmp.icon.extended.More
+import top.yukonga.miuix.kmp.icon.extended.MoreCircle
 import top.yukonga.miuix.kmp.icon.extended.Notes
 import top.yukonga.miuix.kmp.icon.extended.Notes
 import top.yukonga.miuix.kmp.icon.extended.Pin
 import top.yukonga.miuix.kmp.icon.extended.Pin
 import top.yukonga.miuix.kmp.icon.extended.Refresh
 import top.yukonga.miuix.kmp.icon.extended.Refresh
@@ -105,6 +107,11 @@ object AppIcons {
         @Composable
         @Composable
         get() = if (isMiuix) MiuixIcons.Refresh else Icons.Default.Replay
         get() = if (isMiuix) MiuixIcons.Refresh else Icons.Default.Replay
 
 
+    val MoreCircle: ImageVector
+        @Composable
+        get() = if (isMiuix) MiuixIcons.MoreCircle else Icons.Default.MoreHoriz
+
+
     @Composable
     @Composable
     fun mainDestination(destination: MainDestination, selected: Boolean): ImageVector {
     fun mainDestination(destination: MainDestination, selected: Boolean): ImageVector {
         return when (destination) {
         return when (destination) {