Browse Source

[优化] 修复一些稳定性和界面问题,清明了孩子们这几天华南F3要干活忙忙忙没空修bug

HapeLee 7 months ago
parent
commit
b2f497c845

+ 10 - 37
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt

@@ -46,9 +46,7 @@ import androidx.compose.material.icons.filled.Warning
 import androidx.compose.material.icons.outlined.FilterAlt
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
-import androidx.compose.material3.FilterChip
 import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.Slider
 import androidx.compose.material3.Surface
@@ -69,16 +67,15 @@ import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import dev.chrisbanes.haze.HazeState
 import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
 import io.legado.app.data.entities.SearchBook
-import io.legado.app.data.entities.rule.ExploreKind
 import io.legado.app.model.BookShelfState
 import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.theme.responsiveHazeEffect
 import io.legado.app.ui.theme.responsiveHazeSource
 import io.legado.app.ui.widget.components.AppScaffold
@@ -88,6 +85,7 @@ import io.legado.app.ui.widget.components.button.TopBarActionButton
 import io.legado.app.ui.widget.components.button.TopbarNavigationButton
 import io.legado.app.ui.widget.components.card.TextCard
 import io.legado.app.ui.widget.components.cover.Cover
+import io.legado.app.ui.widget.components.explore.ExploreKindItem
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
@@ -132,6 +130,7 @@ fun ExploreShowScreen(
     val isGridMode = layoutState == 1
     var showGridCountSheet by remember { mutableStateOf(false) }
     val gridColumnCount by viewModel.gridCount.collectAsState()
+    val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)
 
     val isRefreshing by viewModel.isRefreshing.collectAsState()
     val pullToRefreshState = rememberPullToRefreshState()
