main
  1import 'dart:async';
  2
  3import 'package:flutter/material.dart';
  4import 'package:blood_pressure_app/l10n/app_localizations.dart';
  5
  6/// A list of colors in circles where one can be selected at a time.
  7class ColorPicker extends StatefulWidget {
  8  /// Create a widget to select one color from a list.
  9  const ColorPicker({super.key,
 10    required this.onColorSelected,
 11    this.availableColors,
 12    this.initialColor,
 13    this.showTransparentColor = true,
 14    this.circleSize = 50,
 15  });
 16
 17  /// Colors to choose from.
 18  ///
 19  /// Defaults to [ColorPicker.allColors].
 20  final List<Color>? availableColors;
 21
 22  /// Color that starts out highlighted.
 23  ///
 24  /// When [initialColor] is null the transparent color is selected. When
 25  /// [showTransparentColor] is false as well no color is selected.
 26  final Color? initialColor;
 27
 28  /// Called after a click on a color.
 29  final FutureOr<void> Function(Color? color) onColorSelected;
 30
 31  /// Controls whether a option for selecting that no color is displayed.
 32  final bool showTransparentColor;
 33
 34  /// List of all material colors and black/white
 35  static final List<Color> allColors = [
 36    const Color(0xFFFFFFFF),
 37    const Color(0xFF000000),
 38    Colors.red,
 39    Colors.redAccent,
 40    Colors.pink,
 41    Colors.pinkAccent,
 42    Colors.purple,
 43    Colors.purpleAccent,
 44    Colors.deepPurple,
 45    Colors.deepPurpleAccent,
 46    Colors.indigo,
 47    Colors.indigoAccent,
 48    Colors.blue,
 49    Colors.blueAccent,
 50    Colors.lightBlue,
 51    Colors.lightBlueAccent,
 52    Colors.cyan,
 53    Colors.cyanAccent,
 54    Colors.teal,
 55    Colors.tealAccent,
 56    Colors.green,
 57    Colors.greenAccent,
 58    Colors.lightGreen,
 59    Colors.lightGreenAccent,
 60    Colors.lime,
 61    Colors.limeAccent,
 62    Colors.yellow,
 63    Colors.yellowAccent,
 64    Colors.amber,
 65    Colors.amberAccent,
 66    Colors.orange,
 67    Colors.orangeAccent,
 68    Colors.deepOrange,
 69    Colors.deepOrangeAccent,
 70    Colors.brown,
 71    Colors.grey,
 72    Colors.blueGrey,
 73  ];
 74
 75  /// Size of the color circles.
 76  final double circleSize;
 77
 78  @override
 79  State<ColorPicker> createState() => _ColorPickerState();
 80}
 81
 82class _ColorPickerState extends State<ColorPicker> {
 83  /// Currently selected color.
 84  late Color _selected;
 85  late final List<Color> availableColors;
 86
 87  @override
 88  void initState() {
 89    super.initState();
 90    _selected = widget.initialColor ?? Colors.transparent;
 91    availableColors = widget.availableColors ?? ColorPicker.allColors;
 92  }
 93  @override
 94  Widget build(BuildContext context) => Wrap(
 95      children: [
 96        for (final color in availableColors)
 97            InkWell(
 98              onTap: () {
 99                setState(() {
100                  _selected = color;
101                  widget.onColorSelected(_selected);
102                });
103              },
104              child: Container(
105                decoration: BoxDecoration(
106                  color: _selected == color
107                      ? Theme.of(context).disabledColor
108                      : Colors.transparent,
109                  shape: BoxShape.circle,),
110                padding: const EdgeInsets.all(5),
111                child: Container(
112                  height: widget.circleSize,
113                  width: widget.circleSize,
114                  decoration: BoxDecoration(
115                    color: color,
116                    shape: BoxShape.circle,
117                  ),
118                ),
119              ),
120            ),
121        if (widget.showTransparentColor)
122          InkWell(
123            onTap: () {
124              setState(() {
125                _selected = Colors.transparent;
126                widget.onColorSelected(_selected);
127              });
128            },
129            child: Container(
130              padding: const EdgeInsets.all(5),
131              decoration: BoxDecoration(
132                color: _selected == Colors.transparent
133                    ? Theme.of(context).disabledColor
134                    : Colors.transparent,
135                shape: BoxShape.circle,),
136              child: SizedBox(
137                height: widget.circleSize,
138                width: widget.circleSize,
139                child: const Icon(Icons.block),
140              ),
141            ),
142          ),
143      ],
144    );
145}
146
147/// Shows a dialog with a ColorPicker and with an cancel button inside.
148///
149/// Returns the selected color or null when cancel is pressed.
150Future<Color?> showColorPickerDialog(
151  BuildContext context, [
152    Color? initialColor,
153]) async => showDialog(
154  context: context,
155  builder: (_) => AlertDialog(
156    contentPadding: const EdgeInsets.all(6.0),
157    content: ColorPicker(
158      initialColor: initialColor,
159      onColorSelected: (color) {
160        Navigator.pop(context, color);
161      },
162    ),
163    actions: [
164      TextButton(
165        onPressed: Navigator.of(context).pop,
166        child: Text(AppLocalizations.of(context)!.btnCancel),
167      ),
168    ],
169  ),
170);