跳转至

好友邀请接收、资料库删除与刷新按钮恢复

历史记录 / Historical record:本文保留当时的计划、研究或验收证据,不代表 0.11 当前能力全集。现行说明见 文档入口;英文入口见 English overview。

日期:2026-10-20。分支:dev3,基线 6ec1061b。用户继续要求暂不生成 APK。

问题与方案

原好友通道只有发送端本地记录和共享文件夹,没有接收端发现或绑定流程。更直接的问题是 Rust seafile_repos 把 virtual=true 的共享子目录全部过滤了,对方甚至看不到收到的共享资源。旧留言实现只有写入,没有读取。

采用学校 Seafile 已有的账号共享作为邀请传输,无需新增应用服务器。新建通道只给指定云盘邮箱授予读写权限,不生成公开链接。受邀账号在自己的共享库根目录读取小型邀请清单,核对云盘返回的所有者、收件人及权限后,一次点击接入同一个库。接收方不需要反向再创建一个库或再交换口令。

已实现

  • 完整模式启动、回到前台、恢复联网以及前台每 30 秒检查邀请。应用隐藏时暂停检查;不会承诺 App 关闭后的系统推送。
  • 顶栏和竖直标签栏都有待接入信封计数,通讯录有检查、接入、忽略入口。收到邀请不会自动添加联系人或传出完整个人名片。
  • 接入写入回执,发起者的状态由“等待对方接入”变为“已连接”。只有名字与云盘账号标识进入通道清单。
  • 旧共享子目录保留接收方虚拟库 ID,接收路径使用 /,不错误沿用所有者的库 ID 和子目录。
  • 旧通道点击“补发邀请”可升级;若存在公开链接,先明确确认、撤销该链接,再写入账号邀请。原文件和留言保留。
  • 忽略按投递版本保存,补发可重新出现;重试复用已经创建的库。双方分别发起时,可以明确确认切换到其中一个通道,旧映射保留在 previousShares,旧文件仍在云盘。
  • 消息采用独立 JSON 清单、唯一 ID 和附件目录,双方可拉取留言及下载文件。通道打开时每 15 秒刷新、回前台刷新,也有手动刷新。兼容原有 TXT 留言和文件,防止同名附件覆盖。
  • 消息与邀请均隔离账号和通道;注销、重新登录同一 Token、切换账号或在请求中改变通道,不会把迟到响应写回新状态。云端协作者可编辑的作者字段不被当作身份签名。
  • 资料库卡片及库内增加删除按钮。仅本人拥有的非虚拟库可删除,前端与 Rust 都核实所有者;rw 共享权限不能删除对方整库。
  • 删除前说明文件和共享访问后果,关联组织时列出组织名。失败保留列表,成功清缓存并刷新;私密分享专用清理命令没有放宽。
  • 云盘深链支持安全的 cloudRepo + cloudPath,打开好友共享文件可直达正确目录;后台刷新不把当前目录拉回根目录。

用户追加:强制刷新按钮消失

检查发现既存代码用 !simple 隐藏强制刷新按钮,导致极简和实用模式根本不挂载。完整模式还有旧位置首次挂载不校正、负坐标不校正的问题。

已改为三种模式均保留按钮;手动位置首次加载、窗口变化及控件尺寸变化时约束到屏内,保存位置与自由拖动保留。拖动边界排除滚动条宽度,修复左侧仍被裁切的误差。新一次按下清除过期的拖动点击抑制标记,避免拖完后下一次真实点击被吞。

用户继续反馈“点上没反应”后,补到了原先测试遗漏的按下微抖:旧实现任一轴移动超过 3px 即吞点击,实际鼠标输入 4px/6px 均不刷新。现改为移动距离达到鼠标 10px / 触摸 12px 才进入拖动;阈值前不移动按钮、不存位置。保留按下捕获,保证快速拖出小按钮边界仍能自由拖动。自动避让也不再在按下期间移动目标。新增 2/4/6px 微抖及键盘激活验收。

本轮检查时 127.0.0.1:5180 无监听,dev App 的页面重载目标不可达。已用独立进程恢复 Vite,接口返回 HTTP 200。修正 dev-app.sh:构建装壳后明确结束同路径旧 dev 进程并启动新版;原脚本仅 open 会激活旧进程,新 Rust 命令可能始终不生效。

现场回归:OH-Memory 重复建库与删除按钮消失

最初推测是旧原生接口缺元数据;随后真实云盘只读检查纠正了这个判断:学校 /api2/repos/ 实际返回 type: "repo" / "grepo",而不是夹具使用的 "mine" / "shared"。Rust 当时原样转发,前端只认 mine,于是找不到已有库、重复创建空库,并把删除入口全部隐藏。测试夹具同样使用了错误假设,因此之前全绿未能发现问题。