@@ -236,6 +235,7 @@ fun ExploreShowScreen(
 
     AppModalBottomSheet(
         show = showKindSheet,
+        containerColor = LegadoTheme.colorScheme.surface,
         onDismissRequest = { showKindSheet = false }
     ) {
 
@@ -243,7 +243,7 @@ fun ExploreShowScreen(
 
         SearchBarSection(
             query = kindQuery,
-            backgroundColor = MaterialTheme.colorScheme.surfaceContainerHigh,
+            backgroundColor = LegadoTheme.colorScheme.surfaceContainerHigh,
             onQueryChange = { kindQuery = it },
             placeholder = "选择或搜索分类",
         )
@@ -258,7 +258,7 @@ fun ExploreShowScreen(
 
         LazyVerticalGrid(
             columns = GridCells.Fixed(3),
-            contentPadding = PaddingValues(16.dp),
+            contentPadding = PaddingValues(vertical = 16.dp),
             horizontalArrangement = Arrangement.spacedBy(8.dp),
             verticalArrangement = Arrangement.spacedBy(8.dp),
             modifier = Modifier.weight(1f, fill = false)
@@ -271,14 +271,15 @@ fun ExploreShowScreen(
                     if (isClickable) GridItemSpan(1) else GridItemSpan(3)
                 }
             ) { _, kind ->
-                KindGridItem(
+                ExploreKindItem(
                     modifier = Modifier.animateItem(),
                     kind = kind,
-                    currentTitle = selectedTitle ?: title,
+                    isClickable = !kind.url.isNullOrBlank(),
                     onClick = {
                         showKindSheet = false
                         viewModel.switchExploreUrl(kind)
-                    }
+                    },
+                    isMiuix = isMiuix
                 )
             }
         }
@@ -486,34 +487,6 @@ fun ExploreShowScreen(
     }
 }
 
-@Composable
-fun KindGridItem(
-    kind: ExploreKind,
-    currentTitle: String?,
-    onClick: () -> Unit,
-    modifier: Modifier = Modifier
-) {
-    val isClickable = !kind.url.isNullOrBlank()
-    val isSelected = kind.title == currentTitle
-
-    FilterChip(
-        onClick = { if (isClickable) onClick() },
-        enabled = isClickable,
-        selected = isSelected,
-        label = {
-            AppText(
-                text = kind.title,
-                fontSize = 12.sp,
-                modifier = Modifier.fillMaxWidth(),
-                textAlign = TextAlign.Center,
-                maxLines = 1,
-                overflow = TextOverflow.Ellipsis
-            )
-        },
-        modifier = modifier.fillMaxWidth()
-    )
-}
-
 @Composable
 fun ExploreBookItem(
     book: SearchBook,

+ 31 - 48
app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt

@@ -60,9 +60,8 @@ import androidx.compose.material3.FloatingActionButtonMenuItem
 import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset
 import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.PrimaryScrollableTabRow
 import androidx.compose.material3.Surface
-import androidx.compose.material3.Tab
+import androidx.compose.material3.Text
 import androidx.compose.material3.ToggleFloatingActionButton
 import androidx.compose.material3.ToggleFloatingActionButtonDefaults.animateIcon
 import androidx.compose.material3.animateFloatingActionButton
@@ -95,6 +94,7 @@ import io.legado.app.help.book.isLocal
 import io.legado.app.ui.book.toc.rule.TxtTocRuleActivity
 import io.legado.app.ui.replace.ReplaceEditRoute
 import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.widget.CollapsibleHeader
 import io.legado.app.ui.widget.components.ActionItem
 import io.legado.app.ui.widget.components.AppScaffold
@@ -108,6 +108,7 @@ import io.legado.app.ui.widget.components.divider.PillHeaderDivider
 import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.tabRow.AppTabRow
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.topbar.DynamicTopAppBar
 import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
@@ -415,39 +416,21 @@ fun TocScreen(
                 },
                 bottomContent = {
                     Row(
-                        modifier = Modifier.fillMaxWidth(),
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .adaptiveHorizontalPadding(),
                         verticalAlignment = Alignment.CenterVertically
                     ) {
-                        PrimaryScrollableTabRow(
+                        AppTabRow(
+                            tabTitles = listOf("目录", "书签"),
                             selectedTabIndex = pagerState.currentPage,
-                            edgePadding = 0.dp,
-                            divider = {},
-                            modifier = Modifier.weight(1f),
-                            containerColor = Color.Transparent
-                        ) {
-                            Tab(
-                                selected = pagerState.currentPage == 0,
-                                onClick = { scope.launch { pagerState.animateScrollToPage(0) } },
-                                text = {
-                                    AppText(
-                                        text = "目录",
-                                        modifier = Modifier.padding(horizontal = 16.dp),
-                                        color = MaterialTheme.colorScheme.onSurfaceVariant
-                                    )
-                                }
-                            )
-                            Tab(
-                                selected = pagerState.currentPage == 1,
-                                onClick = { scope.launch { pagerState.animateScrollToPage(1) } },
-                                text = {
-                                    AppText(
-                                        text = "书签",
-                                        modifier = Modifier.padding(horizontal = 16.dp),
-                                        color = MaterialTheme.colorScheme.onSurfaceVariant
-                                    )
+                            onTabSelected = { index ->
+                                scope.launch {
+                                    pagerState.animateScrollToPage(index)
                                 }
-                            )
-                        }
+                            },
+                            modifier = Modifier.weight(1f)
+                        )
 
                         if (pagerState.currentPage == 0 && hasVolumes) {
                             Box(
@@ -542,7 +525,7 @@ fun TocScreen(
                             fabMenuExpanded = false
                         },
                         icon = { Icon(icon, contentDescription = null) },
-                        text = { AppText(text = label) }
+                        text = { Text(text = label) }
                     )
                 }
             }
@@ -683,25 +666,25 @@ fun ChapterItem(
 ) {
     val backgroundColor by animateColorAsState(
         targetValue = when {
-            item.isSelected -> MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.5f)
-            item.isDur -> MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.3f)
+            item.isSelected -> LegadoTheme.colorScheme.primaryContainer.copy(alpha = 0.5f)
+            item.isDur -> LegadoTheme.colorScheme.secondaryContainer.copy(alpha = 0.3f)
             else -> Color.Transparent
         }, label = "BgColor"
     )
 
     val textColor by animateColorAsState(
         targetValue = when {
-            item.isSelected -> MaterialTheme.colorScheme.onSurface
-            item.isDur -> MaterialTheme.colorScheme.primary
-            else -> MaterialTheme.colorScheme.onSurface
+            item.isSelected -> LegadoTheme.colorScheme.onSurface
+            item.isDur -> LegadoTheme.colorScheme.primary
+            else -> LegadoTheme.colorScheme.onSurface
         }, label = "BgColor"
     )
 
     val detailColor by animateColorAsState(
         targetValue = when {
-            item.isSelected -> MaterialTheme.colorScheme.onSurfaceVariant
-            item.isDur -> MaterialTheme.colorScheme.primary
-            else -> MaterialTheme.colorScheme.onSurfaceVariant
+            item.isSelected -> LegadoTheme.colorScheme.onSurfaceVariant
+            item.isDur -> LegadoTheme.colorScheme.primary
+            else -> LegadoTheme.colorScheme.onSurfaceVariant
         }, label = "BgColor"
     )
 
@@ -725,7 +708,7 @@ fun ChapterItem(
                         Icon(
                             imageVector = Icons.Default.Lock,
                             contentDescription = null,
-                            tint = MaterialTheme.colorScheme.error,
+                            tint = LegadoTheme.colorScheme.error,
                             modifier = Modifier
                                 .size(14.dp)
                                 .padding(end = 4.dp)
@@ -891,7 +874,7 @@ private fun StatusIcon(
                     imageVector = Icons.Rounded.LocationOn,
                     contentDescription = null,
                     modifier = Modifier.size(24.dp),
-                    tint = MaterialTheme.colorScheme.secondary
+                    tint = LegadoTheme.colorScheme.secondary
                 )
             }
 
@@ -899,7 +882,7 @@ private fun StatusIcon(
                 CircularProgressIndicator(
                     modifier = Modifier.size(24.dp),
                     strokeWidth = 2.dp,
-                    color = MaterialTheme.colorScheme.secondary
+                    color = LegadoTheme.colorScheme.secondary
                 )
             }
 
@@ -908,7 +891,7 @@ private fun StatusIcon(
                     shape = MaterialTheme.shapes.medium,
                     border = BorderStroke(
                         1.dp,
-                        MaterialTheme.colorScheme.outlineVariant
+                        LegadoTheme.colorScheme.outlineVariant
                     ),
                     color = Color.Transparent
                 ) {
@@ -918,7 +901,7 @@ private fun StatusIcon(
                                 .padding(horizontal = 8.dp, vertical = 4.dp),
                             text = wordCount,
                             style = LegadoTheme.typography.labelSmall.copy(fontSize = 9.sp),
-                            color = MaterialTheme.colorScheme.onSurfaceVariant
+                            color = LegadoTheme.colorScheme.onSurfaceVariant
                         )
                     }
                 }
@@ -929,7 +912,7 @@ private fun StatusIcon(
                     imageVector = Icons.Default.CheckCircle,
                     contentDescription = null,
                     modifier = Modifier.size(24.dp),
-                    tint = MaterialTheme.colorScheme.secondary
+                    tint = LegadoTheme.colorScheme.secondary
                 )
             }
 
@@ -938,7 +921,7 @@ private fun StatusIcon(
                     imageVector = Icons.Default.Refresh,
                     contentDescription = null,
                     modifier = Modifier.size(24.dp),
-                    tint = MaterialTheme.colorScheme.error
+                    tint = LegadoTheme.colorScheme.error
                 )
             }
 
@@ -947,7 +930,7 @@ private fun StatusIcon(
                     imageVector = Icons.Outlined.DownloadForOffline,
                     contentDescription = null,
                     modifier = Modifier.size(24.dp),
-                    tint = MaterialTheme.colorScheme.outline.copy(alpha = 0.5f)
+                    tint = LegadoTheme.colorScheme.outline.copy(alpha = 0.5f)
                 )
             }
         }

