14 KiB
LumaPlayer 项目交接说明(移交下一 AI 开发者)
本文档是给下一位接手本项目的 AI 开发者/工程师的交接说明,请在动手前完整阅读。 交接时间:2026-08-28 | 工作目录:
F:\lumaplayerAPP\lumaplayer| Git 分支:master
1. 项目是什么
LumaPlayer 是一款 Android(Kotlin + Jetpack Compose)的 Emby 媒体库客户端:
- 用户可添加 / 管理多个 Emby 服务器(支持 HTTP / HTTPS、登录认证、API Key)。
- 浏览媒体库(电影 / 剧集)、查看媒体详情、在线流媒体播放(Media3 ExoPlayer,支持 HLS)。
- 支持搜索、收藏、播放记录、图标库管理、主题 / 语言 / 玻璃风格设置等。
- UI 主打「液态玻璃 / 毛玻璃」设计风格,采用 Kyant0 Backdrop + 自定义降级玻璃。
目前处于可构建、可运行状态(Debug / Lint / Unit 通过,API 35 模拟器已回归),但仍有未提交的工作区改动(见第 6 节)。
2. 技术栈与版本
| 项 | 值 |
|---|---|
| 语言 | Kotlin + 少量 Java(Room 实体 / DAO) |
| UI | Jetpack Compose(Material 3) |
| 视频播放 | AndroidX Media3 ExoPlayer 1.5.1(+ HLS) |
| 网络 | Retrofit 2.11.0 + OkHttp 4.12.0 + Gson |
| 本地存储 | Room 2.8.4(数据库名 emby_player.db,当前 version 6) |
| 导航 | Navigation Compose 2.10.0 |
| 图片 | Coil 2.7.0 + Palette |
| 玻璃 / 液态 | io.github.kyant0:backdrop:2.0.1、io.github.kyant0:shapes:1.2.1、top.yukonga.miuix.kmp:miuix-ui:0.9.4-rc01 |
| Gradle | 9.5.0(wrapper) |
| AGP | com.android.application 9.0.1 |
| Kotlin | 2.3.20(org.jetbrains.kotlin.plugin.compose) |
| compileSdk / targetSdk / minSdk | 35 / 35 / 24 |
| Java 兼容 | VERSION_21 |
仓库镜像源:
settings.gradle.kts使用阿里云镜像 + google() + mavenCentral();Gradle 发行版走腾讯云镜像(gradle-wrapper.properties)。
3. 目录结构
lumaplayer/
├── settings.gradle.kts / build.gradle.kts / gradle.properties / local.properties
├── gradle/
│ ├── libs.versions.toml # 版本目录(当前只有少量条目)
│ ├── gradle-daemon-jvm.properties
│ └── wrapper/ # Gradle 9.5.0 wrapper(腾讯镜像)
├── memory/ # 项目记忆库(重要!见第 7 节)
│ ├── MEMORY.md # 记忆索引
│ ├── projects.md # 项目状态 / 变更历史
│ ├── 2026-08-2x.md # 每日变更记录
│ ├── lessons.md # 踩坑教训(必读)
│ └── infra.md # 基础设施速查
└── app/src/main/
├── AndroidManifest.xml
├── java/com/example/myapplication/data/ # Room 实体/DAO(Java)
│ ├── AppDatabase.java # DB 版本 6,含 1→6 迁移
│ ├── ServerEntity.java / ServerDao.java
│ └── IconLibraryEntity.java / IconLibraryDao.java
├── kotlin/com/example/myapplication/
│ ├── MainActivity.kt # 启动入口,初始化主题/语言/Repository
│ ├── MainApp.kt # 根 Composable,玻璃 Backdrop 源层 + 底栏 + NavHost
│ ├── data/ # Emby API 与业务数据层
│ │ ├── EmbyApiModels.kt / EmbyApiService.kt / EmbyRepository.kt
│ │ ├── EmbyServer.kt # EmbyServer 模型(fullUrl 拼装逻辑)
│ │ ├── ServerRepository.kt / IconLibrary.kt
│ ├── navigation/
│ │ ├── AppRoute.kt # 路由定义(sealed interface)
│ │ ├── AppNavHost.kt # 导航宿主 + 各目的地 Composable
│ │ └── NavigationTransitions.kt
│ ├── screens/ # 各页面
│ │ ├── HomeScreen.kt / LibraryScreen.kt / RecordsScreen.kt
│ │ ├── SearchScreen.kt / MediaDetailScreen.kt / VideoPlayerScreen.kt
│ │ ├── SettingsScreen.kt / SettingsChildScreens.kt
│ │ └── library/IconLibraryManagerScreen.kt
│ └── ui/
│ ├── AppTheme.kt # 主题 / 玻璃模式(Liquid/Frosted)全局状态与持久化
│ ├── AppLanguage.kt / AppBottomBar.kt / ImmersiveBackground.kt
│ ├── LiquidGlass.kt # 玻璃控件组件库(对话框、表单、菜单等)
│ ├── design/ # 设计系统
│ │ ├── LumaDesignSystem.kt # 颜色/令牌/GlassSpec/LumaGlassRuntime/rememberLumaLayerBackdrop
│ │ ├── LumaComponents.kt # 公共组件(加载/空态/按钮/分段等)
│ │ └── LumaIcons.kt
│ └── liquidglass/ # 液态底栏专有实现
│ ├── LiquidBottomTabs.kt / LiquidBottomTab.kt
│ └── DampedDragAnimation.kt / DragGestureInspector.kt / InteractiveHighlight.kt
└── res/
├── drawable/ # aurora_* 图标子集(大量 XML selector)
├── values/strings.xml(中文)、values-en/strings.xml(英文) # 双语
└── mipmap-*/ 图标
注意:应用包名/命名空间仍是默认的
com.example.myapplication,尚未改名为com.luma.player之类。是否改名属可选优化,改动会涉及 namespace、applicationId、Manifest、Room 相关路径。
4. 核心架构
4.1 数据层(data/)
- Room 数据库
emby_player.db:表servers与icon_libraries。- 版本 6,定义了 1→2、2→3、3→4、4→5、5→6 的迁移(见
AppDatabase.java)。 ServerEntity(Java)字段:id、name、protocol、host、basePath、port、username、password、note、accessToken、userId、iconUrl、isSelected。- protocol(http/https)是 5→6 迁移新增的可空列,模型中读取时兜底为
https。
- 版本 6,定义了 1→2、2→3、3→4、4→5、5→6 的迁移(见
- Emby 业务层都由
EmbyRepository(object 单例) 承载,主要能力:- 认证:
AuthenticateByName(用户名密码换 token)。 - 媒体库:
Library/MediaFolders、Users/{userId}/Items、Items/{itemId}/PlaybackInfo等。 - 图片 URL 拼装:
buildImageUrl/buildBackdropUrl/buildEpisodeImageUrl/buildPersonImageUrl。 - 在线检测:
checkOnline(System/Info/Public)。 - 播放进度回报:内部用
Channel串行队列 + 工作协程,把 开始 / 进度 / 停止 事件按 Emby Playback Check-in 约定上报;进度按 10 秒或位置变化阈值上报。
- 认证:
EmbyServer.fullUrl:统一负责协议、端口、basePath 的拼接与http:///https://前缀去重。
4.2 导航(navigation/)
AppRoute(sealed interface)定义路由:- 根 Tab:
home、records、library、settings、search。 - 子页:
detail/{serverId}/{itemId}、player/{serverId}/{itemId}/{seriesId}/{seasonId}、library/icons、settings/cache、settings/about、library/add-server。
- 根 Tab:
AppNavHost.kt承载各目的地 Composable;根 Tab 用popUpTo + launchSingleTop + saveState/restoreState切换。- 细节页 / 播放器用
launchSingleTop防止重复入栈。 rootTabIndex/isRootRoute判断当前是否根 Tab。
4.3 UI / 玻璃系统(重点,历史坑多)
- 玻璃模式(
AppTheme.kt):GlassMode.Liquid(液态)/GlassMode.Frosted(毛玻璃),用户手动在设置页选择,写入 SharedPreferencesapp_settings持久化。 - 运行时判定(
LumaDesignSystem.kt中的LumaGlassRuntime):isBackdropSafe = SDK_INT >= S(API 31+)。useNativeBackdrop = glassMode == Liquid && isBackdropSafe:API 31+ 且液态模式才走 KyantrememberLayerBackdrop;否则返回null(用渐变毛玻璃降级)。rememberLumaLayerBackdrop()用key(AppTheme.glassMode)包裹,确保模式切换时刷新 Backdrop 与 GlassSpec 缓存。
- 关键渲染原则(务必遵守,否则会 RenderThread SIGSEGV 崩溃):
layerBackdrop(源层)与使用drawBackdrop的玻璃控件必须是同一棵树下的兄弟层,来源层只包底层内容(背景 / 视频 AndroidView),玻璃消费层在源层之外。- 禁止在同一个 backdrop 捕获范围内再绘制使用同一 backdrop 的玻璃控件,会形成循环渲染 → RenderThread SIGSEGV。
- 播放器不捕获 AndroidView;页面捕获层只服务根 Tab / 底栏。
- 弹出层 / 菜单必须用页面内部专属 source,不能直接消费包住整个页面的外层 source。
- 降级玻璃的边缘高光要在
drawContent()之前绘制,否则文字/图标会被高光洗白。
- 降级毛玻璃:当
useNativeBackdrop == false时,用 Compose 渐变 + tint/边框/圆角模拟玻璃(见LumaGlassLevel/GlassSpec)。 - 设计系统:
LumaColors、LumaShapes、LumaTypography、LumaMotion、LumaIcons等令牌;公共组件在LumaComponents.kt(加载 / 空态 / 按钮 / 分段控件 / 输入框等)。
4.4 播放器(screens/VideoPlayerScreen.kt)
- 基于 Media3 ExoPlayer +
PlayerView(AndroidView)。 - 支持:起播位置恢复、暂停/继续、进度拖拽、剧集/字幕菜单、全屏、播放进度回报(串行队列)。
- 当前工作区正在大改播放器 UI(见第 6 节)。
5. 构建与运行
# 在项目根目录
.\gradlew.bat assembleDebug # Debug 构建
.\gradlew.bat lintDebug # 静态检查
.\gradlew.bat testDebugUnitTest # 单元测试
- Gradle 9.5.0 wrapper(腾讯镜像),AGP 9.0.1,Kotlin 2.3.20。
- SDK 路径在
local.properties(本机:C:\Users\Administrator\AppData\Local\Android\Sdk),该文件被 gitignore,不入库。 app/build.gradle.kts中有任务钩子:跳过AarMetadata相关check任务(tasks.whenTaskAdded);gradle.properties设android.aarMetadataCheck.enable=false、android.suppressUnsupportedCompileSdk=37.0。- 历史提交常在
assembleDebug、lintDebug、testDebugUnitTest三者通过后收尾。真机 GPU 稳定性尚未充分验证(主要是 RenderThread)。
注意:
memory/infra.md里写的 JDK 路径是 macOS 路径(/Applications/Android Studio.app/...),那是历史环境信息,与当前 Windows 工作环境不一致,仅作参考。
6. 当前工作区状态(⚠️ 交接重点)
Git 分支 master,与 origin/master 同步。存在 3 个文件未提交:
| 文件 | 改动 |
|---|---|
app/build.gradle.kts |
重新加入 androidx.compose.material:material-icons-extended 依赖 |
navigation/AppNavHost.kt |
onPlaybackProgress 回调签名简化:由外部传 eventName 改为内部根据 paused 自动映射为 "Pause" / "TimeUpdate" |
screens/VideoPlayerScreen.kt |
大范围重构(+518/-502):播放器新增信号/电量/存储状态、连接状态监测、玻璃菜单、Material 图标等;改动与远端设计系统可能存在交互,提交前务必重新编译 + 回归 |
最近 6 条提交:
07dc93c 收口玻璃交互与界面细节 8f59235 收敛玻璃边缘并清理图标库旧界面 594f47b 修复玻璃模式切换并统一设置组件 dafac3e 取消液态玻璃安全门并收敛底栏绘制 485538f 收敛降级玻璃与页面状态恢复 e76637c 完善降级玻璃界面并增加手动玻璃模式
接手建议:先 git diff 复核上述未提交改动是否完整、可编译,确认无误后再提交/推送;若与远端有冲突,按 memory/lessons.md 的三方合并经验处理(先暂存本地改动再合并,避免整文件覆盖)。
7. 项目记忆库(必读)
memory/ 目录记录了完整开发历史与踩坑经验,接手前建议通读:
MEMORY.md— 项目记忆索引、当前实现概览、稳定性策略。projects.md— 逐日项目状态与变更历史。2026-08-26.md/2026-08-27.md/2026-08-28.md— 每日详细变更与教训。lessons.md— 踩坑教训集(重点),尤其是 RenderThread SIGSEGV 的玻璃渲染约束、Room 迁移可空性、Emby 播放回报、导航状态等。infra.md— Git 远端地址等。
8. 已知要点 / 注意事项(给下一位开发)
Git
- 远端:
https://git.leee.xin/beyond/lumaplayer.git(origin,分支 master)。认证信息不要写入远端配置。 - 本地
memory/保留本地参考素材(未跟踪,不随源码提交),删除前务必确认无引用。 - 清理遗留实现前,一律用全仓库引用检索确认目标未被活动页面使用。
玻璃渲染(崩溃风险最高)
- 任何修改涉及
layerBackdrop/drawBackdrop/ 弹窗 / 菜单 / 播放器,都要遵守第 4.3 节原则,否则可能 RenderThread SIGSEGV。 - 玻璃模式是全局 Compose 状态,涉及 Backdrop / GlassSpec 缓存时必须把
AppTheme.glassMode纳入remember的 key。 - 模拟器不一定用标准指纹,
isBackdropSafe已简化为只看 API 级别;真机 GPU 的液态玻璃稳定性仍需单独验证。
Room
- 改
ServerEntity/ 新增列时,迁移列定义必须与 Room 的notNull预期一致(参考protocol可空列的教训),否则旧库启动会崩。
播放回报
- 必须沿用 PlaybackInfo 返回的
PlaySessionId/MediaSourceId,开始/进度/停止事件串行化;回报协程不要绑到播放器 Composable 生命周期(返回页面会丢停止事件)。
无障碍 / 触控
BasicTextField的decorationBox无论是否为空都必须调用inner(),否则破坏焦点/光标。- 交互目标尽量 ≥ 48dp 触控范围。
9. 可能的后续方向(非必须,供参考)
若产品方向需要,可考虑:
- 包名/命名空间从
com.example.myapplication规范命名。 - 真机 GPU 上逐一验证液态玻璃(RenderThread 稳定性)。
- 补充更完整的单元测试覆盖(目前测试较少)。
- 是否支持 Jellyfin(API 兼容)等,属于需求决策,需与产品确认,勿自行扩展。
本文档基于 memory/、源码与 Git 状态整理生成,供下一位 AI 开发者快速上手。动手前请先确认第 6 节未提交改动。