feat: 主题颜色选择

This commit is contained in:
guozhigq
2023-08-22 16:49:49 +08:00
parent b6023e35bc
commit 5a03bee410
6 changed files with 227 additions and 16 deletions

View File

@ -7,6 +7,7 @@ import 'package:dynamic_color/dynamic_color.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/common/widgets/custom_toast.dart';
import 'package:pilipala/http/init.dart';
import 'package:pilipala/models/common/color_type.dart';
import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/pages/search/index.dart';
import 'package:pilipala/pages/video/detail/index.dart';
@ -35,15 +36,24 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Color brandColor = const Color.fromARGB(255, 92, 182, 123);
Box setting = GStrorage.setting;
// 主题色
Color defaultColor =
colorThemeTypes[setting.get(SettingBoxKey.customColor, defaultValue: 0)]
['color'];
Color brandColor = defaultColor;
// 主题模式
ThemeType currentThemeValue = ThemeType.values[setting
.get(SettingBoxKey.themeMode, defaultValue: ThemeType.system.code)];
// 是否动态取色
bool isDynamicColor =
setting.get(SettingBoxKey.dynamicColor, defaultValue: true);
return DynamicColorBuilder(
builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
ColorScheme? lightColorScheme;
ColorScheme? darkColorScheme;
if (lightDynamic != null && darkDynamic != null) {
if (lightDynamic != null && darkDynamic != null && isDynamicColor) {
// dynamic取色成功
lightColorScheme = lightDynamic.harmonized();
darkColorScheme = darkDynamic.harmonized();
@ -93,9 +103,15 @@ class MyApp extends StatelessWidget {
fallbackLocale: const Locale("zh", "CN"),
getPages: Routes.getPages,
home: const MainApp(),
builder: FlutterSmartDialog.init(
toastBuilder: (String msg) => CustomToast(msg: msg),
),
builder: (BuildContext context, Widget? child) {
return FlutterSmartDialog(
toastBuilder: (String msg) => CustomToast(msg: msg),
child: MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: child!,
),
);
},
navigatorObservers: [
VideoDetailPage.routeObserver,
SearchPage.routeObserver,

View File

@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
final List<Map<String, dynamic>> colorThemeTypes = [
{'color': const Color.fromARGB(255, 92, 182, 123), 'label': '默认绿'},
{'color': Colors.pink, 'label': '粉红色'},
{'color': Colors.red, 'label': '红色'},
{'color': Colors.orange, 'label': '橙色'},
{'color': Colors.amber, 'label': '琥珀色'},
{'color': Colors.yellow, 'label': '黄色'},
{'color': Colors.lime, 'label': '酸橙色'},
{'color': Colors.lightGreen, 'label': '浅绿色'},
{'color': Colors.green, 'label': '绿色'},
{'color': Colors.teal, 'label': '青色'},
{'color': Colors.cyan, 'label': '蓝绿色'},
{'color': Colors.lightBlue, 'label': '浅蓝色'},
{'color': Colors.blue, 'label': '蓝色'},
{'color': Colors.indigo, 'label': '靛蓝色'},
{'color': Colors.purple, 'label': '紫色'},
{'color': Colors.deepPurple, 'label': '深紫色'},
{'color': Colors.blueGrey, 'label': '蓝灰色'},
{'color': Colors.brown, 'label': '棕色'},
{'color': Colors.grey, 'label': '灰色'},
];

View File

@ -0,0 +1,162 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/models/common/color_type.dart';
import 'package:pilipala/utils/storage.dart';
class ColorSelectPage extends StatefulWidget {
const ColorSelectPage({super.key});
@override
State<ColorSelectPage> createState() => _ColorSelectPageState();
}
class Item {
Item({
required this.expandedValue,
required this.headerValue,
this.isExpanded = false,
});
String expandedValue;
String headerValue;
bool isExpanded;
}
List<Item> generateItems(int count) {
return List<Item>.generate(count, (int index) {
return Item(
headerValue: 'Panel $index',
expandedValue: 'This is item number $index',
);
});
}
class _ColorSelectPageState extends State<ColorSelectPage> {
final ColorSelectController ctr = Get.put(ColorSelectController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: const Text('选择应用主题'),
),
body: ListView(
children: [
Obx(
() => RadioListTile(
value: 0,
title: const Text('动态取色'),
groupValue: ctr.type.value,
onChanged: (dynamic val) async {
ctr.type.value = 0;
ctr.setting.put(SettingBoxKey.dynamicColor, true);
},
),
),
Obx(
() => RadioListTile(
value: 1,
title: const Text('指定颜色'),
groupValue: ctr.type.value,
onChanged: (dynamic val) async {
ctr.type.value = 1;
ctr.setting.put(SettingBoxKey.dynamicColor, false);
},
),
),
Obx(
() {
int type = ctr.type.value;
return AnimatedOpacity(
opacity: type == 1 ? 1 : 0,
duration: const Duration(milliseconds: 200),
child: Padding(
padding: const EdgeInsets.only(top: 12, left: 12, right: 12),
child: Wrap(
alignment: WrapAlignment.center,
spacing: 22,
runSpacing: 18,
children: [
...ctr.colorThemes.map(
(e) {
final index = ctr.colorThemes.indexOf(e);
return GestureDetector(
onTap: () {
ctr.currentColor.value = index;
ctr.setting.put(SettingBoxKey.customColor, index);
Get.forceAppUpdate();
},
child: Column(
children: [
Container(
width: 46,
height: 46,
decoration: BoxDecoration(
color: e['color'].withOpacity(0.8),
borderRadius: BorderRadius.circular(50),
border: Border.all(
width: 2,
color: ctr.currentColor.value == index
? Colors.black
: e['color'].withOpacity(0.8),
),
),
child: AnimatedOpacity(
opacity:
ctr.currentColor.value == index ? 1 : 0,
duration: const Duration(milliseconds: 200),
child: const Icon(
Icons.done,
color: Colors.black,
size: 20,
),
),
),
const SizedBox(height: 3),
Text(
e['label'],
style: TextStyle(
fontSize: 12,
color: ctr.currentColor.value != index
? Theme.of(context).colorScheme.outline
: null,
),
),
],
),
);
},
)
],
),
),
);
},
),
],
),
);
}
}
class ColorSelectController extends GetxController {
Box setting = GStrorage.setting;
RxBool dynamicColor = true.obs;
RxInt type = 0.obs;
late final List<Map<String, dynamic>> colorThemes;
RxInt currentColor = 0.obs;
@override
void onInit() {
colorThemes = colorThemeTypes;
// 默认使用动态取色
dynamicColor.value =
setting.get(SettingBoxKey.dynamicColor, defaultValue: true);
type.value = dynamicColor.value ? 0 : 1;
currentColor.value =
setting.get(SettingBoxKey.customColor, defaultValue: 0);
super.onInit();
}
}

View File

@ -184,6 +184,11 @@ class _StyleSettingState extends State<StyleSetting> {
style: subTitleStyle)),
trailing: const Icon(Icons.arrow_right_alt_outlined),
),
ListTile(
dense: false,
onTap: () => Get.toNamed('/colorSetting'),
title: Text('应用主题', style: titleStyle),
),
],
),
);

