# 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`。 - **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`。 - `AppNavHost.kt` 承载各目的地 Composable;根 Tab 用 `popUpTo + launchSingleTop + saveState/restoreState` 切换。 - 细节页 / 播放器用 `launchSingleTop` 防止重复入栈。 - `rootTabIndex` / `isRootRoute` 判断当前是否根 Tab。 ### 4.3 UI / 玻璃系统(重点,历史坑多) - **玻璃模式**(`AppTheme.kt`):`GlassMode.Liquid`(液态)/ `GlassMode.Frosted`(毛玻璃),用户手动在设置页选择,写入 SharedPreferences `app_settings` 持久化。 - **运行时判定**(`LumaDesignSystem.kt` 中的 `LumaGlassRuntime`): - `isBackdropSafe = SDK_INT >= S`(API 31+)。 - `useNativeBackdrop = glassMode == Liquid && isBackdropSafe`:API 31+ 且液态模式才走 Kyant `rememberLayerBackdrop`;否则返回 `null`(用渐变毛玻璃降级)。 - `rememberLumaLayerBackdrop()` 用 `key(AppTheme.glassMode)` 包裹,确保模式切换时刷新 Backdrop 与 GlassSpec 缓存。 - **关键渲染原则(务必遵守,否则会 RenderThread SIGSEGV 崩溃)**: 1. `layerBackdrop`(源层)与使用 `drawBackdrop` 的玻璃控件必须是**同一棵树下的兄弟层**,来源层只包底层内容(背景 / 视频 AndroidView),玻璃消费层在源层之外。 2. **禁止**在同一个 backdrop 捕获范围内再绘制使用同一 backdrop 的玻璃控件,会形成循环渲染 → RenderThread SIGSEGV。 3. **播放器不捕获 AndroidView**;页面捕获层只服务根 Tab / 底栏。 4. 弹出层 / 菜单必须用页面内部专属 source,不能直接消费包住整个页面的外层 source。 5. 降级玻璃的边缘高光要在 `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. 构建与运行 ```powershell # 在项目根目录 .\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 节未提交改动。*