Преглед изворни кода

fix(ui): 清除用户可见的 Matrix 表述 + 修复深色模式开关状态不可辨

一、界面文案去技术名词
- 删除会话确认框:「Matrix 服务器上的消息本身不会被删除」整句删除
- 「Matrix 登录失败」→「连接失败」
- 「Matrix 凭据不完整(缺 accessToken 或 userId)」→「登录凭据不完整,请重新进入」
- 「附件上传到 Matrix 失败」→「附件上传失败」
- 「Matrix 客户端未连接」→「尚未连接,请稍后重试」
代码注释与标识符保持不变(不进界面)。

二、深色模式开关
根因:关闭态轨道用 --edge-strong(#454b56),与白色圆点亮度接近,
边界消失,看起来像一团白、分不清开还是关。
- 关闭态轨道改用 --surface-active
- 圆点加极淡描边使边界更实
- 开启态保持 --primary 蓝色

已用 Chrome 渲染核对深色主题下明/暗两种卡片的效果。

验证:tsc 0 错误;单测 1089/1089;构建通过;verify:ui 12/12

Co-Authored-By: Claude Code <noreply@anthropic.com>
Huccct пре 23 часа
родитељ
комит
ee6b836b79

+ 31 - 0
docs/00-tracking/操作追踪.md

@@ -3795,3 +3795,34 @@ CSS 模板字符串的注释里用反引号包标识符(如 `` `opacity: 0` ``
 ### 验证
 - tsc 0 错误;单测 **1089/1089**(新增 4 条工作区重名用例)
 - 构建通过;verify:ui 12/12
+
+## 2026-11-01 第二十轮:清除用户可见的 Matrix 表述 + 深色模式开关修复
+
+### 一、用户可见文案去技术名词
+用户要求:只要界面上说明里涉及 Matrix 的全部删除。
+
+| 位置 | 原文案 | 现在 |
+|---|---|---|
+| 删除会话确认框 | 「Matrix 服务器上的消息本身不会被删除。」 | **整句删除** |
+| 连接失败提示 | 「Matrix 登录失败:…」 | 「连接失败:…」 |
+| 凭据错误 | 「Matrix 凭据不完整(缺 accessToken 或 userId)」 | 「登录凭据不完整,请重新进入」 |
+| 附件上传失败 | 「附件上传到 Matrix 失败(没有返回地址)」 | 「附件上传失败(没有返回地址)」 |
+| 未连接 | 「Matrix 客户端未连接」 | 「尚未连接,请稍后重试」 |
+
+代码注释、变量名(`MatrixClientService` 等)保持不变 —— 它们不进界面。
+
+### 二、深色模式开关状态不可辨
+**现象**:深色主题下开关呈「一团浅白」,分不清开还是关。
+
+**根因**:关闭态轨道用 `--edge-strong`(深色主题下 `#454b56`),
+与白色圆点亮度接近,边界消失。
+
+**修复**:
+- 关闭态轨道改用 `--surface-active`(比背景深一层的中性色)
+- 圆点加 `ring-1 ring-black/5` 极淡描边,让边界更实
+- 开启态保持 `--primary`(蓝色),两态对比明确
+
+已用 Chrome 实际渲染核对深色主题下明/暗两种卡片的开关效果。
+
+### 验证
+- tsc 0 错误;单测 **1089/1089**;构建通过;verify:ui 12/12

+ 1 - 2
src/app/components/domain/session-tree/session-tree.ts

@@ -554,8 +554,7 @@ export interface NewSessionRequest {
       (openChange)="$event || removing.set(null)"
     >
       <p class="rm-note">
-        将从列表删除「{{ removing()?.title }}」,删除后<strong>不可恢复</strong>。<br />
-        Matrix 服务器上的消息本身不会被删除。
+        将从列表删除「{{ removing()?.title }}」,删除后<strong>不可恢复</strong>。
       </p>
       <div class="rm-acts">
         <ui-button variant="ghost" (click)="removing.set(null)">取消</ui-button>

+ 3 - 2
src/app/core/chat.service.spec.ts

@@ -381,11 +381,12 @@ describe('ChatService', () => {
       expect(svc.error()).toContain('SessionToken 无效');
     });
 
-    it('SDK 登录失败 → 文案含「Matrix 登录失败」', async () => {
+    it('SDK 登录失败 → 文案含「连接失败」(不暴露技术名词)', async () => {
       realMode();
       mxStub.connectSession.and.returnValue(Promise.reject(new Error('凭据不完整')));
       await svc.open('a');
-      expect(svc.error()).toContain('Matrix 登录失败');
+      expect(svc.error()).toContain('连接失败');
+      expect(svc.error()).withContext('界面文案不应出现 Matrix').not.toContain('Matrix');
     });
 
     it('房间创建失败 → 文案含「房间创建失败」', async () => {

+ 1 - 1
src/app/core/chat.service.ts

@@ -433,7 +433,7 @@ export class ChatService {
       await this.mx.connectSession(prov.accessToken, prov.userMxId ?? '', prov.deviceId);
     } catch (e) {
       if (my !== this.seq) return;
-      throw new Error(`Matrix 登录失败:${msgOf(e)}`);
+      throw new Error(`连接失败:${msgOf(e)}`);
     }
     if (my !== this.seq) return;
 

+ 3 - 3
src/app/core/matrix-client.service.ts

@@ -244,7 +244,7 @@ export class MatrixClientService implements OnDestroy {
    */
   async connectSession(accessToken: string, userId: string, deviceId?: string): Promise<void> {
     if (!accessToken || !userId) {
-      throw new Error('Matrix 凭据不完整(缺 accessToken 或 userId)');
+      throw new Error('登录凭据不完整,请重新进入');
     }
     // 同身份重复调用:幂等,不打断现有 sync
     if (this.client && this.token === accessToken && this._userId() === userId) {
@@ -520,7 +520,7 @@ export class MatrixClientService implements OnDestroy {
     // ① 上传到媒体库 → mxc://
     const upload = await c.uploadContent(blob, { name: card.name, type: card.mimeType });
     const mxc = upload.content_uri;
-    if (!mxc) throw new Error('附件上传到 Matrix 失败(没有返回地址)');
+    if (!mxc) throw new Error('附件上传失败(没有返回地址)');
 
     // ② 发原生附件事件。图片用 m.image(客户端可直接内联显示),其余用 m.file
     const isImage = card.mimeType.startsWith('image/');
@@ -871,7 +871,7 @@ export class MatrixClientService implements OnDestroy {
   }
 
   private requireClient(): MatrixClient {
-    if (!this.client) throw new Error('Matrix 客户端未连接');
+    if (!this.client) throw new Error('尚未连接,请稍后重试');
     return this.client;
   }
 

+ 14 - 1
src/app/ui/components/switch/switch.ts

@@ -31,7 +31,15 @@ export class UiSwitch {
     return [
       'relative inline-flex shrink-0 items-center rounded-full transition-colors duration-200',
       'disabled:pointer-events-none disabled:opacity-50',
-      this.checked() ? 'bg-primary' : 'bg-edge-strong',
+      /*
+       * 关闭态用 --surface-active 而不是 --edge-strong(2026-11-01 深色模式修正)。
+       *
+       * --edge-strong 在深色主题下是 #454b56,但白色圆点压在它上面时,
+       * 两者亮度接近 —— 开关看起来像「一团白」,分不清是开还是关(用户截图反馈)。
+       * --surface-active 是「比背景深一层」的中性色,在明暗两套主题下
+       * 都能与白色圆点形成明确边界。
+       */
+      this.checked() ? 'bg-primary' : 'bg-surface-active',
       sizes[this.size()],
     ].join(' ');
   });
@@ -42,6 +50,11 @@ export class UiSwitch {
     const x = this.checked() ? (sm ? 'translate-x-4' : 'translate-x-5') : 'translate-x-0.5';
     return [
       'pointer-events-none inline-flex items-center justify-center rounded-full bg-white shadow-sm',
+      /*
+       * 圆点加一圈极淡描边:深色主题下白色圆点与深轨道之间缺少过渡时会发虚,
+       * 描边让它的边界更实(1px,颜色取页面边框色)。
+       */
+      'ring-1 ring-black/5',
       'transition-transform duration-200',
       knob,
       x,