新增:档案页共享组件三件 + TagPill 深变体映射(DEBT-1 偿还)

- PetAvatar 四尺寸档(96/64/44/32)收敛头像重复实现:3px 白描边 +
  轻投影,编辑徽标底改 primaryStrong(白图标 4.49:1 达非文字 3:1),
  M2 无上传(ADR-010),url 缺省渲染本地占位形态
- RecordTypeDot 三尺寸档 + 五类记录类型的图标/三色映射唯一出口
  (05 号规范 §2 表,供 T2-13/14 时间线复用)
- EmptyStateIllustration 空态插画区(112 圆 + 标题 + 说明 + 可选 CTA)
- TagPill 增可选 inkColor,缺省按 color 查深变体映射
  (primary→primaryDark 8.74:1 / success→successInk 7.39:1 /
  accent→accentDark 7.07:1 / error→errorDark 5.78:1 / 未命中→ink),
  既有调用零参数回归
- AppColors 新增 errorDark #B02C25、inkSoft #6B5A4A(05 号规范 D8)

flutter test 141/141 全绿;analyze 0 问题(T2-12 第一部分)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 11:57:31 +08:00
parent 7fb9031f8d
commit 3179528c57
9 changed files with 648 additions and 2 deletions
+72
View File
@@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:patbond_flutter/core/theme/app_theme.dart';
import 'package:patbond_flutter/core/widgets/pet_avatar.dart';
void main() {
Future<void> pump(WidgetTester tester, Widget child) {
return tester.pumpWidget(
MaterialApp(
home: Scaffold(body: Center(child: child)),
),
);
}
testWidgets('四档尺寸与规格一致(96/64/44/32', (tester) async {
expect(PetAvatarSize.xl.dimension, 96);
expect(PetAvatarSize.lg.dimension, 64);
expect(PetAvatarSize.md.dimension, 44);
expect(PetAvatarSize.sm.dimension, 32);
await pump(tester, const PetAvatar(size: PetAvatarSize.xl));
final size = tester.getSize(find.byType(PetAvatar));
expect(size.width, 96);
expect(size.height, 96);
});
testWidgets('无 url 渲染本地占位形态(ADR-010pets 图标)', (tester) async {
await pump(tester, const PetAvatar(size: PetAvatarSize.lg));
final icon = tester.widget<Icon>(find.byIcon(Icons.pets));
expect(icon.color, AppColors.muted);
expect(find.byType(Image), findsNothing);
});
testWidgets('xl 档编辑徽标为 primaryStrong 底白图标(无障碍修订)', (tester) async {
await pump(
tester,
const PetAvatar(size: PetAvatarSize.xl, showEditBadge: true),
);
final badgeIcon = tester.widget<Icon>(find.byIcon(Icons.edit));
expect(badgeIcon.color, Colors.white);
final badge = tester.widget<Container>(
find.ancestor(
of: find.byIcon(Icons.edit),
matching: find.byType(Container),
),
);
final decoration = badge.decoration as BoxDecoration;
expect(decoration.color, AppColors.primaryStrong);
});
testWidgets('sm/md 档不渲染编辑徽标', (tester) async {
await pump(
tester,
const PetAvatar(size: PetAvatarSize.sm, showEditBadge: true),
);
expect(find.byIcon(Icons.edit), findsNothing);
});
testWidgets('onTap 生效且禁用态不响应', (tester) async {
var taps = 0;
await pump(tester, PetAvatar(size: PetAvatarSize.lg, onTap: () => taps++));
await tester.tap(find.byType(PetAvatar));
expect(taps, 1);
await pump(
tester,
PetAvatar(size: PetAvatarSize.lg, enabled: false, onTap: () => taps++),
);
await tester.tap(find.byType(PetAvatar));
expect(taps, 1);
});
}