# 如梦 — 架构文档 ## 总览 ``` iPhone (如梦.app) │ ├─ HTTP ── Tailscale ── Mac (push.py :8795) │ ├── /tmux/capture ─→ tmux capture-pane │ ├── /tmux/send ─→ tmux send-keys │ └── /health ─→ 健康检查 │ └─ 网络层: ServerConfig → URLSession → push.py ``` ## 文件清单 | 文件 | 职责 | 依赖 | |------|------|------| | `如梦App.swift` | @main 入口,WindowGroup → ContentView | ContentView | | `ContentView.swift` | 页面路由 + 手势导航菜单 + ZStack 层级 | 所有页面 View | | `ChatPlaceholderView.swift` | 聊天占位(待开发) | 无 | | `TerminalView.swift` | tmux 终端 UI(黑底浅灰字) | TerminalViewModel | | `TerminalViewModel.swift` | tmux 网络层:轮询 capture-pane + 发送 send-keys | ServerConfig | | `ServerConfig.swift` | endpoint 列表 + 当前选中 + URL 构建 | UserDefaults | | `SettingsView.swift` | 设置页:endpoint 管理 + 主题切换 | ServerConfig, EndpointChecker | | `EndpointResolver.swift` | 异步 ping /health,返回每个 endpoint 状态 | ServerConfig | | `ThemeManager.swift` | 白天/夜间两套色板定义 | UserDefaults | ## 数据流 ### 1. 网络请求 ``` TerminalView / SettingsView → ServerConfig.makeRequest(path:) → ServerConfig.activeHost (从 UserDefaults 读) → URLSession 请求 push.py ``` - `ServerConfig.endpoints` 是预定义列表,顺序可被 SettingsView 的上下箭头重排 - 重排结果持久化到 `endpoint_urls` / `endpoint_labels`(UserDefaults) - `active_endpoint`(UserDefaults)决定当前用哪个 - `EndpointChecker` 定期 ping 所有 endpoint,更新状态灯(绿/红/灰) ### 2. 主题 ``` SettingsView 点击「夜间/白天」 → setTheme() → UserDefaults("active_theme") → ContentView 监听 UserDefaults.didChangeNotification → theme = currentTheme() → 所有颜色从 theme.bg / theme.text / theme.textDim 读取 ``` - `AppTheme.dark` 和 `AppTheme.light` 各自定义完整色板 - 目前只有 dark 在用,light 是 placeholder ### 3. 菜单导航 ``` 用户左边缘右滑 → DragGesture → menuX 跟踪手势 → 松手 → snapTo(.open) 或 snapTo(.closed) → spring 动画 → menuX 归位 → ContentView 根据 currentPage 切换页面 ``` - `menuX` 是菜单唯一的状态源(-200 隐藏,0 打开,>0 弹性过冲) - `menuOpen` 是辅助状态(控制触控条激活/禁用) - 页面切换是 `@State currentPage` 驱动 `@ViewBuilder pageView` ## ZStack 层级(自上而下) ``` 4. 左边缘触控条 (HStack 24pt) — allowsHitTesting(!menuOpen) 3. 页面标题 (VStack) — menuX < -150 时显示 2. 菜单层 (if menuX > -200): ├── 遮罩 Color.black 0.15 — allowsHitTesting(false) ├── 关闭热区 Color.clear.contentShape — onTapGesture → snapTo(.closed) └── 图标列 VStack — Button × 4,点击切换页面 1. 当前页面 (pageView) — Termina​lView / Chat / 阅读 / 设置 ``` **规则**: - 菜单打开时触控条失活,避免抢手势 - 遮罩背景不拦截触摸,关闭热区在图标列下面 - 图标列在最上层,按钮始终可点 ## 各页面状态 | 页面 | 状态 | 备注 | |------|------|------| | 聊天 | 占位 | 纯黑 + "聊天" 文字,待开发 | | 终端 | 完成 | tmux capture-pane 轮询 + send-keys 发送,带时间戳 | | 阅读 | 占位 | 待开发 Coffee Time | | 设置 | 开发中 | endpoint 管理 + 主题切换,功能可用但 UI 需继续 | ## 设计原则 - **单一状态源**:menuX 驱动菜单,currentPage 驱动页面,UserDefaults 驱动配置 - **无 Combine**:不用 @StateObject/@Published,用 @State + UserDefaults 通知 - **零第三方依赖**:纯 SwiftUI + Foundation - **不向后兼容**:部署目标 iOS 26.4,不考虑旧版本 API - **所有网络走 push.py**:不直连 DeepSeek,不引入新服务端 ## 更新日志 - 2026-05-22 — 初始架构。ZStack 菜单导航 + endpoint 切换 + 主题系统骨架。