用户反馈四件事一起改: - 「目录里有一张图就被当成最终目录」→ 取消「目录含图=一本书」全部链路 (探测/页数/封面/续读角标/懒算 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;交叉构建零警告。
144 lines
4.6 KiB
C
144 lines
4.6 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);
|
||
}
|
||
|
||
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;
|
||
}
|