diff --git a/lib/common/widgets/color_palette.dart b/lib/common/widgets/color_palette.dart index 8cf5ff8ec..12020efb4 100644 --- a/lib/common/widgets/color_palette.dart +++ b/lib/common/widgets/color_palette.dart @@ -1,39 +1,32 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:flutter/material.dart'; -import 'package:material_color_utilities/material_color_utilities.dart'; class ColorPalette extends StatelessWidget { - final Color color; + final ColorScheme colorScheme; final bool selected; + final bool showBgColor; const ColorPalette({ super.key, - required this.color, + required this.colorScheme, required this.selected, + this.showBgColor = true, }); @override Widget build(BuildContext context) { - final theme = Theme.of(context); - final Hct hct = Hct.fromInt(color.toARGB32()); - final primary = Color(Hct.from(hct.hue, 20.0, 90.0).toInt()); - 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(), - ), - ); + final primary = colorScheme.primary; + final tertiary = colorScheme.tertiary; + final primaryContainer = colorScheme.primaryContainer; Widget child = ClipOval( child: Column( children: [ - coloredBox(primary), + _coloredBox(primary), Expanded( child: Row( children: [ - coloredBox(tertiary), - coloredBox(primaryContainer), + _coloredBox(tertiary), + _coloredBox(primaryContainer), ], ), ), @@ -50,7 +43,7 @@ class ColorPalette extends StatelessWidget { width: 23, height: 23, decoration: BoxDecoration( - color: Color(Hct.from(hct.hue, 30.0, 40.0).toInt()), + color: colorScheme.surfaceContainer, shape: BoxShape.circle, ), child: Icon( @@ -66,11 +59,20 @@ class ColorPalette extends StatelessWidget { width: 50, height: 50, padding: const EdgeInsets.all(6), - decoration: BoxDecoration( - color: theme.colorScheme.onInverseSurface, - borderRadius: StyleString.mdRadius, - ), + decoration: showBgColor + ? BoxDecoration( + color: colorScheme.onInverseSurface, + borderRadius: StyleString.mdRadius, + ) + : null, child: child, ); } + + static Widget _coloredBox(Color color) => Expanded( + child: ColoredBox( + color: color, + child: const SizedBox.expand(), + ), + ); } diff --git a/lib/common/widgets/flutter/text_field/editable_text.dart b/lib/common/widgets/flutter/text_field/editable_text.dart index 0b5f77245..d41861503 100644 --- a/lib/common/widgets/flutter/text_field/editable_text.dart +++ b/lib/common/widgets/flutter/text_field/editable_text.dart @@ -3402,6 +3402,17 @@ class EditableTextState extends State if (!_isMultiline) { _finalizeEditing(action, shouldUnfocus: true); } 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); } case TextInputAction.done: diff --git a/lib/main.dart b/lib/main.dart index a6bfae0ca..a5d9f1f81 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,6 +15,7 @@ import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/cache_manager.dart'; import 'package:PiliPlus/utils/calc_window_position.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/page_utils.dart'; import 'package:PiliPlus/utils/path_utils.dart'; @@ -267,24 +268,14 @@ class MyApp extends StatelessWidget { theme: ThemeUtils.getThemeData( colorScheme: dynamicColor ? _light! - : SeedColorScheme.fromSeeds( - variant: variant, - primaryKey: brandColor, - brightness: Brightness.light, - useExpressiveOnContainerColors: false, - ), + : brandColor.asColorSchemeSeed(variant, .light), isDynamic: dynamicColor, ), darkTheme: ThemeUtils.getThemeData( isDark: true, colorScheme: dynamicColor ? _dark! - : SeedColorScheme.fromSeeds( - variant: variant, - primaryKey: brandColor, - brightness: Brightness.dark, - useExpressiveOnContainerColors: false, - ), + : brandColor.asColorSchemeSeed(variant, .dark), isDynamic: dynamicColor, ), themeMode: Pref.themeMode, @@ -348,8 +339,8 @@ class MyApp extends StatelessWidget { } /// from [DynamicColorBuilderState.initPlatformState] - static Future initPlatformState() async { - if (_light != null || _dark != null) return; + static Future initPlatformState() async { + if (_light != null || _dark != null) return true; // Platform messages may fail, so we use a try/catch PlatformException. try { final corePalette = await DynamicColorPlugin.getCorePalette(); @@ -360,7 +351,7 @@ class MyApp extends StatelessWidget { } _light = corePalette.toColorScheme(); _dark = corePalette.toColorScheme(brightness: Brightness.dark); - return; + return true; } } on PlatformException { if (kDebugMode) { @@ -375,15 +366,10 @@ class MyApp extends StatelessWidget { if (kDebugMode) { debugPrint('dynamic_color: Accent color detected.'); } - _light = ColorScheme.fromSeed( - seedColor: accentColor, - brightness: Brightness.light, - ); - _dark = ColorScheme.fromSeed( - seedColor: accentColor, - brightness: Brightness.dark, - ); - return; + final variant = FlexSchemeVariant.values[Pref.schemeVariant]; + _light = accentColor.asColorSchemeSeed(variant, .light); + _dark = accentColor.asColorSchemeSeed(variant, .dark); + return true; } } on PlatformException { if (kDebugMode) { @@ -393,6 +379,8 @@ class MyApp extends StatelessWidget { if (kDebugMode) { debugPrint('dynamic_color: Dynamic color not detected on this device.'); } + GStorage.setting.put(SettingBoxKey.dynamicColor, false); + return false; } } diff --git a/lib/pages/setting/models/style_settings.dart b/lib/pages/setting/models/style_settings.dart index 0c11bfb11..b3d61195f 100644 --- a/lib/pages/setting/models/style_settings.dart +++ b/lib/pages/setting/models/style_settings.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'dart:math'; +import 'package:PiliPlus/common/widgets/color_palette.dart'; import 'package:PiliPlus/common/widgets/custom_toast.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.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/msg/msg_unread_type.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/pages/main/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/slide_dialog.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/platform_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; import 'package:PiliPlus/utils/storage_pref.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/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -548,7 +553,7 @@ List get styleSettings => [ Get.find().themeType.value = result; } catch (_) {} GStorage.setting.put(SettingBoxKey.themeMode, result.index); - Get.put(ColorSelectController()).themeType.value = result; + Get.putOrFind(ColorSelectController.new).themeType.value = result; Get.changeThemeMode(result.toThemeMode); setState(); } @@ -572,8 +577,21 @@ List get styleSettings => [ onTap: (context, setState) => Get.toNamed('/colorSetting'), leading: const Icon(Icons.color_lens_outlined), title: '应用主题', - getSubtitle: () => - '当前主题:${Get.put(ColorSelectController()).dynamicColor.value ? '动态取色' : '指定颜色'}', + getSubtitle: () => '当前主题:${Pref.dynamicColor ? '动态取色' : '指定颜色'}', + 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( onTap: (context, setState) async { @@ -671,15 +689,18 @@ List get styleSettings => [ onTap: (context, setState) async { final result = await Get.toNamed('/fontSizeSetting'); if (result != null) { - Get.put(ColorSelectController()).currentTextScale.value = result; + Get.putOrFind(ColorSelectController.new).currentTextScale.value = + result; } }, title: '字体大小', leading: const Icon(Icons.format_size_outlined), 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( onTap: (context, setState) => Get.toNamed( diff --git a/lib/pages/setting/pages/color_select.dart b/lib/pages/setting/pages/color_select.dart index a8f8bdd91..9388a6b1c 100644 --- a/lib/pages/setting/pages/color_select.dart +++ b/lib/pages/setting/pages/color_select.dart @@ -8,11 +8,13 @@ import 'package:PiliPlus/models/common/theme/theme_type.dart'; import 'package:PiliPlus/pages/home/view.dart'; import 'package:PiliPlus/pages/mine/controller.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_key.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:flex_seed_scheme/flex_seed_scheme.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; @@ -45,7 +47,7 @@ List generateItems(int count) { } class _ColorSelectPageState extends State { - final ColorSelectController ctr = Get.put(ColorSelectController()); + final ctr = Get.put(ColorSelectController()); FlexSchemeVariant _dynamicSchemeVariant = FlexSchemeVariant.values[Pref.schemeVariant]; @@ -177,9 +179,15 @@ class _ColorSelectPageState extends State { ..dynamicColor.value = val! ..setting.put(SettingBoxKey.dynamicColor, 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 { spacing: 3, children: [ ColorPalette( - color: item.color, + colorScheme: item.color.asColorSchemeSeed( + _dynamicSchemeVariant, + theme.brightness, + ), selected: ctr.currentColor.value == index, ), Text( @@ -275,5 +286,5 @@ class ColorSelectController extends GetxController { final RxDouble currentTextScale = Pref.defaultTextScale.obs; final Rx themeType = Pref.themeType.obs; - Box setting = GStorage.setting; + Box get setting => GStorage.setting; } diff --git a/lib/pages/setting/widgets/normal_item.dart b/lib/pages/setting/widgets/normal_item.dart index aebd5a1df..0076b465e 100644 --- a/lib/pages/setting/widgets/normal_item.dart +++ b/lib/pages/setting/widgets/normal_item.dart @@ -7,7 +7,7 @@ class NormalItem extends StatefulWidget { final String? subtitle; final ValueGetter? getSubtitle; final Widget? leading; - final Widget Function()? getTrailing; + final ValueGetter? getTrailing; final void Function(BuildContext context, void Function() setState)? onTap; final EdgeInsetsGeometry? contentPadding; final TextStyle? titleStyle; diff --git a/lib/utils/extension/theme_ext.dart b/lib/utils/extension/theme_ext.dart index 28acde4ae..a14f669aa 100644 --- a/lib/utils/extension/theme_ext.dart +++ b/lib/utils/extension/theme_ext.dart @@ -1,3 +1,4 @@ +import 'package:flex_seed_scheme/flex_seed_scheme.dart'; import 'package:flutter/material.dart'; extension ColorSchemeExt on ColorScheme { @@ -17,6 +18,16 @@ extension ColorExtension on Color { assert(amount >= 0 && amount <= 1, 'Amount must be between 0 and 1'); 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 {