diff --git a/client/lib/state/update_provider.dart b/client/lib/state/update_provider.dart index e52b2c7..340fce7 100644 --- a/client/lib/state/update_provider.dart +++ b/client/lib/state/update_provider.dart @@ -47,11 +47,20 @@ class AppUpdateInfo { /// 更新检查 Notifier。build() 惰性触发:延迟首查 + 每小时轮询。 class UpdateNotifier extends AsyncNotifier { Timer? _timer; + Timer? _initialTimer; @override Future build() async { - ref.onDispose(() => _timer?.cancel()); - await Future.delayed(_kInitialDelay); + // 两个 timer 都在 onDispose 取消。初始延迟用可取消的 Timer(而非 + // Future.delayed:其内部 timer 无法取消,provider 在延迟期间被 dispose + // 时会悬挂 → widget 测试报 pending timer、生产留资源)。 + ref.onDispose(() { + _initialTimer?.cancel(); + _timer?.cancel(); + }); + final ready = Completer(); + _initialTimer = Timer(_kInitialDelay, ready.complete); + await ready.future; // 若延迟期间被 dispose,_initialTimer 取消 → 永不 complete,build 中止 final first = await _check(); _timer = Timer.periodic(_kPollInterval, (_) async { state = AsyncValue.data(await _check()); diff --git a/client/test/flutter_test_config.dart b/client/test/flutter_test_config.dart index 04070c7..4388616 100644 --- a/client/test/flutter_test_config.dart +++ b/client/test/flutter_test_config.dart @@ -20,6 +20,9 @@ Future testExecutable(FutureOr Function() testMain) async { 'test/fonts/Manrope-Bold.ttf', ]); await _load('JetBrains Mono', const ['test/fonts/JetBrainsMono-Regular.ttf']); + // Noto Sans SC 子集(= 生产打包同一 client/fonts/ 子集):golden 中文用真字体渲染, + // 不出豆腐块、与真机一致(family 须匹配 PangolinFonts.cjk = 'Noto Sans SC')。 + await _load('Noto Sans SC', const ['test/fonts/NotoSansSC-Regular-subset.otf']); // Lucide 图标字体(family 须带 package 前缀以匹配 PangolinIcons 的 fontPackage)。 await _load('packages/lucide_icons/Lucide', const ['packages/lucide_icons_patched/fonts/lucide.ttf']); await testMain(); diff --git a/client/test/fonts/NotoSansSC-Regular-subset.otf b/client/test/fonts/NotoSansSC-Regular-subset.otf new file mode 100644 index 0000000..a75251c Binary files /dev/null and b/client/test/fonts/NotoSansSC-Regular-subset.otf differ diff --git a/client/test/golden/goldens/auth_login_dark.png b/client/test/golden/goldens/auth_login_dark.png index 7371672..6e6af25 100644 Binary files a/client/test/golden/goldens/auth_login_dark.png and b/client/test/golden/goldens/auth_login_dark.png differ diff --git a/client/test/golden/goldens/auth_login_light.png b/client/test/golden/goldens/auth_login_light.png index 484fe64..937e511 100644 Binary files a/client/test/golden/goldens/auth_login_light.png and b/client/test/golden/goldens/auth_login_light.png differ diff --git a/client/test/golden/goldens/connect_off_dark.png b/client/test/golden/goldens/connect_off_dark.png index 23877ad..cdb3043 100644 Binary files a/client/test/golden/goldens/connect_off_dark.png and b/client/test/golden/goldens/connect_off_dark.png differ diff --git a/client/test/golden/goldens/connect_off_light.png b/client/test/golden/goldens/connect_off_light.png index d2dba96..6190ca8 100644 Binary files a/client/test/golden/goldens/connect_off_light.png and b/client/test/golden/goldens/connect_off_light.png differ diff --git a/client/test/golden/goldens/connect_on_dark.png b/client/test/golden/goldens/connect_on_dark.png index 9047bd6..942fa71 100644 Binary files a/client/test/golden/goldens/connect_on_dark.png and b/client/test/golden/goldens/connect_on_dark.png differ diff --git a/client/test/golden/goldens/connect_on_light.png b/client/test/golden/goldens/connect_on_light.png index c806383..5035931 100644 Binary files a/client/test/golden/goldens/connect_on_light.png and b/client/test/golden/goldens/connect_on_light.png differ diff --git a/client/test/golden/goldens/desktop_account.png b/client/test/golden/goldens/desktop_account.png index 545616c..ba0eca3 100644 Binary files a/client/test/golden/goldens/desktop_account.png and b/client/test/golden/goldens/desktop_account.png differ diff --git a/client/test/golden/goldens/desktop_contact.png b/client/test/golden/goldens/desktop_contact.png index c180eac..1d67bc9 100644 Binary files a/client/test/golden/goldens/desktop_contact.png and b/client/test/golden/goldens/desktop_contact.png differ diff --git a/client/test/golden/goldens/desktop_devices.png b/client/test/golden/goldens/desktop_devices.png index c3adbda..fa38eb0 100644 Binary files a/client/test/golden/goldens/desktop_devices.png and b/client/test/golden/goldens/desktop_devices.png differ diff --git a/client/test/golden/goldens/desktop_plans.png b/client/test/golden/goldens/desktop_plans.png index 26ad4db..4c0a4fa 100644 Binary files a/client/test/golden/goldens/desktop_plans.png and b/client/test/golden/goldens/desktop_plans.png differ diff --git a/client/test/golden/goldens/desktop_redeem.png b/client/test/golden/goldens/desktop_redeem.png index de35588..0f2fe8c 100644 Binary files a/client/test/golden/goldens/desktop_redeem.png and b/client/test/golden/goldens/desktop_redeem.png differ diff --git a/client/test/golden/goldens/desktop_servers.png b/client/test/golden/goldens/desktop_servers.png index a49f2b2..68addd3 100644 Binary files a/client/test/golden/goldens/desktop_servers.png and b/client/test/golden/goldens/desktop_servers.png differ diff --git a/client/test/golden/goldens/desktop_settings.png b/client/test/golden/goldens/desktop_settings.png index 4016bd3..e3d5c7a 100644 Binary files a/client/test/golden/goldens/desktop_settings.png and b/client/test/golden/goldens/desktop_settings.png differ diff --git a/client/test/golden/goldens/desktop_stats.png b/client/test/golden/goldens/desktop_stats.png index aa9a11c..427ec83 100644 Binary files a/client/test/golden/goldens/desktop_stats.png and b/client/test/golden/goldens/desktop_stats.png differ diff --git a/client/test/golden/goldens/quota_exhausted_dark.png b/client/test/golden/goldens/quota_exhausted_dark.png index fb38683..6e082bb 100644 Binary files a/client/test/golden/goldens/quota_exhausted_dark.png and b/client/test/golden/goldens/quota_exhausted_dark.png differ diff --git a/client/test/golden/goldens/quota_exhausted_light.png b/client/test/golden/goldens/quota_exhausted_light.png index 547dbbb..d987372 100644 Binary files a/client/test/golden/goldens/quota_exhausted_light.png and b/client/test/golden/goldens/quota_exhausted_light.png differ diff --git a/client/test/golden/goldens/quota_low_dark.png b/client/test/golden/goldens/quota_low_dark.png index 60ca44a..0179d15 100644 Binary files a/client/test/golden/goldens/quota_low_dark.png and b/client/test/golden/goldens/quota_low_dark.png differ diff --git a/client/test/golden/goldens/quota_low_light.png b/client/test/golden/goldens/quota_low_light.png index 73cf10a..e5b58c7 100644 Binary files a/client/test/golden/goldens/quota_low_light.png and b/client/test/golden/goldens/quota_low_light.png differ diff --git a/client/test/golden/goldens/smart_card_dark.png b/client/test/golden/goldens/smart_card_dark.png index 3c7b425..a0ddccb 100644 Binary files a/client/test/golden/goldens/smart_card_dark.png and b/client/test/golden/goldens/smart_card_dark.png differ diff --git a/client/test/golden/goldens/smart_card_light.png b/client/test/golden/goldens/smart_card_light.png index 9a7b708..48649cb 100644 Binary files a/client/test/golden/goldens/smart_card_light.png and b/client/test/golden/goldens/smart_card_light.png differ diff --git a/client/test/golden/goldens/tablet_account_dark_zh.png b/client/test/golden/goldens/tablet_account_dark_zh.png index a33f1ee..16d848e 100644 Binary files a/client/test/golden/goldens/tablet_account_dark_zh.png and b/client/test/golden/goldens/tablet_account_dark_zh.png differ diff --git a/client/test/golden/goldens/tablet_account_light_en.png b/client/test/golden/goldens/tablet_account_light_en.png index fc83634..d6bf07d 100644 Binary files a/client/test/golden/goldens/tablet_account_light_en.png and b/client/test/golden/goldens/tablet_account_light_en.png differ diff --git a/client/test/golden/goldens/tablet_account_light_zh.png b/client/test/golden/goldens/tablet_account_light_zh.png index 5b11aeb..c7feea9 100644 Binary files a/client/test/golden/goldens/tablet_account_light_zh.png and b/client/test/golden/goldens/tablet_account_light_zh.png differ diff --git a/client/test/golden/goldens/tablet_connect_dark_zh.png b/client/test/golden/goldens/tablet_connect_dark_zh.png index 3414650..31d6cfa 100644 Binary files a/client/test/golden/goldens/tablet_connect_dark_zh.png and b/client/test/golden/goldens/tablet_connect_dark_zh.png differ diff --git a/client/test/golden/goldens/tablet_connect_light_en.png b/client/test/golden/goldens/tablet_connect_light_en.png index 7a2e8d2..a5d56c1 100644 Binary files a/client/test/golden/goldens/tablet_connect_light_en.png and b/client/test/golden/goldens/tablet_connect_light_en.png differ diff --git a/client/test/golden/goldens/tablet_connect_light_zh.png b/client/test/golden/goldens/tablet_connect_light_zh.png index 8fb8595..9ba545c 100644 Binary files a/client/test/golden/goldens/tablet_connect_light_zh.png and b/client/test/golden/goldens/tablet_connect_light_zh.png differ diff --git a/client/test/golden/goldens/tablet_servers_dark_zh.png b/client/test/golden/goldens/tablet_servers_dark_zh.png index 9526bb2..3570bec 100644 Binary files a/client/test/golden/goldens/tablet_servers_dark_zh.png and b/client/test/golden/goldens/tablet_servers_dark_zh.png differ diff --git a/client/test/golden/goldens/tablet_servers_light_en.png b/client/test/golden/goldens/tablet_servers_light_en.png index f0a14c5..664c5d9 100644 Binary files a/client/test/golden/goldens/tablet_servers_light_en.png and b/client/test/golden/goldens/tablet_servers_light_en.png differ diff --git a/client/test/golden/goldens/tablet_servers_light_zh.png b/client/test/golden/goldens/tablet_servers_light_zh.png index 10ed931..3317bf1 100644 Binary files a/client/test/golden/goldens/tablet_servers_light_zh.png and b/client/test/golden/goldens/tablet_servers_light_zh.png differ diff --git a/client/test/golden/goldens/tablet_stats_dark_zh.png b/client/test/golden/goldens/tablet_stats_dark_zh.png index 3ab3c76..9b2a882 100644 Binary files a/client/test/golden/goldens/tablet_stats_dark_zh.png and b/client/test/golden/goldens/tablet_stats_dark_zh.png differ diff --git a/client/test/golden/goldens/tablet_stats_light_en.png b/client/test/golden/goldens/tablet_stats_light_en.png index ab7dcf0..0631b9f 100644 Binary files a/client/test/golden/goldens/tablet_stats_light_en.png and b/client/test/golden/goldens/tablet_stats_light_en.png differ diff --git a/client/test/golden/goldens/tablet_stats_light_zh.png b/client/test/golden/goldens/tablet_stats_light_zh.png index 8e71a30..e584957 100644 Binary files a/client/test/golden/goldens/tablet_stats_light_zh.png and b/client/test/golden/goldens/tablet_stats_light_zh.png differ diff --git a/client/test/golden/tablet_pages_golden_test.dart b/client/test/golden/tablet_pages_golden_test.dart index 1856836..b99b620 100644 --- a/client/test/golden/tablet_pages_golden_test.dart +++ b/client/test/golden/tablet_pages_golden_test.dart @@ -91,6 +91,15 @@ class _FakeMeNotifier extends MeNotifier { Future build() async => _demoMe; } +// 固定语言的 locale notifier:localeProvider 是 StateNotifierProvider,override 须返回 LocaleNotifier(子类)。构造后直接钉死 state 为目标语言 +// (prefs 在测试态为空,父类 _load() 不会改写)。 +class _FixedLocale extends LocaleNotifier { + _FixedLocale(AppLang lang) { + state = lang; + } +} + const Size _ipad = Size(1180, 820); // 对齐设计源 tabapp.jsx 内屏 Future _shoot( @@ -112,7 +121,7 @@ Future _shoot( tokenStoreProvider.overrideWithValue(const _NullTokenStore()), vpnBridgeProvider.overrideWithValue(VpnBridgeMock()), navViewProvider.overrideWith((ref) => view), - localeProvider.overrideWith((ref) => lang), + localeProvider.overrideWith((ref) => _FixedLocale(lang)), nodesProvider.overrideWith(_FakeNodesNotifier.new), meProvider.overrideWith(_FakeMeNotifier.new), usageProvider((days: 30, device: null)).overrideWith((ref) async => _demoUsage), diff --git a/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md b/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md index a4c3fe8..30144e1 100644 --- a/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md +++ b/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md @@ -89,12 +89,12 @@ Flutter 已很干净(UI 层零裸 hex),只需收尾。 - [x] 4.1 清 `client/lib/widgets/adaptive_menu.dart` 唯 1 处裸 Material 色 → 走 token -- [ ] 4.2 测试字体补 CJK 子集:用 `tools/fonts/make-cjk-subset.sh` 生成 Noto Sans SC 子集放 +- [x] 4.2 测试字体补 CJK 子集:用 `tools/fonts/make-cjk-subset.sh` 生成 Noto Sans SC 子集放 `client/test/fonts/`,`flutter_test_config.dart` 注册——消除 golden 中文与生产渲染差异 -- [ ] 4.3 处理现存 6 张 `client/test/golden/failures/` diff:逐张确认「原型对得上」后 `--update-goldens` 重录入库 +- [x] 4.3 处理现存 6 张 `client/test/golden/failures/` diff:逐张确认「原型对得上」后 `--update-goldens` 重录入库 - [ ] 4.4 golden 覆盖扩容:desktop/tablet/mobile 全屏 × light/dark 双主题矩阵 (现有 `desktop_pages/tablet_pages/components/auth` → 补 mobile + 主题维度) -- [ ] 4.5 `client/test/helpers/harness.dart` 对齐 jiu `golden_harness.dart` 手法: +- [x] 4.5 `client/test/helpers/harness.dart` 对齐 jiu `golden_harness.dart` 手法: 多主题循环辅助 + 钉死 viewport/dpr + ProviderScope 固定数据(防动态值翻车) --- diff --git a/todo/todo.html b/todo/todo.html index 2187bd2..89e068c 100644 --- a/todo/todo.html +++ b/todo/todo.html @@ -330,11 +330,11 @@ header .header-meta{color:var(--fg-soft)}
生成于 2026-07-07 · 真相源 todo/todo.json
18全部
-
9待开始
-
0开发中
+
8待开始
+
1开发中
1待验收
8已验收
-
1待确认
+
@@ -376,7 +376,7 @@ header .header-meta{color:var(--fg-soft)}
- 📋 待开始 9 + 📋 待开始 8 ▴ 收起
@@ -599,47 +599,6 @@ header .header-meta{color:var(--fg-soft)}
-
  • -
    - #19 - 前端设计系统治理重构(ds-flow 全端) -
    - 待开始 - 重要 - 一级 - - -
    -
    - -
    用 ds-flow 把 Flutter 五端+官网+用户中心收口到设计单源。补原型三件套(atoms.css/icons.js/index.html)+Web共享原子层去重(各自实现+同源闸)+硬编码色/fidelity闸+启用pre-commit。6阶段。计划见 docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md
    -
    -
    ⏸ 待确认 - 一级方案规划 · 确认后方可继续开发
    -
    6 阶段 ds-flow 治理重构:Phase0 CLAUDE.md+计划落库 / Phase1 原型三件套(atoms.css/icons.js/index.html,收敛ui_kits) / Phase2 Web token同源闸 / Phase3 Web共享原子层去重(各自实现+同源闸,★工作量最大) / Phase4 Flutter收尾+golden补齐 / Phase5 静态闸挂满+启用pre-commit+fidelity体检。已定决策:Web各自实现+同源闸、ui_kits收敛纯HTML、先定稿再逐刀。主题保持light/dark。
    📄 详见 docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md
    - - -
    - - -
  • -
  • - 🔨 开发中 0 + 🔨 开发中 1 ▴ 收起
      -

      暂无条目

      + +
    • +
      + #19 + 前端设计系统治理重构(ds-flow 全端) +
      + 开发中 + 重要 + 一级 + + +
      +
      + +
      用 ds-flow 把 Flutter 五端+官网+用户中心收口到设计单源。补原型三件套(atoms.css/icons.js/index.html)+Web共享原子层去重(各自实现+同源闸)+硬编码色/fidelity闸+启用pre-commit。6阶段。计划见 docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md
      +
      +
      ✓ 已确认 + 一级方案规划 + 2026-07-07
      +
      6 阶段 ds-flow 治理重构:Phase0 CLAUDE.md+计划落库 / Phase1 原型三件套(atoms.css/icons.js/index.html,收敛ui_kits) / Phase2 Web token同源闸 / Phase3 Web共享原子层去重(各自实现+同源闸,★工作量最大) / Phase4 Flutter收尾+golden补齐 / Phase5 静态闸挂满+启用pre-commit+fidelity体检。已定决策:Web各自实现+同源闸、ui_kits收敛纯HTML、先定稿再逐刀。主题保持light/dark。
      📄 详见 docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md
      +
      + + +
    diff --git a/todo/todo.json b/todo/todo.json index 53dfbcc..b20fc1b 100644 --- a/todo/todo.json +++ b/todo/todo.json @@ -1,7 +1,7 @@ { "meta": { "title": "feature+windows — 项目 TODO", - "updated_at": "2026-07-07T15:41:36.537Z" + "updated_at": "2026-07-07T15:54:54.457Z" }, "seq": 19, "items": [ @@ -304,7 +304,7 @@ "CI/CD" ], "owner": "agent", - "status": "open", + "status": "doing", "created_at": "2026-07-07T15:41:25.760Z", "done": false, "completed_at": null, @@ -313,9 +313,9 @@ "kind": "plan", "note": "6 阶段 ds-flow 治理重构:Phase0 CLAUDE.md+计划落库 / Phase1 原型三件套(atoms.css/icons.js/index.html,收敛ui_kits) / Phase2 Web token同源闸 / Phase3 Web共享原子层去重(各自实现+同源闸,★工作量最大) / Phase4 Flutter收尾+golden补齐 / Phase5 静态闸挂满+启用pre-commit+fidelity体检。已定决策:Web各自实现+同源闸、ui_kits收敛纯HTML、先定稿再逐刀。主题保持light/dark。", "ref": "docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md", - "approval": "pending", + "approval": "granted", "proposed_at": "2026-07-07T15:41:36.536Z", - "approved_at": null + "approved_at": "2026-07-07T15:54:54.386Z" } } ]