Files
nj/app/lib/core/theme/app_theme.dart
iven ee5ce9bc56 feat(app): 初始化 Flutter 前端项目 (Phase F0)
- Flutter 3.44.0 + Dart 3.12.0
- 设计系统: 7色Token×浅/深模式, NotoSansSC/Caveat字体, 圆角10/16/22/28/pill, 三级阴影
- ResponsiveScaffold: 手机底部TabBar / 平板侧边Rail / 桌面三栏
- go_router 路由表: 13个页面 (5个Tab + 8个全屏页面)
- 13个功能模块占位页面 (home/calendar/mood/search/profile/editor/auth/class/teacher/parent/achievement/stickers/templates)
- 依赖: flutter_bloc, go_router, freezed, isar, dio, perfect_freehand, fl_chart
- 中国镜像: PUB_HOSTED_URL + FLUTTER_STORAGE_BASE_URL
- flutter analyze: No issues found
2026-06-01 00:17:16 +08:00

160 lines
4.6 KiB
Dart

// 暖记主题入口 — 浅色/深色 ThemeData
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'app_colors.dart';
import 'app_typography.dart';
import 'app_radius.dart';
class AppTheme {
AppTheme._();
/// 浅色主题
static ThemeData light() => _buildTheme(AppColors.lightScheme());
/// 深色主题
static ThemeData dark() => _buildTheme(AppColors.darkScheme());
static ThemeData _buildTheme(ColorScheme colorScheme) {
final isLight = colorScheme.brightness == Brightness.light;
final textTheme = isLight
? AppTypography.lightTextTheme()
: AppTypography.darkTextTheme();
return ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
textTheme: textTheme,
scaffoldBackgroundColor: isLight ? AppColors.bgLight : AppColors.bgDark,
// AppBar
appBarTheme: AppBarTheme(
elevation: 0,
scrolledUnderElevation: 1,
centerTitle: true,
backgroundColor: isLight ? AppColors.bgLight : AppColors.bgDark,
foregroundColor: colorScheme.onSurface,
titleTextStyle: textTheme.titleLarge,
),
// Card
cardTheme: CardThemeData(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: AppRadius.mdBorder,
side: BorderSide(
color: colorScheme.outlineVariant.withValues(alpha: 0.3),
),
),
color: colorScheme.surface,
),
// ElevatedButton
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: AppRadius.smBorder,
),
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
textStyle: textTheme.labelLarge,
),
),
// OutlinedButton
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: AppRadius.smBorder,
),
side: BorderSide(color: colorScheme.primary),
textStyle: textTheme.labelLarge,
),
),
// InputDecoration
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: colorScheme.surfaceContainerHighest.withValues(alpha: 0.5),
border: OutlineInputBorder(
borderRadius: AppRadius.smBorder,
borderSide: BorderSide.none,
),
enabledBorder: OutlineInputBorder(
borderRadius: AppRadius.smBorder,
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: AppRadius.smBorder,
borderSide: BorderSide(
color: colorScheme.primary,
width: 2,
),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
// BottomNavigationBar
bottomNavigationBarTheme: BottomNavigationBarThemeData(
type: BottomNavigationBarType.fixed,
selectedItemColor: colorScheme.primary,
unselectedItemColor: colorScheme.onSurface.withValues(alpha: 0.5),
backgroundColor: colorScheme.surface,
elevation: 8,
),
// Chip
chipTheme: ChipThemeData(
shape: RoundedRectangleBorder(
borderRadius: AppRadius.pillBorder,
),
side: BorderSide.none,
),
// FloatingActionButton
floatingActionButtonTheme: FloatingActionButtonThemeData(
shape: RoundedRectangleBorder(
borderRadius: AppRadius.mdBorder,
),
elevation: 4,
),
// Page transitions — 弹性曲线
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: _WarmCurveBuilder(),
TargetPlatform.iOS: const CupertinoPageTransitionsBuilder(),
},
),
);
}
}
/// 暖记弹性页面转场: cubic-bezier(0.34, 1.56, 0.64, 1)
class _WarmCurveBuilder extends PageTransitionsBuilder {
const _WarmCurveBuilder();
static const Curve _warmCurve = Curves.easeOutBack;
@override
Widget buildTransitions<T>(
PageRoute<T> route,
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return SlideTransition(
position: animation.drive(
Tween(begin: const Offset(1.0, 0.0), end: Offset.zero)
.chain(CurveTween(curve: _warmCurve)),
),
child: child,
);
}
}