Browse Source

[优化] 优化发现界面,增加ModalBottomSheet的背景模糊效果。注意,仅为初始版本,存在不稳定情况。

HapeLee 10 months ago
parent
commit
c4345d4945
1 changed files with 34 additions and 14 deletions
  1. 34 14
      app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt

+ 34 - 14
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt

@@ -15,6 +15,7 @@ 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
 import androidx.compose.foundation.layout.FlowRow
 import androidx.compose.foundation.layout.FlowRow
+import androidx.compose.foundation.layout.FlowRowScope
 import androidx.compose.foundation.layout.IntrinsicSize
 import androidx.compose.foundation.layout.IntrinsicSize
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Row
@@ -86,6 +87,12 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.compose.ui.unit.sp
+import dev.chrisbanes.haze.HazeProgressive
+import dev.chrisbanes.haze.HazeState
+import dev.chrisbanes.haze.hazeEffect
+import dev.chrisbanes.haze.hazeSource
+import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
+import dev.chrisbanes.haze.materials.HazeMaterials
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.data.entities.rule.ExploreKind
 import io.legado.app.data.entities.rule.ExploreKind
 import io.legado.app.model.BookShelfState
 import io.legado.app.model.BookShelfState
@@ -98,7 +105,7 @@ import kotlinx.coroutines.flow.Flow
 import org.koin.androidx.compose.koinViewModel
 import org.koin.androidx.compose.koinViewModel
 
 
 @SuppressLint("LocalContextConfigurationRead", "ConfigurationScreenWidthHeight")
 @SuppressLint("LocalContextConfigurationRead", "ConfigurationScreenWidthHeight")
