Commit 8ff19827 authored by Andrew Wilson's avatar Andrew Wilson Committed by Andrew P. Wilson

Allow Draggables to drop through DragTargets that don't accept them to one that does.

parent d5deea49
......@@ -391,7 +391,7 @@ class _DragAvatar<T> extends Drag {
final _OnDragEnd onDragEnd;
_DragTargetState<T> _activeTarget;
bool _activeTargetWillAcceptDrop = false;
List<_DragTargetState<T>> _lastTargets = <_DragTargetState<T>>[];
Point _position;
Offset _lastOffset;
OverlayEntry _entry;
......@@ -418,32 +418,58 @@ class _DragAvatar<T> extends Drag {
_entry.markNeedsBuild();
HitTestResult result = new HitTestResult();
WidgetFlutterBinding.instance.hitTest(result, globalPosition + feedbackOffset);
_DragTargetState<T> target = _getDragTarget(result.path);
if (target == _activeTarget)
List<_DragTargetState<T>> targets = _getDragTargets(result.path).toList();
bool listsMatch = false;
if (targets.length >= _lastTargets.length && _lastTargets.isNotEmpty) {
listsMatch = true;
Iterator<_DragTargetState<T>> iterator = targets.iterator;
for (int i = 0; i < _lastTargets.length; i += 1) {
iterator.moveNext();
if (iterator.current != _lastTargets[i]) {
listsMatch = false;
break;
}
}
}
// If everything's the same, bail early.
if (listsMatch)
return;
if (_activeTarget != null)
_activeTarget.didLeave(data);
_activeTarget = target;
_activeTargetWillAcceptDrop = _activeTarget != null && _activeTarget.didEnter(data);
// Leave old targets.
for (int i = 0; i < _lastTargets.length; i += 1)
_lastTargets[i].didLeave(data);
_lastTargets.clear();
// Enter new targets.
_DragTargetState<T> newTarget = targets.firstWhere((_DragTargetState<T> target) {
_lastTargets.add(target);
return target.didEnter(data);
},
orElse: () => null
);
_activeTarget = newTarget;
}
_DragTargetState<T> _getDragTarget(List<HitTestEntry> path) {
// Look for the RenderBox that corresponds to the hit target (the hit target
// widget builds a RenderMetadata box for us for this purpose).
Iterable<_DragTargetState<T>> _getDragTargets(List<HitTestEntry> path) sync* {
// Look for the RenderBoxes that corresponds to the hit target (the hit target
// widgets build RenderMetadata boxes for us for this purpose).
for (HitTestEntry entry in path) {
if (entry.target is RenderMetaData) {
RenderMetaData renderMetaData = entry.target;
if (renderMetaData.metaData is _DragTargetState<T>)
return renderMetaData.metaData;
yield renderMetaData.metaData;
}
}
return null;
}
void finish(_DragEndKind endKind, [Velocity velocity]) {
bool wasAccepted = false;
if (_activeTarget != null) {
if (endKind == _DragEndKind.dropped && _activeTargetWillAcceptDrop) {
if (endKind == _DragEndKind.dropped && _activeTarget != null) {
_activeTarget.didDrop(data);
wasAccepted = true;
} else {
......@@ -451,7 +477,6 @@ class _DragAvatar<T> extends Drag {
}
}
_activeTarget = null;
_activeTargetWillAcceptDrop = false;
_entry.remove();
_entry = null;
// TODO(ianh): consider passing _entry as well so the client can perform an animation.
......
......@@ -753,4 +753,123 @@ void main() {
expect(onDraggableCanceledOffset, equals(new Offset(flingStart.x, flingStart.y) + new Offset(0.0, 100.0)));
});
});
test('Drag and drop - allow pass thru of unaccepted data test', () {
testWidgets((WidgetTester tester) {
List<int> acceptedInts = <int>[];
List<double> acceptedDoubles = <double>[];
tester.pumpWidget(new MaterialApp(
routes: <String, WidgetBuilder>{
'/': (BuildContext context) { return new Column(
children: <Widget>[
new Draggable<int>(
data: 1,
child: new Text('IntSource'),
feedback: new Text('IntDragging')
),
new Draggable<double>(
data: 1.0,
child: new Text('DoubleSource'),
feedback: new Text('DoubleDragging')
),
new Stack(children:[
new DragTarget<int>(
builder: (BuildContext context, List<int> data, List<dynamic> rejects) {
return new IgnorePointer(
child: new Container(
height: 100.0,
child: new Text('Target1')
)
);
},
onAccept: (int data) {
acceptedInts.add(data);
}
),
new DragTarget<double>(
builder: (BuildContext context, List<double> data, List<dynamic> rejects) {
return new IgnorePointer(
child: new Container(
height: 100.0,
child: new Text('Target2')
)
);
},
onAccept: (double data) {
acceptedDoubles.add(data);
}
),
])
]);
},
}
));
expect(acceptedInts, isEmpty);
expect(acceptedDoubles, isEmpty);
expect(tester.findText('IntSource'), isNotNull);
expect(tester.findText('IntDragging'), isNull);
expect(tester.findText('DoubleSource'), isNotNull);
expect(tester.findText('DoubleDragging'), isNull);
expect(tester.findText('Target1'), isNotNull);
expect(tester.findText('Target2'), isNotNull);
Point intLocation = tester.getCenter(tester.findText('IntSource'));
Point doubleLocation = tester.getCenter(tester.findText('DoubleSource'));
Point targetLocation = tester.getCenter(tester.findText('Target1'));
// Drag the double draggable.
TestGesture doubleGesture = tester.startGesture(doubleLocation, pointer: 7);
tester.pump();
expect(acceptedInts, isEmpty);
expect(acceptedDoubles, isEmpty);
expect(tester.findText('IntDragging'), isNull);
expect(tester.findText('DoubleDragging'), isNotNull);
doubleGesture.moveTo(targetLocation);
tester.pump();
expect(acceptedInts, isEmpty);
expect(acceptedDoubles, isEmpty);
expect(tester.findText('IntDragging'), isNull);
expect(tester.findText('DoubleDragging'), isNotNull);
doubleGesture.up();
tester.pump();
expect(acceptedInts, isEmpty);
expect(acceptedDoubles, equals(<double>[1.0]));
expect(tester.findText('IntDragging'), isNull);
expect(tester.findText('DoubleDragging'), isNull);
acceptedDoubles.clear();
// Drag the int draggable.
TestGesture intGesture = tester.startGesture(intLocation, pointer: 7);
tester.pump();
expect(acceptedInts, isEmpty);
expect(acceptedDoubles, isEmpty);
expect(tester.findText('IntDragging'), isNotNull);
expect(tester.findText('DoubleDragging'), isNull);
intGesture.moveTo(targetLocation);
tester.pump();
expect(acceptedInts, isEmpty);
expect(acceptedDoubles, isEmpty);
expect(tester.findText('IntDragging'), isNotNull);
expect(tester.findText('DoubleDragging'), isNull);
intGesture.up();
tester.pump();
expect(acceptedInts, equals(<int>[1]));
expect(acceptedDoubles, isEmpty);
expect(tester.findText('IntDragging'), isNull);
expect(tester.findText('DoubleDragging'), isNull);
});
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment