feat(flutter): 应用浅色暖橙视觉主题
This commit is contained in:
1 parent
0d2367431d
commit
634b63e16c
56 files changed
+941
-409
No files matched your search
@@ -6,79 +6,62 @@ import 'package:flutter/services.dart';
|
||||
import 'app_colors.dart';
|
||||
import 'app_dimens.dart';
|
||||
|
||||
/// Obsidian Flare themes. Dark is the product default; light mirrors the same
|
||||
/// orange primary for system-light devices.
|
||||
/// K28-S 浅色暖橙主题。
|
||||
abstract final class AppTheme {
|
||||
static const _lightBackground = Color(0xFFF7F7F8);
|
||||
static const _darkBackground = AppColors.ink;
|
||||
|
||||
/// Light theme for system light mode.
|
||||
static ThemeData light() => _build(
|
||||
brightness: Brightness.light,
|
||||
surface: _lightBackground,
|
||||
accent: AppColors.blue,
|
||||
/// 页面顶部暖色到米白背景的渐变。
|
||||
static const LinearGradient pageGradient = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [AppColors.surfaceTop, AppColors.ink],
|
||||
stops: [0, 0.24],
|
||||
);
|
||||
|
||||
/// Dark theme for system dark mode.
|
||||
static ThemeData dark() => _build(
|
||||
brightness: Brightness.dark,
|
||||
surface: _darkBackground,
|
||||
accent: AppColors.blue,
|
||||
/// 卡片轻阴影。
|
||||
static const BoxShadow cardShadow = BoxShadow(
|
||||
color: AppColors.cardShadow,
|
||||
blurRadius: AppDimens.cardShadowBlur,
|
||||
offset: Offset(0, AppDimens.cardShadowY),
|
||||
);
|
||||
|
||||
static ThemeData _build({
|
||||
required Brightness brightness,
|
||||
required Color surface,
|
||||
required Color accent,
|
||||
}) {
|
||||
final dark = brightness == Brightness.dark;
|
||||
final scheme = dark
|
||||
? const ColorScheme.dark(
|
||||
primary: AppColors.blue,
|
||||
onPrimary: AppColors.onPrimary,
|
||||
secondary: AppColors.secondary,
|
||||
onSecondary: AppColors.onPrimary,
|
||||
primaryContainer: AppColors.bluePressed,
|
||||
onPrimaryContainer: AppColors.onPrimary,
|
||||
secondaryContainer: AppColors.raised,
|
||||
onSecondaryContainer: AppColors.onPrimary,
|
||||
surface: _darkBackground,
|
||||
onSurface: AppColors.onSurface,
|
||||
outline: AppColors.outlineDark,
|
||||
outlineVariant: AppColors.outlineVariantDark,
|
||||
surfaceTint: AppColors.blue,
|
||||
inversePrimary: AppColors.blueSoft,
|
||||
)
|
||||
: ColorScheme.light(
|
||||
primary: AppColors.blue,
|
||||
onPrimary: AppColors.onPrimary,
|
||||
secondary: AppColors.secondary,
|
||||
onSecondary: AppColors.onPrimary,
|
||||
primaryContainer: AppColors.blue.withValues(alpha: 0.14),
|
||||
onPrimaryContainer: AppColors.ink,
|
||||
secondaryContainer: AppColors.blueSoft.withValues(alpha: 0.14),
|
||||
onSecondaryContainer: AppColors.ink,
|
||||
surface: _lightBackground,
|
||||
onSurface: AppColors.ink,
|
||||
outline: AppColors.outlineLight,
|
||||
outlineVariant: AppColors.outlineVariantLight,
|
||||
surfaceTint: AppColors.blue,
|
||||
inversePrimary: AppColors.blueSoft,
|
||||
);
|
||||
/// 全局浅色暖橙主题。
|
||||
static ThemeData light() {
|
||||
const scheme = ColorScheme.light(
|
||||
primary: AppColors.blue,
|
||||
onPrimary: AppColors.onPrimary,
|
||||
secondary: AppColors.secondary,
|
||||
onSecondary: AppColors.onPrimary,
|
||||
primaryContainer: AppColors.surfaceTop,
|
||||
onPrimaryContainer: AppColors.onSurface,
|
||||
secondaryContainer: AppColors.badgePink,
|
||||
onSecondaryContainer: AppColors.badgePinkText,
|
||||
surface: AppColors.ink,
|
||||
onSurface: AppColors.onSurface,
|
||||
outline: AppColors.border,
|
||||
outlineVariant: AppColors.border,
|
||||
surfaceTint: AppColors.blue,
|
||||
inversePrimary: AppColors.bluePressed,
|
||||
);
|
||||
final base = ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: brightness,
|
||||
brightness: Brightness.light,
|
||||
colorScheme: scheme,
|
||||
scaffoldBackgroundColor: surface,
|
||||
scaffoldBackgroundColor: AppColors.ink,
|
||||
fontFamily: 'PlusJakartaSans',
|
||||
progressIndicatorTheme: ProgressIndicatorThemeData(color: accent),
|
||||
sliderTheme: SliderThemeData(
|
||||
activeTrackColor: accent,
|
||||
progressIndicatorTheme: const ProgressIndicatorThemeData(
|
||||
color: AppColors.blue,
|
||||
),
|
||||
sliderTheme: const SliderThemeData(
|
||||
activeTrackColor: AppColors.blue,
|
||||
inactiveTrackColor: AppColors.border,
|
||||
thumbColor: AppColors.onPrimary,
|
||||
),
|
||||
tabBarTheme: TabBarThemeData(labelColor: accent, indicatorColor: accent),
|
||||
tabBarTheme: const TabBarThemeData(
|
||||
labelColor: AppColors.blue,
|
||||
indicatorColor: AppColors.blue,
|
||||
unselectedLabelColor: AppColors.muted,
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(foregroundColor: accent),
|
||||
style: TextButton.styleFrom(foregroundColor: AppColors.blue),
|
||||
),
|
||||
filledButtonTheme: FilledButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
@@ -87,25 +70,26 @@ abstract final class AppTheme {
|
||||
minimumSize: const WidgetStatePropertyAll(
|
||||
Size(0, AppDimens.buttonHeight),
|
||||
),
|
||||
shape: const WidgetStatePropertyAll(StadiumBorder()),
|
||||
),
|
||||
),
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
foregroundColor: WidgetStatePropertyAll(
|
||||
dark ? AppColors.blueSoft : AppColors.bluePressed,
|
||||
),
|
||||
foregroundColor: const WidgetStatePropertyAll(AppColors.blue),
|
||||
minimumSize: const WidgetStatePropertyAll(
|
||||
Size(0, AppDimens.buttonHeight),
|
||||
),
|
||||
side: WidgetStatePropertyAll(
|
||||
BorderSide(
|
||||
color: dark ? AppColors.outlineDark : AppColors.outlineLight,
|
||||
),
|
||||
side: const WidgetStatePropertyAll(
|
||||
BorderSide(color: AppColors.border),
|
||||
),
|
||||
shape: const WidgetStatePropertyAll(StadiumBorder()),
|
||||
),
|
||||
),
|
||||
appBarTheme: const AppBarTheme(
|
||||
systemOverlayStyle: SystemUiOverlayStyle.light,
|
||||
backgroundColor: AppColors.ink,
|
||||
foregroundColor: AppColors.onSurface,
|
||||
elevation: 0,
|
||||
systemOverlayStyle: SystemUiOverlayStyle.dark,
|
||||
titleTextStyle: TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontFamily: 'Outfit',
|
||||
@@ -113,6 +97,16 @@ abstract final class AppTheme {
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
iconTheme: const IconThemeData(color: AppColors.onSurface),
|
||||
dividerTheme: const DividerThemeData(color: AppColors.border),
|
||||
cardTheme: const CardThemeData(
|
||||
color: AppColors.card,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(AppDimens.cardRadius)),
|
||||
side: BorderSide(color: AppColors.border),
|
||||
),
|
||||
),
|
||||
switchTheme: SwitchThemeData(
|
||||
thumbColor: WidgetStateProperty.resolveWith(
|
||||
(states) => states.contains(WidgetState.selected)
|
||||
@@ -120,36 +114,35 @@ abstract final class AppTheme {
|
||||
: null,
|
||||
),
|
||||
trackColor: WidgetStateProperty.resolveWith(
|
||||
(states) => states.contains(WidgetState.selected) ? accent : null,
|
||||
(states) =>
|
||||
states.contains(WidgetState.selected) ? AppColors.blue : null,
|
||||
),
|
||||
),
|
||||
snackBarTheme: SnackBarThemeData(
|
||||
backgroundColor: AppColors.bluePressed,
|
||||
contentTextStyle: const TextStyle(color: AppColors.onPrimary),
|
||||
snackBarTheme: const SnackBarThemeData(
|
||||
backgroundColor: AppColors.onSurface,
|
||||
contentTextStyle: TextStyle(color: AppColors.onPrimary),
|
||||
),
|
||||
);
|
||||
final textTheme = base.textTheme
|
||||
.apply(
|
||||
fontFamily: 'PlusJakartaSans',
|
||||
bodyColor: dark ? AppColors.cream : AppColors.ink,
|
||||
displayColor: dark ? AppColors.onSurface : AppColors.ink,
|
||||
bodyColor: AppColors.cream,
|
||||
displayColor: AppColors.onSurface,
|
||||
)
|
||||
.copyWith(
|
||||
displayLarge: _display(base.textTheme.displayLarge, dark),
|
||||
displayMedium: _display(base.textTheme.displayMedium, dark),
|
||||
displaySmall: _display(base.textTheme.displaySmall, dark),
|
||||
headlineLarge: _display(base.textTheme.headlineLarge, dark),
|
||||
headlineMedium: _display(base.textTheme.headlineMedium, dark),
|
||||
headlineSmall: _display(base.textTheme.headlineSmall, dark),
|
||||
titleLarge: _display(base.textTheme.titleLarge, dark),
|
||||
displayLarge: _display(base.textTheme.displayLarge),
|
||||
displayMedium: _display(base.textTheme.displayMedium),
|
||||
displaySmall: _display(base.textTheme.displaySmall),
|
||||
headlineLarge: _display(base.textTheme.headlineLarge),
|
||||
headlineMedium: _display(base.textTheme.headlineMedium),
|
||||
headlineSmall: _display(base.textTheme.headlineSmall),
|
||||
titleLarge: _display(base.textTheme.titleLarge),
|
||||
);
|
||||
return base.copyWith(textTheme: textTheme);
|
||||
}
|
||||
|
||||
static TextStyle? _display(TextStyle? style, bool dark) => style?.copyWith(
|
||||
fontFamily: 'Outfit',
|
||||
color: dark ? AppColors.onSurface : AppColors.ink,
|
||||
);
|
||||
static TextStyle? _display(TextStyle? style) =>
|
||||
style?.copyWith(fontFamily: 'Outfit', color: AppColors.onSurface);
|
||||
|
||||
static Color _buttonColor(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.pressed) ||
|
||||
|
||||
Reference in new issue
Block a user