♿ Make theme switcher easier to use
This commit is contained in:
parent
31d50bfb1f
commit
52e58fce3d
@ -5,11 +5,12 @@ import 'package:get/get.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:media_kit/media_kit.dart';
|
import 'package:media_kit/media_kit.dart';
|
||||||
import 'package:protocol_handler/protocol_handler.dart';
|
import 'package:protocol_handler/protocol_handler.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'package:solian/bootstrapper.dart';
|
import 'package:solian/bootstrapper.dart';
|
||||||
import 'package:solian/firebase_options.dart';
|
import 'package:solian/firebase_options.dart';
|
||||||
import 'package:solian/platform.dart';
|
import 'package:solian/platform.dart';
|
||||||
|
import 'package:solian/providers/theme_switcher.dart';
|
||||||
import 'package:solian/providers/websocket.dart';
|
import 'package:solian/providers/websocket.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/providers/content/attachment.dart';
|
import 'package:solian/providers/content/attachment.dart';
|
||||||
@ -38,7 +39,6 @@ void main() async {
|
|||||||
MediaKit.ensureInitialized();
|
MediaKit.ensureInitialized();
|
||||||
|
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
_initializeTheme(),
|
|
||||||
_initializeFirebase(),
|
_initializeFirebase(),
|
||||||
_initializePlatformComponents(),
|
_initializePlatformComponents(),
|
||||||
]);
|
]);
|
||||||
@ -51,16 +51,6 @@ void main() async {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _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<void> _initializeFirebase() async {
|
Future<void> _initializeFirebase() async {
|
||||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||||
}
|
}
|
||||||
@ -83,33 +73,45 @@ Future<void> _initializePlatformComponents() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final themeSwitcher = ThemeSwitcher(
|
||||||
|
lightThemeData: SolianTheme.build(Brightness.light),
|
||||||
|
darkThemeData: SolianTheme.build(Brightness.dark),
|
||||||
|
)..restoreTheme();
|
||||||
|
|
||||||
class SolianApp extends StatelessWidget {
|
class SolianApp extends StatelessWidget {
|
||||||
const SolianApp({super.key});
|
const SolianApp({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetMaterialApp.router(
|
return ChangeNotifierProvider.value(
|
||||||
title: 'Solian',
|
value: themeSwitcher,
|
||||||
theme: currentLightTheme,
|
child: Builder(builder: (context) {
|
||||||
darkTheme: currentDarkTheme,
|
final theme = Provider.of<ThemeSwitcher>(context);
|
||||||
themeMode: ThemeMode.system,
|
|
||||||
routerDelegate: AppRouter.instance.routerDelegate,
|
return GetMaterialApp.router(
|
||||||
routeInformationParser: AppRouter.instance.routeInformationParser,
|
title: 'Solian',
|
||||||
routeInformationProvider: AppRouter.instance.routeInformationProvider,
|
theme: theme.lightThemeData,
|
||||||
backButtonDispatcher: AppRouter.instance.backButtonDispatcher,
|
darkTheme: theme.darkThemeData,
|
||||||
translations: SolianMessages(),
|
themeMode: ThemeMode.system,
|
||||||
locale: Get.deviceLocale,
|
routerDelegate: AppRouter.instance.routerDelegate,
|
||||||
fallbackLocale: const Locale('en', 'US'),
|
routeInformationParser: AppRouter.instance.routeInformationParser,
|
||||||
onInit: () => _initializeProviders(context),
|
routeInformationProvider: AppRouter.instance.routeInformationProvider,
|
||||||
builder: (context, child) {
|
backButtonDispatcher: AppRouter.instance.backButtonDispatcher,
|
||||||
return SystemShell(
|
translations: SolianMessages(),
|
||||||
child: ScaffoldMessenger(
|
locale: Get.deviceLocale,
|
||||||
child: BootstrapperShell(
|
fallbackLocale: const Locale('en', 'US'),
|
||||||
child: child ?? const SizedBox(),
|
onInit: () => _initializeProviders(context),
|
||||||
),
|
builder: (context, child) {
|
||||||
),
|
return SystemShell(
|
||||||
|
child: ScaffoldMessenger(
|
||||||
|
child: BootstrapperShell(
|
||||||
|
child: child ?? const SizedBox(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
lib/providers/theme_switcher.dart
Normal file
30
lib/providers/theme_switcher.dart
Normal file
@ -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<void> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,10 @@ import 'dart:ui';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:solian/exts.dart';
|
import 'package:solian/exts.dart';
|
||||||
|
import 'package:solian/providers/theme_switcher.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
|
|
||||||
class SettingScreen extends StatefulWidget {
|
class SettingScreen extends StatefulWidget {
|
||||||
@ -30,22 +32,16 @@ class _SettingScreenState extends State<SettingScreen> {
|
|||||||
icon: Icon(Icons.circle, color: color),
|
icon: Icon(Icons.circle, color: color),
|
||||||
tooltip: label,
|
tooltip: label,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
currentLightTheme = SolianTheme.build(
|
context.read<ThemeSwitcher>().setTheme(
|
||||||
Brightness.light,
|
SolianTheme.build(
|
||||||
seedColor: color,
|
Brightness.light,
|
||||||
);
|
seedColor: color,
|
||||||
currentDarkTheme = SolianTheme.build(
|
),
|
||||||
Brightness.dark,
|
SolianTheme.build(
|
||||||
seedColor: color,
|
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
|
|
||||||
}
|
|
||||||
_prefs.setInt('global_theme_color', color.value);
|
_prefs.setInt('global_theme_color', color.value);
|
||||||
context.clearSnackbar();
|
context.clearSnackbar();
|
||||||
context.showSnackbar('themeColorApplied'.tr);
|
context.showSnackbar('themeColorApplied'.tr);
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:solian/platform.dart';
|
import 'package:solian/platform.dart';
|
||||||
|
|
||||||
ThemeData? currentLightTheme = SolianTheme.build(Brightness.light);
|
|
||||||
ThemeData? currentDarkTheme = SolianTheme.build(Brightness.dark);
|
|
||||||
|
|
||||||
abstract class SolianTheme {
|
abstract class SolianTheme {
|
||||||
static bool isLargeScreen(BuildContext context) =>
|
static bool isLargeScreen(BuildContext context) =>
|
||||||
MediaQuery.of(context).size.width > 640;
|
MediaQuery.of(context).size.width > 640;
|
||||||
|
@ -312,6 +312,5 @@ const i18nEnglish = {
|
|||||||
'themeColorMiku': 'Miku Blue',
|
'themeColorMiku': 'Miku Blue',
|
||||||
'themeColorKagamine': 'Kagamine Yellow',
|
'themeColorKagamine': 'Kagamine Yellow',
|
||||||
'themeColorLuka': 'Luka Pink',
|
'themeColorLuka': 'Luka Pink',
|
||||||
'themeColorApplied':
|
'themeColorApplied': 'Global theme color has been applied.',
|
||||||
'Global theme color has been applied, dark mode theme need restart to get applied.',
|
|
||||||
};
|
};
|
||||||
|
@ -289,5 +289,5 @@ const i18nSimplifiedChinese = {
|
|||||||
'themeColorMiku': '未来色',
|
'themeColorMiku': '未来色',
|
||||||
'themeColorKagamine': '镜音黄',
|
'themeColorKagamine': '镜音黄',
|
||||||
'themeColorLuka': '流音粉',
|
'themeColorLuka': '流音粉',
|
||||||
'themeColorApplied': '全局主题颜色已应用,深色模式中主题需要重启生效',
|
'themeColorApplied': '全局主题颜色已应用',
|
||||||
};
|
};
|
||||||
|
16
pubspec.lock
16
pubspec.lock
@ -1016,6 +1016,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
nm:
|
nm:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1272,6 +1280,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
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:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -2,7 +2,7 @@ name: solian
|
|||||||
description: "The Solar Network App"
|
description: "The Solar Network App"
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
|
|
||||||
version: 1.2.0+3
|
version: 1.2.0+4
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.3.4 <4.0.0"
|
sdk: ">=3.3.4 <4.0.0"
|
||||||
@ -61,6 +61,7 @@ dependencies:
|
|||||||
flutter_markdown_selectionarea: ^0.6.17+1
|
flutter_markdown_selectionarea: ^0.6.17+1
|
||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
easy_debounce: ^2.0.3
|
easy_debounce: ^2.0.3
|
||||||
|
provider: ^6.1.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
107
web/index.html
107
web/index.html
@ -1,8 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
<head>
|
<!--
|
||||||
<!--
|
|
||||||
If you are serving your web app in a path other than the root, change the
|
If you are serving your web app in a path other than the root, change the
|
||||||
href value below to reflect the base path you are serving from.
|
href value below to reflect the base path you are serving from.
|
||||||
|
|
||||||
@ -15,66 +14,64 @@
|
|||||||
This is a placeholder for base href that will be replaced by the value of
|
This is a placeholder for base href that will be replaced by the value of
|
||||||
the `--base-href` argument provided to `flutter build`.
|
the `--base-href` argument provided to `flutter build`.
|
||||||
-->
|
-->
|
||||||
<!-- <base href="$FLUTTER_BASE_HREF"> -->
|
<base href="$FLUTTER_BASE_HREF" />
|
||||||
<base href="/" />
|
|
||||||
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible" />
|
||||||
<meta name="description" content="A new Flutter project.">
|
<meta name="description" content="A new Flutter project." />
|
||||||
|
|
||||||
<!-- iOS meta tags & icons -->
|
<!-- iOS meta tags & icons -->
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||||
<meta name="apple-mobile-web-app-title" content="solian">
|
<meta name="apple-mobile-web-app-title" content="solian" />
|
||||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
<link rel="apple-touch-icon" href="icons/Icon-192.png" />
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/png" href="favicon.png" />
|
<link rel="icon" type="image/png" href="favicon.png" />
|
||||||
|
|
||||||
<!-- Loading styles -->
|
<!-- Loading styles -->
|
||||||
<style>
|
<style>
|
||||||
.loader-container {
|
.loader-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
-ms-transform: translate(-50%, -50%);
|
-ms-transform: translate(-50%, -50%);
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
|
||||||
border: 10px solid #f3f3f3;
|
|
||||||
border-top: 10px solid #8f94ca;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
animation: spin .35s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
.loader {
|
||||||
transform: rotate(360deg);
|
border: 10px solid #f3f3f3;
|
||||||
|
border-top: 10px solid #8f94ca;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
animation: spin 0.35s linear infinite;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>Solian</title>
|
@keyframes spin {
|
||||||
<link rel="manifest" href="manifest.json">
|
0% {
|
||||||
</head>
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
<body>
|
100% {
|
||||||
<div class="loader-container">
|
transform: rotate(360deg);
|
||||||
<div class="loader"></div>
|
}
|
||||||
</div>
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script src="flutter_bootstrap.js" async></script>
|
<title>Solian</title>
|
||||||
</body>
|
<link rel="manifest" href="manifest.json" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="loader-container">
|
||||||
|
<div class="loader"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="flutter_bootstrap.js" async></script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user