feat(launcher): 批4 Now Playing双页(播放页⇄歌词页) — 方向感知手势(播放页右→左进歌词/左缘右滑回桌面;歌词页左→右回播放)+歌词页用批3数据+批1/2控件实时滚动+空态;宿主G5/G6全过,0warning;meow_ui.a未重编
This commit is contained in:
1 parent
2e5b814059
commit
8c677f127f
4 files changed
+310
-39
No files matched your search
@@ -29,6 +29,7 @@ SYSROOT="$ROOT/.tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf"
|
||||
font_theme.c keys.c util.c meow_dep.c \
|
||||
meow_touch.c meow_settings.c meow_notif.c meow_media.c meow_bgplay.c \
|
||||
meow_ams_start.c lock_screen.c lock_screen_ui.c lock_settings.c \
|
||||
"../sdk/meow_lyric.c" "../sdk/meow_lyric_view.c" \
|
||||
"../sdk/meow_ui.a" "$SYSROOT/lib/libz.a" -lpthread -o meow_launcherd
|
||||
echo "== meow_launcherd =="
|
||||
ls -la meow_launcherd
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
* 元数据/源变化立即整页重画;交互只重绘按钮/进度带。
|
||||
*/
|
||||
#include "meow_launcher_internal.h"
|
||||
#include "np_gesture.h" /* 批4:双页方向感知手势决策(header-only,宿主可单测) */
|
||||
#include "meow_lyric_view.h" /* 批2控件:歌词页渲染(批4接入,数据批3 meow_media_lyric_*) */
|
||||
|
||||
|
||||
#define NP_COVER 300 /* 封面边长(方,居中) */
|
||||
@@ -33,6 +35,23 @@
|
||||
static meow_img *g_np_cover = NULL;
|
||||
static char g_np_cover_path[200] = "";
|
||||
|
||||
/* ---- 批4:Now Playing 双页状态 + 歌词页控件 ----
|
||||
* 同一容器两页:NP_PAGE_PLAY(播放页,原有内容)+ NP_PAGE_LYRIC(歌词页,批2 meow_lyric_view)。
|
||||
* 页面切换靠方向感知手势(np_gesture.h);歌词数据批3(meow_media_lyric_*),主题先走 meow_theme
|
||||
* 默认;meow_lyric_view_set_colors 为批5 封面取色动态主题预留(本批不取色,见 np_lyric_refresh)。 */
|
||||
static int g_np_page = NP_PAGE_PLAY;
|
||||
static meow_lyric_view *g_np_lyric = NULL; /* 歌词视图(lazy 建一次,跨进入复用) */
|
||||
static uint32_t g_np_lyric_seq = 0xFFFFFFFFu; /* 上次解析的歌曲代际(新 seq 才重解析) */
|
||||
static char g_np_lyric_app[MEOW_APP_ID_MAX] = ""; /* 上次解析的源 app_id */
|
||||
static int g_np_lyric_last_valid = -1; /* -1=未初始化 0=无词 1=有词(防重复 clear) */
|
||||
|
||||
/* 批4:歌词页宽度测量(launcher ui_width 包装成 meow_lyric_width_fn;meow_lyric_view 需要)。 */
|
||||
static int np_lyric_width(const char *u, int size, void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return ui_width(u, size);
|
||||
}
|
||||
|
||||
/* 封面解码缓存(artwork 路径变化才重载)。 */
|
||||
static void np_cover_load(const meow_media_session_t *s)
|
||||
{
|
||||
@@ -137,6 +156,12 @@ static void np_widgets_create(void)
|
||||
op.bg = th->primary; op.fg = th->onPrimary;
|
||||
if (g_np_play) meow_widget_set_opts(g_np_play, &op);
|
||||
if (g_np_pause) meow_widget_set_opts(g_np_pause, &op);
|
||||
/* 批4:歌词页视图(覆盖状态栏下整页;宽测量走 launcher ui_width 包装)。
|
||||
* set_colors 留作批5 封面取色覆盖入口;本批用 meow_theme 默认(不调用)。 */
|
||||
g_np_lyric = meow_lyric_view_create(0, SB_BAR_H, fb_xres, fb_yres - SB_BAR_H,
|
||||
np_lyric_width, NULL);
|
||||
if (g_np_lyric)
|
||||
meow_lyric_view_set_empty(g_np_lyric, meow_str_zh("np.no_lyric", "暂无歌词"));
|
||||
meow_ui_activity_pop();
|
||||
g_np_init = 1;
|
||||
}
|
||||
@@ -180,12 +205,64 @@ static void np_draw_progress(const meow_media_session_t *s, uint32_t pos, const
|
||||
ui_draw(NP_PROG_X + NP_PROG_W - ui_width(rbuf, 16), NP_TIME_Y, rbuf, th->on_surface_variant, 16);
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
* 批4:歌词页渲染(批2 meow_lyric_view + 数据批3 meow_media_lyric_*)。
|
||||
* - 有词:meow_lyric_parse(lrc,tlrc)→meow_lyric_view_set_pos(display_pos) 实时滚动,
|
||||
* 当前行由 meow_lyric_view 内部 meow_lyric_line_at(pos_ms) 计算(与绘制/点跳同源)。
|
||||
* - 无词/无源:清空并置 pos=0,视图内建空态文案(np.no_lyric→"暂无歌词")。
|
||||
* 主题:先走 meow_theme 默认(视图自绘 scrim/活动行纯白/灰阶递减);批5 封面取色动态主题的可
|
||||
* 接入点为 meow_lyric_view_set_colors(本批不取色,故不调用;接入只需在下方填 meow_lyric_view_colors
|
||||
* 后调用一次,字段 0=回主题默认)。
|
||||
* ================================================================== */
|
||||
static void np_lyric_refresh(const meow_media_session_t *s)
|
||||
{
|
||||
if (!g_np_lyric) return;
|
||||
int valid = meow_media_lyric_valid(s);
|
||||
if (valid) {
|
||||
/* 换歌/换源(新 lyric_seq/app_id)才重解析;否则沿用,只推进位置。 */
|
||||
if (g_np_lyric_seq != s->lyric_seq || strcmp(g_np_lyric_app, s->app_id) != 0) {
|
||||
meow_lyric_parse(meow_media_lyric_lrc(s), meow_media_lyric_tlrc(s));
|
||||
g_np_lyric_seq = s->lyric_seq;
|
||||
snprintf(g_np_lyric_app, sizeof g_np_lyric_app, "%s", s->app_id);
|
||||
}
|
||||
meow_lyric_view_set_pos(g_np_lyric, meow_media_display_pos(s));
|
||||
} else {
|
||||
/* 无词/无源:仅当上次仍有词才清空(省冗余 memset),置 pos=0。 */
|
||||
if (g_np_lyric_last_valid != 0) {
|
||||
meow_lyric_clear();
|
||||
g_np_lyric_seq = 0xFFFFFFFFu;
|
||||
g_np_lyric_app[0] = 0;
|
||||
}
|
||||
meow_lyric_view_set_pos(g_np_lyric, 0);
|
||||
}
|
||||
g_np_lyric_last_valid = valid;
|
||||
}
|
||||
|
||||
/* 歌词页整页绘制:铺 theme surface 底 → lyric_view(自绘 scrim + 歌词/空态)。 */
|
||||
static void np_draw_lyric_page(int redraw_sb)
|
||||
{
|
||||
const meow_ui_theme_t *th = s_ui_theme();
|
||||
int W = fb_xres, H = fb_yres;
|
||||
if (!g_np_init) np_widgets_create();
|
||||
if (redraw_sb) fill_rect(0, 0, W, SB_BAR_H, th->surface);
|
||||
fill_rect(0, SB_BAR_H, W, H - SB_BAR_H, th->surface);
|
||||
np_lyric_refresh(meow_media_current());
|
||||
if (g_np_lyric)
|
||||
meow_widget_draw(meow_lyric_view_widget(g_np_lyric));
|
||||
if (redraw_sb) draw_statusbar();
|
||||
}
|
||||
|
||||
/* 整页绘制(空态占位)。redraw_sb=1 时喂/标脏状态栏(打开/主题变化),否则保留上次顶条。 */
|
||||
static void np_draw_page(int redraw_sb)
|
||||
{
|
||||
const meow_ui_theme_t *th = s_ui_theme();
|
||||
int W = fb_xres, H = fb_yres;
|
||||
if (!g_np_init) np_widgets_create(); /* M7.0b:lazy 建控件(跨进入复用) */
|
||||
/* 批4:歌词页整页走 lyric_view(无源/无词空态由视图内建)。 */
|
||||
if (g_np_page == NP_PAGE_LYRIC) {
|
||||
np_draw_lyric_page(redraw_sb);
|
||||
return;
|
||||
}
|
||||
if (redraw_sb) fill_rect(0, 0, W, SB_BAR_H, th->surface);
|
||||
fill_rect(0, SB_BAR_H, W, H - SB_BAR_H, th->surface);
|
||||
const meow_media_session_t *s = meow_media_current();
|
||||
@@ -299,10 +376,14 @@ void run_now_playing(struct app *apps, int napps)
|
||||
uint32_t last_state = 0xFFFFFFFFu;
|
||||
char last_app[MEOW_APP_ID_MAX] = "";
|
||||
|
||||
meow_ui_activity_push(NP_SENTINEL_ACT); /* M7.0b:进入 push 哨兵(与函数尾 449 行 pop 配对)。
|
||||
meow_ui_activity_push(NP_SENTINEL_ACT); /* M7.0b:进入 push 哨兵(与函数尾 pop 配对)。
|
||||
* 控件 owner 一直钉哨兵,命中要走 meow_widget_hit 的
|
||||
* owner==active 闸门——漏 push 则 active()!=0x51,
|
||||
* 三钮 meow_widget_hit 恒 false(「播放页三键无效」根因)。 */
|
||||
g_np_page = NP_PAGE_PLAY; /* 批4:每次进入 Now Playing 从播放页起(上次退出页不残留) */
|
||||
g_np_lyric_last_valid = -1; /* 批4:重置歌词「是否有词」过渡态,防首帧多清一次 */
|
||||
g_np_lyric_seq = 0xFFFFFFFFu; /* 批4:强制首次进歌词页重解析(防跨进入残留缓存) */
|
||||
g_np_lyric_app[0] = 0;
|
||||
np_draw_page(1);
|
||||
meow_dirty_full();
|
||||
meow_ui_flush();
|
||||
@@ -335,43 +416,61 @@ void run_now_playing(struct app *apps, int napps)
|
||||
if (td_ok) {
|
||||
int dx = tlx - tdx, dy = tly - tdy;
|
||||
int adx = dx < 0 ? -dx : dx, ady = dy < 0 ? -dy : dy;
|
||||
/* M6.21 诊断:打印该次抬手手势的完整输入与各判定结果(真机定位
|
||||
* 「返回滑不出」根因——状态栏/通知中心已生效,惟返回未触发)。 */
|
||||
int np_is_top = mnp_top_swipe_down(tdx, tdy, dx, dy, SB_BAR_H, 65);
|
||||
int np_edge = meow_edge_back(tdx, dx, dy);
|
||||
int np_anyright = (dx >= 40 && adx > ady);
|
||||
logmsg("np up: down=(%d,%d) d=(%d,%d) adx=%d ady=%d top=%d edge=%d anyright=%d",
|
||||
tdx, tdy, dx, dy, adx, ady, np_is_top, np_edge, np_anyright);
|
||||
/* 顶部热区下滑 → 打开通知中心(与主界面同语义;mnp_top_swipe_down
|
||||
* 内部已排除左缘 down_x<24,与下方返回手势互斥)。run_notif_center
|
||||
* 为阻塞模态,返回后整页重画播放页。 */
|
||||
if (np_is_top) {
|
||||
notif_click_t click;
|
||||
memset(&click, 0, sizeof click);
|
||||
click.app_idx = -1;
|
||||
click.status = NOTIF_CLICK_STATUS_NONE;
|
||||
run_notif_center(apps, napps, &click, 0, 0, 0);
|
||||
need_redraw = 1;
|
||||
meow_dirty_full();
|
||||
meow_ui_flush();
|
||||
}
|
||||
/* 左缘右滑返回(全局手势语义),或任意横向右滑返回——与主界面
|
||||
* 「左滑进入 Now Playing」对称。返回阈值 65→40 放宽(防用户右滑
|
||||
* 幅度不足 65 判不中);播放页无横向分页内容、无进度条拖动
|
||||
* (进度=点按,幅度<60 走 tap 分支),故任意位置横向右滑恒判返回。 */
|
||||
else if (np_edge || np_anyright) {
|
||||
logmsg("np: BACK break (edge=%d anyright=%d dx=%d)", np_edge, np_anyright, dx);
|
||||
np_exit = 1;
|
||||
break; /* 仅跳出内层读事件 while;外层主循环靠 np_exit 退出 */
|
||||
}
|
||||
if (adx < 60 && ady < 60) {
|
||||
int cmd = np_btn_tap(tlx, tly);
|
||||
if (cmd) { meow_media_playctl((uint32_t)cmd, 0); need_redraw = 1; }
|
||||
else {
|
||||
int64_t seek = np_progress_seek(tlx, tly);
|
||||
if (seek > 0) meow_media_playctl(5, seek);
|
||||
/* M6.21 诊断 + 批4 页感知:打印该次抬手手势的完整输入与按当前页
|
||||
* 的方向感知判定(真机定位「返回滑不出」根因曾依赖此日志;
|
||||
* 保留,键改为 ges=np_gesture_decide 返回值)。 */
|
||||
np_gest_t gnp = np_gesture_decide(g_np_page, tdx, tdy, dx, dy);
|
||||
logmsg("np up: page=%d down=(%d,%d) d=(%d,%d) adx=%d ady=%d ges=%d",
|
||||
g_np_page, tdx, tdy, dx, dy, adx, ady, (int)gnp);
|
||||
switch (gnp) {
|
||||
case NP_GEST_TOP:
|
||||
/* 顶部热区下滑 → 打开通知中心(与主界面同语义;mnp_top_swipe_down
|
||||
* 内部已排除左缘 down_x<24,与下方返回手势互斥)。run_notif_center
|
||||
* 为阻塞模态,返回后整页重画。 */
|
||||
{
|
||||
notif_click_t click;
|
||||
memset(&click, 0, sizeof click);
|
||||
click.app_idx = -1;
|
||||
click.status = NOTIF_CLICK_STATUS_NONE;
|
||||
run_notif_center(apps, napps, &click, 0, 0, 0);
|
||||
need_redraw = 1;
|
||||
meow_dirty_full();
|
||||
meow_ui_flush();
|
||||
}
|
||||
break;
|
||||
case NP_GEST_EXIT:
|
||||
/* 播放页左缘右滑 → 回桌面(保留 M6.26 全局手势语义)。 */
|
||||
logmsg("np: BACK break (exit, page=%d)", g_np_page);
|
||||
np_exit = 1;
|
||||
break;
|
||||
case NP_GEST_NEXT:
|
||||
/* 播放页 右→左滑 → 进歌词页。 */
|
||||
g_np_page = NP_PAGE_LYRIC;
|
||||
need_redraw = 1;
|
||||
logmsg("np: -> lyric page");
|
||||
break;
|
||||
case NP_GEST_PREV:
|
||||
/* 歌词页 左→右滑 → 回播放页(含左缘;不接桌面,避免误退)。 */
|
||||
g_np_page = NP_PAGE_PLAY;
|
||||
need_redraw = 1;
|
||||
logmsg("np: -> play page");
|
||||
break;
|
||||
case NP_GEST_TAP:
|
||||
/* 近点按(按页分派):播放页=三钮/进度看点;歌词页预留点跳
|
||||
* (本批不启用,见 batch5/后续:借 meow_lyric_view_hit_line + on_seek)。 */
|
||||
if (g_np_page == NP_PAGE_PLAY) {
|
||||
int cmd = np_btn_tap(tlx, tly);
|
||||
if (cmd) { meow_media_playctl((uint32_t)cmd, 0); need_redraw = 1; }
|
||||
else {
|
||||
int64_t seek = np_progress_seek(tlx, tly);
|
||||
if (seek > 0) meow_media_playctl(5, seek);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break; /* NP_GEST_NONE:反向/纵向主导,忽略不误切 */
|
||||
}
|
||||
if (np_exit) break; /* M6.22:返回手势已命中 → 跳出内层读事件 while */
|
||||
tdx = tdy = -1;
|
||||
} else { tdx = tdy = -1; }
|
||||
}
|
||||
@@ -438,9 +537,18 @@ void run_now_playing(struct app *apps, int napps)
|
||||
need_redraw = 0;
|
||||
last_prog = now;
|
||||
} else if (s && (now - last_prog >= 1000)) {
|
||||
/* 进度推进:仅重绘进度带 + 按钮 */
|
||||
/* 进度推进(按页分流):播放页=进度带+按钮;歌词页=歌词实时滚动重绘(当前行随 pos)。 */
|
||||
last_prog = now;
|
||||
np_repaint_progress();
|
||||
if (g_np_page == NP_PAGE_LYRIC) {
|
||||
np_lyric_refresh(s);
|
||||
if (g_np_lyric) {
|
||||
meow_widget_draw(meow_lyric_view_widget(g_np_lyric));
|
||||
meow_dirty_add(0, SB_BAR_H, fb_xres, fb_yres - SB_BAR_H);
|
||||
meow_ui_flush();
|
||||
}
|
||||
} else {
|
||||
np_repaint_progress();
|
||||
}
|
||||
}
|
||||
/* M6.20:播放页状态栏时钟 1s 刷新(与主界面/子页同语义;draw_clock 喂 SDK 全局
|
||||
* 状态栏 + 标脏顶条,SDK present() 重绘——否则时间冻结在进入播放页那一刻)。 */
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/* np_gesture.h — Now Playing 双页手势方向感知(header-only 纯逻辑,宿主可单测)。
|
||||
*
|
||||
* 定案(用户,批4):Now Playing 同一容器两页——播放页 + 歌词页,手势按当前页方向感知:
|
||||
* - 播放页:右→左滑 → 进歌词页;左缘右滑 → 回桌面(保留 M6.26 语义)。
|
||||
* - 歌词页:左→右滑 → 回播放页(不是回桌面);左缘右滑不接桌面(避免误退)。
|
||||
* 本头为 now_playing.c 与宿主单测(test_now_playing_widgets.c)共用的唯一手势决策,避免两端漂移。
|
||||
*
|
||||
* 依赖:仅 <stdint.h> + meow_notif_panel.h(mnp_top_swipe_down,纯函数)。左缘返回逻辑自
|
||||
* (re)实现(镜像 meow_touch.c meow_edge_back 同口径,宿主编译无需链 meow_touch.c)。
|
||||
*/
|
||||
#ifndef NP_GESTURE_H
|
||||
#define NP_GESTURE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "meow_notif_panel.h" /* mnp_top_swipe_down(顶部下滑→通知中心) */
|
||||
|
||||
/* ---- 页面 ---- */
|
||||
#define NP_PAGE_PLAY 0
|
||||
#define NP_PAGE_LYRIC 1
|
||||
|
||||
/* ---- 手势动作 ---- */
|
||||
typedef enum {
|
||||
NP_GEST_NONE = 0, /* 无(横向反向滑/纵向主导不匹配;调用方忽略,不误切页) */
|
||||
NP_GEST_TOP, /* 顶部热区下滑 → 打开通知中心 */
|
||||
NP_GEST_NEXT, /* 播放页 右→左滑 → 进入歌词页 */
|
||||
NP_GEST_PREV, /* 歌词页 左→右滑 → 回到播放页 */
|
||||
NP_GEST_EXIT, /* 播放页 左缘右滑 → 返回桌面 */
|
||||
NP_GEST_TAP, /* 近点按(按当前页分派:播放页=按钮/进度看点) */
|
||||
} np_gest_t;
|
||||
|
||||
/* ---- 常量(对齐 launcher 同口径;#ifndef 防与 meow_touch.h 等重复定义冲突)---- */
|
||||
#ifndef NP_SWIPE_THRESH
|
||||
#define NP_SWIPE_THRESH 65 /* 顶部下滑触发位移阈值(对齐 launcher MENU_SWIPE_THRESH) */
|
||||
#endif
|
||||
#ifndef NP_PAGE_SWIPE
|
||||
#define NP_PAGE_SWIPE 40 /* 横向切页最小位移(对齐 M6.26 np_anyright 的 dx>=40) */
|
||||
#endif
|
||||
#ifndef NP_TAP_MAX
|
||||
#define NP_TAP_MAX 60 /* 点按位移上限(对齐现有 adx<60 && ady<60) */
|
||||
#endif
|
||||
#ifndef NP_TOP_HOTZONE
|
||||
#define NP_TOP_HOTZONE 28 /* 顶部热区高(= launcher SB_BAR_H;通知中心/播放页同) */
|
||||
#endif
|
||||
#ifndef NP_EDGE_W
|
||||
#define NP_EDGE_W 24 /* 左缘起点宽度(镜像 meow_touch.h MEOW_EDGE_W) */
|
||||
#endif
|
||||
#ifndef NP_EDGE_SWIPE
|
||||
#define NP_EDGE_SWIPE 65 /* 左缘右滑位移阈值(镜像 meow_touch.h MEOW_EDGE_SWIPE) */
|
||||
#endif
|
||||
|
||||
/* 左缘返回(镜像 meow_touch.c meow_edge_back:down_x∈[0,NP_EDGE_W) 且 dx>=NP_EDGE_SWIPE
|
||||
* 且横向主导)。为宿主测试免链 meow_touch.c,此处 static inline 复刻同口径。 */
|
||||
static inline int np_edge_back(int down_x, int dx, int dy)
|
||||
{
|
||||
int ady = dy < 0 ? -dy : dy;
|
||||
if (down_x >= 0 && down_x < NP_EDGE_W && dx >= NP_EDGE_SWIPE && ady < dx)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 按当前页把手势几何 → 动作。down_x/down_y=抬手原点;dx/dy=抬手位移(释放-原点,即 tlx-tdx)。
|
||||
* 优先级:顶部下滑 > 横向主导切页/返回 > 点按。横向反向或无主导 → NONE(调用方忽略,不误切)。 */
|
||||
static inline np_gest_t np_gesture_decide(int page, int down_x, int down_y, int dx, int dy)
|
||||
{
|
||||
int adx = dx < 0 ? -dx : dx, ady = dy < 0 ? -dy : dy;
|
||||
/* 顶部热区下滑 → 通知中心(与主界面同语义;mnp_top_swipe_down 内部排除左缘起点) */
|
||||
if (mnp_top_swipe_down(down_x, down_y, dx, dy, NP_TOP_HOTZONE, NP_SWIPE_THRESH))
|
||||
return NP_GEST_TOP;
|
||||
/* 横向主导(adx>=NP_PAGE_SWIPE 且横向位移>竖向)→ 按当前页分流切页/返回 */
|
||||
if (adx >= NP_PAGE_SWIPE && adx > ady) {
|
||||
if (page == NP_PAGE_PLAY) {
|
||||
if (np_edge_back(down_x, dx, dy)) return NP_GEST_EXIT; /* 左缘右滑 → 回桌面 */
|
||||
if (dx <= -NP_PAGE_SWIPE) return NP_GEST_NEXT; /* 右→左滑 → 进歌词页 */
|
||||
return NP_GEST_NONE; /* 非左缘右滑=播放页无上一页,忽略 */
|
||||
} else { /* NP_PAGE_LYRIC */
|
||||
if (dx >= NP_PAGE_SWIPE) return NP_GEST_PREV; /* 左→右滑 → 回播放页(含左缘,不接桌面) */
|
||||
return NP_GEST_NONE; /* 右→左滑=歌词页是末页,忽略 */
|
||||
}
|
||||
}
|
||||
/* 非横向主导:近点按 */
|
||||
if (adx < NP_TAP_MAX && ady < NP_TAP_MAX) return NP_GEST_TAP;
|
||||
return NP_GEST_NONE;
|
||||
}
|
||||
|
||||
#endif /* NP_GESTURE_H */
|
||||
@@ -16,11 +16,15 @@
|
||||
* ../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 -I../sdk -I. -DMEOW_UI_HOST_TEST -pthread -lm
|
||||
* ../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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -86,6 +90,13 @@ static void mk_widgets(void)
|
||||
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);
|
||||
@@ -168,6 +179,72 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* ============ 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");
|
||||
/* 播放页:非左缘右滑 → 播放页无上一页,忽略(不误切/不误退) */
|
||||
CHECK(np_gesture_decide(NP_PAGE_PLAY, 200, 100, 80, 5) == NP_GEST_NONE,
|
||||
"play: non-edge right-swipe -> none");
|
||||
/* 歌词页:左→右滑 → 回播放页(不是回桌面) */
|
||||
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");
|
||||
|
||||
/* ============ 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);
|
||||
|
||||
Reference in new issue
Block a user