✨ Global theme color
This commit is contained in:
parent
b70d3795d1
commit
cc9c99f375
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user