meow_ui.a→3e0ee8f7 launcher→9d0efc2f hello→9609ea6e files→90f5cf07 ncm→be8be221(均已上卡); 真机截图证据 .tmp/meowbug/fix1.png+fix_b2_after.png
176 lines
7.0 KiB
C
176 lines
7.0 KiB
C
/* app.c — files 应用装配层:main + 组装 + 事件分发。
|
||
*
|
||
* 职责(对齐 hello_app/app.c):main 只做初始化/建页/跑事件循环/清理;把 meow_ui_run 的平铺输入
|
||
* 回调(key/tap/swipe/tick/touch)路由到当前活动页(browser/viewer);通用长按走独立注册
|
||
* (meow_ui_set_long_press_cb,§6.3)路由到 browser。页面切换统一走
|
||
* meow_view_page_push/pop(活动栈 + on_enter/on_leave 唯一驱动)。
|
||
*
|
||
* 铁律(APPS.md §3.4.1 / WORK_STATE.md):物理键禁映射——不处理任何 key 语义;返回=左缘左滑
|
||
* (on_swipe LEFT)/返回钮/meow_ui_request_exit。目录进退不换页(browser 改 cur_dir 重扫);
|
||
* 文本预览换页(push ACT_VIEWER)。退出=在根目录左滑或 SIGTERM(看门狗)。
|
||
*/
|
||
#include "files_internal.h"
|
||
#include "meow_notify_ipc.h" /* §6.2 二期:picker 结果经 MSG_PICKER_RESULT 回传 */
|
||
#include "meow_ipc.h"
|
||
|
||
#include <signal.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
static meow_view *g_browser_view;
|
||
static meow_view *g_viewer_view;
|
||
|
||
static void on_sigterm(int s) { (void)s; meow_ui_request_exit(); }
|
||
|
||
/* ============================================================ */
|
||
/* §6.2 二期:picker 模式(launcher 注入 MEOW_PICKER_* → 选文件返回路径) */
|
||
/* ============================================================ */
|
||
static char g_picker_action[24];
|
||
static char g_picker_caller[MEOW_APP_ID_MAX];
|
||
static uint32_t g_picker_req_id;
|
||
static int g_picker_active;
|
||
|
||
int picker_active(void) { return g_picker_active; }
|
||
const char *picker_action(void) { return g_picker_action; }
|
||
uint32_t picker_req_id(void) { return g_picker_req_id; }
|
||
|
||
static void picker_init(void)
|
||
{
|
||
const char *a = getenv("MEOW_PICKER_ACTION");
|
||
if (!a || !a[0]) return;
|
||
snprintf(g_picker_action, sizeof g_picker_action, "%s", a);
|
||
g_picker_active = 1;
|
||
const char *c = getenv("MEOW_PICKER_CALLER");
|
||
if (c) snprintf(g_picker_caller, sizeof g_picker_caller, "%s", c);
|
||
const char *r = getenv("MEOW_PICKER_REQ_ID");
|
||
g_picker_req_id = r ? (uint32_t)atoi(r) : 0;
|
||
meow_log(MEOW_LOG_INFO, "picker: mode action=%s req=%u caller=%s",
|
||
g_picker_action, g_picker_req_id, g_picker_caller);
|
||
}
|
||
|
||
/* 选文件:发 MSG_PICKER_RESULT(OK+路径)+ 请求退出。best-effort(launcher 不在静默)。 */
|
||
void picker_return_file(const char *path)
|
||
{
|
||
m_picker_result_t r;
|
||
memset(&r, 0, sizeof r);
|
||
snprintf(r.caller, sizeof r.caller, "%s", g_picker_caller);
|
||
r.req_id = g_picker_req_id;
|
||
snprintf(r.action, sizeof r.action, "%s", g_picker_action);
|
||
r.code = MEOW_OK;
|
||
if (path) snprintf(r.value, sizeof r.value, "%s", path);
|
||
(void)meow_notify_ipc_send_raw(MSG_PICKER_RESULT, &r, (uint32_t)sizeof r, 1);
|
||
meow_log(MEOW_LOG_INFO, "picker: return path=%s", path ? path : "");
|
||
meow_ui_request_exit();
|
||
}
|
||
|
||
/* 取消:发 MSG_PICKER_RESULT(MEOW_ERR_NOENT+空值)+ 请求退出。 */
|
||
void picker_cancel(void)
|
||
{
|
||
m_picker_result_t r;
|
||
memset(&r, 0, sizeof r);
|
||
snprintf(r.caller, sizeof r.caller, "%s", g_picker_caller);
|
||
r.req_id = g_picker_req_id;
|
||
snprintf(r.action, sizeof r.action, "%s", g_picker_action);
|
||
r.code = MEOW_ERR_NOENT; /* 用户取消 */
|
||
(void)meow_notify_ipc_send_raw(MSG_PICKER_RESULT, &r, (uint32_t)sizeof r, 1);
|
||
meow_log(MEOW_LOG_INFO, "picker: cancel");
|
||
meow_ui_request_exit();
|
||
}
|
||
|
||
/* ============================================================ */
|
||
/* 事件分发:meow_ui_run 平铺回调 → 当前页 */
|
||
/* ============================================================ */
|
||
|
||
/* 物理键系统语义(息屏/音量/媒体)由 SDK 消化;App 不映射(§3.4.1)。 */
|
||
static void app_on_key(int keycode, int is_down)
|
||
{
|
||
(void)keycode; (void)is_down;
|
||
}
|
||
|
||
static void app_on_tap(int x, int y)
|
||
{
|
||
if (viewer_is_active()) { viewer_on_tap(x, y); return; }
|
||
if (browser_is_active()) { browser_on_tap(x, y); return; }
|
||
}
|
||
|
||
static void app_on_swipe(int dir, int dx, int dy)
|
||
{
|
||
(void)dx;
|
||
if (dir == MEOW_SWIPE_LEFT) {
|
||
/* 左缘返回:预览页→回目录;浏览器→上级目录;到根→退出 App(picker 模式则取消)。 */
|
||
if (viewer_is_active()) { meow_view_page_pop(); return; }
|
||
if (browser_is_active() && browser_go_up()) return;
|
||
if (picker_active()) { picker_cancel(); return; } /* §6.2 二期:根屏左滑=取消 picker */
|
||
meow_log(MEOW_LOG_INFO, "exit:swipe");
|
||
meow_ui_request_exit();
|
||
return;
|
||
}
|
||
if (viewer_is_active()) { viewer_swipe(dir, dy); return; }
|
||
if (browser_is_active()) { browser_swipe(dir, dy); return; }
|
||
}
|
||
|
||
/* 左缘返回手势过程视觉条(SDK 自动画顶部进度条,App 转发)。 */
|
||
static void app_on_swipe_progress(int x_start, int dx)
|
||
{
|
||
meow_ui_swipe_hint(x_start + dx);
|
||
}
|
||
|
||
/* 拖拽过程(跟手):列表/文本内容滚动。 */
|
||
static void app_on_touch_down(int x, int y)
|
||
{
|
||
if (viewer_is_active()) viewer_touch_down(x, y);
|
||
else if (browser_is_active()) browser_touch_down(x, y);
|
||
}
|
||
static void app_on_touch_move(int x, int y)
|
||
{
|
||
if (viewer_is_active()) viewer_touch_move(x, y);
|
||
else if (browser_is_active()) browser_touch_move(x, y);
|
||
}
|
||
|
||
/* 通用长按(§6.3):SDK 判定「按下 ≥ 阈值未抬手且位移 ≤ 容忍」后带坐标回调;
|
||
* browser 据此行命中打开 BottomSheet。viewer 无长按语义。 */
|
||
static void app_on_long_press(int x, int y)
|
||
{
|
||
if (browser_is_active()) browser_on_long_press(x, y);
|
||
}
|
||
|
||
/* on_tick:本 App 无帧动画/时钟(长按计时已下沉 SDK §6.3),保留为空槽。 */
|
||
static void app_on_tick(void) { }
|
||
|
||
/* ============================================================ */
|
||
/* main */
|
||
/* ============================================================ */
|
||
int main(void)
|
||
{
|
||
meow_log(MEOW_LOG_INFO, "start");
|
||
meow_ui_opts o = { APP_W, APP_H };
|
||
if (meow_ui_init(&o) != 0) { meow_log(MEOW_LOG_ERROR, "init failed"); return 1; }
|
||
meow_theme_add_listener(NULL);
|
||
|
||
signal(SIGTERM, on_sigterm);
|
||
picker_init(); /* §6.2 二期:读 MEOW_PICKER_* 决定是否进入 picker 模式 */
|
||
|
||
/* 建两页 view(on_create 建各自控件/状态 + 读卡扫首个目录) */
|
||
g_browser_view = browser_view_create();
|
||
g_viewer_view = viewer_view_create();
|
||
|
||
/* 进入根页(ACT_BROWSER = 目录浏览;默认卡根 /usr/data/mnt/sd_0) */
|
||
meow_view_page_push(ACT_BROWSER);
|
||
|
||
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,
|
||
};
|
||
/* 通用长按走独立注册(§6.3):不进 meow_ui_events(避免位置初始化在 -Wextra 下告警)。 */
|
||
meow_ui_set_long_press_cb(app_on_long_press);
|
||
meow_ui_run(&ev);
|
||
|
||
/* 清理:meow_view_free 触发各页 on_destroy(控件 + 文本缓冲) */
|
||
meow_view_free(g_viewer_view);
|
||
meow_view_free(g_browser_view);
|
||
meow_ui_shutdown();
|
||
meow_log(MEOW_LOG_INFO, "exit");
|
||
return 0;
|
||
}
|