Chore/use pub.dev color picker package (#1877)
* chore: restore flutter_colorpicker and update to the latest compatible stable flutter sdk * revert: remove cloned flutter_colorpicker package * chore: update import of flutter_colorpicker package in color_dialog.dartpull/1878/head
parent
c4e47fd18a
commit
4e1d8475ee
9 changed files with 3 additions and 3418 deletions
@ -1,9 +0,0 @@ |
|||||||
library flutter_colorpicker; |
|
||||||
|
|
||||||
// TODO: temporarily clone https://pub.dev/packages/flutter_colorpicker as it's hasn't been published on pub.dev for a while |
|
||||||
|
|
||||||
export 'src/block_picker.dart'; |
|
||||||
export 'src/colorpicker.dart'; |
|
||||||
export 'src/material_picker.dart'; |
|
||||||
export 'src/palette.dart'; |
|
||||||
export 'src/utils.dart'; |
|
@ -1,211 +0,0 @@ |
|||||||
// ignore_for_file: type=lint |
|
||||||
|
|
||||||
/// Blocky Color Picker |
|
||||||
|
|
||||||
library block_colorpicker; |
|
||||||
|
|
||||||
import 'package:flutter/material.dart'; |
|
||||||
import 'utils.dart'; |
|
||||||
|
|
||||||
/// Child widget for layout builder. |
|
||||||
typedef PickerItem = Widget Function(Color color); |
|
||||||
|
|
||||||
/// Customize the layout. |
|
||||||
typedef PickerLayoutBuilder = Widget Function( |
|
||||||
BuildContext context, List<Color> colors, PickerItem child); |
|
||||||
|
|
||||||
/// Customize the item shape. |
|
||||||
typedef PickerItemBuilder = Widget Function( |
|
||||||
Color color, bool isCurrentColor, void Function() changeColor); |
|
||||||
|
|
||||||
// Provide a list of colors for block color picker. |
|
||||||
const List<Color> _defaultColors = [ |
|
||||||
Colors.red, |
|
||||||
Colors.pink, |
|
||||||
Colors.purple, |
|
||||||
Colors.deepPurple, |
|
||||||
Colors.indigo, |
|
||||||
Colors.blue, |
|
||||||
Colors.lightBlue, |
|
||||||
Colors.cyan, |
|
||||||
Colors.teal, |
|
||||||
Colors.green, |
|
||||||
Colors.lightGreen, |
|
||||||
Colors.lime, |
|
||||||
Colors.yellow, |
|
||||||
Colors.amber, |
|
||||||
Colors.orange, |
|
||||||
Colors.deepOrange, |
|
||||||
Colors.brown, |
|
||||||
Colors.grey, |
|
||||||
Colors.blueGrey, |
|
||||||
Colors.black, |
|
||||||
]; |
|
||||||
|
|
||||||
// Provide a layout for [BlockPicker]. |
|
||||||
Widget _defaultLayoutBuilder( |
|
||||||
BuildContext context, List<Color> colors, PickerItem child) { |
|
||||||
Orientation orientation = MediaQuery.of(context).orientation; |
|
||||||
|
|
||||||
return SizedBox( |
|
||||||
width: 300, |
|
||||||
height: orientation == Orientation.portrait ? 360 : 200, |
|
||||||
child: GridView.count( |
|
||||||
crossAxisCount: orientation == Orientation.portrait ? 4 : 6, |
|
||||||
crossAxisSpacing: 5, |
|
||||||
mainAxisSpacing: 5, |
|
||||||
children: [for (Color color in colors) child(color)], |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
// Provide a shape for [BlockPicker]. |
|
||||||
Widget _defaultItemBuilder( |
|
||||||
Color color, bool isCurrentColor, void Function() changeColor) { |
|
||||||
return Container( |
|
||||||
margin: const EdgeInsets.all(7), |
|
||||||
decoration: BoxDecoration( |
|
||||||
shape: BoxShape.circle, |
|
||||||
color: color, |
|
||||||
boxShadow: [ |
|
||||||
BoxShadow( |
|
||||||
color: color.withOpacity(0.8), |
|
||||||
offset: const Offset(1, 2), |
|
||||||
blurRadius: 5) |
|
||||||
], |
|
||||||
), |
|
||||||
child: Material( |
|
||||||
color: Colors.transparent, |
|
||||||
child: InkWell( |
|
||||||
onTap: changeColor, |
|
||||||
borderRadius: BorderRadius.circular(50), |
|
||||||
child: AnimatedOpacity( |
|
||||||
duration: const Duration(milliseconds: 210), |
|
||||||
opacity: isCurrentColor ? 1 : 0, |
|
||||||
child: Icon(Icons.done, |
|
||||||
color: useWhiteForeground(color) ? Colors.white : Colors.black), |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
// The blocky color picker you can alter the layout and shape. |
|
||||||
class BlockPicker extends StatefulWidget { |
|
||||||
const BlockPicker({ |
|
||||||
Key? key, |
|
||||||
required this.pickerColor, |
|
||||||
required this.onColorChanged, |
|
||||||
this.availableColors = _defaultColors, |
|
||||||
this.useInShowDialog = true, |
|
||||||
this.layoutBuilder = _defaultLayoutBuilder, |
|
||||||
this.itemBuilder = _defaultItemBuilder, |
|
||||||
}) : super(key: key); |
|
||||||
|
|
||||||
final Color? pickerColor; |
|
||||||
final ValueChanged<Color> onColorChanged; |
|
||||||
final List<Color> availableColors; |
|
||||||
final bool useInShowDialog; |
|
||||||
final PickerLayoutBuilder layoutBuilder; |
|
||||||
final PickerItemBuilder itemBuilder; |
|
||||||
|
|
||||||
@override |
|
||||||
State<StatefulWidget> createState() => _BlockPickerState(); |
|
||||||
} |
|
||||||
|
|
||||||
class _BlockPickerState extends State<BlockPicker> { |
|
||||||
Color? _currentColor; |
|
||||||
|
|
||||||
@override |
|
||||||
void initState() { |
|
||||||
_currentColor = widget.pickerColor; |
|
||||||
super.initState(); |
|
||||||
} |
|
||||||
|
|
||||||
void changeColor(Color color) { |
|
||||||
setState(() => _currentColor = color); |
|
||||||
widget.onColorChanged(color); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
return widget.layoutBuilder( |
|
||||||
context, |
|
||||||
widget.availableColors, |
|
||||||
(Color color) => widget.itemBuilder( |
|
||||||
color, |
|
||||||
(_currentColor != null && |
|
||||||
(widget.useInShowDialog ? true : widget.pickerColor != null)) |
|
||||||
? (_currentColor?.value == color.value) && |
|
||||||
(widget.useInShowDialog |
|
||||||
? true |
|
||||||
: widget.pickerColor?.value == color.value) |
|
||||||
: false, |
|
||||||
() => changeColor(color), |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// The blocky color picker you can alter the layout and shape with multiple choice. |
|
||||||
class MultipleChoiceBlockPicker extends StatefulWidget { |
|
||||||
const MultipleChoiceBlockPicker({ |
|
||||||
Key? key, |
|
||||||
required this.pickerColors, |
|
||||||
required this.onColorsChanged, |
|
||||||
this.availableColors = _defaultColors, |
|
||||||
this.useInShowDialog = true, |
|
||||||
this.layoutBuilder = _defaultLayoutBuilder, |
|
||||||
this.itemBuilder = _defaultItemBuilder, |
|
||||||
}) : super(key: key); |
|
||||||
|
|
||||||
final List<Color>? pickerColors; |
|
||||||
final ValueChanged<List<Color>> onColorsChanged; |
|
||||||
final List<Color> availableColors; |
|
||||||
final bool useInShowDialog; |
|
||||||
final PickerLayoutBuilder layoutBuilder; |
|
||||||
final PickerItemBuilder itemBuilder; |
|
||||||
|
|
||||||
@override |
|
||||||
State<StatefulWidget> createState() => _MultipleChoiceBlockPickerState(); |
|
||||||
} |
|
||||||
|
|
||||||
class _MultipleChoiceBlockPickerState extends State<MultipleChoiceBlockPicker> { |
|
||||||
List<Color>? _currentColors; |
|
||||||
|
|
||||||
@override |
|
||||||
void initState() { |
|
||||||
_currentColors = widget.pickerColors; |
|
||||||
super.initState(); |
|
||||||
} |
|
||||||
|
|
||||||
void toggleColor(Color color) { |
|
||||||
setState(() { |
|
||||||
if (_currentColors != null) { |
|
||||||
_currentColors!.contains(color) |
|
||||||
? _currentColors!.remove(color) |
|
||||||
: _currentColors!.add(color); |
|
||||||
} |
|
||||||
}); |
|
||||||
widget.onColorsChanged(_currentColors ?? []); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
return widget.layoutBuilder( |
|
||||||
context, |
|
||||||
widget.availableColors, |
|
||||||
(Color color) => widget.itemBuilder( |
|
||||||
color, |
|
||||||
(_currentColors != null && |
|
||||||
(widget.useInShowDialog ? true : widget.pickerColors != null)) |
|
||||||
? _currentColors!.contains(color) && |
|
||||||
(widget.useInShowDialog |
|
||||||
? true |
|
||||||
: widget.pickerColors!.contains(color)) |
|
||||||
: false, |
|
||||||
() => toggleColor(color), |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,891 +0,0 @@ |
|||||||
// ignore_for_file: type=lint |
|
||||||
|
|
||||||
/// HSV(HSB)/HSL Color Picker example |
|
||||||
/// |
|
||||||
/// You can create your own layout by importing `picker.dart`. |
|
||||||
|
|
||||||
library hsv_picker; |
|
||||||
|
|
||||||
import 'package:flutter/material.dart'; |
|
||||||
import 'palette.dart'; |
|
||||||
import 'utils.dart'; |
|
||||||
|
|
||||||
/// The default layout of Color Picker. |
|
||||||
class ColorPicker extends StatefulWidget { |
|
||||||
const ColorPicker({ |
|
||||||
Key? key, |
|
||||||
required this.pickerColor, |
|
||||||
required this.onColorChanged, |
|
||||||
this.pickerHsvColor, |
|
||||||
this.onHsvColorChanged, |
|
||||||
this.paletteType = PaletteType.hsvWithHue, |
|
||||||
this.enableAlpha = true, |
|
||||||
@Deprecated('Use empty list in [labelTypes] to disable label.') |
|
||||||
this.showLabel = true, |
|
||||||
this.labelTypes = const [ |
|
||||||
ColorLabelType.rgb, |
|
||||||
ColorLabelType.hsv, |
|
||||||
ColorLabelType.hsl |
|
||||||
], |
|
||||||
@Deprecated( |
|
||||||
'Use Theme.of(context).textTheme.bodyText1 & 2 to alter text style.') |
|
||||||
this.labelTextStyle, |
|
||||||
this.displayThumbColor = false, |
|
||||||
this.portraitOnly = false, |
|
||||||
this.colorPickerWidth = 300.0, |
|
||||||
this.pickerAreaHeightPercent = 1.0, |
|
||||||
this.pickerAreaBorderRadius = const BorderRadius.all(Radius.zero), |
|
||||||
this.hexInputBar = false, |
|
||||||
this.hexInputController, |
|
||||||
this.colorHistory, |
|
||||||
this.onHistoryChanged, |
|
||||||
}) : super(key: key); |
|
||||||
|
|
||||||
final Color pickerColor; |
|
||||||
final ValueChanged<Color> onColorChanged; |
|
||||||
final HSVColor? pickerHsvColor; |
|
||||||
final ValueChanged<HSVColor>? onHsvColorChanged; |
|
||||||
final PaletteType paletteType; |
|
||||||
final bool enableAlpha; |
|
||||||
final bool showLabel; |
|
||||||
final List<ColorLabelType> labelTypes; |
|
||||||
final TextStyle? labelTextStyle; |
|
||||||
final bool displayThumbColor; |
|
||||||
final bool portraitOnly; |
|
||||||
final double colorPickerWidth; |
|
||||||
final double pickerAreaHeightPercent; |
|
||||||
final BorderRadius pickerAreaBorderRadius; |
|
||||||
final bool hexInputBar; |
|
||||||
|
|
||||||
/// Allows setting the color using text input, via [TextEditingController]. |
|
||||||
/// |
|
||||||
/// Listens to [String] input and trying to convert it to the valid [Color]. |
|
||||||
/// Contains basic validator, that requires final input to be provided |
|
||||||
/// in one of those formats: |
|
||||||
/// |
|
||||||
/// * RGB |
|
||||||
/// * #RGB |
|
||||||
/// * RRGGBB |
|
||||||
/// * #RRGGBB |
|
||||||
/// * AARRGGBB |
|
||||||
/// * #AARRGGBB |
|
||||||
/// |
|
||||||
/// Where: A stands for Alpha, R for Red, G for Green, and B for blue color. |
|
||||||
/// It will only accept 3/6/8 long HEXs with an optional hash (`#`) at the beginning. |
|
||||||
/// Allowed characters are Latin A-F case insensitive and numbers 0-9. |
|
||||||
/// It does respect the [enableAlpha] flag, so if alpha is disabled, all inputs |
|
||||||
/// with transparency are also converted to non-transparent color values. |
|
||||||
/// ```dart |
|
||||||
/// MaterialButton( |
|
||||||
/// elevation: 3.0, |
|
||||||
/// onPressed: () { |
|
||||||
/// // The initial value can be provided directly to the controller. |
|
||||||
/// final textController = |
|
||||||
/// TextEditingController(text: '#2F19DB'); |
|
||||||
/// showDialog( |
|
||||||
/// context: context, |
|
||||||
/// builder: (BuildContext context) { |
|
||||||
/// return AlertDialog( |
|
||||||
/// scrollable: true, |
|
||||||
/// titlePadding: const EdgeInsets.all(0.0), |
|
||||||
/// contentPadding: const EdgeInsets.all(0.0), |
|
||||||
/// content: Column( |
|
||||||
/// children: [ |
|
||||||
/// ColorPicker( |
|
||||||
/// pickerColor: currentColor, |
|
||||||
/// onColorChanged: changeColor, |
|
||||||
/// colorPickerWidth: 300.0, |
|
||||||
/// pickerAreaHeightPercent: 0.7, |
|
||||||
/// enableAlpha: |
|
||||||
/// true, // hexInputController will respect it too. |
|
||||||
/// displayThumbColor: true, |
|
||||||
/// showLabel: true, |
|
||||||
/// paletteType: PaletteType.hsv, |
|
||||||
/// pickerAreaBorderRadius: const BorderRadius.only( |
|
||||||
/// topLeft: const Radius.circular(2.0), |
|
||||||
/// topRight: const Radius.circular(2.0), |
|
||||||
/// ), |
|
||||||
/// hexInputController: textController, // <- here |
|
||||||
/// portraitOnly: true, |
|
||||||
/// ), |
|
||||||
/// Padding( |
|
||||||
/// padding: const EdgeInsets.all(16), |
|
||||||
/// /* It can be any text field, for example: |
|
||||||
/// * TextField |
|
||||||
/// * TextFormField |
|
||||||
/// * CupertinoTextField |
|
||||||
/// * EditableText |
|
||||||
/// * any text field from 3-rd party package |
|
||||||
/// * your own text field |
|
||||||
/// so basically anything that supports/uses |
|
||||||
/// a TextEditingController for an editable text. |
|
||||||
/// */ |
|
||||||
/// child: CupertinoTextField( |
|
||||||
/// controller: textController, |
|
||||||
/// // Everything below is purely optional. |
|
||||||
/// prefix: Padding( |
|
||||||
/// padding: const EdgeInsets.only(left: 8), |
|
||||||
/// child: const Icon(Icons.tag), |
|
||||||
/// ), |
|
||||||
/// suffix: IconButton( |
|
||||||
/// icon: |
|
||||||
/// const Icon(Icons.content_paste_rounded), |
|
||||||
/// onPressed: () async => |
|
||||||
/// copyToClipboard(textController.text), |
|
||||||
/// ), |
|
||||||
/// autofocus: true, |
|
||||||
/// maxLength: 9, |
|
||||||
/// inputFormatters: [ |
|
||||||
/// // Any custom input formatter can be passed |
|
||||||
/// // here or use any Form validator you want. |
|
||||||
/// UpperCaseTextFormatter(), |
|
||||||
/// FilteringTextInputFormatter.allow( |
|
||||||
/// RegExp(kValidHexPattern)), |
|
||||||
/// ], |
|
||||||
/// ), |
|
||||||
/// ) |
|
||||||
/// ], |
|
||||||
/// ), |
|
||||||
/// ); |
|
||||||
/// }, |
|
||||||
/// ); |
|
||||||
/// }, |
|
||||||
/// child: const Text('Change me via text input'), |
|
||||||
/// color: currentColor, |
|
||||||
/// textColor: useWhiteForeground(currentColor) |
|
||||||
/// ? const Color(0xffffffff) |
|
||||||
/// : const Color(0xff000000), |
|
||||||
/// ), |
|
||||||
/// ``` |
|
||||||
/// |
|
||||||
/// Do not forget to `dispose()` your [TextEditingController] if you creating |
|
||||||
/// it inside any kind of [StatefulWidget]'s [State]. |
|
||||||
/// Reference: https://en.wikipedia.org/wiki/Web_colors#Hex_triplet |
|
||||||
final TextEditingController? hexInputController; |
|
||||||
final List<Color>? colorHistory; |
|
||||||
final ValueChanged<List<Color>>? onHistoryChanged; |
|
||||||
|
|
||||||
@override |
|
||||||
_ColorPickerState createState() => _ColorPickerState(); |
|
||||||
} |
|
||||||
|
|
||||||
class _ColorPickerState extends State<ColorPicker> { |
|
||||||
HSVColor currentHsvColor = const HSVColor.fromAHSV(0.0, 0.0, 0.0, 0.0); |
|
||||||
List<Color> colorHistory = []; |
|
||||||
|
|
||||||
@override |
|
||||||
void initState() { |
|
||||||
currentHsvColor = (widget.pickerHsvColor != null) |
|
||||||
? widget.pickerHsvColor as HSVColor |
|
||||||
: HSVColor.fromColor(widget.pickerColor); |
|
||||||
// If there's no initial text in `hexInputController`, |
|
||||||
if (widget.hexInputController?.text.isEmpty == true) { |
|
||||||
// set it to the current's color HEX value. |
|
||||||
widget.hexInputController?.text = colorToHex( |
|
||||||
currentHsvColor.toColor(), |
|
||||||
enableAlpha: widget.enableAlpha, |
|
||||||
); |
|
||||||
} |
|
||||||
// Listen to the text input, If there is an `hexInputController` provided. |
|
||||||
widget.hexInputController?.addListener(colorPickerTextInputListener); |
|
||||||
if (widget.colorHistory != null && widget.onHistoryChanged != null) { |
|
||||||
colorHistory = widget.colorHistory ?? []; |
|
||||||
} |
|
||||||
super.initState(); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
void didUpdateWidget(ColorPicker oldWidget) { |
|
||||||
super.didUpdateWidget(oldWidget); |
|
||||||
currentHsvColor = (widget.pickerHsvColor != null) |
|
||||||
? widget.pickerHsvColor as HSVColor |
|
||||||
: HSVColor.fromColor(widget.pickerColor); |
|
||||||
} |
|
||||||
|
|
||||||
void colorPickerTextInputListener() { |
|
||||||
// It can't be null really, since it's only listening if the controller |
|
||||||
// is provided, but it may help to calm the Dart analyzer in the future. |
|
||||||
if (widget.hexInputController == null) return; |
|
||||||
// If a user is inserting/typing any text — try to get the color value from it, |
|
||||||
// and interpret its transparency, dependent on the widget's settings. |
|
||||||
final Color? color = colorFromHex(widget.hexInputController!.text, |
|
||||||
enableAlpha: widget.enableAlpha); |
|
||||||
// If it's the valid color: |
|
||||||
if (color != null) { |
|
||||||
// set it as the current color and |
|
||||||
setState(() => currentHsvColor = HSVColor.fromColor(color)); |
|
||||||
// notify with a callback. |
|
||||||
widget.onColorChanged(color); |
|
||||||
if (widget.onHsvColorChanged != null) |
|
||||||
widget.onHsvColorChanged!(currentHsvColor); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
void dispose() { |
|
||||||
widget.hexInputController?.removeListener(colorPickerTextInputListener); |
|
||||||
super.dispose(); |
|
||||||
} |
|
||||||
|
|
||||||
Widget colorPickerSlider(TrackType trackType) { |
|
||||||
return ColorPickerSlider( |
|
||||||
trackType, |
|
||||||
currentHsvColor, |
|
||||||
(HSVColor color) { |
|
||||||
// Update text in `hexInputController` if provided. |
|
||||||
widget.hexInputController?.text = |
|
||||||
colorToHex(color.toColor(), enableAlpha: widget.enableAlpha); |
|
||||||
setState(() => currentHsvColor = color); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
if (widget.onHsvColorChanged != null) |
|
||||||
widget.onHsvColorChanged!(currentHsvColor); |
|
||||||
}, |
|
||||||
displayThumbColor: widget.displayThumbColor, |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
void onColorChanging(HSVColor color) { |
|
||||||
// Update text in `hexInputController` if provided. |
|
||||||
widget.hexInputController?.text = |
|
||||||
colorToHex(color.toColor(), enableAlpha: widget.enableAlpha); |
|
||||||
setState(() => currentHsvColor = color); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
if (widget.onHsvColorChanged != null) |
|
||||||
widget.onHsvColorChanged!(currentHsvColor); |
|
||||||
} |
|
||||||
|
|
||||||
Widget colorPicker() { |
|
||||||
return ClipRRect( |
|
||||||
borderRadius: widget.pickerAreaBorderRadius, |
|
||||||
child: Padding( |
|
||||||
padding: |
|
||||||
EdgeInsets.all(widget.paletteType == PaletteType.hueWheel ? 10 : 0), |
|
||||||
child: ColorPickerArea( |
|
||||||
currentHsvColor, onColorChanging, widget.paletteType), |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
Widget sliderByPaletteType() { |
|
||||||
switch (widget.paletteType) { |
|
||||||
case PaletteType.hsv: |
|
||||||
case PaletteType.hsvWithHue: |
|
||||||
case PaletteType.hsl: |
|
||||||
case PaletteType.hslWithHue: |
|
||||||
return colorPickerSlider(TrackType.hue); |
|
||||||
case PaletteType.hsvWithValue: |
|
||||||
case PaletteType.hueWheel: |
|
||||||
return colorPickerSlider(TrackType.value); |
|
||||||
case PaletteType.hsvWithSaturation: |
|
||||||
return colorPickerSlider(TrackType.saturation); |
|
||||||
case PaletteType.hslWithLightness: |
|
||||||
return colorPickerSlider(TrackType.lightness); |
|
||||||
case PaletteType.hslWithSaturation: |
|
||||||
return colorPickerSlider(TrackType.saturationForHSL); |
|
||||||
case PaletteType.rgbWithBlue: |
|
||||||
return colorPickerSlider(TrackType.blue); |
|
||||||
case PaletteType.rgbWithGreen: |
|
||||||
return colorPickerSlider(TrackType.green); |
|
||||||
case PaletteType.rgbWithRed: |
|
||||||
return colorPickerSlider(TrackType.red); |
|
||||||
default: |
|
||||||
return const SizedBox(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
if (MediaQuery.of(context).orientation == Orientation.portrait || |
|
||||||
widget.portraitOnly) { |
|
||||||
return Column( |
|
||||||
children: <Widget>[ |
|
||||||
SizedBox( |
|
||||||
width: widget.colorPickerWidth, |
|
||||||
height: widget.colorPickerWidth * widget.pickerAreaHeightPercent, |
|
||||||
child: colorPicker(), |
|
||||||
), |
|
||||||
Padding( |
|
||||||
padding: const EdgeInsets.fromLTRB(15.0, 5.0, 10.0, 5.0), |
|
||||||
child: Row( |
|
||||||
mainAxisAlignment: MainAxisAlignment.center, |
|
||||||
children: <Widget>[ |
|
||||||
GestureDetector( |
|
||||||
onTap: () => setState(() { |
|
||||||
if (widget.onHistoryChanged != null && |
|
||||||
!colorHistory.contains(currentHsvColor.toColor())) { |
|
||||||
colorHistory.add(currentHsvColor.toColor()); |
|
||||||
widget.onHistoryChanged!(colorHistory); |
|
||||||
} |
|
||||||
}), |
|
||||||
child: ColorIndicator(currentHsvColor), |
|
||||||
), |
|
||||||
Expanded( |
|
||||||
child: Column( |
|
||||||
children: <Widget>[ |
|
||||||
SizedBox( |
|
||||||
height: 40.0, |
|
||||||
width: widget.colorPickerWidth - 75.0, |
|
||||||
child: sliderByPaletteType()), |
|
||||||
if (widget.enableAlpha) |
|
||||||
SizedBox( |
|
||||||
height: 40.0, |
|
||||||
width: widget.colorPickerWidth - 75.0, |
|
||||||
child: colorPickerSlider(TrackType.alpha), |
|
||||||
), |
|
||||||
], |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
), |
|
||||||
), |
|
||||||
if (colorHistory.isNotEmpty) |
|
||||||
SizedBox( |
|
||||||
width: widget.colorPickerWidth, |
|
||||||
height: 50, |
|
||||||
child: |
|
||||||
ListView(scrollDirection: Axis.horizontal, children: <Widget>[ |
|
||||||
for (Color color in colorHistory) |
|
||||||
Padding( |
|
||||||
key: Key(color.hashCode.toString()), |
|
||||||
padding: const EdgeInsets.fromLTRB(15, 0, 0, 10), |
|
||||||
child: Center( |
|
||||||
child: GestureDetector( |
|
||||||
onTap: () => onColorChanging(HSVColor.fromColor(color)), |
|
||||||
child: ColorIndicator(HSVColor.fromColor(color), |
|
||||||
width: 30, height: 30), |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
const SizedBox(width: 15), |
|
||||||
]), |
|
||||||
), |
|
||||||
if (widget.showLabel && widget.labelTypes.isNotEmpty) |
|
||||||
FittedBox( |
|
||||||
child: ColorPickerLabel( |
|
||||||
currentHsvColor, |
|
||||||
enableAlpha: widget.enableAlpha, |
|
||||||
textStyle: widget.labelTextStyle, |
|
||||||
colorLabelTypes: widget.labelTypes, |
|
||||||
), |
|
||||||
), |
|
||||||
if (widget.hexInputBar) |
|
||||||
ColorPickerInput( |
|
||||||
currentHsvColor.toColor(), |
|
||||||
(Color color) { |
|
||||||
setState(() => currentHsvColor = HSVColor.fromColor(color)); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
if (widget.onHsvColorChanged != null) |
|
||||||
widget.onHsvColorChanged!(currentHsvColor); |
|
||||||
}, |
|
||||||
enableAlpha: widget.enableAlpha, |
|
||||||
embeddedText: false, |
|
||||||
), |
|
||||||
const SizedBox(height: 20.0), |
|
||||||
], |
|
||||||
); |
|
||||||
} else { |
|
||||||
return Row( |
|
||||||
children: <Widget>[ |
|
||||||
SizedBox( |
|
||||||
width: widget.colorPickerWidth, |
|
||||||
height: widget.colorPickerWidth * widget.pickerAreaHeightPercent, |
|
||||||
child: colorPicker()), |
|
||||||
Column( |
|
||||||
children: <Widget>[ |
|
||||||
Row( |
|
||||||
children: <Widget>[ |
|
||||||
const SizedBox(width: 20.0), |
|
||||||
GestureDetector( |
|
||||||
onTap: () => setState(() { |
|
||||||
if (widget.onHistoryChanged != null && |
|
||||||
!colorHistory.contains(currentHsvColor.toColor())) { |
|
||||||
colorHistory.add(currentHsvColor.toColor()); |
|
||||||
widget.onHistoryChanged!(colorHistory); |
|
||||||
} |
|
||||||
}), |
|
||||||
child: ColorIndicator(currentHsvColor), |
|
||||||
), |
|
||||||
Column( |
|
||||||
children: <Widget>[ |
|
||||||
SizedBox( |
|
||||||
height: 40.0, |
|
||||||
width: 260.0, |
|
||||||
child: sliderByPaletteType()), |
|
||||||
if (widget.enableAlpha) |
|
||||||
SizedBox( |
|
||||||
height: 40.0, |
|
||||||
width: 260.0, |
|
||||||
child: colorPickerSlider(TrackType.alpha)), |
|
||||||
], |
|
||||||
), |
|
||||||
const SizedBox(width: 10.0), |
|
||||||
], |
|
||||||
), |
|
||||||
if (colorHistory.isNotEmpty) |
|
||||||
SizedBox( |
|
||||||
width: widget.colorPickerWidth, |
|
||||||
height: 50, |
|
||||||
child: ListView( |
|
||||||
scrollDirection: Axis.horizontal, |
|
||||||
children: <Widget>[ |
|
||||||
for (Color color in colorHistory) |
|
||||||
Padding( |
|
||||||
key: Key(color.hashCode.toString()), |
|
||||||
padding: const EdgeInsets.fromLTRB(15, 18, 0, 0), |
|
||||||
child: Center( |
|
||||||
child: GestureDetector( |
|
||||||
onTap: () => |
|
||||||
onColorChanging(HSVColor.fromColor(color)), |
|
||||||
onLongPress: () { |
|
||||||
if (colorHistory.remove(color)) { |
|
||||||
widget.onHistoryChanged!(colorHistory); |
|
||||||
setState(() {}); |
|
||||||
} |
|
||||||
}, |
|
||||||
child: ColorIndicator(HSVColor.fromColor(color), |
|
||||||
width: 30, height: 30), |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
const SizedBox(width: 15), |
|
||||||
]), |
|
||||||
), |
|
||||||
const SizedBox(height: 20.0), |
|
||||||
if (widget.showLabel && widget.labelTypes.isNotEmpty) |
|
||||||
FittedBox( |
|
||||||
child: ColorPickerLabel( |
|
||||||
currentHsvColor, |
|
||||||
enableAlpha: widget.enableAlpha, |
|
||||||
textStyle: widget.labelTextStyle, |
|
||||||
colorLabelTypes: widget.labelTypes, |
|
||||||
), |
|
||||||
), |
|
||||||
if (widget.hexInputBar) |
|
||||||
ColorPickerInput( |
|
||||||
currentHsvColor.toColor(), |
|
||||||
(Color color) { |
|
||||||
setState(() => currentHsvColor = HSVColor.fromColor(color)); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
if (widget.onHsvColorChanged != null) |
|
||||||
widget.onHsvColorChanged!(currentHsvColor); |
|
||||||
}, |
|
||||||
enableAlpha: widget.enableAlpha, |
|
||||||
embeddedText: false, |
|
||||||
), |
|
||||||
const SizedBox(height: 5), |
|
||||||
], |
|
||||||
), |
|
||||||
], |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// The Color Picker with sliders only. Support HSV, HSL and RGB color model. |
|
||||||
class SlidePicker extends StatefulWidget { |
|
||||||
const SlidePicker({ |
|
||||||
Key? key, |
|
||||||
required this.pickerColor, |
|
||||||
required this.onColorChanged, |
|
||||||
this.colorModel = ColorModel.rgb, |
|
||||||
this.enableAlpha = true, |
|
||||||
this.sliderSize = const Size(260, 40), |
|
||||||
this.showSliderText = true, |
|
||||||
@Deprecated( |
|
||||||
'Use Theme.of(context).textTheme.bodyText1 & 2 to alter text style.') |
|
||||||
this.sliderTextStyle, |
|
||||||
this.showParams = true, |
|
||||||
@Deprecated('Use empty list in [labelTypes] to disable label.') |
|
||||||
this.showLabel = true, |
|
||||||
this.labelTypes = const [], |
|
||||||
@Deprecated( |
|
||||||
'Use Theme.of(context).textTheme.bodyText1 & 2 to alter text style.') |
|
||||||
this.labelTextStyle, |
|
||||||
this.showIndicator = true, |
|
||||||
this.indicatorSize = const Size(280, 50), |
|
||||||
this.indicatorAlignmentBegin = const Alignment(-1.0, -3.0), |
|
||||||
this.indicatorAlignmentEnd = const Alignment(1.0, 3.0), |
|
||||||
this.displayThumbColor = true, |
|
||||||
this.indicatorBorderRadius = const BorderRadius.all(Radius.zero), |
|
||||||
}) : super(key: key); |
|
||||||
|
|
||||||
final Color pickerColor; |
|
||||||
final ValueChanged<Color> onColorChanged; |
|
||||||
final ColorModel colorModel; |
|
||||||
final bool enableAlpha; |
|
||||||
final Size sliderSize; |
|
||||||
final bool showSliderText; |
|
||||||
final TextStyle? sliderTextStyle; |
|
||||||
final bool showLabel; |
|
||||||
final bool showParams; |
|
||||||
final List<ColorLabelType> labelTypes; |
|
||||||
final TextStyle? labelTextStyle; |
|
||||||
final bool showIndicator; |
|
||||||
final Size indicatorSize; |
|
||||||
final AlignmentGeometry indicatorAlignmentBegin; |
|
||||||
final AlignmentGeometry indicatorAlignmentEnd; |
|
||||||
final bool displayThumbColor; |
|
||||||
final BorderRadius indicatorBorderRadius; |
|
||||||
|
|
||||||
@override |
|
||||||
State<StatefulWidget> createState() => _SlidePickerState(); |
|
||||||
} |
|
||||||
|
|
||||||
class _SlidePickerState extends State<SlidePicker> { |
|
||||||
HSVColor currentHsvColor = const HSVColor.fromAHSV(0.0, 0.0, 0.0, 0.0); |
|
||||||
|
|
||||||
@override |
|
||||||
void initState() { |
|
||||||
super.initState(); |
|
||||||
currentHsvColor = HSVColor.fromColor(widget.pickerColor); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
void didUpdateWidget(SlidePicker oldWidget) { |
|
||||||
super.didUpdateWidget(oldWidget); |
|
||||||
currentHsvColor = HSVColor.fromColor(widget.pickerColor); |
|
||||||
} |
|
||||||
|
|
||||||
Widget colorPickerSlider(TrackType trackType) { |
|
||||||
return ColorPickerSlider( |
|
||||||
trackType, |
|
||||||
currentHsvColor, |
|
||||||
(HSVColor color) { |
|
||||||
setState(() => currentHsvColor = color); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
}, |
|
||||||
displayThumbColor: widget.displayThumbColor, |
|
||||||
fullThumbColor: true, |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
Widget indicator() { |
|
||||||
return ClipRRect( |
|
||||||
borderRadius: widget.indicatorBorderRadius, |
|
||||||
clipBehavior: Clip.antiAliasWithSaveLayer, |
|
||||||
child: GestureDetector( |
|
||||||
onTap: () { |
|
||||||
setState( |
|
||||||
() => currentHsvColor = HSVColor.fromColor(widget.pickerColor)); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
}, |
|
||||||
child: Container( |
|
||||||
width: widget.indicatorSize.width, |
|
||||||
height: widget.indicatorSize.height, |
|
||||||
margin: const EdgeInsets.only(bottom: 15.0), |
|
||||||
foregroundDecoration: BoxDecoration( |
|
||||||
gradient: LinearGradient( |
|
||||||
colors: [ |
|
||||||
widget.pickerColor, |
|
||||||
widget.pickerColor, |
|
||||||
currentHsvColor.toColor(), |
|
||||||
currentHsvColor.toColor(), |
|
||||||
], |
|
||||||
begin: widget.indicatorAlignmentBegin, |
|
||||||
end: widget.indicatorAlignmentEnd, |
|
||||||
stops: const [0.0, 0.5, 0.5, 1.0], |
|
||||||
), |
|
||||||
), |
|
||||||
child: const CustomPaint(painter: CheckerPainter()), |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
String getColorParams(int pos) { |
|
||||||
assert(pos >= 0 && pos < 4); |
|
||||||
if (widget.colorModel == ColorModel.rgb) { |
|
||||||
final Color color = currentHsvColor.toColor(); |
|
||||||
return [ |
|
||||||
color.red.toString(), |
|
||||||
color.green.toString(), |
|
||||||
color.blue.toString(), |
|
||||||
'${(color.opacity * 100).round()}', |
|
||||||
][pos]; |
|
||||||
} else if (widget.colorModel == ColorModel.hsv) { |
|
||||||
return [ |
|
||||||
currentHsvColor.hue.round().toString(), |
|
||||||
(currentHsvColor.saturation * 100).round().toString(), |
|
||||||
(currentHsvColor.value * 100).round().toString(), |
|
||||||
(currentHsvColor.alpha * 100).round().toString(), |
|
||||||
][pos]; |
|
||||||
} else if (widget.colorModel == ColorModel.hsl) { |
|
||||||
HSLColor hslColor = hsvToHsl(currentHsvColor); |
|
||||||
return [ |
|
||||||
hslColor.hue.round().toString(), |
|
||||||
(hslColor.saturation * 100).round().toString(), |
|
||||||
(hslColor.lightness * 100).round().toString(), |
|
||||||
(currentHsvColor.alpha * 100).round().toString(), |
|
||||||
][pos]; |
|
||||||
} else { |
|
||||||
return '??'; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
double fontSize = 14; |
|
||||||
if (widget.labelTextStyle != null && |
|
||||||
widget.labelTextStyle?.fontSize != null) { |
|
||||||
fontSize = widget.labelTextStyle?.fontSize ?? 14; |
|
||||||
} |
|
||||||
final List<TrackType> trackTypes = [ |
|
||||||
if (widget.colorModel == ColorModel.hsv) ...[ |
|
||||||
TrackType.hue, |
|
||||||
TrackType.saturation, |
|
||||||
TrackType.value |
|
||||||
], |
|
||||||
if (widget.colorModel == ColorModel.hsl) ...[ |
|
||||||
TrackType.hue, |
|
||||||
TrackType.saturationForHSL, |
|
||||||
TrackType.lightness |
|
||||||
], |
|
||||||
if (widget.colorModel == ColorModel.rgb) ...[ |
|
||||||
TrackType.red, |
|
||||||
TrackType.green, |
|
||||||
TrackType.blue |
|
||||||
], |
|
||||||
if (widget.enableAlpha) ...[TrackType.alpha], |
|
||||||
]; |
|
||||||
List<SizedBox> sliders = [ |
|
||||||
for (TrackType trackType in trackTypes) |
|
||||||
SizedBox( |
|
||||||
width: widget.sliderSize.width, |
|
||||||
height: widget.sliderSize.height, |
|
||||||
child: Row( |
|
||||||
children: <Widget>[ |
|
||||||
if (widget.showSliderText) |
|
||||||
Padding( |
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10.0), |
|
||||||
child: Text( |
|
||||||
trackType.toString().split('.').last[0].toUpperCase(), |
|
||||||
style: widget.sliderTextStyle ?? |
|
||||||
Theme.of(context).textTheme.bodyLarge, |
|
||||||
), |
|
||||||
), |
|
||||||
Expanded(child: colorPickerSlider(trackType)), |
|
||||||
if (widget.showParams) |
|
||||||
ConstrainedBox( |
|
||||||
constraints: BoxConstraints(minWidth: fontSize * 2 + 5), |
|
||||||
child: Text( |
|
||||||
getColorParams(trackTypes.indexOf(trackType)), |
|
||||||
style: widget.sliderTextStyle ?? |
|
||||||
Theme.of(context).textTheme.bodyMedium, |
|
||||||
textAlign: TextAlign.right, |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
), |
|
||||||
), |
|
||||||
]; |
|
||||||
|
|
||||||
return Column( |
|
||||||
mainAxisAlignment: MainAxisAlignment.center, |
|
||||||
crossAxisAlignment: CrossAxisAlignment.center, |
|
||||||
children: <Widget>[ |
|
||||||
if (widget.showIndicator) indicator(), |
|
||||||
if (!widget.showIndicator) const SizedBox(height: 20), |
|
||||||
...sliders, |
|
||||||
const SizedBox(height: 20.0), |
|
||||||
if (widget.showLabel && widget.labelTypes.isNotEmpty) |
|
||||||
Padding( |
|
||||||
padding: const EdgeInsets.only(bottom: 20.0), |
|
||||||
child: ColorPickerLabel( |
|
||||||
currentHsvColor, |
|
||||||
enableAlpha: widget.enableAlpha, |
|
||||||
textStyle: widget.labelTextStyle, |
|
||||||
colorLabelTypes: widget.labelTypes, |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// The Color Picker with HUE Ring & HSV model. |
|
||||||
class HueRingPicker extends StatefulWidget { |
|
||||||
const HueRingPicker({ |
|
||||||
Key? key, |
|
||||||
required this.pickerColor, |
|
||||||
required this.onColorChanged, |
|
||||||
this.portraitOnly = false, |
|
||||||
this.colorPickerHeight = 250.0, |
|
||||||
this.hueRingStrokeWidth = 20.0, |
|
||||||
this.enableAlpha = false, |
|
||||||
this.displayThumbColor = true, |
|
||||||
this.pickerAreaBorderRadius = const BorderRadius.all(Radius.zero), |
|
||||||
}) : super(key: key); |
|
||||||
|
|
||||||
final Color pickerColor; |
|
||||||
final ValueChanged<Color> onColorChanged; |
|
||||||
final bool portraitOnly; |
|
||||||
final double colorPickerHeight; |
|
||||||
final double hueRingStrokeWidth; |
|
||||||
final bool enableAlpha; |
|
||||||
final bool displayThumbColor; |
|
||||||
final BorderRadius pickerAreaBorderRadius; |
|
||||||
|
|
||||||
@override |
|
||||||
_HueRingPickerState createState() => _HueRingPickerState(); |
|
||||||
} |
|
||||||
|
|
||||||
class _HueRingPickerState extends State<HueRingPicker> { |
|
||||||
HSVColor currentHsvColor = const HSVColor.fromAHSV(0.0, 0.0, 0.0, 0.0); |
|
||||||
|
|
||||||
@override |
|
||||||
void initState() { |
|
||||||
currentHsvColor = HSVColor.fromColor(widget.pickerColor); |
|
||||||
super.initState(); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
void didUpdateWidget(HueRingPicker oldWidget) { |
|
||||||
super.didUpdateWidget(oldWidget); |
|
||||||
currentHsvColor = HSVColor.fromColor(widget.pickerColor); |
|
||||||
} |
|
||||||
|
|
||||||
void onColorChanging(HSVColor color) { |
|
||||||
setState(() => currentHsvColor = color); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
if (MediaQuery.of(context).orientation == Orientation.portrait || |
|
||||||
widget.portraitOnly) { |
|
||||||
return Column( |
|
||||||
children: <Widget>[ |
|
||||||
ClipRRect( |
|
||||||
borderRadius: widget.pickerAreaBorderRadius, |
|
||||||
child: Padding( |
|
||||||
padding: const EdgeInsets.all(15), |
|
||||||
child: Stack( |
|
||||||
alignment: AlignmentDirectional.center, |
|
||||||
children: <Widget>[ |
|
||||||
SizedBox( |
|
||||||
width: widget.colorPickerHeight, |
|
||||||
height: widget.colorPickerHeight, |
|
||||||
child: ColorPickerHueRing( |
|
||||||
currentHsvColor, |
|
||||||
onColorChanging, |
|
||||||
displayThumbColor: widget.displayThumbColor, |
|
||||||
strokeWidth: widget.hueRingStrokeWidth, |
|
||||||
), |
|
||||||
), |
|
||||||
SizedBox( |
|
||||||
width: widget.colorPickerHeight / 1.6, |
|
||||||
height: widget.colorPickerHeight / 1.6, |
|
||||||
child: ColorPickerArea( |
|
||||||
currentHsvColor, onColorChanging, PaletteType.hsv), |
|
||||||
) |
|
||||||
]), |
|
||||||
), |
|
||||||
), |
|
||||||
if (widget.enableAlpha) |
|
||||||
SizedBox( |
|
||||||
height: 40.0, |
|
||||||
width: widget.colorPickerHeight, |
|
||||||
child: ColorPickerSlider( |
|
||||||
TrackType.alpha, |
|
||||||
currentHsvColor, |
|
||||||
onColorChanging, |
|
||||||
displayThumbColor: widget.displayThumbColor, |
|
||||||
), |
|
||||||
), |
|
||||||
Padding( |
|
||||||
padding: const EdgeInsets.fromLTRB(15.0, 5.0, 10.0, 5.0), |
|
||||||
child: Row( |
|
||||||
mainAxisAlignment: MainAxisAlignment.center, |
|
||||||
children: <Widget>[ |
|
||||||
const SizedBox(width: 10), |
|
||||||
ColorIndicator(currentHsvColor), |
|
||||||
Expanded( |
|
||||||
child: Padding( |
|
||||||
padding: const EdgeInsets.fromLTRB(0, 5, 0, 20), |
|
||||||
child: ColorPickerInput( |
|
||||||
currentHsvColor.toColor(), |
|
||||||
(Color color) { |
|
||||||
setState( |
|
||||||
() => currentHsvColor = HSVColor.fromColor(color)); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
}, |
|
||||||
enableAlpha: widget.enableAlpha, |
|
||||||
embeddedText: true, |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
); |
|
||||||
} else { |
|
||||||
return Row( |
|
||||||
children: <Widget>[ |
|
||||||
Expanded( |
|
||||||
child: SizedBox( |
|
||||||
width: 300.0, |
|
||||||
height: widget.colorPickerHeight, |
|
||||||
child: ClipRRect( |
|
||||||
borderRadius: widget.pickerAreaBorderRadius, |
|
||||||
child: ColorPickerArea( |
|
||||||
currentHsvColor, onColorChanging, PaletteType.hsv), |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
ClipRRect( |
|
||||||
borderRadius: widget.pickerAreaBorderRadius, |
|
||||||
child: Padding( |
|
||||||
padding: const EdgeInsets.all(15), |
|
||||||
child: Stack( |
|
||||||
alignment: AlignmentDirectional.topCenter, |
|
||||||
children: <Widget>[ |
|
||||||
SizedBox( |
|
||||||
width: widget.colorPickerHeight - |
|
||||||
widget.hueRingStrokeWidth * 2, |
|
||||||
height: widget.colorPickerHeight - |
|
||||||
widget.hueRingStrokeWidth * 2, |
|
||||||
child: ColorPickerHueRing( |
|
||||||
currentHsvColor, onColorChanging, |
|
||||||
strokeWidth: widget.hueRingStrokeWidth), |
|
||||||
), |
|
||||||
Column( |
|
||||||
children: [ |
|
||||||
SizedBox(height: widget.colorPickerHeight / 8.5), |
|
||||||
ColorIndicator(currentHsvColor), |
|
||||||
const SizedBox(height: 10), |
|
||||||
ColorPickerInput( |
|
||||||
currentHsvColor.toColor(), |
|
||||||
(Color color) { |
|
||||||
setState(() => |
|
||||||
currentHsvColor = HSVColor.fromColor(color)); |
|
||||||
widget.onColorChanged(currentHsvColor.toColor()); |
|
||||||
}, |
|
||||||
enableAlpha: widget.enableAlpha, |
|
||||||
embeddedText: true, |
|
||||||
disable: true, |
|
||||||
), |
|
||||||
if (widget.enableAlpha) const SizedBox(height: 5), |
|
||||||
if (widget.enableAlpha) |
|
||||||
SizedBox( |
|
||||||
height: 40.0, |
|
||||||
width: (widget.colorPickerHeight - |
|
||||||
widget.hueRingStrokeWidth * 2) / |
|
||||||
2, |
|
||||||
child: ColorPickerSlider( |
|
||||||
TrackType.alpha, |
|
||||||
currentHsvColor, |
|
||||||
onColorChanging, |
|
||||||
displayThumbColor: true, |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
), |
|
||||||
]), |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,172 +0,0 @@ |
|||||||
// ignore_for_file: type=lint |
|
||||||
|
|
||||||
import 'dart:ui'; |
|
||||||
|
|
||||||
/// X11 Colors |
|
||||||
/// |
|
||||||
/// https://en.wikipedia.org/wiki/X11_color_names |
|
||||||
|
|
||||||
const Map<String, Color> x11Colors = { |
|
||||||
'aliceblue': Color(0xfff0f8ff), |
|
||||||
'antiquewhite': Color(0xfffaebd7), |
|
||||||
'aqua': Color(0xff00ffff), |
|
||||||
'aquamarine': Color(0xff7fffd4), |
|
||||||
'azure': Color(0xfff0ffff), |
|
||||||
'beige': Color(0xfff5f5dc), |
|
||||||
'bisque': Color(0xffffe4c4), |
|
||||||
'black': Color(0xff000000), |
|
||||||
'blanchedalmond': Color(0xffffebcd), |
|
||||||
'blue': Color(0xff0000ff), |
|
||||||
'blueviolet': Color(0xff8a2be2), |
|
||||||
'brown': Color(0xffa52a2a), |
|
||||||
'burlywood': Color(0xffdeb887), |
|
||||||
'cadetblue': Color(0xff5f9ea0), |
|
||||||
'chartreuse': Color(0xff7fff00), |
|
||||||
'chocolate': Color(0xffd2691e), |
|
||||||
'coral': Color(0xffff7f50), |
|
||||||
'cornflower': Color(0xff6495ed), |
|
||||||
'cornflowerblue': Color(0xff6495ed), |
|
||||||
'cornsilk': Color(0xfffff8dc), |
|
||||||
'crimson': Color(0xffdc143c), |
|
||||||
'cyan': Color(0xff00ffff), |
|
||||||
'darkblue': Color(0xff00008b), |
|
||||||
'darkcyan': Color(0xff008b8b), |
|
||||||
'darkgoldenrod': Color(0xffb8860b), |
|
||||||
'darkgray': Color(0xffa9a9a9), |
|
||||||
'darkgreen': Color(0xff006400), |
|
||||||
'darkgrey': Color(0xffa9a9a9), |
|
||||||
'darkkhaki': Color(0xffbdb76b), |
|
||||||
'darkmagenta': Color(0xff8b008b), |
|
||||||
'darkolivegreen': Color(0xff556b2f), |
|
||||||
'darkorange': Color(0xffff8c00), |
|
||||||
'darkorchid': Color(0xff9932cc), |
|
||||||
'darkred': Color(0xff8b0000), |
|
||||||
'darksalmon': Color(0xffe9967a), |
|
||||||
'darkseagreen': Color(0xff8fbc8f), |
|
||||||
'darkslateblue': Color(0xff483d8b), |
|
||||||
'darkslategray': Color(0xff2f4f4f), |
|
||||||
'darkslategrey': Color(0xff2f4f4f), |
|
||||||
'darkturquoise': Color(0xff00ced1), |
|
||||||
'darkviolet': Color(0xff9400d3), |
|
||||||
'deeppink': Color(0xffff1493), |
|
||||||
'deepskyblue': Color(0xff00bfff), |
|
||||||
'dimgray': Color(0xff696969), |
|
||||||
'dimgrey': Color(0xff696969), |
|
||||||
'dodgerblue': Color(0xff1e90ff), |
|
||||||
'firebrick': Color(0xffb22222), |
|
||||||
'floralwhite': Color(0xfffffaf0), |
|
||||||
'forestgreen': Color(0xff228b22), |
|
||||||
'fuchsia': Color(0xffff00ff), |
|
||||||
'gainsboro': Color(0xffdcdcdc), |
|
||||||
'ghostwhite': Color(0xfff8f8ff), |
|
||||||
'gold': Color(0xffffd700), |
|
||||||
'goldenrod': Color(0xffdaa520), |
|
||||||
'gray': Color(0xff808080), |
|
||||||
'green': Color(0xff008000), |
|
||||||
'greenyellow': Color(0xffadff2f), |
|
||||||
'grey': Color(0xff808080), |
|
||||||
'honeydew': Color(0xfff0fff0), |
|
||||||
'hotpink': Color(0xffff69b4), |
|
||||||
'indianred': Color(0xffcd5c5c), |
|
||||||
'indigo': Color(0xff4b0082), |
|
||||||
'ivory': Color(0xfffffff0), |
|
||||||
'khaki': Color(0xfff0e68c), |
|
||||||
'laserlemon': Color(0xffffff54), |
|
||||||
'lavender': Color(0xffe6e6fa), |
|
||||||
'lavenderblush': Color(0xfffff0f5), |
|
||||||
'lawngreen': Color(0xff7cfc00), |
|
||||||
'lemonchiffon': Color(0xfffffacd), |
|
||||||
'lightblue': Color(0xffadd8e6), |
|
||||||
'lightcoral': Color(0xfff08080), |
|
||||||
'lightcyan': Color(0xffe0ffff), |
|
||||||
'lightgoldenrod': Color(0xfffafad2), |
|
||||||
'lightgoldenrodyellow': Color(0xfffafad2), |
|
||||||
'lightgray': Color(0xffd3d3d3), |
|
||||||
'lightgreen': Color(0xff90ee90), |
|
||||||
'lightgrey': Color(0xffd3d3d3), |
|
||||||
'lightpink': Color(0xffffb6c1), |
|
||||||
'lightsalmon': Color(0xffffa07a), |
|
||||||
'lightseagreen': Color(0xff20b2aa), |
|
||||||
'lightskyblue': Color(0xff87cefa), |
|
||||||
'lightslategray': Color(0xff778899), |
|
||||||
'lightslategrey': Color(0xff778899), |
|
||||||
'lightsteelblue': Color(0xffb0c4de), |
|
||||||
'lightyellow': Color(0xffffffe0), |
|
||||||
'lime': Color(0xff00ff00), |
|
||||||
'limegreen': Color(0xff32cd32), |
|
||||||
'linen': Color(0xfffaf0e6), |
|
||||||
'magenta': Color(0xffff00ff), |
|
||||||
'maroon': Color(0xff800000), |
|
||||||
'maroon2': Color(0xff7f0000), |
|
||||||
'maroon3': Color(0xffb03060), |
|
||||||
'mediumaquamarine': Color(0xff66cdaa), |
|
||||||
'mediumblue': Color(0xff0000cd), |
|
||||||
'mediumorchid': Color(0xffba55d3), |
|
||||||
'mediumpurple': Color(0xff9370db), |
|
||||||
'mediumseagreen': Color(0xff3cb371), |
|
||||||
'mediumslateblue': Color(0xff7b68ee), |
|
||||||
'mediumspringgreen': Color(0xff00fa9a), |
|
||||||
'mediumturquoise': Color(0xff48d1cc), |
|
||||||
'mediumvioletred': Color(0xffc71585), |
|
||||||
'midnightblue': Color(0xff191970), |
|
||||||
'mintcream': Color(0xfff5fffa), |
|
||||||
'mistyrose': Color(0xffffe4e1), |
|
||||||
'moccasin': Color(0xffffe4b5), |
|
||||||
'navajowhite': Color(0xffffdead), |
|
||||||
'navy': Color(0xff000080), |
|
||||||
'oldlace': Color(0xfffdf5e6), |
|
||||||
'olive': Color(0xff808000), |
|
||||||
'olivedrab': Color(0xff6b8e23), |
|
||||||
'orange': Color(0xffffa500), |
|
||||||
'orangered': Color(0xffff4500), |
|
||||||
'orchid': Color(0xffda70d6), |
|
||||||
'palegoldenrod': Color(0xffeee8aa), |
|
||||||
'palegreen': Color(0xff98fb98), |
|
||||||
'paleturquoise': Color(0xffafeeee), |
|
||||||
'palevioletred': Color(0xffdb7093), |
|
||||||
'papayawhip': Color(0xffffefd5), |
|
||||||
'peachpuff': Color(0xffffdab9), |
|
||||||
'peru': Color(0xffcd853f), |
|
||||||
'pink': Color(0xffffc0cb), |
|
||||||
'plum': Color(0xffdda0dd), |
|
||||||
'powderblue': Color(0xffb0e0e6), |
|
||||||
'purple': Color(0xff800080), |
|
||||||
'purple2': Color(0xff7f007f), |
|
||||||
'purple3': Color(0xffa020f0), |
|
||||||
'rebeccapurple': Color(0xff663399), |
|
||||||
'red': Color(0xffff0000), |
|
||||||
'rosybrown': Color(0xffbc8f8f), |
|
||||||
'royalblue': Color(0xff4169e1), |
|
||||||
'saddlebrown': Color(0xff8b4513), |
|
||||||
'salmon': Color(0xfffa8072), |
|
||||||
'sandybrown': Color(0xfff4a460), |
|
||||||
'seagreen': Color(0xff2e8b57), |
|
||||||
'seashell': Color(0xfffff5ee), |
|
||||||
'sienna': Color(0xffa0522d), |
|
||||||
'silver': Color(0xffc0c0c0), |
|
||||||
'skyblue': Color(0xff87ceeb), |
|
||||||
'slateblue': Color(0xff6a5acd), |
|
||||||
'slategray': Color(0xff708090), |
|
||||||
'slategrey': Color(0xff708090), |
|
||||||
'snow': Color(0xfffffafa), |
|
||||||
'springgreen': Color(0xff00ff7f), |
|
||||||
'steelblue': Color(0xff4682b4), |
|
||||||
'tan': Color(0xffd2b48c), |
|
||||||
'teal': Color(0xff008080), |
|
||||||
'thistle': Color(0xffd8bfd8), |
|
||||||
'tomato': Color(0xffff6347), |
|
||||||
'turquoise': Color(0xff40e0d0), |
|
||||||
'violet': Color(0xffee82ee), |
|
||||||
'wheat': Color(0xfff5deb3), |
|
||||||
'white': Color(0xffffffff), |
|
||||||
'whitesmoke': Color(0xfff5f5f5), |
|
||||||
'yellow': Color(0xffffff00), |
|
||||||
'yellowgreen': Color(0xff9acd32), |
|
||||||
}; |
|
||||||
|
|
||||||
Color? colorFromName(String val) => |
|
||||||
x11Colors[val.trim().replaceAll(' ', '').toLowerCase()]; |
|
||||||
|
|
||||||
extension ColorExtension on String { |
|
||||||
Color? toColor() => colorFromName(this); |
|
||||||
} |
|
@ -1,384 +0,0 @@ |
|||||||
// ignore_for_file: type=lint |
|
||||||
|
|
||||||
/// Material Color Picker |
|
||||||
|
|
||||||
library material_colorpicker; |
|
||||||
|
|
||||||
import 'package:flutter/gestures.dart'; |
|
||||||
import 'package:flutter/material.dart'; |
|
||||||
import 'utils.dart'; |
|
||||||
|
|
||||||
// The Color Picker which contains Material Design Color Palette. |
|
||||||
class MaterialPicker extends StatefulWidget { |
|
||||||
const MaterialPicker({ |
|
||||||
Key? key, |
|
||||||
required this.pickerColor, |
|
||||||
required this.onColorChanged, |
|
||||||
this.onPrimaryChanged, |
|
||||||
this.enableLabel = false, |
|
||||||
this.portraitOnly = false, |
|
||||||
}) : super(key: key); |
|
||||||
|
|
||||||
final Color pickerColor; |
|
||||||
final ValueChanged<Color> onColorChanged; |
|
||||||
final ValueChanged<Color>? onPrimaryChanged; |
|
||||||
final bool enableLabel; |
|
||||||
final bool portraitOnly; |
|
||||||
|
|
||||||
@override |
|
||||||
State<StatefulWidget> createState() => _MaterialPickerState(); |
|
||||||
} |
|
||||||
|
|
||||||
class _MaterialPickerState extends State<MaterialPicker> { |
|
||||||
final List<List<Color>> _colorTypes = [ |
|
||||||
[Colors.red, Colors.redAccent], |
|
||||||
[Colors.pink, Colors.pinkAccent], |
|
||||||
[Colors.purple, Colors.purpleAccent], |
|
||||||
[Colors.deepPurple, Colors.deepPurpleAccent], |
|
||||||
[Colors.indigo, Colors.indigoAccent], |
|
||||||
[Colors.blue, Colors.blueAccent], |
|
||||||
[Colors.lightBlue, Colors.lightBlueAccent], |
|
||||||
[Colors.cyan, Colors.cyanAccent], |
|
||||||
[Colors.teal, Colors.tealAccent], |
|
||||||
[Colors.green, Colors.greenAccent], |
|
||||||
[Colors.lightGreen, Colors.lightGreenAccent], |
|
||||||
[Colors.lime, Colors.limeAccent], |
|
||||||
[Colors.yellow, Colors.yellowAccent], |
|
||||||
[Colors.amber, Colors.amberAccent], |
|
||||||
[Colors.orange, Colors.orangeAccent], |
|
||||||
[Colors.deepOrange, Colors.deepOrangeAccent], |
|
||||||
[Colors.brown], |
|
||||||
[Colors.grey], |
|
||||||
[Colors.blueGrey], |
|
||||||
[Colors.black], |
|
||||||
]; |
|
||||||
|
|
||||||
List<Color> _currentColorType = [Colors.red, Colors.redAccent]; |
|
||||||
Color _currentShading = Colors.transparent; |
|
||||||
|
|
||||||
List<Map<Color, String>> _shadingTypes(List<Color> colors) { |
|
||||||
List<Map<Color, String>> result = []; |
|
||||||
|
|
||||||
for (Color colorType in colors) { |
|
||||||
if (colorType == Colors.grey) { |
|
||||||
result.addAll([ |
|
||||||
50, |
|
||||||
100, |
|
||||||
200, |
|
||||||
300, |
|
||||||
350, |
|
||||||
400, |
|
||||||
500, |
|
||||||
600, |
|
||||||
700, |
|
||||||
800, |
|
||||||
850, |
|
||||||
900 |
|
||||||
].map((int shade) => {Colors.grey[shade]!: shade.toString()}).toList()); |
|
||||||
} else if (colorType == Colors.black || colorType == Colors.white) { |
|
||||||
result.addAll([ |
|
||||||
{Colors.black: ''}, |
|
||||||
{Colors.white: ''} |
|
||||||
]); |
|
||||||
} else if (colorType is MaterialAccentColor) { |
|
||||||
result.addAll([100, 200, 400, 700] |
|
||||||
.map((int shade) => {colorType[shade]!: 'A$shade'}) |
|
||||||
.toList()); |
|
||||||
} else if (colorType is MaterialColor) { |
|
||||||
result.addAll([50, 100, 200, 300, 400, 500, 600, 700, 800, 900] |
|
||||||
.map((int shade) => {colorType[shade]!: shade.toString()}) |
|
||||||
.toList()); |
|
||||||
} else { |
|
||||||
result.add({const Color(0x00000000): ''}); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
void initState() { |
|
||||||
for (List<Color> _colors in _colorTypes) { |
|
||||||
_shadingTypes(_colors).forEach((Map<Color, String> color) { |
|
||||||
if (widget.pickerColor.value == color.keys.first.value) { |
|
||||||
return setState(() { |
|
||||||
_currentColorType = _colors; |
|
||||||
_currentShading = color.keys.first; |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
super.initState(); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
bool _isPortrait = |
|
||||||
MediaQuery.of(context).orientation == Orientation.portrait || |
|
||||||
widget.portraitOnly; |
|
||||||
|
|
||||||
Widget _colorList() { |
|
||||||
return Container( |
|
||||||
clipBehavior: Clip.hardEdge, |
|
||||||
decoration: const BoxDecoration(), |
|
||||||
child: Container( |
|
||||||
margin: _isPortrait |
|
||||||
? const EdgeInsets.only(right: 10) |
|
||||||
: const EdgeInsets.only(bottom: 10), |
|
||||||
width: _isPortrait ? 60 : null, |
|
||||||
height: _isPortrait ? null : 60, |
|
||||||
decoration: BoxDecoration( |
|
||||||
color: Theme.of(context).cardColor, |
|
||||||
boxShadow: [ |
|
||||||
BoxShadow( |
|
||||||
color: (Theme.of(context).brightness == Brightness.light) |
|
||||||
? (Theme.of(context).brightness == Brightness.light) |
|
||||||
? Colors.grey[300]! |
|
||||||
: Colors.black38 |
|
||||||
: Colors.black38, |
|
||||||
blurRadius: 10) |
|
||||||
], |
|
||||||
border: _isPortrait |
|
||||||
? Border( |
|
||||||
right: BorderSide( |
|
||||||
color: |
|
||||||
(Theme.of(context).brightness == Brightness.light) |
|
||||||
? Colors.grey[300]! |
|
||||||
: Colors.black38, |
|
||||||
width: 1)) |
|
||||||
: Border( |
|
||||||
top: BorderSide( |
|
||||||
color: |
|
||||||
(Theme.of(context).brightness == Brightness.light) |
|
||||||
? Colors.grey[300]! |
|
||||||
: Colors.black38, |
|
||||||
width: 1)), |
|
||||||
), |
|
||||||
child: ScrollConfiguration( |
|
||||||
behavior: ScrollConfiguration.of(context) |
|
||||||
.copyWith(dragDevices: PointerDeviceKind.values.toSet()), |
|
||||||
child: ListView( |
|
||||||
scrollDirection: _isPortrait ? Axis.vertical : Axis.horizontal, |
|
||||||
children: [ |
|
||||||
_isPortrait |
|
||||||
? const Padding(padding: EdgeInsets.only(top: 7)) |
|
||||||
: const Padding(padding: EdgeInsets.only(left: 7)), |
|
||||||
..._colorTypes.map((List<Color> _colors) { |
|
||||||
Color _colorType = _colors[0]; |
|
||||||
return GestureDetector( |
|
||||||
onTap: () { |
|
||||||
if (widget.onPrimaryChanged != null) |
|
||||||
widget.onPrimaryChanged!(_colorType); |
|
||||||
setState(() => _currentColorType = _colors); |
|
||||||
}, |
|
||||||
child: Container( |
|
||||||
color: const Color(0x00000000), |
|
||||||
padding: _isPortrait |
|
||||||
? const EdgeInsets.fromLTRB(0, 7, 0, 7) |
|
||||||
: const EdgeInsets.fromLTRB(7, 0, 7, 0), |
|
||||||
child: Align( |
|
||||||
child: AnimatedContainer( |
|
||||||
duration: const Duration(milliseconds: 300), |
|
||||||
width: 25, |
|
||||||
height: 25, |
|
||||||
decoration: BoxDecoration( |
|
||||||
color: _colorType, |
|
||||||
shape: BoxShape.circle, |
|
||||||
boxShadow: _currentColorType == _colors |
|
||||||
? [ |
|
||||||
_colorType == Theme.of(context).cardColor |
|
||||||
? BoxShadow( |
|
||||||
color: |
|
||||||
(Theme.of(context).brightness == |
|
||||||
Brightness.light) |
|
||||||
? Colors.grey[300]! |
|
||||||
: Colors.black38, |
|
||||||
blurRadius: 10, |
|
||||||
) |
|
||||||
: BoxShadow( |
|
||||||
color: _colorType, |
|
||||||
blurRadius: 10, |
|
||||||
), |
|
||||||
] |
|
||||||
: null, |
|
||||||
border: _colorType == Theme.of(context).cardColor |
|
||||||
? Border.all( |
|
||||||
color: (Theme.of(context).brightness == |
|
||||||
Brightness.light) |
|
||||||
? Colors.grey[300]! |
|
||||||
: Colors.black38, |
|
||||||
width: 1) |
|
||||||
: null, |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
||||||
}), |
|
||||||
_isPortrait |
|
||||||
? const Padding(padding: EdgeInsets.only(top: 5)) |
|
||||||
: const Padding(padding: EdgeInsets.only(left: 5)), |
|
||||||
], |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
Widget _shadingList() { |
|
||||||
return ScrollConfiguration( |
|
||||||
behavior: ScrollConfiguration.of(context) |
|
||||||
.copyWith(dragDevices: PointerDeviceKind.values.toSet()), |
|
||||||
child: ListView( |
|
||||||
scrollDirection: _isPortrait ? Axis.vertical : Axis.horizontal, |
|
||||||
children: [ |
|
||||||
_isPortrait |
|
||||||
? const Padding(padding: EdgeInsets.only(top: 15)) |
|
||||||
: const Padding(padding: EdgeInsets.only(left: 15)), |
|
||||||
..._shadingTypes(_currentColorType).map((Map<Color, String> color) { |
|
||||||
final Color _color = color.keys.first; |
|
||||||
return GestureDetector( |
|
||||||
onTap: () { |
|
||||||
setState(() => _currentShading = _color); |
|
||||||
widget.onColorChanged(_color); |
|
||||||
}, |
|
||||||
child: Container( |
|
||||||
color: const Color(0x00000000), |
|
||||||
margin: _isPortrait |
|
||||||
? const EdgeInsets.only(right: 10) |
|
||||||
: const EdgeInsets.only(bottom: 10), |
|
||||||
padding: _isPortrait |
|
||||||
? const EdgeInsets.fromLTRB(0, 7, 0, 7) |
|
||||||
: const EdgeInsets.fromLTRB(7, 0, 7, 0), |
|
||||||
child: Align( |
|
||||||
child: AnimatedContainer( |
|
||||||
curve: Curves.fastOutSlowIn, |
|
||||||
duration: const Duration(milliseconds: 500), |
|
||||||
width: _isPortrait |
|
||||||
? (_currentShading == _color ? 250 : 230) |
|
||||||
: (_currentShading == _color ? 50 : 30), |
|
||||||
height: _isPortrait ? 50 : 220, |
|
||||||
decoration: BoxDecoration( |
|
||||||
color: _color, |
|
||||||
boxShadow: _currentShading == _color |
|
||||||
? [ |
|
||||||
(_color == Colors.white) || |
|
||||||
(_color == Colors.black) |
|
||||||
? BoxShadow( |
|
||||||
color: (Theme.of(context).brightness == |
|
||||||
Brightness.light) |
|
||||||
? Colors.grey[300]! |
|
||||||
: Colors.black38, |
|
||||||
blurRadius: 10, |
|
||||||
) |
|
||||||
: BoxShadow( |
|
||||||
color: _color, |
|
||||||
blurRadius: 10, |
|
||||||
), |
|
||||||
] |
|
||||||
: null, |
|
||||||
border: |
|
||||||
(_color == Colors.white) || (_color == Colors.black) |
|
||||||
? Border.all( |
|
||||||
color: (Theme.of(context).brightness == |
|
||||||
Brightness.light) |
|
||||||
? Colors.grey[300]! |
|
||||||
: Colors.black38, |
|
||||||
width: 1) |
|
||||||
: null, |
|
||||||
), |
|
||||||
child: widget.enableLabel |
|
||||||
? _isPortrait |
|
||||||
? Row( |
|
||||||
children: [ |
|
||||||
Text( |
|
||||||
' ${color.values.first}', |
|
||||||
style: TextStyle( |
|
||||||
color: useWhiteForeground(_color) |
|
||||||
? Colors.white |
|
||||||
: Colors.black), |
|
||||||
), |
|
||||||
Expanded( |
|
||||||
child: Align( |
|
||||||
alignment: Alignment.centerRight, |
|
||||||
child: Text( |
|
||||||
'#${(_color.toString().replaceFirst('Color(0xff', '').replaceFirst(')', '')).toUpperCase()} ', |
|
||||||
style: TextStyle( |
|
||||||
color: useWhiteForeground(_color) |
|
||||||
? Colors.white |
|
||||||
: Colors.black, |
|
||||||
fontWeight: FontWeight.bold, |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
) |
|
||||||
: AnimatedOpacity( |
|
||||||
duration: const Duration(milliseconds: 300), |
|
||||||
opacity: _currentShading == _color ? 1 : 0, |
|
||||||
child: Container( |
|
||||||
padding: const EdgeInsets.only(top: 16), |
|
||||||
alignment: Alignment.topCenter, |
|
||||||
child: Text( |
|
||||||
color.values.first, |
|
||||||
style: TextStyle( |
|
||||||
color: useWhiteForeground(_color) |
|
||||||
? Colors.white |
|
||||||
: Colors.black, |
|
||||||
fontWeight: FontWeight.bold, |
|
||||||
fontSize: 14, |
|
||||||
), |
|
||||||
softWrap: false, |
|
||||||
), |
|
||||||
), |
|
||||||
) |
|
||||||
: const SizedBox(), |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
||||||
}), |
|
||||||
_isPortrait |
|
||||||
? const Padding(padding: EdgeInsets.only(top: 15)) |
|
||||||
: const Padding(padding: EdgeInsets.only(left: 15)), |
|
||||||
], |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
if (_isPortrait) { |
|
||||||
return SizedBox( |
|
||||||
width: 350, |
|
||||||
height: 500, |
|
||||||
child: Row( |
|
||||||
children: <Widget>[ |
|
||||||
_colorList(), |
|
||||||
Expanded( |
|
||||||
child: Padding( |
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12), |
|
||||||
child: _shadingList(), |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
), |
|
||||||
); |
|
||||||
} else { |
|
||||||
return SizedBox( |
|
||||||
width: 500, |
|
||||||
height: 300, |
|
||||||
child: Column( |
|
||||||
children: <Widget>[ |
|
||||||
_colorList(), |
|
||||||
Expanded( |
|
||||||
child: Padding( |
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12), |
|
||||||
child: _shadingList(), |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
File diff suppressed because it is too large
Load Diff
@ -1,224 +0,0 @@ |
|||||||
// ignore_for_file: type=lint |
|
||||||
|
|
||||||
/// Common function lib |
|
||||||
|
|
||||||
import 'dart:math'; |
|
||||||
import 'package:flutter/painting.dart'; |
|
||||||
import 'colors.dart'; |
|
||||||
|
|
||||||
/// Check if is good condition to use white foreground color by passing |
|
||||||
/// the background color, and optional bias. |
|
||||||
/// |
|
||||||
/// Reference: |
|
||||||
/// |
|
||||||
/// Old: https://www.w3.org/TR/WCAG20-TECHS/G18.html |
|
||||||
/// |
|
||||||
/// New: https://github.com/mchome/flutter_statusbarcolor/issues/40 |
|
||||||
bool useWhiteForeground(Color backgroundColor, {double bias = 0.0}) { |
|
||||||
// Old: |
|
||||||
// return 1.05 / (color.computeLuminance() + 0.05) > 4.5; |
|
||||||
|
|
||||||
// New: |
|
||||||
int v = sqrt(pow(backgroundColor.red, 2) * 0.299 + |
|
||||||
pow(backgroundColor.green, 2) * 0.587 + |
|
||||||
pow(backgroundColor.blue, 2) * 0.114) |
|
||||||
.round(); |
|
||||||
return v < 130 + bias ? true : false; |
|
||||||
} |
|
||||||
|
|
||||||
/// Convert HSV to HSL |
|
||||||
/// |
|
||||||
/// Reference: https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_HSL |
|
||||||
HSLColor hsvToHsl(HSVColor color) { |
|
||||||
double s = 0.0; |
|
||||||
double l = 0.0; |
|
||||||
l = (2 - color.saturation) * color.value / 2; |
|
||||||
if (l != 0) { |
|
||||||
if (l == 1) { |
|
||||||
s = 0.0; |
|
||||||
} else if (l < 0.5) { |
|
||||||
s = color.saturation * color.value / (l * 2); |
|
||||||
} else { |
|
||||||
s = color.saturation * color.value / (2 - l * 2); |
|
||||||
} |
|
||||||
} |
|
||||||
return HSLColor.fromAHSL( |
|
||||||
color.alpha, |
|
||||||
color.hue, |
|
||||||
s.clamp(0.0, 1.0), |
|
||||||
l.clamp(0.0, 1.0), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/// Convert HSL to HSV |
|
||||||
/// |
|
||||||
/// Reference: https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_HSV |
|
||||||
HSVColor hslToHsv(HSLColor color) { |
|
||||||
double s = 0.0; |
|
||||||
double v = 0.0; |
|
||||||
|
|
||||||
v = color.lightness + |
|
||||||
color.saturation * |
|
||||||
(color.lightness < 0.5 ? color.lightness : 1 - color.lightness); |
|
||||||
if (v != 0) s = 2 - 2 * color.lightness / v; |
|
||||||
|
|
||||||
return HSVColor.fromAHSV( |
|
||||||
color.alpha, |
|
||||||
color.hue, |
|
||||||
s.clamp(0.0, 1.0), |
|
||||||
v.clamp(0.0, 1.0), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
/// [RegExp] pattern for validation HEX color [String] inputs, allows only: |
|
||||||
/// |
|
||||||
/// * exactly 1 to 8 digits in HEX format, |
|
||||||
/// * only Latin A-F characters, case insensitive, |
|
||||||
/// * and integer numbers 0,1,2,3,4,5,6,7,8,9, |
|
||||||
/// * with optional hash (`#`) symbol at the beginning (not calculated in length). |
|
||||||
/// |
|
||||||
/// ```dart |
|
||||||
/// final RegExp hexInputValidator = RegExp(kValidHexPattern); |
|
||||||
/// if (hexInputValidator.hasMatch(hex)) print('$hex might be a valid HEX color'); |
|
||||||
/// ``` |
|
||||||
/// Reference: https://en.wikipedia.org/wiki/Web_colors#Hex_triplet |
|
||||||
const String kValidHexPattern = r'^#?[0-9a-fA-F]{1,8}'; |
|
||||||
|
|
||||||
/// [RegExp] pattern for validation complete HEX color [String], allows only: |
|
||||||
/// |
|
||||||
/// * exactly 6 or 8 digits in HEX format, |
|
||||||
/// * only Latin A-F characters, case insensitive, |
|
||||||
/// * and integer numbers 0,1,2,3,4,5,6,7,8,9, |
|
||||||
/// * with optional hash (`#`) symbol at the beginning (not calculated in length). |
|
||||||
/// |
|
||||||
/// ```dart |
|
||||||
/// final RegExp hexCompleteValidator = RegExp(kCompleteValidHexPattern); |
|
||||||
/// if (hexCompleteValidator.hasMatch(hex)) print('$hex is valid HEX color'); |
|
||||||
/// ``` |
|
||||||
/// Reference: https://en.wikipedia.org/wiki/Web_colors#Hex_triplet |
|
||||||
const String kCompleteValidHexPattern = |
|
||||||
r'^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$'; |
|
||||||
|
|
||||||
/// Try to convert text input or any [String] to valid [Color]. |
|
||||||
/// The [String] must be provided in one of those formats: |
|
||||||
/// |
|
||||||
/// * RGB |
|
||||||
/// * #RGB |
|
||||||
/// * RRGGBB |
|
||||||
/// * #RRGGBB |
|
||||||
/// * AARRGGBB |
|
||||||
/// * #AARRGGBB |
|
||||||
/// |
|
||||||
/// Where: A stands for Alpha, R for Red, G for Green, and B for blue color. |
|
||||||
/// It will only accept 3/6/8 long HEXs with an optional hash (`#`) at the beginning. |
|
||||||
/// Allowed characters are Latin A-F case insensitive and numbers 0-9. |
|
||||||
/// Optional [enableAlpha] can be provided (it's `true` by default). If it's set |
|
||||||
/// to `false` transparency information (alpha channel) will be removed. |
|
||||||
/// ```dart |
|
||||||
/// /// // Valid 3 digit HEXs: |
|
||||||
/// colorFromHex('abc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('ABc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('ABC') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#Abc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#abc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#ABC') == Color(0xffaabbcc) |
|
||||||
/// // Valid 6 digit HEXs: |
|
||||||
/// colorFromHex('aabbcc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('AABbcc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('AABBCC') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#AABbcc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#aabbcc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#AABBCC') == Color(0xffaabbcc) |
|
||||||
/// // Valid 8 digit HEXs: |
|
||||||
/// colorFromHex('ffaabbcc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('ffAABbcc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('ffAABBCC') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('ffaabbcc', enableAlpha: true) == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('FFAAbbcc', enableAlpha: true) == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('ffAABBCC', enableAlpha: true) == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('FFaabbcc', enableAlpha: true) == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#ffaabbcc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#ffAABbcc') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#FFAABBCC') == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#ffaabbcc', enableAlpha: true) == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#FFAAbbcc', enableAlpha: true) == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#ffAABBCC', enableAlpha: true) == Color(0xffaabbcc) |
|
||||||
/// colorFromHex('#FFaabbcc', enableAlpha: true) == Color(0xffaabbcc) |
|
||||||
/// // Invalid HEXs: |
|
||||||
/// colorFromHex('bc') == null // length 2 |
|
||||||
/// colorFromHex('aabbc') == null // length 5 |
|
||||||
/// colorFromHex('#ffaabbccd') == null // length 9 (+#) |
|
||||||
/// colorFromHex('aabbcx') == null // x character |
|
||||||
/// colorFromHex('#aabbвв') == null // в non-latin character |
|
||||||
/// colorFromHex('') == null // empty |
|
||||||
/// ``` |
|
||||||
/// Reference: https://en.wikipedia.org/wiki/Web_colors#Hex_triplet |
|
||||||
Color? colorFromHex(String inputString, {bool enableAlpha = true}) { |
|
||||||
// Registers validator for exactly 6 or 8 digits long HEX (with optional #). |
|
||||||
final RegExp hexValidator = RegExp(kCompleteValidHexPattern); |
|
||||||
// Validating input, if it does not match — it's not proper HEX. |
|
||||||
if (!hexValidator.hasMatch(inputString)) return null; |
|
||||||
// Remove optional hash if exists and convert HEX to UPPER CASE. |
|
||||||
String hexToParse = inputString.replaceFirst('#', '').toUpperCase(); |
|
||||||
// It may allow HEXs with transparency information even if alpha is disabled, |
|
||||||
if (!enableAlpha && hexToParse.length == 8) { |
|
||||||
// but it will replace this info with 100% non-transparent value (FF). |
|
||||||
hexToParse = 'FF${hexToParse.substring(2)}'; |
|
||||||
} |
|
||||||
// HEX may be provided in 3-digits format, let's just duplicate each letter. |
|
||||||
if (hexToParse.length == 3) { |
|
||||||
hexToParse = hexToParse.split('').expand((i) => [i * 2]).join(); |
|
||||||
} |
|
||||||
// We will need 8 digits to parse the color, let's add missing digits. |
|
||||||
if (hexToParse.length == 6) hexToParse = 'FF$hexToParse'; |
|
||||||
// HEX must be valid now, but as a precaution, it will just "try" to parse it. |
|
||||||
final intColorValue = int.tryParse(hexToParse, radix: 16); |
|
||||||
// If for some reason HEX is not valid — abort the operation, return nothing. |
|
||||||
if (intColorValue == null) return null; |
|
||||||
// Register output color for the last step. |
|
||||||
final color = Color(intColorValue); |
|
||||||
// Decide to return color with transparency information or not. |
|
||||||
return enableAlpha ? color : color.withAlpha(255); |
|
||||||
} |
|
||||||
|
|
||||||
/// Converts `dart:ui` [Color] to the 6/8 digits HEX [String]. |
|
||||||
/// |
|
||||||
/// Prefixes a hash (`#`) sign if [includeHashSign] is set to `true`. |
|
||||||
/// The result will be provided as UPPER CASE, it can be changed via [toUpperCase] |
|
||||||
/// flag set to `false` (default is `true`). Hex can be returned without alpha |
|
||||||
/// channel information (transparency), with the [enableAlpha] flag set to `false`. |
|
||||||
String colorToHex( |
|
||||||
Color color, { |
|
||||||
bool includeHashSign = false, |
|
||||||
bool enableAlpha = true, |
|
||||||
bool toUpperCase = true, |
|
||||||
}) { |
|
||||||
final String hex = (includeHashSign ? '#' : '') + |
|
||||||
(enableAlpha ? _padRadix(color.alpha) : '') + |
|
||||||
_padRadix(color.red) + |
|
||||||
_padRadix(color.green) + |
|
||||||
_padRadix(color.blue); |
|
||||||
return toUpperCase ? hex.toUpperCase() : hex; |
|
||||||
} |
|
||||||
|
|
||||||
// Shorthand for padLeft of RadixString, DRY. |
|
||||||
String _padRadix(int value) => value.toRadixString(16).padLeft(2, '0'); |
|
||||||
|
|
||||||
// Extension for String |
|
||||||
extension ColorExtension1 on String { |
|
||||||
Color? toColor() { |
|
||||||
Color? color = colorFromName(this); |
|
||||||
if (color != null) return color; |
|
||||||
return colorFromHex(this); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Extension from Color |
|
||||||
extension ColorExtension2 on Color { |
|
||||||
String toHexString( |
|
||||||
{bool includeHashSign = false, |
|
||||||
bool enableAlpha = true, |
|
||||||
bool toUpperCase = true}) => |
|
||||||
colorToHex(this, |
|
||||||
includeHashSign: false, enableAlpha: true, toUpperCase: true); |
|
||||||
} |
|
Loading…
Reference in new issue