feat: 主题切换

This commit is contained in:
guozhigq
2023-08-11 16:35:07 +08:00
parent f4dc4be811
commit c55887af53
6 changed files with 155 additions and 24 deletions

View File

@ -4,8 +4,10 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/common/widgets/custom_toast.dart'; import 'package:pilipala/common/widgets/custom_toast.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/init.dart';
import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/pages/search/index.dart'; import 'package:pilipala/pages/search/index.dart';
import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/index.dart';
import 'package:pilipala/router/app_pages.dart'; import 'package:pilipala/router/app_pages.dart';
@ -33,19 +35,38 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Color brandColor = Colors.green;
Box setting = GStrorage.setting;
ThemeType currentThemeValue = ThemeType.values[setting
.get(SettingBoxKey.themeMode, defaultValue: ThemeType.system.code)];
return DynamicColorBuilder( return DynamicColorBuilder(
builder: ((lightDynamic, darkDynamic) { builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
ColorScheme? lightColorScheme;
ColorScheme? darkColorScheme;
if (lightDynamic != null && darkDynamic != null) {
// dynamic取色成功
lightColorScheme = lightDynamic.harmonized();
darkColorScheme = darkDynamic.harmonized();
} else {
// dynamic取色失败采用品牌色
lightColorScheme = ColorScheme.fromSeed(
seedColor: brandColor,
brightness: Brightness.light,
);
darkColorScheme = ColorScheme.fromSeed(
seedColor: brandColor,
brightness: Brightness.dark,
);
}
// 图片缓存 // 图片缓存
// PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20; // PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20;
return GetMaterialApp( return GetMaterialApp(
title: 'PiLiPaLa', title: 'PiLiPaLa',
theme: ThemeData( theme: ThemeData(
// fontFamily: 'HarmonyOS', // fontFamily: 'HarmonyOS',
colorScheme: lightDynamic ?? colorScheme: currentThemeValue == ThemeType.dark
ColorScheme.fromSeed( ? darkColorScheme
seedColor: Colors.green, : lightColorScheme,
brightness: Brightness.light,
),
useMaterial3: true, useMaterial3: true,
pageTransitionsTheme: const PageTransitionsTheme( pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{ builders: <TargetPlatform, PageTransitionsBuilder>{
@ -57,11 +78,9 @@ class MyApp extends StatelessWidget {
), ),
darkTheme: ThemeData( darkTheme: ThemeData(
// fontFamily: 'HarmonyOS', // fontFamily: 'HarmonyOS',
colorScheme: darkDynamic ?? colorScheme: currentThemeValue == ThemeType.light
ColorScheme.fromSeed( ? lightColorScheme
seedColor: Colors.green, : darkColorScheme,
brightness: Brightness.dark,
),
useMaterial3: true, useMaterial3: true,
), ),
localizationsDelegates: const [ localizationsDelegates: const [

View File

@ -0,0 +1,13 @@
enum ThemeType {
light,
dark,
system,
}
extension ThemeTypeDesc on ThemeType {
String get description => ['浅色', '深色', '跟随系统'][index];
}
extension ThemeTypeCode on ThemeType {
int get code => [0, 1, 2][index];
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/user.dart'; import 'package:pilipala/http/user.dart';
import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/models/user/info.dart'; import 'package:pilipala/models/user/info.dart';
import 'package:pilipala/models/user/stat.dart'; import 'package:pilipala/models/user/stat.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
@ -10,9 +12,11 @@ class MineController extends GetxController {
Rx<UserInfoData> userInfo = UserInfoData().obs; Rx<UserInfoData> userInfo = UserInfoData().obs;
// 用户状态 动态、关注、粉丝 // 用户状态 动态、关注、粉丝
Rx<UserStat> userStat = UserStat().obs; Rx<UserStat> userStat = UserStat().obs;
Box user = GStrorage.user;
RxBool userLogin = false.obs; RxBool userLogin = false.obs;
Box user = GStrorage.user;
Box setting = GStrorage.setting;
Box userInfoCache = GStrorage.userInfo; Box userInfoCache = GStrorage.userInfo;
Rx<ThemeType> themeType = ThemeType.system.obs;
@override @override
onInit() { onInit() {
@ -21,6 +25,9 @@ class MineController extends GetxController {
if (userInfoCache.get('userInfoCache') != null) { if (userInfoCache.get('userInfoCache') != null) {
userInfo.value = userInfoCache.get('userInfoCache'); userInfo.value = userInfoCache.get('userInfoCache');
} }
themeType.value = ThemeType.values[setting.get(SettingBoxKey.themeMode,
defaultValue: ThemeType.system.code)];
} }
onLogin() async { onLogin() async {
@ -90,4 +97,31 @@ class MineController extends GetxController {
userLogin.value = false; userLogin.value = false;
// Get.find<MainController>().resetLast(); // Get.find<MainController>().resetLast();
} }
onChangeTheme() {
Brightness currentBrightness =
MediaQuery.of(Get.context!).platformBrightness;
ThemeType currentTheme = themeType.value;
switch (currentTheme) {
case ThemeType.dark:
setting.put(SettingBoxKey.themeMode, ThemeType.light.code);
themeType.value = ThemeType.light;
break;
case ThemeType.light:
setting.put(SettingBoxKey.themeMode, ThemeType.dark.code);
themeType.value = ThemeType.dark;
break;
case ThemeType.system:
// 判断当前的颜色模式
if (currentBrightness == Brightness.light) {
setting.put(SettingBoxKey.themeMode, ThemeType.dark.code);
themeType.value = ThemeType.dark;
} else {
setting.put(SettingBoxKey.themeMode, ThemeType.light.code);
themeType.value = ThemeType.light;
}
break;
}
Get.forceAppUpdate();
}
} }

View File

@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/utils/storage.dart';
import 'controller.dart'; import 'controller.dart';
class MinePage extends StatelessWidget { class MinePage extends StatelessWidget {
@ -24,13 +26,11 @@ class MinePage extends StatelessWidget {
title: null, title: null,
actions: [ actions: [
IconButton( IconButton(
onPressed: () { onPressed: () => mineController.onChangeTheme(),
Get.changeThemeMode(ThemeMode.dark);
},
icon: Icon( icon: Icon(
Get.theme == ThemeData.light() mineController.themeType.value == ThemeType.dark
? CupertinoIcons.moon ? CupertinoIcons.sun_max
: CupertinoIcons.sun_max, : CupertinoIcons.moon,
size: 22, size: 22,
), ),
), ),
@ -93,7 +93,7 @@ class MinePage extends StatelessWidget {
src: _mineController.userInfo.value.face, src: _mineController.userInfo.value.face,
width: 85, width: 85,
height: 85) height: 85)
: Image.asset('assets/images/loading.png'), : Image.asset('assets/images/noface.jpeg'),
), ),
), ),
), ),

View File

@ -1,11 +1,9 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/init.dart';
import 'package:pilipala/pages/dynamics/index.dart'; import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/pages/home/index.dart'; import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/main/index.dart';
import 'package:pilipala/pages/mine/controller.dart'; import 'package:pilipala/pages/mine/controller.dart';
import 'package:pilipala/utils/data.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
@ -17,6 +15,7 @@ class SettingController extends GetxController {
RxBool userLogin = false.obs; RxBool userLogin = false.obs;
RxBool feedBackEnable = false.obs; RxBool feedBackEnable = false.obs;
RxInt picQuality = 10.obs; RxInt picQuality = 10.obs;
Rx<ThemeType> themeType = ThemeType.system.obs;
@override @override
void onInit() { void onInit() {
@ -26,6 +25,8 @@ class SettingController extends GetxController {
setting.get(SettingBoxKey.feedBackEnable, defaultValue: false); setting.get(SettingBoxKey.feedBackEnable, defaultValue: false);
picQuality.value = picQuality.value =
setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10); setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10);
themeType.value = ThemeType.values[setting.get(SettingBoxKey.themeMode,
defaultValue: ThemeType.system.code)];
} }
loginOut() async { loginOut() async {

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'controller.dart'; import 'controller.dart';
@ -16,11 +17,13 @@ class _StyleSettingState extends State<StyleSetting> {
final SettingController settingController = Get.put(SettingController()); final SettingController settingController = Get.put(SettingController());
Box setting = GStrorage.setting; Box setting = GStrorage.setting;
late int picQuality; late int picQuality;
late ThemeType _tempThemeValue;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
picQuality = setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10); picQuality = setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10);
_tempThemeValue = settingController.themeType.value;
} }
@override @override
@ -74,7 +77,7 @@ class _StyleSettingState extends State<StyleSetting> {
final SettingController settingController = final SettingController settingController =
Get.put(SettingController()); Get.put(SettingController());
return AlertDialog( return AlertDialog(
title: Text('图片清晰度 - $picQuality%', style: titleStyle), title: const Text('图片质量'),
contentPadding: const EdgeInsets.only( contentPadding: const EdgeInsets.only(
top: 20, left: 8, right: 8, bottom: 8), top: 20, left: 8, right: 8, bottom: 8),
content: SizedBox( content: SizedBox(
@ -94,7 +97,11 @@ class _StyleSettingState extends State<StyleSetting> {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(), onPressed: () => Get.back(),
child: const Text('取消')), child: Text('取消',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.outline))),
TextButton( TextButton(
onPressed: () { onPressed: () {
setting.put( setting.put(
@ -120,6 +127,63 @@ class _StyleSettingState extends State<StyleSetting> {
), ),
), ),
), ),
ListTile(
dense: false,
onTap: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('主题模式'),
contentPadding: const EdgeInsets.fromLTRB(0, 12, 0, 12),
content: StatefulBuilder(
builder: (context, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
for (var i in ThemeType.values) ...[
RadioListTile(
value: i,
title: Text(i.description, style: titleStyle),
groupValue: _tempThemeValue,
onChanged: (ThemeType? value) {
setState(() {
_tempThemeValue = i;
});
},
),
]
],
);
}),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(
'取消',
style: TextStyle(
color: Theme.of(context).colorScheme.outline),
)),
TextButton(
onPressed: () {
settingController.themeType.value = _tempThemeValue;
setting.put(
SettingBoxKey.themeMode, _tempThemeValue.code);
Get.forceAppUpdate();
Get.back();
},
child: const Text('确定'))
],
);
},
);
},
title: Text('主题模式', style: titleStyle),
subtitle: Obx(() => Text(
'当前模式:${settingController.themeType.value.description}',
style: subTitleStyle)),
trailing: const Icon(Icons.arrow_right_alt_outlined),
),
], ],
), ),
); );