/* 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 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; }