commit
53575aa797
@ -42,5 +42,5 @@ void main() {
|
||||
child: new RenderPadding(child: table, padding: new EdgeDims.symmetric(vertical: 50.0))
|
||||
);
|
||||
|
||||
new FlutterBinding(root: root);
|
||||
new RenderingFlutterBinding(root: root);
|
||||
}
|
||||
|
@ -87,5 +87,5 @@ void main() {
|
||||
direction: FlexDirection.vertical,
|
||||
alignItems: FlexAlignItems.stretch
|
||||
);
|
||||
new FlutterBinding(root: root);
|
||||
new RenderingFlutterBinding(root: root);
|
||||
}
|
||||
|
@ -73,5 +73,5 @@ void main() {
|
||||
],
|
||||
direction: FlexDirection.vertical
|
||||
);
|
||||
new FlutterBinding(root: root);
|
||||
new RenderingFlutterBinding(root: root);
|
||||
}
|
||||
|
@ -53,5 +53,5 @@ RenderBox buildFlexExample() {
|
||||
}
|
||||
|
||||
void main() {
|
||||
new FlutterBinding(root: buildFlexExample());
|
||||
new RenderingFlutterBinding(root: buildFlexExample());
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import 'dart:ui' as ui;
|
||||
import 'dart:math' as math;
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:mojo/bindings.dart' as bindings;
|
||||
@ -37,13 +38,20 @@ class RenderImageGrow extends RenderImage {
|
||||
|
||||
RenderImageGrow image;
|
||||
|
||||
void handlePopRoute() {
|
||||
class DemoBinding extends BindingBase with Scheduler, Renderer {
|
||||
DemoBinding({ RenderBox root }) {
|
||||
renderView.child = root;
|
||||
ui.window.onPopRoute = handlePopRoute;
|
||||
ui.window.onPointerPacket = handlePointerPacket;
|
||||
}
|
||||
|
||||
void handlePopRoute() {
|
||||
activity.finishCurrentActivity();
|
||||
}
|
||||
}
|
||||
|
||||
final Map<int, Touch> touches = <int, Touch>{};
|
||||
final Map<int, Touch> touches = <int, Touch>{};
|
||||
|
||||
void handlePointerPacket(ByteData serializedPacket) {
|
||||
void handlePointerPacket(ByteData serializedPacket) {
|
||||
bindings.Message message = new bindings.Message(
|
||||
serializedPacket,
|
||||
<core.MojoHandle>[],
|
||||
@ -51,12 +59,12 @@ void handlePointerPacket(ByteData serializedPacket) {
|
||||
0
|
||||
);
|
||||
PointerPacket packet = PointerPacket.deserialize(message);
|
||||
|
||||
for (Pointer pointer in packet.pointers) {
|
||||
if (pointer.type == PointerType.MOVE)
|
||||
image.growth = math.max(0.0, image.growth + pointer.x - touches[pointer.pointer].x);
|
||||
touches[pointer.pointer] = new Touch(pointer.x, pointer.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
@ -74,7 +82,7 @@ void main() {
|
||||
|
||||
// Resizeable image
|
||||
image = new RenderImageGrow(null, new Size(100.0, null));
|
||||
imageCache.load("https://www.dartlang.org/logos/dart-logo.png").first.then((ui.Image dartLogo) {
|
||||
imageCache.load("http://flutter.io/favicon.ico").first.then((ui.Image dartLogo) {
|
||||
image.image = dartLogo;
|
||||
});
|
||||
|
||||
@ -114,7 +122,5 @@ Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
|
||||
);
|
||||
|
||||
updateTaskDescription('Interactive Flex', topColor);
|
||||
new FlutterBinding(root: root);
|
||||
ui.window.onPopRoute = handlePopRoute;
|
||||
ui.window.onPointerPacket = handlePointerPacket;
|
||||
new DemoBinding(root: root);
|
||||
}
|
||||
|
@ -37,5 +37,5 @@ void main() {
|
||||
child: new RenderPadding(child: table, padding: new EdgeDims.symmetric(vertical: 50.0))
|
||||
);
|
||||
|
||||
new FlutterBinding(root: root);
|
||||
new RenderingFlutterBinding(root: root);
|
||||
}
|
||||
|
@ -23,4 +23,4 @@ RenderBox buildGridExample() {
|
||||
return new RenderGrid(children: children, maxChildExtent: 100.0);
|
||||
}
|
||||
|
||||
main() => new FlutterBinding(root: buildGridExample());
|
||||
main() => new RenderingFlutterBinding(root: buildGridExample());
|
||||
|
@ -40,5 +40,5 @@ Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
|
||||
childParentData = child.parentData;
|
||||
childParentData.flex = 1;
|
||||
|
||||
new FlutterBinding(root: root);
|
||||
new RenderingFlutterBinding(root: root);
|
||||
}
|
||||
|
@ -18,5 +18,5 @@ RenderBox buildSectorExample() {
|
||||
}
|
||||
|
||||
void main() {
|
||||
new FlutterBinding(root: buildSectorExample());
|
||||
new RenderingFlutterBinding(root: buildSectorExample());
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ void main() {
|
||||
var paddedBox = new RenderPadding(
|
||||
padding: const EdgeDims.all(50.0),
|
||||
child: coloredBox);
|
||||
new FlutterBinding(root: new RenderDecoratedBox(
|
||||
new RenderingFlutterBinding(root: new RenderDecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
backgroundColor: const Color(0xFFFFFFFF)
|
||||
),
|
||||
|
@ -59,5 +59,5 @@ void main() {
|
||||
(p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint,
|
||||
]);
|
||||
|
||||
new FlutterBinding(root: root);
|
||||
new RenderingFlutterBinding(root: root);
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
import 'lib/solid_color_box.dart';
|
||||
|
||||
@ -30,9 +29,8 @@ void main() {
|
||||
|
||||
RenderPadding root = new RenderPadding(padding: new EdgeDims.all(20.0), child: transformBox);
|
||||
|
||||
new FlutterBinding(root: root);
|
||||
|
||||
scheduler.addPersistentFrameCallback(rotate);
|
||||
new RenderingFlutterBinding(root: root)
|
||||
..addPersistentFrameCallback(rotate);
|
||||
}
|
||||
|
||||
void rotate(Duration timeStamp) {
|
||||
|
@ -77,5 +77,5 @@ void main() {
|
||||
final StackParentData paragraphParentData = paragraph.parentData;
|
||||
paragraphParentData..top = 40.0
|
||||
..left = 20.0;
|
||||
new FlutterBinding(root: stack);
|
||||
new RenderingFlutterBinding(root: stack);
|
||||
}
|
||||
|
@ -24,5 +24,5 @@ void main() {
|
||||
|
||||
RenderFlex flex = new RenderFlex();
|
||||
flex.add(spin);
|
||||
new FlutterBinding(root: flex);
|
||||
new RenderingFlutterBinding(root: flex);
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
import 'package:flutter_rendering_examples/solid_color_box.dart';
|
||||
|
||||
@ -84,11 +83,6 @@ void rotate(Duration timeStamp) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Because we're going to use Widgets, we want to ensure we're using a
|
||||
// WidgetFlutterBinding rather than some other kind of binding (e.g. a
|
||||
// straight rendering library FlutterBinding).
|
||||
WidgetFlutterBinding.ensureInitialized();
|
||||
|
||||
RenderProxyBox proxy = new RenderProxyBox();
|
||||
attachWidgetTreeToRenderTree(proxy);
|
||||
|
||||
@ -100,6 +94,7 @@ void main() {
|
||||
transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity());
|
||||
RenderPadding root = new RenderPadding(padding: new EdgeDims.all(80.0), child: transformBox);
|
||||
|
||||
FlutterBinding.instance.renderView.child = root;
|
||||
scheduler.addPersistentFrameCallback(rotate);
|
||||
WidgetFlutterBinding.ensureInitialized()
|
||||
..renderView.child = root
|
||||
..addPersistentFrameCallback(rotate);
|
||||
}
|
||||
|
@ -6,9 +6,12 @@
|
||||
library gestures;
|
||||
|
||||
export 'src/gestures/arena.dart';
|
||||
export 'src/gestures/binding.dart';
|
||||
export 'src/gestures/constants.dart';
|
||||
export 'src/gestures/converter.dart';
|
||||
export 'src/gestures/drag.dart';
|
||||
export 'src/gestures/events.dart';
|
||||
export 'src/gestures/hit_test.dart';
|
||||
export 'src/gestures/long_press.dart';
|
||||
export 'src/gestures/lsq_solver.dart';
|
||||
export 'src/gestures/multitap.dart';
|
||||
|
@ -16,7 +16,6 @@ export 'src/rendering/editable_paragraph.dart';
|
||||
export 'src/rendering/error.dart';
|
||||
export 'src/rendering/flex.dart';
|
||||
export 'src/rendering/grid.dart';
|
||||
export 'src/rendering/hit_test.dart';
|
||||
export 'src/rendering/image.dart';
|
||||
export 'src/rendering/layer.dart';
|
||||
export 'src/rendering/node.dart';
|
||||
|
@ -13,6 +13,7 @@ library services;
|
||||
|
||||
export 'src/services/activity.dart';
|
||||
export 'src/services/asset_bundle.dart';
|
||||
export 'src/services/binding.dart';
|
||||
export 'src/services/fetch.dart';
|
||||
export 'src/services/image_cache.dart';
|
||||
export 'src/services/image_decoder.dart';
|
||||
|
@ -40,7 +40,7 @@ class Ticker {
|
||||
_startTime = null;
|
||||
|
||||
if (_animationId != null) {
|
||||
scheduler.cancelFrameCallbackWithId(_animationId);
|
||||
Scheduler.instance.cancelFrameCallbackWithId(_animationId);
|
||||
_animationId = null;
|
||||
}
|
||||
|
||||
@ -74,6 +74,6 @@ class Ticker {
|
||||
void _scheduleTick() {
|
||||
assert(isTicking);
|
||||
assert(_animationId == null);
|
||||
_animationId = scheduler.scheduleFrameCallback(_tick);
|
||||
_animationId = Scheduler.instance.scheduleFrameCallback(_tick);
|
||||
}
|
||||
}
|
||||
|
@ -64,8 +64,6 @@ class _GestureArenaState {
|
||||
class GestureArena {
|
||||
final Map<Object, _GestureArenaState> _arenas = new Map<Object, _GestureArenaState>();
|
||||
|
||||
static final GestureArena instance = new GestureArena();
|
||||
|
||||
GestureArenaEntry add(Object key, GestureArenaMember member) {
|
||||
_GestureArenaState state = _arenas.putIfAbsent(key, () => new _GestureArenaState());
|
||||
state.add(member);
|
||||
|
94
packages/flutter/lib/src/gestures/binding.dart
Normal file
94
packages/flutter/lib/src/gestures/binding.dart
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright 2015 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 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:mojo/bindings.dart' as mojo_bindings;
|
||||
import 'package:mojo/core.dart' as mojo_core;
|
||||
import 'package:sky_services/pointer/pointer.mojom.dart';
|
||||
|
||||
import 'arena.dart';
|
||||
import 'converter.dart';
|
||||
import 'events.dart';
|
||||
import 'hit_test.dart';
|
||||
import 'pointer_router.dart';
|
||||
|
||||
abstract class Pointerer extends BindingBase implements HitTestTarget, HitTestable {
|
||||
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
ui.window.onPointerPacket = _handlePointerPacket;
|
||||
}
|
||||
|
||||
static Pointerer _instance;
|
||||
static Pointerer get instance => _instance;
|
||||
|
||||
void _handlePointerPacket(ByteData serializedPacket) {
|
||||
final mojo_bindings.Message message = new mojo_bindings.Message(
|
||||
serializedPacket,
|
||||
<mojo_core.MojoHandle>[],
|
||||
serializedPacket.lengthInBytes,
|
||||
0
|
||||
);
|
||||
final PointerPacket packet = PointerPacket.deserialize(message);
|
||||
for (PointerEvent event in PointerEventConverter.expand(packet.pointers))
|
||||
_handlePointerEvent(event);
|
||||
}
|
||||
|
||||
/// A router that routes all pointer events received from the engine.
|
||||
final PointerRouter pointerRouter = new PointerRouter();
|
||||
|
||||
/// The gesture arenas used for disambiguating the meaning of sequences of
|
||||
/// pointer events.
|
||||
final GestureArena gestureArena = new GestureArena();
|
||||
|
||||
/// State for all pointers which are currently down.
|
||||
///
|
||||
/// The state of hovering pointers is not tracked because that would require
|
||||
/// hit-testing on every frame.
|
||||
Map<int, HitTestResult> _hitTests = <int, HitTestResult>{};
|
||||
|
||||
void _handlePointerEvent(PointerEvent event) {
|
||||
if (event is PointerDownEvent) {
|
||||
assert(!_hitTests.containsKey(event.pointer));
|
||||
HitTestResult result = new HitTestResult();
|
||||
hitTest(result, event.position);
|
||||
_hitTests[event.pointer] = result;
|
||||
} else if (event is! PointerUpEvent) {
|
||||
assert(event.down == _hitTests.containsKey(event.pointer));
|
||||
if (!event.down)
|
||||
return; // we currently ignore add, remove, and hover move events
|
||||
}
|
||||
assert(_hitTests[event.pointer] != null);
|
||||
dispatchEvent(event, _hitTests[event.pointer]);
|
||||
if (event is PointerUpEvent) {
|
||||
assert(_hitTests.containsKey(event.pointer));
|
||||
_hitTests.remove(event.pointer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine which [HitTestTarget] objects are located at a given position.
|
||||
void hitTest(HitTestResult result, Point position) {
|
||||
result.add(new HitTestEntry(this));
|
||||
}
|
||||
|
||||
/// Dispatch the given event to the path of the given hit test result
|
||||
void dispatchEvent(PointerEvent event, HitTestResult result) {
|
||||
assert(result != null);
|
||||
for (HitTestEntry entry in result.path)
|
||||
entry.target.handleEvent(event, entry);
|
||||
}
|
||||
|
||||
void handleEvent(PointerEvent event, HitTestEntry entry) {
|
||||
pointerRouter.route(event);
|
||||
if (event is PointerDownEvent) {
|
||||
gestureArena.close(event.pointer);
|
||||
} else if (event is PointerUpEvent) {
|
||||
gestureArena.sweep(event.pointer);
|
||||
}
|
||||
}
|
||||
}
|
183
packages/flutter/lib/src/gestures/converter.dart
Normal file
183
packages/flutter/lib/src/gestures/converter.dart
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright 2015 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:sky_services/pointer/pointer.mojom.dart';
|
||||
|
||||
import 'events.dart';
|
||||
|
||||
class _PointerState {
|
||||
_PointerState(this.lastPosition);
|
||||
|
||||
int get pointer => _pointer; // The identifier used in PointerEvent objects.
|
||||
int _pointer;
|
||||
static int _pointerCount = 0;
|
||||
void startNewPointer() {
|
||||
_pointerCount += 1;
|
||||
_pointer = _pointerCount;
|
||||
}
|
||||
|
||||
bool get down => _down;
|
||||
bool _down = false;
|
||||
void setDown() {
|
||||
assert(!_down);
|
||||
_down = true;
|
||||
}
|
||||
void setUp() {
|
||||
assert(_down);
|
||||
_down = false;
|
||||
}
|
||||
|
||||
Point lastPosition;
|
||||
}
|
||||
|
||||
class PointerEventConverter {
|
||||
// Map from platform pointer identifiers to PointerEvent pointer identifiers.
|
||||
static Map<int, _PointerState> _pointers = <int, _PointerState>{};
|
||||
|
||||
static Iterable<PointerEvent> expand(Iterable<Pointer> packet) sync* {
|
||||
for (Pointer datum in packet) {
|
||||
Point position = new Point(datum.x, datum.y);
|
||||
Duration timeStamp = new Duration(microseconds: datum.timeStamp);
|
||||
assert(_pointerKindMap.containsKey(datum.kind));
|
||||
PointerDeviceKind kind = _pointerKindMap[datum.kind];
|
||||
switch (datum.type) {
|
||||
case PointerType.DOWN:
|
||||
assert(!_pointers.containsKey(datum.pointer));
|
||||
_PointerState state = _pointers.putIfAbsent(
|
||||
datum.pointer,
|
||||
() => new _PointerState(position)
|
||||
);
|
||||
assert(state.lastPosition == position);
|
||||
state.startNewPointer();
|
||||
state.setDown();
|
||||
yield new PointerAddedEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
obscured: datum.obscured,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distance: datum.distance,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
yield new PointerDownEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
obscured: datum.obscured,
|
||||
pressure: datum.pressure,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMajor: datum.radiusMajor,
|
||||
radiusMinor: datum.radiusMajor,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
break;
|
||||
case PointerType.MOVE:
|
||||
// If the service starts supporting hover pointers, then it must also
|
||||
// start sending us ADDED and REMOVED data points.
|
||||
// See also: https://github.com/flutter/flutter/issues/720
|
||||
assert(_pointers.containsKey(datum.pointer));
|
||||
_PointerState state = _pointers[datum.pointer];
|
||||
assert(state.down);
|
||||
Offset offset = position - state.lastPosition;
|
||||
state.lastPosition = position;
|
||||
yield new PointerMoveEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
delta: offset,
|
||||
down: state.down,
|
||||
obscured: datum.obscured,
|
||||
pressure: datum.pressure,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distance: datum.distance,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMajor: datum.radiusMajor,
|
||||
radiusMinor: datum.radiusMajor,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
break;
|
||||
case PointerType.UP:
|
||||
case PointerType.CANCEL:
|
||||
assert(_pointers.containsKey(datum.pointer));
|
||||
_PointerState state = _pointers[datum.pointer];
|
||||
assert(state.down);
|
||||
assert(position == state.lastPosition);
|
||||
state.setUp();
|
||||
if (datum.type == PointerType.UP) {
|
||||
yield new PointerUpEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
obscured: datum.obscured,
|
||||
pressureMax: datum.pressureMax,
|
||||
distance: datum.distance,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
} else {
|
||||
yield new PointerCancelEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
obscured: datum.obscured,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distance: datum.distance,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
}
|
||||
yield new PointerRemovedEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
obscured: datum.obscured,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax
|
||||
);
|
||||
_pointers.remove(datum.pointer);
|
||||
break;
|
||||
default:
|
||||
// TODO(ianh): once https://github.com/flutter/flutter/issues/720 is
|
||||
// done, add real support for PointerAddedEvent and PointerRemovedEvent
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const Map<PointerKind, PointerDeviceKind> _pointerKindMap = const <PointerKind, PointerDeviceKind>{
|
||||
PointerKind.TOUCH: PointerDeviceKind.touch,
|
||||
PointerKind.MOUSE: PointerDeviceKind.mouse,
|
||||
PointerKind.STYLUS: PointerDeviceKind.stylus,
|
||||
PointerKind.INVERTED_STYLUS: PointerDeviceKind.invertedStylus,
|
||||
};
|
||||
}
|
@ -32,8 +32,16 @@ bool _isFlingGesture(Offset velocity) {
|
||||
}
|
||||
|
||||
abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGestureRecognizer {
|
||||
_DragGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd })
|
||||
: super(router: router);
|
||||
_DragGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
this.onStart,
|
||||
this.onUpdate,
|
||||
this.onEnd
|
||||
}) : super(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
GestureDragStartCallback onStart;
|
||||
_GesturePolymorphicUpdateCallback<T> onUpdate;
|
||||
@ -120,10 +128,17 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
|
||||
class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
||||
VerticalDragGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
GestureDragStartCallback onStart,
|
||||
GestureDragUpdateCallback onUpdate,
|
||||
GestureDragEndCallback onEnd
|
||||
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
|
||||
}) : super(
|
||||
router: router,
|
||||
gestureArena: gestureArena,
|
||||
onStart: onStart,
|
||||
onUpdate: onUpdate,
|
||||
onEnd: onEnd
|
||||
);
|
||||
|
||||
double get _initialPendingDragDelta => 0.0;
|
||||
double _getDragDelta(PointerEvent event) => event.delta.dy;
|
||||
@ -133,10 +148,17 @@ class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
||||
class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
||||
HorizontalDragGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
GestureDragStartCallback onStart,
|
||||
GestureDragUpdateCallback onUpdate,
|
||||
GestureDragEndCallback onEnd
|
||||
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
|
||||
}) : super(
|
||||
router: router,
|
||||
gestureArena: gestureArena,
|
||||
onStart: onStart,
|
||||
onUpdate: onUpdate,
|
||||
onEnd: onEnd
|
||||
);
|
||||
|
||||
double get _initialPendingDragDelta => 0.0;
|
||||
double _getDragDelta(PointerEvent event) => event.delta.dx;
|
||||
@ -146,10 +168,17 @@ class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
||||
class PanGestureRecognizer extends _DragGestureRecognizer<Offset> {
|
||||
PanGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
GesturePanStartCallback onStart,
|
||||
GesturePanUpdateCallback onUpdate,
|
||||
GesturePanEndCallback onEnd
|
||||
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
|
||||
}) : super(
|
||||
router: router,
|
||||
gestureArena: gestureArena,
|
||||
onStart: onStart,
|
||||
onUpdate: onUpdate,
|
||||
onEnd: onEnd
|
||||
);
|
||||
|
||||
Offset get _initialPendingDragDelta => Offset.zero;
|
||||
Offset _getDragDelta(PointerEvent event) => event.delta;
|
||||
|
@ -2,7 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'events.dart';
|
||||
|
||||
/// An object that can hit-test pointers.
|
||||
abstract class HitTestable {
|
||||
void hitTest(HitTestResult result, Point position);
|
||||
}
|
||||
|
||||
/// An object that can handle events.
|
||||
abstract class HitTestTarget {
|
@ -11,8 +11,15 @@ import 'recognizer.dart';
|
||||
typedef void GestureLongPressCallback();
|
||||
|
||||
class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
LongPressGestureRecognizer({ PointerRouter router, this.onLongPress })
|
||||
: super(router: router, deadline: kLongPressTimeout);
|
||||
LongPressGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
this.onLongPress
|
||||
}) : super(
|
||||
router: router,
|
||||
gestureArena: gestureArena,
|
||||
deadline: kLongPressTimeout
|
||||
);
|
||||
|
||||
GestureLongPressCallback onLongPress;
|
||||
|
||||
|
@ -58,9 +58,12 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
|
||||
|
||||
DoubleTapGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
this.onDoubleTap
|
||||
}) : _router = router {
|
||||
}) : _router = router,
|
||||
_gestureArena = gestureArena {
|
||||
assert(router != null);
|
||||
assert(gestureArena != null);
|
||||
}
|
||||
|
||||
// Implementation notes:
|
||||
@ -84,6 +87,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
|
||||
// - The gesture arena decides we have been rejected wholesale
|
||||
|
||||
PointerRouter _router;
|
||||
GestureArena _gestureArena;
|
||||
GestureDoubleTapCallback onDoubleTap;
|
||||
|
||||
Timer _doubleTapTimer;
|
||||
@ -98,7 +102,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
|
||||
_stopDoubleTapTimer();
|
||||
_TapTracker tracker = new _TapTracker(
|
||||
event: event,
|
||||
entry: GestureArena.instance.add(event.pointer, this)
|
||||
entry: _gestureArena.add(event.pointer, this)
|
||||
);
|
||||
_trackers[event.pointer] = tracker;
|
||||
tracker.startTrackingPointer(_router, handleEvent);
|
||||
@ -149,6 +153,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
|
||||
void dispose() {
|
||||
_reset();
|
||||
_router = null;
|
||||
_gestureArena = null;
|
||||
}
|
||||
|
||||
void _reset() {
|
||||
@ -159,14 +164,14 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
|
||||
_TapTracker tracker = _firstTap;
|
||||
_firstTap = null;
|
||||
_reject(tracker);
|
||||
GestureArena.instance.release(tracker.pointer);
|
||||
_gestureArena.release(tracker.pointer);
|
||||
}
|
||||
_clearTrackers();
|
||||
}
|
||||
|
||||
void _registerFirstTap(_TapTracker tracker) {
|
||||
_startDoubleTapTimer();
|
||||
GestureArena.instance.hold(tracker.pointer);
|
||||
_gestureArena.hold(tracker.pointer);
|
||||
// Note, order is important below in order for the clear -> reject logic to
|
||||
// work properly.
|
||||
_freezeTracker(tracker);
|
||||
@ -226,7 +231,10 @@ class _TapGesture extends _TapTracker {
|
||||
Duration longTapDelay
|
||||
}) : gestureRecognizer = gestureRecognizer,
|
||||
_lastPosition = event.position,
|
||||
super(event: event, entry: GestureArena.instance.add(event.pointer, gestureRecognizer)) {
|
||||
super(
|
||||
event: event,
|
||||
entry: gestureRecognizer._gestureArena.add(event.pointer, gestureRecognizer)
|
||||
) {
|
||||
startTrackingPointer(gestureRecognizer.router, handleEvent);
|
||||
if (longTapDelay > Duration.ZERO) {
|
||||
_timer = new Timer(longTapDelay, () {
|
||||
@ -299,18 +307,23 @@ class _TapGesture extends _TapTracker {
|
||||
class MultiTapGestureRecognizer extends GestureRecognizer {
|
||||
MultiTapGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
this.onTapDown,
|
||||
this.onTapUp,
|
||||
this.onTap,
|
||||
this.onTapCancel,
|
||||
this.longTapDelay: Duration.ZERO,
|
||||
this.onLongTapDown
|
||||
}) : _router = router {
|
||||
}) : _router = router,
|
||||
_gestureArena = gestureArena {
|
||||
assert(router != null);
|
||||
assert(gestureArena != null);
|
||||
}
|
||||
|
||||
PointerRouter get router => _router;
|
||||
PointerRouter _router;
|
||||
GestureArena get gestureArena => _gestureArena;
|
||||
GestureArena _gestureArena;
|
||||
GestureMultiTapDownCallback onTapDown;
|
||||
GestureMultiTapUpCallback onTapUp;
|
||||
GestureMultiTapCallback onTap;
|
||||
@ -369,6 +382,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer {
|
||||
// Rejection of each gesture should cause it to be removed from our map
|
||||
assert(_gestureMap.isEmpty);
|
||||
_router = null;
|
||||
_gestureArena = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,11 +30,17 @@ abstract class GestureRecognizer extends GestureArenaMember {
|
||||
}
|
||||
|
||||
abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
|
||||
OneSequenceGestureRecognizer({ PointerRouter router }) : _router = router {
|
||||
OneSequenceGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena
|
||||
}) : _router = router,
|
||||
_gestureArena = gestureArena {
|
||||
assert(_router != null);
|
||||
assert(_gestureArena != null);
|
||||
}
|
||||
|
||||
PointerRouter _router;
|
||||
GestureArena _gestureArena;
|
||||
|
||||
final List<GestureArenaEntry> _entries = <GestureArenaEntry>[];
|
||||
final Set<int> _trackedPointers = new Set<int>();
|
||||
@ -58,12 +64,13 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
|
||||
_trackedPointers.clear();
|
||||
assert(_entries.isEmpty);
|
||||
_router = null;
|
||||
_gestureArena = null;
|
||||
}
|
||||
|
||||
void startTrackingPointer(int pointer) {
|
||||
_router.addRoute(pointer, handleEvent);
|
||||
_trackedPointers.add(pointer);
|
||||
_entries.add(GestureArena.instance.add(pointer, this));
|
||||
_entries.add(_gestureArena.add(pointer, this));
|
||||
}
|
||||
|
||||
void stopTrackingPointer(int pointer) {
|
||||
@ -87,8 +94,14 @@ enum GestureRecognizerState {
|
||||
}
|
||||
|
||||
abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecognizer {
|
||||
PrimaryPointerGestureRecognizer({ PointerRouter router, this.deadline })
|
||||
: super(router: router);
|
||||
PrimaryPointerGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
this.deadline
|
||||
}) : super(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
final Duration deadline;
|
||||
|
||||
|
@ -19,8 +19,16 @@ typedef void GestureScaleUpdateCallback(double scale, Point focalPoint);
|
||||
typedef void GestureScaleEndCallback();
|
||||
|
||||
class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
|
||||
ScaleGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd })
|
||||
: super(router: router);
|
||||
ScaleGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
this.onStart,
|
||||
this.onUpdate,
|
||||
this.onEnd
|
||||
}) : super(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
GestureScaleStartCallback onStart;
|
||||
GestureScaleUpdateCallback onUpdate;
|
||||
|
@ -19,11 +19,16 @@ typedef void GestureTapCancelCallback();
|
||||
class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
TapGestureRecognizer({
|
||||
PointerRouter router,
|
||||
GestureArena gestureArena,
|
||||
this.onTapDown,
|
||||
this.onTapUp,
|
||||
this.onTap,
|
||||
this.onTapCancel
|
||||
}) : super(router: router, deadline: kPressTimeout);
|
||||
}) : super(
|
||||
router: router,
|
||||
gestureArena: gestureArena,
|
||||
deadline: kPressTimeout
|
||||
);
|
||||
|
||||
GestureTapDownCallback onTapDown;
|
||||
GestureTapDownCallback onTapUp;
|
||||
|
@ -74,11 +74,11 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
|
||||
_navigator = new GlobalObjectKey(this);
|
||||
_size = ui.window.size;
|
||||
didChangeLocale(ui.window.locale);
|
||||
FlutterBinding.instance.addObserver(this);
|
||||
WidgetFlutterBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
FlutterBinding.instance.removeObserver(this);
|
||||
WidgetFlutterBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ class _RenderSlider extends RenderConstrainedBox {
|
||||
_activeColor = activeColor,
|
||||
super(additionalConstraints: const BoxConstraints.tightFor(width: _kTrackWidth + 2 * _kReactionRadius, height: 2 * _kReactionRadius)) {
|
||||
assert(value != null && value >= 0.0 && value <= 1.0);
|
||||
_drag = new HorizontalDragGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
|
||||
_drag = new HorizontalDragGestureRecognizer(router: Pointerer.instance.pointerRouter, gestureArena: Pointerer.instance.gestureArena)
|
||||
..onStart = _handleDragStart
|
||||
..onUpdate = _handleDragUpdate
|
||||
..onEnd = _handleDragEnd;
|
||||
|
@ -115,7 +115,7 @@ class _RenderSwitch extends RenderToggleable {
|
||||
) {
|
||||
_activeTrackColor = activeTrackColor;
|
||||
_inactiveTrackColor = inactiveTrackColor;
|
||||
_drag = new HorizontalDragGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
|
||||
_drag = new HorizontalDragGestureRecognizer(router: Pointerer.instance.pointerRouter, gestureArena: Pointerer.instance.gestureArena)
|
||||
..onStart = _handleDragStart
|
||||
..onUpdate = _handleDragUpdate
|
||||
..onEnd = _handleDragEnd;
|
||||
|
@ -29,7 +29,7 @@ abstract class RenderToggleable extends RenderConstrainedBox {
|
||||
assert(value != null);
|
||||
assert(activeColor != null);
|
||||
assert(inactiveColor != null);
|
||||
_tap = new TapGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
|
||||
_tap = new TapGestureRecognizer(router: Pointerer.instance.pointerRouter, gestureArena: Pointerer.instance.gestureArena)
|
||||
..onTapDown = _handleTapDown
|
||||
..onTap = _handleTap
|
||||
..onTapUp = _handleTapUp
|
||||
|
@ -420,6 +420,8 @@ void paintImage({
|
||||
double alignX,
|
||||
double alignY
|
||||
}) {
|
||||
assert(canvas != null);
|
||||
assert(image != null);
|
||||
Size outputSize = rect.size;
|
||||
Size inputSize = new Size(image.width.toDouble(), image.height.toDouble());
|
||||
Offset sliceBorder;
|
||||
|
@ -220,7 +220,7 @@ class RenderAutoLayout extends RenderBox
|
||||
// only indicates that the value has been flushed to the variable.
|
||||
}
|
||||
|
||||
bool hitTestChildren(HitTestResult result, {Point position}) {
|
||||
bool hitTestChildren(HitTestResult result, { Point position }) {
|
||||
return defaultHitTestChildren(result, position: position);
|
||||
}
|
||||
|
||||
|
@ -2,265 +2,64 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:mojo/bindings.dart' as mojo_bindings;
|
||||
import 'package:mojo/core.dart' as mojo_core;
|
||||
import 'package:sky_services/pointer/pointer.mojom.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'box.dart';
|
||||
import 'debug.dart';
|
||||
import 'hit_test.dart';
|
||||
import 'object.dart';
|
||||
import 'view.dart';
|
||||
|
||||
typedef void MetricListener(Size size);
|
||||
|
||||
class _PointerState {
|
||||
_PointerState(this.lastPosition);
|
||||
|
||||
int get pointer => _pointer; // The identifier used in PointerEvent objects.
|
||||
int _pointer;
|
||||
static int _pointerCount = 0;
|
||||
void startNewPointer() {
|
||||
_pointerCount += 1;
|
||||
_pointer = _pointerCount;
|
||||
}
|
||||
|
||||
bool get down => _down;
|
||||
bool _down = false;
|
||||
void setDown() {
|
||||
assert(!_down);
|
||||
_down = true;
|
||||
}
|
||||
void setUp() {
|
||||
assert(_down);
|
||||
_down = false;
|
||||
}
|
||||
|
||||
Point lastPosition;
|
||||
}
|
||||
|
||||
class _PointerEventConverter {
|
||||
// Map from platform pointer identifiers to PointerEvent pointer identifiers.
|
||||
static Map<int, _PointerState> _pointers = <int, _PointerState>{};
|
||||
|
||||
static Iterable<PointerEvent> expand(Iterable<Pointer> packet) sync* {
|
||||
for (Pointer datum in packet) {
|
||||
Point position = new Point(datum.x, datum.y);
|
||||
Duration timeStamp = new Duration(microseconds: datum.timeStamp);
|
||||
assert(_pointerKindMap.containsKey(datum.kind));
|
||||
PointerDeviceKind kind = _pointerKindMap[datum.kind];
|
||||
switch (datum.type) {
|
||||
case PointerType.DOWN:
|
||||
assert(!_pointers.containsKey(datum.pointer));
|
||||
_PointerState state = _pointers.putIfAbsent(
|
||||
datum.pointer,
|
||||
() => new _PointerState(position)
|
||||
);
|
||||
assert(state.lastPosition == position);
|
||||
state.startNewPointer();
|
||||
state.setDown();
|
||||
yield new PointerAddedEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
obscured: datum.obscured,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distance: datum.distance,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
yield new PointerDownEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
obscured: datum.obscured,
|
||||
pressure: datum.pressure,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMajor: datum.radiusMajor,
|
||||
radiusMinor: datum.radiusMajor,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
break;
|
||||
case PointerType.MOVE:
|
||||
// If the service starts supporting hover pointers, then it must also
|
||||
// start sending us ADDED and REMOVED data points.
|
||||
// See also: https://github.com/flutter/flutter/issues/720
|
||||
assert(_pointers.containsKey(datum.pointer));
|
||||
_PointerState state = _pointers[datum.pointer];
|
||||
assert(state.down);
|
||||
Offset offset = position - state.lastPosition;
|
||||
state.lastPosition = position;
|
||||
yield new PointerMoveEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
delta: offset,
|
||||
down: state.down,
|
||||
obscured: datum.obscured,
|
||||
pressure: datum.pressure,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distance: datum.distance,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMajor: datum.radiusMajor,
|
||||
radiusMinor: datum.radiusMajor,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
break;
|
||||
case PointerType.UP:
|
||||
case PointerType.CANCEL:
|
||||
assert(_pointers.containsKey(datum.pointer));
|
||||
_PointerState state = _pointers[datum.pointer];
|
||||
assert(state.down);
|
||||
assert(position == state.lastPosition);
|
||||
state.setUp();
|
||||
if (datum.type == PointerType.UP) {
|
||||
yield new PointerUpEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
obscured: datum.obscured,
|
||||
pressureMax: datum.pressureMax,
|
||||
distance: datum.distance,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
} else {
|
||||
yield new PointerCancelEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
position: position,
|
||||
obscured: datum.obscured,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distance: datum.distance,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax,
|
||||
orientation: datum.orientation,
|
||||
tilt: datum.tilt
|
||||
);
|
||||
}
|
||||
yield new PointerRemovedEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
kind: kind,
|
||||
obscured: datum.obscured,
|
||||
pressureMin: datum.pressureMin,
|
||||
pressureMax: datum.pressureMax,
|
||||
distanceMax: datum.distanceMax,
|
||||
radiusMin: datum.radiusMin,
|
||||
radiusMax: datum.radiusMax
|
||||
);
|
||||
_pointers.remove(datum.pointer);
|
||||
break;
|
||||
default:
|
||||
// TODO(ianh): once https://github.com/flutter/flutter/issues/720 is
|
||||
// done, add real support for PointerAddedEvent and PointerRemovedEvent
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const Map<PointerKind, PointerDeviceKind> _pointerKindMap = const <PointerKind, PointerDeviceKind>{
|
||||
PointerKind.TOUCH: PointerDeviceKind.touch,
|
||||
PointerKind.MOUSE: PointerDeviceKind.mouse,
|
||||
PointerKind.STYLUS: PointerDeviceKind.stylus,
|
||||
PointerKind.INVERTED_STYLUS: PointerDeviceKind.invertedStylus,
|
||||
};
|
||||
}
|
||||
|
||||
class BindingObserver {
|
||||
bool didPopRoute() => false;
|
||||
void didChangeSize(Size size) { }
|
||||
void didChangeLocale(ui.Locale locale) { }
|
||||
}
|
||||
export 'package:flutter/gestures.dart' show HitTestResult;
|
||||
|
||||
/// The glue between the render tree and the Flutter engine.
|
||||
class FlutterBinding extends HitTestTarget {
|
||||
abstract class Renderer extends Scheduler
|
||||
implements HitTestable {
|
||||
|
||||
FlutterBinding({ RenderBox root: null, RenderView renderViewOverride }) {
|
||||
assert(_instance == null);
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
|
||||
ui.window.onPointerPacket = _handlePointerPacket;
|
||||
ui.window.onMetricsChanged = _handleMetricsChanged;
|
||||
ui.window.onLocaleChanged = _handleLocaleChanged;
|
||||
ui.window.onPopRoute = _handlePopRoute;
|
||||
|
||||
if (renderViewOverride == null) {
|
||||
_renderView = new RenderView(child: root);
|
||||
_renderView.attach();
|
||||
_handleMetricsChanged();
|
||||
_renderView.scheduleInitialFrame();
|
||||
} else {
|
||||
_renderView = renderViewOverride;
|
||||
}
|
||||
assert(_renderView != null);
|
||||
scheduler.addPersistentFrameCallback(_handlePersistentFrameCallback);
|
||||
|
||||
assert(_instance == this);
|
||||
ui.window.onMetricsChanged = handleMetricsChanged;
|
||||
initRenderView();
|
||||
addPersistentFrameCallback(_handlePersistentFrameCallback);
|
||||
}
|
||||
|
||||
/// The singleton instance of the binding.
|
||||
static FlutterBinding get instance => _instance;
|
||||
static FlutterBinding _instance;
|
||||
static Renderer _instance;
|
||||
static Renderer get instance => _instance;
|
||||
|
||||
void initRenderView() {
|
||||
if (renderView == null) {
|
||||
renderView = new RenderView();
|
||||
renderView.scheduleInitialFrame();
|
||||
}
|
||||
handleMetricsChanged(); // configures _renderView's metrics
|
||||
}
|
||||
|
||||
/// The render tree that's attached to the output surface.
|
||||
RenderView get renderView => _renderView;
|
||||
RenderView _renderView;
|
||||
|
||||
final List<BindingObserver> _observers = new List<BindingObserver>();
|
||||
|
||||
void addObserver(BindingObserver observer) => _observers.add(observer);
|
||||
bool removeObserver(BindingObserver observer) => _observers.remove(observer);
|
||||
|
||||
void _handleMetricsChanged() {
|
||||
Size size = ui.window.size;
|
||||
_renderView.rootConstraints = new ViewConstraints(size: size);
|
||||
for (BindingObserver observer in _observers)
|
||||
observer.didChangeSize(size);
|
||||
void set renderView(RenderView value) {
|
||||
if (_renderView == value)
|
||||
return;
|
||||
if (_renderView != null)
|
||||
_renderView.detach();
|
||||
_renderView = value;
|
||||
if (_renderView != null)
|
||||
_renderView.attach();
|
||||
}
|
||||
|
||||
void _handleLocaleChanged() {
|
||||
dispatchLocaleChanged(ui.window.locale);
|
||||
}
|
||||
|
||||
void dispatchLocaleChanged(ui.Locale locale) {
|
||||
for (BindingObserver observer in _observers)
|
||||
observer.didChangeLocale(locale);
|
||||
void handleMetricsChanged() {
|
||||
_renderView.rootConstraints = new ViewConstraints(size: ui.window.size);
|
||||
}
|
||||
|
||||
void _handlePersistentFrameCallback(Duration timeStamp) {
|
||||
beginFrame();
|
||||
}
|
||||
|
||||
/// Pump the rendering pipeline to generate a frame for the given time stamp.
|
||||
/// Pump the rendering pipeline to generate a frame.
|
||||
void beginFrame() {
|
||||
RenderObject.flushLayout();
|
||||
_renderView.updateCompositingBits();
|
||||
@ -268,82 +67,26 @@ class FlutterBinding extends HitTestTarget {
|
||||
_renderView.compositeFrame();
|
||||
}
|
||||
|
||||
void _handlePopRoute() {
|
||||
for (BindingObserver observer in _observers) {
|
||||
if (observer.didPopRoute())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _handlePointerPacket(ByteData serializedPacket) {
|
||||
final mojo_bindings.Message message = new mojo_bindings.Message(
|
||||
serializedPacket,
|
||||
<mojo_core.MojoHandle>[],
|
||||
serializedPacket.lengthInBytes,
|
||||
0
|
||||
);
|
||||
final PointerPacket packet = PointerPacket.deserialize(message);
|
||||
for (PointerEvent event in _PointerEventConverter.expand(packet.pointers))
|
||||
_handlePointerEvent(event);
|
||||
}
|
||||
|
||||
/// A router that routes all pointer events received from the engine.
|
||||
final PointerRouter pointerRouter = new PointerRouter();
|
||||
|
||||
/// State for all pointers which are currently down.
|
||||
///
|
||||
/// The state of hovering pointers is not tracked because that would require
|
||||
/// hit-testing on every frame.
|
||||
Map<int, HitTestResult> _hitTests = <int, HitTestResult>{};
|
||||
|
||||
void _handlePointerEvent(PointerEvent event) {
|
||||
if (event is PointerDownEvent) {
|
||||
assert(!_hitTests.containsKey(event.pointer));
|
||||
_hitTests[event.pointer] = hitTest(event.position);
|
||||
} else if (event is! PointerUpEvent) {
|
||||
assert(event.down == _hitTests.containsKey(event.pointer));
|
||||
if (!event.down)
|
||||
return; // we currently ignore add, remove, and hover move events
|
||||
}
|
||||
assert(_hitTests[event.pointer] != null);
|
||||
dispatchEvent(event, _hitTests[event.pointer]);
|
||||
if (event is PointerUpEvent) {
|
||||
assert(_hitTests.containsKey(event.pointer));
|
||||
_hitTests.remove(event.pointer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine which [HitTestTarget] objects are located at a given position.
|
||||
HitTestResult hitTest(Point position) {
|
||||
HitTestResult result = new HitTestResult();
|
||||
void hitTest(HitTestResult result, Point position) {
|
||||
_renderView.hitTest(result, position: position);
|
||||
result.add(new HitTestEntry(this));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Dispatch the given event to the path of the given hit test result
|
||||
void dispatchEvent(PointerEvent event, HitTestResult result) {
|
||||
assert(result != null);
|
||||
for (HitTestEntry entry in result.path)
|
||||
entry.target.handleEvent(event, entry);
|
||||
}
|
||||
|
||||
void handleEvent(PointerEvent event, HitTestEntry entry) {
|
||||
pointerRouter.route(event);
|
||||
if (event is PointerDownEvent) {
|
||||
GestureArena.instance.close(event.pointer);
|
||||
} else if (event is PointerUpEvent) {
|
||||
GestureArena.instance.sweep(event.pointer);
|
||||
}
|
||||
super.hitTest(result, position);
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a textual representation of the entire render tree.
|
||||
void debugDumpRenderTree() {
|
||||
debugPrint(FlutterBinding.instance.renderView.toStringDeep());
|
||||
debugPrint(Renderer.instance.renderView.toStringDeep());
|
||||
}
|
||||
|
||||
/// Prints a textual representation of the entire layer tree.
|
||||
void debugDumpLayerTree() {
|
||||
debugPrint(FlutterBinding.instance.renderView.layer.toStringDeep());
|
||||
debugPrint(Renderer.instance.renderView.layer.toStringDeep());
|
||||
}
|
||||
|
||||
/// A concrete binding for applications that use the Rendering framework
|
||||
/// directly. This is the glue that binds the framework to the Flutter engine.
|
||||
class RenderingFlutterBinding extends BindingBase with Scheduler, Renderer, Pointerer {
|
||||
RenderingFlutterBinding({ RenderBox root }) {
|
||||
renderView.child = root;
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,11 @@ import 'package:flutter/scheduler.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'debug.dart';
|
||||
import 'hit_test.dart';
|
||||
import 'layer.dart';
|
||||
import 'node.dart';
|
||||
|
||||
export 'layer.dart';
|
||||
export 'hit_test.dart';
|
||||
export 'package:flutter/gestures.dart' show HitTestEntry, HitTestResult;
|
||||
|
||||
typedef ui.Shader ShaderCallback(Rect bounds);
|
||||
|
||||
@ -551,7 +550,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
assert(parent == this.parent);
|
||||
} else {
|
||||
_nodesNeedingLayout.add(this);
|
||||
scheduler.ensureVisualUpdate();
|
||||
Scheduler.instance.ensureVisualUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -916,7 +915,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
// ourselves without involving any other nodes.
|
||||
assert(_layer != null);
|
||||
_nodesNeedingPaint.add(this);
|
||||
scheduler.ensureVisualUpdate();
|
||||
Scheduler.instance.ensureVisualUpdate();
|
||||
} else if (parent is RenderObject) {
|
||||
// We don't have our own layer; one of our ancestors will take
|
||||
// care of updating the layer we're in and when they do that
|
||||
@ -930,7 +929,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
// then we have to paint ourselves, since nobody else can paint
|
||||
// us. We don't add ourselves to _nodesNeedingPaint in this
|
||||
// case, because the root is always told to paint regardless.
|
||||
scheduler.ensureVisualUpdate();
|
||||
Scheduler.instance.ensureVisualUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
||||
void scheduleInitialFrame() {
|
||||
scheduleInitialLayout();
|
||||
scheduleInitialPaint(new TransformLayer(transform: _logicalToDeviceTransform));
|
||||
scheduler.ensureVisualUpdate();
|
||||
Scheduler.instance.ensureVisualUpdate();
|
||||
}
|
||||
|
||||
// We never call layout() on this class, so this should never get
|
||||
|
@ -7,6 +7,7 @@ import 'dart:developer';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:collection/priority_queue.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// Slows down animations by this factor to help in development.
|
||||
double timeDilation = 1.0;
|
||||
@ -80,12 +81,18 @@ class Priority {
|
||||
/// the task should be run.
|
||||
///
|
||||
/// Tasks always run in the idle time after a frame has been committed.
|
||||
class Scheduler {
|
||||
abstract class Scheduler extends BindingBase {
|
||||
/// Requires clients to use the [scheduler] singleton
|
||||
Scheduler._() {
|
||||
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
ui.window.onBeginFrame = handleBeginFrame;
|
||||
}
|
||||
|
||||
static Scheduler _instance;
|
||||
static Scheduler get instance => _instance;
|
||||
|
||||
SchedulingStrategy schedulingStrategy = new DefaultSchedulingStrategy();
|
||||
|
||||
final PriorityQueue _taskQueue = new HeapPriorityQueue<_TaskEntry>(
|
||||
@ -120,7 +127,7 @@ class Scheduler {
|
||||
if (_taskQueue.isEmpty)
|
||||
return;
|
||||
_TaskEntry entry = _taskQueue.first;
|
||||
if (schedulingStrategy.shouldRunTaskWithPriority(entry.priority)) {
|
||||
if (schedulingStrategy.shouldRunTaskWithPriority(priority: entry.priority, scheduler: this)) {
|
||||
try {
|
||||
(_taskQueue.removeFirst().task)();
|
||||
} finally {
|
||||
@ -295,17 +302,15 @@ class Scheduler {
|
||||
}
|
||||
}
|
||||
|
||||
final Scheduler scheduler = new Scheduler._();
|
||||
|
||||
abstract class SchedulingStrategy {
|
||||
bool shouldRunTaskWithPriority(int priority);
|
||||
bool shouldRunTaskWithPriority({ int priority, Scheduler scheduler });
|
||||
}
|
||||
|
||||
class DefaultSchedulingStrategy implements SchedulingStrategy {
|
||||
// TODO(floitsch): for now we only expose the priority. It might be
|
||||
// interesting to provide more info (like, how long the task ran the last
|
||||
// time).
|
||||
bool shouldRunTaskWithPriority(int priority) {
|
||||
bool shouldRunTaskWithPriority({ int priority, Scheduler scheduler }) {
|
||||
if (scheduler.transientCallbackCount > 0)
|
||||
return priority >= Priority.animation._value;
|
||||
return true;
|
||||
|
@ -100,7 +100,8 @@ class MojoAssetBundle extends AssetBundle {
|
||||
AssetBundle _initRootBundle() {
|
||||
try {
|
||||
AssetBundleProxy bundle = new AssetBundleProxy.fromHandle(
|
||||
new core.MojoHandle(internals.takeRootBundleHandle()));
|
||||
new core.MojoHandle(internals.takeRootBundleHandle())
|
||||
);
|
||||
return new MojoAssetBundle(bundle);
|
||||
} catch (e) {
|
||||
return null;
|
||||
|
32
packages/flutter/lib/src/services/binding.dart
Normal file
32
packages/flutter/lib/src/services/binding.dart
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
/// Base class for mixins that provide singleton services (also known as
|
||||
/// "bindings").
|
||||
///
|
||||
/// To use this class in a mixin, inherit from it and implement
|
||||
/// [initInstances()]. The mixin is guaranteed to only be constructed once in
|
||||
/// the lifetime of the app (more precisely, it will assert if constructed twice
|
||||
/// in checked mode).
|
||||
abstract class BindingBase {
|
||||
BindingBase() {
|
||||
assert(!_debugInitialized);
|
||||
initInstances();
|
||||
assert(_debugInitialized);
|
||||
}
|
||||
|
||||
static bool _debugInitialized = false;
|
||||
|
||||
/// The initialization method. Subclasses override this method to hook into
|
||||
/// the platform and otherwise configure their services. Subclasses must call
|
||||
/// "super.initInstances()".
|
||||
///
|
||||
/// By convention, if the service is to be provided as a singleton, it should
|
||||
/// be exposed as `MixinClassName.instance`, a static getter that returns
|
||||
/// `MixinClassName._instance`, a static field that is set by
|
||||
/// `initInstances()`.
|
||||
void initInstances() {
|
||||
assert(() { _debugInitialized = true; return true; });
|
||||
}
|
||||
}
|
@ -2,35 +2,82 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'framework.dart';
|
||||
|
||||
/// The glue that binds the widget framework to the Flutter engine.
|
||||
class WidgetFlutterBinding extends FlutterBinding {
|
||||
class BindingObserver {
|
||||
bool didPopRoute() => false;
|
||||
void didChangeSize(Size size) { }
|
||||
void didChangeLocale(ui.Locale locale) { }
|
||||
}
|
||||
|
||||
WidgetFlutterBinding() {
|
||||
BuildableElement.scheduleBuildFor = scheduleBuildFor;
|
||||
/// A concrete binding for applications based on the Widgets framework.
|
||||
/// This is the glue that binds the framework to the Flutter engine.
|
||||
class WidgetFlutterBinding extends BindingBase with Scheduler, Pointerer, Renderer {
|
||||
|
||||
WidgetFlutterBinding._();
|
||||
|
||||
/// Creates and initializes the WidgetFlutterBinding. This constructor is
|
||||
/// idempotent; calling it a second time will just return the
|
||||
/// previously-created instance.
|
||||
static WidgetFlutterBinding ensureInitialized() {
|
||||
if (_instance == null)
|
||||
new WidgetFlutterBinding._();
|
||||
return _instance;
|
||||
}
|
||||
|
||||
/// Ensures that there is a FlutterBinding object instantiated.
|
||||
static void ensureInitialized() {
|
||||
if (FlutterBinding.instance == null)
|
||||
new WidgetFlutterBinding();
|
||||
assert(FlutterBinding.instance is WidgetFlutterBinding);
|
||||
initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
BuildableElement.scheduleBuildFor = scheduleBuildFor;
|
||||
ui.window.onLocaleChanged = handleLocaleChanged;
|
||||
ui.window.onPopRoute = handlePopRoute;
|
||||
}
|
||||
|
||||
/// The one static instance of this class.
|
||||
///
|
||||
/// Only valid after ensureInitialized() (or the WidgetFlutterBinding
|
||||
/// constructor) has been called. If another FlutterBinding subclass is
|
||||
/// instantiated before this one (e.g. bindings from other frameworks based on
|
||||
/// the Flutter "rendering" library), then WidgetFlutterBinding.instance will
|
||||
/// not be valid (and will throw in checked mode).
|
||||
static WidgetFlutterBinding get instance => FlutterBinding.instance;
|
||||
/// Only valid after the WidgetFlutterBinding constructor) has been called.
|
||||
/// Only one binding class can be instantiated per process. If another
|
||||
/// BindingBase implementation has been instantiated before this one (e.g.
|
||||
/// bindings from other frameworks based on the Flutter "rendering" library),
|
||||
/// then WidgetFlutterBinding.instance will not be valid (and will throw in
|
||||
/// checked mode).
|
||||
static WidgetFlutterBinding _instance;
|
||||
static WidgetFlutterBinding get instance => _instance;
|
||||
|
||||
final List<BindingObserver> _observers = new List<BindingObserver>();
|
||||
|
||||
void addObserver(BindingObserver observer) => _observers.add(observer);
|
||||
bool removeObserver(BindingObserver observer) => _observers.remove(observer);
|
||||
|
||||
void handleMetricsChanged() {
|
||||
super.handleMetricsChanged();
|
||||
for (BindingObserver observer in _observers)
|
||||
observer.didChangeSize(ui.window.size);
|
||||
}
|
||||
|
||||
void handleLocaleChanged() {
|
||||
dispatchLocaleChanged(ui.window.locale);
|
||||
}
|
||||
|
||||
void dispatchLocaleChanged(ui.Locale locale) {
|
||||
for (BindingObserver observer in _observers)
|
||||
observer.didChangeLocale(locale);
|
||||
}
|
||||
|
||||
void handlePopRoute() {
|
||||
for (BindingObserver observer in _observers) {
|
||||
if (observer.didPopRoute())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void beginFrame() {
|
||||
buildDirtyElements();
|
||||
@ -46,7 +93,7 @@ class WidgetFlutterBinding extends FlutterBinding {
|
||||
assert(!_dirtyElements.contains(element));
|
||||
assert(element.dirty);
|
||||
if (_dirtyElements.isEmpty)
|
||||
scheduler.ensureVisualUpdate();
|
||||
ensureVisualUpdate();
|
||||
_dirtyElements.add(element);
|
||||
}
|
||||
|
||||
@ -93,8 +140,7 @@ class WidgetFlutterBinding extends FlutterBinding {
|
||||
|
||||
/// Inflate the given widget and attach it to the screen.
|
||||
void runApp(Widget app) {
|
||||
WidgetFlutterBinding.ensureInitialized();
|
||||
WidgetFlutterBinding.instance._runApp(app);
|
||||
WidgetFlutterBinding.ensureInitialized()._runApp(app);
|
||||
}
|
||||
|
||||
/// Print a string representation of the currently running app.
|
||||
@ -157,7 +203,7 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RenderObjectEl
|
||||
|
||||
Element _child;
|
||||
|
||||
static const _rootChild = const Object();
|
||||
static const _rootChildSlot = const Object();
|
||||
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
if (_child != null)
|
||||
@ -167,19 +213,19 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RenderObjectEl
|
||||
void mount(Element parent, dynamic newSlot) {
|
||||
assert(parent == null);
|
||||
super.mount(parent, newSlot);
|
||||
_child = updateChild(_child, widget.child, _rootChild);
|
||||
_child = updateChild(_child, widget.child, _rootChildSlot);
|
||||
}
|
||||
|
||||
void update(RenderObjectToWidgetAdapter<T> newWidget) {
|
||||
super.update(newWidget);
|
||||
assert(widget == newWidget);
|
||||
_child = updateChild(_child, widget.child, _rootChild);
|
||||
_child = updateChild(_child, widget.child, _rootChildSlot);
|
||||
}
|
||||
|
||||
RenderObjectWithChildMixin<T> get renderObject => super.renderObject;
|
||||
|
||||
void insertChildRenderObject(RenderObject child, dynamic slot) {
|
||||
assert(slot == _rootChild);
|
||||
assert(slot == _rootChildSlot);
|
||||
renderObject.child = child;
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,7 @@ class Draggable<T> extends DraggableBase<T> {
|
||||
GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter) {
|
||||
return new MultiTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: Pointerer.instance.gestureArena,
|
||||
onTapDown: starter
|
||||
);
|
||||
}
|
||||
@ -122,6 +123,7 @@ class LongPressDraggable<T> extends DraggableBase<T> {
|
||||
GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter) {
|
||||
return new MultiTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: Pointerer.instance.gestureArena,
|
||||
longTapDelay: kLongPressTimeout,
|
||||
onLongTapDown: (Point position, int pointer) {
|
||||
userFeedback.performHapticFeedback(HapticFeedbackType.VIRTUAL_KEY);
|
||||
@ -133,7 +135,7 @@ class LongPressDraggable<T> extends DraggableBase<T> {
|
||||
|
||||
class _DraggableState<T> extends State<DraggableBase<T>> implements GestureArenaMember {
|
||||
|
||||
PointerRouter get router => FlutterBinding.instance.pointerRouter;
|
||||
PointerRouter get router => Pointerer.instance.pointerRouter;
|
||||
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -144,7 +146,7 @@ class _DraggableState<T> extends State<DraggableBase<T>> implements GestureArena
|
||||
Map<int, GestureArenaEntry> _activePointers = <int, GestureArenaEntry>{};
|
||||
|
||||
void _routePointer(PointerEvent event) {
|
||||
_activePointers[event.pointer] = GestureArena.instance.add(event.pointer, this);
|
||||
_activePointers[event.pointer] = Pointerer.instance.gestureArena.add(event.pointer, this);
|
||||
_recognizer.addPointer(event);
|
||||
}
|
||||
|
||||
@ -315,7 +317,8 @@ class _DragAvatar<T> {
|
||||
void update(Point globalPosition) {
|
||||
_lastOffset = globalPosition - dragStartPoint;
|
||||
_entry.markNeedsBuild();
|
||||
HitTestResult result = WidgetFlutterBinding.instance.hitTest(globalPosition + feedbackOffset);
|
||||
HitTestResult result = new HitTestResult();
|
||||
WidgetFlutterBinding.instance.hitTest(result, globalPosition + feedbackOffset);
|
||||
_DragTargetState target = _getDragTarget(result.path);
|
||||
if (target == _activeTarget)
|
||||
return;
|
||||
|
@ -121,7 +121,7 @@ class GestureDetector extends StatefulComponent {
|
||||
}
|
||||
|
||||
class _GestureDetectorState extends State<GestureDetector> {
|
||||
PointerRouter get _router => FlutterBinding.instance.pointerRouter;
|
||||
PointerRouter get _router => Pointerer.instance.pointerRouter;
|
||||
|
||||
TapGestureRecognizer _tap;
|
||||
DoubleTapGestureRecognizer _doubleTap;
|
||||
@ -165,7 +165,7 @@ class _GestureDetectorState extends State<GestureDetector> {
|
||||
if (config.onTapDown == null && config.onTapUp == null && config.onTap == null && config.onTapCancel == null) {
|
||||
_tap = _ensureDisposed(_tap);
|
||||
} else {
|
||||
_tap ??= new TapGestureRecognizer(router: _router);
|
||||
_tap ??= new TapGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
|
||||
_tap
|
||||
..onTapDown = config.onTapDown
|
||||
..onTapUp = config.onTapUp
|
||||
@ -178,7 +178,7 @@ class _GestureDetectorState extends State<GestureDetector> {
|
||||
if (config.onDoubleTap == null) {
|
||||
_doubleTap = _ensureDisposed(_doubleTap);
|
||||
} else {
|
||||
_doubleTap ??= new DoubleTapGestureRecognizer(router: _router);
|
||||
_doubleTap ??= new DoubleTapGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
|
||||
_doubleTap.onDoubleTap = config.onDoubleTap;
|
||||
}
|
||||
}
|
||||
@ -187,7 +187,7 @@ class _GestureDetectorState extends State<GestureDetector> {
|
||||
if (config.onLongPress == null) {
|
||||
_longPress = _ensureDisposed(_longPress);
|
||||
} else {
|
||||
_longPress ??= new LongPressGestureRecognizer(router: _router);
|
||||
_longPress ??= new LongPressGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
|
||||
_longPress.onLongPress = config.onLongPress;
|
||||
}
|
||||
}
|
||||
@ -196,7 +196,7 @@ class _GestureDetectorState extends State<GestureDetector> {
|
||||
if (config.onVerticalDragStart == null && config.onVerticalDragUpdate == null && config.onVerticalDragEnd == null) {
|
||||
_verticalDrag = _ensureDisposed(_verticalDrag);
|
||||
} else {
|
||||
_verticalDrag ??= new VerticalDragGestureRecognizer(router: _router);
|
||||
_verticalDrag ??= new VerticalDragGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
|
||||
_verticalDrag
|
||||
..onStart = config.onVerticalDragStart
|
||||
..onUpdate = config.onVerticalDragUpdate
|
||||
@ -208,7 +208,7 @@ class _GestureDetectorState extends State<GestureDetector> {
|
||||
if (config.onHorizontalDragStart == null && config.onHorizontalDragUpdate == null && config.onHorizontalDragEnd == null) {
|
||||
_horizontalDrag = _ensureDisposed(_horizontalDrag);
|
||||
} else {
|
||||
_horizontalDrag ??= new HorizontalDragGestureRecognizer(router: _router);
|
||||
_horizontalDrag ??= new HorizontalDragGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
|
||||
_horizontalDrag
|
||||
..onStart = config.onHorizontalDragStart
|
||||
..onUpdate = config.onHorizontalDragUpdate
|
||||
@ -221,7 +221,7 @@ class _GestureDetectorState extends State<GestureDetector> {
|
||||
_pan = _ensureDisposed(_pan);
|
||||
} else {
|
||||
assert(_scale == null); // Scale is a superset of pan; just use scale
|
||||
_pan ??= new PanGestureRecognizer(router: _router);
|
||||
_pan ??= new PanGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
|
||||
_pan
|
||||
..onStart = config.onPanStart
|
||||
..onUpdate = config.onPanUpdate
|
||||
@ -234,7 +234,7 @@ class _GestureDetectorState extends State<GestureDetector> {
|
||||
_scale = _ensureDisposed(_scale);
|
||||
} else {
|
||||
assert(_pan == null); // Scale is a superset of pan; just use scale
|
||||
_scale ??= new ScaleGestureRecognizer(router: _router);
|
||||
_scale ??= new ScaleGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
|
||||
_scale
|
||||
..onStart = config.onScaleStart
|
||||
..onUpdate = config.onScaleUpdate
|
||||
|
@ -455,7 +455,7 @@ class HeroController extends NavigatorObserver {
|
||||
void _checkForHeroQuest() {
|
||||
if (_from != null && _to != null && _from != _to) {
|
||||
_to.offstage = _to.performance.status != PerformanceStatus.completed;
|
||||
scheduler.addPostFrameCallback(_updateQuest);
|
||||
Scheduler.instance.addPostFrameCallback(_updateQuest);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,15 @@ typedef Point SizeToPointFunction(Size size);
|
||||
|
||||
class WidgetTester {
|
||||
WidgetTester._(FakeAsync async)
|
||||
: async = async,
|
||||
: binding = WidgetFlutterBinding.ensureInitialized(),
|
||||
async = async,
|
||||
clock = async.getClock(new DateTime.utc(2015, 1, 1)) {
|
||||
timeDilation = 1.0;
|
||||
ui.window.onBeginFrame = null;
|
||||
runApp(new ErrorWidget()); // flush out the last build entirely
|
||||
}
|
||||
|
||||
final WidgetFlutterBinding binding;
|
||||
final FakeAsync async;
|
||||
final Clock clock;
|
||||
|
||||
@ -34,15 +36,16 @@ class WidgetTester {
|
||||
|
||||
void setLocale(String languageCode, String countryCode) {
|
||||
ui.Locale locale = new ui.Locale(languageCode, countryCode);
|
||||
FlutterBinding.instance.dispatchLocaleChanged(locale);
|
||||
binding.dispatchLocaleChanged(locale);
|
||||
async.flushMicrotasks();
|
||||
}
|
||||
|
||||
void pump([ Duration duration ]) {
|
||||
if (duration != null)
|
||||
async.elapse(duration);
|
||||
scheduler.handleBeginFrame(new Duration(
|
||||
milliseconds: clock.now().millisecondsSinceEpoch));
|
||||
binding.handleBeginFrame(new Duration(
|
||||
milliseconds: clock.now().millisecondsSinceEpoch)
|
||||
);
|
||||
async.flushMicrotasks();
|
||||
}
|
||||
|
||||
@ -58,7 +61,7 @@ class WidgetTester {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
List<Layer> get layers => _layers(FlutterBinding.instance.renderView.layer);
|
||||
List<Layer> get layers => _layers(binding.renderView.layer);
|
||||
|
||||
|
||||
void walkElements(ElementVisitor visitor) {
|
||||
@ -66,7 +69,7 @@ class WidgetTester {
|
||||
visitor(element);
|
||||
element.visitChildren(walk);
|
||||
}
|
||||
WidgetFlutterBinding.instance.renderViewElement.visitChildren(walk);
|
||||
binding.renderViewElement.visitChildren(walk);
|
||||
}
|
||||
|
||||
Element findElement(bool predicate(Element element)) {
|
||||
@ -184,10 +187,14 @@ class WidgetTester {
|
||||
_dispatchEvent(event, _hitTest(location));
|
||||
}
|
||||
|
||||
HitTestResult _hitTest(Point location) => WidgetFlutterBinding.instance.hitTest(location);
|
||||
HitTestResult _hitTest(Point location) {
|
||||
HitTestResult result = new HitTestResult();
|
||||
binding.hitTest(result, location);
|
||||
return result;
|
||||
}
|
||||
|
||||
void _dispatchEvent(PointerEvent event, HitTestResult result) {
|
||||
WidgetFlutterBinding.instance.dispatchEvent(event, result);
|
||||
binding.dispatchEvent(event, result);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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 'dart:ui' as ui;
|
||||
import 'dart:ui' show Rect, Color, Paint;
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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 'dart:ui';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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 'dart:ui';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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 'dart:ui';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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:test/test.dart';
|
||||
|
||||
import '../rendering/rendering_tester.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/gestures.dart';
|
||||
import 'package:quiver/testing/async.dart';
|
||||
import 'package:test/test.dart';
|
||||
@ -77,7 +81,11 @@ void main() {
|
||||
|
||||
test('Should recognize double tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -85,25 +93,25 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isTrue);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isTrue);
|
||||
|
||||
tap.dispose();
|
||||
@ -111,7 +119,11 @@ void main() {
|
||||
|
||||
test('Inter-tap distance cancels double tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -119,25 +131,25 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down3);
|
||||
GestureArena.instance.close(3);
|
||||
gestureArena.close(3);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down3);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up3);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(3);
|
||||
gestureArena.sweep(3);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.dispose();
|
||||
@ -145,7 +157,11 @@ void main() {
|
||||
|
||||
test('Intra-tap distance cancels double tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -153,7 +169,7 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down4);
|
||||
GestureArena.instance.close(4);
|
||||
gestureArena.close(4);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down4);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
@ -162,18 +178,18 @@ void main() {
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(up4);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(4);
|
||||
gestureArena.sweep(4);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.dispose();
|
||||
@ -181,7 +197,11 @@ void main() {
|
||||
|
||||
test('Inter-tap delay cancels double tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -190,26 +210,26 @@ void main() {
|
||||
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
async.elapse(new Duration(milliseconds: 5000));
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
});
|
||||
|
||||
@ -218,7 +238,11 @@ void main() {
|
||||
|
||||
test('Inter-tap delay resets double tap, allowing third tap to be a double-tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -227,38 +251,38 @@ void main() {
|
||||
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
async.elapse(new Duration(milliseconds: 5000));
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
async.elapse(new Duration(milliseconds: 100));
|
||||
tap.addPointer(down5);
|
||||
GestureArena.instance.close(5);
|
||||
gestureArena.close(5);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down5);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up5);
|
||||
expect(doubleTapRecognized, isTrue);
|
||||
GestureArena.instance.sweep(5);
|
||||
gestureArena.sweep(5);
|
||||
expect(doubleTapRecognized, isTrue);
|
||||
});
|
||||
|
||||
@ -267,7 +291,11 @@ void main() {
|
||||
|
||||
test('Intra-tap delay does not cancel double tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -276,7 +304,7 @@ void main() {
|
||||
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
@ -284,18 +312,18 @@ void main() {
|
||||
async.elapse(new Duration(milliseconds: 1000));
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isTrue);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isTrue);
|
||||
});
|
||||
|
||||
@ -304,7 +332,11 @@ void main() {
|
||||
|
||||
test('Should not recognize two overlapping taps', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -312,25 +344,25 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.dispose();
|
||||
@ -338,7 +370,11 @@ void main() {
|
||||
|
||||
test('Should recognize one tap of group followed by second tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -346,36 +382,36 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isTrue);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isTrue);
|
||||
|
||||
tap.dispose();
|
||||
@ -384,7 +420,11 @@ void main() {
|
||||
|
||||
test('Should cancel on arena reject during first tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -393,8 +433,8 @@ void main() {
|
||||
|
||||
tap.addPointer(down1);
|
||||
TestGestureArenaMember member = new TestGestureArenaMember();
|
||||
GestureArenaEntry entry = GestureArena.instance.add(1, member);
|
||||
GestureArena.instance.close(1);
|
||||
GestureArenaEntry entry = gestureArena.add(1, member);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
@ -404,18 +444,18 @@ void main() {
|
||||
entry.resolve(GestureDisposition.accepted);
|
||||
expect(member.accepted, isTrue);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.dispose();
|
||||
@ -423,7 +463,11 @@ void main() {
|
||||
|
||||
test('Should cancel on arena reject between taps', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -432,29 +476,29 @@ void main() {
|
||||
|
||||
tap.addPointer(down1);
|
||||
TestGestureArenaMember member = new TestGestureArenaMember();
|
||||
GestureArenaEntry entry = GestureArena.instance.add(1, member);
|
||||
GestureArena.instance.close(1);
|
||||
GestureArenaEntry entry = gestureArena.add(1, member);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
entry.resolve(GestureDisposition.accepted);
|
||||
expect(member.accepted, isTrue);
|
||||
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.dispose();
|
||||
@ -462,7 +506,11 @@ void main() {
|
||||
|
||||
test('Should cancel on arena reject during last tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -471,19 +519,19 @@ void main() {
|
||||
|
||||
tap.addPointer(down1);
|
||||
TestGestureArenaMember member = new TestGestureArenaMember();
|
||||
GestureArenaEntry entry = GestureArena.instance.add(1, member);
|
||||
GestureArena.instance.close(1);
|
||||
GestureArenaEntry entry = gestureArena.add(1, member);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
@ -493,7 +541,7 @@ void main() {
|
||||
|
||||
router.route(up2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
tap.dispose();
|
||||
@ -501,7 +549,11 @@ void main() {
|
||||
|
||||
test('Passive gesture should trigger on double tap cancel', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool doubleTapRecognized = false;
|
||||
tap.onDoubleTap = () {
|
||||
@ -511,15 +563,15 @@ void main() {
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
tap.addPointer(down1);
|
||||
TestGestureArenaMember member = new TestGestureArenaMember();
|
||||
GestureArena.instance.add(1, member);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.add(1, member);
|
||||
gestureArena.close(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(doubleTapRecognized, isFalse);
|
||||
|
||||
expect(member.accepted, isFalse);
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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:quiver/testing/async.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
@ -15,7 +19,11 @@ const PointerUpEvent up = const PointerUpEvent(
|
||||
void main() {
|
||||
test('Should recognize long press', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool longPressRecognized = false;
|
||||
longPress.onLongPress = () {
|
||||
@ -24,7 +32,7 @@ void main() {
|
||||
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
longPress.addPointer(down);
|
||||
GestureArena.instance.close(5);
|
||||
gestureArena.close(5);
|
||||
expect(longPressRecognized, isFalse);
|
||||
router.route(down);
|
||||
expect(longPressRecognized, isFalse);
|
||||
@ -39,7 +47,11 @@ void main() {
|
||||
|
||||
test('Up cancels long press', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool longPressRecognized = false;
|
||||
longPress.onLongPress = () {
|
||||
@ -48,7 +60,7 @@ void main() {
|
||||
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
longPress.addPointer(down);
|
||||
GestureArena.instance.close(5);
|
||||
gestureArena.close(5);
|
||||
expect(longPressRecognized, isFalse);
|
||||
router.route(down);
|
||||
expect(longPressRecognized, isFalse);
|
||||
@ -65,8 +77,15 @@ void main() {
|
||||
|
||||
test('Should recognize both tap down and long press', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool tapDownRecognized = false;
|
||||
tap.onTapDown = (_) {
|
||||
@ -81,7 +100,7 @@ void main() {
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
tap.addPointer(down);
|
||||
longPress.addPointer(down);
|
||||
GestureArena.instance.close(5);
|
||||
gestureArena.close(5);
|
||||
expect(tapDownRecognized, isFalse);
|
||||
expect(longPressRecognized, isFalse);
|
||||
router.route(down);
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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_test/flutter_test.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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_test/flutter_test.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
@ -5,8 +9,15 @@ import 'package:test/test.dart';
|
||||
void main() {
|
||||
test('Should recognize scale gestures', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
ScaleGestureRecognizer scale = new ScaleGestureRecognizer(router: router);
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
ScaleGestureRecognizer scale = new ScaleGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool didStartScale = false;
|
||||
Point updatedFocalPoint;
|
||||
@ -37,7 +48,7 @@ void main() {
|
||||
scale.addPointer(down);
|
||||
tap.addPointer(down);
|
||||
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(didStartScale, isFalse);
|
||||
expect(updatedScale, isNull);
|
||||
expect(updatedFocalPoint, isNull);
|
||||
@ -67,7 +78,7 @@ void main() {
|
||||
PointerDownEvent down2 = pointer2.down(const Point(10.0, 20.0));
|
||||
scale.addPointer(down2);
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
router.route(down2);
|
||||
|
||||
expect(didEndScale, isTrue);
|
||||
@ -100,7 +111,7 @@ void main() {
|
||||
PointerDownEvent down3 = pointer3.down(const Point(25.0, 35.0));
|
||||
scale.addPointer(down3);
|
||||
tap.addPointer(down3);
|
||||
GestureArena.instance.close(3);
|
||||
gestureArena.close(3);
|
||||
router.route(down3);
|
||||
|
||||
expect(didEndScale, isTrue);
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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_test/flutter_test.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
@ -5,8 +9,15 @@ import 'package:test/test.dart';
|
||||
void main() {
|
||||
test('Should recognize pan', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
PanGestureRecognizer pan = new PanGestureRecognizer(router: router);
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
PanGestureRecognizer pan = new PanGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool didStartPan = false;
|
||||
pan.onStart = (_) {
|
||||
@ -32,7 +43,7 @@ void main() {
|
||||
PointerDownEvent down = pointer.down(const Point(10.0, 10.0));
|
||||
pan.addPointer(down);
|
||||
tap.addPointer(down);
|
||||
GestureArena.instance.close(5);
|
||||
gestureArena.close(5);
|
||||
expect(didStartPan, isFalse);
|
||||
expect(updatedScrollDelta, isNull);
|
||||
expect(didEndPan, isFalse);
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/gestures.dart';
|
||||
import 'package:quiver/testing/async.dart';
|
||||
import 'package:test/test.dart';
|
||||
@ -49,7 +53,11 @@ void main() {
|
||||
|
||||
test('Should recognize tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool tapRecognized = false;
|
||||
tap.onTap = () {
|
||||
@ -57,14 +65,14 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(tapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(tapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(tapRecognized, isTrue);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(tapRecognized, isTrue);
|
||||
|
||||
tap.dispose();
|
||||
@ -72,7 +80,11 @@ void main() {
|
||||
|
||||
test('No duplicate tap events', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
int tapsRecognized = 0;
|
||||
tap.onTap = () {
|
||||
@ -80,25 +92,25 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(tapsRecognized, 0);
|
||||
router.route(down1);
|
||||
expect(tapsRecognized, 0);
|
||||
|
||||
router.route(up1);
|
||||
expect(tapsRecognized, 1);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(tapsRecognized, 1);
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(tapsRecognized, 1);
|
||||
router.route(down1);
|
||||
expect(tapsRecognized, 1);
|
||||
|
||||
router.route(up1);
|
||||
expect(tapsRecognized, 2);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(tapsRecognized, 2);
|
||||
|
||||
tap.dispose();
|
||||
@ -106,7 +118,11 @@ void main() {
|
||||
|
||||
test('Should not recognize two overlapping taps', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
int tapsRecognized = 0;
|
||||
tap.onTap = () {
|
||||
@ -114,13 +130,13 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(tapsRecognized, 0);
|
||||
router.route(down1);
|
||||
expect(tapsRecognized, 0);
|
||||
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
gestureArena.close(2);
|
||||
expect(tapsRecognized, 0);
|
||||
router.route(down1);
|
||||
expect(tapsRecognized, 0);
|
||||
@ -128,12 +144,12 @@ void main() {
|
||||
|
||||
router.route(up1);
|
||||
expect(tapsRecognized, 1);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(tapsRecognized, 1);
|
||||
|
||||
router.route(up2);
|
||||
expect(tapsRecognized, 1);
|
||||
GestureArena.instance.sweep(2);
|
||||
gestureArena.sweep(2);
|
||||
expect(tapsRecognized, 1);
|
||||
|
||||
tap.dispose();
|
||||
@ -141,7 +157,11 @@ void main() {
|
||||
|
||||
test('Distance cancels tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool tapRecognized = false;
|
||||
tap.onTap = () {
|
||||
@ -153,7 +173,7 @@ void main() {
|
||||
};
|
||||
|
||||
tap.addPointer(down3);
|
||||
GestureArena.instance.close(3);
|
||||
gestureArena.close(3);
|
||||
expect(tapRecognized, isFalse);
|
||||
expect(tapCanceled, isFalse);
|
||||
router.route(down3);
|
||||
@ -166,7 +186,7 @@ void main() {
|
||||
router.route(up3);
|
||||
expect(tapRecognized, isFalse);
|
||||
expect(tapCanceled, isTrue);
|
||||
GestureArena.instance.sweep(3);
|
||||
gestureArena.sweep(3);
|
||||
expect(tapRecognized, isFalse);
|
||||
expect(tapCanceled, isTrue);
|
||||
|
||||
@ -175,7 +195,11 @@ void main() {
|
||||
|
||||
test('Timeout does not cancel tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool tapRecognized = false;
|
||||
tap.onTap = () {
|
||||
@ -184,7 +208,7 @@ void main() {
|
||||
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
tap.addPointer(down1);
|
||||
GestureArena.instance.close(1);
|
||||
gestureArena.close(1);
|
||||
expect(tapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(tapRecognized, isFalse);
|
||||
@ -193,7 +217,7 @@ void main() {
|
||||
expect(tapRecognized, isFalse);
|
||||
router.route(up1);
|
||||
expect(tapRecognized, isTrue);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(tapRecognized, isTrue);
|
||||
});
|
||||
|
||||
@ -202,7 +226,11 @@ void main() {
|
||||
|
||||
test('Should yield to other arena members', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool tapRecognized = false;
|
||||
tap.onTap = () {
|
||||
@ -211,16 +239,16 @@ void main() {
|
||||
|
||||
tap.addPointer(down1);
|
||||
TestGestureArenaMember member = new TestGestureArenaMember();
|
||||
GestureArenaEntry entry = GestureArena.instance.add(1, member);
|
||||
GestureArena.instance.hold(1);
|
||||
GestureArena.instance.close(1);
|
||||
GestureArenaEntry entry = gestureArena.add(1, member);
|
||||
gestureArena.hold(1);
|
||||
gestureArena.close(1);
|
||||
expect(tapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(tapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(tapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(tapRecognized, isFalse);
|
||||
|
||||
entry.resolve(GestureDisposition.accepted);
|
||||
@ -231,7 +259,11 @@ void main() {
|
||||
|
||||
test('Should trigger on release of held arena', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
|
||||
GestureArena gestureArena = new GestureArena();
|
||||
TapGestureRecognizer tap = new TapGestureRecognizer(
|
||||
router: router,
|
||||
gestureArena: gestureArena
|
||||
);
|
||||
|
||||
bool tapRecognized = false;
|
||||
tap.onTap = () {
|
||||
@ -240,16 +272,16 @@ void main() {
|
||||
|
||||
tap.addPointer(down1);
|
||||
TestGestureArenaMember member = new TestGestureArenaMember();
|
||||
GestureArenaEntry entry = GestureArena.instance.add(1, member);
|
||||
GestureArena.instance.hold(1);
|
||||
GestureArena.instance.close(1);
|
||||
GestureArenaEntry entry = gestureArena.add(1, member);
|
||||
gestureArena.hold(1);
|
||||
gestureArena.close(1);
|
||||
expect(tapRecognized, isFalse);
|
||||
router.route(down1);
|
||||
expect(tapRecognized, isFalse);
|
||||
|
||||
router.route(up1);
|
||||
expect(tapRecognized, isFalse);
|
||||
GestureArena.instance.sweep(1);
|
||||
gestureArena.sweep(1);
|
||||
expect(tapRecognized, isFalse);
|
||||
|
||||
entry.resolve(GestureDisposition.rejected);
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/gestures.dart';
|
||||
|
||||
const List<PointerEvent> velocityEventData = const <PointerEvent>[
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'velocity_tracker_data.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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:test/test.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/painting.dart';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -1,11 +1,19 @@
|
||||
// Copyright 2015 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/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
const Size _kTestViewSize = const Size(800.0, 600.0);
|
||||
|
||||
class TestRenderView extends RenderView {
|
||||
TestRenderView() {
|
||||
attach();
|
||||
rootConstraints = new ViewConstraints(size: _kTestViewSize);
|
||||
}
|
||||
void scheduleInitialFrame() {
|
||||
scheduleInitialLayout();
|
||||
scheduleInitialPaint(new TransformLayer(transform: new Matrix4.identity()));
|
||||
}
|
||||
@ -17,18 +25,37 @@ enum EnginePhase {
|
||||
composite
|
||||
}
|
||||
|
||||
RenderView _renderView;
|
||||
RenderView get renderView => _renderView;
|
||||
class TestRenderingFlutterBinding extends BindingBase with Scheduler, Renderer, Pointerer {
|
||||
void initRenderView() {
|
||||
if (renderView == null) {
|
||||
renderView = new TestRenderView();
|
||||
renderView.scheduleInitialFrame();
|
||||
}
|
||||
}
|
||||
|
||||
EnginePhase phase = EnginePhase.composite;
|
||||
|
||||
void beginFrame() {
|
||||
RenderObject.flushLayout();
|
||||
if (phase == EnginePhase.layout)
|
||||
return;
|
||||
renderer.renderView.updateCompositingBits();
|
||||
RenderObject.flushPaint();
|
||||
if (phase == EnginePhase.paint)
|
||||
return;
|
||||
renderer.renderView.compositeFrame();
|
||||
}
|
||||
}
|
||||
|
||||
TestRenderingFlutterBinding _renderer;
|
||||
TestRenderingFlutterBinding get renderer => _renderer;
|
||||
|
||||
void layout(RenderBox box, { BoxConstraints constraints, EnginePhase phase: EnginePhase.layout }) {
|
||||
assert(box != null); // if you want to just repump the last box, call pumpFrame().
|
||||
|
||||
if (renderView == null)
|
||||
_renderView = new TestRenderView();
|
||||
|
||||
if (renderView.child != null)
|
||||
renderView.child = null;
|
||||
_renderer ??= new TestRenderingFlutterBinding();
|
||||
|
||||
renderer.renderView.child = null;
|
||||
if (constraints != null) {
|
||||
box = new RenderPositionedBox(
|
||||
child: new RenderConstrainedBox(
|
||||
@ -37,21 +64,15 @@ void layout(RenderBox box, { BoxConstraints constraints, EnginePhase phase: Engi
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
renderView.child = box;
|
||||
renderer.renderView.child = box;
|
||||
|
||||
pumpFrame(phase: phase);
|
||||
}
|
||||
|
||||
void pumpFrame({ EnginePhase phase: EnginePhase.layout }) {
|
||||
RenderObject.flushLayout();
|
||||
if (phase == EnginePhase.layout)
|
||||
return;
|
||||
renderView.updateCompositingBits();
|
||||
RenderObject.flushPaint();
|
||||
if (phase == EnginePhase.paint)
|
||||
return;
|
||||
renderView.compositeFrame();
|
||||
assert(renderer != null);
|
||||
renderer.phase = phase;
|
||||
renderer.beginFrame();
|
||||
}
|
||||
|
||||
class TestCallbackPainter extends CustomPainter {
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Copyright 2015 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/rendering.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@ -26,11 +30,11 @@ void main() {
|
||||
HitTestResult result;
|
||||
|
||||
result = new HitTestResult();
|
||||
renderView.hitTest(result, position: new Point(15.0, 0.0));
|
||||
renderer.renderView.hitTest(result, position: new Point(15.0, 0.0));
|
||||
expect(result.path.first.target.runtimeType, equals(TestRenderView));
|
||||
|
||||
result = new HitTestResult();
|
||||
renderView.hitTest(result, position: new Point(15.0, 15.0));
|
||||
renderer.renderView.hitTest(result, position: new Point(15.0, 15.0));
|
||||
expect(result.path.first.target, equals(green));
|
||||
});
|
||||
}
|
||||
|
@ -1,7 +1,16 @@
|
||||
// Copyright 2015 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/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
class TestSchedulerBinding extends BindingBase with Scheduler { }
|
||||
|
||||
void main() {
|
||||
Scheduler scheduler = new TestSchedulerBinding();
|
||||
|
||||
test("Check for a time dilation being in effect", () {
|
||||
expect(timeDilation, equals(1.0));
|
||||
});
|
||||
|
@ -2,43 +2,52 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This test is disabled because it triggers https://github.com/dart-lang/sdk/issues/25246
|
||||
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
class TestSchedulerBinding extends BindingBase with Scheduler { }
|
||||
|
||||
class TestStrategy implements SchedulingStrategy {
|
||||
int allowedPriority = 10000;
|
||||
|
||||
bool shouldRunTaskWithPriority(int priority) {
|
||||
bool shouldRunTaskWithPriority({ int priority, Scheduler scheduler }) {
|
||||
return priority >= allowedPriority;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
test("Tasks are executed in the right order", () {
|
||||
var strategy = new TestStrategy();
|
||||
Scheduler scheduler = new TestSchedulerBinding();
|
||||
TestStrategy strategy = new TestStrategy();
|
||||
scheduler.schedulingStrategy = strategy;
|
||||
List input = [2, 23, 23, 11, 0, 80, 3];
|
||||
List executedTasks = [];
|
||||
List<int> input = <int>[2, 23, 23, 11, 0, 80, 3];
|
||||
List<int> executedTasks = <int>[];
|
||||
|
||||
void scheduleAddingTask(int x) {
|
||||
scheduler.scheduleTask(() { executedTasks.add(x); }, Priority.idle + x);
|
||||
}
|
||||
|
||||
for (int x in input) {
|
||||
for (int x in input)
|
||||
scheduleAddingTask(x);
|
||||
}
|
||||
|
||||
strategy.allowedPriority = 100;
|
||||
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback();
|
||||
for (int i = 0; i < 3; i += 1)
|
||||
scheduler.handleEventLoopCallback();
|
||||
expect(executedTasks.isEmpty, isTrue);
|
||||
|
||||
strategy.allowedPriority = 50;
|
||||
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback();
|
||||
for (int i = 0; i < 3; i += 1)
|
||||
scheduler.handleEventLoopCallback();
|
||||
expect(executedTasks.length, equals(1));
|
||||
expect(executedTasks.single, equals(80));
|
||||
executedTasks.clear();
|
||||
|
||||
strategy.allowedPriority = 20;
|
||||
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback();
|
||||
for (int i = 0; i < 3; i += 1)
|
||||
scheduler.handleEventLoopCallback();
|
||||
expect(executedTasks.length, equals(2));
|
||||
expect(executedTasks[0], equals(23));
|
||||
expect(executedTasks[1], equals(23));
|
||||
@ -48,21 +57,24 @@ void main() {
|
||||
scheduleAddingTask(19);
|
||||
scheduleAddingTask(5);
|
||||
scheduleAddingTask(97);
|
||||
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback();
|
||||
for (int i = 0; i < 3; i += 1)
|
||||
scheduler.handleEventLoopCallback();
|
||||
expect(executedTasks.length, equals(2));
|
||||
expect(executedTasks[0], equals(99));
|
||||
expect(executedTasks[1], equals(97));
|
||||
executedTasks.clear();
|
||||
|
||||
strategy.allowedPriority = 10;
|
||||
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback();
|
||||
for (int i = 0; i < 3; i += 1)
|
||||
scheduler.handleEventLoopCallback();
|
||||
expect(executedTasks.length, equals(2));
|
||||
expect(executedTasks[0], equals(19));
|
||||
expect(executedTasks[1], equals(11));
|
||||
executedTasks.clear();
|
||||
|
||||
strategy.allowedPriority = 1;
|
||||
for (int i = 0; i < 4; i++) scheduler.handleEventLoopCallback();
|
||||
for (int i = 0; i < 4; i += 1)
|
||||
scheduler.handleEventLoopCallback();
|
||||
expect(executedTasks.length, equals(3));
|
||||
expect(executedTasks[0], equals(5));
|
||||
expect(executedTasks[1], equals(3));
|
@ -4,7 +4,6 @@
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@ -65,9 +64,9 @@ void main() {
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
expect(tester.binding.transientCallbackCount, 0);
|
||||
tester.pump(new Duration(seconds: 1));
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
expect(tester.binding.transientCallbackCount, 0);
|
||||
tester.pumpWidget(
|
||||
new AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
@ -76,9 +75,9 @@ void main() {
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
expect(tester.binding.transientCallbackCount, 0);
|
||||
tester.pump(new Duration(seconds: 1));
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
expect(tester.binding.transientCallbackCount, 0);
|
||||
tester.pumpWidget(
|
||||
new AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
@ -87,9 +86,9 @@ void main() {
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(scheduler.transientCallbackCount, 1); // this is the only time an animation should have started!
|
||||
expect(tester.binding.transientCallbackCount, 1); // this is the only time an animation should have started!
|
||||
tester.pump(new Duration(seconds: 1));
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
expect(tester.binding.transientCallbackCount, 0);
|
||||
tester.pumpWidget(
|
||||
new AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
@ -98,7 +97,7 @@ void main() {
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
expect(tester.binding.transientCallbackCount, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user