Files
laoyang d6bda758d8 v0.3.0 沉浸式按 SyncCalendar 重做(通知栏与页面完全同色)+ 个人信息卡改白块
## ① 沉浸式:改用本机 SyncCalendar 的方案(用户指定参考)

用户原话:「上面那一块的颜色和通知栏的颜色完全融为一体;
紧接着就是应用图标和标题,尽量靠上」。

三件套(缺一不可):
1. 系统栏涂**全透明** `#00000000`;
2. `setWindowBackgroundColor(页面底色)` 供透明系统栏透出;
3. **紧邻系统栏的元素不设自己的背景色** + 根容器 `expandSafeArea`。

🔴 第三件是最关键、也是我先前漏掉的一环:
我原来给顶栏设了白色 `backgroundColor`,于是状态栏(透出纸色)与顶栏(白)
仍上下拼接。读 SyncCalendar 源码发现它的 `header()` **根本没有 backgroundColor**
—— 这才是"融为一体"的真正机制。已在代码里写明原因,防止回退。

配套简化:删掉自己算安全区的那套(`statusBarH`/`bottomBarH`/
`loadWindowInsets`/`applyAvoidAreas`,共约 110 行)—— 不再手算,也就不会算错。

## ② 顶栏改「图标 + 标题」

按用户要求:应用图标 + 「家书」标题(下行小字显示当前模块)贴左上,
右侧铃铛与头像。顶栏高度 56 → 48vp,上下内边距压到 4,内容整体上移。

## ③ 个人信息卡恢复为白色卡片

用户明确要求("还是得用一个白色的块,这样显得好看")。
曾一度做成"不套卡片的头部"(理由是省首屏高度),现按用户观感改回白卡。
⚠️ 与顶栏的区别:顶栏**不能**有背景色(否则与状态栏割裂),
而这张卡在顶栏下方、与状态栏不相邻,套白卡没有这个问题。

## 验证(全部基于真机)

逐行像素采样(`_tooling/familybook_immersion_check.py`,
模型读不了图 ⇒ 用数字裁定,不靠目测):
· `y=0..271` 全为 `#F7F3EA` ⇒ **状态栏与顶栏同色,融为一体** ✓
· 底部 `y=2224..2444` 为纸色,无异常条 ✓

真机界面遍历(`_tooling/familybook_harmonyos_probe.py`):
· A 组抽屉 11 个模块 **11/11**
· B 组家谱 **1/1**;C 组通知/设置 **2/2**
· D 组深验(特征文本)**12/12**
合计 **14 个页面全通过**。

⚠️ 顺带修掉探针自身两个坑(都记进注释了):
· `nodes_of` 原来只收集**有文字**的节点 ⇒ 找不到纯图标的汉堡按钮,
  导致"抽屉打不开"、10 个模块连锁失败(看着像应用坏了,其实是探针瞎了);
· 汉堡按钮坐标写死 ⇒ 顶栏变矮后点空。改为在界面树里动态探测、
  并**排除系统状态栏区域**(那里也有可点击元素,曾误取到 (103,56))。

## 编译
0 error(保留 1 条 `setWindowBackgroundColor` 的 unavailable 告警,它是透明方案的必需组成)
2026-10-12 08:43:32 +08:00

