Add Material 3 support for Slider
- Part 1 (#114079)
This commit is contained in:
parent
f10021b378
commit
97d0247d59
@ -38,6 +38,7 @@ import 'package:gen_defaults/navigation_rail_template.dart';
|
|||||||
import 'package:gen_defaults/popup_menu_template.dart';
|
import 'package:gen_defaults/popup_menu_template.dart';
|
||||||
import 'package:gen_defaults/progress_indicator_template.dart';
|
import 'package:gen_defaults/progress_indicator_template.dart';
|
||||||
import 'package:gen_defaults/radio_template.dart';
|
import 'package:gen_defaults/radio_template.dart';
|
||||||
|
import 'package:gen_defaults/slider_template.dart';
|
||||||
import 'package:gen_defaults/surface_tint.dart';
|
import 'package:gen_defaults/surface_tint.dart';
|
||||||
import 'package:gen_defaults/switch_template.dart';
|
import 'package:gen_defaults/switch_template.dart';
|
||||||
import 'package:gen_defaults/text_field_template.dart';
|
import 'package:gen_defaults/text_field_template.dart';
|
||||||
@ -144,6 +145,7 @@ Future<void> main(List<String> args) async {
|
|||||||
PopupMenuTemplate('PopupMenu', '$materialLib/popup_menu.dart', tokens).updateFile();
|
PopupMenuTemplate('PopupMenu', '$materialLib/popup_menu.dart', tokens).updateFile();
|
||||||
ProgressIndicatorTemplate('ProgressIndicator', '$materialLib/progress_indicator.dart', tokens).updateFile();
|
ProgressIndicatorTemplate('ProgressIndicator', '$materialLib/progress_indicator.dart', tokens).updateFile();
|
||||||
RadioTemplate('Radio<T>', '$materialLib/radio.dart', tokens).updateFile();
|
RadioTemplate('Radio<T>', '$materialLib/radio.dart', tokens).updateFile();
|
||||||
|
SliderTemplate('md.comp.slider', 'Slider', '$materialLib/slider.dart', tokens).updateFile();
|
||||||
SurfaceTintTemplate('SurfaceTint', '$materialLib/elevation_overlay.dart', tokens).updateFile();
|
SurfaceTintTemplate('SurfaceTint', '$materialLib/elevation_overlay.dart', tokens).updateFile();
|
||||||
SwitchTemplate('Switch', '$materialLib/switch.dart', tokens).updateFile();
|
SwitchTemplate('Switch', '$materialLib/switch.dart', tokens).updateFile();
|
||||||
TextFieldTemplate('TextField', '$materialLib/text_field.dart', tokens).updateFile();
|
TextFieldTemplate('TextField', '$materialLib/text_field.dart', tokens).updateFile();
|
||||||
|
77
dev/tools/gen_defaults/lib/slider_template.dart
Normal file
77
dev/tools/gen_defaults/lib/slider_template.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'template.dart';
|
||||||
|
|
||||||
|
class SliderTemplate extends TokenTemplate {
|
||||||
|
const SliderTemplate(this.tokenGroup, super.blockName, super.fileName, super.tokens, {
|
||||||
|
super.colorSchemePrefix = '_colors.',
|
||||||
|
});
|
||||||
|
|
||||||
|
final String tokenGroup;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String generate() => '''
|
||||||
|
class _${blockName}DefaultsM3 extends SliderThemeData {
|
||||||
|
_${blockName}DefaultsM3(this.context)
|
||||||
|
: _colors = Theme.of(context).colorScheme,
|
||||||
|
super(trackHeight: ${tokens['$tokenGroup.active.track.height']});
|
||||||
|
|
||||||
|
final BuildContext context;
|
||||||
|
final ColorScheme _colors;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get activeTrackColor => ${componentColor('$tokenGroup.active.track')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get inactiveTrackColor => ${componentColor('$tokenGroup.inactive.track')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get secondaryActiveTrackColor => _colors.primary.withOpacity(0.54);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledActiveTrackColor => ${componentColor('$tokenGroup.disabled.active.track')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledInactiveTrackColor => ${componentColor('$tokenGroup.disabled.inactive.track')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledSecondaryActiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get activeTickMarkColor => ${componentColor('$tokenGroup.with-tick-marks.active.container')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get inactiveTickMarkColor => ${componentColor('$tokenGroup.with-tick-marks.inactive.container')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledActiveTickMarkColor => ${componentColor('$tokenGroup.with-tick-marks.disabled.container')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledInactiveTickMarkColor => ${componentColor('$tokenGroup.with-tick-marks.disabled.container')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get thumbColor => ${componentColor('$tokenGroup.handle')};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledThumbColor => Color.alphaBlend(${componentColor('$tokenGroup.disabled.handle')}, _colors.surface);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get overlayColor => MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return ${componentColor('$tokenGroup.hover.state-layer')};
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return ${componentColor('$tokenGroup.focus.state-layer')};
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.dragged)) {
|
||||||
|
return ${componentColor('$tokenGroup.pressed.state-layer')};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Colors.transparent;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
|
||||||
|
}
|
@ -12,6 +12,8 @@ import 'package:flutter/rendering.dart';
|
|||||||
import 'package:flutter/scheduler.dart' show timeDilation;
|
import 'package:flutter/scheduler.dart' show timeDilation;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'color_scheme.dart';
|
||||||
|
import 'colors.dart';
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'debug.dart';
|
import 'debug.dart';
|
||||||
import 'material.dart';
|
import 'material.dart';
|
||||||
@ -374,8 +376,9 @@ class Slider extends StatefulWidget {
|
|||||||
/// The "active" side of the slider is the side between the thumb and the
|
/// The "active" side of the slider is the side between the thumb and the
|
||||||
/// minimum value.
|
/// minimum value.
|
||||||
///
|
///
|
||||||
/// Defaults to [SliderThemeData.activeTrackColor] of the current
|
/// If null, [SliderThemeData.activeTrackColor] of the ambient
|
||||||
/// [SliderTheme].
|
/// [SliderTheme] is used. If that is null, [ColorScheme.primary] of the
|
||||||
|
/// surrounding [ThemeData] is used.
|
||||||
///
|
///
|
||||||
/// Using a [SliderTheme] gives much more fine-grained control over the
|
/// Using a [SliderTheme] gives much more fine-grained control over the
|
||||||
/// appearance of various components of the slider.
|
/// appearance of various components of the slider.
|
||||||
@ -386,8 +389,10 @@ class Slider extends StatefulWidget {
|
|||||||
/// The "inactive" side of the slider is the side between the thumb and the
|
/// The "inactive" side of the slider is the side between the thumb and the
|
||||||
/// maximum value.
|
/// maximum value.
|
||||||
///
|
///
|
||||||
/// Defaults to the [SliderThemeData.inactiveTrackColor] of the current
|
/// If null, [SliderThemeData.inactiveTrackColor] of the ambient [SliderTheme]
|
||||||
/// [SliderTheme].
|
/// is used. If that is null and [ThemeData.useMaterial3] is true,
|
||||||
|
/// [ColorScheme.surfaceVariant] will be used, otherwise [ColorScheme.primary]
|
||||||
|
/// with an opacity of 0.24 will be used.
|
||||||
///
|
///
|
||||||
/// Using a [SliderTheme] gives much more fine-grained control over the
|
/// Using a [SliderTheme] gives much more fine-grained control over the
|
||||||
/// appearance of various components of the slider.
|
/// appearance of various components of the slider.
|
||||||
@ -401,6 +406,9 @@ class Slider extends StatefulWidget {
|
|||||||
/// Defaults to the [SliderThemeData.secondaryActiveTrackColor] of the current
|
/// Defaults to the [SliderThemeData.secondaryActiveTrackColor] of the current
|
||||||
/// [SliderTheme].
|
/// [SliderTheme].
|
||||||
///
|
///
|
||||||
|
/// If that is also null, defaults to [ColorScheme.primary] with an
|
||||||
|
/// opacity of 0.54.
|
||||||
|
///
|
||||||
/// Using a [SliderTheme] gives much more fine-grained control over the
|
/// Using a [SliderTheme] gives much more fine-grained control over the
|
||||||
/// appearance of various components of the slider.
|
/// appearance of various components of the slider.
|
||||||
///
|
///
|
||||||
@ -409,19 +417,27 @@ class Slider extends StatefulWidget {
|
|||||||
|
|
||||||
/// The color of the thumb.
|
/// The color of the thumb.
|
||||||
///
|
///
|
||||||
/// If this color is null:
|
/// If this color is null, [Slider] will use [activeColor], If [activeColor]
|
||||||
/// * [Slider] will use [activeColor].
|
/// is also null, [Slider] will use [SliderThemeData.thumbColor].
|
||||||
|
///
|
||||||
|
/// If that is also null, defaults to [ColorScheme.primary].
|
||||||
|
///
|
||||||
/// * [CupertinoSlider] will have a white thumb
|
/// * [CupertinoSlider] will have a white thumb
|
||||||
/// (like the native default iOS slider).
|
/// (like the native default iOS slider).
|
||||||
final Color? thumbColor;
|
final Color? thumbColor;
|
||||||
|
|
||||||
/// The highlight color that's typically used to indicate that
|
/// The highlight color that's typically used to indicate that
|
||||||
/// the slider is focused, hovered, or dragged.
|
/// the slider thumb is focused, hovered, or dragged.
|
||||||
///
|
///
|
||||||
/// If this property is null, [Slider] will use [activeColor] with
|
/// If this property is null, [Slider] will use [activeColor] with
|
||||||
/// with an opacity of 0.12, If null, [SliderThemeData.overlayColor]
|
/// with an opacity of 0.12, If null, [SliderThemeData.overlayColor]
|
||||||
/// will be used, If this is also null, defaults to [ColorScheme.primary]
|
/// will be used.
|
||||||
/// with an opacity of 0.12.
|
///
|
||||||
|
/// If that is also null, If [ThemeData.useMaterial3] is true,
|
||||||
|
/// Slider will use [ColorScheme.primary] with an opacity of 0.08 when
|
||||||
|
/// slider thumb is hovered and with an opacity of 0.12 when slider thumb
|
||||||
|
/// is focused or dragged, If [ThemeData.useMaterial3] is false, defaults
|
||||||
|
/// to [ColorScheme.primary] with an opacity of 0.12.
|
||||||
final MaterialStateProperty<Color?>? overlayColor;
|
final MaterialStateProperty<Color?>? overlayColor;
|
||||||
|
|
||||||
/// {@template flutter.material.slider.mouseCursor}
|
/// {@template flutter.material.slider.mouseCursor}
|
||||||
@ -730,6 +746,7 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||||||
Widget _buildMaterialSlider(BuildContext context) {
|
Widget _buildMaterialSlider(BuildContext context) {
|
||||||
final ThemeData theme = Theme.of(context);
|
final ThemeData theme = Theme.of(context);
|
||||||
SliderThemeData sliderTheme = SliderTheme.of(context);
|
SliderThemeData sliderTheme = SliderTheme.of(context);
|
||||||
|
final SliderThemeData defaults = theme.useMaterial3 ? _SliderDefaultsM3(context) : _SliderDefaultsM2(context);
|
||||||
|
|
||||||
// If the widget has active or inactive colors specified, then we plug them
|
// If the widget has active or inactive colors specified, then we plug them
|
||||||
// in to the slider theme as best we can. If the developer wants more
|
// in to the slider theme as best we can. If the developer wants more
|
||||||
@ -738,7 +755,6 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||||||
// the default shapes and text styles are aligned to the Material
|
// the default shapes and text styles are aligned to the Material
|
||||||
// Guidelines.
|
// Guidelines.
|
||||||
|
|
||||||
const double defaultTrackHeight = 4;
|
|
||||||
const SliderTrackShape defaultTrackShape = RoundedRectSliderTrackShape();
|
const SliderTrackShape defaultTrackShape = RoundedRectSliderTrackShape();
|
||||||
const SliderTickMarkShape defaultTickMarkShape = RoundSliderTickMarkShape();
|
const SliderTickMarkShape defaultTickMarkShape = RoundSliderTickMarkShape();
|
||||||
const SliderComponentShape defaultOverlayShape = RoundSliderOverlayShape();
|
const SliderComponentShape defaultOverlayShape = RoundSliderOverlayShape();
|
||||||
@ -769,23 +785,23 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||||||
return widget.overlayColor?.resolve(states)
|
return widget.overlayColor?.resolve(states)
|
||||||
?? widget.activeColor?.withOpacity(0.12)
|
?? widget.activeColor?.withOpacity(0.12)
|
||||||
?? MaterialStateProperty.resolveAs<Color?>(sliderTheme.overlayColor, states)
|
?? MaterialStateProperty.resolveAs<Color?>(sliderTheme.overlayColor, states)
|
||||||
?? theme.colorScheme.primary.withOpacity(0.12);
|
?? MaterialStateProperty.resolveAs<Color?>(defaults.overlayColor, states);
|
||||||
}
|
}
|
||||||
|
|
||||||
sliderTheme = sliderTheme.copyWith(
|
sliderTheme = sliderTheme.copyWith(
|
||||||
trackHeight: sliderTheme.trackHeight ?? defaultTrackHeight,
|
trackHeight: sliderTheme.trackHeight ?? defaults.trackHeight,
|
||||||
activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? theme.colorScheme.primary,
|
activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? defaults.activeTrackColor,
|
||||||
inactiveTrackColor: widget.inactiveColor ?? sliderTheme.inactiveTrackColor ?? theme.colorScheme.primary.withOpacity(0.24),
|
inactiveTrackColor: widget.inactiveColor ?? sliderTheme.inactiveTrackColor ?? defaults.inactiveTrackColor,
|
||||||
secondaryActiveTrackColor: widget.secondaryActiveColor ?? sliderTheme.secondaryActiveTrackColor ?? theme.colorScheme.primary.withOpacity(0.54),
|
secondaryActiveTrackColor: widget.secondaryActiveColor ?? sliderTheme.secondaryActiveTrackColor ?? defaults.secondaryActiveTrackColor,
|
||||||
disabledActiveTrackColor: sliderTheme.disabledActiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.32),
|
disabledActiveTrackColor: sliderTheme.disabledActiveTrackColor ?? defaults.disabledActiveTrackColor,
|
||||||
disabledInactiveTrackColor: sliderTheme.disabledInactiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.12),
|
disabledInactiveTrackColor: sliderTheme.disabledInactiveTrackColor ?? defaults.disabledInactiveTrackColor,
|
||||||
disabledSecondaryActiveTrackColor: sliderTheme.disabledSecondaryActiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.12),
|
disabledSecondaryActiveTrackColor: sliderTheme.disabledSecondaryActiveTrackColor ?? defaults.disabledSecondaryActiveTrackColor,
|
||||||
activeTickMarkColor: widget.inactiveColor ?? sliderTheme.activeTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.54),
|
activeTickMarkColor: widget.inactiveColor ?? sliderTheme.activeTickMarkColor ?? defaults.activeTickMarkColor,
|
||||||
inactiveTickMarkColor: widget.activeColor ?? sliderTheme.inactiveTickMarkColor ?? theme.colorScheme.primary.withOpacity(0.54),
|
inactiveTickMarkColor: widget.activeColor ?? sliderTheme.inactiveTickMarkColor ?? defaults.inactiveTickMarkColor,
|
||||||
disabledActiveTickMarkColor: sliderTheme.disabledActiveTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.12),
|
disabledActiveTickMarkColor: sliderTheme.disabledActiveTickMarkColor ?? defaults.disabledActiveTickMarkColor,
|
||||||
disabledInactiveTickMarkColor: sliderTheme.disabledInactiveTickMarkColor ?? theme.colorScheme.onSurface.withOpacity(0.12),
|
disabledInactiveTickMarkColor: sliderTheme.disabledInactiveTickMarkColor ?? defaults.disabledInactiveTickMarkColor,
|
||||||
thumbColor: widget.thumbColor ?? widget.activeColor ?? sliderTheme.thumbColor ?? theme.colorScheme.primary,
|
thumbColor: widget.thumbColor ?? widget.activeColor ?? sliderTheme.thumbColor ?? defaults.thumbColor,
|
||||||
disabledThumbColor: sliderTheme.disabledThumbColor ?? Color.alphaBlend(theme.colorScheme.onSurface.withOpacity(.38), theme.colorScheme.surface),
|
disabledThumbColor: sliderTheme.disabledThumbColor ?? defaults.disabledThumbColor,
|
||||||
overlayColor: effectiveOverlayColor(),
|
overlayColor: effectiveOverlayColor(),
|
||||||
valueIndicatorColor: valueIndicatorColor,
|
valueIndicatorColor: valueIndicatorColor,
|
||||||
trackShape: sliderTheme.trackShape ?? defaultTrackShape,
|
trackShape: sliderTheme.trackShape ?? defaultTrackShape,
|
||||||
@ -1795,3 +1811,122 @@ class _RenderValueIndicator extends RenderBox with RelayoutWhenSystemFontsChange
|
|||||||
return constraints.smallest;
|
return constraints.smallest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _SliderDefaultsM2 extends SliderThemeData {
|
||||||
|
_SliderDefaultsM2(this.context)
|
||||||
|
: _colors = Theme.of(context).colorScheme,
|
||||||
|
super(trackHeight: 4.0);
|
||||||
|
|
||||||
|
final BuildContext context;
|
||||||
|
final ColorScheme _colors;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get activeTrackColor => _colors.primary;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get inactiveTrackColor => _colors.primary.withOpacity(0.24);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get secondaryActiveTrackColor => _colors.primary.withOpacity(0.54);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledActiveTrackColor => _colors.onSurface.withOpacity(0.32);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledInactiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledSecondaryActiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get activeTickMarkColor => _colors.onPrimary.withOpacity(0.54);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get inactiveTickMarkColor => _colors.primary.withOpacity(0.54);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledActiveTickMarkColor => _colors.onPrimary.withOpacity(0.12);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledInactiveTickMarkColor => _colors.onSurface.withOpacity(0.12);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get thumbColor => _colors.primary;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledThumbColor => Color.alphaBlend(_colors.onSurface.withOpacity(.38), _colors.surface);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get overlayColor => _colors.primary.withOpacity(0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BEGIN GENERATED TOKEN PROPERTIES - Slider
|
||||||
|
|
||||||
|
// Do not edit by hand. The code between the "BEGIN GENERATED" and
|
||||||
|
// "END GENERATED" comments are generated from data in the Material
|
||||||
|
// Design token database by the script:
|
||||||
|
// dev/tools/gen_defaults/bin/gen_defaults.dart.
|
||||||
|
|
||||||
|
// Token database version: v0_137
|
||||||
|
|
||||||
|
class _SliderDefaultsM3 extends SliderThemeData {
|
||||||
|
_SliderDefaultsM3(this.context)
|
||||||
|
: _colors = Theme.of(context).colorScheme,
|
||||||
|
super(trackHeight: 4.0);
|
||||||
|
|
||||||
|
final BuildContext context;
|
||||||
|
final ColorScheme _colors;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get activeTrackColor => _colors.primary;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get inactiveTrackColor => _colors.surfaceVariant;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get secondaryActiveTrackColor => _colors.primary.withOpacity(0.54);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledActiveTrackColor => _colors.onSurface.withOpacity(0.38);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledInactiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledSecondaryActiveTrackColor => _colors.onSurface.withOpacity(0.12);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get activeTickMarkColor => _colors.onPrimary.withOpacity(0.38);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get inactiveTickMarkColor => _colors.onSurfaceVariant.withOpacity(0.38);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledActiveTickMarkColor => _colors.onSurface.withOpacity(0.38);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledInactiveTickMarkColor => _colors.onSurface.withOpacity(0.38);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get thumbColor => _colors.primary;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get disabledThumbColor => Color.alphaBlend(_colors.onSurface.withOpacity(0.38), _colors.surface);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get overlayColor => MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return _colors.primary.withOpacity(0.08);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return _colors.primary.withOpacity(0.12);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.dragged)) {
|
||||||
|
return _colors.primary.withOpacity(0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Colors.transparent;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// END GENERATED TOKEN PROPERTIES - Slider
|
||||||
|
@ -1710,17 +1710,15 @@ void main() {
|
|||||||
testWidgets('Slider is focusable and has correct focus color', (WidgetTester tester) async {
|
testWidgets('Slider is focusable and has correct focus color', (WidgetTester tester) async {
|
||||||
final FocusNode focusNode = FocusNode(debugLabel: 'Slider');
|
final FocusNode focusNode = FocusNode(debugLabel: 'Slider');
|
||||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
double value = 0.5;
|
double value = 0.5;
|
||||||
Widget buildApp({bool enabled = true}) {
|
Widget buildApp({bool enabled = true}) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
theme: theme,
|
||||||
home: Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||||
return SliderTheme(
|
return Slider(
|
||||||
data: SliderThemeData(
|
|
||||||
overlayColor: Colors.orange[500],
|
|
||||||
),
|
|
||||||
child: Slider(
|
|
||||||
value: value,
|
value: value,
|
||||||
onChanged: enabled
|
onChanged: enabled
|
||||||
? (double newValue) {
|
? (double newValue) {
|
||||||
@ -1731,7 +1729,6 @@ void main() {
|
|||||||
: null,
|
: null,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@ -1745,7 +1742,7 @@ void main() {
|
|||||||
expect(focusNode.hasPrimaryFocus, isTrue);
|
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||||
expect(
|
expect(
|
||||||
Material.of(tester.element(find.byType(Slider))),
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
paints..circle(color: Colors.orange[500]),
|
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check that the overlay does not show when unfocused and disabled.
|
// Check that the overlay does not show when unfocused and disabled.
|
||||||
@ -1754,7 +1751,7 @@ void main() {
|
|||||||
expect(focusNode.hasPrimaryFocus, isFalse);
|
expect(focusNode.hasPrimaryFocus, isFalse);
|
||||||
expect(
|
expect(
|
||||||
Material.of(tester.element(find.byType(Slider))),
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
isNot(paints..circle(color: Colors.orange[500])),
|
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1813,17 +1810,15 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Slider can be hovered and has correct hover color', (WidgetTester tester) async {
|
testWidgets('Slider can be hovered and has correct hover color', (WidgetTester tester) async {
|
||||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
double value = 0.5;
|
double value = 0.5;
|
||||||
Widget buildApp({bool enabled = true}) {
|
Widget buildApp({bool enabled = true}) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
theme: theme,
|
||||||
home: Material(
|
home: Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||||
return SliderTheme(
|
return Slider(
|
||||||
data: SliderThemeData(
|
|
||||||
overlayColor: Colors.orange[500],
|
|
||||||
),
|
|
||||||
child: Slider(
|
|
||||||
value: value,
|
value: value,
|
||||||
onChanged: enabled
|
onChanged: enabled
|
||||||
? (double newValue) {
|
? (double newValue) {
|
||||||
@ -1832,7 +1827,6 @@ void main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@ -1858,7 +1852,7 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(
|
expect(
|
||||||
Material.of(tester.element(find.byType(Slider))),
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
paints..circle(color: Colors.orange[500]),
|
paints..circle(color: theme.colorScheme.primary.withOpacity(0.08)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Slider does not have an overlay when disabled and hovered.
|
// Slider does not have an overlay when disabled and hovered.
|
||||||
@ -1931,6 +1925,67 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Slider is draggable and has correct dragged color', (WidgetTester tester) async {
|
||||||
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
|
double value = 0.5;
|
||||||
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
|
final Key sliderKey = UniqueKey();
|
||||||
|
|
||||||
|
Widget buildApp({bool enabled = true}) {
|
||||||
|
return MaterialApp(
|
||||||
|
theme: theme,
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return Slider(
|
||||||
|
value: value,
|
||||||
|
key: sliderKey,
|
||||||
|
onChanged: enabled
|
||||||
|
? (double newValue) {
|
||||||
|
setState(() {
|
||||||
|
value = newValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await tester.pumpWidget(buildApp());
|
||||||
|
|
||||||
|
// Slider does not have overlay when enabled and not dragged.
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start dragging.
|
||||||
|
final TestGesture drag = await tester.startGesture(tester.getCenter(find.byKey(sliderKey)));
|
||||||
|
await tester.pump(kPressTimeout);
|
||||||
|
|
||||||
|
// Less than configured touch slop, more than default touch slop
|
||||||
|
await drag.moveBy(const Offset(19.0, 0));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Slider has overlay when enabled and dragged.
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||||
|
);
|
||||||
|
|
||||||
|
await drag.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Slider still has overlay when stopped dragging.
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Slider has correct dragged color from overlayColor property', (WidgetTester tester) async {
|
testWidgets('Slider has correct dragged color from overlayColor property', (WidgetTester tester) async {
|
||||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
double value = 0.5;
|
double value = 0.5;
|
||||||
@ -3381,4 +3436,171 @@ void main() {
|
|||||||
isNot(paints..path(color: const Color(0xff000000))..paragraph()),
|
isNot(paints..path(color: const Color(0xff000000))..paragraph()),
|
||||||
);
|
);
|
||||||
}, variant: TargetPlatformVariant.desktop());
|
}, variant: TargetPlatformVariant.desktop());
|
||||||
|
|
||||||
|
group('Material 2', () {
|
||||||
|
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
|
||||||
|
// is turned on by default, these tests can be removed.
|
||||||
|
|
||||||
|
testWidgets('Slider can be hovered and has correct hover color', (WidgetTester tester) async {
|
||||||
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
|
final ThemeData theme = ThemeData();
|
||||||
|
double value = 0.5;
|
||||||
|
Widget buildApp({bool enabled = true}) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return Slider(
|
||||||
|
value: value,
|
||||||
|
onChanged: enabled
|
||||||
|
? (double newValue) {
|
||||||
|
setState(() {
|
||||||
|
value = newValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await tester.pumpWidget(buildApp());
|
||||||
|
|
||||||
|
// Slider does not have overlay when enabled and not hovered.
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start hovering.
|
||||||
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||||
|
await gesture.addPointer();
|
||||||
|
await gesture.moveTo(tester.getCenter(find.byType(Slider)));
|
||||||
|
|
||||||
|
// Slider has overlay when enabled and hovered.
|
||||||
|
await tester.pumpWidget(buildApp());
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Slider does not have an overlay when disabled and hovered.
|
||||||
|
await tester.pumpWidget(buildApp(enabled: false));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Slider is focusable and has correct focus color', (WidgetTester tester) async {
|
||||||
|
final FocusNode focusNode = FocusNode(debugLabel: 'Slider');
|
||||||
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
|
final ThemeData theme = ThemeData();
|
||||||
|
double value = 0.5;
|
||||||
|
Widget buildApp({bool enabled = true}) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return Slider(
|
||||||
|
value: value,
|
||||||
|
onChanged: enabled
|
||||||
|
? (double newValue) {
|
||||||
|
setState(() {
|
||||||
|
value = newValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
autofocus: true,
|
||||||
|
focusNode: focusNode,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await tester.pumpWidget(buildApp());
|
||||||
|
|
||||||
|
// Check that the overlay shows when focused.
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check that the overlay does not show when unfocused and disabled.
|
||||||
|
await tester.pumpWidget(buildApp(enabled: false));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(focusNode.hasPrimaryFocus, isFalse);
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Slider is draggable and has correct dragged color', (WidgetTester tester) async {
|
||||||
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
|
double value = 0.5;
|
||||||
|
final ThemeData theme = ThemeData();
|
||||||
|
final Key sliderKey = UniqueKey();
|
||||||
|
|
||||||
|
Widget buildApp({bool enabled = true}) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return Slider(
|
||||||
|
value: value,
|
||||||
|
key: sliderKey,
|
||||||
|
onChanged: enabled
|
||||||
|
? (double newValue) {
|
||||||
|
setState(() {
|
||||||
|
value = newValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await tester.pumpWidget(buildApp());
|
||||||
|
|
||||||
|
// Slider does not have overlay when enabled and not dragged.
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start dragging.
|
||||||
|
final TestGesture drag = await tester.startGesture(tester.getCenter(find.byKey(sliderKey)));
|
||||||
|
await tester.pump(kPressTimeout);
|
||||||
|
|
||||||
|
// Less than configured touch slop, more than default touch slop
|
||||||
|
await drag.moveBy(const Offset(19.0, 0));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Slider has overlay when enabled and dragged.
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||||
|
);
|
||||||
|
|
||||||
|
await drag.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Slider still has overlay when stopped dragging.
|
||||||
|
expect(
|
||||||
|
Material.of(tester.element(find.byType(Slider))),
|
||||||
|
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,137 @@ void main() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Slider defaults', (WidgetTester tester) async {
|
||||||
|
debugDisableShadows = false;
|
||||||
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
|
final ColorScheme colorScheme = theme.colorScheme;
|
||||||
|
const double trackHeight = 4.0;
|
||||||
|
final Color activeTrackColor = Color(colorScheme.primary.value);
|
||||||
|
final Color inactiveTrackColor = colorScheme.surfaceVariant;
|
||||||
|
final Color secondaryActiveTrackColor = colorScheme.primary.withOpacity(0.54);
|
||||||
|
final Color disabledActiveTrackColor = colorScheme.onSurface.withOpacity(0.38);
|
||||||
|
final Color disabledInactiveTrackColor = colorScheme.onSurface.withOpacity(0.12);
|
||||||
|
final Color disabledSecondaryActiveTrackColor = colorScheme.onSurface.withOpacity(0.12);
|
||||||
|
final Color shadowColor = colorScheme.shadow;
|
||||||
|
final Color thumbColor = Color(colorScheme.primary.value);
|
||||||
|
final Color disabledThumbColor = Color.alphaBlend(colorScheme.onSurface.withOpacity(0.38), colorScheme.surface);
|
||||||
|
final Color activeTickMarkColor = colorScheme.onPrimary.withOpacity(0.38);
|
||||||
|
final Color inactiveTickMarkColor = colorScheme.onSurfaceVariant.withOpacity(0.38);
|
||||||
|
final Color disabledActiveTickMarkColor = colorScheme.onSurface.withOpacity(0.38);
|
||||||
|
final Color disabledInactiveTickMarkColor = colorScheme.onSurface.withOpacity(0.38);
|
||||||
|
|
||||||
|
try {
|
||||||
|
double value = 0.45;
|
||||||
|
Widget buildApp({
|
||||||
|
int? divisions,
|
||||||
|
bool enabled = true,
|
||||||
|
}) {
|
||||||
|
final ValueChanged<double>? onChanged = !enabled
|
||||||
|
? null
|
||||||
|
: (double d) {
|
||||||
|
value = d;
|
||||||
|
};
|
||||||
|
return MaterialApp(
|
||||||
|
home: Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Material(
|
||||||
|
child: Center(
|
||||||
|
child: Theme(
|
||||||
|
data: theme,
|
||||||
|
child: Slider(
|
||||||
|
value: value,
|
||||||
|
secondaryTrackValue: 0.75,
|
||||||
|
label: '$value',
|
||||||
|
divisions: divisions,
|
||||||
|
onChanged: onChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildApp());
|
||||||
|
|
||||||
|
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||||
|
|
||||||
|
// Test default track height.
|
||||||
|
const Radius radius = Radius.circular(trackHeight / 2);
|
||||||
|
const Radius activatedRadius = Radius.circular((trackHeight + 2) / 2);
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 362.4, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: activeTrackColor)
|
||||||
|
..rrect(rrect: RRect.fromLTRBAndCorners(362.4, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: inactiveTrackColor),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test default colors for enabled slider.
|
||||||
|
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||||
|
expect(material, paints..shadow(color: shadowColor));
|
||||||
|
expect(material, paints..circle(color: thumbColor));
|
||||||
|
expect(material, isNot(paints..circle(color: disabledThumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledActiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledInactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledSecondaryActiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..circle(color: activeTickMarkColor)));
|
||||||
|
expect(material, isNot(paints..circle(color: inactiveTickMarkColor)));
|
||||||
|
|
||||||
|
// Test defaults colors for discrete slider.
|
||||||
|
await tester.pumpWidget(buildApp(divisions: 3));
|
||||||
|
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..circle(color: activeTickMarkColor)
|
||||||
|
..circle(color: activeTickMarkColor)
|
||||||
|
..circle(color: inactiveTickMarkColor)
|
||||||
|
..circle(color: inactiveTickMarkColor)
|
||||||
|
..shadow(color: Colors.black)
|
||||||
|
..circle(color: thumbColor),
|
||||||
|
);
|
||||||
|
expect(material, isNot(paints..circle(color: disabledThumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledActiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledInactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledSecondaryActiveTrackColor)));
|
||||||
|
|
||||||
|
// Test defaults colors for disabled slider.
|
||||||
|
await tester.pumpWidget(buildApp(enabled: false));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..rrect(color: disabledActiveTrackColor)
|
||||||
|
..rrect(color: disabledInactiveTrackColor)
|
||||||
|
..rrect(color: disabledSecondaryActiveTrackColor),
|
||||||
|
);
|
||||||
|
expect(material, paints..shadow(color: shadowColor)..circle(color: disabledThumbColor));
|
||||||
|
expect(material, isNot(paints..circle(color: thumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: activeTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: inactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: secondaryActiveTrackColor)));
|
||||||
|
|
||||||
|
// Test defaults colors for disabled discrete slider.
|
||||||
|
await tester.pumpWidget(buildApp(divisions: 3, enabled: false));
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..circle(color: disabledActiveTickMarkColor)
|
||||||
|
..circle(color: disabledActiveTickMarkColor)
|
||||||
|
..circle(color: disabledInactiveTickMarkColor)
|
||||||
|
..circle(color: disabledInactiveTickMarkColor)
|
||||||
|
..shadow(color: shadowColor)
|
||||||
|
..circle(color: disabledThumbColor),
|
||||||
|
);
|
||||||
|
expect(material, isNot(paints..circle(color: thumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: activeTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: inactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: secondaryActiveTrackColor)));
|
||||||
|
} finally {
|
||||||
|
debugDisableShadows = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Slider uses the right theme colors for the right components', (WidgetTester tester) async {
|
testWidgets('Slider uses the right theme colors for the right components', (WidgetTester tester) async {
|
||||||
debugDisableShadows = false;
|
debugDisableShadows = false;
|
||||||
try {
|
try {
|
||||||
@ -279,6 +410,25 @@ void main() {
|
|||||||
expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor)));
|
expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor)));
|
||||||
expect(material, isNot(paints..rrect(color: sliderTheme.secondaryActiveTrackColor)));
|
expect(material, isNot(paints..rrect(color: sliderTheme.secondaryActiveTrackColor)));
|
||||||
|
|
||||||
|
// Test default theme for disabled discrete widget.
|
||||||
|
await tester.pumpWidget(buildApp(divisions: 3, enabled: false));
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..circle(color: sliderTheme.disabledActiveTickMarkColor)
|
||||||
|
..circle(color: sliderTheme.disabledActiveTickMarkColor)
|
||||||
|
..circle(color: sliderTheme.disabledInactiveTickMarkColor)
|
||||||
|
..circle(color: sliderTheme.disabledInactiveTickMarkColor)
|
||||||
|
..shadow(color: Colors.black)
|
||||||
|
..circle(color: sliderTheme.disabledThumbColor),
|
||||||
|
);
|
||||||
|
expect(material, isNot(paints..circle(color: sliderTheme.thumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: sliderTheme.secondaryActiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor)));
|
||||||
|
expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor)));
|
||||||
|
|
||||||
// Test setting the activeColor, inactiveColor and secondaryActiveColor for disabled widget.
|
// Test setting the activeColor, inactiveColor and secondaryActiveColor for disabled widget.
|
||||||
await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, secondaryActiveColor: customColor3, enabled: false));
|
await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, secondaryActiveColor: customColor3, enabled: false));
|
||||||
expect(
|
expect(
|
||||||
@ -343,6 +493,60 @@ void main() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Slider parameters overrides theme properties', (WidgetTester tester) async {
|
||||||
|
debugDisableShadows = false;
|
||||||
|
const Color activeTrackColor = Color(0xffff0001);
|
||||||
|
const Color inactiveTrackColor = Color(0xffff0002);
|
||||||
|
const Color secondaryActiveTrackColor = Color(0xffff0003);
|
||||||
|
const Color thumbColor = Color(0xffff0004);
|
||||||
|
|
||||||
|
final ThemeData theme = ThemeData(
|
||||||
|
platform: TargetPlatform.android,
|
||||||
|
primarySwatch: Colors.blue,
|
||||||
|
sliderTheme: const SliderThemeData(
|
||||||
|
activeTrackColor: Color(0xff000001),
|
||||||
|
inactiveTickMarkColor: Color(0xff000002),
|
||||||
|
secondaryActiveTrackColor: Color(0xff000003),
|
||||||
|
thumbColor: Color(0xff000004),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const double value = 0.45;
|
||||||
|
Widget buildApp({ bool enabled = true }) {
|
||||||
|
return MaterialApp(
|
||||||
|
theme: theme,
|
||||||
|
home: Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Material(
|
||||||
|
child: Center(
|
||||||
|
child: Slider(
|
||||||
|
activeColor: activeTrackColor,
|
||||||
|
inactiveColor: inactiveTrackColor,
|
||||||
|
secondaryActiveColor: secondaryActiveTrackColor,
|
||||||
|
thumbColor: thumbColor,
|
||||||
|
value: value,
|
||||||
|
secondaryTrackValue: 0.75,
|
||||||
|
label: '$value',
|
||||||
|
onChanged: (double value) { },
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildApp());
|
||||||
|
|
||||||
|
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||||
|
|
||||||
|
// Test Slider parameters.
|
||||||
|
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||||
|
expect(material, paints..circle(color: thumbColor));
|
||||||
|
} finally {
|
||||||
|
debugDisableShadows = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async {
|
testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(
|
final ThemeData theme = ThemeData(
|
||||||
platform: TargetPlatform.android,
|
platform: TargetPlatform.android,
|
||||||
@ -1652,6 +1856,161 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
group('Material 2', () {
|
||||||
|
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
|
||||||
|
// is turned on by default, these tests can be removed.
|
||||||
|
|
||||||
|
testWidgets('Slider defaults', (WidgetTester tester) async {
|
||||||
|
debugDisableShadows = false;
|
||||||
|
final ThemeData theme = ThemeData();
|
||||||
|
const double trackHeight = 4.0;
|
||||||
|
final ColorScheme colorScheme = theme.colorScheme;
|
||||||
|
final Color activeTrackColor = Color(colorScheme.primary.value);
|
||||||
|
final Color inactiveTrackColor = colorScheme.primary.withOpacity(0.24);
|
||||||
|
final Color secondaryActiveTrackColor = colorScheme.primary.withOpacity(0.54);
|
||||||
|
final Color disabledActiveTrackColor = colorScheme.onSurface.withOpacity(0.32);
|
||||||
|
final Color disabledInactiveTrackColor = colorScheme.onSurface.withOpacity(0.12);
|
||||||
|
final Color disabledSecondaryActiveTrackColor = colorScheme.onSurface.withOpacity(0.12);
|
||||||
|
final Color shadowColor = colorScheme.shadow;
|
||||||
|
final Color thumbColor = Color(colorScheme.primary.value);
|
||||||
|
final Color disabledThumbColor = Color.alphaBlend(colorScheme.onSurface.withOpacity(.38), colorScheme.surface);
|
||||||
|
final Color activeTickMarkColor = colorScheme.onPrimary.withOpacity(0.54);
|
||||||
|
final Color inactiveTickMarkColor = colorScheme.primary.withOpacity(0.54);
|
||||||
|
final Color disabledActiveTickMarkColor = colorScheme.onPrimary.withOpacity(0.12);
|
||||||
|
final Color disabledInactiveTickMarkColor = colorScheme.onSurface.withOpacity(0.12);
|
||||||
|
final Color valueIndicatorColor = Color.alphaBlend(colorScheme.onSurface.withOpacity(0.60), colorScheme.surface.withOpacity(0.90));
|
||||||
|
|
||||||
|
try {
|
||||||
|
double value = 0.45;
|
||||||
|
Widget buildApp({
|
||||||
|
int? divisions,
|
||||||
|
bool enabled = true,
|
||||||
|
}) {
|
||||||
|
final ValueChanged<double>? onChanged = !enabled
|
||||||
|
? null
|
||||||
|
: (double d) {
|
||||||
|
value = d;
|
||||||
|
};
|
||||||
|
return MaterialApp(
|
||||||
|
home: Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Material(
|
||||||
|
child: Center(
|
||||||
|
child: Slider(
|
||||||
|
value: value,
|
||||||
|
secondaryTrackValue: 0.75,
|
||||||
|
label: '$value',
|
||||||
|
divisions: divisions,
|
||||||
|
onChanged: onChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildApp());
|
||||||
|
|
||||||
|
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||||
|
final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay));
|
||||||
|
|
||||||
|
// Test default track height.
|
||||||
|
const Radius radius = Radius.circular(trackHeight / 2);
|
||||||
|
const Radius activatedRadius = Radius.circular((trackHeight + 2) / 2);
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 362.4, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: activeTrackColor)
|
||||||
|
..rrect(rrect: RRect.fromLTRBAndCorners(362.4, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: inactiveTrackColor),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test default colors for enabled slider.
|
||||||
|
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||||
|
expect(material, paints..shadow(color: shadowColor));
|
||||||
|
expect(material, paints..circle(color: thumbColor));
|
||||||
|
expect(material, isNot(paints..circle(color: disabledThumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledActiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledInactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledSecondaryActiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..circle(color: activeTickMarkColor)));
|
||||||
|
expect(material, isNot(paints..circle(color: inactiveTickMarkColor)));
|
||||||
|
|
||||||
|
// Test defaults colors for discrete slider.
|
||||||
|
await tester.pumpWidget(buildApp(divisions: 3));
|
||||||
|
expect(material, paints..rrect(color: activeTrackColor)..rrect(color: inactiveTrackColor)..rrect(color: secondaryActiveTrackColor));
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..circle(color: activeTickMarkColor)
|
||||||
|
..circle(color: activeTickMarkColor)
|
||||||
|
..circle(color: inactiveTickMarkColor)
|
||||||
|
..circle(color: inactiveTickMarkColor)
|
||||||
|
..shadow(color: Colors.black)
|
||||||
|
..circle(color: thumbColor),
|
||||||
|
);
|
||||||
|
expect(material, isNot(paints..circle(color: disabledThumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledActiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledInactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: disabledSecondaryActiveTrackColor)));
|
||||||
|
|
||||||
|
// Test defaults colors for disabled slider.
|
||||||
|
await tester.pumpWidget(buildApp(enabled: false));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..rrect(color: disabledActiveTrackColor)
|
||||||
|
..rrect(color: disabledInactiveTrackColor)
|
||||||
|
..rrect(color: disabledSecondaryActiveTrackColor),
|
||||||
|
);
|
||||||
|
expect(material, paints..shadow(color: Colors.black)..circle(color: disabledThumbColor));
|
||||||
|
expect(material, isNot(paints..circle(color: thumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: activeTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: inactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: secondaryActiveTrackColor)));
|
||||||
|
|
||||||
|
// Test defaults colors for disabled discrete slider.
|
||||||
|
await tester.pumpWidget(buildApp(divisions: 3, enabled: false));
|
||||||
|
expect(
|
||||||
|
material,
|
||||||
|
paints
|
||||||
|
..circle(color: disabledActiveTickMarkColor)
|
||||||
|
..circle(color: disabledActiveTickMarkColor)
|
||||||
|
..circle(color: disabledInactiveTickMarkColor)
|
||||||
|
..circle(color: disabledInactiveTickMarkColor)
|
||||||
|
..shadow(color: Colors.black)
|
||||||
|
..circle(color: disabledThumbColor),
|
||||||
|
);
|
||||||
|
expect(material, isNot(paints..circle(color: thumbColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: activeTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: inactiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..rrect(color: secondaryActiveTrackColor)));
|
||||||
|
expect(material, isNot(paints..circle(color: activeTickMarkColor)));
|
||||||
|
expect(material, isNot(paints..circle(color: inactiveTickMarkColor)));
|
||||||
|
|
||||||
|
// Test the default color for value indicator.
|
||||||
|
await tester.pumpWidget(buildApp(divisions: 3));
|
||||||
|
final Offset center = tester.getCenter(find.byType(Slider));
|
||||||
|
final TestGesture gesture = await tester.startGesture(center);
|
||||||
|
// Wait for value indicator animation to finish.
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(value, equals(2.0 / 3.0));
|
||||||
|
expect(
|
||||||
|
valueIndicatorBox,
|
||||||
|
paints
|
||||||
|
..path(color: valueIndicatorColor)
|
||||||
|
..paragraph(),
|
||||||
|
);
|
||||||
|
await gesture.up();
|
||||||
|
// Wait for value indicator animation to finish.
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
} finally {
|
||||||
|
debugDisableShadows = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight extends RoundedRectSliderTrackShape {
|
class RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight extends RoundedRectSliderTrackShape {
|
||||||
@ -1681,6 +2040,7 @@ Widget _buildApp(
|
|||||||
double? secondaryTrackValue,
|
double? secondaryTrackValue,
|
||||||
bool enabled = true,
|
bool enabled = true,
|
||||||
int? divisions,
|
int? divisions,
|
||||||
|
FocusNode? focusNode,
|
||||||
}) {
|
}) {
|
||||||
final ValueChanged<double>? onChanged = enabled ? (double d) => value = d : null;
|
final ValueChanged<double>? onChanged = enabled ? (double d) => value = d : null;
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
@ -1694,6 +2054,7 @@ Widget _buildApp(
|
|||||||
label: '$value',
|
label: '$value',
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
divisions: divisions,
|
divisions: divisions,
|
||||||
|
focusNode: focusNode,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user