526 lines
18 KiB
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;
|
|
}
|
|
}
|