修复:

  • Rust 从当前 Token 的 /api2/account/info/ 取得真实邮箱,结合库 owner 将 repo 规范为 mine 或 shared,grepo 保持组资源。不按名称或 rw 推定所有权;缺少 virtual 时保留未知状态。
  • 文件夹、暂存箱、壁纸、记忆、组织建库五条入口统一到 ownedCloudRepo.ts。未知归属禁止自动建库;同一账号和库名并发只查建一次;POST 结果不明时先复查列表,跨页面重载保留防重标记。
  • 空副本不能覆盖原非空库;唯一非空库优先,多个非空库且没有可信缓存时停止自动选择。
  • 旧原生接口明确提示更新重启,删除按钮显示为禁用并说明原因,不再无解释消失。

真实操作及核对:

  • 逐个检查了 25 个误建 OH-Memory:当前账号所有、非虚拟、0 字节、目录确为空。
  • 用户明确同意清理这 25 个后,删除前再次核对归属、修改时间和空目录,实际删除 25 个。
  • 重启新版 dev App 后,从实际日志确认它选择了原有记忆库。随后只读重新列库,OH-Memory 仅剩一个,大小 19,177 字节。
  • 未删除或改写原记忆库及其他资料库;无真实好友邀请发送。

验收

  • tools/friend-inbox-state-test.mjs:22 项,运行真实 inbox/nameCard 模块,包括权限撤销、虚拟库、部分失败、账号切换、重复及冲突邀请、并发回执、旧链接升级。
  • tools/friend-channel-state-test.mjs:20 项,双向消息、独立附件、旧格式、作者范围、账号及通道隔离、重试和去重。
  • tools/friend-invitation-browser-test.mjs:30 项。两个独立浏览器上下文及 Node 端账号权限夹具;1280 桌面和 390 手机触摸操作实际跑过发起、首页发现、信封入口、接入、回执及双向表单留言。全部非本地网络被阻断。
  • tools/cloud-library-browser-test.mjs:34 项,桌面与手机的取消、失败、删除、组织提示、共享库权限、子目录深链,以及旧原生字段缺失/更新后恢复入口。
  • tools/friend-channel-browser-test.mjs:6 项,无云盘情况下的本地留言及明确失败提示。
  • tools/seafile-account-lifecycle-test.mjs:16 项,包含所有者删除、旧接口拒绝和异步缓存失效。
  • tools/personal-cloud-target-state-test.mjs:50 项,包含未知/真实旧类型不创建、跨入口单飞、跨重载防重复、保留原非空库及组织库隔离。
  • tools/hard-refresh-browser-test.mjs:88 项,三模式、桌面鼠标/手机触摸、点击微抖、自由拖动、持久化、屏幕边界、取消后的下一次点击、键盘激活。
  • Rust 两项仓库元数据测试通过,新增真实 repo/grepo 样例与权限边界;本地 desktop debug 构建完成并重启,没有构建 APK。
  • TypeScript、CSS 解析、OneGUI 护栏通过;中英词典 7375/7375、errors 0,新词条登记在 seed,翻译批次统一重新生成并检查。

截图已经实际查看,保存在外盘:

  • /Volumes/OneTHUBuild/artifacts/friend-invitation-review/
  • /Volumes/OneTHUBuild/artifacts/cloud-library-review/
  • 刷新按钮专项:/Volumes/OneTHUBuild/artifacts/hard-refresh-review/

手机默认暂存箱浮钮仍可能遮住卡片说明的右缘;邀请接入和信封按钮可操作,未改变用户的自由拖动布局。

真实联调边界

尚无第二个真实学校云盘账号,未发送真实邀请。真实云盘检查及获准的 25 个空库删除已执行。上述浏览器测试验证真实 React 操作与隔离权限夹具,不等同于学校实例双账号联调或 Android 真机验收。实际 macOS 窗口自动操作被系统屏幕捕捉错误阻断,本轮不能声称已用自动鼠标点击验收 WKWebView;已确认新版进程启动、实际记忆同步选中原库,浏览器微抖回归通过。

后续有第二账号时:双方更新到此实现并连接各自云盘 → A 收到 B 含云盘邮箱的名片并邀请 → B 回前台点击信封接入 → A 确认回执 → 双向留言、传同名文件 → 使用一次性空资料库测试删除。旧文件夹通道另跑补发升级,确认 B 使用自己的虚拟库根路径。关闭 App 后不要求推送,重新打开应发现邀请。