refactor(client): Phase 0.1 统一中文字体地基(golden 消豆腐块,可与原型保真比对)
- 打包 Noto Sans SC(pubspec fonts:),ThemeData.fontFamily 全平台统一 - golden_harness 用 FontLoader 注入 ttf + withGoldenFont,golden 渲染真实中文 - 修复 data_table_card 根因:DefaultTextStyle → .merge(替换式会吞掉继承字体, 导致所有表格屏表头/单元格渲染豆腐块);顺手 hover 硬编码色 → context.tokens.rowHover - 全部 golden 用新字体重生成;test/golden/failures/ 加入 gitignore Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TSKEiHsvauyxYUW2itzUXX
@@ -33,6 +33,9 @@ migrate_working_dir/
|
||||
/build/
|
||||
/coverage/
|
||||
|
||||
# Golden test diff artifacts (transient, regenerated on failure)
|
||||
test/golden/failures/
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ ThemeData buildTheme(String key) {
|
||||
brightness: brightness,
|
||||
colorScheme: scheme,
|
||||
scaffoldBackgroundColor: t.bg,
|
||||
fontFamily: null, // 系统中文字体;字号梯度后续在组件层接入
|
||||
// 全平台统一中文字体(与原型截图、golden 保真 diff 一致);打包内置。
|
||||
fontFamily: 'NotoSansSC',
|
||||
extensions: <ThemeExtension<dynamic>>[t],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class _DataTableCardState extends State<DataTableCard> {
|
||||
children: widget.columns.map((col) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: DefaultTextStyle(
|
||||
child: DefaultTextStyle.merge(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -187,10 +187,10 @@ class _DataTableCardState extends State<DataTableCard> {
|
||||
constraints: const BoxConstraints(minHeight: 48),
|
||||
alignment:
|
||||
col.numeric ? Alignment.centerRight : Alignment.centerLeft,
|
||||
color: hovered == rowIndex ? const Color(0xFFF5F7FF) : null,
|
||||
color: hovered == rowIndex ? context.tokens.rowHover : null,
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
child: DefaultTextStyle(
|
||||
child: DefaultTextStyle.merge(
|
||||
style: TextStyle(
|
||||
fontSize: 13, color: context.tokens.text),
|
||||
child: cell.child,
|
||||
|
||||
@@ -62,5 +62,11 @@ flutter:
|
||||
|
||||
assets:
|
||||
- assets/fonts/NotoSansSC-Regular.ttf
|
||||
- assets/fonts/NotoSansSC.ttf
|
||||
- assets/config/app_info.json
|
||||
- assets/brand/logo_mark.png
|
||||
|
||||
fonts:
|
||||
- family: NotoSansSC
|
||||
fonts:
|
||||
- asset: assets/fonts/NotoSansSC.ttf
|
||||
|
||||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 148 KiB |
@@ -1,8 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show rootBundle, FontLoader;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:jiu_client/core/theme/themes.dart';
|
||||
|
||||
// 加载真实中文字体(消除 golden 豆腐块),使 golden 能与原型截图做保真 diff。
|
||||
// 原型截图侧同样注入 Noto Sans SC(见 tools/fidelity.mjs),两边字体一致。
|
||||
bool _fontsLoaded = false;
|
||||
Future<void> ensureGoldenFonts() async {
|
||||
if (_fontsLoaded) return;
|
||||
final loader = FontLoader('NotoSansSC')
|
||||
..addFont(rootBundle.load('assets/fonts/NotoSansSC.ttf'));
|
||||
await loader.load();
|
||||
_fontsLoaded = true;
|
||||
}
|
||||
|
||||
/// 把 NotoSansSC 套到主题文字上(含 hardcoded TextStyle 经 DefaultTextStyle 继承)。
|
||||
ThemeData withGoldenFont(ThemeData base) => base.copyWith(
|
||||
textTheme: base.textTheme.apply(fontFamily: 'NotoSansSC'),
|
||||
primaryTextTheme: base.primaryTextTheme.apply(fontFamily: 'NotoSansSC'),
|
||||
);
|
||||
|
||||
/// design-distill 阶段4(Flutter 端)可复用 golden 骨架。
|
||||
/// 在指定主题 / viewport 下渲染 [child](含 provider 覆盖),比对/更新 golden。
|
||||
///
|
||||
@@ -23,6 +41,7 @@ Future<void> pumpGolden(
|
||||
Size logical = const Size(1280, 900),
|
||||
double dpr = 2.0,
|
||||
}) async {
|
||||
await ensureGoldenFonts();
|
||||
tester.view.physicalSize = Size(logical.width * dpr, logical.height * dpr);
|
||||
tester.view.devicePixelRatio = dpr;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
@@ -32,7 +51,7 @@ Future<void> pumpGolden(
|
||||
overrides: overrides,
|
||||
child: MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: buildTheme(theme),
|
||||
theme: withGoldenFont(buildTheme(theme)),
|
||||
home: child,
|
||||
),
|
||||
));
|
||||
|
||||