From 001ef48b82717c53c588fbe5c9ef2e480ff5ff87 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Tue, 19 Nov 2024 17:39:13 +0000 Subject: [PATCH 1/5] feat: Created Range Selector test: wrote 1 test for range selector --- example/lib/home.dart | 2 + .../components/range_selector_example.dart | 214 ++++++++ example/widgetbook/main.dart | 2 + .../components/range_selector_widgetbook.dart | 35 ++ lib/src/components/components.dart | 1 + .../range_selector/range_selector.dart | 475 ++++++++++++++++++ .../range_selector/range_selector_test.dart | 97 ++++ 7 files changed, 826 insertions(+) create mode 100644 example/lib/pages/components/range_selector_example.dart create mode 100644 example/widgetbook/pages/components/range_selector_widgetbook.dart create mode 100644 lib/src/components/range_selector/range_selector.dart create mode 100644 test/src/components/range_selector/range_selector_test.dart diff --git a/example/lib/home.dart b/example/lib/home.dart index b60898e3..e3a587a5 100644 --- a/example/lib/home.dart +++ b/example/lib/home.dart @@ -26,6 +26,7 @@ import 'package:zeta_example/pages/components/navigation_rail_example.dart'; import 'package:zeta_example/pages/components/notification_list_example.dart'; import 'package:zeta_example/pages/components/phone_input_example.dart'; import 'package:zeta_example/pages/components/radio_example.dart'; +import 'package:zeta_example/pages/components/range_selector_example.dart'; import 'package:zeta_example/pages/components/screen_header_bar_example.dart'; import 'package:zeta_example/pages/components/select_input_example.dart'; @@ -89,6 +90,7 @@ final List components = [ Component(TabsExample.name, (context) => const TabsExample()), Component(DialPadExample.name, (context) => const DialPadExample()), Component(RadioButtonExample.name, (context) => const RadioButtonExample()), + Component(RangeSelectorExample.name, (context) => const RangeSelectorExample()), Component(SwitchExample.name, (context) => const SwitchExample()), Component(SliderExample.name, (context) => const SliderExample()), Component(DateInputExample.name, (context) => const DateInputExample()), diff --git a/example/lib/pages/components/range_selector_example.dart b/example/lib/pages/components/range_selector_example.dart new file mode 100644 index 00000000..8811c3cf --- /dev/null +++ b/example/lib/pages/components/range_selector_example.dart @@ -0,0 +1,214 @@ +import 'package:flutter/material.dart'; +import 'package:zeta_example/widgets.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +class RangeSelectorExample extends StatefulWidget { + static const String name = 'RangeSelector'; + + const RangeSelectorExample({super.key}); + + @override + State createState() => _RangeSelectorExampleState(); +} + +class _RangeSelectorExampleState extends State { + double value = 0.5; + + @override + Widget build(BuildContext context) { + return ExampleScaffold( + name: RangeSelectorExample.name, + child: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Slider - Rounded - Continuous', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + onChange: (value) { + print(value.start); + print(value.end); + }, + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + showValues: false, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Slider - Rounded - Stepped', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + onChange: (value) {}, + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + showValues: false, + divisions: 10, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Slider - Rounded - Disabled', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + showValues: false, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Slider - Sharp - Continuous', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + onChange: (value) {}, + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + showValues: false, + rounded: false, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Slider - Sharp - Stepped', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + onChange: (value) {}, + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + showValues: false, + divisions: 10, + rounded: false, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Slider - Sharp - Disabled', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + showValues: false, + rounded: false, + ), + ].gap(12), + ), + SizedBox( + height: 32, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Range Selector - Rounded - Continuous', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + onChange: (value) {}, + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + label: 'Label', + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Range Selector - Rounded - Stepped', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + onChange: (value) {}, + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + label: 'Label', + divisions: 10, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Range Selector - Rounded - Disabled', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + label: 'Label', + divisions: 10, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Range Selector - Sharp - Continuous', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + onChange: (value) {}, + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + label: 'Label', + rounded: false, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Range Selector - Sharp - Stepped', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + onChange: (value) {}, + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + label: 'Label', + rounded: false, + divisions: 10, + ), + ].gap(12), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Range Selector - Sharp - Disabled', style: ZetaTextStyles.bodyLarge), + ZetaRangeSelector( + lowerValue: 20, + upperValue: 80, + min: 0, + max: 100, + label: 'Label', + rounded: false, + divisions: 10, + ), + ].gap(12), + ), + ].gap(32), + ).paddingVertical(32), + ), + ), + ); + } +} diff --git a/example/widgetbook/main.dart b/example/widgetbook/main.dart index 740cb129..c381b4e0 100644 --- a/example/widgetbook/main.dart +++ b/example/widgetbook/main.dart @@ -38,6 +38,7 @@ import 'pages/components/password_input_widgetbook.dart'; import 'pages/components/phone_input_widgetbook.dart'; import 'pages/components/progress_widgetbook.dart'; import 'pages/components/radio_widgetbook.dart'; +import 'pages/components/range_selector_widgetbook.dart'; import 'pages/components/screen_header_bar_widgetbook.dart'; import 'pages/components/search_bar_widgetbook.dart'; import 'pages/components/segmented_control_widgetbook.dart'; @@ -212,6 +213,7 @@ class _HotReloadState extends State { WidgetbookUseCase(name: 'Segmented Control', builder: (context) => segmentedControlUseCase(context)), WidgetbookUseCase(name: 'Select Input', builder: (context) => selectInputUseCase(context)), WidgetbookUseCase(name: 'Slider', builder: (context) => sliderUseCase(context)), + WidgetbookUseCase(name: 'Range Selector', builder: (context) => rangeSelectorUseCase(context)), WidgetbookUseCase(name: 'Snack Bar', builder: (context) => snackBarUseCase(context)), WidgetbookUseCase(name: 'Stepper Input', builder: (context) => stepperInputUseCase(context)), WidgetbookUseCase(name: 'Stepper', builder: (context) => stepperUseCase(context)), diff --git a/example/widgetbook/pages/components/range_selector_widgetbook.dart b/example/widgetbook/pages/components/range_selector_widgetbook.dart new file mode 100644 index 00000000..f29698a7 --- /dev/null +++ b/example/widgetbook/pages/components/range_selector_widgetbook.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:widgetbook/widgetbook.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../utils/scaffold.dart'; +import '../../utils/utils.dart'; + +Widget rangeSelectorUseCase(BuildContext context) { + return WidgetbookScaffold( + builder: (context, _) => RangeSelectorExample(context), + ); +} + +class RangeSelectorExample extends StatelessWidget { + RangeSelectorExample(this.context); + final BuildContext context; + + @override + Widget build(BuildContext _) { + return Padding( + padding: const EdgeInsets.all(16), + child: ZetaRangeSelector( + label: context.knobs.string(label: 'Label', initialValue: 'Range Selector'), + divisions: context.knobs.intOrNull.input(label: 'Divisions', initialValue: null), + showValues: context.knobs.boolean(label: 'Show Values', initialValue: true), + onChange: disabledKnob(context) ? null : (value) {}, + rounded: context.knobs.booleanOrNull(label: 'Rounded', initialValue: true), + lowerValue: context.knobs.double.input(label: 'Lower Value', initialValue: 20), + upperValue: context.knobs.double.input(label: 'Upper Value', initialValue: 80), + min: context.knobs.double.input(label: 'Min', initialValue: 0), + max: context.knobs.double.input(label: 'Max', initialValue: 100), + ), + ); + } +} diff --git a/lib/src/components/components.dart b/lib/src/components/components.dart index 01ad7ba4..acaa56b2 100644 --- a/lib/src/components/components.dart +++ b/lib/src/components/components.dart @@ -40,6 +40,7 @@ export 'phone_input/phone_input.dart'; export 'progress/progress_bar.dart'; export 'progress/progress_circle.dart'; export 'radio/radio.dart'; +export 'range_selector/range_selector.dart'; export 'screen_header_bar/screen_header_bar.dart'; export 'search_bar/search_bar.dart'; export 'segmented_control/segmented_control.dart'; diff --git a/lib/src/components/range_selector/range_selector.dart b/lib/src/components/range_selector/range_selector.dart new file mode 100644 index 00000000..aa487462 --- /dev/null +++ b/lib/src/components/range_selector/range_selector.dart @@ -0,0 +1,475 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../../../zeta_flutter.dart'; + +/// The [ZetaRangeSelector] is a customizable range selector widget that +/// allows users to select a range of values within a specified minimum +/// and maximum range. It provides a visual representation of the selected +/// range and allows for precise adjustments through both dragging and direct input +class ZetaRangeSelector extends ZetaStatefulWidget { + /// Creates a new [ZetaRangeSelector] + const ZetaRangeSelector({ + super.key, + super.rounded, + required this.lowerValue, + required this.upperValue, + this.min = 0.0, + this.max = 100, + this.label, + this.onChange, + this.divisions, + this.semanticLabel, + this.showValues = true, + }) : assert( + min <= lowerValue && lowerValue <= upperValue && upperValue <= max, + 'The lowerValue must be less than or equal to the upperValue, and both must be within the range of min and max.', + ); + + /// The lower value of the range selector. + final double lowerValue; + + /// The upper value of the range selector. + final double upperValue; + + /// The minimum value of the range selector. + final double min; + + /// The maximum value of the range selector. + final double max; + + /// The label of the range selector. + final String? label; + + /// Called with the values of the range selector whenever it is changed. + final ValueChanged? onChange; + + /// The number of divisions for the range selector. + final int? divisions; + + /// Value passed to the wrapping [Semantics] widget. + final String? semanticLabel; + + /// Whether to show the values of the range selector. + final bool showValues; + + @override + State createState() => _ZetaRangeSelectorState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DoubleProperty('lowerValue', lowerValue)) + ..add(DoubleProperty('upperValue', upperValue)) + ..add(DoubleProperty('min', min)) + ..add(DoubleProperty('max', max)) + ..add(StringProperty('label', label)) + ..add(ObjectFlagProperty?>.has('onChange', onChange)) + ..add(IntProperty('divisions', divisions)) + ..add(StringProperty('semanticLabel', semanticLabel)) + ..add(DiagnosticsProperty('showValues', showValues)); + } +} + +class _ZetaRangeSelectorState extends State { + bool _selected = false; + + late RangeValues _values; + + final TextEditingController _lowerController = TextEditingController(); + final TextEditingController _upperController = TextEditingController(); + + bool get disabled => widget.onChange == null; + + @override + void initState() { + super.initState(); + _values = RangeValues(widget.lowerValue, widget.upperValue); + _lowerController.text = widget.lowerValue.round().toString(); + _upperController.text = widget.upperValue.round().toString(); + } + + @override + void didUpdateWidget(ZetaRangeSelector oldWidget) { + super.didUpdateWidget(oldWidget); + if (RangeValues(widget.lowerValue, widget.upperValue) != RangeValues(oldWidget.lowerValue, oldWidget.upperValue)) { + _values = RangeValues(widget.lowerValue, widget.upperValue); + _lowerController.text = widget.lowerValue.toString(); + _upperController.text = widget.upperValue.toString(); + } + } + + @override + void dispose() { + super.dispose(); + _lowerController.dispose(); + _upperController.dispose(); + } + + Color get _activeColor { + final colors = Zeta.of(context).colors; + if (widget.onChange == null) { + return colors.textDisabled; + } + return _selected ? colors.primary : colors.surfaceDefaultInverse; + } + + void _onEditingComplete(TextEditingController controller, {bool lower = true}) { + if (controller.text.isNotEmpty) { + double? val = double.tryParse(controller.text); + if (val != null) { + if (val < widget.min) { + val = widget.min; + } + if (lower ? val >= _values.end : val <= _values.start) { + val = lower ? _values.end - 1 : _values.start + 1; + } + if (widget.onChange != null) { + widget.onChange?.call(RangeValues(lower ? val : _values.start, lower ? _values.end : val)); + setState(() { + _values = RangeValues(lower ? val! : _values.start, lower ? _values.end : val!); + controller.text = val!.round().toString(); + }); + } + } + } + } + + void _onChanged(String value, TextEditingController controller) { + double? val = double.tryParse(value); + if (val != null) { + if (val > widget.max) { + val = widget.max; + } + setState(() { + controller.text = val!.round().toString(); + }); + } + } + + void _onTapOutside(TextEditingController controller, {bool lower = true}) { + if (controller.text.isNotEmpty) { + double? val = double.tryParse(controller.text); + if (val != null) { + if (lower ? val >= _values.end : val <= _values.start) { + val = lower ? _values.end - 1 : _values.start + 1; + } + if (widget.onChange != null) { + widget.onChange?.call(RangeValues(lower ? val : _values.start, lower ? _values.end : val)); + setState(() { + _values = RangeValues(lower ? val! : _values.start, lower ? _values.end : val!); + controller.text = val!.round().toString(); + }); + } + } + } + } + + void _rangeSliderOnChanged(RangeValues value) { + if (widget.onChange != null) { + widget.onChange?.call(RangeValues(value.start, value.end)); + setState(() { + _values = RangeValues(value.start, value.end); + _lowerController.text = value.start.round().toString(); + _upperController.text = value.end.round().toString(); + }); + } + } + + void _setSelected(bool selected) { + setState(() { + _selected = selected; + }); + } + + @override + Widget build(BuildContext context) { + final colors = Zeta.of(context).colors; + final bool rounded = context.rounded; + + return ZetaRoundedScope( + rounded: rounded, + child: MergeSemantics( + child: Semantics( + label: widget.semanticLabel ?? widget.label, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (widget.label != null) + Text( + widget.label!, + style: ZetaTextStyles.bodySmall.copyWith( + color: disabled ? colors.textDisabled : colors.textDefault, + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.showValues) + _ValueField( + controller: _lowerController, + onEditingComplete: () { + _onEditingComplete(_lowerController); + }, + onChanged: (value) { + _onChanged(value, _lowerController); + }, + onTapOutside: (_) { + _onTapOutside(_lowerController); + }, + disabled: disabled, + rounded: rounded, + context: context, + ), + Expanded( + child: SliderTheme( + data: SliderThemeData( + /// Active Track + activeTrackColor: _activeColor, + + /// Inactive Track + inactiveTrackColor: colors.surfaceDisabled, + + /// Ticks + activeTickMarkColor: colors.surfaceDefault, + inactiveTickMarkColor: colors.surfaceDefault, + rangeTickMarkShape: const RoundRangeSliderTickMarkShape(tickMarkRadius: 2), + + /// Thumb + overlayShape: _DrawThumbOverlay( + size: Zeta.of(context).spacing.xl_2 / (context.rounded ? 2 : 1), + rounded: context.rounded, + color: _activeColor, + ), + rangeThumbShape: _DrawThumb( + size: Zeta.of(context).spacing.xl / 2, + rounded: context.rounded, + color: _activeColor, + ), + ), + child: RangeSlider( + values: _values, + onChanged: _rangeSliderOnChanged, + divisions: widget.divisions, + onChangeStart: (_) { + _setSelected(true); + }, + onChangeEnd: (_) { + _setSelected(false); + }, + min: widget.min, + max: widget.max, + mouseCursor: WidgetStatePropertyAll( + disabled ? SystemMouseCursors.basic : SystemMouseCursors.click, + ), + ), + ), + ), + if (widget.showValues) + _ValueField( + controller: _upperController, + onEditingComplete: () { + _onEditingComplete(_upperController, lower: false); + }, + onChanged: (value) { + _onChanged(value, _upperController); + }, + onTapOutside: (_) { + _onTapOutside(_upperController, lower: false); + }, + disabled: disabled, + rounded: rounded, + context: context, + ), + ].gap(Zeta.of(context).spacing.xl_8), + ), + ].gap(Zeta.of(context).spacing.small), + ), + ), + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('disabled', disabled)); + } +} + +class _ValueField extends StatelessWidget { + const _ValueField({ + required this.controller, + required this.onEditingComplete, + required this.onChanged, + required this.onTapOutside, + required this.disabled, + required this.rounded, + required this.context, + }); + + final TextEditingController controller; + final VoidCallback onEditingComplete; + final ValueChanged onChanged; + final TapRegionCallback? onTapOutside; + final bool disabled; + final bool rounded; + final BuildContext context; + + InputBorder get _border { + final colors = Zeta.of(context).colors; + + return OutlineInputBorder( + borderSide: BorderSide( + color: !disabled ? colors.borderSubtle : colors.borderDisabled, + ), + borderRadius: rounded ? Zeta.of(context).radius.minimal : Zeta.of(context).radius.none, + ); + } + + InputDecoration get _inputDecoration { + final colors = Zeta.of(context).colors; + + return InputDecoration( + filled: true, + fillColor: disabled ? colors.surfaceDisabled : null, + contentPadding: EdgeInsets.zero, + constraints: BoxConstraints(maxHeight: Zeta.of(context).spacing.xl_6), + border: _border, + focusedBorder: _border, + enabledBorder: _border, + disabledBorder: _border, + ); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: Zeta.of(context).spacing.xl_9, + child: TextFormField( + keyboardType: TextInputType.number, + enabled: !disabled, + controller: controller, + onEditingComplete: onEditingComplete, + onChanged: onChanged, + onTapOutside: (event) => onTapOutside?.call(event), + textAlign: TextAlign.center, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: disabled ? Zeta.of(context).colors.textDisabled : null, + ), + decoration: _inputDecoration, + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('controller', controller)) + ..add(ObjectFlagProperty.has('onEditingComplete', onEditingComplete)) + ..add(ObjectFlagProperty>.has('onChanged', onChanged)) + ..add(ObjectFlagProperty.has('onTapOutside', onTapOutside)) + ..add(DiagnosticsProperty('disabled', disabled)) + ..add(DiagnosticsProperty('rounded', rounded)) + ..add(DiagnosticsProperty('context', context)); + } +} + +class _DrawThumb extends RangeSliderThumbShape { + /// Constructor for [_DrawThumb] + const _DrawThumb({required this.size, required this.rounded, required this.color}); + + /// Radius or width/height for [_DrawThumb] depending on shape + final double size; + + /// If [_DrawThumb] is circular or a square + final bool rounded; + + /// Color of [_DrawThumb] + final Color color; + + @override + Size getPreferredSize(bool isEnabled, bool isDiscrete) { + return Size.fromRadius(size); + } + + /// Paints thumb + @override + void paint( + PaintingContext context, + Offset center, { + required Animation activationAnimation, + required Animation enableAnimation, + bool? isDiscrete, + bool? isEnabled, + bool isOnTop = true, + bool? isPressed, + required SliderThemeData sliderTheme, + TextDirection? textDirection, + Thumb? thumb, + }) { + final Canvas canvas = context.canvas; + + final paint = Paint() + ..style = PaintingStyle.fill + ..color = color; + + // draw icon with text painter + rounded + ? canvas.drawCircle(center, size, paint) + : canvas.drawRect(Rect.fromCenter(center: center, width: size * 2, height: size * 2), paint); + } +} + +/// Custom slider thumb component +class _DrawThumbOverlay extends SliderComponentShape { + /// Constructor for [_DrawThumbOverlay] + const _DrawThumbOverlay({required this.size, required this.rounded, required this.color}); + + /// Radius or width/height for [_DrawThumbOverlay] depending on shape + final double size; + + /// If [_DrawThumbOverlay] is circular or a square + final bool rounded; + + /// Color of [_DrawThumbOverlay] + final Color color; + + @override + Size getPreferredSize(bool isEnabled, bool isDiscrete) { + return Size.fromRadius(size); + } + + /// Paints thumb + @override + void paint( + PaintingContext context, + Offset center, { + required Animation activationAnimation, + required Animation enableAnimation, + required bool isDiscrete, + required TextPainter labelPainter, + required RenderBox parentBox, + required SliderThemeData sliderTheme, + required TextDirection textDirection, + required double value, + required double textScaleFactor, + required Size sizeWithOverflow, + }) { + final Canvas canvas = context.canvas; + + final paint = Paint() + ..style = PaintingStyle.fill + ..color = color; + + // draw icon with text painter + rounded + ? canvas.drawCircle(center, size, paint) + : canvas.drawRect(Rect.fromCenter(center: center, width: size, height: size), paint); + } +} diff --git a/test/src/components/range_selector/range_selector_test.dart b/test/src/components/range_selector/range_selector_test.dart new file mode 100644 index 00000000..bb9e5bcd --- /dev/null +++ b/test/src/components/range_selector/range_selector_test.dart @@ -0,0 +1,97 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../../test_utils/test_app.dart'; +import '../../../test_utils/tolerant_comparator.dart'; +import '../../../test_utils/utils.dart'; + +void main() { + const String parentFolder = 'range_selector'; + + const goldenFile = GoldenFiles(component: parentFolder); + setUpAll(() { + goldenFileComparator = TolerantComparator(goldenFile.uri); + }); + + group('Accessibility Tests', () {}); + + group('Content Tests', () { + final debugFillProperties = { + 'label': '"Range Selector"', + 'lowerValue': '20.0', + 'upperValue': '80.0', + 'divisions': 'null', + 'showValues': 'true', + 'rounded': 'null', + 'min': '0.0', + 'max': '100.0', + }; + debugFillPropertiesTest( + ZetaRangeSelector( + label: 'Range Selector', + lowerValue: 20, + upperValue: 80, + onChange: (value) {}, + ), + debugFillProperties, + ); + }); + + group('Dimensions Tests', () { + // + }); + + group('Styling Tests', () { + // has correct default style + }); + + group('Interaction Tests', () { + testWidgets('onChange callback is called when value is changed', (tester) async { + double? firstValue; + double? secondValue; + await tester.pumpWidget( + TestApp( + home: Padding( + padding: const EdgeInsets.all(32), + child: ZetaRangeSelector( + label: 'Range Selector', + lowerValue: 20, + upperValue: 80, + showValues: false, + onChange: (newValue) { + secondValue = newValue.end; + firstValue = newValue.start; + }, + ), + ), + ), + ); + + await tester.pumpAndSettle(); + final slider = find.byType(RangeSlider); + + final sliderTopLeft = tester.getTopLeft(slider, warnIfMissed: true); + + await tester.dragFrom(sliderTopLeft.translate(0, 0), const Offset(250, 0)); + + await tester.pumpAndSettle(); + + await tester.dragFrom(sliderTopLeft.translate(700, 0), const Offset(-250, 0)); + + await tester.pumpAndSettle(); + + expect(firstValue!.round(), 33); + expect(secondValue!.round(), 62); + }); + }); + + group('Golden Tests', () { + // goldenTest(goldenFile, widget, 'PNG_FILE_NAME'); + }); + + group('Performance Tests', () {}); +} From a61045cc4ac847892c9cc13b9bb080f1e7e8bbec Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Wed, 20 Nov 2024 22:19:12 +0000 Subject: [PATCH 2/5] test: testing range selector docs: widgetbook and example for range selector --- .../components/range_selector_example.dart | 51 +- .../components/range_selector_widgetbook.dart | 4 +- example/widgetbook/utils/utils.dart | 38 ++ .../range_selector/range_selector.dart | 272 +++++------ .../range_selector_rounded_continuous.png | Bin 0 -> 4618 bytes .../range_selector_rounded_disabled.png | Bin 0 -> 4744 bytes .../golden/range_selector_rounded_stepped.png | Bin 0 -> 4832 bytes .../range_selector_sharp_continuous.png | Bin 0 -> 3611 bytes .../golden/range_selector_sharp_disabled.png | Bin 0 -> 3769 bytes .../golden/range_selector_sharp_stepped.png | Bin 0 -> 3847 bytes .../range_slider_rounded_continuous.png | Bin 0 -> 3856 bytes .../golden/range_slider_rounded_disabled.png | Bin 0 -> 3842 bytes .../golden/range_slider_rounded_stepped.png | Bin 0 -> 4495 bytes .../golden/range_slider_sharp_continuous.png | Bin 0 -> 3343 bytes .../golden/range_slider_sharp_disabled.png | Bin 0 -> 3349 bytes .../golden/range_slider_sharp_stepped.png | Bin 0 -> 3963 bytes .../range_selector/range_selector_test.dart | 455 +++++++++++++++++- test/test_utils/utils.dart | 36 ++ 18 files changed, 661 insertions(+), 195 deletions(-) create mode 100644 test/src/components/range_selector/golden/range_selector_rounded_continuous.png create mode 100644 test/src/components/range_selector/golden/range_selector_rounded_disabled.png create mode 100644 test/src/components/range_selector/golden/range_selector_rounded_stepped.png create mode 100644 test/src/components/range_selector/golden/range_selector_sharp_continuous.png create mode 100644 test/src/components/range_selector/golden/range_selector_sharp_disabled.png create mode 100644 test/src/components/range_selector/golden/range_selector_sharp_stepped.png create mode 100644 test/src/components/range_selector/golden/range_slider_rounded_continuous.png create mode 100644 test/src/components/range_selector/golden/range_slider_rounded_disabled.png create mode 100644 test/src/components/range_selector/golden/range_slider_rounded_stepped.png create mode 100644 test/src/components/range_selector/golden/range_slider_sharp_continuous.png create mode 100644 test/src/components/range_selector/golden/range_slider_sharp_disabled.png create mode 100644 test/src/components/range_selector/golden/range_slider_sharp_stepped.png diff --git a/example/lib/pages/components/range_selector_example.dart b/example/lib/pages/components/range_selector_example.dart index 8811c3cf..69b2fd75 100644 --- a/example/lib/pages/components/range_selector_example.dart +++ b/example/lib/pages/components/range_selector_example.dart @@ -26,14 +26,13 @@ class _RangeSelectorExampleState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Slider - Rounded - Continuous', style: ZetaTextStyles.bodyLarge), + Text('Range Slider - Rounded - Continuous', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) { print(value.start); print(value.end); }, - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, showValues: false, @@ -43,11 +42,10 @@ class _RangeSelectorExampleState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Slider - Rounded - Stepped', style: ZetaTextStyles.bodyLarge), + Text('Range Slider - Rounded - Stepped', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) {}, - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, showValues: false, @@ -58,10 +56,9 @@ class _RangeSelectorExampleState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Slider - Rounded - Disabled', style: ZetaTextStyles.bodyLarge), + Text('Range Slider - Rounded - Disabled', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, showValues: false, @@ -71,11 +68,10 @@ class _RangeSelectorExampleState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Slider - Sharp - Continuous', style: ZetaTextStyles.bodyLarge), + Text('Range Slider - Sharp - Continuous', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) {}, - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, showValues: false, @@ -86,11 +82,10 @@ class _RangeSelectorExampleState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Slider - Sharp - Stepped', style: ZetaTextStyles.bodyLarge), + Text('Range Slider - Sharp - Stepped', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) {}, - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, showValues: false, @@ -102,10 +97,9 @@ class _RangeSelectorExampleState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Slider - Sharp - Disabled', style: ZetaTextStyles.bodyLarge), + Text('Range Slider - Sharp - Disabled', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, showValues: false, @@ -122,11 +116,11 @@ class _RangeSelectorExampleState extends State { Text('Range Selector - Rounded - Continuous', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) {}, - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 40), min: 0, - max: 100, + max: 50, label: 'Label', + semanticLabel: 'Hello World!', ), ].gap(12), ), @@ -136,8 +130,7 @@ class _RangeSelectorExampleState extends State { Text('Range Selector - Rounded - Stepped', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) {}, - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, label: 'Label', @@ -150,8 +143,7 @@ class _RangeSelectorExampleState extends State { children: [ Text('Range Selector - Rounded - Disabled', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, label: 'Label', @@ -165,8 +157,7 @@ class _RangeSelectorExampleState extends State { Text('Range Selector - Sharp - Continuous', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) {}, - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, label: 'Label', @@ -180,8 +171,7 @@ class _RangeSelectorExampleState extends State { Text('Range Selector - Sharp - Stepped', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) {}, - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, label: 'Label', @@ -195,8 +185,7 @@ class _RangeSelectorExampleState extends State { children: [ Text('Range Selector - Sharp - Disabled', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( - lowerValue: 20, - upperValue: 80, + initialValues: RangeValues(20, 80), min: 0, max: 100, label: 'Label', diff --git a/example/widgetbook/pages/components/range_selector_widgetbook.dart b/example/widgetbook/pages/components/range_selector_widgetbook.dart index f29698a7..fe5d46fd 100644 --- a/example/widgetbook/pages/components/range_selector_widgetbook.dart +++ b/example/widgetbook/pages/components/range_selector_widgetbook.dart @@ -24,9 +24,9 @@ class RangeSelectorExample extends StatelessWidget { divisions: context.knobs.intOrNull.input(label: 'Divisions', initialValue: null), showValues: context.knobs.boolean(label: 'Show Values', initialValue: true), onChange: disabledKnob(context) ? null : (value) {}, + largeSliderThumbs: context.knobs.boolean(label: 'Large Slider Thumbs', initialValue: false), rounded: context.knobs.booleanOrNull(label: 'Rounded', initialValue: true), - lowerValue: context.knobs.double.input(label: 'Lower Value', initialValue: 20), - upperValue: context.knobs.double.input(label: 'Upper Value', initialValue: 80), + initialValues: context.knobs.range(label: 'Initial Range', initialValue: RangeValues(20, 80)), min: context.knobs.double.input(label: 'Min', initialValue: 0), max: context.knobs.double.input(label: 'Max', initialValue: 100), ), diff --git a/example/widgetbook/utils/utils.dart b/example/widgetbook/utils/utils.dart index c3fcdfcf..a5f782f7 100644 --- a/example/widgetbook/utils/utils.dart +++ b/example/widgetbook/utils/utils.dart @@ -37,3 +37,41 @@ bool disabledKnob(BuildContext context) => context.knobs.boolean( label: 'Disabled', initialValue: false, ); + +class RangeKnob extends Knob { + RangeKnob({ + required super.label, + required super.initialValue, + }); + @override + List get fields => [ + DoubleInputField( + name: 'min-$label', + initialValue: initialValue.start, + ), + DoubleInputField( + name: 'max-$label', + initialValue: initialValue.end, + ), + ]; + @override + RangeValues valueFromQueryGroup(Map group) { + return RangeValues( + valueOf('min-$label', group)!, + valueOf('max-$label', group)!, + ); + } +} + +extension RangeKnobBuilder on KnobsBuilder { + RangeValues range({ + required String label, + RangeValues initialValue = const RangeValues(0, 10), + }) => + onKnobAdded( + RangeKnob( + label: label, + initialValue: initialValue, + ), + )!; +} diff --git a/lib/src/components/range_selector/range_selector.dart b/lib/src/components/range_selector/range_selector.dart index aa487462..aadf8681 100644 --- a/lib/src/components/range_selector/range_selector.dart +++ b/lib/src/components/range_selector/range_selector.dart @@ -10,11 +10,10 @@ import '../../../zeta_flutter.dart'; /// range and allows for precise adjustments through both dragging and direct input class ZetaRangeSelector extends ZetaStatefulWidget { /// Creates a new [ZetaRangeSelector] - const ZetaRangeSelector({ + ZetaRangeSelector({ super.key, super.rounded, - required this.lowerValue, - required this.upperValue, + required this.initialValues, this.min = 0.0, this.max = 100, this.label, @@ -22,21 +21,21 @@ class ZetaRangeSelector extends ZetaStatefulWidget { this.divisions, this.semanticLabel, this.showValues = true, + this.largeSliderThumbs = false, }) : assert( - min <= lowerValue && lowerValue <= upperValue && upperValue <= max, - 'The lowerValue must be less than or equal to the upperValue, and both must be within the range of min and max.', + min <= initialValues.start && initialValues.start <= initialValues.end && initialValues.end <= max, + 'The start value must be less than or equal to the end value, and both must be within the range of min and max.', ); - /// The lower value of the range selector. - final double lowerValue; - - /// The upper value of the range selector. - final double upperValue; + /// The initial values of the range selector. + final RangeValues initialValues; /// The minimum value of the range selector. + /// Defaults to 0. final double min; /// The maximum value of the range selector. + /// Defaults to 100. final double max; /// The label of the range selector. @@ -52,8 +51,13 @@ class ZetaRangeSelector extends ZetaStatefulWidget { final String? semanticLabel; /// Whether to show the values of the range selector. + /// Defaults to true. final bool showValues; + /// Whether to use larger slider thumbs. + /// Defaults to false. + final bool largeSliderThumbs; + @override State createState() => _ZetaRangeSelectorState(); @@ -61,15 +65,15 @@ class ZetaRangeSelector extends ZetaStatefulWidget { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(DoubleProperty('lowerValue', lowerValue)) - ..add(DoubleProperty('upperValue', upperValue)) ..add(DoubleProperty('min', min)) ..add(DoubleProperty('max', max)) ..add(StringProperty('label', label)) ..add(ObjectFlagProperty?>.has('onChange', onChange)) ..add(IntProperty('divisions', divisions)) ..add(StringProperty('semanticLabel', semanticLabel)) - ..add(DiagnosticsProperty('showValues', showValues)); + ..add(DiagnosticsProperty('showValues', showValues)) + ..add(DiagnosticsProperty('initialValues', initialValues)) + ..add(DiagnosticsProperty('largeSliderThumbs', largeSliderThumbs)); } } @@ -86,18 +90,18 @@ class _ZetaRangeSelectorState extends State { @override void initState() { super.initState(); - _values = RangeValues(widget.lowerValue, widget.upperValue); - _lowerController.text = widget.lowerValue.round().toString(); - _upperController.text = widget.upperValue.round().toString(); + _values = widget.initialValues; + _lowerController.text = widget.initialValues.start.round().toString(); + _upperController.text = widget.initialValues.end.round().toString(); } @override void didUpdateWidget(ZetaRangeSelector oldWidget) { super.didUpdateWidget(oldWidget); - if (RangeValues(widget.lowerValue, widget.upperValue) != RangeValues(oldWidget.lowerValue, oldWidget.upperValue)) { - _values = RangeValues(widget.lowerValue, widget.upperValue); - _lowerController.text = widget.lowerValue.toString(); - _upperController.text = widget.upperValue.toString(); + if (widget.initialValues != oldWidget.initialValues) { + _values = widget.initialValues; + _lowerController.text = widget.initialValues.start.toString(); + _upperController.text = widget.initialValues.end.toString(); } } @@ -116,7 +120,7 @@ class _ZetaRangeSelectorState extends State { return _selected ? colors.primary : colors.surfaceDefaultInverse; } - void _onEditingComplete(TextEditingController controller, {bool lower = true}) { + void _onSubmit(TextEditingController controller, {bool lower = true}) { if (controller.text.isNotEmpty) { double? val = double.tryParse(controller.text); if (val != null) { @@ -124,7 +128,7 @@ class _ZetaRangeSelectorState extends State { val = widget.min; } if (lower ? val >= _values.end : val <= _values.start) { - val = lower ? _values.end - 1 : _values.start + 1; + val = lower ? _values.end : _values.start; } if (widget.onChange != null) { widget.onChange?.call(RangeValues(lower ? val : _values.start, lower ? _values.end : val)); @@ -137,7 +141,7 @@ class _ZetaRangeSelectorState extends State { } } - void _onChanged(String value, TextEditingController controller) { + void _valueFieldOnChanged(String value, TextEditingController controller) { double? val = double.tryParse(value); if (val != null) { if (val > widget.max) { @@ -149,24 +153,6 @@ class _ZetaRangeSelectorState extends State { } } - void _onTapOutside(TextEditingController controller, {bool lower = true}) { - if (controller.text.isNotEmpty) { - double? val = double.tryParse(controller.text); - if (val != null) { - if (lower ? val >= _values.end : val <= _values.start) { - val = lower ? _values.end - 1 : _values.start + 1; - } - if (widget.onChange != null) { - widget.onChange?.call(RangeValues(lower ? val : _values.start, lower ? _values.end : val)); - setState(() { - _values = RangeValues(lower ? val! : _values.start, lower ? _values.end : val!); - controller.text = val!.round().toString(); - }); - } - } - } - } - void _rangeSliderOnChanged(RangeValues value) { if (widget.onChange != null) { widget.onChange?.call(RangeValues(value.start, value.end)); @@ -187,107 +173,94 @@ class _ZetaRangeSelectorState extends State { @override Widget build(BuildContext context) { final colors = Zeta.of(context).colors; + final spacing = Zeta.of(context).spacing; final bool rounded = context.rounded; return ZetaRoundedScope( rounded: rounded, - child: MergeSemantics( - child: Semantics( - label: widget.semanticLabel ?? widget.label, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.label != null) - Text( - widget.label!, - style: ZetaTextStyles.bodySmall.copyWith( - color: disabled ? colors.textDisabled : colors.textDefault, - ), + child: Semantics( + label: widget.semanticLabel, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (widget.label != null) + Text( + widget.label!, + style: ZetaTextStyles.bodySmall.copyWith( + color: disabled ? colors.textDisabled : colors.textDefault, ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.showValues) - _ValueField( - controller: _lowerController, - onEditingComplete: () { - _onEditingComplete(_lowerController); - }, - onChanged: (value) { - _onChanged(value, _lowerController); - }, - onTapOutside: (_) { - _onTapOutside(_lowerController); - }, - disabled: disabled, - rounded: rounded, - context: context, - ), - Expanded( - child: SliderTheme( - data: SliderThemeData( - /// Active Track - activeTrackColor: _activeColor, - - /// Inactive Track - inactiveTrackColor: colors.surfaceDisabled, - - /// Ticks - activeTickMarkColor: colors.surfaceDefault, - inactiveTickMarkColor: colors.surfaceDefault, - rangeTickMarkShape: const RoundRangeSliderTickMarkShape(tickMarkRadius: 2), - - /// Thumb - overlayShape: _DrawThumbOverlay( - size: Zeta.of(context).spacing.xl_2 / (context.rounded ? 2 : 1), - rounded: context.rounded, - color: _activeColor, - ), - rangeThumbShape: _DrawThumb( - size: Zeta.of(context).spacing.xl / 2, - rounded: context.rounded, - color: _activeColor, - ), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.showValues) + _ValueField( + controller: _lowerController, + onEditingComplete: () => _onSubmit(_lowerController), + onTapOutside: (event) => _onSubmit(_lowerController), + onChanged: (value) => _valueFieldOnChanged(value, _lowerController), + disabled: disabled, + rounded: rounded, + context: context, + ), + Expanded( + child: SliderTheme( + data: SliderThemeData( + /// Track + activeTrackColor: _activeColor, + inactiveTrackColor: colors.surfaceDisabled, + rangeTrackShape: rounded + ? const RoundedRectRangeSliderTrackShape() as RangeSliderTrackShape + : const RectangularRangeSliderTrackShape() as RangeSliderTrackShape, + + /// Ticks + activeTickMarkColor: colors.surfaceDefault, + inactiveTickMarkColor: colors.surfaceDefault, + rangeTickMarkShape: const RoundRangeSliderTickMarkShape(tickMarkRadius: 2), + + /// Thumbs + overlayShape: _DrawThumbOverlay( + size: widget.largeSliderThumbs ? spacing.xl_3 / 2 : spacing.xl / 2, + rounded: rounded, + color: _activeColor, ), - child: RangeSlider( - values: _values, - onChanged: _rangeSliderOnChanged, - divisions: widget.divisions, - onChangeStart: (_) { - _setSelected(true); - }, - onChangeEnd: (_) { - _setSelected(false); - }, - min: widget.min, - max: widget.max, - mouseCursor: WidgetStatePropertyAll( - disabled ? SystemMouseCursors.basic : SystemMouseCursors.click, - ), + rangeThumbShape: _DrawThumb( + size: widget.largeSliderThumbs ? spacing.xl_2 / 2 : spacing.large / 2, + rounded: rounded, + color: _activeColor, ), ), - ), - if (widget.showValues) - _ValueField( - controller: _upperController, - onEditingComplete: () { - _onEditingComplete(_upperController, lower: false); - }, - onChanged: (value) { - _onChanged(value, _upperController); - }, - onTapOutside: (_) { - _onTapOutside(_upperController, lower: false); + child: RangeSlider( + values: _values, + onChanged: _rangeSliderOnChanged, + divisions: widget.divisions, + onChangeStart: (_) => _setSelected(true), + onChangeEnd: (_) => _setSelected(false), + min: widget.min, + max: widget.max, + mouseCursor: WidgetStatePropertyAll( + disabled ? SystemMouseCursors.basic : SystemMouseCursors.click, + ), + semanticFormatterCallback: (value) { + return '${value.round()}'; }, - disabled: disabled, - rounded: rounded, - context: context, ), - ].gap(Zeta.of(context).spacing.xl_8), - ), - ].gap(Zeta.of(context).spacing.small), - ), + ), + ), + if (widget.showValues) + _ValueField( + controller: _upperController, + onEditingComplete: () => _onSubmit(_upperController, lower: false), + onTapOutside: (event) => _onSubmit(_upperController, lower: false), + onChanged: (value) => _valueFieldOnChanged(value, _upperController), + disabled: disabled, + rounded: rounded, + context: context, + ), + ].gap(spacing.xl_4), + ), + ].gap(spacing.small), ), ), ); @@ -314,30 +287,36 @@ class _ValueField extends StatelessWidget { final TextEditingController controller; final VoidCallback onEditingComplete; final ValueChanged onChanged; - final TapRegionCallback? onTapOutside; + final TapRegionCallback onTapOutside; final bool disabled; final bool rounded; final BuildContext context; + ZetaColors get _colors { + return Zeta.of(context).colors; + } + + ZetaSpacingSemantics get _spacing { + return Zeta.of(context).spacing; + } + InputBorder get _border { - final colors = Zeta.of(context).colors; + final radius = Zeta.of(context).radius; return OutlineInputBorder( borderSide: BorderSide( - color: !disabled ? colors.borderSubtle : colors.borderDisabled, + color: !disabled ? _colors.borderDefault : _colors.borderDisabled, ), - borderRadius: rounded ? Zeta.of(context).radius.minimal : Zeta.of(context).radius.none, + borderRadius: rounded ? radius.minimal : radius.none, ); } InputDecoration get _inputDecoration { - final colors = Zeta.of(context).colors; - return InputDecoration( filled: true, - fillColor: disabled ? colors.surfaceDisabled : null, + fillColor: disabled ? _colors.surfaceDisabled : null, contentPadding: EdgeInsets.zero, - constraints: BoxConstraints(maxHeight: Zeta.of(context).spacing.xl_6), + constraints: BoxConstraints(maxHeight: _spacing.xl_6), border: _border, focusedBorder: _border, enabledBorder: _border, @@ -348,7 +327,8 @@ class _ValueField extends StatelessWidget { @override Widget build(BuildContext context) { return SizedBox( - width: Zeta.of(context).spacing.xl_9, + width: _spacing.xl_9 - 8, + height: _spacing.xl_8, child: TextFormField( keyboardType: TextInputType.number, enabled: !disabled, @@ -359,7 +339,7 @@ class _ValueField extends StatelessWidget { textAlign: TextAlign.center, inputFormatters: [FilteringTextInputFormatter.digitsOnly], style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: disabled ? Zeta.of(context).colors.textDisabled : null, + color: disabled ? _colors.textDisabled : _colors.textSubtle, ), decoration: _inputDecoration, ), @@ -373,10 +353,10 @@ class _ValueField extends StatelessWidget { ..add(DiagnosticsProperty('controller', controller)) ..add(ObjectFlagProperty.has('onEditingComplete', onEditingComplete)) ..add(ObjectFlagProperty>.has('onChanged', onChanged)) - ..add(ObjectFlagProperty.has('onTapOutside', onTapOutside)) ..add(DiagnosticsProperty('disabled', disabled)) ..add(DiagnosticsProperty('rounded', rounded)) - ..add(DiagnosticsProperty('context', context)); + ..add(DiagnosticsProperty('context', context)) + ..add(ObjectFlagProperty.has('onTapOutside', onTapOutside)); } } @@ -407,7 +387,7 @@ class _DrawThumb extends RangeSliderThumbShape { required Animation enableAnimation, bool? isDiscrete, bool? isEnabled, - bool isOnTop = true, + bool? isOnTop, bool? isPressed, required SliderThemeData sliderTheme, TextDirection? textDirection, @@ -470,6 +450,6 @@ class _DrawThumbOverlay extends SliderComponentShape { // draw icon with text painter rounded ? canvas.drawCircle(center, size, paint) - : canvas.drawRect(Rect.fromCenter(center: center, width: size, height: size), paint); + : canvas.drawRect(Rect.fromCenter(center: center, width: size * 2, height: size * 2), paint); } } diff --git a/test/src/components/range_selector/golden/range_selector_rounded_continuous.png b/test/src/components/range_selector/golden/range_selector_rounded_continuous.png new file mode 100644 index 0000000000000000000000000000000000000000..536ef9a2cbd41f94d2e425b840cdc96d793cff60 GIT binary patch literal 4618 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 literal 0 HcmV?d00001 diff --git a/test/src/components/range_selector/golden/range_selector_rounded_stepped.png b/test/src/components/range_selector/golden/range_selector_rounded_stepped.png new file mode 100644 index 0000000000000000000000000000000000000000..dbd1aef3f51717d6f947b2ec20ab74ef4acfa68d GIT binary patch literal 4832 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 literal 0 HcmV?d00001 diff --git a/test/src/components/range_selector/golden/range_slider_rounded_continuous.png b/test/src/components/range_selector/golden/range_slider_rounded_continuous.png new file mode 100644 index 0000000000000000000000000000000000000000..3ec1c0207b210bbc6500d10c51fe27a953698bad GIT binary patch literal 3856 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`$Ar;B4q#hkZy?7QcN${qNa{7yi*x%FyODAT!)WW{sV8#p==6yN0C zJ7^?rZT?G0j3rPfRr{tETVYR9hkin?$*D(fC)cED9X#cf@;QIq?F{8b zxgGzXRmDHnTvqe(=ydM2_it6D?D_RdJ30IH zMCJLs4AWYHWgf+VI$n^UoiDd8yu?qQ(#*`uS(g zo`1jWk9X_;t9=z1;mFN?;(y*9srz;1$#-^s{wzNGfq~u6C-;N<85p$RzDl3pzkc7p zv{!~dWFw+y_x`@_-}Bo~CO+fup>l^K?E9Dg{reiMGPl0I{*~a5xjTxVC)E7D+uM45 zcgs1IzWdehuP8Gx7&NvrKl%4nI5{`BY|G^hMsoLRDqaaPBrLV;{<-$g56)|cUW><8 z-0ytMU4NZ*e_HkLjUNxP|DRRG!w?a9`*wdX`~MFIt|V`0`opU~c}LyfUlor!FF*eF z_I7(!UTtmdp8x-Fqqlg-2CxMuz$b5{onIWujOk?vSW6Ac{k(i9ap9Xc}xFDGmxU2Ic9osHQ6@5 z-^AA!3eP#4_V~@sxgXD2?>6&h_`wOZG4N?b|Wr1mgVo%uM_K zw{MRxmlI@oS9LCUS|bA^1A~#>K_(!{#KOREf literal 0 HcmV?d00001 diff --git a/test/src/components/range_selector/golden/range_slider_rounded_disabled.png b/test/src/components/range_selector/golden/range_slider_rounded_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..4e0ab618d907b716cec1a6f5fbc9a6e17ab1335e GIT binary patch literal 3842 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`$0r;B4q#hkZy&-YLHDtqAL`$Jg<9J@C-ZT#re%Q_`#l}dquq1>!{ z)vxVuOs;R3zD)e`l_iTDdF+Lf9yKy0PH)xKRP4Fky;ov!bK-se%awc2ou6F8H~Hro z>(6u3!{*skZn6ei%Jh4g9FU5TTOG{Lkla)F``xo0Rexu1-1@g5C)ZvAC{j|JD`Q(! zG3V#olZB6d9J`{-bb$N3U8>+3i>9Mf(l+1xar}AsG4bi^`|sYBuh(3+W=+rcb93dy z&(D|r{q5%^K8CszcBvCN1k{T2i>qrsUEkmTo4@SYu76v5zkY1z*YCM*cI|tO8AF7~ zH_dLhe?~K<&G*m!eYU9PKU?+VXWOf-gc)?Ceot{#c9?Nw|GPWV)Ai!3pZ(U0-DmbL zH}CyPABGJXZ-T`pDo6M{%AfzQIA&*6@hd}ygv`0NpP&7B(fm2M|De#U-B+sqTMZISd;#w#mQg z*X0s?+$APGqzBp*ro(e|I{O!kM}*?0Hdedpcxd7dr! zHYCV=m(4B!0L+8W2V4RGlfwXD9ER8dTPoA&@sx zXTEYvIo*>V>)3ZH?Khj58f1OYgK{IABBb|0bZBY{BGqEQjd8%4U%r4AIIN!^JG-5` z5Kj-4$}{coq4MEenKn`&hS-wY1CAk7Bmm^SlGm8QQ4#DK3XuRB{i~(Fm!*%)lDIfT z;g(>L6%`duO;f(C3@NSZwq`-dQhg4@n&uH{ir;zHUps^yf4jCY2p*tsF6L}7==AmV zb-cQ=w6wHieInvx6H8J)ewDWe=;o4!ZEojXq3up}=-~0(B zz$0IS0j7>q>k=_!lipq*<(s~QoEGY&%L_|ir7V2L6sRhK?;Nn-YxRL8(oPE7rN!|v zF$-yI0*OT8tQ9q@Cw2g^`z0h0djy#y8)=53J<*Jo7PrYL6_gNn0Oy>u;PU7bqQIBpDbjPg*9fh*CYwA{mrEEK(s9L*1HPIi z>C6tHr(fQ5?^qk~r)nW7wW7kr%!1!%>EF5>40hGl)_P{jUQH+WtrIt8PZW=fb5e1c z^Z9`SFOaRM?siA%H}Qg_WsxW7&@>2+(RHjqtXH$oM&BSP1o79D4~V_P!}6{;P|BTf zZXm9VFDO1-Xg;3x_L=NiQUqADJA?a{OZ6fB_?-X1P z1l?SXW6~~YW5#0=2h9pQh+xi~2?dj_l0+$=Uc8~#d4uv1kzW~Jx1l%RM`p9LReVUK zuVWBFe#gdNDn2LI-35*^S;0e5Z#9urkvVG-poFCoJhb@mC6@0;uwaqXJYc&o1ELFJGP%+tz_~uKL6fnr2)dQ>kZgIBrf(BMfHeiEa<_9UOV7e9#-G za22WfcD@>JO#;>5{G=w(CyO z?@GQoT7t=k-_4PcAh@ddQ0U70$;1pSaHNGPpAu)`a&c#+uU59RS2Mu(A|2SF*I{`r zF@sjVVybF|A>h+|LwR!fu$`B(UOmySgOB4oNwX%$6=sw8?qzH6-es|v!DMxfI0w`6l!OcqsV=<*AX0$l?zxEC!DyWvFoNwY=fil0$ikTqLpFP%c;^_tLxxVWW8 zf=M2)7v8wAy|K0RM6r*&m}Xix-$8XDBlpoRuD{Qs(i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`eIr;B4q#hkZy4Y>|Eh&VWk>L;jXJp9|Ax-cPie{YTh{aO7RZP)Z+;-P=6Kyp#)##ge;U31cl+(Ht&t25;w$HU>R;0Ul$2y-Vqi#N z;b35xAgI8=;NS)loOyD2!d?0E_x+gUXH>spXL#_p@4b~Q|KxR>nNU@yeUh87@_vcq z!THgQ3IFDKyf4=|$c1Vak_9*W4CB1{8G$Zp78PJ%P*8SYU})%J016l}u`n>4;20Gg z4Uo~qFq#oYONP->akNGltqn(O!_nGsv^E^twc%$rzb7(kg;Fp2fE^14Pgg&ebxsLQ E0Q5B9i~s-t literal 0 HcmV?d00001 diff --git a/test/src/components/range_selector/golden/range_slider_sharp_disabled.png b/test/src/components/range_selector/golden/range_slider_sharp_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..0c511caf8fadfe869fbb14382dec71343a868837 GIT binary patch literal 3349 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`egr;B4q#hkZyH})QK5OHvHFmY%p>5XM=332vdHEAok_;j`dw_97f z;`t-nz8L?`-23{i#N&;O3=AA^rpW=#i|GG*iFt$H^w+u9{yx9_{&pH;L;lmsQ|6nP zm>3vRSU4CMCI~7pFgUn102NCzf&|s(H1ho+s&>lhgBy{}k5|8e4_(l7@G zhK3#npy5VLEDQ`MeC{zDeVwhR@uOIq;mm#Emw)?IBN*Yb90Cjs3d#sAw+)Xazf=U8 zP`UxP-B=woDyV=OL!$vQ8Xyd?>^hnlMiawmV!&0IjpmNg+%cLvMso*dGk3IPphL+p ZPu)OvMgG1ID}Z^B!PC{xWt~$(695;hwaNeh literal 0 HcmV?d00001 diff --git a/test/src/components/range_selector/golden/range_slider_sharp_stepped.png b/test/src/components/range_selector/golden/range_slider_sharp_stepped.png new file mode 100644 index 0000000000000000000000000000000000000000..945196c721723e493ada85e7f416559041ea35f4 GIT binary patch literal 3963 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`Gu)5S5QV$R#U=euLSGPXZ_?^EYzl*OjV##54bZED|7?lYTiOsHM0 zu(Df;gLQ7pI&T>!R>xf%950l~3+?Kycbt=Sy)dvtm2=DF7e_qvCV7gpE|iwOvd6r< zX5Q7iG4ImL-&LP`IA`a{lusb1usmCC3#5L0ykYs4@sEY=|3Ciwu7BVErKl$ahnYVvF|N1r4ze4HF4MY2Ru~k)XZtg9)j=f(}?-*4>S zP=0Ijjb&ou;>TZJ)_#0p;qzk`7wh*| z31kb%GZU5ddz9VdeyF+pC_8=n^y91H^_J77O*^(RS-)Rcz0be;l8;5@r>})yUU-9z zT^X#MTzK(6zg+)c?&{-*?%hqUtE;owTAv8?0x*En4wb)U-kxyK?BNmH4Rg<)^{r<7 z;9U8HVP|D_@}1rP6To=S){hn8xx(e@-;afFH$Q&u+O->dj3u|5zxSyYx_#x?v11kA z?_Mo@d+TfA&ri!A-`U9z3^KJj_VtM|yS|)^h>w?-um3ZBZ;*w4@6%RnYre}A~6=I3Rw$(slider); + + final zetaSelector = find.byType(ZetaRangeSelector); + final zetaSelectorWidget = tester.widget(zetaSelector); + + final semantics = find.byType(Semantics).first; + final semanticsWidget = tester.widget(semantics); + + expect(zetaSelectorWidget.rounded, null); + expect(sliderWidget.values, const RangeValues(20, 80)); + expect(sliderWidget.min, 0); + expect(sliderWidget.max, 100); + expect(zetaSelectorWidget.label, null); + expect(sliderWidget.divisions, null); + expect(semanticsWidget.properties.label, null); + expect(zetaSelectorWidget.showValues, true); + }); + + testWidgets('renders two TextFormFields', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + ), + ), + ); + + await tester.pumpAndSettle(); + + expect(find.byType(TextFormField), findsNWidgets(2)); + }); + + testWidgets('renders one range slider', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + ), + ), + ); + + await tester.pumpAndSettle(); + + expect(find.byType(RangeSlider), findsOneWidget); + }); + + testWidgets('renders a Text widget with the correct label', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + label: 'Range Selector', + ), + ), + ); + + await tester.pumpAndSettle(); + + final label = find.text('Range Selector'); + expect(label, findsOneWidget); + }); }); group('Dimensions Tests', () { - // + testWidgets('TextFormFields have the correct dimenions', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + ), + ), + ); + + await tester.pumpAndSettle(); + + final textFields = find.byType(TextFormField); + expect(textFields, findsNWidgets(2)); + + expect(tester.getRect(textFields.first).width, 56); + expect(tester.getRect(textFields.first).height, 48); + + expect(tester.getRect(textFields.last).width, 56); + expect(tester.getRect(textFields.last).height, 48); + }); + + // slider has the correct height + testWidgets('Slider has the correct height', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + ), + ), + ); + + await tester.pumpAndSettle(); + + final slider = find.byType(RangeSlider); + expect(tester.getRect(slider).height, 20); + }); + + testWidgets('Padding between TextFormFields and slider', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + ), + ), + ); + + await tester.pumpAndSettle(); + + final textFields = find.byType(TextFormField); + final slider = find.byType(RangeSlider); + + final textFieldRight = tester.getBottomRight(textFields.first); + final sliderLeft = tester.getBottomLeft(slider); + + expect(sliderLeft.dx - textFieldRight.dx, 32); + }); }); group('Styling Tests', () { - // has correct default style + testWidgets('Label has the correct font style', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + label: 'Range Selector', + ), + ), + ); + final colors = Zeta.of(tester.element(find.byType(ZetaRangeSelector))).colors; + + await tester.pumpAndSettle(); + + final label = find.text('Range Selector'); + final labelWidget = tester.widget(label); + + expect(labelWidget.style!.color, colors.textDefault); + expect(labelWidget.style!.fontSize, 14); + expect(labelWidget.style!.fontWeight, FontWeight.w400); + }); + + testWidgets('TextFormField have the correct font style', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + ), + ), + ); + final colors = Zeta.of(tester.element(find.byType(ZetaRangeSelector))).colors; + + await tester.pumpAndSettle(); + + final textFields = find.byType(TextField); + final firstTextFieldWidget = tester.widget(textFields.first); + + expect(firstTextFieldWidget.style!.color, colors.textSubtle); + expect(firstTextFieldWidget.style!.fontSize, 16); + expect(firstTextFieldWidget.style!.fontWeight, FontWeight.w400); + + final lastTextFieldWidget = tester.widget(textFields.last); + + expect(lastTextFieldWidget.style!.color, colors.textSubtle); + expect(lastTextFieldWidget.style!.fontSize, 16); + expect(lastTextFieldWidget.style!.fontWeight, FontWeight.w400); + }); + + testWidgets('TextFormFields have the correct border color and width', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + ), + ), + ); + final colors = Zeta.of(tester.element(find.byType(ZetaRangeSelector))).colors; + + await tester.pumpAndSettle(); + + final textFields = find.byType(TextField); + final firstTextFieldWidget = tester.widget(textFields.first); + + expect(firstTextFieldWidget.decoration!.border!.borderSide.color, colors.borderDefault); + expect(firstTextFieldWidget.decoration!.border!.borderSide.width, 1); + + final lastTextFieldWidget = tester.widget(textFields.last); + + expect(lastTextFieldWidget.decoration!.border!.borderSide.color, colors.borderDefault); + expect(lastTextFieldWidget.decoration!.border!.borderSide.width, 1); + }); + + // slider has the correct color + testWidgets('Slider has the correct color', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + ), + ), + ); + final colors = Zeta.of(tester.element(find.byType(ZetaRangeSelector))).colors; + + final sliderTheme = find.byType(SliderTheme); + final sliderThemeWidget = tester.widget(sliderTheme); + + expect(sliderThemeWidget.data.activeTrackColor, colors.surfaceDefaultInverse); + }); }); group('Interaction Tests', () { @@ -59,8 +290,7 @@ void main() { padding: const EdgeInsets.all(32), child: ZetaRangeSelector( label: 'Range Selector', - lowerValue: 20, - upperValue: 80, + initialValues: const RangeValues(20, 80), showValues: false, onChange: (newValue) { secondValue = newValue.end; @@ -74,7 +304,7 @@ void main() { await tester.pumpAndSettle(); final slider = find.byType(RangeSlider); - final sliderTopLeft = tester.getTopLeft(slider, warnIfMissed: true); + final sliderTopLeft = tester.getTopLeft(slider); await tester.dragFrom(sliderTopLeft.translate(0, 0), const Offset(250, 0)); @@ -84,13 +314,206 @@ void main() { await tester.pumpAndSettle(); - expect(firstValue!.round(), 33); - expect(secondValue!.round(), 62); + expect(firstValue!.round(), 34); + expect(secondValue!.round(), 61); + }); + + // input boxes set the value of the slider + testWidgets('TextFormFields set the value of the slider', (tester) async { + await tester.pumpWidget( + TestApp( + home: Padding( + padding: const EdgeInsets.all(32), + child: ZetaRangeSelector( + label: 'Range Selector', + initialValues: const RangeValues(20, 80), + onChange: (value) => , + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + final slider = find.byType(ZetaRangeSelector); + final sliderWidget = tester.widget(slider); + + expect(slider.first., const RangeValues(20, 80)); + + final textFields = find.byType(TextField); + final firstTextField = textFields.first; + final lastTextField = textFields.last; + + await tester.enterText(firstTextField, '50'); + + await tester.tapAt(const Offset(100, 100)); + await tester.enterText(lastTextField, '70'); + await tester.tapAt(const Offset(100, 100)); + + await tester.pumpAndSettle(); + + expect(sliderWidget.values, const RangeValues(50, 70)); + }); + + testWidgets('TextFormFields set the value of the slider', (tester) async { + await tester.pumpWidget( + MaterialApp( + home: Padding( + padding: const EdgeInsets.all(32), + child: ZetaRangeSelector( + label: 'Range Selector', + initialValues: const RangeValues(20, 80), + onChange: (value) {}, + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + + final sliderFinder = find.byType(ZetaRangeSelector); + expect(sliderFinder, findsOneWidget); + + final state = tester.; + expect(state._values, const RangeValues(20, 80)); + + final textFields = find.byType(TextField); + final firstTextField = textFields.first; + final lastTextField = textFields.last; + + await tester.enterText(firstTextField, '50'); + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pumpAndSettle(); + + await tester.enterText(lastTextField, '70'); + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pumpAndSettle(); + + expect(state._values, const RangeValues(50, 70)); }); }); group('Golden Tests', () { - // goldenTest(goldenFile, widget, 'PNG_FILE_NAME'); + goldenTest( + goldenFile, + ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + showValues: false, + ), + 'range_slider_rounded_continuous', + ); + goldenTest( + goldenFile, + ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + showValues: false, + divisions: 10, + ), + 'range_slider_rounded_stepped', + ); + goldenTest( + goldenFile, + ZetaRangeSelector( + initialValues: const RangeValues(20, 80), + showValues: false, + ), + 'range_slider_rounded_disabled', + ); + + goldenTest( + goldenFile, + ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + showValues: false, + rounded: false, + ), + 'range_slider_sharp_continuous', + ); + goldenTest( + goldenFile, + ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + showValues: false, + divisions: 10, + rounded: false, + ), + 'range_slider_sharp_stepped', + ); + goldenTest( + goldenFile, + ZetaRangeSelector( + initialValues: const RangeValues(20, 80), + showValues: false, + rounded: false, + ), + 'range_slider_sharp_disabled', + ); + + goldenTest( + goldenFile, + ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + label: 'Label', + ), + 'range_selector_rounded_continuous', + ); + goldenTest( + goldenFile, + ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + label: 'Label', + divisions: 10, + ), + 'range_selector_rounded_stepped', + ); + goldenTest( + goldenFile, + ZetaRangeSelector( + initialValues: const RangeValues(20, 80), + label: 'Label', + divisions: 10, + ), + 'range_selector_rounded_disabled', + ); + + goldenTest( + goldenFile, + ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + label: 'Label', + rounded: false, + ), + 'range_selector_sharp_continuous', + ); + goldenTest( + goldenFile, + ZetaRangeSelector( + onChange: (value) {}, + initialValues: const RangeValues(20, 80), + label: 'Label', + rounded: false, + divisions: 10, + ), + 'range_selector_sharp_stepped', + ); + goldenTest( + goldenFile, + ZetaRangeSelector( + initialValues: const RangeValues(20, 80), + label: 'Label', + rounded: false, + divisions: 10, + ), + 'range_selector_sharp_disabled', + ); }); group('Performance Tests', () {}); diff --git a/test/test_utils/utils.dart b/test/test_utils/utils.dart index 406d598e..bb35d331 100644 --- a/test/test_utils/utils.dart +++ b/test/test_utils/utils.dart @@ -88,3 +88,39 @@ void debugFillPropertiesTest(Widget widget, Map properties) { }); }); } + +void meetsAccessbilityGuidelinesTest( + Widget widget, { + ThemeMode themeMode = ThemeMode.system, + Size? screenSize, + bool? rounded, + Future Function(WidgetTester)? setUp, + Future Function(WidgetTester)? beforeTest, +}) { + testWidgets('meets accessibility requirements', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + if (setUp != null) { + await setUp(tester); + } + + await tester.pumpWidget( + TestApp( + screenSize: screenSize, + themeMode: themeMode, + rounded: rounded, + home: widget, + ), + ); + + if (beforeTest != null) { + await beforeTest(tester); + } + + await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); + await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); + await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + await expectLater(tester, meetsGuideline(textContrastGuideline)); + + handle.dispose(); + }); +} From 172985e068f27c6fd483c3af612ee3f880afecc3 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Thu, 21 Nov 2024 13:22:38 +0000 Subject: [PATCH 3/5] test: created interaction tests --- .../components/range_selector_example.dart | 4 +- .../range_selector/range_selector.dart | 4 +- .../range_selector_rounded_disabled.png | Bin 4744 -> 4625 bytes .../golden/range_selector_rounded_stepped.png | Bin 4832 -> 4692 bytes .../golden/range_selector_sharp_disabled.png | Bin 3769 -> 3668 bytes .../golden/range_selector_sharp_stepped.png | Bin 3847 -> 3687 bytes .../golden/range_slider_rounded_stepped.png | Bin 4495 -> 3990 bytes .../golden/range_slider_sharp_stepped.png | Bin 3963 -> 3498 bytes .../range_selector/range_selector_test.dart | 75 ++++++++---------- 9 files changed, 36 insertions(+), 47 deletions(-) diff --git a/example/lib/pages/components/range_selector_example.dart b/example/lib/pages/components/range_selector_example.dart index 69b2fd75..f6add6d0 100644 --- a/example/lib/pages/components/range_selector_example.dart +++ b/example/lib/pages/components/range_selector_example.dart @@ -116,9 +116,9 @@ class _RangeSelectorExampleState extends State { Text('Range Selector - Rounded - Continuous', style: ZetaTextStyles.bodyLarge), ZetaRangeSelector( onChange: (value) {}, - initialValues: RangeValues(20, 40), + initialValues: RangeValues(20, 80), min: 0, - max: 50, + max: 100, label: 'Label', semanticLabel: 'Hello World!', ), diff --git a/lib/src/components/range_selector/range_selector.dart b/lib/src/components/range_selector/range_selector.dart index aadf8681..7db9526c 100644 --- a/lib/src/components/range_selector/range_selector.dart +++ b/lib/src/components/range_selector/range_selector.dart @@ -217,7 +217,7 @@ class _ZetaRangeSelectorState extends State { /// Ticks activeTickMarkColor: colors.surfaceDefault, inactiveTickMarkColor: colors.surfaceDefault, - rangeTickMarkShape: const RoundRangeSliderTickMarkShape(tickMarkRadius: 2), + rangeTickMarkShape: const RoundRangeSliderTickMarkShape(tickMarkRadius: 1), /// Thumbs overlayShape: _DrawThumbOverlay( @@ -335,7 +335,7 @@ class _ValueField extends StatelessWidget { controller: controller, onEditingComplete: onEditingComplete, onChanged: onChanged, - onTapOutside: (event) => onTapOutside?.call(event), + onTapOutside: onTapOutside.call, textAlign: TextAlign.center, inputFormatters: [FilteringTextInputFormatter.digitsOnly], style: Theme.of(context).textTheme.bodyMedium?.copyWith( diff --git a/test/src/components/range_selector/golden/range_selector_rounded_disabled.png b/test/src/components/range_selector/golden/range_selector_rounded_disabled.png index c0fd34dd733a42fb57839539e31fd63c0acab774..921e12ede07d0ef1283d895903bc39ca6e5e4e9a 100644 GIT binary patch delta 1562 zcmV+#2IcvPC6OeMKz|XtNklfe9*q zG^?r>I=$-l`qgYUtI=o-d!}!t-|tti*Q-{uQ4{Uvu*U%afE63%{rTAKxw}jKrK-in zUUfR%>i7G@p7C30G#b@zw`zR6S&gw0ApiiZD+`@ojq?6{?BknrOP_waRCn*r4|}$O znw*@dW}{JCHn)a73IG5s+wD7@8s+^q`KD&GS)ERI*z*irx4T%4=K6kI1pvUtGwS>E zO^rrl-9Og(D*b+c-Jh2O0AS-8_5HcGU;&e{2snRCbGa9udgt9bd;Wt}f1?NP-&t3# zUSIY4sqNe9xo3~AdOf6_d;i0_aPe}@+`L^gv$w0=8n3DC+iJ)3wtDihM{4Vq&BGoM zU_-k-cc)IBey?uK+^U;$p8pxiepvE?=$F@1Cn;N55B(A3iv=IRQ4ZxBq#z-u&CCT3qaX z>Fd|7&(yW+Gj--)@7JOId+NloBQ-hE9@?BRiUbG@(Af)@>h(9?s`-V^*Iu`{*sDLk z@sB!x@pAp>*{5prcP3*q0&HY=?#|cm|MY*?x_srMZ@l*Gg-dn$%18D5iKDf5&jXS9 zU?cDu5E!7-@1Fn0`1qoWm#);uH)hv#CICKn?W37x#mE25FLdhE>G#%jCfH~M2n@(O zXU^3JA6{MYxRbFI}m3&YWA5nP4Mw1Pcb_?K6L8 zSGDfW-TC^(FJB$_JOB*N+h@-D+#U>w0J%rZFLZ0}&O-Hi{b7&7Dl9E6)$Hutu*U#k zjoiBRNnO4=Q)6Re!ybiIXf_+QW%EQ$PPB$S3XWjiJLc{z)Q+hwwQJ}0VUH5CYv=Zn zx!?Kuh3fUi;}^aB()0E5OV1B`j2M6SJKEeYi@jdW&o2ynjDZ-XzrV||Yv=abF}0=U z?u^F2-zX3uFaVnxev|-4o!|8^7>;1wBeraws2exuHq;TUYu88T?N1Z!cD38B>i97E zXMXd$*M>bpl=~fR?w5AERTJ&e`2Rpg>F@7yT)RH|*%2)64FcpIF*(t4E^&XI+qH9g zRd2xp;NG`u=X5=|YiihIz(^1vFd$DHKD4R;*|zn*`uR^^sPS<>jsR%hL1 z|9%I)ngD?TI{x&LnpnY6y2F2u?yCpy|L&U31ii5OHJu4I z8UX?Wbl>L5dgbL8>(Kr^Uwhs7c(YDCeWXqvKN_12fd4vq{Am5~*!REj>GPred+L>+ zy;u`%pV5Rta_$2LY;vMqKR)?`I(z<7y?^Q7HFNWJ&CK4ec5A$*wr^ak9n;(D$;Te4 zty?w^dsKi8>+!<}>*0s)uT!Vrs~a=7>gMdN>U0-tdi&Ozp4wXb_wKHP`yLwhm@tyY z=I(ZvZrr#z>^auNjvZ6gmRJA)tRtOX)hO@J9l-*V!3a2im`(kDzZ#9ku;&=KMx#;v zet+0w006*>jQak3Q?J*ncDps~c?Pc48n1p&fB*onzKr_*yxD3ts=rhX0035I)c5CO-EMbjq0_6y-lx@QHrD;)o_@by{a(Muo11E) z-5mBf006KPVxzo2AM19zOT!)t007t+yafxh;RullvtS8w0T-D609sr75S=xqjsO4v M07*qoM6N<$f?_{fNB{r; delta 1680 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 delta 770 zcmV+d1O5Ex9ETo|L4UDHL_t(|obBCDi(T~@!0}(q1Zj{Y6{JuXE*vF`Odx{z5{&kb zub{Z^PH~!j3x(-GH-T)$cHufvlep+xXdsh?&~f3WAQnwRP`t)Y7cHTG7ENYyzb85O z^I6@+{J77v7|!`}?#w;3SS(HuA8^N9w&}J_0QM0?u@U$`F84&mg?vao}AUbUwnD{K<9UMZj5K2eeR*nGqpF~ z`1v?@ZgY$=#@5#MxOnl>)FUmGeeF9ZtG4fh_~OgkXGmSRpN`$#Psi5Q z_SEAnoqgxczRbz0U4K_?-^Yc&0eM86ICgZ5y}#dky%L{MoYB62`~28}&d)IUo6s*@ zI6p32I6w6m8T-zgeIIWJ{U-Eho<25y{G%T})R`tRqwDW|`L}&}GbQDAYDmUX)K9a6#WD0LOV)HW60Ddt3p>@gwQ0KX*aG! z+8NrsH(%y?*7pv-)j7Q1J!c-cef##m1^@s+VAs?G0000x$A7}q1Hc$#tgnAE&Yu14 z*x2~XxN>DC}be#$&}z!5B_bnDiw@yaVdAFsdu z>v8AKoo{?*Hk*wTCw@3yeDU;HSkTM>@OAc6=7|7dGM6rWHcp&4IX?gVuUmS4W#x(S z+H0?lm6a#%`hRQyFfZ(<%o}$=n9PL>Z*6(89A7Q47cRVYS7!o%d1F6i-uME-BtHK5 zkK?)LzBe{EH@EfPu3fvv`|rQ&R~rDZpE9Q$0Av#9&i!uNi{%(&Y;JCjqes7US7ri$ zonmuybG-4!Z^p|n|7_|}*nzejApg91dtAS9bA0*bH-BGjg6;V9(?3l;0s!o2mp;2Z z{`U8OOg#qofrW+H*tfW6?A^0_OV4ll4#@QzH^(FU_l*OOJ^a7Sx8v-7aA7=t@X@if zxOeJN?kU%rXq-9o($u5OmE*^sAD1s*9ILApryheH z$iLxb5?8NY9nU;-bbRr}7u$MoadB~c@WH#|(4j+jZ8iXy7xq);kvkwv;_%_aWhO+_^KJefGQK;>AC2>G{>wmGRztzaO*N?5@uS0Q16r z%3i$j1%%1WX0!43+vmrrQ$PBTi{NZF8z)bm81KAu!D0yjUt>RI-uME-Jz;(QlX3R! zxv{aaF|J(M7-Niaye_g=8ngHFc62-J%|;M~s*O8jT)17c*CMaR_t{5*h+TL53Ck znJcc?J-c`Bo||s^P1fkfODSnl+9qtBUmib z@#Dwm6QB6xeD<@SpY`?iU-_Dqm6f^m)?4PTyY86PRm}_lzsz~cW+FgXn8zOb;oN%b zZS$ia{pT6Iet*xNtLD(5`)ALdtIqm10N5;?r))NU1H!^Q^w7g+e6gI@F0cc=PdcwW_QS{L+2>zc^o(=D%F6P*W#{kA)-9`Z?A7D*;!CeAdeWxw zrfpm2q6>G-(#)JZd1_Wy&+OM7XZ#zGwYAk*U4LDfwbhlm=)xWUpRI2gTeqyuj_uoK zd3kxZU9e@gZ@Xa8lg=4WKmF9AC!AMy?AS5)+_Qf!zWA+k%{A|yn{WQ$q9<(%`}W;9 z*IxVH*|~G)eBc9rHhcH(UG$_)VgLR+=km+nK9^tq_WunLe!abW_s;v@|EIHa=gztI z+JE=XzI`_?deWwF^UWWeYp!|sTzv6c=kB}r&yF2FfBZH*{q)m|o^a0CzU_k9cEOfe zUS6IzZ{Idsx2!FC(x!0Hg*#?#b>)8=VeQNxtnwpt7GlfRt&5&;-tomfa6VgFTJ!?o zw`Jwtd++_LGkM{uQ|q&|v^47*r{||H|9@;wp8D1QW19c7zP>RlE6cOCx-!2wesW%Z z<(S7iUh^;C`OX|Y`plwdoHtIKI58(qoR}-GymB6Y{E0bu@Neh&=bvBntaIKo&m5gA zue@S*?!0IoeDKTj#V>wo(UUfXAOH9#vuDp$^Wuvy&4B|4=ZPntSoEZG-gD1AH-Ec! z?V7i}?RV$f-~Q*h|Nc+Sv17*;J?otJ?6c3#o;_F1^76_YI`pae*0=s?(UZozvvm~gj4J5v$nQ6E6YoB?B~CjSB|~9=t-Nx`ufIf*|IjLH%`yVlc#2R`OLm4 z@L#Z4i2LsQoB7OV{(jLj0N@Sl_J7+yG#~re-HV>V8;}5DA)b2bsd>+PuA7r5Prk1A zZQs6qzWL3s&83%Kde*i9z-Hk*Wi#>{5EkOH%PyNc?)d2Ie&3yU{)LMr0KCR|%4Xya z2n(~mzCQ1J-wpGFAN>0nz5X5V*fU@M`d4RVW#z1I1AxuKdCF$v4hRdgvRkq;k38~^ zbNlTd`n4Cqm6esb?Y3LzD_?oY#S#F1iSv}r#vKsO35O3qIuAVX;2b$}WS)HT$jr=K zamDW0z5DXH>83xKy?d`-^h5wS=Q&T=3i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|s42wL#WAE}&fB{iy`mEt+8!ncI@&a|x&|!S9qF~uJh;es(rv*#0*WOC zCvF{dTK+Ebjjl`bedjZu&!|7VJ!$&?Cr=Xg#_i_;8r+##F z{(k5!|qehHFuxjF#K4fk0usFWLo;Ik|382Cdp{7} zR{M&b;lXd&_pe`l`s{Xn?<3Ii zqr3<``SwDYg&+)MT>e}8|U zpDiQ9w|kF2J-;IS!@+DXYxZN~Wxn?Xxc==FW!U!Lcgg#5pM$y)SiA-HYue-EAAlas zIgQ)eDU literal 3963 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`Gu)5S5QV$R#U=euLSGPXZ_?^EYzl*OjV##54bZED|7?lYTiOsHM0 zu(Df;gLQ7pI&T>!R>xf%950l~3+?Kycbt=Sy)dvtm2=DF7e_qvCV7gpE|iwOvd6r< zX5Q7iG4ImL-&LP`IA`a{lusb1usmCC3#5L0ykYs4@sEY=|3Ciwu7BVErKl$ahnYVvF|N1r4ze4HF4MY2Ru~k)XZtg9)j=f(}?-*4>S zP=0Ijjb&ou;>TZJ)_#0p;qzk`7wh*| z31kb%GZU5ddz9VdeyF+pC_8=n^y91H^_J77O*^(RS-)Rcz0be;l8;5@r>})yUU-9z zT^X#MTzK(6zg+)c?&{-*?%hqUtE;owTAv8?0x*En4wb)U-kxyK?BNmH4Rg<)^{r<7 z;9U8HVP|D_@}1rP6To=S){hn8xx(e@-;afFH$Q&u+O->dj3u|5zxSyYx_#x?v11kA z?_Mo@d+TfA&ri!A-`U9z3^KJj_VtM|yS|)^h>w?-um3ZBZ;*w4@6%RnYre}A~6=I3Rw$ , + initialValues: values, + onChange: (newValues) { + values = newValues; + }, ), ), ), ); - await tester.pumpAndSettle(); - - final slider = find.byType(ZetaRangeSelector); - final sliderWidget = tester.widget(slider); - - expect(slider.first., const RangeValues(20, 80)); - - final textFields = find.byType(TextField); - final firstTextField = textFields.first; - final lastTextField = textFields.last; - - await tester.enterText(firstTextField, '50'); - - await tester.tapAt(const Offset(100, 100)); - await tester.enterText(lastTextField, '70'); - await tester.tapAt(const Offset(100, 100)); + final firstTextFinder = find.ancestor(of: find.text('20'), matching: find.byType(TextFormField)); + final secondTextFinder = find.ancestor(of: find.text('80'), matching: find.byType(TextFormField)); await tester.pumpAndSettle(); + await tester.enterText(firstTextFinder, '40'); + await tester.testTextInput.receiveAction(TextInputAction.done); + + await tester.enterText(secondTextFinder, '60'); + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pump(); - expect(sliderWidget.values, const RangeValues(50, 70)); + expect(values, const RangeValues(40, 60)); }); - testWidgets('TextFormFields set the value of the slider', (tester) async { + testWidgets('TextFormFields set the value of the slider on tap outside', (tester) async { + RangeValues values = const RangeValues(20, 80); await tester.pumpWidget( - MaterialApp( + TestApp( home: Padding( padding: const EdgeInsets.all(32), child: ZetaRangeSelector( label: 'Range Selector', - initialValues: const RangeValues(20, 80), - onChange: (value) {}, + initialValues: values, + onChange: (newValues) { + values = newValues; + }, ), ), ), ); - await tester.pumpAndSettle(); - + final firstTextFinder = find.ancestor(of: find.text('20'), matching: find.byType(TextFormField)); + final secondTextFinder = find.ancestor(of: find.text('80'), matching: find.byType(TextFormField)); - final sliderFinder = find.byType(ZetaRangeSelector); - expect(sliderFinder, findsOneWidget); - - final state = tester.; - expect(state._values, const RangeValues(20, 80)); - - final textFields = find.byType(TextField); - final firstTextField = textFields.first; - final lastTextField = textFields.last; - - await tester.enterText(firstTextField, '50'); - await tester.testTextInput.receiveAction(TextInputAction.done); await tester.pumpAndSettle(); + await tester.enterText(firstTextFinder, '30'); + await tester.pump(); + await tester.tapAt(Offset.zero); + await tester.pump(); - await tester.enterText(lastTextField, '70'); - await tester.testTextInput.receiveAction(TextInputAction.done); await tester.pumpAndSettle(); + await tester.enterText(secondTextFinder, '70'); + await tester.pump(); + await tester.tapAt(Offset.zero); + await tester.pump(); - expect(state._values, const RangeValues(50, 70)); + expect(values, const RangeValues(30, 70)); }); }); From c38cd28f548bb90bb1354dbded98928cfd7ff050 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Thu, 21 Nov 2024 13:37:20 +0000 Subject: [PATCH 4/5] test: adjusted golden tolerence --- test/src/components/range_selector/range_selector_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/components/range_selector/range_selector_test.dart b/test/src/components/range_selector/range_selector_test.dart index 589b5117..a81796b6 100644 --- a/test/src/components/range_selector/range_selector_test.dart +++ b/test/src/components/range_selector/range_selector_test.dart @@ -11,7 +11,7 @@ void main() { const goldenFile = GoldenFiles(component: parentFolder); setUpAll(() { - goldenFileComparator = TolerantComparator(goldenFile.uri, tolerance: 0); + goldenFileComparator = TolerantComparator(goldenFile.uri, tolerance: 0.001); }); group('Accessibility Tests', () { From 9b356bc6c7a48ae6782d39ba4900b03670cfc605 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Fri, 22 Nov 2024 09:49:01 +0000 Subject: [PATCH 5/5] fix: removed rounded from widgetbook fix: removed large thumbs fix: removed defaults to true on showValues --- .../pages/components/range_selector_example.dart | 1 - .../pages/components/range_selector_widgetbook.dart | 2 -- .../components/range_selector/range_selector.dart | 13 +++---------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/example/lib/pages/components/range_selector_example.dart b/example/lib/pages/components/range_selector_example.dart index f6add6d0..1820dec1 100644 --- a/example/lib/pages/components/range_selector_example.dart +++ b/example/lib/pages/components/range_selector_example.dart @@ -120,7 +120,6 @@ class _RangeSelectorExampleState extends State { min: 0, max: 100, label: 'Label', - semanticLabel: 'Hello World!', ), ].gap(12), ), diff --git a/example/widgetbook/pages/components/range_selector_widgetbook.dart b/example/widgetbook/pages/components/range_selector_widgetbook.dart index fe5d46fd..3c8bd50d 100644 --- a/example/widgetbook/pages/components/range_selector_widgetbook.dart +++ b/example/widgetbook/pages/components/range_selector_widgetbook.dart @@ -24,8 +24,6 @@ class RangeSelectorExample extends StatelessWidget { divisions: context.knobs.intOrNull.input(label: 'Divisions', initialValue: null), showValues: context.knobs.boolean(label: 'Show Values', initialValue: true), onChange: disabledKnob(context) ? null : (value) {}, - largeSliderThumbs: context.knobs.boolean(label: 'Large Slider Thumbs', initialValue: false), - rounded: context.knobs.booleanOrNull(label: 'Rounded', initialValue: true), initialValues: context.knobs.range(label: 'Initial Range', initialValue: RangeValues(20, 80)), min: context.knobs.double.input(label: 'Min', initialValue: 0), max: context.knobs.double.input(label: 'Max', initialValue: 100), diff --git a/lib/src/components/range_selector/range_selector.dart b/lib/src/components/range_selector/range_selector.dart index 7db9526c..de14fe8e 100644 --- a/lib/src/components/range_selector/range_selector.dart +++ b/lib/src/components/range_selector/range_selector.dart @@ -21,7 +21,6 @@ class ZetaRangeSelector extends ZetaStatefulWidget { this.divisions, this.semanticLabel, this.showValues = true, - this.largeSliderThumbs = false, }) : assert( min <= initialValues.start && initialValues.start <= initialValues.end && initialValues.end <= max, 'The start value must be less than or equal to the end value, and both must be within the range of min and max.', @@ -51,13 +50,8 @@ class ZetaRangeSelector extends ZetaStatefulWidget { final String? semanticLabel; /// Whether to show the values of the range selector. - /// Defaults to true. final bool showValues; - /// Whether to use larger slider thumbs. - /// Defaults to false. - final bool largeSliderThumbs; - @override State createState() => _ZetaRangeSelectorState(); @@ -72,8 +66,7 @@ class ZetaRangeSelector extends ZetaStatefulWidget { ..add(IntProperty('divisions', divisions)) ..add(StringProperty('semanticLabel', semanticLabel)) ..add(DiagnosticsProperty('showValues', showValues)) - ..add(DiagnosticsProperty('initialValues', initialValues)) - ..add(DiagnosticsProperty('largeSliderThumbs', largeSliderThumbs)); + ..add(DiagnosticsProperty('initialValues', initialValues)); } } @@ -221,12 +214,12 @@ class _ZetaRangeSelectorState extends State { /// Thumbs overlayShape: _DrawThumbOverlay( - size: widget.largeSliderThumbs ? spacing.xl_3 / 2 : spacing.xl / 2, + size: spacing.xl / 2, rounded: rounded, color: _activeColor, ), rangeThumbShape: _DrawThumb( - size: widget.largeSliderThumbs ? spacing.xl_2 / 2 : spacing.large / 2, + size: spacing.large / 2, rounded: rounded, color: _activeColor, ),