View File

@ -17,6 +17,7 @@ import 'package:pilipala/pages/preview/index.dart';
import 'package:pilipala/pages/search/index.dart';
import 'package:pilipala/pages/searchResult/index.dart';
import 'package:pilipala/pages/setting/extra_setting.dart';
import 'package:pilipala/pages/setting/pages/color_select.dart';
import 'package:pilipala/pages/setting/play_setting.dart';
import 'package:pilipala/pages/setting/privacy_setting.dart';
import 'package:pilipala/pages/setting/style_setting.dart';
@ -85,6 +86,7 @@ class Routes {
GetPage(name: '/extraSetting', page: () => const ExtraSetting()),
//
GetPage(name: '/blackListPage', page: () => const BlackListPage()),
GetPage(name: '/colorSetting', page: () => const ColorSelectPage()),
// 关于
GetPage(name: '/about', page: () => const AboutPage()),
];

View File

@ -82,24 +82,27 @@ class GStrorage {
}
class SettingBoxKey {
static const String themeMode = 'themeMode';
static const String feedBackEnable = 'feedBackEnable';
static const String defaultFontSize = 'fontSize';
static const String defaultVideoQa = 'defaultVideoQa';
static const String defaultAudioQa = 'defaultAudioQa';
static const String defaultDecode = 'defaultDecode';
static const String btmProgressBehavior = 'btmProgressBehavior';
static const String defaultVideoSpeed = 'defaultVideoSpeed';
static const String autoUpgradeEnable = 'autoUpgradeEnable';
static const String feedBackEnable = 'feedBackEnable';
static const String defaultVideoQa = 'defaultVideoQa';
static const String defaultAudioQa = 'defaultAudioQa';
static const String autoPlayEnable = 'autoPlayEnable';
static const String enableHA = 'enableHA';
static const String defaultPicQa = 'defaultPicQa';
static const String danmakuEnable = 'danmakuEnable';
static const String fullScreenMode = 'fullScreenMode';
static const String defaultDecode = 'defaultDecode';
static const String danmakuEnable = 'danmakuEnable';
static const String defaultPicQa = 'defaultPicQa';
static const String enableHA = 'enableHA';
static const String blackMidsList = 'blackMidsList';
static const String autoUpdate = 'autoUpdate';
static const String btmProgressBehavior = 'btmProgressBehavior';
static const String themeMode = 'themeMode';
static const String defaultFontSize = 'fontSize';
static const String dynamicColor = 'dynamicColor'; // bool
static const String customColor = 'customColor'; // 自定义主题色
}
class LocalCacheKey {