Files
MeowOS-For-R3P2/patch_v2/files_app/files_internal.h
T
AskaEth e69b8efeeb fix(files): 目录列表行高按字体行高派生 — 20px 字库下首行标题不再空白(M17)
根因(承接 M12/M15 finding):SDK meow_listview 双行 renderer 把
block = 2*meow_ui_text_height(font_body) + MEOW_LISTV_SUB_GAP(2) 在行内垂直居中
(ty = 行顶 + (item - block)/2),标题只在 ty >= 视口顶时才画。目录行是双行档位,
真机 source_han_serif 20px(ascent 24 + descent 6)行高 30 → block 62,而
browser_page_create 显式 set_item_h(56) → ty = 行顶 - 3:首行(行顶 == 视口顶)
标题被裁剪守卫整条跳过,只剩大小/时间副标题。

修复:
- files_internal.h:APP_ROW_H 降级为行高下限(56);新增 FILES_ROW_SUB_GAP(2,与
  SDK MEOW_LISTV_SUB_GAP 同口径) + files_row_h_for_line_h(line_h)
  = max(56, 2*line_h + 2) + files_row_h()(取当前主题 meow_theme_get()->font_body
  的 meow_ui_text_height)。本地派生,不依赖 M15 新增导出 meow_listview_item_h;
  显式传值在 M15 之前的 SDK(默认 56)与 M15 之后(默认已派生 62)都成立且一致。
- ui/browser.c:browser_page_create 的 set_item_h 改传 files_row_h()
  (行高 30 → 62)。SDK 的 draw/hit/max_scroll 全部按这一个值换算,滚动/命中天然
  同步;页脚几何(r_list 单独扣 APP_FOOTER_H)与行高无关。其它几何/交互不变。

验证(宿主,未碰真机):
- zig-mipsel-cc -Os -static -Wall -Wextra(另用 -Werror 复验)交叉编译 files:0 warning;
- 新宿主 test/test_row_text_fit.c(32 断言,纯头文件派生、不链 SDK):
  字库行高矩阵 14/21/26/27/30 下 block <= item、首行 ty >= 0;行高 30 → 62;
  旧 56 → ty=-3 的 bug 形态哨兵;全 PASS。

影响:meow_ui.a 未改 → 无需重编 SDK;本 App 需重链重部署(热更 files 二进制)。
2026-11-05 20:57:13 +08:00

