✨ Global theme color
This commit is contained in:
		| @@ -1,12 +1,14 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_animate/flutter_animate.dart'; | ||||
| import 'package:get/get.dart'; | ||||
| import 'package:shared_preferences/shared_preferences.dart'; | ||||
| import 'package:solian/exts.dart'; | ||||
| import 'package:solian/providers/auth.dart'; | ||||
| import 'package:solian/providers/content/channel.dart'; | ||||
| import 'package:solian/providers/relation.dart'; | ||||
| import 'package:solian/providers/websocket.dart'; | ||||
| import 'package:solian/services.dart'; | ||||
| import 'package:solian/theme.dart'; | ||||
| import 'package:solian/widgets/sized_container.dart'; | ||||
|  | ||||
| class BootstrapperShell extends StatefulWidget { | ||||
| @@ -29,6 +31,18 @@ class _BootstrapperShellState extends State<BootstrapperShell> { | ||||
|   int _periodCursor = 0; | ||||
|  | ||||
|   late final List<({String label, Future<void> Function() action})> _periods = [ | ||||
|     ( | ||||
|       label: 'bsLoadingTheme', | ||||
|       action: () async { | ||||
|         final prefs = await SharedPreferences.getInstance(); | ||||
|         if (prefs.containsKey('global_theme_color')) { | ||||
|           final value = prefs.getInt('global_theme_color')!; | ||||
|           final color = Color(value); | ||||
|           currentLightTheme = SolianTheme.build(Brightness.light, seedColor: color); | ||||
|           currentDarkTheme = SolianTheme.build(Brightness.dark, seedColor: color); | ||||
|         } | ||||
|       } | ||||
|     ), | ||||
|     ( | ||||
|       label: 'bsCheckingServer', | ||||
|       action: () async { | ||||
|   | ||||
| @@ -78,8 +78,8 @@ class SolianApp extends StatelessWidget { | ||||
|   Widget build(BuildContext context) { | ||||
|     return GetMaterialApp.router( | ||||
|       title: 'Solian', | ||||
|       theme: SolianTheme.build(Brightness.light), | ||||
|       darkTheme: SolianTheme.build(Brightness.dark), | ||||
|       theme: currentLightTheme, | ||||
|       darkTheme: currentDarkTheme, | ||||
|       themeMode: ThemeMode.system, | ||||
|       routerDelegate: AppRouter.instance.routerDelegate, | ||||
|       routeInformationParser: AppRouter.instance.routeInformationParser, | ||||
|   | ||||
| @@ -18,6 +18,7 @@ import 'package:solian/screens/realms/realm_organize.dart'; | ||||
| import 'package:solian/screens/realms/realm_view.dart'; | ||||
| import 'package:solian/screens/home.dart'; | ||||
| import 'package:solian/screens/posts/post_editor.dart'; | ||||
| import 'package:solian/screens/settings.dart'; | ||||
| import 'package:solian/shells/root_shell.dart'; | ||||
| import 'package:solian/shells/title_shell.dart'; | ||||
|  | ||||
| @@ -34,6 +35,22 @@ abstract class AppRouter { | ||||
|           _chatRoute, | ||||
|           _realmRoute, | ||||
|           _accountRoute, | ||||
|           GoRoute( | ||||
|             path: '/about', | ||||
|             name: 'about', | ||||
|             builder: (context, state) => TitleShell( | ||||
|               state: state, | ||||
|               child: const AboutScreen(), | ||||
|             ), | ||||
|           ), | ||||
|           GoRoute( | ||||
|             path: '/settings', | ||||
|             name: 'settings', | ||||
|             builder: (context, state) => TitleShell( | ||||
|               state: state, | ||||
|               child: const SettingScreen(), | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ], | ||||
| @@ -210,14 +227,6 @@ abstract class AppRouter { | ||||
|           name: state.pathParameters['name']!, | ||||
|         ), | ||||
|       ), | ||||
|       GoRoute( | ||||
|         path: '/about', | ||||
|         name: 'about', | ||||
|         builder: (context, state) => TitleShell( | ||||
|           state: state, | ||||
|           child: const AboutScreen(), | ||||
|         ), | ||||
|       ), | ||||
|     ], | ||||
|   ); | ||||
| } | ||||
|   | ||||
							
								
								
									
										81
									
								
								lib/screens/settings.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								lib/screens/settings.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| import 'dart:ui'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:get/get.dart'; | ||||
| import 'package:shared_preferences/shared_preferences.dart'; | ||||
| import 'package:solian/exts.dart'; | ||||
| import 'package:solian/theme.dart'; | ||||
|  | ||||
| class SettingScreen extends StatefulWidget { | ||||
|   const SettingScreen({super.key}); | ||||
|  | ||||
|   @override | ||||
|   State<SettingScreen> createState() => _SettingScreenState(); | ||||
| } | ||||
|  | ||||
| class _SettingScreenState extends State<SettingScreen> { | ||||
|   late final SharedPreferences _prefs; | ||||
|  | ||||
|   Widget _buildCaptionHeader(String title) { | ||||
|     return Container( | ||||
|       width: MediaQuery.of(context).size.width, | ||||
|       color: Theme.of(context).colorScheme.surfaceContainer, | ||||
|       padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), | ||||
|       child: Text(title), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   Widget _buildThemeColorButton(String label, Color color) { | ||||
|     return IconButton( | ||||
|       icon: Icon(Icons.circle, color: color), | ||||
|       tooltip: label, | ||||
|       onPressed: () { | ||||
|         currentLightTheme = | ||||
|             SolianTheme.build(Brightness.light, seedColor: color); | ||||
|         currentDarkTheme = SolianTheme.build(Brightness.dark, seedColor: color); | ||||
|         _prefs.setInt('global_theme_color', color.value); | ||||
|         context.showSnackbar('themeColorApplied'.tr); | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     SharedPreferences.getInstance().then((inst) { | ||||
|       _prefs = inst; | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Material( | ||||
|       color: Theme.of(context).colorScheme.surface, | ||||
|       child: ListView( | ||||
|         children: [ | ||||
|           _buildCaptionHeader('themeColor'.tr), | ||||
|           SizedBox( | ||||
|             height: 56, | ||||
|             child: ListView( | ||||
|               scrollDirection: Axis.horizontal, | ||||
|               children: [ | ||||
|                 _buildThemeColorButton( | ||||
|                   'themeColorRed'.tr, | ||||
|                   const Color.fromRGBO(154, 98, 91, 1), | ||||
|                 ), | ||||
|                 _buildThemeColorButton( | ||||
|                   'themeColorBlue'.tr, | ||||
|                   const Color.fromRGBO(103, 96, 193, 1), | ||||
|                 ), | ||||
|                 _buildThemeColorButton( | ||||
|                   'themeColorMiku'.tr, | ||||
|                   const Color.fromRGBO(56, 120, 126, 1), | ||||
|                 ), | ||||
|               ], | ||||
|             ).paddingSymmetric(horizontal: 12, vertical: 8), | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -1,6 +1,9 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:solian/platform.dart'; | ||||
|  | ||||
| ThemeData? currentLightTheme = SolianTheme.build(Brightness.light); | ||||
| ThemeData? currentDarkTheme = SolianTheme.build(Brightness.dark); | ||||
|  | ||||
| abstract class SolianTheme { | ||||
|   static bool isLargeScreen(BuildContext context) => | ||||
|       MediaQuery.of(context).size.width > 640; | ||||
| @@ -27,13 +30,13 @@ abstract class SolianTheme { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static ThemeData build(Brightness brightness) { | ||||
|   static ThemeData build(Brightness brightness, {Color? seedColor}) { | ||||
|     return ThemeData( | ||||
|       brightness: brightness, | ||||
|       useMaterial3: true, | ||||
|       colorScheme: ColorScheme.fromSeed( | ||||
|         brightness: brightness, | ||||
|         seedColor: const Color.fromRGBO(154, 98, 91, 1), | ||||
|         seedColor: seedColor ?? const Color.fromRGBO(154, 98, 91, 1), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|   | ||||
| @@ -27,6 +27,7 @@ const i18nEnglish = { | ||||
|   'about': 'About', | ||||
|   'edit': 'Edit', | ||||
|   'delete': 'Delete', | ||||
|   'settings': 'Settings', | ||||
|   'search': 'Search', | ||||
|   'post': 'Post', | ||||
|   'article': 'Article', | ||||
| @@ -293,6 +294,7 @@ const i18nEnglish = { | ||||
|   'accountStatusNegative': 'Negative', | ||||
|   'accountStatusNeutral': 'Neutral', | ||||
|   'accountStatusPositive': 'Positive', | ||||
|   'bsLoadingTheme': 'Loading Theme', | ||||
|   'bsCheckingServer': 'Checking Server Status', | ||||
|   'bsCheckingServerFail': | ||||
|       'Unable connect to server, check your network connection', | ||||
| @@ -304,4 +306,9 @@ const i18nEnglish = { | ||||
|   'postShareContent': | ||||
|       '@content\n\n@username on the Solar Network\nCheck it out: @link', | ||||
|   'postShareSubject': '@username posted a post on the Solar Network', | ||||
|   'themeColor': 'Global Theme Color', | ||||
|   'themeColorRed': 'Modern Red', | ||||
|   'themeColorBlue': 'Classic Blue', | ||||
|   'themeColorMiku': 'Miku Blue', | ||||
|   'themeColorApplied': 'Global theme color has been saved, restart to get applied.', | ||||
| }; | ||||
|   | ||||
| @@ -13,6 +13,7 @@ const i18nSimplifiedChinese = { | ||||
|   'about': '关于', | ||||
|   'edit': '编辑', | ||||
|   'delete': '删除', | ||||
|   'settings': '设置', | ||||
|   'page': '页面', | ||||
|   'draft': '草稿', | ||||
|   'draftSave': '存为草稿', | ||||
| @@ -272,6 +273,7 @@ const i18nSimplifiedChinese = { | ||||
|   'accountStatusNegative': '负面', | ||||
|   'accountStatusNeutral': '中性', | ||||
|   'accountStatusPositive': '积极', | ||||
|   'bsLoadingTheme': '正在装载主题', | ||||
|   'bsCheckingServer': '检查服务器状态中', | ||||
|   'bsCheckingServerFail': '无法连接至服务器,请检查你的网络连接状态', | ||||
|   'bsCheckingServerDown': '当前服务器不可用,请稍后重试', | ||||
| @@ -281,4 +283,9 @@ const i18nSimplifiedChinese = { | ||||
|   'bsRegisteringPushNotify': '正在启用推送通知', | ||||
|   'postShareContent': '@content\n\n@username 在 Solar Network\n原帖地址:@link', | ||||
|   'postShareSubject': '@username 在 Solar Network 上发布了一篇帖子', | ||||
|   'themeColor': '全局主题色', | ||||
|   'themeColorRed': '现代红', | ||||
|   'themeColorBlue': '经典蓝', | ||||
|   'themeColorMiku': '未来色', | ||||
|   'themeColorApplied': '全局主题颜色已保存,重启后生效。', | ||||
| }; | ||||
|   | ||||
| @@ -138,8 +138,19 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> { | ||||
|               ); | ||||
|             }), | ||||
|             trailing: IconButton( | ||||
|               icon: const Icon(Icons.face_retouching_natural), | ||||
|               icon: const Icon(Icons.settings), | ||||
|               onPressed: () { | ||||
|                 AppRouter.instance.pushNamed('settings'); | ||||
|                 setState(() => _selectedIndex = null); | ||||
|                 closeDrawer(); | ||||
|               }, | ||||
|             ), | ||||
|             onTap: () { | ||||
|               AppRouter.instance.goNamed('account'); | ||||
|               setState(() => _selectedIndex = null); | ||||
|               closeDrawer(); | ||||
|             }, | ||||
|             onLongPress: () { | ||||
|               showModalBottomSheet( | ||||
|                 useRootNavigator: true, | ||||
|                 context: context, | ||||
| @@ -150,12 +161,6 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> { | ||||
|                 if (val == true) getStatus(); | ||||
|               }); | ||||
|             }, | ||||
|             ), | ||||
|             onTap: () { | ||||
|               AppRouter.instance.goNamed('account'); | ||||
|               setState(() => _selectedIndex = null); | ||||
|               closeDrawer(); | ||||
|             }, | ||||
|           ); | ||||
|         }).paddingOnly(top: 8), | ||||
|         const Divider(thickness: 0.3, height: 1).paddingOnly( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user