Files
FruitServer/docs/plans/2026-10-21-K94-home-type-feed.md

4.6 KiB
Raw Permalink Blame History

K94 首页内容类型 Feed 与无感切换

目标

  • 首页顶栏「漫剧 / 真人剧 / 推荐」接入既有 /app/feed。
  • 每频道独立缓存与分页,切换时先同步展示缓存,再后台静默刷新。
  • 推荐首屏复用 /app/home/feed 打平数据,首次进入不额外转圈。
  • 无缓存频道只在黑色内容区显示小转圈,顶栏和底栏保持。
  • 滑动接近末尾自动加载下一页,并在播放器队列中原地追加。

分支

  • ReelShort:feat/k94-home-type-feed,从 origin/develop 创建。
  • FruitServer 仅文档留痕,不改功能代码。

A. 数据层

A1 FeedPage

新增 lib/core/data/models/feed_page.dart:

  • dramas 使用 Drama.fromCardJson。
  • nextCursor 兼容数字/字符串,空值或字符串 "null" 转为 null。
  • hasMore 读取布尔值。

A2 CatalogApi / Repository

  • CatalogApi.feed({types, cursor, size}) 请求 /app/feed。
  • types 为空不传;非空用逗号拼接。
  • cursor 为空不传。
  • 返回结构异常抛 ApiException(-1, '返回数据格式异常')。
  • CatalogRepository 与 HTTP 实现增加 fetchFeed。
  • 所有测试 CatalogRepository 实现同步补齐方法。

B. 频道控制器

新增:

  • lib/pages/home/home_feed_channel.dart
  • lib/core/data/services/home_feed_controller.dart

HomeFeedController 使用每个频道独立状态:

  • dramas / cursor / hasMore / loaded / loadingMore / requestSeq
  • 当前 channel,默认 recommend
  • seedRecommend:同步写入推荐首屏,不发请求
  • selectChannel:同步切频道并 notify;无缓存加载第一页,有缓存静默刷新
  • refreshCurrent:失败保留旧列表
  • loadMore:cursor 追加,按 drama.id 去重
  • 所有响应必须同时满足“仍为当前频道 + requestSeq 最新”才应用
  • dispose 后停止 notify

C. 首页接入

C1 顶栏受控

HomeFeedHeader:

  • 删除内部 tab 状态、comingSoon 和 SnackBar。
  • 新增 channel 与 onChannelSelected。
  • 三个 Key 保持不变。
  • refresh 内部 loading 状态保留。

C2 HomePage

  • _HomePageState 用 CatalogController.repository 创建 HomeFeedController。
  • Catalog 首次有数据时同步 seed recommend,随后在 post-frame 静默刷新 recommend。
  • _HomeTabs 使用稳定 Key,删除 ValueKey(catalog.dramas.first.id)。
  • 当前频道无数据时,保留 _HomeTabs 顶栏/底栏,body 用黑色背景 + 居中 home-feed-channel-loading。
  • 当前频道有数据时把频道列表传给 PlayerPage。
  • 刷新回调改 refreshCurrent;分页回调改 loadMore。

C3 PlayerPage / PlayerLogic

  • PlayerPage 增加 feedChannel 和 onLoadMore。
  • 同频道 feed 列表变化:updateFeed(..., keepDramaId: currentDramaId)。
  • channel 变化:updateFeed(..., keepDramaId: null),回到新频道第 1 个。
  • PlayerLogic 保存 factory/coordinator,支持需要换内容时替换 PlaybackSession。
  • 空列表清空 queue/visibleIndices 并停止旧播放。
  • 当前剧仍在新列表且索引不变时,只扩展队列与 episode 列表,不重新 select。
  • PageView 在 position >= visibleIndices.length - 3 时调用 onLoadMore。

D. 测试

新增 test/core/data/services/home_feed_controller_test.dart:

  • recommendation seed 不发请求
  • 三频道请求 types 分别为 [] / [ANIME] / [LIVE]
  • 缓存频道切换不清空并后台刷新
  • loadMore 追加去重、无更多后不再请求
  • 串包只接受最新频道请求
  • refresh 失败保留旧数据

新增顶栏 widget 测试:

  • 三个 Key 存在
  • 点击分别回调 anime/live/recommend
  • 当前 channel 决定选中样式

PlayerLogic 测试补充:

  • updateFeed 空列表安全
  • 追加列表保持当前剧
  • 切频道列表回到第 1 个

门禁:

  • dart analyze lib test
  • flutter test --no-pub
  • flutter build apk --debug

风险与控制

  1. PlaybackSession 的 episodes 是构造时绑定的列表;分页原地追加时会同步扩展该列表, 避免仅换 queue 而 session 仍指向旧列表。
  2. 换频道可能释放并重建播放器 session,这是内容源变化;静默刷新/分页在顺序不变时 不重新 select 当前剧,避免视频重启。
  3. 推荐 seed 只保证首帧立即有内容;后台 /app/feed 刷新失败时保留 seed。
  4. 首页仍在 /app/home/feed 首次加载期间使用既有启动页;频道切换不再触发整页 splash。

Git

  • 提交:feat(home): 首页按内容类型分频道 Feed 并支持分页
  • --no-ff 合回 ReelShort develop 并 push。
  • 作者:Zhou Weidong <502333560@qq.com>;禁止 git add -A。