- P1: meow_ui_dialog.c 对话框底框 radius_card→MEOW_SHAPE_EXTRA_LARGE(28) 三处(:103填充/:104描边/:361 BottomSheet); meow_ui_widgets.h 新增 MEOW_SHAPE_EXTRA_LARGE 28 宏; TextField/FAB/Slider/Progress 按设计文档保留 - 批②: np_gesture.h 新增 NP_GEST_HOME+np_home_gesture(底部热区上滑,与左缘返回对称互斥); now_playing.c 新增 np_draw_home_bar(屏底左缘pill指示条)+手势衔接; test_now_playing_widgets G5b - 批6: ncm home.c 顶栏加回播放页按钮(MEOW_ICON_QUEUE_MUSIC)→push(ACT_PLAYER), 无音频也生效 - 批④: meowpanel /api/ams/bg 只读端点+前端后台列表页+杀/清复用kill通道 - UI微调: now_playing.c 播放页布局宏下移(NP_COVER_Y 84/NP_BTN_Y 612消底部留白)+歌词页背景统一黑色半透明叠层(弃封面取色底,删 np_draw_lyric_coverbg) - 封面保留: now_playing.c/notif_center.c 空artwork保留上一张已解码封面(防暂停/开歌单致META报空artwork后封面闪没); test_np_cover C2断言更新+mirror同步 0warning;宿主测试 test_np_cover ALL PASS;launcher/ncm/panel 宿主测试无回归。二进制留批量批次未入库
397 lines
21 KiB
C
397 lines
21 KiB
C
/* test_now_playing_widgets.c — M7.0b Now Playing 控件化宿主验证。
|
||
*
|
||
* 复现 run_now_playing() 所建控件集(np_widgets_create:meow_progress 进度条 + meow_iconbtn
|
||
* 三钮,play/pause 同位双钮按状态只画其一),验证:
|
||
* N1 进度条:value clamp 0-100 + track/fill 渲染(填充分界像素不同);
|
||
* N2 三钮圆形命中:圆心命中、角部不命中;
|
||
* N3 play/pause 同位切换:两钮图标位图不同 → 中心像素不同(画 PAUSE vs PLAY_ARROW);
|
||
* N4 主题四态(MD3/MIUIx × 明暗)下进度条+三钮渲染非背景像素。
|
||
*
|
||
* 几何常量与 now_playing.c 同源(镜像);控件创建方式与 np_widgets_create 同。
|
||
* 编译(在 patch_v2/meow_launcherd 下):
|
||
* gcc -Wall -Wextra -o test_now_playing_widgets test_now_playing_widgets.c \
|
||
* ../sdk/test_host_stub.c ../sdk/meow_ui_gfx.c ../sdk/meow_ui_sys.c \
|
||
* ../sdk/meow_ui_theme.c ../sdk/meow_ui_vol.c ../sdk/meow_ui_log.c \
|
||
* ../sdk/meow_ui_widget.c ../sdk/meow_ui_input.c ../sdk/meow_ui_activity.c \
|
||
* ../sdk/meow_ui_dialog.c ../sdk/meow_ui_ime.c ../sdk/meow_ui_str.c ../sdk/meow_pinyin.c \
|
||
* ../sdk/meow_ui_draw.c ../sdk/meow_ui_view.c ../sdk/meow_ui_box.c ../sdk/meow_ui_anim.c \
|
||
* ../sdk/meow_ui_scroll.c ../sdk/meow_ui_img.c ../sdk/meow_ui_media.c \
|
||
* ../sdk/meow_notify_ipc.c ../sdk/stb_image.c \
|
||
* ../sdk/meow_lyric.c ../sdk/meow_lyric_view.c \
|
||
* -I../sdk -I. -DMEOW_UI_HOST_TEST -pthread -lm
|
||
* 运行:./test_now_playing_widgets
|
||
*/
|
||
#include "meow_ui.h"
|
||
#include "meow_ui_internal.h" /* meow_ui_back_buf/pitch/bpp */
|
||
#include "np_gesture.h" /* 批4:双页方向感知手势决策(纯逻辑,宿主可单测) */
|
||
#include "meow_lyric_view.h" /* 批2:歌词页控件(批4接入,数据批3 meow_media_lyric_*) */
|
||
#include "meow_img_color.h" /* 批5b:封面取色主题派生(局部重绘进度条/按钮带取色用例) */
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <assert.h>
|
||
|
||
static int g_fail = 0;
|
||
#define CHECK(cond, name) do { \
|
||
if (cond) printf(" PASS %s\n", name); \
|
||
else { printf(" FAIL %s\n", name); g_fail++; } } while (0)
|
||
|
||
/* ---- 与 now_playing.c 同源几何(镜像) ---- */
|
||
#define NP_PROG_X 40
|
||
#define NP_PROG_W (480 - 80) /* 400 */
|
||
#define NP_PROG_Y 518
|
||
#define NP_TIME_Y 492
|
||
#define NP_BTN_Y 568
|
||
#define NP_PLAY_CX 240
|
||
#define NP_PREV_CX (NP_PLAY_CX - 78) /* 162 */
|
||
#define NP_NEXT_CX (NP_PLAY_CX + 78) /* 318 */
|
||
#define NP_PLAY_R 30
|
||
#define NP_PREV_R 22
|
||
#define NP_SENTINEL 0x51
|
||
|
||
static meow_widget *prog = NULL, *prev = NULL, *play = NULL, *pause = NULL, *next = NULL;
|
||
|
||
static void rd_px(int x, int y, unsigned short *p)
|
||
{
|
||
unsigned char *bb = meow_ui_back_buf();
|
||
int line = meow_ui_back_buf_pitch(), bpp = meow_ui_back_buf_bpp();
|
||
if (!bb || x < 0 || y < 0) { *p = 0; return; }
|
||
if (bpp == 16) *p = *(unsigned short *)(bb + (size_t)y * line + (size_t)x * 2);
|
||
else *p = (unsigned short)(*(unsigned int *)(bb + (size_t)y * line + (size_t)x * 4) >> 16);
|
||
}
|
||
static unsigned short px565(int x, int y) { unsigned short p; rd_px(x, y, &p); return p; }
|
||
static unsigned short rgb565(uint32_t c)
|
||
{ return (unsigned short)(((c >> 8) & 0xF800) | ((c >> 5) & 0x07E0) | ((c >> 3) & 0x001F)); }
|
||
static int region_nonbg(int x, int y, int w, int h, uint32_t bg)
|
||
{
|
||
unsigned short bg565 = ((bg >> 8) & 0xF800) | ((bg >> 5) & 0x07E0) | ((bg >> 3) & 0x001F);
|
||
int cnt = 0;
|
||
for (int dy = 0; dy < h; dy++)
|
||
for (int dx = 0; dx < w; dx++)
|
||
if (px565(x + dx, y + dy) != bg565) cnt++;
|
||
return cnt;
|
||
}
|
||
|
||
static void mk_widgets(void)
|
||
{
|
||
meow_ui_activity_push(NP_SENTINEL);
|
||
prog = meow_progress_create(NP_PROG_X, NP_PROG_Y, NP_PROG_W, 6, 0);
|
||
prev = meow_iconbtn_create(NP_PREV_CX - NP_PREV_R, NP_BTN_Y - NP_PREV_R,
|
||
NP_PREV_R * 2, MEOW_ICON_SKIP_PREV);
|
||
play = meow_iconbtn_create(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R,
|
||
NP_PLAY_R * 2, MEOW_ICON_PLAY_ARROW);
|
||
pause = meow_iconbtn_create(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R,
|
||
NP_PLAY_R * 2, MEOW_ICON_PAUSE);
|
||
next = meow_iconbtn_create(NP_NEXT_CX - NP_PREV_R, NP_BTN_Y - NP_PREV_R,
|
||
NP_PREV_R * 2, MEOW_ICON_SKIP_NEXT);
|
||
/* 主播放钮强调:primary/onPrimary(镜像 np_widgets_create) */
|
||
const meow_theme *th = meow_theme_get();
|
||
meow_widget_opts op; memset(&op, 0, sizeof op);
|
||
op.bg = th->primary; op.fg = th->onPrimary;
|
||
meow_widget_set_opts(play, &op);
|
||
meow_widget_set_opts(pause, &op);
|
||
meow_ui_activity_pop();
|
||
}
|
||
|
||
/* 歌词视图宽度测量(宿主:字节数近似,够用不裂屏;launcher 侧为 ui_width)。 */
|
||
static int lv_test_width(const char *u, int size, void *ctx)
|
||
{
|
||
(void)size; (void)ctx;
|
||
return (int)strlen(u);
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
setbuf(stdout, NULL);
|
||
setenv("MEOW_UI_DUMP", "/tmp/nowplaying.ppm", 1);
|
||
meow_ui_opts o = { 480, 720 };
|
||
assert(meow_ui_init(&o) == 0);
|
||
|
||
meow_ui_activity_push(NP_SENTINEL);
|
||
mk_widgets();
|
||
const meow_theme *th = meow_theme_get();
|
||
meow_ui_set_style(MEOW_STYLE_MD3);
|
||
meow_theme_set_mode(MEOW_THEME_DARK);
|
||
th = meow_theme_get();
|
||
|
||
/* ============ N1 进度条 clamp + track/fill 渲染 ============ */
|
||
printf("N1 progress value + track/fill\n");
|
||
meow_widget_set_opts(prog, &(meow_widget_opts){ .bg = 0 });
|
||
meow_ui_clear(0);
|
||
meow_progress_set(prog, 150); /* clamp → 100 */
|
||
meow_widget_draw(prog);
|
||
unsigned short fill_end = px565(NP_PROG_X + NP_PROG_W - 2, NP_PROG_Y + 3);
|
||
unsigned short track_mid = px565(NP_PROG_X + NP_PROG_W / 2, NP_PROG_Y + 3);
|
||
CHECK(fill_end != 0 && track_mid != 0, "value 150 clamp 100 -> full fill renders");
|
||
meow_progress_set(prog, 50);
|
||
meow_widget_draw(prog);
|
||
/* 50% 填充区 [40,240) 内像素应为主色;240 之后的轨道区应为轨道色(surfaceVariant) */
|
||
unsigned short infill = px565(NP_PROG_X + NP_PROG_W / 4, NP_PROG_Y + 3); /* x=140,填充区 */
|
||
unsigned short empty = px565(NP_PROG_X + NP_PROG_W - 4, NP_PROG_Y + 3); /* x=436,轨道区 */
|
||
CHECK(infill != empty, "value 50 -> fill region differs from empty tail");
|
||
|
||
/* ============ N2 三钮圆形命中 ============ */
|
||
printf("N2 circular hit\n");
|
||
CHECK(meow_widget_hit(prev, NP_PREV_CX, NP_BTN_Y), "prev center hits");
|
||
CHECK(!meow_widget_hit(prev, NP_PREV_CX - NP_PREV_R, NP_BTN_Y - NP_PREV_R), "prev corner MISSES");
|
||
CHECK(meow_widget_hit(play, NP_PLAY_CX, NP_BTN_Y), "play center hits");
|
||
CHECK(meow_widget_hit(pause, NP_PLAY_CX, NP_BTN_Y), "pause(overlay) center hits");
|
||
CHECK(!meow_widget_hit(play, NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R), "play corner MISSES");
|
||
CHECK(meow_widget_hit(next, NP_NEXT_CX, NP_BTN_Y), "next center hits");
|
||
|
||
/* ============ N3 play/pause 同位切换(两钮位图不同 → 像素不同) ============ */
|
||
printf("N3 play/pause overlay icon switch\n");
|
||
meow_ui_clear(0);
|
||
meow_widget_draw(play); meow_ui_clear(0); /* 只画 play */
|
||
meow_widget_draw(play);
|
||
unsigned short p_play = px565(NP_PLAY_CX, NP_BTN_Y); /* 中心=图标墨色 */
|
||
meow_ui_clear(0);
|
||
meow_widget_draw(pause);
|
||
unsigned short p_pause = px565(NP_PLAY_CX, NP_BTN_Y);
|
||
CHECK(p_play != p_pause, "play vs pause icon differs at centre (overlay switch works)");
|
||
/* 圆心区域非页面底色(画出来了) */
|
||
meow_ui_clear(0); meow_widget_draw(pause);
|
||
CHECK(region_nonbg(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R,
|
||
NP_PLAY_R * 2, NP_PLAY_R * 2, th->surface) > 0,
|
||
"pause button renders non-bg in circle");
|
||
|
||
/* ============ N4 主题四态:进度条+三钮渲染非背景 ============ */
|
||
printf("N4 theme 4-state render\n");
|
||
const int styles[2] = { MEOW_STYLE_MD3, MEOW_STYLE_MIUIX };
|
||
const int modes[2] = { MEOW_THEME_LIGHT, MEOW_THEME_DARK };
|
||
for (int si = 0; si < 2; si++) {
|
||
for (int mi = 0; mi < 2; mi++) {
|
||
meow_ui_set_style(styles[si]);
|
||
meow_theme_set_mode((meow_theme_mode)modes[mi]);
|
||
th = meow_theme_get();
|
||
meow_theme ex; meow_theme_export(&ex);
|
||
CHECK(ex.primary == th->primary && ex.surface == th->surface &&
|
||
ex.surfaceVariant == th->surfaceVariant, "export == get (spot roles)");
|
||
meow_ui_clear(0);
|
||
meow_progress_set(prog, 40); meow_widget_draw(prog);
|
||
meow_widget_draw(prev);
|
||
meow_widget_draw(pause);
|
||
meow_widget_draw(next);
|
||
char nm[80];
|
||
int progpx = region_nonbg(NP_PROG_X, NP_PROG_Y, NP_PROG_W, 6, th->surface);
|
||
int btnpx = region_nonbg(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R,
|
||
NP_PLAY_R * 2, NP_PLAY_R * 2, th->surface);
|
||
snprintf(nm, sizeof nm, "style=%s mode=%s prog+btn render",
|
||
styles[si] ? "MIUIx" : "MD3", modes[mi] ? "dark" : "light");
|
||
CHECK(progpx > 0 && btnpx > 0, nm);
|
||
}
|
||
}
|
||
|
||
/* ============ R1 批5b:局部重绘取色——进度条 fill=accent/track=fg_dim + 默认回退 ============
|
||
* 镜像 np_theme_widgets(取色有效→进度条 opts.bg=fg_dim/opts.fg=accent)+ np_draw_progress。
|
||
* 用「直接 fill_rect 参考像素」对比,绕开 565 精度差异(同一渲染器同色 → 同 565)。 */
|
||
printf("R1 progress cover-theme fill/track + default fallback\n");
|
||
meow_ui_set_style(MEOW_STYLE_MD3);
|
||
meow_theme_set_mode(MEOW_THEME_DARK);
|
||
th = meow_theme_get();
|
||
meow_img_color_theme cc; memset(&cc, 0, sizeof cc);
|
||
meow_img_color_derive(0xE53935u, 0x1E88E5u, th, &cc); /* 红/蓝两色 → 派生取色主题 */
|
||
|
||
/* 覆盖取色:进度条 fill=accent / track=fg_dim */
|
||
{
|
||
meow_widget_opts op; memset(&op, 0, sizeof op);
|
||
op.bg = cc.fg_dim; op.fg = cc.accent;
|
||
meow_widget_set_opts(prog, &op);
|
||
meow_ui_clear(0);
|
||
meow_ui_fill_rect(NP_PROG_X, NP_PROG_Y, 5, 6, cc.accent); /* fill 参考 */
|
||
unsigned short ref_fill = px565(NP_PROG_X + 2, NP_PROG_Y + 3);
|
||
meow_ui_clear(0);
|
||
meow_ui_fill_rect(NP_PROG_X + NP_PROG_W - 4, NP_PROG_Y, 3, 6, cc.fg_dim); /* track 参考 */
|
||
unsigned short ref_track = px565(NP_PROG_X + NP_PROG_W - 3, NP_PROG_Y + 3);
|
||
meow_ui_clear(0);
|
||
meow_progress_set(prog, 50);
|
||
meow_widget_draw(prog);
|
||
int fill_x = NP_PROG_X + NP_PROG_W / 4; /* 50% 填充区内 */
|
||
int track_x = NP_PROG_X + NP_PROG_W - 4; /* 尾部轨道区 */
|
||
CHECK(px565(fill_x, NP_PROG_Y + 3) == ref_fill, "cover: progress fill == accent");
|
||
CHECK(px565(track_x, NP_PROG_Y + 3) == ref_track, "cover: progress track == fg_dim");
|
||
|
||
/* 默认回退:清 opts → 回到主题 primary/surfaceVariant(无取色回退默认) */
|
||
memset(&op, 0, sizeof op);
|
||
meow_widget_set_opts(prog, &op);
|
||
meow_ui_clear(0);
|
||
meow_ui_fill_rect(NP_PROG_X, NP_PROG_Y, 5, 6, th->primary);
|
||
unsigned short ref_pri = px565(NP_PROG_X + 2, NP_PROG_Y + 3);
|
||
meow_ui_clear(0);
|
||
meow_progress_set(prog, 50);
|
||
meow_widget_draw(prog);
|
||
CHECK(px565(fill_x, NP_PROG_Y + 3) == ref_pri, "default: progress fill == theme primary");
|
||
CHECK(px565(fill_x, NP_PROG_Y + 3) != ref_fill, "default vs cover fill differ");
|
||
}
|
||
|
||
/* ============ R2 批5b:进度/按钮带底色随取色渐变(非默认 surface) ============
|
||
* 镜像 np_repaint_progress 的带底色分支(np_page_bg_row 按整页 span 插值)。
|
||
* 旧 bug:本地重绘用 th->surface 清带 → 带内被刷成默认色;现应取色渐变且 != surface。 */
|
||
printf("R2 band background uses cover gradient (not default surface)\n");
|
||
{
|
||
#define NP_SB_H 28
|
||
int H = 720;
|
||
meow_ui_clear(0);
|
||
for (int yy = NP_TIME_Y; yy < NP_BTN_Y + NP_PLAY_R; yy++) {
|
||
int t = (H - NP_SB_H <= 1) ? 0 : (yy - NP_SB_H) * 255 / (H - NP_SB_H - 1);
|
||
if (t < 0) t = 0; else if (t > 255) t = 255;
|
||
int tr = (cc.bg_top >> 16) & 255, tg = (cc.bg_top >> 8) & 255, tb = cc.bg_top & 255;
|
||
int br = (cc.bg_bottom >> 16) & 255, bg = (cc.bg_bottom >> 8) & 255, bb = cc.bg_bottom & 255;
|
||
int r = tr + ((br - tr) * t + 128) / 255;
|
||
int g = tg + ((bg - tg) * t + 128) / 255;
|
||
int b = tb + ((bb - tb) * t + 128) / 255;
|
||
meow_ui_fill_rect(0, yy, 480, 1, ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b);
|
||
}
|
||
unsigned short bandpx = px565(10, NP_TIME_Y + 55);
|
||
CHECK(bandpx != rgb565(th->surface), "cover: band bg != default surface");
|
||
CHECK(bandpx != 0, "cover: band bg rendered");
|
||
}
|
||
|
||
/* ============ R3 批5b:控制三钮(含 prev/next)随取色 accent + 默认回退 ============
|
||
* 镜像 np_theme_widgets:取色有效→四钮 opts.bg=accent/opts.fg=accent_fg(prev/next 不再默认底色)。 */
|
||
printf("R3 control buttons follow cover accent\n");
|
||
{
|
||
meow_widget_opts op; memset(&op, 0, sizeof op);
|
||
op.bg = cc.accent; op.fg = cc.accent_fg;
|
||
meow_widget_set_opts(prev, &op);
|
||
meow_widget_set_opts(next, &op);
|
||
meow_widget_set_opts(play, &op);
|
||
meow_widget_set_opts(pause, &op);
|
||
meow_ui_clear(0);
|
||
meow_ui_fill_rect(NP_PREV_CX - 2, NP_BTN_Y - 18, 4, 2, cc.accent); /* accent 参考(圆底上方、图标外) */
|
||
unsigned short ref_acct = px565(NP_PREV_CX, NP_BTN_Y - 17);
|
||
meow_ui_clear(0);
|
||
meow_widget_draw(prev); /* r=22,cy-17 在圆内且高于图标(cy-13) */
|
||
CHECK(px565(NP_PREV_CX, NP_BTN_Y - 17) == ref_acct, "cover: prev bg == accent");
|
||
meow_ui_clear(0);
|
||
meow_widget_draw(play); /* r=30,cy-26 在圆内且高于图标(cy-18) */
|
||
CHECK(px565(NP_PLAY_CX, NP_BTN_Y - 26) == ref_acct, "cover: play bg == accent");
|
||
|
||
/* 默认回退:清 prev/next opts → 回 surfaceContainerLow(无取色不回归旧形态) */
|
||
memset(&op, 0, sizeof op);
|
||
meow_widget_set_opts(prev, &op);
|
||
meow_widget_set_opts(next, &op);
|
||
meow_ui_clear(0);
|
||
meow_ui_fill_rect(NP_PREV_CX - 2, NP_BTN_Y - 18, 4, 2, th->surfaceContainerLow);
|
||
unsigned short ref_def = px565(NP_PREV_CX, NP_BTN_Y - 17);
|
||
meow_ui_clear(0);
|
||
meow_widget_draw(prev);
|
||
CHECK(px565(NP_PREV_CX, NP_BTN_Y - 17) == ref_def, "default: prev bg == surfaceContainerLow");
|
||
}
|
||
|
||
/* ============ G5 双页手势方向感知(np_gesture.h,纯逻辑) ============ */
|
||
printf("G5 dual-page direction-aware gestures\n");
|
||
/* 播放页:右→左滑 → 进歌词页 */
|
||
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 100, -50, 5) == NP_GEST_NEXT,
|
||
"play: left-swipe -> lyric");
|
||
/* 播放页:左缘右滑 → 回桌面(保留 M6.26) */
|
||
CHECK(np_gesture_decide(NP_PAGE_PLAY, 8, 100, 80, 5) == NP_GEST_EXIT,
|
||
"play: edge right-swipe -> exit");
|
||
/* 播放页:任意右滑 → 返回桌面(用户定案「播放页任意右滑回桌面」,含非左缘;np_gesture.h 恒 EXIT) */
|
||
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 100, 80, 5) == NP_GEST_EXIT,
|
||
"play: non-edge right-swipe -> EXIT");
|
||
/* 歌词页:左→右滑 → 回播放页(不是回桌面) */
|
||
CHECK(np_gesture_decide(NP_PAGE_LYRIC, 200, 100, 60, 5) == NP_GEST_PREV,
|
||
"lyric: right-swipe -> play");
|
||
/* 歌词页:左缘右滑 → 回播放页(不接桌面,避免误退) */
|
||
CHECK(np_gesture_decide(NP_PAGE_LYRIC, 8, 100, 80, 5) == NP_GEST_PREV,
|
||
"lyric: edge right-swipe -> play (not exit)");
|
||
/* 歌词页:右→左滑 → 歌词页是末页,忽略 */
|
||
CHECK(np_gesture_decide(NP_PAGE_LYRIC, 200, 100, -60, 5) == NP_GEST_NONE,
|
||
"lyric: left-swipe -> none");
|
||
/* 顶部热区下滑 → 通知中心(两个页面同语义) */
|
||
CHECK(np_gesture_decide(NP_PAGE_PLAY, 100, 10, 0, 70) == NP_GEST_TOP,
|
||
"top swipe-down -> notif");
|
||
/* 近点按 → TAP;纵向主导 → NONE(不误切) */
|
||
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 300, 5, 5) == NP_GEST_TAP,
|
||
"near tap -> TAP");
|
||
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 300, 5, 80) == NP_GEST_NONE,
|
||
"vertical dominant -> NONE");
|
||
|
||
/* ============ G5b 批② 底部上滑(home)手势(np_gesture.h np_home_gesture,纯逻辑) ============ */
|
||
printf("G5b bottom-swipe-up home gesture\n");
|
||
const int FBRES = 720; /* 屏高(宿主 480x720;真机 fb_yres=720) */
|
||
const int BZ = FBRES - NP_HOME_EDGE_H; /* 底部起滑区上界 692 */
|
||
/* 底部起滑 + 向上主导 ≥阈值 → HOME */
|
||
CHECK(np_home_gesture(200, BZ + 10, 0, -120, FBRES) == 1,
|
||
"home: bottom zone + up-swipe -> HOME");
|
||
CHECK(np_home_gesture(100, FBRES - 1, 20, -80, FBRES) == 1,
|
||
"home: very bottom + slight right-drift up -> HOME");
|
||
/* 与左缘返回互斥:左缘起点(down_x<NP_EDGE_W)不认 home(让给左缘返回) */
|
||
CHECK(np_home_gesture(10, BZ + 10, 0, -120, FBRES) == 0,
|
||
"home: left-edge origin -> NOT home (reserved for edge-back)");
|
||
/* 起点不在底部起滑区(顶部/中部)不认 home */
|
||
CHECK(np_home_gesture(200, 10, 0, -120, FBRES) == 0,
|
||
"home: top origin -> NOT home");
|
||
CHECK(np_home_gesture(200, 300, 0, -120, FBRES) == 0,
|
||
"home: mid origin -> NOT home");
|
||
/* 横向主导(向右滑)不认 home(该判给左缘返回/切页) */
|
||
CHECK(np_home_gesture(200, BZ + 10, 120, 0, FBRES) == 0,
|
||
"home: right-dominant -> NOT home");
|
||
/* 向下滑 / 未达阈值 / 竖向不主导 不认 home */
|
||
CHECK(np_home_gesture(200, BZ + 10, 0, 120, FBRES) == 0,
|
||
"home: downward -> NOT home");
|
||
CHECK(np_home_gesture(200, BZ + 10, 0, -NP_HOME_SWIPE + 1, FBRES) == 0,
|
||
"home: below up-threshold -> NOT home");
|
||
CHECK(np_home_gesture(200, BZ + 10, -120, -80, FBRES) == 0,
|
||
"home: horizontal-dominant up -> NOT home");
|
||
/* 与 now_playing.c 集成顺序一致:np_gesture_decide 对底部纵滑返回 NONE,再由 home 覆盖为 HOME */
|
||
{
|
||
int dx = 0, dy = -120, tdx = 200, tdy = BZ + 10;
|
||
np_gest_t gnp = np_gesture_decide(NP_PAGE_PLAY, tdx, tdy, dx, dy);
|
||
if (np_home_gesture(tdx, tdy, dx, dy, FBRES)) gnp = NP_GEST_HOME;
|
||
CHECK(gnp == NP_GEST_HOME,
|
||
"integration: bottom up-swipe -> HOME (overrides decide-NONE)");
|
||
}
|
||
/* 集成:左缘起点底部上滑不被误判为 home(保留给左缘返回) */
|
||
{
|
||
int tdx = 8, tdy = BZ + 10, dx = 0, dy = -120; /* 左缘 + 上滑(竖向主导) */
|
||
np_gest_t gnp = np_gesture_decide(NP_PAGE_PLAY, tdx, tdy, dx, dy);
|
||
if (np_home_gesture(tdx, tdy, dx, dy, FBRES)) gnp = NP_GEST_HOME;
|
||
CHECK(gnp != NP_GEST_HOME,
|
||
"integration: left-edge origin up-swipe -> NOT home");
|
||
}
|
||
|
||
/* ============ G6 歌词页:空态 + 渲染(批2 控件 + 批3 数据语义) ============ */
|
||
printf("G6 lyric view: empty + render\n");
|
||
meow_ui_activity_push(NP_SENTINEL);
|
||
meow_lyric_view *lv = meow_lyric_view_create(0, 28, 480, 720 - 28, lv_test_width, NULL);
|
||
meow_lyric_view_set_empty(lv, "暂无歌词");
|
||
meow_ui_activity_pop();
|
||
CHECK(lv != NULL, "lyric_view created");
|
||
if (lv) {
|
||
/* 无歌词空态:无解析 → 0 行、visible=0(视图内建空态文案) */
|
||
meow_lyric_clear();
|
||
CHECK(meow_lyric_count() == 0, "clear -> 0 lines");
|
||
CHECK(meow_lyric_view_visible(lv, 0, NULL, 0) == 0, "empty -> 0 visible entries");
|
||
/* 有词:解析两行 → count/line_at/visible/当前行色 */
|
||
int np = meow_lyric_parse("[00:01.00]第一行歌词\n[00:05.00]第二行歌词", "");
|
||
CHECK(np == 2, "parse -> 2 lines");
|
||
CHECK(meow_lyric_count() == 2, "count == 2");
|
||
CHECK(meow_lyric_line_at(0) == 0, "line_at(0) -> first");
|
||
CHECK(meow_lyric_line_at(3000) == 0, "line_at(3000) -> first");
|
||
CHECK(meow_lyric_line_at(6000) == 1, "line_at(6000) -> second");
|
||
CHECK(strcmp(meow_lyric_line_text(0), "第一行歌词") == 0, "text(0) == 第一行歌词");
|
||
meow_lyric_view_vis vb[9];
|
||
int vn = meow_lyric_view_visible(lv, 3000, vb, 9);
|
||
CHECK(vn > 0, "visible(3000) > 0");
|
||
CHECK(meow_lyric_view_cur_color(lv) == meow_theme_get()->onSurface,
|
||
"cur_color == theme onSurface");
|
||
/* 批5 取色预留:set_colors 可接入(覆盖活动行为主题 accent 后再还原默认) */
|
||
meow_lyric_view_colors c; memset(&c, 0, sizeof c);
|
||
c.cur = meow_theme_get()->accent;
|
||
meow_lyric_view_set_colors(lv, &c);
|
||
CHECK(meow_lyric_view_cur_color(lv) == meow_theme_get()->accent,
|
||
"set_colors cur override works");
|
||
meow_lyric_view_set_colors(lv, NULL); /* 回主题默认 */
|
||
CHECK(meow_lyric_view_cur_color(lv) == meow_theme_get()->onSurface,
|
||
"set_colors NULL -> theme default");
|
||
meow_lyric_view_free(lv);
|
||
}
|
||
|
||
meow_ui_activity_pop();
|
||
meow_ui_shutdown();
|
||
printf(g_fail ? "\nRESULT: %d FAIL(S)\n" : "\nRESULT: ALL PASS\n", g_fail);
|
||
return g_fail;
|
||
}
|