基本功能

This commit is contained in:
吕新雨
2026-01-28 22:13:55 +08:00
parent 049995692d
commit b485b52eec
6 changed files with 488 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
# Onboarding App Shell技术计划
## 1. 计划目标
基于 `spec.md` 的确认项,落地客户端的“首次进入体验 + 主应用壳 + 关键入口”:
- Onboarding**35 页**,每页都有问题但**全部可跳过**
- Push 设置页:**需要**,且**可跳过**;选择“立即开启”会触发系统权限申请
- 进入主 App内容卡片支持 **点赞/讨厌**
- Like**加入收藏**
- Dislike**仅本地记录**(不做“永不出现/降权”)
- 收藏夹入口:需要;**不支持取消收藏/清空**
- 通用设置入口:需要;仅展示 **version**iOS 小组件入口仅展示一段**美观说明文案**
- 当前阶段:**仅做客户端**(不接后端)
## 2. 默认技术决策与约束
- **路由框架**:使用现有 `expo-router`
- **导航结构****不使用 Tabs**
- 使用 Stack + 顶部 Header 入口(从 Home 进入 Favorites/Settings
- **持久化**:使用 `@react-native-async-storage/async-storage`
- **多语言**:沿用现有 i18n 基座(后续在页面文案中逐步补 key
## 3. 路由与页面结构(不使用 Tabs
### 3.1 路由分组(建议)
- `app/(onboarding)/...`Onboarding 多页 + PushPrompt
- `app/(app)/...`Home/Favorites/Settings
- `app/index.tsx`:启动路由分发(根据 onboarding 状态跳转)
### 3.2 页面清单(目标态)
- `Onboarding`35 页)
- 每页:问题展示 + “下一步” + “跳过”
- 进度指示:`x / total`
- `PushPrompt`
- 按钮:立即开启 / 稍后
- `Home`
- 内容卡片(本地 mock
- Like / Dislike
- Header 入口:收藏夹、设置
- `Favorites`
- 仅展示收藏列表(不提供取消/清空)
- `Settings`
- version 展示
- iOS 小组件说明卡片(美观文案)
- 可选:通知状态展示(不影响验收)
## 4. 数据模型与本地存储设计
### 4.1 Key 约定AsyncStorage
- `onboarding.completed`: `true | false`
- `push.promptState`: `enabled | skipped | unknown`
- `content.reactions`: `{ [contentId: string]: 'like' | 'dislike' }`
- `favorites.items`: `string[]`(收藏内容 ID 列表)
### 4.2 内容模型(本地 mock
最小字段:
- `id: string`
- `text: string`(情绪文字/正念短句)
可选字段(非必需):
- `bgColor/bgGradient/image`(用于后续小组件与卡片美化)
## 5. 核心交互逻辑
### 5.1 Onboarding 跳过策略
- **每页可跳过**:点击跳过直接进入下一页(或直接结束 Onboarding二选一默认“跳到下一页”最后一页结束
- **整体跳过**:在任意页可“一键跳过整个 Onboarding”
- **不允许重进**:设置页不提供重新进入 Onboarding 的入口
- Onboarding 结束后写入 `onboarding.completed=true`
### 5.2 PushPrompt
- 立即开启:触发权限申请
- 成功/失败都可继续进入主 App
- 写入 `push.promptState=enabled`(或按结果细分,当前阶段不强制)
- 稍后:写入 `push.promptState=skipped`
- 页面可跳过,不阻塞进入主 App
### 5.3 Like / Dislike / 收藏
- Like
- 写入 `content.reactions[contentId]='like'`
-`contentId` 追加到 `favorites.items`(去重)
- Dislike
- 写入 `content.reactions[contentId]='dislike'`
- 不影响收藏,不改变内容排序策略(仅记录)
## 6. UI 设计要点(高层)
- Onboarding
- 温柔、轻量、可跳过
- 进度清晰(例如 2/4
- Home
- 卡片居中按钮明显Like/Dislike
- Header 右侧放“收藏/设置”入口(避免 Tab
- Settings
- version 用“信息行”展示
- iOS 小组件用卡片样式展示一段美观文案(可多语言)
## 7. 实施步骤(落地顺序)
1. **路由重构**:从 Tabs 模板迁移为 Stack + Header 入口(不使用 Tabs
2. **实现启动分发**`app/index.tsx` 根据 `onboarding.completed` 跳转
3. **实现 Onboarding 35 页**:支持逐页跳过与整体跳过,持久化完成状态
4. **实现 PushPrompt**:可跳过,立即开启触发权限申请并记录状态
5. **实现 Home**:本地 mock 内容 + Like/Dislike + Header 入口
6. **实现 Favorites**:展示收藏列表(不提供取消/清空)
7. **实现 Settings**version + iOS 小组件说明文案卡片
8. **补齐 i18n key**:把新增文案接入五语资源(先覆盖 zh-CN/en其他语言可逐步补齐
## 8. 验收与自测清单
- 首次启动:
- Onboarding 35 页可正常前进,且每页都可跳过
- 可“一键跳过整个 Onboarding”
- PushPrompt 可跳过;立即开启会触发权限申请;无论选择都能进入主 App
- 非首次启动:
- 不再出现 Onboarding直接进入主 App
- 主功能:
- Home 可 Like/Dislike 并写入本地记录
- Like 会进入收藏夹列表
- 收藏夹可进入且能看到收藏内容(不提供取消/清空)
- Settings 可进入并显示 version 与小组件说明文案
## 9. 风险与处理
- Expo/模拟器环境差异:确保在 iOS 模拟器与真机Expo Go都能走通流程
- 通知权限弹窗:若用户拒绝,不影响进入主功能,状态按“已提示”记录即可

View File

@@ -0,0 +1,127 @@
# Onboarding App Shell任务清单
> 说明:本清单根据 `plan.md` 拆解,要求“可执行、可验收、可标记”。
> 标记规则:执行完成后将对应项从 `- [ ]` 改为 `- [x]`,并把“状态”改为 **已完成**;进行中改为 **进行中**;阻塞写明原因与解除条件。
## 0. 清单状态说明
- **状态**:未开始 / 进行中 / 已完成 / 阻塞
- **阻塞**:必须写明阻塞点与解除条件
## 1. 路由重构(不使用 Tabs
- [ ] **移除 Tabs 导航结构,切换为 Stack + Header 入口**
- **状态**:未开始
- **范围**`client/app/(tabs)/*``client/app/_layout.tsx`、新增 `client/app/(app)/*``client/app/(onboarding)/*`
- **要求**
- 首页为 `Home`(非 Tab
- 从 Home 的 Header 进入 `Favorites``Settings`
- **验收**:启动后不出现 TabBar可从 Home 进入收藏夹与设置
- [ ] **实现启动分发 `app/index.tsx`(按 onboarding 状态跳转)**
- **状态**:未开始
- **规则**
- `onboarding.completed=true`:进入 `/(app)/home`
- 否则进入 `/(onboarding)/onboarding`
- **验收**:首次启动进入 Onboarding完成后重启直接进 Home
## 2. 本地存储与数据模型
- [ ] **封装 AsyncStorage 访问层(统一 key 与读写)**
- **状态**:未开始
- **Key**
- `onboarding.completed`
- `push.promptState`
- `content.reactions`
- `favorites.items`
- **验收**:读写都有类型约束;不会散落在 UI 代码里重复写 key
- [ ] **提供本地 mock 内容列表(带稳定 id**
- **状态**:未开始
- **字段**`id``text`
- **验收**Home 可稳定渲染一条内容,并能切换到下一条(如实现)
## 3. Onboarding35 页,全部可跳过)
- [ ] **实现 Onboarding 容器页35 页)**
- **状态**:未开始
- **要求**
- 显示进度(例如 `2/4`
- 每页都有“下一步”与“跳过”
- 任意页有“一键跳过整个 Onboarding”
- **验收**:可从任意页跳过且不阻塞进入 PushPrompt
- [ ] **Onboarding 完成状态持久化**
- **状态**:未开始
- **要求**:完成或整体跳过时写入 `onboarding.completed=true`
- **验收**:重启 App 不再出现 Onboarding
## 4. PushPrompt需要且可跳过
- [ ] **实现 PushPrompt 页面**
- **状态**:未开始
- **按钮**
- 立即开启(触发系统权限申请)
- 稍后(跳过)
- **持久化**
- 立即开启:写入 `push.promptState=enabled`
- 稍后:写入 `push.promptState=skipped`
- **验收**:无论选择/权限结果如何,都能进入 Home
## 5. Home点赞/讨厌)
- [ ] **实现 Home 页面(内容卡片 + Like/Dislike**
- **状态**:未开始
- **要求**
- 展示一条 mock 内容
- Like / Dislike 按钮明显
- **验收**:点击 Like/Dislike 会写入本地记录
- [ ] **实现 Like=收藏规则**
- **状态**:未开始
- **规则**
- Like记录 `content.reactions[id]='like'`
- Like`id` 追加到 `favorites.items`(去重)
- Dislike记录 `content.reactions[id]='dislike'`(不改变出现策略)
- **验收**Like 后收藏夹可见该内容Dislike 仅记录不影响收藏
- [ ] **在 Home Header 加入入口:收藏夹、设置**
- **状态**:未开始
- **验收**:从 Home 可进入 Favorites 与 Settings
## 6. Favorites仅展示不可取消/清空)
- [ ] **实现 Favorites 页面(只读列表)**
- **状态**:未开始
- **要求**
- 展示 `favorites.items` 对应的内容
- 不提供取消收藏/清空
- **验收**Like 的内容在此页可见;无取消入口
## 7. Settingsversion + iOS 小组件说明文案)
- [ ] **实现 Settings 页面**
- **状态**:未开始
- **内容**
- version 信息行(仅 version
- iOS 小组件说明卡片(美观文案)
- **验收**:页面可进入,信息展示正确,文案样式不突兀
## 8. i18n 文案补齐
- [ ] **补齐 Onboarding/Push/Home/Favorites/Settings 的 i18n key至少 zh-CN/en**
- **状态**:未开始
- **要求**
- key 点分层:`onboarding.*``push.*``home.*``favorites.*``settings.*`
- 先覆盖 `zh-CN/en`,其余语言可后续逐步补齐
- **验收**:页面不出现硬编码长句;主要文案可切换语言生效
## 9. 自测与验收
- [ ] **流程自测(首次/非首次)**
- **状态**:未开始
- **路径**
- 首次启动Onboarding逐页跳过/整体跳过)-> PushPrompt开启/稍后)-> Home
- 非首次:直接 Home
- **验收**:与 `plan.md` 的验收清单一致

View File

@@ -0,0 +1,50 @@
# iOS Widget技术计划V1 写死文案)
## 1. 计划目标
在 iOS 上实现真正可添加到桌面的小组件WidgetKit ExtensionV1 先展示**写死的美观文案**,不做 App->Widget 数据同步与更新。
- **构建方式**:方案 A`expo prebuild` + Xcode
- **点击跳转**:跳转到 App 的 Home
- **尺寸**Small / Medium / Large 都支持
## 2. 默认技术决策
- **小组件实现**iOS 原生 WidgetKit ExtensionSwiftUI
- **数据来源**V1 写死在 Widget 代码内
- **跳转**:使用 Widget 的 `widgetURL` 打开 App深链
- **App 侧路由**:使用现有 `expo-router`
## 3. Deep Link 约定(点击小组件打开 Home
### 3.1 Scheme
当前 `client/app.json` 中已存在:
- `expo.scheme = "client"`
因此小组件点击跳转使用:
- `client:///(app)/home`
> 说明:这是 expo-router 的路径形态;若你后续调整路由结构,需要同步更新此 URL。
## 4. 实施步骤(高层)
1. **预构建 iOS 原生工程**:生成 `client/ios/`
2. **在 Xcode 创建 WidgetKit Extension**:命名例如 `MindfulnessWidget`
3. **实现 3 种尺寸 UI**Small/Medium/Large 都展示写死文案,但排版适配不同尺寸
4. **设置点击跳转**:为 Widget 配置 `widgetURL` 指向 `client:///(app)/home`
5. **本地运行验证**:在模拟器安装 App添加桌面小组件并验证显示与跳转
## 5. 验收标准
- 可以在 iOS 桌面添加小组件Small/Medium/Large
- 小组件展示写死文案,排版美观
- 点击小组件能打开 App 并进入 Home
## 6. 风险与注意事项
- **Expo Go 不支持**:必须用 Xcode 运行预构建后的 App或后续 EAS Build
- **Bundle Identifier**:当前 `client/app.json` 使用 `com.anonymous.client`,仅适合本地验证;上线前需替换为真实 bundle id并同步证书/签名

View File

@@ -0,0 +1,84 @@
# iOS Widget高层规范
## 1. 背景与目标
当前客户端仅在设置页展示了“小组件说明文案”,并未实现真正的 iOS 桌面小组件。
本需求用于实现**真正的 iOS 小组件**WidgetKit Extension使用户可以在 iOS 桌面添加小组件并看到“情绪文字/正念短句”等内容。
### 目标
- **可添加到桌面**:支持在 iOS 桌面添加小组件WidgetKit
- **V1本期写死内容**:小组件展示一段美观文案(先写死,不做数据同步/更新)
- **可点击跳转**:点击小组件可跳转回 App 指定页面(默认 Home
### 非目标(本阶段不做)
- 不承诺严格准点刷新(受 iOS 系统调度限制)
- 不做复杂的小组件交互配置(如需可后续拆分)
- 不要求 Android Widget仅 iOS
- **V1 不做数据更新**:不做 App -> Widget 数据共享与更新触发App Group 留到后续版本)
## 2. 关键结论与约束(必须接受)
- **Expo Go 不支持 WidgetKit**:必须使用 **Development Build / 预构建后的原生工程 / EAS Build** 才能安装带小组件扩展的 App
- **需要原生扩展**iOS 小组件必须创建 **WidgetKit ExtensionSwiftUI**
- **V1 不需要 App Group**:因为内容写死在 Widget 内部;后续做数据共享时再引入 App Group
## 3. 小组件功能需求(高层)
### 3.1 展示内容
- 展示一段“情绪文字/正念短句”
- 背景支持:
- 纯色或渐变(优先)
- 图片(可选,后续)
- 文案需“美观可读”,适配暗色模式(可选)
### 3.2 尺寸支持
- 支持 iOS 常见尺寸:
- Small
- Medium
- Large
### 3.3 更新策略
V1不做更新策略内容写死。后续版本可扩展
- 固定间隔更新(例如每天/每小时)
- App 驱动更新App 写入新内容Widget 触发 reload系统仍可能延迟
### 3.4 点击跳转
- 点击小组件可打开 App 并跳转到指定页面:
- 默认Home
- 可选Favorites
## 4. 数据共享与持久化(高层)
V1不做数据共享与持久化写死文案
后续版本V2再引入 App Group共享 UserDefaults与数据来源策略
- `widget.text``widget.updatedAt``widget.lang``widget.theme`
- 数据来源可选Home 当前/最近 Like/随机 mock
## 5. 多语言(与 App 一致)
- 语言码沿用客户端:`zh-CN/en/es/pt/zh-TW`
- V1Widget 内可先写死单语(例如中文)或做最小的本地化(可选)
- V2建议由 App 端选择语言并写入共享数据,降低 Widget 端 i18n 复杂度
## 6. 验收标准
- 可以在 iOS 桌面搜索并添加小组件
- 小组件能显示一段美观文案(至少支持 Small
- 点击小组件能打开 App 并进入预期页面
## 7. 风险与注意事项
- iOS 刷新频率限制:不可承诺“每分钟刷新”等高频
- App Group / Bundle ID 配置错误会导致 Widget 读不到数据
- Dev Build / EAS 证书配置成本较高,需要在计划阶段明确落地路径

View File

@@ -0,0 +1,79 @@
# iOS Widget任务清单V1 写死文案)
> 说明:本清单根据 `plan.md` 拆解,要求“可执行、可验收、可标记”。
> 标记规则:执行完成后将对应项从 `- [ ]` 改为 `- [x]`,并把“状态”改为 **已完成**;进行中改为 **进行中**;阻塞写明原因与解除条件。
## 0. 清单状态说明
- **状态**:未开始 / 进行中 / 已完成 / 阻塞
- **阻塞**:必须写明阻塞点与解除条件
## 1. 预构建 iOS 原生工程(必须)
- [x] **执行 prebuild 生成 `ios/` 目录**
- **状态**:已完成(已执行 `npx expo prebuild -p ios --no-install`,已生成 `client/ios/`
- **命令**
```bash
cd client
npx expo prebuild -p ios
```
- **产出**`client/ios/`(包含 Xcode 工程)
- **验收**`client/ios/` 目录存在,并能在 Xcode 打开
## 2. 创建 WidgetKit ExtensionXcode 操作)
- [x] **在 Xcode 新建 Widget ExtensionWidgetKit**
- **状态**:已完成(已创建 Target情绪小组件下一步把 Swift 文件加入该 Target 并跑模拟器验证)
- **操作**
- 打开 `client/ios/*.xcworkspace`(优先 workspace
- `File -> New -> Target... -> Widget Extension`
- 名称建议:`MindfulnessWidget`(或你喜欢的命名)
- **验收**:工程里新增 Widget target能编译通过
- **下一步(必须做)**
-`client/ios/MindfulnessWidget/MindfulnessWidget.swift` 加入 Target Membership`情绪小组件`
- 如果 Xcode 自动生成了同类的 Widget 主文件(例如 `情绪小组件.swift` / `*_Bundle.swift`),请确保最终只有一个 `@main struct ...: Widget` 入口(避免重复入口导致编译失败)
## 3. 实现写死文案3 个尺寸都要)
- [x] **实现 Small/Medium/Large 三种尺寸布局**
- **状态**:已完成(已提供 `client/ios/MindfulnessWidget/MindfulnessWidget.swift` 写死文案 + 三尺寸布局代码骨架)
- **文案(写死)**:可先用一条默认文案,例如:`你已经很努力了,今天也值得被温柔对待。`
- **要求**
- Small一行标题 + 主文案(可截断)
- Medium主文案更完整可多行
- Large增加留白与排版层次例如标题 + 文案 + 小注脚)
- **验收**:三种尺寸均显示美观,无溢出/遮挡
## 4. 点击跳转到 HomeDeep Link
- [x] **为 Widget 配置点击跳转 URL**
- **状态**:已完成(代码骨架已使用 `.widgetURL(URL(string: \"client:///(app)/home\")!)`
- **URL**`client:///(app)/home`
- **实现**:在 Widget 中设置 `.widgetURL(URL(string: \"client:///(app)/home\")!)`
- **验收**:点击小组件能打开 App 并进入 Home
## 5. 本地验证
- [ ] **在 iOS 模拟器运行并添加桌面小组件**
- **状态**:阻塞(需要本机 Xcode Run 安装后在模拟器桌面添加 Widget 验证)
- **步骤**
- Xcode Scheme 选择主 App一般是 `client`),选择模拟器,点击 Run 安装 App
- 回到桌面长按 -> “+” -> 搜索小组件 -> 添加 Small/Medium/Large
- **验收**:小组件显示正确,点击跳转正确
- **排查**
- 桌面搜索不到:通常是没有 Run 安装过主 App或 Widget target 未加入编译
- 点击不跳转:确认 Widget 里 `widgetURL``client:///(app)/home`,且 `app.json``scheme``client`
## 6. 文档补充(可选但建议)
- [x] **在 `client/README.md` 增加“小组件开发V1 写死文案)”说明**
- **状态**:已完成
- **内容**
- Expo Go 不支持
- prebuild 命令
- Xcode 创建 Widget Extension 的步骤
- deep link`client:///(app)/home`
- **验收**:新同学照 README 可复现

View File

@@ -36,3 +36,14 @@
- **核心范围**Onboarding 多页流程、Push 引导页、主界面反应操作Like/Dislike、收藏夹、设置页版本、iOS 小组件入口/说明) - **核心范围**Onboarding 多页流程、Push 引导页、主界面反应操作Like/Dislike、收藏夹、设置页版本、iOS 小组件入口/说明)
- **阶段产物** - **阶段产物**
- `spec_kit/Onboarding App Shell/spec.md` - `spec_kit/Onboarding App Shell/spec.md`
- `spec_kit/Onboarding App Shell/plan.md`
- `spec_kit/Onboarding App Shell/tasks.md`
## iOS Widget
- **目标**:实现真正的 iOS 桌面小组件WidgetKit Extension展示美观文案并与 App 共享数据
- **核心范围**WidgetKit 扩展、App Group 数据共享、尺寸适配Small/Medium/Large、点击跳转回 App
- **阶段产物**
- `spec_kit/iOS Widget/spec.md`
- `spec_kit/iOS Widget/plan.md`
- `spec_kit/iOS Widget/tasks.md`