前端修复: - calendar_page: 移除不存在的 JournalEntry.content getter - responsive_scaffold: 移除不存在的 notchThickness 参数 - splash_page: SingleTickerProvider → TickerProvider (多 AnimationController) - profile_page: UserRoleType.name → .code (修复运行时崩溃) - 导入缺失的 user.dart 后端修复: - class_service: generate_class_code 取 UUID 后6位(随机部分)避免碰撞 - diary_role_seed: 移除不存在的 id 列,使用复合主键 ON CONFLICT 基础设施: - config/default.toml: CORS 改为通配符(开发模式) - scripts/dev.sh: 统一启动脚本(自动清理端口) - docs/opendesign/: Open Design 设计规格 HTML 原型稿 验证结果: flutter analyze 0 error, cargo test 77/77 通过, 17个页面全部渲染正常
161 lines
4.8 KiB
Dart
161 lines
4.8 KiB
Dart
// 暖记主题入口 — 浅色/深色 ThemeData
|
|
// 对齐 Open Design 原型稿设计系统
|
|
|
|
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,
|
|
),
|
|
),
|
|
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.onSurfaceVariant,
|
|
backgroundColor: colorScheme.surface,
|
|
elevation: 8,
|
|
),
|
|
|
|
// Chip
|
|
chipTheme: ChipThemeData(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppRadius.pillBorder,
|
|
),
|
|
side: BorderSide.none,
|
|
),
|
|
|
|
// FloatingActionButton — 珊瑚色圆形凸起
|
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
|
backgroundColor: isLight ? AppColors.accent : AppColors.accentDark,
|
|
foregroundColor: isLight ? const Color(0xFFFFF8F0) : const Color(0xFF1A1614),
|
|
shape: const CircleBorder(),
|
|
elevation: 4,
|
|
),
|
|
|
|
// Page transitions — 弹性曲线 cubic-bezier(0.34, 1.56, 0.64, 1)
|
|
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,
|
|
);
|
|
}
|
|
}
|