M29 评审 P2-1:SDK 长按是 opt-in,全仓没有运行时调用 meow_ui_set_long_press_cb,meow_input_long_press_poll 恒返回 0,真机上 MEOW_EV_LONG_PRESS 永不产生——「长按退格清空」只表现为删一位。 - app.c 注册 no-op 长按回调,但只在 ACT_LOCK 为顶层页时启用(进主循环前对齐 一次 + on_tick 每拍对齐),解锁 pop 后置 NULL。全程开启会让长按触发后的 抬手不再产生 TAP/SWIPE,吞掉书库/阅读器里「按住 >=500ms」的点击。 - test_settings_lock_host:长按用例改走真实 SDK 路径——未注册 poll==0(P2 根因)、注册后按住 700ms 产出 LONG_PRESS 且坐标=退格键心、被锁屏 view 消费、 抬手不补发 TAP、解锁后关掉再 poll==0。 - lock.c 头注释补上该 opt-in 依赖,避免以后只看锁屏页时误判可达。
169 lines
5.8 KiB
C
169 lines
5.8 KiB
C
/* app.c — 图库装配层:main + 建页 + meow_ui_run 回调路由 + 主题监听。
|
||
*
|
||
* 契约(docs/APP_DEV_GUIDE.md §2-§3):
|
||
* - main 只做 meow_ui_init → 建 view → meow_ui_run → 清理;退出走 meow_ui_request_exit;
|
||
* - 页面切换统一走 meow_view_page_push/pop(activity 栈 + on_enter/on_leave 唯一入口);
|
||
* - 物理键不映射返回/确认(on_key 仅日志);屏底上滑由 SDK 系统手势接管,App 不拦截;
|
||
* - 左缘返回:reader/settings=pop;lock 页自行消费;书库逐级上移,
|
||
* **到 TF 卡根=退出 App**(浏览根锁定,不再上溯系统目录;顶栏也没有越根的「上级」)。
|
||
*
|
||
* 主题同步:注册 meow_theme_add_listener;明暗/风格族切换时更新页面底色并整帧 invalidate,
|
||
* 各页 on_draw / SDK 控件下一帧即用新语义色重绘(不缓存颜色)。
|
||
*/
|
||
#include "tuku_internal.h"
|
||
#include "ui/reader/reader.h"
|
||
#include "meow_ui_nav.h"
|
||
|
||
#include <signal.h>
|
||
|
||
static void on_sigterm(int s)
|
||
{
|
||
(void)s;
|
||
meow_ui_request_exit();
|
||
}
|
||
|
||
/* 向 launcher 上报当前页栈深/顶层,供系统导航栈跟随。各页 on_enter 调用。 */
|
||
void mr_nav_report(void)
|
||
{
|
||
int depth = meow_ui_activity_depth();
|
||
if (depth <= 0) depth = 1;
|
||
int id = meow_ui_activity_active();
|
||
const char *top = (id == ACT_READER) ? "reader"
|
||
: (id == ACT_SETTINGS) ? "settings"
|
||
: (id == ACT_LOCK) ? "lock"
|
||
: "library";
|
||
meow_ui_nav_report((uint32_t)depth, top);
|
||
}
|
||
|
||
/* 主题切换:页面底色 + 整帧重绘(控件与 on_draw 全部从 meow_theme_get() 取色)。 */
|
||
static void app_theme_changed(meow_theme_mode m)
|
||
{
|
||
(void)m;
|
||
meow_ui_set_page_bg(meow_theme_get()->bg);
|
||
meow_ui_invalidate(0, 0, meow_ui_width(), meow_ui_height());
|
||
}
|
||
|
||
static int app_active(void)
|
||
{
|
||
return meow_ui_activity_active();
|
||
}
|
||
|
||
static void app_on_key(int keycode, int is_down)
|
||
{
|
||
(void)keycode; (void)is_down; /* 物理键是系统语义,不做返回/确认映射 */
|
||
meow_log(MEOW_LOG_DEBUG, "key");
|
||
}
|
||
|
||
static void app_on_tap(int x, int y)
|
||
{
|
||
switch (app_active()) {
|
||
case ACT_LIBRARY: library_on_tap(x, y); break;
|
||
case ACT_READER: reader_on_tap(x, y); break;
|
||
default: break;
|
||
}
|
||
}
|
||
|
||
static void app_on_swipe(int dir, int dx, int dy)
|
||
{
|
||
(void)dy;
|
||
if (dir == MEOW_SWIPE_LEFT) {
|
||
if (app_active() == ACT_LIBRARY) {
|
||
if (!library_go_up()) {
|
||
meow_log(MEOW_LOG_INFO, "exit:swipe");
|
||
meow_ui_request_exit();
|
||
}
|
||
} else {
|
||
meow_view_page_pop();
|
||
}
|
||
return;
|
||
}
|
||
/* SDK 的 on_swipe 把位移量放在第二参(第三参为 0):UP/DOWN 时 dx=纵向位移。 */
|
||
if (app_active() == ACT_LIBRARY) library_on_swipe(dir, dx);
|
||
}
|
||
|
||
/* 通用长按(SDK §6.3)是 opt-in:未注册回调时 meow_input_long_press_poll 直接返回 0,
|
||
* MEOW_EV_LONG_PRESS 永远不会产生 —— 锁屏的「长按退格清空」在真机上就退化成单删一位。
|
||
* 这里注册一个 no-op 回调把长按打开;事件仍然先经 meow_view_dispatch_event 路由,锁屏页
|
||
* 自己消费 LONG_PRESS(其它页命中不到就走 no-op)。
|
||
*
|
||
* 只在锁屏为顶层页时启用:长按一旦触发,其抬手不再产生 TAP/SWIPE(SDK 抑制点击),
|
||
* 全程开启会让书库/阅读器里「按住稍久」的点击被吞掉。锁屏页解锁 pop 后由 app_on_tick
|
||
* 下一拍关掉,避免把长按语义泄漏到其它页。 */
|
||
static int g_long_press_on;
|
||
|
||
static void app_on_long_press(int x, int y)
|
||
{
|
||
(void)x; (void)y; /* 锁屏已在 view 分发里消费;其余页没有长按语义 */
|
||
}
|
||
|
||
static void app_sync_long_press(void)
|
||
{
|
||
int on = (app_active() == ACT_LOCK);
|
||
if (on == g_long_press_on) return;
|
||
meow_ui_set_long_press_cb(on ? app_on_long_press : NULL);
|
||
g_long_press_on = on;
|
||
}
|
||
|
||
static void app_on_tick(void)
|
||
{
|
||
app_sync_long_press();
|
||
library_on_tick();
|
||
}
|
||
|
||
static void app_on_swipe_progress(int x_start, int dx)
|
||
{
|
||
meow_ui_swipe_hint(x_start + dx);
|
||
}
|
||
|
||
/* 跟手拖动路由(M6):ACT_READER 需要原始 down/move 算位移;其余页保持原语义。
|
||
* 屏底热区/左缘的避让由 reader 侧按同一口径判断(reader_on_touch_down)。 */
|
||
static void app_on_touch_down(int x, int y)
|
||
{
|
||
if (app_active() == ACT_LIBRARY) library_on_touch_down(x, y);
|
||
else if (app_active() == ACT_READER) reader_on_touch_down(x, y);
|
||
}
|
||
|
||
static void app_on_touch_move(int x, int y)
|
||
{
|
||
if (app_active() == ACT_LIBRARY) library_on_touch_move(x, y);
|
||
else if (app_active() == ACT_READER) reader_on_touch_move(x, y);
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
meow_log(MEOW_LOG_INFO, "start");
|
||
meow_ui_opts o = { 480, 720 };
|
||
if (meow_ui_init(&o) != 0) {
|
||
meow_log(MEOW_LOG_ERROR, "init failed");
|
||
return 1;
|
||
}
|
||
|
||
meow_theme_add_listener(app_theme_changed);
|
||
meow_ui_set_page_bg(meow_theme_get()->bg);
|
||
meow_ui_nav_init();
|
||
signal(SIGTERM, on_sigterm);
|
||
|
||
/* 先建全部页面(on_create 建各自控件/扫描书库),再按启动锁状态进根页。 */
|
||
meow_view *library = library_view_create();
|
||
meow_view *reader = reader_view_create();
|
||
meow_view *settings = settings_view_create();
|
||
meow_view *lock = lock_view_create();
|
||
|
||
meow_view_page_push(lock_view_should_show() ? ACT_LOCK : ACT_LIBRARY);
|
||
app_sync_long_press(); /* 进主循环前先对齐一次:启动即锁屏时首帧长按就可用 */
|
||
|
||
meow_ui_events ev = {
|
||
app_on_key, app_on_tap, app_on_swipe, app_on_tick,
|
||
app_on_swipe_progress, app_on_touch_down, app_on_touch_move,
|
||
};
|
||
meow_ui_run(&ev);
|
||
|
||
meow_view_free(lock);
|
||
meow_view_free(settings);
|
||
meow_view_free(reader);
|
||
meow_view_free(library);
|
||
meow_ui_shutdown();
|
||
meow_log(MEOW_LOG_INFO, "exit");
|
||
return 0;
|
||
}
|