/// 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 {}), const Size(64, 48), ); expect( theme.elevatedButtonTheme.style!.minimumSize!.resolve( const {}, ), const Size(64, 48), ); final shape = filled.shape!.resolve(const {}) as RoundedRectangleBorder; expect(shape.borderRadius, BorderRadius.circular(kRadiusInput)); expect( theme.outlinedButtonTheme.style!.minimumSize!.resolve( const {}, ), const Size(48, 48), ); expect( theme.textButtonTheme.style!.minimumSize!.resolve( const {}, ), 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); }); }); }