Files
MeowOS-SDK/tuku/app.c
T
AskaEth 64336f95d9 图库: 书库改文件管理器模型 + 关闭缩略图 + 根锁定/无卡容错(M18)
用户反馈四件事一起改:
- 「目录里有一张图就被当成最终目录」→ 取消「目录含图=一本书」全部链路
  (探测/页数/封面/续读角标/懒算 worker/sr2 补位),列表 = 目录 + 图片 +
  .cbz/.zip(目录优先、组内自然序)。点目录=进入(空目录也进),点图片=
  mr_reader_open_dir_at(当前目录, 图片自然序下标),点档案册=打开档案册。
- 「文件夹浏览特别卡」→ 删除缩略图线程/磁盘 bmp 缓存/LRU/解码路径与行内
  缩略图;首帧只做一次 opendir/readdir+lstat,副标题(类型·大小)扫描期
  生成一次,行合成/滚动/点击零 IO 零格式化;去掉逐行 snap(自由滚动手感)。
  2000 项目录扫描 ~2.8ms(opendir=1, lstat=2000),行合成 2.78ms/200 万次
  (宿主实测;旧实现 2000 项 entry 含 512B cover,内存 2.7MB→1.7MB)。
- 「不要访问 SD 卡上级目录」→ 浏览根锁定 MR_ROOT_DIR:删除越根的顶栏
  「上级」/library_go_parent,根隐藏顶栏返回,左缘返回到根=退出 App。
- 「没有 SD 卡不要报错」→ 根不可访问(未插卡/挂载失败/根是文件)时友好空态
  「未检测到 SD 卡」+ 顶栏刷新/重进页面重试;子目录不可读才弹提示横幅。

集成陷阱:书库图片下标与阅读器目录册共享同一套过滤器(隐藏项/图片扩展名/
普通文件/符号链接)与 mr_natural_cmp,test_browse_lazy 直接对比
mr_dir_book_init 顺序,test_open_book_host 断言「点 img10 就开 img10」。

reader 侧 M17 遗留:mr_reader_open_dir_at 在阅读页已激活时先 pop 再 push,
走完整 leave/enter(SDK 对同 view 重复 push 是 no-op 且会压重复 activity)。

回归:run_tests.sh / run_webtoon_tests.sh 全 PASS;交叉构建零警告。
2026-11-05 20:26:40 +08:00

144 lines
4.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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);
}
static void app_on_tick(void)
{
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);
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;
}