Skip to content

feat: 只加功能、不动架构(#53 返工版:多账号 / 四种登录方式 / 六渠道推送 / 日志页 / 深色模式) - #54

Merged
star620 merged 5 commits into
star620:mainfrom
akexin:feat/port-features
Oct 16, 2026
Merged

star620 merged 5 commits into
star620:mainfrom
akexin:feat/port-features

Conversation

@akexin

@akexin akexin commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

按你在 #53 的返工要求重做的版本:只加功能、不动你的架构。Android 不带(走 android 分支),version.json 未动(仍是 1.3.3)。

33 files changed, +4897 −212(16 个新文件 + 17 个文件的小增量改动)


一、你列的功能,逐条对应

功能 落点
多账号切换:账号列表 / 顶栏下拉 / 冷切换 ViewModels/MainViewModel.TopBar.cs + Views/MainWindow.axaml 顶栏一行「当前账号 + 下拉 + 切换」
四种登录方式 Views/LoginWindow.axaml(.cs):在原有「内嵌浏览器自动登录」「手动粘贴」之外新增 剪贴板智能识别 / 导入账号备份 / 读取本机 TRAE 客户端
六渠道推送 Services/Notify/*(调度 + SMTP + Webhook/钉钉/企业微信/Telegram + 系统通知);设置页新增配置区
日志页 ViewModels/LogViewModel.cs + Views/LogView.axaml(.cs),侧边栏新增「运行日志」入口
自定义设备号 ViewModels/SettingsViewModel.Extended.cs + 设置页新增区段(手填 16 位 + 唯一性校验 + 随机生成 + 一键换全部)

多账号切换没有另起一套:账号列表与选中项直接复用你的 SwitchViewModel.Accounts / SelectedAccount,执行也走它既有的 SwitchAccountCommand(内部即 TraeSwitcher 的冷切换编排)。顶栏只是把同一套能力提到任何页面都能用。

深色模式按你说的做:没有引入第二个配色表,而是把 Styles/AppTheme.axaml 从「单套硬编码浅色」改造为 ResourceDictionary.ThemeDictionaries,同一批语义色定义 Light / Dark 两套;新增 Services/ThemeService.cs 负责 ThemeMode(system/light/dark) 与 ThemeVariant 的映射;AppConfig 持久化 ThemeMode。


二、你要保留的实现,逐条 git diff --quiet 验证为零改动

✅ TraeTools.LoginHost/Program.cs
✅ TraeTools.LoginHost/TraeTools.LoginHost.csproj
✅ TraeTools.LoginHost/LoginHostForm.cs
✅ Services/Checkin/UpdaterService.cs        (cb573f2 的 zip 整包更新器 / 整套文件原子替换)
✅ Services/Switch/AuthProbe.cs
✅ Services/Switch/CarrierProfiler.cs
✅ Services/Switch/ClientController.cs
✅ Services/Switch/SwitcherService.cs
✅ Services/Switch/VaultService.cs
✅ version.json

Services/Json 的源生成不但保留,还把新功能里原先用反射 JSON 的地方全部改回源生成(见下)。


三、AppJson 补登记(你正文里点的那条)

补 [JsonSerializable] 的同时,顺手把新功能里违反 AOT/裁剪规范的写法全部改正 —— 原实现有 7 处 IL2026 警告:

原写法 问题 现在
推送渠道用匿名类型 new { msgtype = "text", … } 匿名类型无法被源生成器登记,裁剪/AOT 下静默丢字段 改具名 TextRobotPayload / TextRobotBody / TelegramSendPayload,登记进 CompactJsonContext
AccountBackup 用 JsonSerializer.SerializeToUtf8Bytes / Deserialize<T> 反射序列化 改 AppJson / AppJsonIndented;Envelope / Payload 由 private 改 internal 以便登记

Services/Json/ApiPayloads.cs 里你原有的类型一个没删。


四、验证

静态门禁(tools/port_gates.py,可直接复跑):

[OK] 主工程内反射式 JSON 0 处
[OK] 含绑定的视图全部带 x:DataType
[OK] 视图内 StaticResource 0 处
[OK] ViewLocator 为 7 个页面全部显式登记
[OK] 上游「必须保留」清单 10 项零改动
[OK] Release 编译 0 error / 0 warning(IL2026 / IL3050 均为 0)

CI 构建记录(windows-latest,build 作业全步骤绿,产物 trae-tools-build 74.28 MB):
https://github.com/akexin/TraeTools-Android/actions/runs/38723308949


五、两点需要你拍板

1. 你提到的主题系统,我在仓库里没找到

你说「上游这边刚做完一套主题系统(Styles/AppTheme.axaml 的 Light/Dark ThemeDictionaries + Services/ThemeService.cs + 配置持久化 ThemeMode)」,但我把上游全部分支(main / android / macos / p0-cost-cache-panel)都核对了一遍:

  • ThemeDictionaries 出现 0 次
  • Services/ThemeService.cs 不存在
  • AppConfig 里没有 ThemeMode
  • App.axaml 写的是 RequestedThemeVariant="Light"(写死浅色)
  • Styles/AppTheme.axaml 是单套硬编码 ARGB + StaticResource

所以我按你描述的形态去改:把那份单一配色改造成 Light/Dark 双字典。Light 的取值与改造前逐字一致,既有页面在浅色下外观零变化。

如果你本地已有一份还没推上来的实现,推上来我再对齐 —— 我这边只是把 Styles/AppTheme.axaml 一个文件改造成双字典,冲突面很小。

2. 为此改了 7 个视图里的 128 处 StaticResource → DynamicResource

这是让主题切换真正生效的必要条件:StaticResource 只在解析时查一次,主题切换后不会刷新。只换引用方式、不换取值,所以浅色外观与改造前完全一致(Views/{Checkin,Cloud,Dashboard,Switch,Usage}View.axaml 的 diff 都是 +N −N 一一对应)。

如果你不希望动这些既有视图,我可以回退这 128 处 —— 代价是切换主题时旧页面不跟随,只有新页面跟随。


六、明确没带的东西

  • Android(按你说的走 android 分支的独立工程方案)
  • 保活、账号简介 / 积分数据面板 —— 不在你的功能清单里,没有夹带
  • 你既有的飞书推送、设备码「一键换全部」、UpdaterService、Services/Switch 全部原样保留,只是新功能与它们并列

七、一个建议(本次没做)

Services/Checkin/AppConfig.cs 的 CloneForStorage() 是逐字段白名单:新增配置项漏加进白名单,该配置就永远不会落盘(表现是「改完重启就失效」)。我这次按最小改动同步补进了白名单(新增项都在),但这属于容易再踩的结构性坑 —— 改成「JSON 深拷贝 + 覆盖敏感字段」就能从根上消除。是否采纳由你定,我没有擅自改。

按维护者返工要求,只加功能、不动上游架构。本提交仅落服务层,UI 接入随后。

新增(全部为新文件):
- Services/AppLog.cs                统一日志(分级 + 内存环形缓冲 + 按月分文件)
- Services/Notify/NotifyDispatcher  推送扇出:互不影响 / 不静默 / 可开关
- Services/Notify/EmailNotifier     自定义 SMTP(可自定义端口与 ssl|starttls|none)
- Services/Notify/RobotNotifiers    通用 Webhook / 钉钉(含加签)/ 企业微信 / Telegram
- Services/Notify/SystemNotifier    系统本地通知(走 UiHost.MainWindow)
- Services/Login/CredentialImporter 会话 Cookie 导入 + 剪贴板智能识别
- Services/Login/LocalClientImporter 读取本机 TRAE 客户端凭证
- Services/Login/AccountBackup      账号导出/导入(PBKDF2 + AES-256-GCM,可跨机迁移)
- Services/Security/SecurityAudit   账号与本地安全检查(只读,不改数据)

修改上游文件(均为最小增量):
- Services/Checkin/AppConfig.cs    末尾追加主题/日志/六渠道配置项;新增 NormalizeTheme()
  并把新字段同步补进 CloneForStorage 白名单与 UnsealSecrets(推送凭证按密文落盘)
- Services/Checkin/TokenUtils.cs   纯新增 TryGetExpiry/TryReadExp/DecodePayload(+56 行)
- Services/Json/AppJson.cs         登记新增 JSON 类型(推送请求体、备份容器与负载)

遵循仓库既有规范:
- JSON 一律走 AppJson/AppJsonIndented 源生成,不引入反射序列化。
  原匿名类型无法被源生成器登记,改为具名类型(TextRobotPayload/TelegramSendPayload)。
  上游 AppConfig 的 DeviceId 非空可空不匹配(CS8601)一并修掉。
- 未触碰 TraeTools.LoginHost、Services/Switch/*、UpdaterService、version.json。

构建:dotnet build -c Release → 0 error / 0 warning(IL2026 与 CS8601 均为 0)。
日志页(维护者返工清单第 4 项):
- ViewModels/LogViewModel.cs  「最近」(内存缓冲 + 实时订阅)/「全部」(磁盘文件逐份查看)
- Views/LogView.axaml(.cs)    可选自动滚动;滚动在布局完成后排队执行,避免停在倒数第二行
- ViewLocator.cs              登记 LogViewModel → LogView(显式映射,AOT 安全)
- ViewModels/MainViewModel.cs 新增 _log 页面与 "log" 导航分支、IsLogActive
- Views/MainWindow.axaml      侧边栏新增「运行日志」入口(置于设置之前)

主题(Light/Dark 双套,仍只有一份配色表):
- Styles/AppTheme.axaml       从「单套硬编码浅色」改造为 ResourceDictionary.ThemeDictionaries,
  同一批语义色按 Light / Dark 定义。**Light 的取值与改造前逐字节一致**,
  因此既有页面在浅色下外观零变化;新增令牌(RowBg/StatusWarn*/Code*/HoverTint/渐变等)
  供新页面使用。组件样式改用 DynamicResource。
