Files
photo-live/apps/mobile/test/app/theme_test.dart
T
浅念 6074fc8ed3 feat(ui06): App line A0-A7 — nav pill removal, light segments, bare summary, token alignment to app-preview
- tokens:次文字 #69778E、soft/card-border/seg 色组、输入圆角 10(kRadiusField)
- theme:导航 indicatorColor 透明+显式选中蓝;卡片去阴影改 1px #EDF0F5 边框;输入边框同步
- 新组件 SegmentTabs(#EDF1F6 轨道/选中实蓝/light 浅蓝变体/null 无高亮)替换 M3 SegmentedButton
- 上传中心:摘要去白卡直排+主数字 32/40;completed 次级筛选无高亮语义保留
- 相册卡 scrim 30% 起 #0C1728E8;导航角标红底白字白边;登录主标题 27/700
- theme_test 三处旧规格断言随 UI06 值更新;397/397 全绿、analyze 0 issues
- 真机证据:MuMu + 测试服务器 API,登录/相册/详情/上传 4 页截图确认达标
- 登记偏差:语义色保持对比度合规深色版;视口矩阵随 G2;详见验收记录 §6

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 08:09:20 +08:00

172 lines
6.0 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.
/// UI-01 主题一致性测试(Task 3)。
///
/// 覆盖:浅色 ColorScheme 方案 §3.1 精确值、深色语义对应值、字阶
/// (UI-03 §3 校准:24/17/16-14/13-12)、组件主题(按钮高 48/圆角 12、
/// 输入圆角 12、Dialog 圆角 16、BottomSheet 顶部圆角 16、AppBar
/// titleLarge)、动效令牌(含「减少动态效果」归零)。
library;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:photo_live/app/theme.dart';
import 'package:photo_live/ui/tokens.dart';
void main() {
group('浅色 ColorScheme(方案 §3.1 精确值)', () {
final scheme = AppTheme.light.colorScheme;
test('基础色', () {
expect(scheme.primary, const Color(0xFF1A73E8));
expect(scheme.onPrimary, const Color(0xFFFFFFFF));
expect(scheme.surface, const Color(0xFFFFFFFF));
expect(scheme.onSurface, const Color(0xFF172033));
expect(scheme.secondary, const Color(0xFF996300), reason: '等待色');
expect(scheme.error, const Color(0xFFB42318));
// 成功色不进 ColorScheme(独立令牌)。
expect(kColorSuccess, const Color(0xFF16794B));
});
test('页面背景与分隔线/次文字', () {
expect(AppTheme.light.scaffoldBackgroundColor, const Color(0xFFF6F8FB));
expect(AppTheme.light.dividerTheme.color, kColorDivider);
expect(kColorDivider, const Color(0xFFE5EAF1));
expect(scheme.onSurfaceVariant, kColorTextSecondary);
expect(kColorTextSecondary, const Color(0xFF69778E)); // UI06: app-preview --muted
});
});
group('深色 ColorScheme(语义对应,不反转图片)', () {
final theme = AppTheme.dark;
final scheme = theme.colorScheme;
test('深表面 + 浅文字 + 提亮主色', () {
expect(scheme.brightness, Brightness.dark);
expect(scheme.surface, const Color(0xFF1F2530));
expect(scheme.onSurface, const Color(0xFFE6EAF2));
expect(scheme.primary, kColorInfoDark);
expect(scheme.onPrimary, const Color(0xFF0B2E6F));
expect(theme.scaffoldBackgroundColor, const Color(0xFF12161D));
});
test('等待/错误为深色提亮变体', () {
expect(scheme.secondary, kColorWaitingDark);
expect(scheme.error, kColorErrorDark);
});
});
group('字阶(随系统缩放:fontSize 走 TextScaler)', () {
final textTheme = AppTheme.light.textTheme;
test('24 页面标题 / 17 分组 / 16-14 正文 / 13-12 辅助', () {
expect(textTheme.titleLarge!.fontSize, 24);
expect(textTheme.titleMedium!.fontSize, 17);
expect(textTheme.bodyLarge!.fontSize, 16);
expect(textTheme.bodyMedium!.fontSize, 14);
expect(textTheme.bodySmall!.fontSize, 13);
expect(textTheme.labelSmall!.fontSize, 12);
});
test('AppBar 标题用 titleLarge', () {
expect(AppTheme.light.appBarTheme.titleTextStyle!.fontSize, 24);
});
});
group('组件主题', () {
final theme = AppTheme.light;
test('按钮高 48、圆角 12', () {
final filled = theme.filledButtonTheme.style;
expect(
filled!.minimumSize!.resolve(const <WidgetState>{}),
const Size(64, 48),
);
expect(
theme.elevatedButtonTheme.style!.minimumSize!.resolve(
const <WidgetState>{},
),
const Size(64, 48),
);
final shape =
filled.shape!.resolve(const <WidgetState>{})
as RoundedRectangleBorder;
expect(shape.borderRadius, BorderRadius.circular(kRadiusInput));
expect(
theme.outlinedButtonTheme.style!.minimumSize!.resolve(
const <WidgetState>{},
),
const Size(48, 48),
);
expect(
theme.textButtonTheme.style!.minimumSize!.resolve(
const <WidgetState>{},
),
const Size(48, 48),
);
});
test('输入框圆角 10(UI06: app-preview .field)', () {
final border = theme.inputDecorationTheme.border as OutlineInputBorder;
expect(border.borderRadius, BorderRadius.circular(kRadiusField));
expect(kRadiusField, 10);
});
test('Dialog 圆角 16、BottomSheet 顶部圆角 16', () {
final dialog = theme.dialogTheme.shape as RoundedRectangleBorder;
expect(dialog.borderRadius, BorderRadius.circular(kRadiusCard));
final sheet = theme.bottomSheetTheme.shape as RoundedRectangleBorder;
expect(
(sheet.borderRadius as BorderRadius).topLeft,
const Radius.circular(kRadiusCard),
);
expect(
(sheet.borderRadius as BorderRadius).topRight,
const Radius.circular(kRadiusCard),
);
expect(kRadiusCard, 16);
});
test('底部导航无胶囊指示器(UI06: app-preview .nav)', () {
expect(theme.navigationBarTheme.indicatorColor, Colors.transparent);
});
});
group('动效令牌', () {
testWidgets('默认轻量 180ms / 轮播 300ms / 减少动态效果归零', (tester) async {
expect(kMotionFast, const Duration(milliseconds: 180));
expect(kMotionCarousel, const Duration(milliseconds: 300));
expect(kMotionReduce, Duration.zero);
late BuildContext captured;
await tester.pumpWidget(
MaterialApp(
home: Builder(
builder: (context) {
captured = context;
return const SizedBox.shrink();
},
),
),
);
expect(motion(captured), kMotionFast);
expect(motion(captured, carousel: true), kMotionCarousel);
// 「减少动态效果」开启 → 一律归零。
await tester.pumpWidget(
MaterialApp(
home: MediaQuery(
data: const MediaQueryData(disableAnimations: true),
child: Builder(
builder: (context) {
captured = context;
return const SizedBox.shrink();
},
),
),
),
);
expect(motion(captured), kMotionReduce);
expect(motion(captured, carousel: true), kMotionReduce);
});
});
}