From 8f5923556d30e626dfe8b379c768936c5e835187 Mon Sep 17 00:00:00 2001 From: BoatingCloud <1759888028@qq.com> Date: Fri, 28 Aug 2026 11:30:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E6=95=9B=E7=8E=BB=E7=92=83=E8=BE=B9?= =?UTF-8?q?=E7=BC=98=E5=B9=B6=E6=B8=85=E7=90=86=E5=9B=BE=E6=A0=87=E5=BA=93?= =?UTF-8?q?=E6=97=A7=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../myapplication/screens/LibraryScreen.kt | 249 ++++-------------- .../example/myapplication/ui/LiquidGlass.kt | 4 +- .../ui/design/LumaDesignSystem.kt | 20 +- memory/2026-08-28.md | 6 + memory/MEMORY.md | 1 + memory/lessons.md | 1 + memory/projects.md | 1 + 7 files changed, 65 insertions(+), 217 deletions(-) diff --git a/app/src/main/kotlin/com/example/myapplication/screens/LibraryScreen.kt b/app/src/main/kotlin/com/example/myapplication/screens/LibraryScreen.kt index 06f06f1..6f0d90e 100644 --- a/app/src/main/kotlin/com/example/myapplication/screens/LibraryScreen.kt +++ b/app/src/main/kotlin/com/example/myapplication/screens/LibraryScreen.kt @@ -166,7 +166,15 @@ private fun ServerCard(server: EmbyServer, tint: Color, onClick: () -> Unit, onC var clicked by remember { mutableStateOf(false) } val pressBg by animateColorAsState(targetValue = if (clicked) LumaColors.glassHighlight.copy(alpha = 0.24f) else Color.Transparent, animationSpec = tween(durationMillis = if (clicked) 80 else 200), label = "pb") LaunchedEffect(clicked) { if (clicked) { delay(150); clicked = false } } - GlassSurface(modifier = Modifier.clickable(interactionSource = remember { MutableInteractionSource() }, indication = null) { clicked = true; onClick() }, cornerRadius = 20.dp, padding = PaddingValues(0.dp)) { + GlassSurface( + modifier = Modifier.clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + role = Role.Button, + ) { clicked = true; onClick() }, + cornerRadius = 20.dp, + padding = PaddingValues(0.dp), + ) { Row(modifier = Modifier.fillMaxWidth().background(pressBg).padding(14.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.weight(1f)) { if (server.iconUrl.isNotBlank()) { @@ -204,7 +212,11 @@ private fun ServerCard(server: EmbyServer, tint: Color, onClick: () -> Unit, onC Modifier .size(48.dp) .onGloballyPositioned(onMorePositioned) - .clickable(indication = null, interactionSource = remember { MutableInteractionSource() }) { onMoreClick() }, + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() }, + role = Role.Button, + ) { onMoreClick() }, contentAlignment = Alignment.Center, ) { LumaIconView(LumaIcon.More, contentDescription = stringResource(Res.string.server_actions), tint = GlassTokens.subtext, modifier = Modifier.size(24.dp)) @@ -222,7 +234,15 @@ private fun ServerGridCard(server: EmbyServer, tint: Color, onClick: () -> Unit, var clicked by remember { mutableStateOf(false) } val pressBg by animateColorAsState(targetValue = if (clicked) LumaColors.glassHighlight.copy(alpha = 0.24f) else Color.Transparent, animationSpec = tween(durationMillis = if (clicked) 80 else 200), label = "pb") LaunchedEffect(clicked) { if (clicked) { delay(150); clicked = false } } - GlassSurface(modifier = Modifier.clickable(interactionSource = remember { MutableInteractionSource() }, indication = null) { clicked = true; onClick() }, cornerRadius = 20.dp, padding = PaddingValues(0.dp)) { + GlassSurface( + modifier = Modifier.clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + role = Role.Button, + ) { clicked = true; onClick() }, + cornerRadius = 20.dp, + padding = PaddingValues(0.dp), + ) { Column(modifier = Modifier.fillMaxWidth().background(pressBg).padding(14.dp), horizontalAlignment = Alignment.Start) { Row(verticalAlignment = Alignment.CenterVertically) { if (server.iconUrl.isNotBlank()) { @@ -265,7 +285,11 @@ private fun ServerGridCard(server: EmbyServer, tint: Color, onClick: () -> Unit, Modifier .size(48.dp) .onGloballyPositioned(onMorePositioned) - .clickable(indication = null, interactionSource = remember { MutableInteractionSource() }) { onMoreClick() }, + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() }, + role = Role.Button, + ) { onMoreClick() }, contentAlignment = Alignment.Center, ) { LumaIconView(LumaIcon.More, contentDescription = stringResource(Res.string.server_actions), tint = GlassTokens.subtext, modifier = Modifier.size(24.dp)) @@ -518,7 +542,11 @@ internal fun IconLibraryManagerScreenContent( Box(Modifier.width(86.dp)) { Box( Modifier.size(48.dp) - .clickable(indication = null, interactionSource = remember { MutableInteractionSource() }) { onBack() }, + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() }, + role = Role.Button, + ) { onBack() }, contentAlignment = Alignment.Center, ) { Box( @@ -538,7 +566,11 @@ internal fun IconLibraryManagerScreenContent( Modifier .heightIn(min = 48.dp) .lumaGlass(radius = 20.dp, level = com.example.myapplication.ui.design.LumaGlassLevel.Interactive) - .clickable(indication = null, interactionSource = remember { MutableInteractionSource() }) { showAddDialog = true } + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() }, + role = Role.Button, + ) { showAddDialog = true } .padding(horizontal = 10.dp, vertical = 7.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(3.dp), @@ -631,7 +663,12 @@ private fun IconLibraryManagerCard(library: IconLibrary, onClick: () -> Unit) { Box( Modifier.fillMaxWidth() .lumaGlass(radius = LumaShapes.large, level = com.example.myapplication.ui.design.LumaGlassLevel.Regular) - .clickable(interactionSource = remember { MutableInteractionSource() }, indication = null, onClick = onClick) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + role = Role.Button, + onClick = onClick, + ) .padding(14.dp), ) { Column { @@ -708,204 +745,6 @@ private fun IconLibraryManagerCard(library: IconLibrary, onClick: () -> Unit) { } } -@Composable -private fun IconLibrarySection( - libraries: List, - isGrid: Boolean, - onClick: (IconLibrary) -> Unit, - onManage: (IconLibrary) -> Unit, -) { - Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { - Row( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Text(stringResource(Res.string.icon_lib_section_title), fontSize = 15.sp, fontWeight = FontWeight.Bold, color = GlassTokens.text) - Text(stringResource(Res.string.icon_count_unit, libraries.size), fontSize = 13.sp, color = GlassTokens.subtext) - } - if (isGrid) { - // Grid layout for icon libraries — use Column+Row to avoid nested scrolling - Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { - libraries.chunked(2).forEach { row -> - Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { - row.forEach { lib -> - IconLibraryCard( - library = lib, - modifier = Modifier.weight(1f), - onClick = { onClick(lib) }, - onLongClick = { onManage(lib) }, - ) - } - // Fill remaining space if odd number - if (row.size < 2) { - Spacer(Modifier.weight(1f)) - } - } - } - } - } else { - // List layout for icon libraries — use Row to avoid nested scrolling - Row( - horizontalArrangement = Arrangement.spacedBy(12.dp), - ) { - libraries.forEach { lib -> - IconLibraryCard( - library = lib, - modifier = Modifier.width(140.dp), - onClick = { onClick(lib) }, - onLongClick = { onManage(lib) }, - ) - } - } - } - } -} - -@Composable -private fun IconLibraryCard( - library: IconLibrary, - modifier: Modifier = Modifier, - onClick: () -> Unit, - onLongClick: () -> Unit, -) { - Box( - modifier = modifier - .lumaGlass(radius = 18.dp, level = LumaGlassLevel.Regular) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null, - onClick = onClick, - ) - .padding(12.dp), - ) { - Column { - // Icon preview row - Row( - horizontalArrangement = Arrangement.spacedBy((-6).dp), - verticalAlignment = Alignment.CenterVertically, - ) { - library.icons.take(3).forEach { icon -> - Box( - Modifier.size(30.dp).clip(RoundedCornerShape(8.dp)) - .lumaGlass(radius = 8.dp, level = LumaGlassLevel.Clear, shadowElevation = 0.dp, tint = Color(0xFFFF8A65).copy(alpha = 0.18f)), - contentAlignment = Alignment.Center, - ) { - LumaAsyncImage( - model = ImageRequest.Builder(LocalContext.current).data(icon.url).crossfade(true).build(), - contentDescription = icon.name, - contentScale = ContentScale.Crop, - modifier = Modifier.size(24.dp).clip(RoundedCornerShape(6.dp)), - ) - } - } - - } - Spacer(Modifier.height(8.dp)) - Text(library.name, fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = GlassTokens.text, maxLines = 1, overflow = TextOverflow.Ellipsis) - Text(stringResource(Res.string.icon_count_suffix, library.iconCount), fontSize = 11.sp, color = GlassTokens.subtext) - Spacer(Modifier.height(6.dp)) - // Manage button - Box( - modifier = Modifier.fillMaxWidth() - .lumaGlass(radius = 10.dp, level = LumaGlassLevel.Interactive, tint = LumaColors.accentSoft, borderColor = GlassTokens.accent.copy(alpha = 0.2f)) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null, - onClick = onLongClick, - ) - .padding(vertical = 6.dp), - contentAlignment = Alignment.Center, - ) { - Text(stringResource(Res.string.icon_lib_manage), fontSize = 12.sp, fontWeight = FontWeight.Medium, color = GlassTokens.accent) - } - } - } -} - -/* ------------------------------------------------------------------ */ -/* Icon Library Detail Dialog — browse icons */ -/* ------------------------------------------------------------------ */ - -@Composable -private fun IconLibraryDetailDialog(library: IconLibrary, backdrop: Backdrop? = null, onDismiss: () -> Unit) { - GlassDialog(backdrop = backdrop, onDismissRequest = onDismiss, modifier = Modifier.width(340.dp)) { - Box(Modifier.fillMaxWidth()) { - Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { - // Header - Row(verticalAlignment = Alignment.CenterVertically) { - Box( - Modifier.size(36.dp).clip(RoundedCornerShape(10.dp)) - .background(Brush.linearGradient(listOf(Color(0xFFFF6B9D), Color(0xFFFF8A65)))), - contentAlignment = Alignment.Center, - ) { - LumaIconView(LumaIcon.Library, contentDescription = null, tint = Color.White, modifier = Modifier.size(20.dp)) - } - Spacer(Modifier.width(12.dp)) - Column(Modifier.weight(1f)) { - Text(library.name, fontWeight = FontWeight.Bold, fontSize = 18.sp, color = GlassTokens.text) - Text(stringResource(Res.string.icon_count_suffix, library.iconCount), fontSize = 12.sp, color = GlassTokens.subtext) - } - } - - if (library.iconCount > 0 && library.icons.isEmpty()) { - Box( - modifier = Modifier.fillMaxWidth() - .lumaGlass(radius = 16.dp, level = LumaGlassLevel.Clear) - .padding(vertical = 36.dp), - contentAlignment = Alignment.Center, - ) { Text(stringResource(Res.string.icon_lib_not_loaded), color = GlassTokens.subtext, fontSize = 14.sp) } - } else if (library.icons.isEmpty()) { - Box( - modifier = Modifier.fillMaxWidth() - .lumaGlass(radius = 16.dp, level = LumaGlassLevel.Clear) - .padding(vertical = 36.dp), - contentAlignment = Alignment.Center, - ) { Text(stringResource(Res.string.icon_lib_no_icons), color = GlassTokens.subtext, fontSize = 14.sp) } - } else { - Box( - Modifier.fillMaxWidth() - .lumaGlass(radius = 16.dp, level = LumaGlassLevel.Clear) - .padding(8.dp) - ) { - LazyVerticalGrid( - columns = GridCells.Fixed(5), - modifier = Modifier.heightIn(min = 120.dp, max = 400.dp), - horizontalArrangement = Arrangement.spacedBy(6.dp), - verticalArrangement = Arrangement.spacedBy(6.dp), - ) { - items(library.icons) { icon -> - Box( - modifier = Modifier.aspectRatio(1f) - .lumaGlass(radius = 10.dp, level = LumaGlassLevel.Clear, shadowElevation = 0.dp) - .padding(4.dp), - contentAlignment = Alignment.Center, - ) { - LumaAsyncImage( - model = ImageRequest.Builder(LocalContext.current).data(icon.url).crossfade(true).build(), - contentDescription = icon.name, - contentScale = ContentScale.Crop, - modifier = Modifier.fillMaxSize().clip(RoundedCornerShape(8.dp)), - ) - } - } - } - } - } - - // Close button - Box( - modifier = Modifier.fillMaxWidth() - .lumaGlass(radius = 16.dp, level = LumaGlassLevel.Interactive) - .clickable { onDismiss() } - .padding(vertical = 14.dp), - contentAlignment = Alignment.Center, - ) { Text(stringResource(Res.string.icon_lib_close), color = GlassTokens.subtext, fontSize = 15.sp, fontWeight = FontWeight.Medium) } - } - } - } -} - /* ------------------------------------------------------------------ */ /* Manage Icon Library Dialog — rename, refresh, delete */ /* ------------------------------------------------------------------ */ diff --git a/app/src/main/kotlin/com/example/myapplication/ui/LiquidGlass.kt b/app/src/main/kotlin/com/example/myapplication/ui/LiquidGlass.kt index 3bbd15f..2d2e222 100644 --- a/app/src/main/kotlin/com/example/myapplication/ui/LiquidGlass.kt +++ b/app/src/main/kotlin/com/example/myapplication/ui/LiquidGlass.kt @@ -440,7 +440,7 @@ fun LiquidGlassPopupOverlay( } else { Color.White.copy(alpha = 0.20f) } - val border = if (GlassTokens.isDark) Color.White.copy(alpha = 0.24f) else Color.White.copy(alpha = 0.62f) + val border = GlassTokens.glassBorder Box(modifier.fillMaxSize().zIndex(20f)) { Box( @@ -476,7 +476,7 @@ fun LiquidGlassPopupOverlay( depthEffect = true, ) }, - highlight = { Highlight.Plain }, + highlight = { Highlight.Plain.copy(alpha = 0.58f) }, shadow = { Shadow(alpha = 0.18f) }, onDrawSurface = { drawRect(surface) }, ) diff --git a/app/src/main/kotlin/com/example/myapplication/ui/design/LumaDesignSystem.kt b/app/src/main/kotlin/com/example/myapplication/ui/design/LumaDesignSystem.kt index c46b771..650846b 100644 --- a/app/src/main/kotlin/com/example/myapplication/ui/design/LumaDesignSystem.kt +++ b/app/src/main/kotlin/com/example/myapplication/ui/design/LumaDesignSystem.kt @@ -129,7 +129,7 @@ object LumaColors { val floatingTint: Color get() = if (isDark) Color(0xFF1B2430).copy(alpha = 0.62f) else Color.White.copy(alpha = 0.30f) val glassBorder: Color - get() = if (isDark) Color.White.copy(alpha = 0.16f) else Color(0xFFB7C3D0).copy(alpha = 0.42f) + get() = if (isDark) Color.White.copy(alpha = 0.16f) else Color(0xFFB7C3D0).copy(alpha = 0.30f) val glassHighlight: Color get() = if (isDark) Color.White.copy(alpha = 0.07f) else Color.White.copy(alpha = 0.24f) val glassShadow: Color @@ -203,10 +203,10 @@ fun Modifier.lumaFallbackGlass( val edge = if (light) { Color.White.copy( alpha = when { - liquidFallback && selected -> 0.86f - liquidFallback -> 0.70f - selected -> 0.78f - else -> 0.64f + liquidFallback && selected -> 0.62f + liquidFallback -> 0.48f + selected -> 0.64f + else -> 0.52f }, ) } else { @@ -222,10 +222,10 @@ fun Modifier.lumaFallbackGlass( val topHighlight = if (light) { Color.White.copy( alpha = when { - liquidFallback && selected -> 0.42f - liquidFallback -> 0.30f - selected -> 0.32f - else -> 0.22f + liquidFallback && selected -> 0.34f + liquidFallback -> 0.24f + selected -> 0.28f + else -> 0.18f }, ) } else { @@ -337,7 +337,7 @@ fun Modifier.lumaGlass( ) } }, - highlight = if (highlight) ({ Highlight.Plain.copy(alpha = 0.75f) }) else null, + highlight = if (highlight) ({ Highlight.Plain.copy(alpha = 0.58f) }) else null, shadow = { Shadow(alpha = spec.shadowAlpha) }, onDrawSurface = { drawRect(surfaceTint) }, ) diff --git a/memory/2026-08-28.md b/memory/2026-08-28.md index 61a51de..837187d 100644 --- a/memory/2026-08-28.md +++ b/memory/2026-08-28.md @@ -21,3 +21,9 @@ 文件变更: ui/design/LumaDesignSystem.kt、ui/design/LumaComponents.kt、ui/design/LumaIcons.kt、screens/SettingsScreen.kt、screens/SettingsChildScreens.kt、values/strings.xml、values-en/strings.xml。 教训: 全局材质状态必须进入 remember key;真实液态玻璃仍需在实体 GPU 上验证。 标签: #lumaplayer #glass-mode #design-system #accessibility + +[PROJECT:lumaplayer] 玻璃边缘与资源库遗留 UI 清理 +结论: 降低原生/降级玻璃的白边和高光强度,删除无引用的旧图标库展示实现,保留当前独立管理页;完整构建和资源库操作回归通过。 +文件变更: ui/design/LumaDesignSystem.kt、ui/LiquidGlass.kt、screens/LibraryScreen.kt。 +教训: 清理前以全仓库引用结果确认目标确实未被活动页面使用。 +标签: #lumaplayer #liquid-glass #library #cleanup diff --git a/memory/MEMORY.md b/memory/MEMORY.md index e5698ff..6a11b27 100644 --- a/memory/MEMORY.md +++ b/memory/MEMORY.md @@ -12,3 +12,4 @@ - 最新改动:播放器进度条改为自绘可访问 SeekBar,媒体首页、Vision 收藏和搜索加载态改为统一骨架占位;移除未使用的 Material 图标依赖,完整 Debug/Lint/Unit 通过。 - 最新校验:修复降级玻璃高光覆盖内容、首页滚动状态恢复与重复详情/播放器导航;Debug/Lint/Unit 和 API35 模拟器启动回归成功。 - 最新校验:修复玻璃模式切换后的 Backdrop/source 与材质缓存刷新;设置页行组件、分组标题和子页返回栏统一;Debug/Lint/Unit 与 API35 模拟器液态↔毛玻璃切换回归成功。 +- 最新收敛:降低统一玻璃边缘高光/白边,清理 `LibraryScreen` 无引用的旧图标库 UI;资源库列表/网格切换回归无崩溃。 diff --git a/memory/lessons.md b/memory/lessons.md index d88b007..3f9f97b 100644 --- a/memory/lessons.md +++ b/memory/lessons.md @@ -22,3 +22,4 @@ - 中:降级玻璃的边缘高光应在 `drawContent()` 之前绘制;否则公共玻璃容器中的文字和图标会被高光层洗白。 - 高:用户明确要求真实液态玻璃时,不能继续保留设备/模拟器安全门;当前仅保留 API 31+ 能力判断,底栏原生 Backdrop 必须先绘制容器与选中胶囊,再绘制清晰图标/文字,避免内容被二次采样覆盖。该取舍需在实体机 GPU 上继续验证 RenderThread 稳定性。 - 中:玻璃模式是全局 Compose 状态;涉及 `rememberLayerBackdrop` 或玻璃规格的缓存必须把 `AppTheme.glassMode` 纳入重建边界,否则设置副标题会变但材质不变。 +- 低:清理页面遗留实现前必须用全仓库引用检索确认;私有且无调用的旧 UI 可以删除,活动页面保留原数据/弹窗实现。 diff --git a/memory/projects.md b/memory/projects.md index b1bd393..d41efd7 100644 --- a/memory/projects.md +++ b/memory/projects.md @@ -40,3 +40,4 @@ - 2026-08-28:继续收尾降级 UI;修复 fallback 高光绘制顺序,首页接入可保存滚动状态,详情/播放器导航启用 `launchSingleTop` 防重复 Push,详情刷新和剧集加载异常进入已有错误态;`assembleDebug`、`lintDebug`、`testDebugUnitTest` 及 API35 模拟器启动回归成功。 - 2026-08-28:按需求取消液态玻璃设备/模拟器安全门,API 31+ 液态模式直接进入 Kyant Backdrop 原生路径;底栏改为玻璃底层、选中胶囊、清晰内容的正确绘制顺序,主图标 40dp、搜索图标 44dp、文字 8sp;补充媒体卡片加载/成功/失败三态和统一按压反馈。`assembleDebug`、`lintDebug`、`testDebugUnitTest` 及 API35 模拟器液态/毛玻璃切换回归成功,未发现 RenderThread 崩溃。 - 2026-08-28:修复玻璃模式切换时 `LayerBackdrop` 与 `GlassSpec` 缓存未刷新问题;新增 `LumaSettingRow`、`LumaPageTopBar`、设置分组标题并补齐公共按钮语义。完整 Debug/Lint/Unit 成功,API35 模拟器切换液态→毛玻璃→液态成功且无 RenderThread 崩溃;参考素材仍未提交。 +- 2026-08-28:收敛原生/降级玻璃边缘高光与白边,清理 `LibraryScreen` 中确认无引用的旧图标库 Section/Card/DetailDialog,并为资源库主要操作补充按钮语义;Debug/Lint/Unit 成功,模拟器资源库列表/网格切换无崩溃。