- Services/ThemeService.cs    新增:ThemeMode(system|light|dark) ↔ ThemeVariant 映射与应用
- App.axaml                   去掉写死的 RequestedThemeVariant="Light"(默认即跟随系统)
- App.axaml.cs                窗口创建前应用配置里的主题,避免先浅后深闪一帧
- Views/*.axaml(7 个) + App.axaml:StaticResource → DynamicResource 共 128 处。
  必须改:StaticResource 只在解析时查一次,主题切换后不刷新(改了才会跟随主题)。
  该改动只换引用方式、不换取值,浅色外观不变。

构建:dotnet build -c Release → 0 error / 0 warning。
维护者返工清单第 3、5 项(六渠道推送、自定义设备号)的界面部分。

新增(均为新文件,**上游 SettingsViewModel.cs 与 SettingsView.axaml 之外零改动**):
- ViewModels/SettingsViewModel.Extended.cs
  SettingsViewModel 的 partial 增量部分。刻意拆文件而不改上游那份 880 行的
  SettingsViewModel.cs,评审时一眼能分清新增与原有。内含:
    · 六渠道配置项:飞书(沿用既有 FeishuWebhook)/ 系统通知 / SMTP 邮箱(可自定义
      服务器与端口 + ssl|starttls|none)/ 通用 Webhook / 钉钉(含加签)/ 企业微信 / Telegram
    · 日志自动滚动、主题模式(切换即生效并落盘,不等保存按钮)
    · 自定义 16 位设备号:手填 + 唯一性校验(重复会触发风控 9074)+ 随机生成
    · 安全检查:调用 SecurityAudit.Run 并展示逐项结论
- Views/SettingsView.axaml 末尾追加四个卡片(推送通知 / 日志与外观 / 自定义设备号 /
  账号与本地安全检查);新增 xmlns:sec 用于安全结论的 DataTemplate x:DataType。

其它改动:
- ViewModels/MainViewModel.cs  构造时与每次进入设置页时调用 LoadExtendedSettings()
- ViewModels/LogViewModel.cs    进日志页时从配置同步「自动滚动」偏好(设置页可能改过)
- Views/SettingsView.axaml      文本框统一用 PlaceholderText(Watermark 在 Avalonia 12 已废弃)

构建:dotnet build -c Release → 0 error / 0 warning。
维护者返工清单第 1、2 项(多账号切换、四种登录方式)的界面部分。

登录页(Views/LoginWindow.axaml(.cs)):
- 新增三种方式,与既有「内嵌浏览器自动登录」「手动粘贴 Token」并列:
  · 从剪贴板智能识别(CredentialImporter:Token 直接用,会话串走 GetUserToken 换取)
  · 导入账号备份文件(StorageProvider 选文件 + 口令输入 → AccountBackup.Read,
    优先取 AccountUid 与当前账号一致的那一份)
  · 读取本机 TRAE 客户端登录态(LocalClientImporter)
- 新增 ApplyCredential 收口:设备号只在「本机其它账号都没用过」时写入 ——
  多账号共用同一设备号会被风控判为同一台机器并返回 9074。
- 窗口颜色由硬编码改为主题令牌;浅色取值与改造前逐字一致(RowBg 的浅色值已对齐
  登录窗口原有的 #FFF9FAFB),因此深色主题下本窗口同样跟随。
- 文案与自动登录一致地走「关闭窗口即成功」的返回约定。

顶栏账号下拉(ViewModels/MainViewModel.TopBar.cs + Views/MainWindow.axaml):
- 内容区顶部新增一行「当前账号 + 下拉 + 切换 + 当前生效提示」。
- **不另起一套切换实现**:账号列表与选中项直接复用上游 SwitchViewModel 的
  Accounts / SelectedAccount,执行走它既有的 SwitchAccountCommand
  (内部复用 TraeSwitch 的 SwitcherService 冷切换编排)。切换时先跳到账号切换页,
  好让 5 步进度与日志可见。
- MainViewModel.cs 仅加:构造时同步初始选中项、NotifyActiveAccountChanged 时刷新顶栏。

构建:dotnet build -c Release → 0 error / 0 warning。
把维护者提出的仓库规范落成可执行的 7 项门禁,便于评审时自行复跑:
  1. 主工程内反射式 JSON 清零(Services/Json 之外不许出现 JsonSerializer.*;
     TraeTools.LoginHost 是独立工程、不参与主工程编译,不在范围内)
  2. 含绑定的视图必须带 x:DataType
  3. 嵌套 DataTemplate 的绑定类型可推断(权威判据是门禁 7 的编译期零警告)
  4. 视图内不得残留 StaticResource(否则主题切换不生效)
  5. ViewLocator 为每个页面显式登记(AOT 下不许约定式反射)
  6. 上游「必须保留」清单零改动(LoginHost / UpdaterService / Services.Switch/* / version.json)
  7. Release 编译 0 error / 0 warning(裁剪与绑定分析的权威判据)

实测结果:7 项全部通过。
@akexin
akexin force-pushed the feat/port-features branch from 2a55be2 to af89983 Compare October 15, 2026 15:37
@akexin
akexin marked this pull request as ready for review October 15, 2026 15:41
star620 added a commit that referenced this pull request Oct 16, 2026
合并 PR #54(只加功能版)后,把本仓库原有的一套视觉与 UX 层重新接回,避免两套主题共存:外壳(无边框 + 真交通灯 + 标题栏含 ☾/☀ 快捷切换 + DWM 圆角,顶栏账号下拉并入内容区第二行);主题沿用 PR #54 的三态 ThemeMode 管线(system/light/dark + 设置页下拉),配色沿用本仓库原定取值(含暗色文字对比度调优),ThemeService 扩展 Normalize/ToVariant/Current/Modes;动效(页面交叉淡入、按钮/导航过渡、主题切换补间);滚动条(卡片内只留圆角滑块,用量统计列表显式 AllowAutoHide=False);屏蔽更新(UpdateGuard + 设置页「客户端更新」区段)。

顺带剔除编辑器误加的 UTF-8 BOM(Avalonia 的 XAML 预处理遇 BOM 会报 AVLN1001 导致整个构建失败)。
@star620
star620 merged commit 01b4eea into star620:main Oct 16, 2026
1 check passed

star620 commented Oct 16, 2026

Copy link
Copy Markdown
Owner

@akexin 已经合进 main 了,谢谢 —— 功能都在,git diff --quiet 核对过你列的「必须保留」清单,10 项确实零改动;tools/port_gates.py 也留下了,很好用。

说明一下 main 上比你的分支多出的那个提交(c55fb64),免得你看到 diff 困惑:

1. 主题我保留了你的管线,只换了取值。 ThemeMode 三态(system/light/dark)+ 设置页下拉 + ThemeService.Apply/Normalize/ToVariant/Current 全部照用;只把 AppTheme.axaml 里 Light/Dark 的取值换成了本仓库原定那套 —— 其中暗色正文用偏灰的 #D5DDE8 而不是接近纯白的 #EDF1FA,是之前专门调过对比度的(纯白在深蓝底上太刺眼)。你核对分支时说「上游没有主题系统」是对的,我这边那套当时还没推上去,让你多写了一份,抱歉。

2. 自绘外壳重新接回。 无边框窗口 + 左侧交通灯 + 标题栏(页面名 + ☾/☀ 快捷切换)是本仓库既有的设计,我把你的顶栏账号下拉移到了标题栏下面第二行,功能一个没少。

另外两点:

  • 我补回了本次改造从 AppTheme.axaml 丢掉的一批上游键(PanelBgBrush / NavHoverBrush / ScrollTrackBrush / StatusBar*Brush / Traffic*Brush 等)。弹窗和旧页面在引用这些键,DynamicResource 缺键是静默失效,界面上会表现为底色/描边直接消失,不容易在编译期发现。
  • 小提醒:.axaml 带 UTF-8 BOM 时 Avalonia 的 XAML 预处理会直接报 AVLN1001 并让整个构建失败(EulaWindow.axaml 就是这么挂的),我把仓库里的 BOM 统一剔了。你编辑器若有「保留 BOM」选项建议关掉。

star620 added a commit that referenced this pull request Oct 18, 2026
本次版本内容:多账号切换 / 四种登录方式 / 六渠道推送 / 运行日志页 / 自定义设备号(PR #54)+ 自绘无边框外壳 / 明暗主题与动效 / 卡片滚动条修正 / 屏蔽客户端更新。
star620 added a commit that referenced this pull request Oct 18, 2026
- 合并 main(PR #54:运行日志 / 通知推送 / 安全审计 / 账号备份,及自绘无边框外壳、
  明暗主题动效等视觉层),Android 分支落后 main 的部分全部补齐
- Android 外壳适配:
  · MainView 顶栏与导航条不再写死白色,改为主题感知配色(浅色主题下也清晰可读),
    导航条补上「运行日志」入口
  · 根工程补回 Android\** 排除项,避免主程序误编译 Android 源码
- Android 工程编译范围修正:保留 Services/Login/AccountBackup.cs
  (纯托管密码学实现,且被共享的 Services/Json/AppJson.cs 源生成上下文引用,排除即编译失败),
  仅排除与 Windows 客户端/登录宿主绑定的 CredentialImporter / LocalClientImporter / LoginHostClient
- Android CI/发版工作流:APK 收集改用递归通配符(按 ABI 输出到 <rid>/ 子目录),
  发版仅收集已签名 APK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants