feat: 后台托盘 + 资安信品牌化 + 修复布局断言(Phase 4 部分)

- 后台托盘(mac/Windows):window_manager 拦截关窗改隐藏,服务持续运行;
  托盘单击恢复窗口、右键菜单(显示主界面/退出),退出入口仅放托盘菜单
- 品牌:App 更名"资安信插件助手"(mac PRODUCT_NAME/xib、win main.cpp+Runner.rc(code_page 65001)、
  MaterialApp/侧栏/托盘 tooltip/日志);图标全家桶换资安信盾牌 logo
  (tool/gen_app_icons.dart 生成 mac AppIcon 7 尺寸/win ICO 7 尺寸/托盘白底圆盘版/assets logo)
- 修复启动布局断言:SliverList 内 Row(stretch) 需 IntrinsicHeight 包裹,
  否则子项收到 h=Infinity 约束(用户实测报错,test/ui_smoke_test.dart 守护复现)
- Agent.stop 幂等(托盘退出与窗口销毁竞态安全)
- 测试修复:smoke 测试改 tester.runAsync 包真实 socket I/O(fake async zone 里会永久挂起)、
  显式 pump 替代 pumpAndSettle;13 个测试全过,analyze 零问题,release 构建实测通过
This commit is contained in:
dzc committed 2026-09-21 13:16:23 +08:00
1 parent 0a78ff1b58
commit bee734fd5b
35 files changed
+1554 -196

No files matched your search

+36
View File
@@ -0,0 +1,36 @@
import 'package:desktop_plugin/agent.dart';
import 'package:desktop_plugin/ui/app_shell.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
/// UI 冒烟:真实装配 Agent + AppShell,捕获布局/渲染异常。
/// 注意:Agent 的端口绑定/关停是真实 socket I/O,必须放 tester.runAsync
/// 让真实 event loop 驱动(fake async zone 里 await 真实 I/O 会永久挂起)。
void main() {
testWidgets('AppShell + 饭卡打印机页布局无异常', (tester) async {
final agent = Agent(AgentOptions(mock: true, port: 38295));
await tester.runAsync(() => agent.start());
addTearDown(() => tester.runAsync(() => agent.stop()));
await tester.pumpWidget(MaterialApp(
theme: ThemeData(brightness: Brightness.dark, useMaterial3: true),
home: AppShell(agent: agent),
));
// 用显式 pump 推帧(不用 pumpAndSettle:页面含持续动画组件时在 fake clock 下永不能 settle)
await tester.pump(const Duration(milliseconds: 100));
await tester.pump(const Duration(milliseconds: 100));
await tester.pump(const Duration(milliseconds: 300));
expect(find.text('饭卡打印机'), findsWidgets);
expect(find.text('技术详情'), findsOneWidget);
// 展开技术详情,覆盖详情区(Table/日志)布局
await tester.tap(find.text('技术详情'));
await tester.pump(const Duration(milliseconds: 400));
await tester.pump(const Duration(milliseconds: 400));
// 显式停掉常驻 Timer(清理定时器),避免测试框架的 pending timer 断言
await tester.runAsync(() => agent.stop());
});
}