From ede560f3da965bd0419b67a77431fec98df2c2ba Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Sat, 16 May 2026 13:46:47 +0800 Subject: [PATCH] =?UTF-8?q?=E7=95=8C=E9=9D=A2=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 8 +- .../java/io/legado/app/ui/main/MainScreen.kt | 6 +- .../components/navigation/AppNavigationBar.kt | 163 ++++++++++++++++++ 3 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/navigation/AppNavigationBar.kt diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 0618fc5b5..f77832291 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -83,7 +83,13 @@ "Bash(findstr /v \"\\\\\\\\build\\\\\\\\\")", "Bash(dir /s /b \"D:\\\\AndroidPrj\\\\legado-with-MD3\\\\.gradle\\\\*miuix*\")", "Skill(legado-compose-review)", - "Bash(cmd /c \".\\\\gradlew.bat :app:compileAppDebugKotlin\")" + "Bash(cmd /c \".\\\\gradlew.bat :app:compileAppDebugKotlin\")", + "PowerShell(gh search *)", + "WebFetch(domain:repo1.maven.org)", + "WebFetch(domain:s01.oss.sonatype.org)", + "WebFetch(domain:api.github.com)", + "Bash(javap -public /tmp/classes.jar!top/yukonga/miuix/kmp/basic/NavigationBarKt.class)", + "Bash(javap -public -cp /tmp/classes.jar top.yukonga.miuix.kmp.basic.NavigationBarKt)" ] } } diff --git a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt index 555da20fc..cc5d6ab53 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt @@ -74,8 +74,6 @@ import io.legado.app.ui.main.explore.ExploreScreen import io.legado.app.ui.main.my.MyScreen import io.legado.app.ui.main.my.PrefClickEvent import io.legado.app.ui.main.rss.RssScreen -import io.legado.app.ui.widget.components.AppNavigationBar -import io.legado.app.ui.widget.components.AppNavigationBarItem import io.legado.app.ui.widget.components.AppScaffold import io.legado.app.ui.widget.components.FloatingBottomBar import io.legado.app.ui.widget.components.FloatingBottomBarItem @@ -84,6 +82,8 @@ import io.legado.app.ui.widget.components.icon.AppIcon import io.legado.app.ui.widget.components.icon.AppIcons 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.navigation.AppNavigationBar +import io.legado.app.ui.widget.components.navigation.AppNavigationBarItem import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.utils.sendToClip @@ -324,7 +324,7 @@ fun MainScreen( blurAlpha = GlassDefaults.ThickBlurAlpha ), m3ShowLabel = showLabel && !customIconPath.isNotEmpty(), - m3AlwaysShowLabel = alwaysShowLabel && !customIconPath.isNotEmpty(), + m3AlwaysShowLabel = alwaysShowLabel, useCustomIcon = customIconPath.isNotEmpty() ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/components/navigation/AppNavigationBar.kt b/app/src/main/java/io/legado/app/ui/widget/components/navigation/AppNavigationBar.kt new file mode 100644 index 000000000..ec09cb31f --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/components/navigation/AppNavigationBar.kt @@ -0,0 +1,163 @@ +package io.legado.app.ui.widget.components.navigation + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.BottomAppBarDefaults +import androidx.compose.material3.ShortNavigationBar +import androidx.compose.material3.ShortNavigationBarItem +import androidx.compose.material3.ShortNavigationBarItemDefaults +import androidx.compose.material3.ripple +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.HorizontalAlignmentLine +import androidx.compose.ui.layout.Measured +import androidx.compose.ui.unit.dp +import io.legado.app.ui.config.themeConfig.ThemeConfig +import io.legado.app.ui.theme.LegadoTheme +import io.legado.app.ui.theme.LocalHazeState +import io.legado.app.ui.theme.ThemeResolver +import io.legado.app.ui.theme.regularHazeEffect +import io.legado.app.ui.widget.components.GlassDefaults +import io.legado.app.ui.widget.components.text.AnimatedText +import top.yukonga.miuix.kmp.basic.NavigationBarDisplayMode +import top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.basic.NavigationBar as MiuixNavigationBar +import top.yukonga.miuix.kmp.basic.NavigationBarItem as MiuixNavigationBarItem + +@Composable +fun AppNavigationBar( + modifier: Modifier = Modifier, + miuixMode: NavigationBarDisplayMode = NavigationBarDisplayMode.IconAndText, + content: @Composable RowScope.() -> Unit +) { + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + val opacity = (ThemeConfig.bottomBarOpacity.coerceIn(0, 100)) / 100f + val hazeState = LocalHazeState.current + val hazeModifier = if (hazeState != null) { + Modifier.regularHazeEffect(hazeState) + } else { + Modifier + } + + if (isMiuix) { + val baseColor = + if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) { + Color(ThemeConfig.secondaryThemeColor) + } else { + GlassDefaults.glassColor( + noBlurColor = MiuixTheme.colorScheme.surface, + blurAlpha = GlassDefaults.TransparentAlpha + ) + } + val finalColor = baseColor.copy(alpha = (baseColor.alpha * opacity).coerceIn(0f, 1f)) + + MiuixNavigationBar( + modifier = modifier.then(hazeModifier), + color = finalColor, + mode = miuixMode, + content = content + ) + } else { + val baseColor = + if (ThemeConfig.enableDeepPersonalization && ThemeConfig.secondaryThemeColor != 0) { + Color(ThemeConfig.secondaryThemeColor) + } else { + GlassDefaults.glassColor( + noBlurColor = BottomAppBarDefaults.containerColor, + blurAlpha = GlassDefaults.TransparentAlpha + ) + } + val finalColor = baseColor.copy(alpha = (baseColor.alpha * opacity).coerceIn(0f, 1f)) + + ShortNavigationBar( + modifier = modifier.then(hazeModifier), + containerColor = finalColor, + content = { + ShortNavigationBarRowScope.content() + } + ) + } +} + +private object ShortNavigationBarRowScope : RowScope { + override fun Modifier.weight(weight: Float, fill: Boolean): Modifier = this + override fun Modifier.align(alignment: Alignment.Vertical): Modifier = this + override fun Modifier.alignBy(alignmentLine: HorizontalAlignmentLine): Modifier = this + override fun Modifier.alignByBaseline(): Modifier = this + override fun Modifier.alignBy(alignmentLineBlock: (Measured) -> Int): Modifier = this +} + +@Composable +fun RowScope.AppNavigationBarItem( + selected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, + labelString: String, + iconVector: ImageVector, + m3Icon: @Composable () -> Unit, + m3IndicatorColor: Color, + m3ShowLabel: Boolean, + m3AlwaysShowLabel: Boolean = true, + useCustomIcon: Boolean = false, +) { + val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine) + val useCustomIconBox = useCustomIcon && ThemeConfig.useFloatingBottomBar + + if (useCustomIconBox) { + Box( + modifier = modifier + .weight(1f) + .fillMaxHeight() + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = ripple(bounded = false, radius = 32.dp), + onClick = onClick + ), + contentAlignment = Alignment.Center + ) { + if (selected) { + Box( + modifier = Modifier + .width(64.dp) + .height(32.dp) + .clip(RoundedCornerShape(16.dp)) + .background(m3IndicatorColor) + ) + } + m3Icon() + } + } else if (isMiuix) { + MiuixNavigationBarItem( + selected = selected, + onClick = onClick, + icon = iconVector, + label = labelString, + modifier = modifier + ) + } else { + ShortNavigationBarItem( + selected = selected, + onClick = onClick, + modifier = modifier, + icon = m3Icon, + colors = ShortNavigationBarItemDefaults.colors(selectedIndicatorColor = m3IndicatorColor), + label = if (m3ShowLabel && (m3AlwaysShowLabel || selected)) { + { + AnimatedText(labelString) + } + } else null + ) + } +}