Unverified Commit 7fab7f6d authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Adding edge avoidance, painting tests, general cleanup (#15078)

Fixed the real repaint problem the Slider had (missing addListener), and added tests for it.

Added GlobalKey reparenting test.

Added the ability for the value indicator to slide left and right to avoid falling off the edge of the screen.
It only shifts as much as it can without deforming, but even at large text scales, that is enough to keep the text on the screen.

Updated the formatting on theme_data.dart and others to use longer line length.

Also, removed a color tween that faded the value indicator in as it scaled, since that wasn't to spec.
parent 3a40d0ee
...@@ -34,7 +34,10 @@ class IconThemeData extends Diagnosticable { ...@@ -34,7 +34,10 @@ class IconThemeData extends Diagnosticable {
/// the new values. /// the new values.
IconThemeData copyWith({Color color, double opacity, double size}) { IconThemeData copyWith({Color color, double opacity, double size}) {
return new IconThemeData( return new IconThemeData(
color: color ?? this.color, opacity: opacity ?? this.opacity, size: size ?? this.size); color: color ?? this.color,
opacity: opacity ?? this.opacity,
size: size ?? this.size,
);
} }
/// Returns a new icon theme that matches this icon theme but with some values /// Returns a new icon theme that matches this icon theme but with some values
...@@ -43,7 +46,11 @@ class IconThemeData extends Diagnosticable { ...@@ -43,7 +46,11 @@ class IconThemeData extends Diagnosticable {
IconThemeData merge(IconThemeData other) { IconThemeData merge(IconThemeData other) {
if (other == null) if (other == null)
return this; return this;
return copyWith(color: other.color, opacity: other.opacity, size: other.size); return copyWith(
color: other.color,
opacity: other.opacity,
size: other.size,
);
} }
/// Whether all the properties of this object are non-null. /// Whether all the properties of this object are non-null.
...@@ -97,11 +104,8 @@ class IconThemeData extends Diagnosticable { ...@@ -97,11 +104,8 @@ class IconThemeData extends Diagnosticable {
@override @override
void debugFillProperties(DiagnosticPropertiesBuilder description) { void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description); super.debugFillProperties(description);
if (color == null && _opacity == null && size == null) { description.add(new DiagnosticsProperty<Color>('color', color, defaultValue: null));
return; description.add(new DoubleProperty('opacity', opacity, defaultValue: null));
} description.add(new DoubleProperty('size', size, defaultValue: null));
description.add(new DiagnosticsProperty<Color>('color', color));
description.add(new DoubleProperty('opacity', _opacity));
description.add(new DoubleProperty('size', size));
} }
} }
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' show window;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
...@@ -31,14 +33,17 @@ void main() { ...@@ -31,14 +33,17 @@ void main() {
Widget buildSlider(SliderThemeData data) { Widget buildSlider(SliderThemeData data) {
return new Directionality( return new Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: new Material( child: new MediaQuery(
child: new Center( data: new MediaQueryData.fromWindow(window),
child: new Theme( child: new Material(
data: theme, child: new Center(
child: const Slider( child: new Theme(
value: 0.5, data: theme,
label: '0.5', child: const Slider(
onChanged: null, value: 0.5,
label: '0.5',
onChanged: null,
),
), ),
), ),
), ),
...@@ -50,15 +55,10 @@ void main() { ...@@ -50,15 +55,10 @@ void main() {
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider)); final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
expect( expect(sliderBox, paints..rect(color: sliderTheme.disabledActiveRailColor)..rect(color: sliderTheme.disabledInactiveRailColor));
sliderBox,
paints
..rect(color: sliderTheme.disabledActiveRailColor)
..rect(color: sliderTheme.disabledInactiveRailColor));
}); });
testWidgets('Slider overrides ThemeData theme if SliderTheme present', testWidgets('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async {
(WidgetTester tester) async {
final ThemeData theme = new ThemeData( final ThemeData theme = new ThemeData(
platform: TargetPlatform.android, platform: TargetPlatform.android,
primarySwatch: Colors.red, primarySwatch: Colors.red,
...@@ -72,16 +72,19 @@ void main() { ...@@ -72,16 +72,19 @@ void main() {
Widget buildSlider(SliderThemeData data) { Widget buildSlider(SliderThemeData data) {
return new Directionality( return new Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: new Material( child: new MediaQuery(
child: new Center( data: new MediaQueryData.fromWindow(window),
child: new Theme( child: new Material(
data: theme, child: new Center(
child: new SliderTheme( child: new Theme(
data: customTheme, data: theme,
child: const Slider( child: new SliderTheme(
value: 0.5, data: customTheme,
label: '0.5', child: const Slider(
onChanged: null, value: 0.5,
label: '0.5',
onChanged: null,
),
), ),
), ),
), ),
...@@ -94,20 +97,15 @@ void main() { ...@@ -94,20 +97,15 @@ void main() {
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider)); final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
expect( expect(sliderBox, paints..rect(color: customTheme.disabledActiveRailColor)..rect(color: customTheme.disabledInactiveRailColor));
sliderBox,
paints
..rect(color: customTheme.disabledActiveRailColor)
..rect(color: customTheme.disabledInactiveRailColor));
}); });
testWidgets('SliderThemeData generates correct opacities for materialDefaults', testWidgets('SliderThemeData generates correct opacities for materialDefaults', (WidgetTester tester) async {
(WidgetTester tester) async {
const Color customColor1 = const Color(0xcafefeed); const Color customColor1 = const Color(0xcafefeed);
const Color customColor2 = const Color(0xdeadbeef); const Color customColor2 = const Color(0xdeadbeef);
const Color customColor3 = const Color(0xdecaface); const Color customColor3 = const Color(0xdecaface);
final SliderThemeData sliderTheme = new SliderThemeData.materialDefaults( final SliderThemeData sliderTheme = new SliderThemeData.fromPrimaryColors(
primaryColor: customColor1, primaryColor: customColor1,
primaryColorDark: customColor2, primaryColorDark: customColor2,
primaryColorLight: customColor3, primaryColorLight: customColor3,
...@@ -126,18 +124,17 @@ void main() { ...@@ -126,18 +124,17 @@ void main() {
expect(sliderTheme.overlayColor, equals(customColor1.withAlpha(0x29))); expect(sliderTheme.overlayColor, equals(customColor1.withAlpha(0x29)));
expect(sliderTheme.valueIndicatorColor, equals(customColor1.withAlpha(0xff))); expect(sliderTheme.valueIndicatorColor, equals(customColor1.withAlpha(0xff)));
expect(sliderTheme.thumbShape, equals(const isInstanceOf<RoundSliderThumbShape>())); expect(sliderTheme.thumbShape, equals(const isInstanceOf<RoundSliderThumbShape>()));
expect(sliderTheme.valueIndicatorShape, expect(sliderTheme.valueIndicatorShape, equals(const isInstanceOf<PaddleSliderValueIndicatorShape>()));
equals(const isInstanceOf<PaddleSliderValueIndicatorShape>()));
expect(sliderTheme.showValueIndicator, equals(ShowValueIndicator.onlyForDiscrete)); expect(sliderTheme.showValueIndicator, equals(ShowValueIndicator.onlyForDiscrete));
}); });
testWidgets('SliderThemeData lerps correctly', (WidgetTester tester) async { testWidgets('SliderThemeData lerps correctly', (WidgetTester tester) async {
final SliderThemeData sliderThemeBlack = new SliderThemeData.materialDefaults( final SliderThemeData sliderThemeBlack = new SliderThemeData.fromPrimaryColors(
primaryColor: Colors.black, primaryColor: Colors.black,
primaryColorDark: Colors.black, primaryColorDark: Colors.black,
primaryColorLight: Colors.black, primaryColorLight: Colors.black,
); );
final SliderThemeData sliderThemeWhite = new SliderThemeData.materialDefaults( final SliderThemeData sliderThemeWhite = new SliderThemeData.fromPrimaryColors(
primaryColor: Colors.white, primaryColor: Colors.white,
primaryColorDark: Colors.white, primaryColorDark: Colors.white,
primaryColorLight: Colors.white, primaryColorLight: Colors.white,
...@@ -172,15 +169,18 @@ void main() { ...@@ -172,15 +169,18 @@ void main() {
final ValueChanged<double> onChanged = enabled ? (double d) => value = d : null; final ValueChanged<double> onChanged = enabled ? (double d) => value = d : null;
return new Directionality( return new Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: new Material( child: new MediaQuery(
child: new Center( data: new MediaQueryData.fromWindow(window),
child: new SliderTheme( child: new Material(
data: sliderTheme, child: new Center(
child: new Slider( child: new SliderTheme(
value: value, data: sliderTheme,
label: '$value', child: new Slider(
divisions: divisions, value: value,
onChanged: onChanged, label: '$value',
divisions: divisions,
onChanged: onChanged,
),
), ),
), ),
), ),
...@@ -225,21 +225,27 @@ void main() { ...@@ -225,21 +225,27 @@ void main() {
platform: TargetPlatform.android, platform: TargetPlatform.android,
primarySwatch: Colors.blue, primarySwatch: Colors.blue,
); );
final SliderThemeData sliderTheme = theme.sliderTheme final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500, showValueIndicator: ShowValueIndicator.always);
.copyWith(thumbColor: Colors.red.shade500, showValueIndicator: ShowValueIndicator.always); Widget buildApp(String value, {double sliderValue = 0.5}) {
Widget buildApp(String value) {
return new Directionality( return new Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: new Material( child: new MediaQuery(
child: new Center( data: new MediaQueryData.fromWindow(window),
child: new SliderTheme( child: new Material(
data: sliderTheme, child: new Row(
child: new Slider( children: <Widget>[
value: 0.5, new Expanded(
label: '$value', child: new SliderTheme(
divisions: 3, data: sliderTheme,
onChanged: (double d) {}, child: new Slider(
), value: sliderValue,
label: '$value',
divisions: 3,
onChanged: (double d) {},
),
),
),
],
), ),
), ),
), ),
...@@ -290,5 +296,47 @@ void main() { ...@@ -290,5 +296,47 @@ void main() {
excludes: <Offset>[const Offset(36.1, -40.0), const Offset(-36.1, -40.0)], excludes: <Offset>[const Offset(36.1, -40.0), const Offset(-36.1, -40.0)],
)); ));
await gesture.up(); await gesture.up();
// Test that it avoids the left edge of the screen.
await tester.pumpWidget(buildApp('1000000', sliderValue: 0.0));
center = tester.getCenter(find.byType(Slider));
gesture = await tester.startGesture(center);
await tester.pump();
// Wait for value indicator animation to finish.
await tester.pump(const Duration(milliseconds: 500));
expect(
sliderBox,
paints
..path(
color: sliderTheme.valueIndicatorColor,
includes: <Offset>[
const Offset(0.0, -40.0),
const Offset(98.0, -40.0),
const Offset(-16.0, -40.0),
],
excludes: <Offset>[const Offset(98.1, -40.0), const Offset(-16.1, -40.0)],
));
await gesture.up();
// Test that it avoids the right edge of the screen.
await tester.pumpWidget(buildApp('1000000', sliderValue: 1.0));
center = tester.getCenter(find.byType(Slider));
gesture = await tester.startGesture(center);
await tester.pump();
// Wait for value indicator animation to finish.
await tester.pump(const Duration(milliseconds: 500));
expect(
sliderBox,
paints
..path(
color: sliderTheme.valueIndicatorColor,
includes: <Offset>[
const Offset(0.0, -40.0),
const Offset(16.0, -40.0),
const Offset(-98.0, -40.0),
],
excludes: <Offset>[const Offset(16.1, -40.0), const Offset(-98.1, -40.0)],
));
await gesture.up();
}); });
} }
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' show window;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
...@@ -292,13 +294,16 @@ void main() { ...@@ -292,13 +294,16 @@ void main() {
child: new SemanticsDebugger( child: new SemanticsDebugger(
child: new Directionality( child: new Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: new Material( child: new MediaQuery(
child: new Center( data: new MediaQueryData.fromWindow(window),
child: new Slider( child: new Material(
value: value, child: new Center(
onChanged: (double newValue) { child: new Slider(
value = newValue; value: value,
}, onChanged: (double newValue) {
value = newValue;
},
),
), ),
), ),
), ),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment