opt: color (#1782)

* fixes

* opt: color

* fix
This commit is contained in:
My-Responsitories
2025-12-18 11:08:03 +08:00
committed by GitHub
parent 11cdb67050
commit d7f7611af4
7 changed files with 102 additions and 58 deletions

View File

@@ -1,39 +1,32 @@
import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/constants.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:material_color_utilities/material_color_utilities.dart';
class ColorPalette extends StatelessWidget { class ColorPalette extends StatelessWidget {
final Color color; final ColorScheme colorScheme;
final bool selected; final bool selected;
final bool showBgColor;
const ColorPalette({ const ColorPalette({
super.key, super.key,
required this.color, required this.colorScheme,
required this.selected, required this.selected,
this.showBgColor = true,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final primary = colorScheme.primary;
final Hct hct = Hct.fromInt(color.toARGB32()); final tertiary = colorScheme.tertiary;
final primary = Color(Hct.from(hct.hue, 20.0, 90.0).toInt()); final primaryContainer = colorScheme.primaryContainer;
final tertiary = Color(Hct.from(hct.hue + 50, 20.0, 85.0).toInt());
final primaryContainer = Color(Hct.from(hct.hue, 30.0, 50.0).toInt());
Widget coloredBox(Color color) => Expanded(
child: ColoredBox(
color: color,
child: const SizedBox.expand(),
),
);
Widget child = ClipOval( Widget child = ClipOval(
child: Column( child: Column(
children: [ children: [
coloredBox(primary), _coloredBox(primary),
Expanded( Expanded(
child: Row( child: Row(
children: [ children: [
coloredBox(tertiary), _coloredBox(tertiary),
coloredBox(primaryContainer), _coloredBox(primaryContainer),
], ],
), ),
), ),
@@ -50,7 +43,7 @@ class ColorPalette extends StatelessWidget {
width: 23, width: 23,
height: 23, height: 23,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color(Hct.from(hct.hue, 30.0, 40.0).toInt()), color: colorScheme.surfaceContainer,
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Icon( child: Icon(
@@ -66,11 +59,20 @@ class ColorPalette extends StatelessWidget {
width: 50, width: 50,
height: 50, height: 50,
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
decoration: BoxDecoration( decoration: showBgColor
color: theme.colorScheme.onInverseSurface, ? BoxDecoration(
borderRadius: StyleString.mdRadius, color: colorScheme.onInverseSurface,
), borderRadius: StyleString.mdRadius,
)
: null,
child: child, child: child,
); );
} }
static Widget _coloredBox(Color color) => Expanded(
child: ColoredBox(
color: color,
child: const SizedBox.expand(),
),
);
} }

View File

@@ -3402,6 +3402,17 @@ class EditableTextState extends State<EditableText>
if (!_isMultiline) { if (!_isMultiline) {
_finalizeEditing(action, shouldUnfocus: true); _finalizeEditing(action, shouldUnfocus: true);
} else if (HardwareKeyboard.instance.isControlPressed) { } else if (HardwareKeyboard.instance.isControlPressed) {
final ctr = widget.controller;
final offset = ctr.selection.end;
// delete newline
ctr.syncRichText(
TextEditingDeltaDeletion(
composing: TextRange.empty,
selection: TextSelection.collapsed(offset: offset - 1),
deletedRange: TextRange(start: offset - 1, end: offset),
oldText: ctr.text,
),
);
_finalizeEditing(action, shouldUnfocus: true); _finalizeEditing(action, shouldUnfocus: true);
} }
case TextInputAction.done: case TextInputAction.done:

View File

@@ -15,6 +15,7 @@ import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/cache_manager.dart'; import 'package:PiliPlus/utils/cache_manager.dart';
import 'package:PiliPlus/utils/calc_window_position.dart'; import 'package:PiliPlus/utils/calc_window_position.dart';
import 'package:PiliPlus/utils/date_utils.dart'; import 'package:PiliPlus/utils/date_utils.dart';
import 'package:PiliPlus/utils/extension/theme_ext.dart';
import 'package:PiliPlus/utils/json_file_handler.dart'; import 'package:PiliPlus/utils/json_file_handler.dart';
import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/path_utils.dart'; import 'package:PiliPlus/utils/path_utils.dart';
@@ -267,24 +268,14 @@ class MyApp extends StatelessWidget {
theme: ThemeUtils.getThemeData( theme: ThemeUtils.getThemeData(
colorScheme: dynamicColor colorScheme: dynamicColor
? _light! ? _light!
: SeedColorScheme.fromSeeds( : brandColor.asColorSchemeSeed(variant, .light),
variant: variant,
primaryKey: brandColor,
brightness: Brightness.light,
useExpressiveOnContainerColors: false,
),
isDynamic: dynamicColor, isDynamic: dynamicColor,
), ),
darkTheme: ThemeUtils.getThemeData( darkTheme: ThemeUtils.getThemeData(
isDark: true, isDark: true,
colorScheme: dynamicColor colorScheme: dynamicColor
? _dark! ? _dark!
: SeedColorScheme.fromSeeds( : brandColor.asColorSchemeSeed(variant, .dark),
variant: variant,
primaryKey: brandColor,
brightness: Brightness.dark,
useExpressiveOnContainerColors: false,
),
isDynamic: dynamicColor, isDynamic: dynamicColor,
), ),
themeMode: Pref.themeMode, themeMode: Pref.themeMode,
@@ -348,8 +339,8 @@ class MyApp extends StatelessWidget {
} }
/// from [DynamicColorBuilderState.initPlatformState] /// from [DynamicColorBuilderState.initPlatformState]
static Future<void> initPlatformState() async { static Future<bool> initPlatformState() async {
if (_light != null || _dark != null) return; if (_light != null || _dark != null) return true;
// Platform messages may fail, so we use a try/catch PlatformException. // Platform messages may fail, so we use a try/catch PlatformException.
try { try {
final corePalette = await DynamicColorPlugin.getCorePalette(); final corePalette = await DynamicColorPlugin.getCorePalette();
@@ -360,7 +351,7 @@ class MyApp extends StatelessWidget {
} }
_light = corePalette.toColorScheme(); _light = corePalette.toColorScheme();
_dark = corePalette.toColorScheme(brightness: Brightness.dark); _dark = corePalette.toColorScheme(brightness: Brightness.dark);
return; return true;
} }
} on PlatformException { } on PlatformException {
if (kDebugMode) { if (kDebugMode) {
@@ -375,15 +366,10 @@ class MyApp extends StatelessWidget {
if (kDebugMode) { if (kDebugMode) {
debugPrint('dynamic_color: Accent color detected.'); debugPrint('dynamic_color: Accent color detected.');
} }
_light = ColorScheme.fromSeed( final variant = FlexSchemeVariant.values[Pref.schemeVariant];
seedColor: accentColor, _light = accentColor.asColorSchemeSeed(variant, .light);
brightness: Brightness.light, _dark = accentColor.asColorSchemeSeed(variant, .dark);
); return true;
_dark = ColorScheme.fromSeed(
seedColor: accentColor,
brightness: Brightness.dark,
);
return;
} }
} on PlatformException { } on PlatformException {
if (kDebugMode) { if (kDebugMode) {
@@ -393,6 +379,8 @@ class MyApp extends StatelessWidget {
if (kDebugMode) { if (kDebugMode) {
debugPrint('dynamic_color: Dynamic color not detected on this device.'); debugPrint('dynamic_color: Dynamic color not detected on this device.');
} }
GStorage.setting.put(SettingBoxKey.dynamicColor, false);
return false;
} }
} }

View File

@@ -1,6 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:PiliPlus/common/widgets/color_palette.dart';
import 'package:PiliPlus/common/widgets/custom_toast.dart'; import 'package:PiliPlus/common/widgets/custom_toast.dart';
import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
@@ -11,6 +12,7 @@ import 'package:PiliPlus/models/common/dynamic/up_panel_position.dart';
import 'package:PiliPlus/models/common/home_tab_type.dart'; import 'package:PiliPlus/models/common/home_tab_type.dart';
import 'package:PiliPlus/models/common/msg/msg_unread_type.dart'; import 'package:PiliPlus/models/common/msg/msg_unread_type.dart';
import 'package:PiliPlus/models/common/nav_bar_config.dart'; import 'package:PiliPlus/models/common/nav_bar_config.dart';
import 'package:PiliPlus/models/common/theme/theme_color_type.dart';
import 'package:PiliPlus/models/common/theme/theme_type.dart'; import 'package:PiliPlus/models/common/theme/theme_type.dart';
import 'package:PiliPlus/pages/main/controller.dart'; import 'package:PiliPlus/pages/main/controller.dart';
import 'package:PiliPlus/pages/mine/controller.dart'; import 'package:PiliPlus/pages/mine/controller.dart';
@@ -22,12 +24,15 @@ import 'package:PiliPlus/pages/setting/widgets/multi_select_dialog.dart';
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart'; import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
import 'package:PiliPlus/pages/setting/widgets/slide_dialog.dart'; import 'package:PiliPlus/pages/setting/widgets/slide_dialog.dart';
import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart'; import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart';
import 'package:PiliPlus/utils/extension/get_ext.dart';
import 'package:PiliPlus/utils/extension/theme_ext.dart';
import 'package:PiliPlus/utils/global_data.dart'; import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart'; import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:auto_orientation/auto_orientation.dart'; import 'package:auto_orientation/auto_orientation.dart';
import 'package:flex_seed_scheme/flex_seed_scheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -548,7 +553,7 @@ List<SettingsModel> get styleSettings => [
Get.find<MineController>().themeType.value = result; Get.find<MineController>().themeType.value = result;
} catch (_) {} } catch (_) {}
GStorage.setting.put(SettingBoxKey.themeMode, result.index); GStorage.setting.put(SettingBoxKey.themeMode, result.index);
Get.put(ColorSelectController()).themeType.value = result; Get.putOrFind(ColorSelectController.new).themeType.value = result;
Get.changeThemeMode(result.toThemeMode); Get.changeThemeMode(result.toThemeMode);
setState(); setState();
} }
@@ -572,8 +577,21 @@ List<SettingsModel> get styleSettings => [
onTap: (context, setState) => Get.toNamed('/colorSetting'), onTap: (context, setState) => Get.toNamed('/colorSetting'),
leading: const Icon(Icons.color_lens_outlined), leading: const Icon(Icons.color_lens_outlined),
title: '应用主题', title: '应用主题',
getSubtitle: () => getSubtitle: () => '当前主题:${Pref.dynamicColor ? '动态取色' : '指定颜色'}',
'当前主题:${Get.put(ColorSelectController()).dynamicColor.value ? '动态取色' : '指定颜色'}', getTrailing: () => Pref.dynamicColor
? Icon(Icons.color_lens_rounded, color: Get.theme.colorScheme.primary)
: SizedBox.square(
dimension: 32,
child: ColorPalette(
colorScheme: colorThemeTypes[Pref.customColor].color
.asColorSchemeSeed(
FlexSchemeVariant.values[Pref.schemeVariant],
Get.theme.brightness,
),
selected: false,
showBgColor: false,
),
),
), ),
NormalModel( NormalModel(
onTap: (context, setState) async { onTap: (context, setState) async {
@@ -671,15 +689,18 @@ List<SettingsModel> get styleSettings => [
onTap: (context, setState) async { onTap: (context, setState) async {
final result = await Get.toNamed('/fontSizeSetting'); final result = await Get.toNamed('/fontSizeSetting');
if (result != null) { if (result != null) {
Get.put(ColorSelectController()).currentTextScale.value = result; Get.putOrFind(ColorSelectController.new).currentTextScale.value =
result;
} }
}, },
title: '字体大小', title: '字体大小',
leading: const Icon(Icons.format_size_outlined), leading: const Icon(Icons.format_size_outlined),
getSubtitle: () => getSubtitle: () =>
Get.put(ColorSelectController()).currentTextScale.value == 1.0 Get.putOrFind(ColorSelectController.new).currentTextScale.value == 1.0
? '默认' ? '默认'
: Get.put(ColorSelectController()).currentTextScale.value.toString(), : Get.putOrFind(
ColorSelectController.new,
).currentTextScale.value.toString(),
), ),
NormalModel( NormalModel(
onTap: (context, setState) => Get.toNamed( onTap: (context, setState) => Get.toNamed(

View File

@@ -8,11 +8,13 @@ import 'package:PiliPlus/models/common/theme/theme_type.dart';
import 'package:PiliPlus/pages/home/view.dart'; import 'package:PiliPlus/pages/home/view.dart';
import 'package:PiliPlus/pages/mine/controller.dart'; import 'package:PiliPlus/pages/mine/controller.dart';
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart'; import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
import 'package:PiliPlus/utils/extension/theme_ext.dart';
import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart'; import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:flex_seed_scheme/flex_seed_scheme.dart'; import 'package:flex_seed_scheme/flex_seed_scheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@@ -45,7 +47,7 @@ List<Item> generateItems(int count) {
} }
class _ColorSelectPageState extends State<ColorSelectPage> { class _ColorSelectPageState extends State<ColorSelectPage> {
final ColorSelectController ctr = Get.put(ColorSelectController()); final ctr = Get.put(ColorSelectController());
FlexSchemeVariant _dynamicSchemeVariant = FlexSchemeVariant _dynamicSchemeVariant =
FlexSchemeVariant.values[Pref.schemeVariant]; FlexSchemeVariant.values[Pref.schemeVariant];
@@ -177,9 +179,15 @@ class _ColorSelectPageState extends State<ColorSelectPage> {
..dynamicColor.value = val! ..dynamicColor.value = val!
..setting.put(SettingBoxKey.dynamicColor, val); ..setting.put(SettingBoxKey.dynamicColor, val);
if (val) { if (val) {
await MyApp.initPlatformState(); if (await MyApp.initPlatformState()) {
Get.forceAppUpdate();
} else {
SmartDialog.showToast('该设备可能不支持动态取色');
ctr.dynamicColor.value = false;
}
} else {
Get.forceAppUpdate();
} }
Get.forceAppUpdate();
}, },
), ),
), ),
@@ -218,7 +226,10 @@ class _ColorSelectPageState extends State<ColorSelectPage> {
spacing: 3, spacing: 3,
children: [ children: [
ColorPalette( ColorPalette(
color: item.color, colorScheme: item.color.asColorSchemeSeed(
_dynamicSchemeVariant,
theme.brightness,
),
selected: ctr.currentColor.value == index, selected: ctr.currentColor.value == index,
), ),
Text( Text(
@@ -275,5 +286,5 @@ class ColorSelectController extends GetxController {
final RxDouble currentTextScale = Pref.defaultTextScale.obs; final RxDouble currentTextScale = Pref.defaultTextScale.obs;
final Rx<ThemeType> themeType = Pref.themeType.obs; final Rx<ThemeType> themeType = Pref.themeType.obs;
Box setting = GStorage.setting; Box get setting => GStorage.setting;
} }

View File

@@ -7,7 +7,7 @@ class NormalItem extends StatefulWidget {
final String? subtitle; final String? subtitle;
final ValueGetter<String>? getSubtitle; final ValueGetter<String>? getSubtitle;
final Widget? leading; final Widget? leading;
final Widget Function()? getTrailing; final ValueGetter<Widget?>? getTrailing;
final void Function(BuildContext context, void Function() setState)? onTap; final void Function(BuildContext context, void Function() setState)? onTap;
final EdgeInsetsGeometry? contentPadding; final EdgeInsetsGeometry? contentPadding;
final TextStyle? titleStyle; final TextStyle? titleStyle;

View File

@@ -1,3 +1,4 @@
import 'package:flex_seed_scheme/flex_seed_scheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
extension ColorSchemeExt on ColorScheme { extension ColorSchemeExt on ColorScheme {
@@ -17,6 +18,16 @@ extension ColorExtension on Color {
assert(amount >= 0 && amount <= 1, 'Amount must be between 0 and 1'); assert(amount >= 0 && amount <= 1, 'Amount must be between 0 and 1');
return Color.lerp(this, Colors.black, amount)!; return Color.lerp(this, Colors.black, amount)!;
} }
ColorScheme asColorSchemeSeed([
FlexSchemeVariant variant = .material,
Brightness brightness = .light,
]) => SeedColorScheme.fromSeeds(
primaryKey: this,
variant: variant,
brightness: brightness,
useExpressiveOnContainerColors: false,
);
} }
extension BrightnessExt on Brightness { extension BrightnessExt on Brightness {