188 lines
9.5 KiB
Markdown
Raw Permalink 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.
# FamilyBook_harmonyos · 家书鸿蒙客户端
**家书**([FamilyBook](https://code.yangyq.net/laoyang/FamilyBook))的 HarmonyOS 客户端。
服务端是那套「自托管的家庭生活系统」,这个仓库是它的手机 / 平板端。
> 把一个家的「人」「日子」「去过的地方、看过的电影」收进同一本书里。
---
## 当前状态
**界面框架阶段(v0.1.0)** —— 骨架与全部模块页面已就位,**数据全部是演示数据**。
服务端还没有客户端用的接口,所以这一轮只做「长什么样」,不做任何读写。
| 已完成 | 说明 |
| --- | --- |
| 工程骨架 | Stage 模型 + ArkTS / ArkUI,targetSdk 26.0.0 / compatibleSdk 6.1.1(24) |
| 沉浸式 | 照本机 SyncCalendar 的方案:系统栏全透明 + 根容器 `expandSafeArea`,通知栏与页面**完全同色** |
| 左侧抽屉 | 宽屏常驻侧栏 / 窄屏滑出层,两套形态同一组件 |
| 12 个模块页面 | 首页、名册、观影、旅程、日程、资源、任务、纪念日、财务、读书、笔记(+ 家谱) |
| 附加页面 | 通知消息、个人设置 |
| 主题体系 | 宣纸米 / 砖红配色,深浅色两套资源,深浅自动跟随系统 |
| 模块主题色 | 与 Web 端 `Module::PRESET_COLORS` 同一套 12 色预设 |
| 编译验证 | `hvigorw assembleHap` **0 error / 0 warning** |
| 真机验证 | 装机成功;15 个页面逐个点开、断言渲染内容,**15/15 通过** |
| 待办(下一轮) | 说明 |
| --- | --- |
| 接口对接 | 服务端需要提供客户端用的 JSON 接口(登录、各模块列表与详情) |
| 登录态 | 会话持久化、令牌刷新、启动时的登录门禁 |
| 交互实现 | 新建 / 编辑 / 删除、搜索、筛选、拖拽排序 |
| 日程周/天视图 | 按半小时定位的时间轴 + 手势(本轮只做了月视图) |
| 附件能力 | 上传、图片/视频预览、裁剪 |
| 财务折线图 | 净资产与各账目的盘点变化曲线 |
---
## 与 Web 端的取舍
数据看 Web 端,**排版按手机重做** —— 不照搬电脑端版面。
### 模块
**不做「导航」模块**(Web 端有)。用户原话:「导航是专门为电脑端开发的,都是网站,
主要用在浏览器的主页,所以不需要」。手机上每个网站都有 App,收藏夹没有使用场景。
⇒ 本工程的模块清单与 Web 端 `Module::LIST` **有意不等**,别"顺手补回去"。
**「家谱」不在抽屉里**(与 Web 端一致):它默认不上导航条(用户说过
「不需要每天都查看家谱」),走「名册 → 家谱」的分段切换进入。
### 版面
| 模块 | Web 端 | 鸿蒙端 | 为什么 |
| --- | --- | --- | --- |
| 首页 | hero 招牌 + 信息面板 + 日程/任务并排 + 我的家人 + 未来七天 + 模块卡 | 去掉 hero;信息面板作**无卡片的页面头部**;其余保持顺序上下堆叠 | hero 只重复信息面板已有的信息(家庭名 × 问候),手机首屏高度宝贵 |
| 观影 | 瀑布流海报墙 | 两列定尺寸网格 | 瀑布流列宽随图高浮动,手机上很难扫 |
| 任务 | 多列看板(拖动改状态) | 按状态分组的三段列表 | 手机宽度放不下多列;用户关心的是"做到哪一步" |
| 笔记 | 定尺寸卡片网格 | 两列定高卡片网格 | 与 Web 端一致(用户要求过"块大小要确定") |
| 家谱 | HTML 折线树 | 「以我为中心的圈层」(直系 / 其他亲属) | 折线树在窄屏排不下 |
| 财务 | 概览 + 折线图 + 账目表 | 概览(图占位)+ 按类别分组的账目 | 折线图需要图表能力,留到第二轮 |
---
## 目录结构
```
entry/src/main/ets/
entryability/EntryAbility.ets 应用入口:主题跟随、系统栏配色
entrybackupability/ 备份扩展
common/
Theme.ets 设计令牌(颜色 / 间距 / 字号)+ 模块调色板
Store.ets 全局状态(V2:@ObservedV2 + @Trace)
model/
Modules.ets 模块注册中心(对应 Web 端 App\Module)
Types.ets 全部数据类型(对应各模板渲染的字段)
DemoData.ets 演示数据(接上接口后可整个删除)
components/
Widgets.ets 共享展示件(头像 / 标签 / 空态 / 圆点…)
Drawer.ets 左侧抽屉 + 骨架(并排 / 浮层两形态)
TopBar.ets 顶栏
pages/
Index.ets 主界面:模块分发
home/ movies/ trips/ calendar/ tasks/ people/
resources/ days/ ledger/ books/ misc/ settings/
```
---
## 设计说明
### 沉浸式(三件套,缺一不可)
参考本机另一个应用 **SyncCalendar**(用户指定)的做法:
1. **系统栏涂成全透明** —— `statusBarColor: '#00000000'`、`navigationBarColor: '#00000000'`;
2. **窗口底色 = 页面底色** —— `win.setWindowBackgroundColor(pageBg)`,供透明系统栏透出;
3. **紧邻系统栏的元素不设自己的背景色** —— 顶栏**不能**有 `backgroundColor`,
让它透出根容器底色;根容器再 `expandSafeArea([SYSTEM], [TOP, BOTTOM])`
把背景铺到状态栏区域。
原理:透明系统栏透出的是**窗口底色**,而顶栏也透出**同一个**底色 ⇒ 天然同色、
「通知栏与上方完全融为一体」。内容仍在安全区内,**不需要手算状态栏高度**。
⚠️ 常见的两个坑(都踩过):
- 调 `setWindowLayoutFullScreen(true)` 后子组件会钻到状态栏底下,页面得自己让位,
极易算错(曾出现顶部重复避让 156px);
- 给状态栏或顶栏**写死颜色**必然与相邻层割裂(曾出现「米色状态栏 + 白色顶栏」的拼接感)。
验证方式:**逐行像素采样**(`_tooling/familybook_immersion_check.py`)。
判据是「状态栏区颜色 == 顶栏区颜色」,用数字裁定而不是目测 ——
最终实测 `y=0..271` 全为 `#F7F3EA`(纸色),达标。
Web 端顶栏是一排横向模块入口,最多放 12 个模块 —— 手机宽度下必然溢出。
改成左侧抽屉后,竖向排列不受数量限制,还能顺带放下「模块说明 + 主题色」
这层信息,一眼看清每个模块是干什么的。
抽屉有**两套形态**,由窗口短边决定(≥ 600vp 为宽屏):
- **宽屏**(平板 / 折叠屏展开 / 横屏手机):抽屉常驻,与内容并排;
- **窄屏**:内容铺满,抽屉从左侧滑出,点遮罩或选中模块即收起。
判据用「短边」而不是「宽度」—— 短边在旋转时不变,所以比例接近 1:1 的设备
横竖屏布局保持一致。
### 为什么是抽屉
Web 端顶栏是一排横向模块入口,最多放 12 个模块 —— 手机宽度下必然溢出。
改成左侧抽屉后,竖向排列不受数量限制,还能顺带放下「模块说明 + 主题色」
这层信息,一眼看清每个模块是干什么的。
抽屉有**两套形态**,由窗口短边决定(≥ 600vp 为宽屏):
- **宽屏**(平板 / 折叠屏展开 / 横屏手机):抽屉常驻,与内容并排;
- **窄屏**:内容铺满,抽屉从左侧滑出,点遮罩或选中模块即收起。
判据用「短边」而不是「宽度」—— 短边在旋转时不变,所以比例接近 1:1 的设备
横竖屏布局保持一致。
### 模块注册中心
模块清单只有**一个来源**:`model/Modules.ets` 的 `FB_MODULES`,
与 Web 端 `app/Module.php` 的 `Module::LIST` 一一对应(key 必须等于路由名)。
加一个模块只改那一处 —— 抽屉、设置页的显隐开关、主题色选择全部自动出现。
这是 Web 端踩过的坑(漏改一处就「有页面但导航里找不到入口」),端上照搬这套结构。
### 主题色
每个模块一个主题色,三档(按钮底 / hover / 文字色)由主色按 HSL 压明度算出来,
保证三档永远同色系。算法与 Web 端 `Module::cssVars()` 共用同一套公式。
预设色板 `FB_PRESET_COLORS` 也与 Web 端 `Module::PRESET_COLORS` **逐值一致** ——
否则同一个人在手机和电脑上选出的「观影紫」会是两种紫。
### 编译期约束(踩过的坑)
| 坑 | 处理 |
| --- | --- |
| `Circle().fill()` 是 API 26 才有的重载 | compatibleSdk 是 24,改用「方块 + 圆角」画圆(`components/Widgets.ets::FbDot`),零版本风险 |
| `setWindowBackgroundColor` 对 phone/tablet 不可用 | 去掉,页面自身已用同色铺满整屏 |
| `window.getLastWindow()` 只有异步版 | 由 `EntryAbility` 用 `getMainWindowSync()` 取一次存进 AppStorage,页面侧同步读 |
| 跨文件顶层名冲突(`arkts-no-decl-merging`) | 所有导出名统一加 `Fb` 前缀 |
| `Button('label') { ... }` 报 10905202 | 一律用 `Button() { Row() { ... } }` |
| `@Param` 类型写成 `string` 导致传 `Resource` 报错 | 颜色类入参统一声明 `ResourceColor` |
| 嵌套目录下 import 相对路径层级 | 页面在 `pages/<模块>/`,公共件在 `components/`、`model/`,相对路径要多退一级 |
---
## 构建
需要 HarmonyOS SDK(DevEco Studio 自带)。本机开发时:
```bash
export NODE_HOME="<DevEco>/tools/node"
export DEVECO_SDK_HOME="<DevEco>/sdk"
<DevEco>/tools/ohpm/bin/ohpm install --all
<DevEco>/tools/hvigor/bin/hvigorw assembleHap --mode module -p product=default
```
产物在 `entry/build/default/outputs/default/entry-default-unsigned.hap`。
`local.properties` 里写本机 SDK 路径,**不入库**(见 `.gitignore`)。
---
## 开源协议
[Apache License 2.0](LICENSE)