mobile-eda/lib/core/theme/eda_theme.dart

526 lines
18 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
/// 主题模式枚举
enum ThemeModeType {
system, // 跟随系统
light, // 浅色模式
dark, // 深色模式
}
/// 主题配置提供者
final themeModeProvider = StateNotifierProvider<ThemeModeNotifier, ThemeModeType>(
(ref) => ThemeModeNotifier(),
);
/// 主题模式状态管理器
class ThemeModeNotifier extends StateNotifier<ThemeModeType> {
ThemeModeNotifier() : super(ThemeModeType.system);
/// 设置主题模式
void setThemeMode(ThemeModeType mode) {
state = mode;
}
/// 切换深色/浅色模式
void toggleDarkMode() {
state = state == ThemeModeType.dark ? ThemeModeType.light : ThemeModeType.dark;
}
/// 获取对应的 Flutter ThemeMode
ThemeMode get flutterThemeMode {
switch (state) {
case ThemeModeType.system:
return ThemeMode.system;
case ThemeModeType.light:
return ThemeMode.light;
case ThemeModeType.dark:
return ThemeMode.dark;
}
}
/// 判断是否为深色模式
bool get isDarkMode {
return state == ThemeModeType.dark;
}
}
/// EDA 专用主题配置
class EdaTheme {
// ========== 浅色主题配色 ==========
// 主色调 - EDA 行业常用蓝色系
static const Color lightPrimaryColor = Color(0xFF1976D2);
static const Color lightSecondaryColor = Color(0xFF42A5F5);
static const Color lightAccentColor = Color(0xFFFF9800);
// 背景色
static const Color lightScaffoldBg = Color(0xFFF5F5F5);
static const Color lightCanvasBg = Color(0xFFFAFAFA);
static const Color lightCardBg = Color(0xFFFFFFFF);
static const Color lightSurfaceBg = Color(0xFFFFFFFF);
// 网格颜色
static const Color lightGridColor = Color(0xFFE0E0E0);
static const Color lightGridDotColor = Color(0xFFBDBDBD);
// 元件颜色
static const Color lightComponentColor = Color(0xFF212121);
static const Color lightComponentBg = Color(0xFFFFFFFF);
static const Color lightPinColor = Color(0xFF424242);
static const Color lightWireColor = Color(0xFF1976D2);
// 选中/高亮颜色
static const Color lightSelectedColor = Color(0xFFFF9800);
static const Color lightHighlightColor = Color(0xFF4CAF50);
static const Color lightHoverColor = Color(0xFFE3F2FD);
// 文本颜色
static const Color lightTextPrimary = Color(0xFF212121);
static const Color lightTextSecondary = Color(0xFF757575);
static const Color lightTextHint = Color(0xFFBDBDBD);
// 边框/分割线颜色
static const Color lightBorderColor = Color(0xFFE0E0E0);
static const Color lightDividerColor = Color(0xFFEEEEEE);
// ========== 深色主题配色 ==========
// 主色调 - 保持品牌一致性,稍微降低饱和度
static const Color darkPrimaryColor = Color(0xFF42A5F5);
static const Color darkSecondaryColor = Color(0xFF64B5F6);
static const Color darkAccentColor = Color(0xFFFFB74D);
// 背景色 - 遵循 Material Design 深色主题规范
static const Color darkScaffoldBg = Color(0xFF121212);
static const Color darkCanvasBg = Color(0xFF1E1E1E);
static const Color darkCardBg = Color(0xFF1E1E1E);
static const Color darkSurfaceBg = Color(0xFF2D2D2D);
// 网格颜色 - 降低对比度避免视觉疲劳
static const Color darkGridColor = Color(0xFF333333);
static const Color darkGridDotColor = Color(0xFF424242);
// 元件颜色 - 提高亮度确保可见性
static const Color darkComponentColor = Color(0xFFE0E0E0);
static const Color darkComponentBg = Color(0xFF2D2D2D);
static const Color darkPinColor = Color(0xFFBDBDBD);
static const Color darkWireColor = Color(0xFF64B5F6);
// 选中/高亮颜色 - 提高饱和度
static const Color darkSelectedColor = Color(0xFFFFB74D);
static const Color darkHighlightColor = Color(0xFF81C784);
static const Color darkHoverColor = Color(0xFF424242);
// 文本颜色 - 遵循 Material Design 深色主题文本规范
static const Color darkTextPrimary = Color(0xFFE0E0E0);
static const Color darkTextSecondary = Color(0xFFB0B0B0);
static const Color darkTextHint = Color(0xFF757575);
// 边框/分割线颜色
static const Color darkBorderColor = Color(0xFF424242);
static const Color darkDividerColor = Color(0xFF333333);
/// 获取浅色主题
static ThemeData get lightTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.light,
colorScheme: const ColorScheme.light(
primary: lightPrimaryColor,
secondary: lightSecondaryColor,
tertiary: lightAccentColor,
surface: lightSurfaceBg,
error: Color(0xFFB00020),
onPrimary: Colors.white,
onSecondary: Colors.white,
onSurface: lightTextPrimary,
onError: Colors.white,
),
scaffoldBackgroundColor: lightScaffoldBg,
canvasColor: lightCanvasBg,
cardColor: lightCardBg,
dividerColor: lightDividerColor,
// AppBar 主题
appBarTheme: const AppBarTheme(
backgroundColor: lightPrimaryColor,
foregroundColor: Colors.white,
elevation: 2,
centerTitle: false,
titleTextStyle: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
// 卡片主题
cardTheme: CardTheme(
color: lightCardBg,
elevation: 2,
shadowColor: Colors.black12,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
// 按钮主题
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: lightPrimaryColor,
foregroundColor: Colors.white,
elevation: 2,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
// 文本字段主题
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: lightCardBg,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: lightBorderColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: lightBorderColor),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: lightPrimaryColor, width: 2),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Color(0xFFB00020)),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
// 文本主题
textTheme: const TextTheme(
displayLarge: TextStyle(color: lightTextPrimary, fontSize: 32, fontWeight: FontWeight.bold),
displayMedium: TextStyle(color: lightTextPrimary, fontSize: 28, fontWeight: FontWeight.bold),
displaySmall: TextStyle(color: lightTextPrimary, fontSize: 24, fontWeight: FontWeight.bold),
headlineLarge: TextStyle(color: lightTextPrimary, fontSize: 22, fontWeight: FontWeight.w600),
headlineMedium: TextStyle(color: lightTextPrimary, fontSize: 20, fontWeight: FontWeight.w600),
headlineSmall: TextStyle(color: lightTextPrimary, fontSize: 18, fontWeight: FontWeight.w600),
titleLarge: TextStyle(color: lightTextPrimary, fontSize: 16, fontWeight: FontWeight.w600),
titleMedium: TextStyle(color: lightTextPrimary, fontSize: 14, fontWeight: FontWeight.w500),
titleSmall: TextStyle(color: lightTextPrimary, fontSize: 12, fontWeight: FontWeight.w500),
bodyLarge: TextStyle(color: lightTextPrimary, fontSize: 16),
bodyMedium: TextStyle(color: lightTextPrimary, fontSize: 14),
bodySmall: TextStyle(color: lightTextSecondary, fontSize: 12),
labelLarge: TextStyle(color: lightTextPrimary, fontSize: 14, fontWeight: FontWeight.w500),
labelMedium: TextStyle(color: lightTextSecondary, fontSize: 12),
labelSmall: TextStyle(color: lightTextHint, fontSize: 10),
),
// 图标主题
iconTheme: const IconThemeData(
color: lightTextPrimary,
size: 24,
),
// 开关主题
switchTheme: SwitchThemeData(
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return lightPrimaryColor;
}
return Colors.grey;
}),
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return lightPrimaryColor.withOpacity(0.5);
}
return Colors.grey.shade300;
}),
),
// 复选框主题
checkboxTheme: CheckboxThemeData(
fillColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return lightPrimaryColor;
}
return Colors.transparent;
}),
),
// 单选按钮主题
radioTheme: RadioThemeData(
fillColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return lightPrimaryColor;
}
return Colors.grey;
}),
),
// 滑块主题
sliderTheme: SliderThemeData(
activeTrackColor: lightPrimaryColor,
inactiveTrackColor: lightPrimaryColor.withOpacity(0.3),
thumbColor: lightPrimaryColor,
overlayColor: lightPrimaryColor.withOpacity(0.12),
),
// 底部导航栏主题
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: lightCardBg,
selectedItemColor: lightPrimaryColor,
unselectedItemColor: lightTextSecondary,
type: BottomNavigationBarType.fixed,
elevation: 8,
),
// 导航抽屉主题
drawerTheme: const DrawerThemeData(
backgroundColor: lightCardBg,
),
// 对话框主题
dialogTheme: DialogTheme(
backgroundColor: lightCardBg,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
// 底部工作表主题
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: lightCardBg,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
),
);
}
/// 获取深色主题
static ThemeData get darkTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorScheme: const ColorScheme.dark(
primary: darkPrimaryColor,
secondary: darkSecondaryColor,
tertiary: darkAccentColor,
surface: darkSurfaceBg,
error: Color(0xFFCF6679),
onPrimary: Colors.black,
onSecondary: Colors.black,
onSurface: darkTextPrimary,
onError: Colors.black,
),
scaffoldBackgroundColor: darkScaffoldBg,
canvasColor: darkCanvasBg,
cardColor: darkCardBg,
dividerColor: darkDividerColor,
// AppBar 主题
appBarTheme: const AppBarTheme(
backgroundColor: darkSurfaceBg,
foregroundColor: darkTextPrimary,
elevation: 0,
centerTitle: false,
titleTextStyle: TextStyle(
color: darkTextPrimary,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
// 卡片主题
cardTheme: CardTheme(
color: darkCardBg,
elevation: 0,
shadowColor: Colors.black26,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(color: darkBorderColor, width: 1),
),
),
// 按钮主题
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: darkPrimaryColor,
foregroundColor: Colors.black,
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
// 文本字段主题
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: darkSurfaceBg,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: darkBorderColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: darkBorderColor),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: darkPrimaryColor, width: 2),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Color(0xFFCF6679)),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
// 文本主题
textTheme: const TextTheme(
displayLarge: TextStyle(color: darkTextPrimary, fontSize: 32, fontWeight: FontWeight.bold),
displayMedium: TextStyle(color: darkTextPrimary, fontSize: 28, fontWeight: FontWeight.bold),
displaySmall: TextStyle(color: darkTextPrimary, fontSize: 24, fontWeight: FontWeight.bold),
headlineLarge: TextStyle(color: darkTextPrimary, fontSize: 22, fontWeight: FontWeight.w600),
headlineMedium: TextStyle(color: darkTextPrimary, fontSize: 20, fontWeight: FontWeight.w600),
headlineSmall: TextStyle(color: darkTextPrimary, fontSize: 18, fontWeight: FontWeight.w600),
titleLarge: TextStyle(color: darkTextPrimary, fontSize: 16, fontWeight: FontWeight.w600),
titleMedium: TextStyle(color: darkTextPrimary, fontSize: 14, fontWeight: FontWeight.w500),
titleSmall: TextStyle(color: darkTextPrimary, fontSize: 12, fontWeight: FontWeight.w500),
bodyLarge: TextStyle(color: darkTextPrimary, fontSize: 16),
bodyMedium: TextStyle(color: darkTextPrimary, fontSize: 14),
bodySmall: TextStyle(color: darkTextSecondary, fontSize: 12),
labelLarge: TextStyle(color: darkTextPrimary, fontSize: 14, fontWeight: FontWeight.w500),
labelMedium: TextStyle(color: darkTextSecondary, fontSize: 12),
labelSmall: TextStyle(color: darkTextHint, fontSize: 10),
),
// 图标主题
iconTheme: const IconThemeData(
color: darkTextPrimary,
size: 24,
),
// 开关主题
switchTheme: SwitchThemeData(
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return darkPrimaryColor;
}
return Colors.grey;
}),
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return darkPrimaryColor.withOpacity(0.5);
}
return Colors.grey.shade700;
}),
),
// 复选框主题
checkboxTheme: CheckboxThemeData(
fillColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return darkPrimaryColor;
}
return Colors.transparent;
}),
),
// 单选按钮主题
radioTheme: RadioThemeData(
fillColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return darkPrimaryColor;
}
return Colors.grey;
}),
),
// 滑块主题
sliderTheme: SliderThemeData(
activeTrackColor: darkPrimaryColor,
inactiveTrackColor: darkPrimaryColor.withOpacity(0.3),
thumbColor: darkPrimaryColor,
overlayColor: darkPrimaryColor.withOpacity(0.12),
),
// 底部导航栏主题
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: darkSurfaceBg,
selectedItemColor: darkPrimaryColor,
unselectedItemColor: darkTextSecondary,
type: BottomNavigationBarType.fixed,
elevation: 8,
),
// 导航抽屉主题
drawerTheme: const DrawerThemeData(
backgroundColor: darkSurfaceBg,
),
// 对话框主题
dialogTheme: DialogTheme(
backgroundColor: darkSurfaceBg,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
// 底部工作表主题
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: darkSurfaceBg,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
),
);
}
/// 获取画布背景色(根据主题)
static Color getCanvasBg(BuildContext context) {
return Theme.of(context).brightness == Brightness.dark
? darkCanvasBg
: lightCanvasBg;
}
/// 获取网格颜色(根据主题)
static Color getGridColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.dark
? darkGridColor
: lightGridColor;
}
/// 获取元件颜色(根据主题)
static Color getComponentColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.dark
? darkComponentColor
: lightComponentColor;
}
/// 获取连线颜色(根据主题)
static Color getWireColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.dark
? darkWireColor
: lightWireColor;
}
/// 获取选中颜色(根据主题)
static Color getSelectedColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.dark
? darkSelectedColor
: lightSelectedColor;
}
}