+ 6 - 5
app/src/main/java/io/legado/app/ui/main/bookshelf/BookItem.kt

@@ -188,11 +188,12 @@ fun BookshelfItem(
                     }
                 }
             }
-            if (BookshelfConfig.bookshelfShowDivider) HorizontalDivider(
-                modifier = Modifier.padding(horizontal = 16.dp),
-                thickness = 0.5.dp,
-                color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)
-            )
+            if (BookshelfConfig.bookshelfShowDivider)
+                HorizontalDivider(
+                    modifier = Modifier.padding(horizontal = 16.dp),
+                    thickness = 0.5.dp,
+                    color = LegadoTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)
+                )
         }
     }
 }

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

@@ -74,6 +74,7 @@ import io.legado.app.ui.book.manage.BookshelfManageActivity
 import io.legado.app.ui.book.search.SearchActivity
 import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
 import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton
 import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
 import io.legado.app.ui.widget.components.importComponents.SourceInputDialog
@@ -317,7 +318,9 @@ fun BookshelfScreen(
                     val selectedTabIndex =
                         pagerState.currentPage.coerceIn(0, uiState.groups.size - 1)
                     Row(
-                        modifier = Modifier.fillMaxWidth(),
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .adaptiveHorizontalPadding(),
                         verticalAlignment = Alignment.CenterVertically
                     ) {
                         val tabTitles = remember(uiState.groups) {
@@ -334,7 +337,7 @@ fun BookshelfScreen(
                         )
 
                         if (BookshelfConfig.shouldShowExpandButton) {
-                            Box(modifier = Modifier.padding(end = 16.dp)) {
+                            Box(modifier = Modifier) {
                                 SmallOutlinedIconToggleButton(
                                     checked = showGroupMenu,
                                     onCheckedChange = { showGroupMenu = it },

+ 1 - 85
app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt

@@ -33,18 +33,14 @@ import androidx.compose.material.icons.filled.Refresh
 import androidx.compose.material.icons.filled.Search
 import androidx.compose.material.icons.filled.VerticalAlignTop
 import androidx.compose.material3.AlertDialog
-import androidx.compose.material3.CardDefaults
 import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
 import androidx.compose.material3.ListItem
 import androidx.compose.material3.ListItemDefaults
-import androidx.compose.material3.LocalMinimumInteractiveComponentSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.derivedStateOf
@@ -59,9 +55,6 @@ import androidx.compose.ui.draw.rotate
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
 import io.legado.app.data.entities.BookSourcePart
@@ -77,6 +70,7 @@ import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.widget.components.card.GlassCard
 import io.legado.app.ui.widget.components.card.TextCard
 import io.legado.app.ui.widget.components.divider.PillHeaderDivider
+import io.legado.app.ui.widget.components.explore.ExploreKindItem
 import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
 import io.legado.app.ui.widget.components.list.ListScaffold
 import io.legado.app.ui.widget.components.menuItem.MenuItemIcon
@@ -473,81 +467,3 @@ fun ExploreStickyCard(
     )
 }
 
-@Composable
-fun ExploreKindItem(
-    kind: ExploreKind,
-    isClickable: Boolean,
-    onClick: () -> Unit,
-    modifier: Modifier = Modifier,
-    isMiuix: Boolean,
-) {
-    val color = if (isMiuix)
-        MiuixTheme.colorScheme.surfaceContainer
-    else
-        MaterialTheme.colorScheme.secondaryContainer
-
-    val contentColor = if (isMiuix)
-        MiuixTheme.colorScheme.onSurface
-    else
-        MaterialTheme.colorScheme.secondary
-
-    val unClickBackColor = if (isMiuix)
-        MiuixTheme.colorScheme.surfaceContainer
-    else
-        MaterialTheme.colorScheme.surface
-
-    val unClickColor = if (isMiuix)
-        MiuixTheme.colorScheme.disabledOnSurface
-    else
-        MaterialTheme.colorScheme.primary
-
-    CompositionLocalProvider(
-        LocalMinimumInteractiveComponentSize provides Dp.Unspecified
-    ) {
-
-        val shape = MaterialTheme.shapes.medium
-
-        if (isClickable) {
-            GlassCard(
-                onClick = onClick,
-                shape = shape,
-                containerColor = color.copy(alpha = 0.6f),
-                contentColor = contentColor,
-                modifier = modifier
-            ) {
-                KindText(kind)
-            }
-        } else {
-            GlassCard(
-                shape = shape,
-                containerColor = unClickBackColor.copy(alpha = 0.6f),
-                contentColor = unClickColor,
-                modifier = modifier,
-                border = CardDefaults.outlinedCardBorder()
-            ) {
-                KindText(kind)
-            }
-        }
-    }
-}
-
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
-@Composable
-private fun KindText(
-    kind: ExploreKind
-) {
-    AppText(
-        text = kind.title,
-        color = if (kind.url.isNullOrBlank())
-            LegadoTheme.colorScheme.primary
-        else
-            LegadoTheme.colorScheme.onSurface,
-        modifier = Modifier
-            .fillMaxWidth()
-            .padding(vertical = 8.dp),
-        style = LegadoTheme.typography.labelMediumEmphasized,
-        textAlign = TextAlign.Center,
-        overflow = TextOverflow.Ellipsis,
-        maxLines = 1
-    )
-}

+ 1 - 1
app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt

@@ -8,7 +8,7 @@ import io.legado.app.ui.theme.LegadoTheme.composeEngine
 
 @Composable
 fun Modifier.adaptiveHorizontalPadding(): Modifier {
-    val horizontal = if (ThemeResolver.isMiuixEngine(composeEngine)) 12.dp else 16.dp
+    val horizontal = if (ThemeResolver.isMiuixEngine(composeEngine)) 8.dp else 16.dp
     return this.padding(horizontal = horizontal)
 }
 

+ 1 - 3
app/src/main/java/io/legado/app/ui/widget/components/AppTextField.kt

@@ -36,12 +36,9 @@ fun AppTextField(
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     readOnly: Boolean = false,
-    // 1. 核心思想:保留 AppText 的统一样式与颜色降级参数
     textStyle: TextStyle? = null,
     textColor: Color = Color.Unspecified,
-    // 2. 将 Label 统一定义为 String 以兼容两套引擎
     label: String? = null,
-    // 3. 保留 M3 TextField 的所有其他参数
     labelPosition: TextFieldLabelPosition = TextFieldLabelPosition.Attached(),
     placeholder: @Composable (() -> Unit)? = null,
     leadingIcon: @Composable (() -> Unit)? = null,
@@ -77,6 +74,7 @@ fun AppTextField(
             enabled = enabled,
             readOnly = readOnly,
             textStyle = MiuixTheme.textStyles.main,
+            backgroundColor = MiuixTheme.colorScheme.surfaceContainerHigh,
             label = label ?: "",
             leadingIcon = leadingIcon,
             trailingIcon = trailingIcon,

+ 2 - 12
app/src/main/java/io/legado/app/ui/widget/components/SearchBarSection.kt

@@ -12,7 +12,6 @@ import androidx.compose.material3.Surface
 import androidx.compose.material3.TextFieldDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -37,6 +36,7 @@ fun SearchBarSection(
     placeholder: String = "搜索...",
     leadingIcon: @Composable (() -> Unit)? = {
         AppIcon(
+            modifier = Modifier.padding(horizontal = 12.dp),
             imageVector = AppIcons.Search,
             contentDescription = null
         )
@@ -67,23 +67,13 @@ fun SearchBarSection(
             }
     }
 
-    val showScrollToTop by remember(scrollState) {
-        derivedStateOf {
-            (scrollState?.firstVisibleItemIndex ?: 0) > 0
-        }
-    }
-
     val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)
 
     val searchTextField = @Composable {
         AppTextField(
             state = textFieldState,
             modifier = Modifier
-                .fillMaxWidth()
-                .then(
-                    if (isMiuix) Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
-                    else Modifier
-                ),
+                .fillMaxWidth(),
             placeholder = { AppText(placeholder) },
             leadingIcon = leadingIcon,
             lineLimits = TextFieldLineLimits.SingleLine,

+ 1 - 0
app/src/main/java/io/legado/app/ui/widget/components/card/TextCard.kt

@@ -45,6 +45,7 @@ fun TextCard(
     NormalCard(
         modifier = modifier,
         shape = RoundedCornerShape(cornerRadius),
+        cornerRadius = 4.dp,
         containerColor = finalBackgroundColor,
         contentColor = finalContentColor,
         onClick = onClick

+ 99 - 0
app/src/main/java/io/legado/app/ui/widget/components/explore/ExploreKindItem.kt

@@ -0,0 +1,99 @@
+package io.legado.app.ui.widget.components.explore
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.LocalMinimumInteractiveComponentSize
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import io.legado.app.data.entities.rule.ExploreKind
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.card.GlassCard
+import io.legado.app.ui.widget.components.text.AppText
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+
+@Composable
+fun ExploreKindItem(
+    kind: ExploreKind,
+    isClickable: Boolean,
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    isMiuix: Boolean
+) {
+    val color = if (isMiuix)
+        MiuixTheme.colorScheme.surfaceContainer
+    else
+        MaterialTheme.colorScheme.secondaryContainer
+
+    val contentColor = if (isMiuix)
+        MiuixTheme.colorScheme.onSurface
+    else
+        MaterialTheme.colorScheme.secondary
+
+    val unClickBackColor = if (isMiuix)
+        MiuixTheme.colorScheme.surfaceContainer
+    else
+        MaterialTheme.colorScheme.surface
+
+    val unClickColor = if (isMiuix)
+        MiuixTheme.colorScheme.disabledOnSurface
+    else
+        MaterialTheme.colorScheme.primary
+
+    CompositionLocalProvider(
+        LocalMinimumInteractiveComponentSize provides Dp.Unspecified
+    ) {
+
+        val shape = MaterialTheme.shapes.medium
+
+        if (isClickable) {
+            GlassCard(
+                onClick = onClick,
+                shape = shape,
+                containerColor = LegadoTheme.colorScheme.surfaceContainer.copy(alpha = 0.6f),
+                contentColor = LegadoTheme.colorScheme.onSurface,
+                modifier = modifier
+            ) {
+                KindText(kind)
+            }
+        } else {
+            GlassCard(
+                shape = shape,
+                containerColor = LegadoTheme.colorScheme.surfaceContainer.copy(alpha = 0.6f),
+                contentColor = LegadoTheme.colorScheme.primary,
+                modifier = modifier,
+                border = CardDefaults.outlinedCardBorder()
+            ) {
+                KindText(kind)
+            }
+        }
+    }
+}
+
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
+@Composable
+private fun KindText(
+    kind: ExploreKind
+) {
+    AppText(
+        text = kind.title,
+        color = if (kind.url.isNullOrBlank())
+            LegadoTheme.colorScheme.primary
+        else
+            LegadoTheme.colorScheme.onSurface,
+        modifier = Modifier
+            .fillMaxWidth()
+            .padding(vertical = 8.dp),
+        style = LegadoTheme.typography.labelMediumEmphasized,
+        textAlign = TextAlign.Center,
+        overflow = TextOverflow.Ellipsis,
+        maxLines = 1
+    )
+}

+ 2 - 1
app/src/main/java/io/legado/app/ui/widget/components/tabRow/AppTabRow.kt

@@ -29,7 +29,8 @@ fun AppTabRow(
             tabs = tabTitles,
             selectedTabIndex = selectedTabIndex,
             onTabSelected = onTabSelected,
-            modifier = modifier.padding(start = 12.dp),
+            modifier = modifier
+                .padding(vertical = 4.dp),
             colors = TabRowDefaults.tabRowColors(
                 backgroundColor = Color.Transparent
             )