Files
lumaplayer/PROJECT_HANDOFF.md
beyond 91366f24b8 1、修复进度条无法拖动问题,
2、修复长按快进问题
3、增加亮度、音量调节
2026-08-28 21:33:58 +08:00

14 KiB
Raw Permalink Blame History

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. 构建与运行

# 在项目根目录
.\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 节未提交改动。