Files
Cyrene-For-Android/app
AskaEth ae4e4e53f6 feat(share): 接入系统分享入口 —— 分享文本 / 图片进会话(未登录先暂存,登录后落地)
主人 2026-10-04 提出的「分享到 App」的客户端半边。触发面就是系统分享菜单的
ACTION_SEND / ACTION_SEND_MULTIPLE;发送侧**完全复用既有路径**(短文本 WS、
长文本与图片 REST、大图先 /upload),不另起一套。

- Manifest:MainActivity 加 SEND / SEND_MULTIPLE 的 intent-filter,MIME 只声明
  text/plain 与 image/*。刻意不声明 */*:对话路径上今天没有「文件」这个表示
  (协同 02/F1 三缺),声明 */* 等于给出一个点进去必然失败的入口;收窄之后非图片
  文件干脆不进分享菜单。另加 launchMode=singleTop 与 label(分享菜单里显示 Cyrene,
  图标沿用应用启动图标,不另设一份会漂移的来源)。
- MainActivity:冷启动(onCreate)与热启动(onNewIntent + setIntent)两条路都接。
  冷启动只在 savedInstanceState==null 时接 intent —— Activity 因旋转 / 深色切换重建
  时系统会把同一个 intent 再送一遍,照单全收就会把同一条分享发第二次。
- 新增 domain/share(纯逻辑,可单测):
  - ShareRules.extract:文本 / 单图 / 多图 / 空内容 / 只有 MIME 没有内容 /
    EXTRA_STREAM 缺席时回落到 ClipData;去重与空白条目在**截断之前**处理
    (重复项既不该挤掉真图,也不该被算成「截掉了」)。一次最多接 4 张,超出的
    条数如实计数,不静默丢。正文一个字都不加(来源标记走独立 RoleSystem 消息 +
    SenderName,拼进正文即违反红线,见 02/F4)。
  - ShareRules.cacheFileName:文件名只由本端 token + 序号 + MIME 白名单扩展名构成,
    外部 URI 的路径 / 显示名绝不参与(纯函数里连本端 token 都不信,非法字符折成 _)。
  - PendingShareHolder:待落地内容的队列,take() 是原子出队 —— 一条内容只能被消费
    一次(消费它的地方都会被重建:重组、切会话、Activity 重建),同时不把先后两条
    挤在同一窗口的那次分享丢掉。
- 新增 app/ShareIntake:进程级单例(不塞 AppContainer,避免碰别的并行改动)。
  图片在收到的那一刻就拷进 cacheDir 并换成**本端 file://**(content:// 的读授权活不过
  登录 / 切页,拷不动的那几张如实计入「未发送」);进程启动清一次缓存目录
  (那份副本只对产生它的进程有意义),运行期间不回收 —— 发送失败回滚到输入框之后
  仍要读它。
- ChatViewModel:sendShared 与输入框的 send 共用 emitAndDeliver(同一套乐观气泡 /
  幂等键 / 回滚),差别只有「不动用户草稿」(分享不是用户按的发送键)。一条消息只能
  带一张图 ⇒ N 张图 = N 条消息,第一条带分享的正文;顺序在同一个协程里串起来。
  长文本不截断,由既有 ChatSendRouting 判据改走 REST(WS 帧 4096 字节是断连不是报错)。
- ChatScreen:仅当**当前会话**的组合存在时认领(已访问过的会话 VM 都还活着,UI 层
  认证才不会让旧会话抢走),落地前先等 WS 连接、上限 3 秒(冷启动必然撞上握手;超时
  也照发,让「没网」退化成内容回到输入框这种看得见的结果,而不是停在看不见的地方)。
  截断 / 读不到 / 空内容用 shareNotice 如实告知(8 秒后自动收走),与 error 分开。
- 测试 +23(ShareExtractionTest 18 / PendingShareHolderTest 5):文本、单图、多图、
  空、只有 MIME、ClipData 兜底与去重、截断计数、超大文本不截断且落 REST、
  文件名不可穿越、原子出队(并发 64 取 64 条不重不漏)。assembleDebug 绿,
  testDebugUnitTest 353 → 376 全绿(failures/errors 皆 0)。
2026-10-04 18:05:27 +08:00
..