Conversation
There was a problem hiding this comment.
Pull request overview
此 PR 主要围绕“录音标记支持重新语音识别并展示处理状态”增强录音转录的可恢复性,同时顺带改进文章文件树的远端同步加载策略,并在移动端引入“我的 / Me”聚合页(活动热力图 + 同步入口 + 设置入口)与相关路由/布局调整。
Changes:
- 录音 Mark 新增“重新语音识别”操作,并在列表中显示处理中的进度提示文案/状态。
- 文章文件树加载支持跳过自动远端同步,并调整远端同步文件加载路径收集与加载顺序。
- 移动端新增 “Me/我的” 页面与活动热力图自适应布局;移动端设置页结构与底部导航文案同步更新;补充多份 codebase 文档与版本号更新。
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/stores/article.ts | loadFileTree 增加可选参数跳过远端同步;远端同步加载路径与加载顺序调整;更新 setFileTree 触发渲染方式 |
| src/stores/article-remote-sync.ts | 新增工具函数:根据已展开目录构建需要加载的远端路径集合 |
| src/components/title-bar-toolbars/sync-toggle.tsx | Sync 面板抽取为可复用 UI,支持 Popover/Drawer 两种呈现方式;对话框 open 命名避免冲突 |
| src/components/app-footbar.tsx | 移动端底部导航文案从“设置”调整为“我的”入口文案 |
| src/components/activity/activity-heatmap.tsx | 热力图组件新增 adaptive 模式,支持移动端等宽自适应列布局 |
| src/app/mobile/writing/custom-header.tsx | 移动端写作文件抽屉新增“刷新”按钮,并引入更细粒度的刷新/加载状态 |
| src/app/mobile/setting/pages/page.tsx | 新增移动端设置 pages 索引页(标题 + SettingTab 容器) |
| src/app/mobile/setting/pages/layout.tsx | 调整移动端设置 pages 布局(顶部返回栏与 padding/高度策略) |
| src/app/mobile/setting/page.tsx | /mobile/setting 入口改为渲染新的 MobileMePage |
| src/app/mobile/setting/components/setting-tab.tsx | 导航到具体设置页前保存 Me 页滚动位置 |
| src/app/mobile/setting/components/mobile-me-profile-card.tsx | 新增 Me 页头部卡片(头像/同步状态/SyncToggle Drawer 入口) |
| src/app/mobile/setting/components/mobile-me-page.tsx | 新增 Me 聚合页(活动热力图、统计、设置入口、滚动恢复) |
| src/app/mobile/setting/components/mobile-me-helpers.ts | 新增 Me 页的活动统计、同步状态与展示文案拼装辅助函数 |
| src/app/mobile/setting/components/mobile-me-activity-drawer.tsx | 新增活动详情 Drawer(复用 ActivityDayDetail) |
| src/app/mobile/record/page.tsx | 调整布局类名以改善 flex 容器的高度/滚动行为 |
| src/app/mobile/record/mobile-record-stream.tsx | 增补 min-h-0 等,修复滚动容器在 flex 下的高度计算问题 |
| src/app/mobile/layout.tsx | 根据 pathname 控制在移动端设置子页面隐藏底部导航栏 |
| src/app/core/main/mark/mark-mobile-actions.tsx | Mark 移动端菜单新增“重新语音识别”入口与 loading 禁用态 |
| src/app/core/main/mark/mark-item.tsx | 实现重新语音识别逻辑 + queue 状态展示(列表内加载提示) |
| src-tauri/tauri.conf.json | 版本号从 0.27.1 升至 0.27.2(含 iOS bundleVersion) |
| messages/zh.json | 新增“重新语音识别”文案与“我的”导航文案;新增 mobile.me 文案块 |
| messages/zh-TW.json | 同步新增相关 i18n 文案(含 mobile.me 与 reconvert stt) |
| messages/pt-BR.json | 同步新增相关 i18n 文案(含 mobile.me 与 reconvert stt) |
| messages/ja.json | 同步新增相关 i18n 文案(含 mobile.me 与 reconvert stt) |
| messages/en.json | 同步新增相关 i18n 文案(含 mobile.me 与 reconvert stt) |
| docs/SYSTEM-DIAGRAM.html | 新增系统结构图(HTML 版) |
| docs/SYSTEM-DIAGRAM-TEXT.md | 新增系统结构图(文本版) |
| docs/READING-ORDER.md | 新增建议阅读顺序文档 |
| docs/MODULE-MAP.md | 新增模块地图文档 |
| docs/CODEBASE-OVERVIEW.md | 新增 codebase 概览文档(含三套子工程说明) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| { | ||
| title: t('navigation.setting'), | ||
| title: t('navigation.me'), | ||
| url: "/mobile/setting", | ||
| icon: Settings, | ||
| }, |
There was a problem hiding this comment.
PR 标题/描述聚焦在“录音标记重新语音识别并显示进度”,但本次改动还包含移动端底部导航从“设置”改为“我的”、新增 Mobile Me 页面/活动热力图、自定义设置路由布局等较大范围 UI 调整。建议在 PR 描述中补充这些变更的动机与范围,或拆分为独立 PR 以便回归验证。
| // 为根目录和已展开的目录加载远程文件。 | ||
| // 这样即使目录只存在于云端,只要用户已展开过,也能继续加载其远程内容。 | ||
| const collapsibleList = get().collapsibleList | ||
| const pathsToLoad: string[] = [''] // 总是加载根目录 | ||
|
|
||
| // 检查 collapsibleList 中的路径是否在本地存在,或者尝试加载远程文件夹 | ||
| for (const path of collapsibleList) { | ||
| const fullPath = await join(workspace.path, path) | ||
| let dirExists = false | ||
|
|
||
| try { | ||
| if (workspace.isCustom) { | ||
| dirExists = await exists(fullPath) | ||
| } else { | ||
| const dirRelative = await toWorkspaceRelativePath(fullPath) | ||
| const pathOptions = await getFilePathOptions(dirRelative) | ||
| dirExists = await exists(pathOptions.path, { baseDir: pathOptions.baseDir }) | ||
| } | ||
| } catch { | ||
| dirExists = false | ||
| } | ||
|
|
||
| // 本地存在的文件夹,或者对于云同步(GitHub/Gitee/GitLab/Gitea/S3/WebDAV),即使本地不存在也尝试加载远程 | ||
| // 这样可以显示仅存在于云端的文件夹 | ||
| if (dirExists || primaryBackupMethod !== 'github') { | ||
| // 对于非 Git 平台,总是尝试加载 | ||
| pathsToLoad.push(path) | ||
| } else if (dirExists) { | ||
| // 对于 Git 平台,只加载本地存在的 | ||
| pathsToLoad.push(path) | ||
| } | ||
| } | ||
| const pathsToLoad = buildRemotePathsToLoad(collapsibleList) | ||
|
|
||
| // 使用 Promise.all 并发请求所有路径的远程文件 | ||
| const loadPromises = pathsToLoad.map(async path => { | ||
| // 目录树会在加载过程中逐步插入父级节点,因此这里必须按层级顺序加载。 | ||
| // 如果并发请求深层路径,远端子目录可能会在父目录节点尚未写入树时被跳过。 | ||
| for (const path of pathsToLoad) { |
There was a problem hiding this comment.
这里改为按 pathsToLoad 顺序逐个加载是对的,但当前循环内部在处理远端“目录项”时仍用 getCurrentFolder(itemPath, dirs)?.parent 来定位父节点(Git/S3/WebDAV 都有类似写法)。当子目录节点尚未存在时(例如列出 a/ 返回 a/b 目录),getCurrentFolder('a/b') 会返回 undefined,从而导致远端子目录节点无法被插入树,cloud-only 的层级结构会丢失。建议改为从 itemPath/localItemPath 计算 parentPath(去掉最后一段并去除尾部 /)后直接 getCurrentFolder(parentPath, dirs),必要时先创建缺失的中间目录节点。
| <div | ||
| id="mobile-me" | ||
| ref={containerRef} | ||
| className="flex h-full w-full flex-col overflow-y-auto" | ||
| onScroll={(event) => { | ||
| window.sessionStorage.setItem(MOBILE_ME_SCROLL_KEY, String(event.currentTarget.scrollTop)) | ||
| }} |
There was a problem hiding this comment.
onScroll 里每次滚动事件都写入 sessionStorage,在移动端会非常频繁,可能造成掉帧/卡顿。建议用节流(例如 requestAnimationFrame / setTimeout debounce)或仅在滚动停止后写入;同时 SettingTab 导航前已保存一次 scrollTop,这里可以只在必要时更新。
| variant="ghost" | ||
| size="icon" | ||
| className="h-8 w-8" | ||
| disabled={syncing || exporting || importing} |
There was a problem hiding this comment.
syncButton 是纯图标按钮,但没有 aria-label(Popover 版本靠 Tooltip 文本不一定能被读屏器读取,Drawer 版本也没有 Tooltip)。建议为该 Button 添加稳定的 aria-label(例如 t('common.sync'))以提升可访问性。
| disabled={syncing || exporting || importing} | |
| disabled={syncing || exporting || importing} | |
| aria-label={t('common.sync')} |
经常会出现转录失败的情况,此功能非常必要。