Commit Graph

2 Commits

Author SHA1 Message Date
xiaoshuai 2b63bf7d0b feat(image): 图片直接显示 + 右键复制图片; 修未读角标不清
## 图片直显 + 右键复制

以前图片消息基本只能看到 "[图片] xxx.png" 的文件卡片, 而且右键没有"复制"。

根因有两层:

1. `asImage` 从来没被设成 true —— 用"发送文件"选中的图片是当**普通文件**发的,
   对方只能看到文件卡片。
2. 拖拽/粘贴的图走 `sendBuffer`, 只在 <200KB 时才带 `thumbDataUrl`,
   大图没有缩略图 -> 渲染层 fallback 成文件卡片。

改法:

- 缩略图随消息体走 (`body.thumbDataUrl`): **发送方生成一次, 对方直接拿来显示**,
  对端不用再解码, 老版本对端也看得到图。
- 缩略图用 Electron 的 `nativeImage` 生成 (`src/main/image.ts`), 不引 sharp/jimp:
  宽度上限 480, **PNG 优先 (保透明 —— 截图转 JPEG 会变黑底)**, PNG 超 60KB 才退 JPEG,
  然后按"降质量 -> 缩尺寸"的阶梯找一档够小的。
  阈值/编码选择/选图源抽到 `src/main/image-core.ts` (纯逻辑, 不 import electron, 可单测)。
  源文件 >20MB 不生成 —— nativeImage 解码会把整张图铺成 RGBA 内存。
- 拖拽/选中的图片改走 `sendFile(asImage: true)` (有真实路径, 流式上传),
  只有粘贴的图片才走 `sendBuffer` (整图 base64 进 WS 帧, 大图撑爆带宽)。
- 右键"复制图片" -> `image:copy` IPC -> `clipboard.writeImage`, 写的是**原图**
  (本地文件优先, 退回 dataBase64), 不是气泡里那个缩略图。
- 缩略图缺失时 (老消息/老版本对端) 渲染层退到 `image:thumb` 现场生成,
  失败才显示文件卡片。点开看大图用 `image:dataUrl` 读本地原图。

## 修未读角标不清

用户正看着某个会话, dock/任务栏角标的数字却不消。

根因: `App.vue` 的 `message:received` 里先判 `if (!savedPath) return` (等文件落地再算未读),
而**文字消息没有 savedPath** —— 正好在"清未读"之前就 return 了。
文件/图片消息因为第二帧带 savedPath 才碰巧能清掉, 所以只有文字消息暴露这个 bug。

改法:

- 决策抽成纯函数 `src/renderer/src/utils/unread.ts` 的 `unreadActionForIncoming()`
  (`clear` / `wait` / `count`): **先判 isActive -> 清未读 + 回已读回执, 再判 savedPath**。
- 侧边栏**重复点同一个设备**时 activePeerId 不变, watch 不触发 -> 显式清一次。
- 主进程 `device:delete` 清了 unread 但忘了 `updateBadge()` -> 角标残留, 补上。

## 验证

- npm run typecheck        ✅
- npm run build            ✅
- npm run selftest         ✅ 76 通过 / 0 失败 (新增 I1-I8 图片 + U1-U4 角标)
- npm run selftest:sync    ✅ 全部通过
- npm run selftest:image   ✅ 真 Electron 下验 nativeImage (新增命令)
- npm run package:linux    ✅ 新 deb
- npm run selftest:package ✅ 4/4

真机 (CDP 驱动真实窗口) 验证过: 图片气泡内联显示 (640x420, fallback 0 个),
右键菜单含"复制图片", 点下去系统剪贴板里是 **640x420 原图** (不是缩略图)。
2026-10-21 14:52:37 +08:00
xiaoshuai a79086e4e8 feat: 网盘浏览下载 + 远程功能修复 + 连接状态同步 + Linux 图标打包
新增网盘功能
- FileServer 增加 GET /drive/meta|list|download, 每机长期 token 校验 + 目录穿越防护
- 新增 drive.ts 客户端: listDrive / getDriveRoot / downloadDriveFile / collectDriveFiles
- ipc 暴露 drive:list|root|download|openFolder|pickDir, DB 增 drive_token 列 + ALTER 迁移
- 新增 DrivePanel.vue, 聊天框加"网盘" tab, 设置页加网盘分区
- 支持整目录递归下载并保持层级

修复远程功能
- 终端: 控制端收到的 output 帧被直接丢弃 (case 'output': return), 导致 xterm 全空白
- ChatServer: ws 构造即 listen, 'listening' 可能早于 start() 挂监听, 导致永久挂起
- USB: serverAttach 自行生成 sessionId 与控制端不一致 (数据帧查表落空);
  libusb 枚举误用 getDevices() (WebUSB 语义, 只返回已授权设备) 改 loadDevices();
  control transfer 传数字 bmRequestType (node-usb v3 要字符串枚举);
  detachKernelDriver 挪到 selectConfiguration 之前 (否则 EBUSY)
- 转发 UI: store 的 onOpened 是 no-op 致对方发起的转发不显示、无轮询致流量/TTL 不刷新、
  对方发起的会话关不掉 (新增 closeSession, server 侧关闭需通知对端否则端口泄漏)、
  入口/目标补归属标注、方向标签语义统一、监听端口输入框加宽

修复"在线却显示等待重连"
- 根因: 启动时主进程先连上对端 (connectTo 早于 createMainWindow), device:wsState
  在渲染层订阅前发出去被丢弃; 之后连接一直保持, 再无 open 事件 -> UI 永久停在等待重连
- 改为推全量快照 + 渲染层 mount 时主动拉取 (app:state); 渲染层先注册监听再 await
- 通道语义改为 outgoing 或 inbound 任一 WS 活着即可用 (原来只看 outgoing)

修复 Linux 安装后没图标
- linux.icon 指向单张 PNG 时 app-builder 解析不出尺寸 (size=0), 图标被装进
  hicolor/0x0/ 非法目录, 桌面环境找不到; 改为指向 resources/icons 目录 (8 个标准尺寸)
- StartupWMClass 填的是 productName, 与窗口真实 WM_CLASS (可执行文件名) 对不上,
  任务栏找不到启动器; 改为 local-net-msg

其他
- 新增 scripts/selftest 自测框架 (两个虚拟节点 + 真实 ChatServer/ChatClient), 30 条用例全过
- 重写 scripts/make-icon.js 生成多尺寸图标集 (原脚本引用的源图已不存在, sharp 依赖也缺)
- 新增 docs/drive.md, docs/connection-status.md
2026-10-20 16:43:56 +08:00