text_field_splash_test.dart 5.89 KB
Newer Older
1 2 3 4
// 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.

5
import 'package:flutter/gestures.dart' show kPressTimeout;
6 7 8 9 10 11 12 13 14 15 16 17 18
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';

int confirmCount = 0;
int cancelCount = 0;

class TestInkSplash extends InkSplash {
  TestInkSplash({
    MaterialInkController controller,
    RenderBox referenceBox,
    Offset position,
    Color color,
19
    bool containedInkWell = false,
20 21
    RectCallback rectCallback,
    BorderRadius borderRadius,
22
    ShapeBorder customBorder,
23 24
    double radius,
    VoidCallback onRemoved,
25
    TextDirection textDirection,
26 27 28 29 30 31 32 33
  }) : super(
    controller: controller,
    referenceBox: referenceBox,
    position: position,
    color: color,
    containedInkWell: containedInkWell,
    rectCallback: rectCallback,
    borderRadius: borderRadius,
34
    customBorder: customBorder,
35 36
    radius: radius,
    onRemoved: onRemoved,
37
    textDirection: textDirection,
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
  );

  @override
  void confirm() {
    confirmCount += 1;
    super.confirm();
  }

  @override
  void cancel() {
    cancelCount += 1;
    super.cancel();
  }
}

class TestInkSplashFactory extends InteractiveInkFeatureFactory {
  const TestInkSplashFactory();

  @override
  InteractiveInkFeature create({
    MaterialInkController controller,
    RenderBox referenceBox,
    Offset position,
    Color color,
62
    bool containedInkWell = false,
63 64
    RectCallback rectCallback,
    BorderRadius borderRadius,
65
    ShapeBorder customBorder,
66 67
    double radius,
    VoidCallback onRemoved,
68
    TextDirection textDirection,
69
  }) {
70
    return TestInkSplash(
71 72 73 74 75 76 77
      controller: controller,
      referenceBox: referenceBox,
      position: position,
      color: color,
      containedInkWell: containedInkWell,
      rectCallback: rectCallback,
      borderRadius: borderRadius,
78
      customBorder: customBorder,
79 80
      radius: radius,
      onRemoved: onRemoved,
81
      textDirection: textDirection,
82 83 84 85 86 87
    );
  }
}

void main() {
  testWidgets('Tap and no focus causes a splash', (WidgetTester tester) async {
88 89
    final Key textField1 = UniqueKey();
    final Key textField2 = UniqueKey();
90 91

    await tester.pumpWidget(
92 93 94 95 96
      MaterialApp(
        home: Theme(
          data: ThemeData.light().copyWith(splashFactory: const TestInkSplashFactory()),
          child: Material(
            child: Container(
97
              alignment: Alignment.topLeft,
98
              child: Column(
99
                children: <Widget>[
100
                  TextField(
101 102 103 104 105
                    key: textField1,
                    decoration: const InputDecoration(
                      labelText: 'label',
                    ),
                  ),
106
                  TextField(
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
                    key: textField2,
                    decoration: const InputDecoration(
                      labelText: 'label',
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      )
    );

    confirmCount = 0;
    cancelCount = 0;

    await tester.tap(find.byKey(textField1));
124
    await tester.pumpAndSettle();
125 126 127 128 129
    expect(confirmCount, 1);
    expect(cancelCount, 0);

    // textField1 already has the focus, no new splash
    await tester.tap(find.byKey(textField1));
130
    await tester.pumpAndSettle();
131 132 133 134 135
    expect(confirmCount, 1);
    expect(cancelCount, 0);

    // textField2 gets the focus and a splash
    await tester.tap(find.byKey(textField2));
136
    await tester.pumpAndSettle();
137 138 139 140 141
    expect(confirmCount, 2);
    expect(cancelCount, 0);

    // Tap outside of textField1's editable. It still gets focus and splash.
    await tester.tapAt(tester.getTopLeft(find.byKey(textField1)));
142
    await tester.pumpAndSettle();
143 144 145 146 147 148
    expect(confirmCount, 3);
    expect(cancelCount, 0);

    // Tap in the center of textField2's editable. It still gets the focus
    // and the splash. There is no splash cancel.
    await tester.tap(find.byKey(textField2));
149
    await tester.pumpAndSettle();
150 151 152 153 154 155
    expect(confirmCount, 4);
    expect(cancelCount, 0);
  });

  testWidgets('Splash cancel', (WidgetTester tester) async {
    await tester.pumpWidget(
156 157 158 159 160
      MaterialApp(
        home: Theme(
          data: ThemeData.light().copyWith(splashFactory: const TestInkSplashFactory()),
          child: Material(
            child: ListView(
161 162
              children: <Widget>[
                const TextField(
163
                  decoration: InputDecoration(
164 165 166 167
                    labelText: 'label1',
                  ),
                ),
                const TextField(
168
                  decoration: InputDecoration(
169 170 171
                    labelText: 'label2',
                  ),
                ),
172
                Container(
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
                  height: 1000.0,
                  color: const Color(0xFF00FF00),
                ),
              ],
            ),
          ),
        ),
      )
    );

    confirmCount = 0;
    cancelCount = 0;

    // Pointer is dragged below the textfield, splash is canceled.
    final TestGesture gesture1 = await tester.startGesture(tester.getCenter(find.text('label1')));
188 189

    // Splashes start on tapDown.
Josh Soref's avatar
Josh Soref committed
190 191
    // If the timeout is less than kPressTimeout the recognizer will just trigger
    // the onTapCancel callback. If the timeout is greater or equal to kPressTimeout
192 193 194
    // and less than kLongPressTimeout then onTapDown, onCancel will be called.
    await tester.pump(kPressTimeout);

195 196 197 198 199 200 201
    await gesture1.moveTo(const Offset(400.0, 300.0));
    await gesture1.up();
    expect(confirmCount, 0);
    expect(cancelCount, 1);

    // Pointer is dragged upwards causing a scroll, splash is canceled.
    final TestGesture gesture2 = await tester.startGesture(tester.getCenter(find.text('label2')));
202 203
    await tester.pump(kPressTimeout);
    await gesture2.moveBy(const Offset(0.0, -200.0));
204 205 206 207 208
    await gesture2.up();
    expect(confirmCount, 0);
    expect(cancelCount, 2);
  });
}