Files
desktop-plugin/tool/gen_tray_icon.dart
T
dzc bee734fd5b 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 构建实测通过
2026-09-21 13:16:23 +08:00

60 lines
2.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 生成托盘图标(32x32 PNG)
// dart run tool/gen_tray_icon.dart
// - assets/tray_icon_template.png:macOS template 图标(纯黑+alpha,系统按菜单栏深浅自动反色)
// - assets/tray_icon_win.png:Windows 彩色图标(绿底+深色卡片剪影)
import 'dart:io';
import 'package:image/image.dart';
final _black = ColorRgba8(0, 0, 0, 255);
final _green = ColorRgba8(74, 222, 128, 255); // 主操作绿 #4ADE80
final _navy = ColorRgba8(15, 23, 42, 255); // 深蓝黑 #0F172A
bool _inRoundRect(int x, int y, int x0, int y0, int x1, int y1, int r) {
if (x < x0 || x > x1 || y < y0 || y > y1) return false;
final nearLeft = x < x0 + r, nearRight = x > x1 - r;
final nearTop = y < y0 + r, nearBottom = y > y1 - r;
if (!(nearLeft || nearRight) || !(nearTop || nearBottom)) return true; // 十字区
final cx = nearLeft ? x0 + r : x1 - r;
final cy = nearTop ? y0 + r : y1 - r;
final dx = x - cx, dy = y - cy;
return dx * dx + dy * dy <= r * r;
}
/// 卡片剪影(含磁条挖空)画到 img 上
void _drawCard(Image img, int x0, int y0, int x1, int y1, ColorUint8 color) {
const r = 2;
final stripeY0 = y0 + (y1 - y0 + 1) ~/ 3;
final stripeY1 = stripeY0 + 2;
for (var y = y0; y <= y1; y++) {
for (var x = x0; x <= x1; x++) {
if (!_inRoundRect(x, y, x0, y0, x1, y1, r)) continue;
if (y >= stripeY0 && y <= stripeY1) continue; // 磁条挖空
img.setPixel(x, y, color);
}
}
}
void main() {
// macOS template:透明底 + 黑卡片
final mac = Image(width: 32, height: 32, numChannels: 4);
_drawCard(mac, 5, 8, 26, 23, _black);
// Windows:绿色圆角底 + 深色卡片
final win = Image(width: 32, height: 32, numChannels: 4);
for (var y = 1; y <= 30; y++) {
for (var x = 1; x <= 30; x++) {
if (_inRoundRect(x, y, 1, 1, 30, 30, 6)) win.setPixel(x, y, _green);
}
}
_drawCard(win, 7, 9, 24, 22, _navy);
for (final entry in [('assets/tray_icon_template.png', mac), ('assets/tray_icon_win.png', win)]) {
final file = File(entry.$1);
file.parent.createSync(recursive: true);
file.writeAsBytesSync(encodePng(entry.$2));
// ignore: avoid_print
print('written ${entry.$1}');
}
}