fix: change the template selection to use light and dark checkmark

This commit is contained in:
Freek van de Ven 2024-07-24 11:52:29 +02:00
parent 97318ff8c0
commit fc0fcc7c9c
2 changed files with 98 additions and 25 deletions

View file

@ -144,6 +144,8 @@ class AvailabilityColors {
this.textDarkColor, this.textDarkColor,
this.textLightColor, this.textLightColor,
this.templateWeekOverviewBackgroundColor, this.templateWeekOverviewBackgroundColor,
this.templateColorLightCheckmarkColor,
this.templateColorDarkCheckmarkColor,
this.templateColors = const [ this.templateColors = const [
Color(0xFF9bb8f2), Color(0xFF9bb8f2),
Color(0xFF4b77d0), Color(0xFF4b77d0),
@ -179,6 +181,14 @@ class AvailabilityColors {
/// If not provided the text color will be the theme's text color /// If not provided the text color will be the theme's text color
final Color? textDarkColor; final Color? textDarkColor;
/// The light color variant of the checkmark icon when selecting a color for
/// a template
final Color? templateColorLightCheckmarkColor;
/// The dark color variant of the checkmark icon when selecting a color for
/// a template
final Color? templateColorDarkCheckmarkColor;
/// The color of the background in the template week overview that creates a /// The color of the background in the template week overview that creates a
/// layered effect by interchanging a color and a transparent color /// layered effect by interchanging a color and a transparent color
/// If not provided the color will be the theme's [ColorScheme.surface] /// If not provided the color will be the theme's [ColorScheme.surface]

View file

@ -1,3 +1,5 @@
import "dart:math";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_availability/src/util/scope.dart"; import "package:flutter_availability/src/util/scope.dart";
@ -38,35 +40,96 @@ class TemplateColorSelection extends StatelessWidget {
spacing: 8, spacing: 8,
runSpacing: 8, runSpacing: 8,
children: [ children: [
for (var color in colors.templateColors) for (var color in colors.templateColors) ...[
GestureDetector( _TemplateColorItem(
onTap: () => _onColorClick(color), color: color,
selectedColor: selectedColor,
onColorSelected: onColorSelected,
),
],
],
),
],
);
}
}
class _TemplateColorItem extends StatelessWidget {
const _TemplateColorItem({
required this.color,
required this.selectedColor,
required this.onColorSelected,
});
/// Callback for when a color is selected or deselected
final void Function(int?) onColorSelected;
final Color color;
final int? selectedColor;
@override
Widget build(BuildContext context) {
var availabilityScope = AvailabilityScope.of(context);
var options = availabilityScope.options;
var colors = options.colors;
/// If the color is selected, deselect it, otherwise select it
void onColorClick(Color color) => onColorSelected(
color.value == selectedColor ? null : color.value,
);
var checkMarkColor = _hasHighContrast(color)
? colors.templateColorLightCheckmarkColor
: colors.templateColorDarkCheckmarkColor;
var icon = selectedColor == color.value
? Icon(Icons.check, color: checkMarkColor)
: null;
return GestureDetector(
onTap: () => onColorClick(color),
child: Container( child: Container(
width: 40, width: 40,
height: 40, height: 40,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color, color: color,
borderRadius: options.borderRadius, borderRadius: options.borderRadius,
border: Border.all(
color: color.value == selectedColor
? Colors.black
: Colors.transparent,
width: 1,
), ),
child: icon,
), ),
child: selectedColor == color.value
? const Icon(Icons.check)
: null,
),
),
],
),
],
); );
} }
}
/// If the color is selected, deselect it, otherwise select it /// Computes the relative luminance of a color
void _onColorClick(Color color) => onColorSelected( /// This is following the formula from the WCAG guidelines
color.value == selectedColor ? null : color.value, double _relativeLuminance(Color color) {
); double channelLuminance(int channel) {
var c = channel / 255.0;
return c <= 0.03928 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4).toDouble();
}
return 0.2126 * channelLuminance(color.red) +
0.7152 * channelLuminance(color.green) +
0.0722 * channelLuminance(color.blue);
}
/// Computes the contrast ratio between two colors
/// This is following the formula from the WCAG guidelines
double _contrastRatio(Color color1, Color color2) {
var luminance1 = _relativeLuminance(color1);
var luminance2 = _relativeLuminance(color2);
if (luminance1 > luminance2) {
return (luminance1 + 0.05) / (luminance2 + 0.05);
} else {
return (luminance2 + 0.05) / (luminance1 + 0.05);
}
}
/// Returns true if the color has high contrast with white
/// This is following the WCAG guidelines
bool _hasHighContrast(Color color) {
const white = Color(0xFFFFFFFF);
return _contrastRatio(color, white) > 4.5;
} }