-@OptIn(ExperimentalMaterial3Api::class)
+@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class)
 @Composable
 @Composable
 fun ExploreShowScreen(
 fun ExploreShowScreen(
     title: String,
     title: String,
@@ -128,7 +135,7 @@ fun ExploreShowScreen(
     val isGridMode = layoutState == 1
     val isGridMode = layoutState == 1
     var showGridCountSheet by remember { mutableStateOf(false) }
     var showGridCountSheet by remember { mutableStateOf(false) }
     val gridColumnCount by viewModel.gridCount.collectAsState()
     val gridColumnCount by viewModel.gridCount.collectAsState()
-
+    val hazeState = remember { HazeState() }
     val shouldLoadMoreList = remember {
     val shouldLoadMoreList = remember {
         derivedStateOf {
         derivedStateOf {
             val total = listState.layoutInfo.totalItemsCount
             val total = listState.layoutInfo.totalItemsCount
@@ -178,12 +185,14 @@ fun ExploreShowScreen(
 
 
         ModalBottomSheet(
         ModalBottomSheet(
             sheetState = sheetState,
             sheetState = sheetState,
+            dragHandle = null,
             onDismissRequest = { showGridCountSheet = false }
             onDismissRequest = { showGridCountSheet = false }
         ) {
         ) {
             Column(
             Column(
                 modifier = Modifier
                 modifier = Modifier
                     .fillMaxWidth()
                     .fillMaxWidth()
-                    .padding(24.dp)
+                    .hazeEffect(state = hazeState, style = HazeMaterials.regular())
+                    .padding(16.dp)
             ) {
             ) {
 
 
                 Text(
                 Text(
@@ -217,7 +226,6 @@ fun ExploreShowScreen(
 
 
     if (showKindSheet) {
     if (showKindSheet) {
         val scrollState = rememberScrollState()
         val scrollState = rememberScrollState()
-        var kindQuery by remember { mutableStateOf("") }
         val sheetState = rememberModalBottomSheetState(
         val sheetState = rememberModalBottomSheetState(
             skipPartiallyExpanded = true,
             skipPartiallyExpanded = true,
             confirmValueChange = { newValue ->
             confirmValueChange = { newValue ->
@@ -226,12 +234,14 @@ fun ExploreShowScreen(
         )
         )
         ModalBottomSheet(
         ModalBottomSheet(
             sheetState = sheetState,
             sheetState = sheetState,
+            dragHandle = null,
             onDismissRequest = { showKindSheet = false }
             onDismissRequest = { showKindSheet = false }
         ) {
         ) {
             Column(
             Column(
                 modifier = Modifier
                 modifier = Modifier
+                    .hazeEffect(state = hazeState, style = HazeMaterials.regular())
                     .fillMaxWidth()
                     .fillMaxWidth()
-                    .heightIn(max = LocalConfiguration.current.screenHeightDp.dp * 0.8f)
+                    .heightIn(max = LocalConfiguration.current.screenHeightDp.dp * 0.72f)
                     .verticalScroll(scrollState)
                     .verticalScroll(scrollState)
             ) {
             ) {
 
 
@@ -255,7 +265,9 @@ fun ExploreShowScreen(
                 FlowRow(
                 FlowRow(
                     modifier = Modifier
                     modifier = Modifier
                         .fillMaxWidth()
                         .fillMaxWidth()
-                        .padding(16.dp)
+                        .padding(16.dp),
+                    maxItemsInEachRow = 3, // 强制每行最多 3 个
+                    horizontalArrangement = Arrangement.spacedBy(0.dp) // 因为 Item 内部有 padding,这里设为 0
                 ) {
                 ) {
                     filteredKinds.forEach { kind ->
                     filteredKinds.forEach { kind ->
                         KindListItem(
                         KindListItem(
@@ -273,9 +285,15 @@ fun ExploreShowScreen(
     }
     }
 
 
     Scaffold(
     Scaffold(
-        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
+        modifier = Modifier
+            .nestedScroll(scrollBehavior.nestedScrollConnection)
+            .hazeSource(hazeState),
         topBar = {
         topBar = {
             ExploreTopBar(
             ExploreTopBar(
+                modifier = Modifier.hazeEffect(hazeState) {
+                    progressive =
+                        HazeProgressive.verticalGradient(startIntensity = 1f, endIntensity = 0f)
+                },
                 title = selectedTitle ?: title,
                 title = selectedTitle ?: title,
                 filterState = filterState,
                 filterState = filterState,
                 onBack = onBack,
                 onBack = onBack,
@@ -293,7 +311,6 @@ fun ExploreShowScreen(
                 .fillMaxSize()
                 .fillMaxSize()
                 .padding(paddingValues)
                 .padding(paddingValues)
         ) {
         ) {
-
             Crossfade(
             Crossfade(
                 targetState = isGridMode,
                 targetState = isGridMode,
                 animationSpec = tween(250),
                 animationSpec = tween(250),
@@ -338,7 +355,6 @@ fun ExploreShowScreen(
                             items = books,
                             items = books,
                             key = { it.bookUrl }
                             key = { it.bookUrl }
                         ) { book ->
                         ) { book ->
-                            val shelfState = viewModel.getCurrentBookShelfState(book)
                             ExploreBookItem(
                             ExploreBookItem(
                                 book = book,
                                 book = book,
                                 shelfState = viewModel.getBookShelfStateFlow(book),
                                 shelfState = viewModel.getBookShelfStateFlow(book),
@@ -364,13 +380,15 @@ fun ExploreShowScreen(
 }
 }
 
 
 @Composable
 @Composable
-fun KindListItem(
+fun FlowRowScope.KindListItem(
     kind: ExploreKind,
     kind: ExploreKind,
     currentTitle: String?,
     currentTitle: String?,
-    onClick: () -> Unit
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier
 ) {
 ) {
     val isClickable = !kind.url.isNullOrBlank()
     val isClickable = !kind.url.isNullOrBlank()
     val isSelected = kind.title == currentTitle
     val isSelected = kind.title == currentTitle
+
     FilterChip(
     FilterChip(
         onClick = { if (isClickable) onClick() },
         onClick = { if (isClickable) onClick() },
         enabled = isClickable,
         enabled = isClickable,
@@ -385,18 +403,19 @@ fun KindListItem(
                 overflow = TextOverflow.Ellipsis
                 overflow = TextOverflow.Ellipsis
             )
             )
         },
         },
-        modifier = Modifier
+        modifier = modifier
+            .padding(horizontal = 4.dp)
             .then(
             .then(
                 if (!isClickable) Modifier.fillMaxWidth()
                 if (!isClickable) Modifier.fillMaxWidth()
-                else Modifier.fillMaxWidth(1f / 3f)
+                else Modifier.weight(1f)
             )
             )
-            .padding(horizontal = 4.dp)
     )
     )
 }
 }
 
 
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Composable
 @Composable
 fun ExploreTopBar(
 fun ExploreTopBar(
+    modifier: Modifier = Modifier,
     title: String,
     title: String,
     filterState: BookFilterState,
     filterState: BookFilterState,
     onBack: () -> Unit,
     onBack: () -> Unit,
@@ -410,6 +429,7 @@ fun ExploreTopBar(
     var showMenu by remember { mutableStateOf(false) }
     var showMenu by remember { mutableStateOf(false) }
 
 
     MediumFlexibleTopAppBar(
     MediumFlexibleTopAppBar(
+        modifier = modifier,
         title = { AnimatedTextLine(title, maxLines = 1, overflow = TextOverflow.Ellipsis) },
         title = { AnimatedTextLine(title, maxLines = 1, overflow = TextOverflow.Ellipsis) },
         navigationIcon = {
         navigationIcon = {
             IconButton(onClick = onBack) {
             IconButton(onClick = onBack) {