feat(ncm §22): 播放页重做——封面页/歌词页双页(NCM_CACHE_DESIGN §6 定案)

- 去标题栏(不再用 ncm_topbar);返回=左缘手势/系统返回钮语义
- 双页结构:封面页/歌词页,屏幕正中左/右滑切换(与左缘≤24px返回、顶部通知分流),
  页面指示点显示当前页;中部横滑=on_touch_move 锁存 page-drag + on_tap/on_swipe 判向
- 封面页:方形大图+圆角(无旋转动画)+进度条(点 seek)+MD3 矢量控制钮(prev/play/pause/next,
  新增 app/ui/ncm_icons.h 32x32 单通道 alpha,参照 sb_icons.h 范式)+元信息+实际音质档
- 歌词页:LRC 滚动(当前行居中高亮、上下渐隐)+点行跳转(新增 lyric_line_time);
  默认=封面模糊置底(封面铺底+主题 scrim),省电=封面背景+黑色半透明叠加层(设置 ncm.player_bg_mode)
- 日夜间:主题配色只映射到半透明叠加层/scrim/accent(红),不动沉浸底(NCM_PLAYER_BG 恒定)
- 分带刷新沿用:封面页=封面静态带+动态带(互不重叠 bbox,tick 只刷动态带);歌词页换行(~5s)才重画
- 性能:宿主 4 页 PPM 核验+手势自检 PASS;mipsel -Wall -Wextra 0 warning;qemu core 回归 PASS;
  0 真实请求(封面/歌词用本地样本注入)。未部署真机(主会话统一)

md5: ncm 730e0b6e / ncm_host 500ac85 / player.c 00934de / ncm_icons.h 20f0bba
This commit is contained in:
MeowOS committed 2026-09-01 18:52:14 +08:00
1 parent ed2ae10320
commit 7bd6962ccb
13 files changed
+795 -343

No files matched your search

+37 -3
View File
@@ -89,7 +89,10 @@ static int page_id(const char *name)
if (strcmp(name, "home") == 0) return ACT_HOME;
if (strcmp(name, "playlist") == 0) return ACT_PLAYLIST;
if (strcmp(name, "player") == 0) return ACT_PLAYER;
if (strcmp(name, "lands") == 0) return ACT_PLAYER; /* 横屏布局 */
if (strcmp(name, "plcover") == 0) return ACT_PLAYER; /* §22 封面页(双页重做) */
if (strcmp(name, "pllyric") == 0) return ACT_PLAYER; /* §22 歌词页(双页重做) */
if (strcmp(name, "gestest") == 0) return ACT_PLAYER; /* §22 手势切换自检 */
if (strcmp(name, "grid") == 0) return ACT_PLAYER; /* 保留:旧横屏(重做后恒竖屏) */
if (strcmp(name, "playerbuf") == 0) return ACT_PLAYER; /* §18 缓冲态 */
if (strcmp(name, "playererr") == 0) return ACT_PLAYER; /* §18 错误态 */
if (strcmp(name, "settings") == 0) return ACT_SETTINGS;
@@ -138,7 +141,9 @@ int main(int argc, char **argv)
printf("live unikey=%s qr_url=%s size=%d\n", unikey, g_st.qr_url, sz);
}
else if (strcmp(name, "playlist") == 0) { mock_playlists(); mock_songs(); }
else if (strcmp(name, "player") == 0 || strcmp(name, "lands") == 0) {
else if (strcmp(name, "player") == 0 || strcmp(name, "plcover") == 0 ||
strcmp(name, "pllyric") == 0 || strcmp(name, "gestest") == 0 ||
strcmp(name, "grid") == 0) {
mock_playlists(); mock_songs(); mock_lyric();
pthread_mutex_lock(&g_play.mu);
g_play.state = NCM_PC_PLAYING;
@@ -207,10 +212,39 @@ int main(int argc, char **argv)
else if (strcmp(name, "search") == 0) v = search_view_create();
if (!v) { fprintf(stderr, "bad page\n"); return 1; }
if (strcmp(name, "lands") == 0) player_set_screen(1);
if (strcmp(name, "grid") == 0) player_set_screen(1); /* 兼容占位(重做后恒竖屏) */
int pid = (strcmp(name, "loginlive") == 0) ? ACT_LOGIN : page_id(name);
meow_view_page_push(pid);
/* §22:歌词页模式注入 + 本地封面注入(0 真实请求) */
if (strcmp(name, "pllyric") == 0) player_set_page(1);
const char *bg = getenv("NCM_BGMODE");
if (bg && strcmp(bg, "power_save") == 0) g_st.player_bg_mode = NCM_BG_POWER_SAVE;
const char *cover = getenv("NCM_COVER");
if (cover && cover[0]) cover_host_inject(cover);
/* §22 手势切换自检(宿主直调,不依赖 SDK 触摸管线):封面页中部左滑→歌词页、右滑→封面页。
* 起点取封面区(避开进度条/控制钮),验证 page-drag 锁存与判向。 */
if (strcmp(name, "gestest") == 0) {
int p0 = player_page();
player_touch_down(240, 200); /* 中部,封面区 */
player_touch_move(140, 200); /* 左移 100px → 锁存 */
player_on_tap(140, 200); /* 抬手落 tap → 判为页切换 */
int p1 = player_page();
player_touch_down(240, 200);
player_touch_move(340, 200); /* 右移 100px */
player_on_swipe(MEOW_SWIPE_RIGHT, 100); /* SDK 中部右滑 → SWIPE_RIGHT */
int p2 = player_page();
/* 起点在进度条上不锁存(防拖进度条误判翻页);(240,504)=进度条行 */
player_touch_down(240, 504);
player_touch_move(140, 504);
player_on_tap(140, 504); /* 拖进度条抬手 → 应仍为封面页(seek 而非翻页) */
int latched_change = player_page();
int ok = (p0 == 0 && p1 == 1 && p2 == 0 && latched_change == 0);
printf("gesture: p0=%d p1(左滑)=%d p2(右滑)=%d 省电锁存=%d -> %s\n",
p0, p1, p2, latched_change, ok ? "PASS" : "FAIL");
if (!ok) return 1;
}
/* player 页:其 on_tick 通常驱动进度;这里直接再画一次确保状态就绪 */
meow_ui_paint_full();
if (page_id(name) == ACT_PLAYER) {