110 lines
6.0 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.
/* files_internal.h — files 应用内部共享头(UI 各页 + app 装配层 + 宿主测试面)。
*
* 层级(对齐 hello_app 的批次②拆分规范):
* - ui/browser.c 目录浏览页(ACT_BROWSER,根页):列表虚拟化渲染 + 进/退目录 + 行操作
* - ui/viewer.c 文本预览页(ACT_VIEWER,子页):只读、可滚动、≤256KB 截断
* - ui/common/chrome.c 共享 chrome(TopAppBar 建置 / 内容区几何 / 空态/页脚绘制)
* - logic/fsx.* 纯业务(路径安全/格式化/枚举/写操作),不依赖 meow_ui
* - app.c main + 装配 + 事件分发(把 meow_ui_run 的平铺回调路由到各页)
*
* 页面生命周期用 meow_view_page_push/pop 驱动 on_enter/on_leave;目录进退不换页(留在 browser
* 页改 cur_dir 重扫)。物理键不映射(§3.4.1):本 App 不做任何 on_key 映射,返回=左缘手势/返回钮/
* request_exit。
*/
#ifndef FILES_INTERNAL_H
#define FILES_INTERNAL_H
#include <stdint.h>
#include "meow_ui.h"
#include "meow_ui_view.h"
#include "logic/fsx.h"
/* ---- Activity 归属(§6.1 ①)---- */
#define ACT_BROWSER 0
#define ACT_VIEWER 1
/* ---- picker 模式(AMSD_DESIGN §6.2 二期)----
* launcher 注入 MEOW_PICKER_ACTION/REQ_ID/CALLER(amsd `am picker` 路由到本 App)。
* 非空 ACTION → 本 App 进入「选文件」picker 模式:浏览目录、点文件=返回路径(经
* MSG_PICKER_RESULT 发回 launcher→amsd)+ 退出;返回/左滑退出=取消。 */
int picker_active(void); /* 1=进入 picker 模式(MEOW_PICKER_ACTION 非空) */
const char *picker_action(void);
uint32_t picker_req_id(void);
void picker_return_file(const char *path); /* 选文件:发 MSG_PICKER_RESULT + 请求退出 */
void picker_cancel(void); /* 取消:发 code=MEOW_ERR_NOENT + 请求退出 */
/* ---- 布局 ---- */
#define APP_W 480
#define APP_H 720
#define APP_TOPBAR_H 56
#define APP_ROW_H 56 /* 列表行高下限(旧固定值;实际按字体行高派生,见 files_row_h) */
#define APP_PAD 16
#define APP_ICON_W 26 /* 图标占宽 */
#define APP_OP_W 52 /* 右侧操作钮占宽(触达区) */
#define APP_FOOTER_H 26 /* 底部信息行高(列表/文本内容在其之上滚动) */
#define APP_READ_MAX (256 * 1024) /* 文本预览读取上限 */
/* ---- 列表行高:按字体行高派生(M17,首行标题不显示根因修复)----
* SDK meow_listview 的双行渲染把「标题+副标题」文本块
* block = 2 * meow_ui_text_height(font_body) + MEOW_LISTV_SUB_GAP(2)
* 在行内垂直居中(ty = 行顶 + (item - block) / 2),标题只在 ty >= 视口顶时才画。
* item < block 时 ty = 行顶 - Δ:第一行(行顶 == 视口顶)标题被整条跳过、只剩副标题。
* 真机 source_han_serif 20px(ascent 24 + descent 6)行高 30 → block 62,旧的显式 56 → Δ=3。
* 故行高按当前主题正文行高派生:max(APP_ROW_H, 2*line_h + 2)(行高 30 → 62)。
* 本页行恒为双行档位(browser_src2 填 title + subtitle)→ 用 lines=2 公式。
* 行几何(draw / hit / max_scroll)全由 SDK 按传入的这一个值换算,故滚动与命中天然同步;
* 页脚几何与行高无关(r_list 单独扣 APP_FOOTER_H)。 */
#define FILES_ROW_SUB_GAP 2 /* 与 SDK MEOW_LISTV_SUB_GAP 同口径(标题/副标题行距) */
static inline int files_row_h_for_line_h(int line_h)
{
if (line_h < 1) line_h = 1; /* 字体未就绪 → 退回下限 */
int h = 2 * line_h + FILES_ROW_SUB_GAP;
return (h > APP_ROW_H) ? h : APP_ROW_H;
}
/* 当前主题正文行高下的两行列表行高(页面 create 时取一次;字体档位切换走页面重建)。 */
static inline int files_row_h(void)
{
const meow_theme *th = meow_theme_get();
return files_row_h_for_line_h(th ? meow_ui_text_height(th->font_body) : 0);
}
/* ---- App 级复用矩形/几何 ---- */
typedef struct { int x, y, w, h; } app_rect_t;
#define AR(x,y,w,h) ((app_rect_t){ (x),(y),(w),(h) })
/* ---- chrome(ui/common/chrome.c)---- */
int app_statusbar(void); /* 状态栏高度 inset(0=无) */
app_rect_t app_topbar_rect(void); /* 顶部栏几何(含状态栏偏移) */
app_rect_t app_content_rect(void); /* topbar 之下 → 屏底(列表/文本内容区) */
/* 建 topbar(owner=当前活动:调用方须在正确 activity 下建);返回 widget 供命中/置顶。 */
meow_widget *app_topbar_create(const char *title, int back, const char *action_label);
void app_draw_empty(app_rect_t r, const char *kind, const char *what); /* 空态/错误居中 */
void app_draw_footer(app_rect_t r, const char *text); /* 底部信息(项数/路径) */
/* ---- browser 页(ui/browser.c)---- */
meow_view *browser_view_create(void);
int browser_is_active(void);
int browser_on_tap(int x, int y); /* 1=已消费 */
void browser_swipe(int dir, int dist);
void browser_touch_down(int x, int y);
void browser_touch_move(int x, int y);
void browser_on_long_press(int x, int y); /* SDK 通用长按(§6.3)→ 行 BottomSheet */
int browser_go_up(void); /* 1=回到上级;0=已在根(未动作) */
int browser_at_root(void);
void browser_reload(void);
const char *browser_current_dir(void);
int browser_entry_count(void); /* 宿主测试:当前目录项数 */
/* ---- viewer 页(ui/viewer.c)---- */
meow_view *viewer_view_create(void);
int viewer_is_active(void);
int viewer_open_file(const char *path); /* 读文件+进预览页;0=成功 */
void viewer_swipe(int dir, int dist);
void viewer_touch_down(int x, int y);
void viewer_touch_move(int x, int y);
int viewer_on_tap(int x, int y);
void viewer_load(const char *path); /* 宿主测试:读入 buffer 并解析行 */
#endif /* FILES_INTERNAL_H */