blob: fcabcb13f2f0df317b18a155c0c42c752abfd82a [file] [log] [blame]
// Copyright 2017 The Chromium 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 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('layout', () {
testWidgets('selected item is in the middle', (WidgetTester tester) async {
final FixedExtentScrollController controller =
FixedExtentScrollController(initialItem: 1);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 300.0,
width: 300.0,
child: CupertinoPicker(
scrollController: controller,
itemExtent: 50.0,
onSelectedItemChanged: (_) { },
children: List<Widget>.generate(3, (int index) {
return Container(
height: 50.0,
width: 300.0,
child: Text(index.toString()),
);
}),
),
),
),
),
);
expect(
tester.getTopLeft(find.widgetWithText(Container, '1')),
const Offset(0.0, 125.0),
);
controller.jumpToItem(0);
await tester.pump();
expect(
tester.getTopLeft(find.widgetWithText(Container, '1')),
const Offset(0.0, 175.0),
);
expect(
tester.getTopLeft(find.widgetWithText(Container, '0')),
const Offset(0.0, 125.0),
);
});
});
group('gradient', () {
testWidgets('gradient displays correctly with background color', (WidgetTester tester) async {
const Color backgroundColor = Color.fromRGBO(255, 0, 0, 1.0);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 300.0,
width: 300.0,
child: CupertinoPicker(
backgroundColor: backgroundColor,
itemExtent: 15.0,
children: const <Widget>[
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
],
onSelectedItemChanged: (int i) { },
),
),
),
),
);
final Container container = tester.firstWidget(find.byType(Container));
final BoxDecoration boxDecoration = container.decoration;
expect(boxDecoration.gradient.colors, <Color>[
backgroundColor,
backgroundColor.withAlpha(0xF2),
backgroundColor.withAlpha(0xDD),
backgroundColor.withAlpha(0x00),
backgroundColor.withAlpha(0x00),
backgroundColor.withAlpha(0xDD),
backgroundColor.withAlpha(0xF2),
backgroundColor,
]);
});
testWidgets('No gradient displays with transparent background color', (WidgetTester tester) async {
const Color backgroundColor = Color.fromRGBO(255, 0, 0, 0.5);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 300.0,
width: 300.0,
child: CupertinoPicker(
backgroundColor: backgroundColor,
itemExtent: 15.0,
children: const <Widget>[
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
],
onSelectedItemChanged: (int i) { },
),
),
),
),
);
final DecoratedBox decoratedBox = tester.firstWidget(find.byType(DecoratedBox));
final BoxDecoration boxDecoration = decoratedBox.decoration;
expect(boxDecoration.gradient, isNull);
expect(boxDecoration.color, isNotNull);
});
testWidgets('gradient displays correctly with null background color', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 300.0,
width: 300.0,
child: CupertinoPicker(
backgroundColor: null,
itemExtent: 15.0,
children: const <Widget>[
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
Text('1'),
],
onSelectedItemChanged: (int i) { },
),
),
),
),
);
// If the background color is null, the gradient color should be white.
const Color backgroundColor = Color(0xFFFFFFFF);
final Container container = tester.firstWidget(find.byType(Container));
final BoxDecoration boxDecoration = container.decoration;
expect(boxDecoration.gradient.colors, <Color>[
backgroundColor,
backgroundColor.withAlpha(0xF2),
backgroundColor.withAlpha(0xDD),
backgroundColor.withAlpha(0x00),
backgroundColor.withAlpha(0x00),
backgroundColor.withAlpha(0xDD),
backgroundColor.withAlpha(0xF2),
backgroundColor,
]);
});
});
group('scroll', () {
testWidgets(
'scrolling calls onSelectedItemChanged and triggers haptic feedback',
(WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final List<int> selectedItems = <int>[];
final List<MethodCall> systemCalls = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
systemCalls.add(methodCall);
});
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: CupertinoPicker(
itemExtent: 100.0,
onSelectedItemChanged: (int index) { selectedItems.add(index); },
children: List<Widget>.generate(100, (int index) {
return Center(
child: Container(
width: 400.0,
height: 100.0,
child: Text(index.toString()),
),
);
}),
),
),
);
await tester.drag(find.text('0'), const Offset(0.0, -100.0));
expect(selectedItems, <int>[1]);
expect(
systemCalls.single,
isMethodCall(
'HapticFeedback.vibrate',
arguments: 'HapticFeedbackType.selectionClick',
),
);
await tester.drag(find.text('0'), const Offset(0.0, 100.0));
expect(selectedItems, <int>[1, 0]);
expect(systemCalls, hasLength(2));
expect(
systemCalls.last,
isMethodCall(
'HapticFeedback.vibrate',
arguments: 'HapticFeedbackType.selectionClick',
),
);
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets(
'do not trigger haptic effects on non-iOS devices',
(WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.android;
final List<int> selectedItems = <int>[];
final List<MethodCall> systemCalls = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
systemCalls.add(methodCall);
});
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: CupertinoPicker(
itemExtent: 100.0,
onSelectedItemChanged: (int index) { selectedItems.add(index); },
children: List<Widget>.generate(100, (int index) {
return Center(
child: Container(
width: 400.0,
height: 100.0,
child: Text(index.toString()),
),
);
}),
),
),
);
await tester.drag(find.text('0'), const Offset(0.0, -100.0));
expect(selectedItems, <int>[1]);
expect(systemCalls, isEmpty);
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets('a drag in between items settles back', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final FixedExtentScrollController controller =
FixedExtentScrollController(initialItem: 10);
final List<int> selectedItems = <int>[];
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: CupertinoPicker(
scrollController: controller,
itemExtent: 100.0,
onSelectedItemChanged: (int index) { selectedItems.add(index); },
children: List<Widget>.generate(100, (int index) {
return Center(
child: Container(
width: 400.0,
height: 100.0,
child: Text(index.toString()),
),
);
}),
),
),
);
// Drag it by a bit but not enough to move to the next item.
await tester.drag(find.text('10'), const Offset(0.0, 30.0), touchSlopY: 0.0);
// The item that was in the center now moved a bit.
expect(
tester.getTopLeft(find.widgetWithText(Container, '10')),
const Offset(200.0, 280.0),
);
await tester.pumpAndSettle();
expect(
tester.getTopLeft(find.widgetWithText(Container, '10')).dy,
moreOrLessEquals(250.0, epsilon: 0.5),
);
expect(selectedItems.isEmpty, true);
// Drag it by enough to move to the next item.
await tester.drag(find.text('10'), const Offset(0.0, 70.0), touchSlopY: 0.0);
await tester.pumpAndSettle();
expect(
tester.getTopLeft(find.widgetWithText(Container, '10')).dy,
// It's down by 100.0 now.
moreOrLessEquals(350.0, epsilon: 0.5),
);
expect(selectedItems, <int>[9]);
debugDefaultTargetPlatformOverride = null;
});
testWidgets('a big fling that overscrolls springs back', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final FixedExtentScrollController controller =
FixedExtentScrollController(initialItem: 10);
final List<int> selectedItems = <int>[];
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: CupertinoPicker(
scrollController: controller,
itemExtent: 100.0,
onSelectedItemChanged: (int index) { selectedItems.add(index); },
children: List<Widget>.generate(100, (int index) {
return Center(
child: Container(
width: 400.0,
height: 100.0,
child: Text(index.toString()),
),
);
}),
),
),
);
// A wild throw appears.
await tester.fling(
find.text('10'),
const Offset(0.0, 10000.0),
1000.0,
);
// Should have been flung far enough that even the first item goes off
// screen and gets removed.
expect(find.widgetWithText(Container, '0').evaluate().isEmpty, true);
expect(
selectedItems,
// This specific throw was fast enough that each scroll update landed
// on every second item.
<int>[8, 6, 4, 2, 0],
);
// Let it spring back.
await tester.pumpAndSettle();
expect(
tester.getTopLeft(find.widgetWithText(Container, '0')).dy,
// Should have sprung back to the middle now.
moreOrLessEquals(250.0),
);
expect(
selectedItems,
// Falling back to 0 shouldn't produce more callbacks.
<int>[8, 6, 4, 2, 0],
);
debugDefaultTargetPlatformOverride = null;
});
});
}