From 52e58fce3de2a75a731df9f97b96d88d8da52b90 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Wed, 31 Jul 2024 22:48:22 +0800 Subject: [PATCH] :wheelchair: Make theme switcher easier to use --- lib/main.dart | 68 ++++++++++--------- lib/providers/theme_switcher.dart | 30 +++++++++ lib/screens/settings.dart | 28 ++++---- lib/theme.dart | 3 - lib/translations/en_us.dart | 3 +- lib/translations/zh_cn.dart | 2 +- pubspec.lock | 16 +++++ pubspec.yaml | 3 +- web/index.html | 107 +++++++++++++++--------------- 9 files changed, 149 insertions(+), 111 deletions(-) create mode 100644 lib/providers/theme_switcher.dart diff --git a/lib/main.dart b/lib/main.dart index 26612df..546bfff 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,11 +5,12 @@ import 'package:get/get.dart'; import 'package:go_router/go_router.dart'; import 'package:media_kit/media_kit.dart'; import 'package:protocol_handler/protocol_handler.dart'; +import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:solian/bootstrapper.dart'; import 'package:solian/firebase_options.dart'; import 'package:solian/platform.dart'; +import 'package:solian/providers/theme_switcher.dart'; import 'package:solian/providers/websocket.dart'; import 'package:solian/providers/auth.dart'; import 'package:solian/providers/content/attachment.dart'; @@ -38,7 +39,6 @@ void main() async { MediaKit.ensureInitialized(); await Future.wait([ - _initializeTheme(), _initializeFirebase(), _initializePlatformComponents(), ]); @@ -51,16 +51,6 @@ void main() async { ); } -Future _initializeTheme() 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); - } -} - Future _initializeFirebase() async { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); } @@ -83,33 +73,45 @@ Future _initializePlatformComponents() async { } } +final themeSwitcher = ThemeSwitcher( + lightThemeData: SolianTheme.build(Brightness.light), + darkThemeData: SolianTheme.build(Brightness.dark), +)..restoreTheme(); + class SolianApp extends StatelessWidget { const SolianApp({super.key}); @override Widget build(BuildContext context) { - return GetMaterialApp.router( - title: 'Solian', - theme: currentLightTheme, - darkTheme: currentDarkTheme, - themeMode: ThemeMode.system, - routerDelegate: AppRouter.instance.routerDelegate, - routeInformationParser: AppRouter.instance.routeInformationParser, - routeInformationProvider: AppRouter.instance.routeInformationProvider, - backButtonDispatcher: AppRouter.instance.backButtonDispatcher, - translations: SolianMessages(), - locale: Get.deviceLocale, - fallbackLocale: const Locale('en', 'US'), - onInit: () => _initializeProviders(context), - builder: (context, child) { - return SystemShell( - child: ScaffoldMessenger( - child: BootstrapperShell( - child: child ?? const SizedBox(), - ), - ), + return ChangeNotifierProvider.value( + value: themeSwitcher, + child: Builder(builder: (context) { + final theme = Provider.of(context); + + return GetMaterialApp.router( + title: 'Solian', + theme: theme.lightThemeData, + darkTheme: theme.darkThemeData, + themeMode: ThemeMode.system, + routerDelegate: AppRouter.instance.routerDelegate, + routeInformationParser: AppRouter.instance.routeInformationParser, + routeInformationProvider: AppRouter.instance.routeInformationProvider, + backButtonDispatcher: AppRouter.instance.backButtonDispatcher, + translations: SolianMessages(), + locale: Get.deviceLocale, + fallbackLocale: const Locale('en', 'US'), + onInit: () => _initializeProviders(context), + builder: (context, child) { + return SystemShell( + child: ScaffoldMessenger( + child: BootstrapperShell( + child: child ?? const SizedBox(), + ), + ), + ); + }, ); - }, + }), ); } diff --git a/lib/providers/theme_switcher.dart b/lib/providers/theme_switcher.dart new file mode 100644 index 0000000..c1e158b --- /dev/null +++ b/lib/providers/theme_switcher.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:solian/theme.dart'; + +class ThemeSwitcher extends ChangeNotifier { + ThemeData lightThemeData; + ThemeData darkThemeData; + + ThemeSwitcher({ + required this.lightThemeData, + required this.darkThemeData, + }); + + Future restoreTheme() async { + final prefs = await SharedPreferences.getInstance(); + if (prefs.containsKey('global_theme_color')) { + final value = prefs.getInt('global_theme_color')!; + final color = Color(value); + lightThemeData = SolianTheme.build(Brightness.light, seedColor: color); + darkThemeData = SolianTheme.build(Brightness.dark, seedColor: color); + notifyListeners(); + } + } + + void setTheme(ThemeData light, dark) { + lightThemeData = light; + darkThemeData = dark; + notifyListeners(); + } +} diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index f96b9ff..e833fb0 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -2,8 +2,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:solian/exts.dart'; +import 'package:solian/providers/theme_switcher.dart'; import 'package:solian/theme.dart'; class SettingScreen extends StatefulWidget { @@ -30,22 +32,16 @@ class _SettingScreenState extends State { icon: Icon(Icons.circle, color: color), tooltip: label, onPressed: () { - currentLightTheme = SolianTheme.build( - Brightness.light, - seedColor: color, - ); - currentDarkTheme = SolianTheme.build( - Brightness.dark, - seedColor: color, - ); - if (!Get.isDarkMode) { - Get.changeTheme( - SolianTheme.build(Brightness.light, seedColor: color), - ); - } else { - // Dark mode cannot be hot reload - // https://github.com/jonataslaw/getx/issues/1411 - } + context.read().setTheme( + SolianTheme.build( + Brightness.light, + seedColor: color, + ), + SolianTheme.build( + Brightness.dark, + seedColor: color, + ), + ); _prefs.setInt('global_theme_color', color.value); context.clearSnackbar(); context.showSnackbar('themeColorApplied'.tr); diff --git a/lib/theme.dart b/lib/theme.dart index e7d4f92..359519f 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -1,9 +1,6 @@ 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; diff --git a/lib/translations/en_us.dart b/lib/translations/en_us.dart index 38d3707..5aa744a 100644 --- a/lib/translations/en_us.dart +++ b/lib/translations/en_us.dart @@ -312,6 +312,5 @@ const i18nEnglish = { 'themeColorMiku': 'Miku Blue', 'themeColorKagamine': 'Kagamine Yellow', 'themeColorLuka': 'Luka Pink', - 'themeColorApplied': - 'Global theme color has been applied, dark mode theme need restart to get applied.', + 'themeColorApplied': 'Global theme color has been applied.', }; diff --git a/lib/translations/zh_cn.dart b/lib/translations/zh_cn.dart index 99ce64d..2c0eb95 100644 --- a/lib/translations/zh_cn.dart +++ b/lib/translations/zh_cn.dart @@ -289,5 +289,5 @@ const i18nSimplifiedChinese = { 'themeColorMiku': '未来色', 'themeColorKagamine': '镜音黄', 'themeColorLuka': '流音粉', - 'themeColorApplied': '全局主题颜色已应用,深色模式中主题需要重启生效', + 'themeColorApplied': '全局主题颜色已应用', }; diff --git a/pubspec.lock b/pubspec.lock index b52711b..a4086ef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1016,6 +1016,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" nm: dependency: transitive description: @@ -1272,6 +1280,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" pub_semver: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e55f14e..4cd9e52 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: solian description: "The Solar Network App" publish_to: "none" -version: 1.2.0+3 +version: 1.2.0+4 environment: sdk: ">=3.3.4 <4.0.0" @@ -61,6 +61,7 @@ dependencies: flutter_markdown_selectionarea: ^0.6.17+1 shared_preferences: ^2.2.3 easy_debounce: ^2.0.3 + provider: ^6.1.2 dev_dependencies: flutter_test: diff --git a/web/index.html b/web/index.html index 7532d9b..d11360a 100644 --- a/web/index.html +++ b/web/index.html @@ -1,8 +1,7 @@ - + - - - - - + - - - + + + - - - - - + + + + + - - + + - - - Solian - - + @keyframes spin { + 0% { + transform: rotate(0deg); + } - -
-
-
+ 100% { + transform: rotate(360deg); + } + } + - - + Solian + + + +
+
+
+ + +