|
|
|
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using RSG; |
|
|
|
using Unity.UIWidgets.animation; |
|
|
|
using Unity.UIWidgets.foundation; |
|
|
|
using Unity.UIWidgets.gestures; |
|
|
|
|
|
|
|
|
|
|
namespace Unity.UIWidgets.widgets { |
|
|
|
public delegate void DismissDirectionCallback(DismissDirection? direction); |
|
|
|
|
|
|
|
public delegate Promise<bool> ConfirmDismissCallback(DismissDirection? direction); |
|
|
|
|
|
|
|
public enum DismissDirection { |
|
|
|
vertical, |
|
|
|
|
|
|
Widget child = null, |
|
|
|
Widget background = null, |
|
|
|
Widget secondaryBackground = null, |
|
|
|
ConfirmDismissCallback confirmDismiss = null, |
|
|
|
VoidCallback onResize = null, |
|
|
|
DismissDirectionCallback onDismissed = null, |
|
|
|
DismissDirection direction = DismissDirection.horizontal, |
|
|
|
|
|
|
float crossAxisEndOffset = 0.0f |
|
|
|
float crossAxisEndOffset = 0.0f, |
|
|
|
DragStartBehavior dragStartBehavior = DragStartBehavior.down |
|
|
|
) : base(key: key) { |
|
|
|
D.assert(key != null); |
|
|
|
D.assert(secondaryBackground != null ? background != null : true); |
|
|
|
|
|
|
this.child = child; |
|
|
|
this.background = background; |
|
|
|
this.secondaryBackground = secondaryBackground; |
|
|
|
this.confirmDismiss = confirmDismiss; |
|
|
|
this.dragStartBehavior = dragStartBehavior; |
|
|
|
} |
|
|
|
|
|
|
|
public readonly Widget child; |
|
|
|
|
|
|
|
|
|
|
public readonly DismissDirectionCallback onDismissed; |
|
|
|
|
|
|
|
public readonly ConfirmDismissCallback confirmDismiss; |
|
|
|
|
|
|
|
public readonly TimeSpan resizeDuration; |
|
|
|
public readonly TimeSpan? resizeDuration; |
|
|
|
public readonly TimeSpan movementDuration; |
|
|
|
public readonly TimeSpan? movementDuration; |
|
|
|
|
|
|
|
public readonly DragStartBehavior dragStartBehavior; |
|
|
|
|
|
|
|
public override State createState() { |
|
|
|
return new _DismissibleState(); |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this._dragUnderway = false; |
|
|
|
if (this._moveController.isCompleted) { |
|
|
|
this._startResizeAnimation(); |
|
|
|
return; |
|
|
|
} |
|
|
|
this._confirmStartResizeAnimation().Then((value) => { |
|
|
|
if (this._moveController.isCompleted && value) { |
|
|
|
this._startResizeAnimation(); |
|
|
|
} |
|
|
|
else { |
|
|
|
float flingVelocity = this._directionIsXAxis |
|
|
|
? details.velocity.pixelsPerSecond.dx |
|
|
|
: details.velocity.pixelsPerSecond.dy; |
|
|
|
switch (this._describeFlingGesture(details.velocity)) { |
|
|
|
case _FlingGestureKind.forward: |
|
|
|
D.assert(this._dragExtent != 0.0f); |
|
|
|
D.assert(!this._moveController.isDismissed); |
|
|
|
if ((this.widget.dismissThresholds.getOrDefault(this._dismissDirection) ?? |
|
|
|
_kDismissThreshold) >= 1.0) { |
|
|
|
this._moveController.reverse(); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
this._dragExtent = flingVelocity.sign(); |
|
|
|
this._moveController.fling(velocity: flingVelocity.abs() * _kFlingVelocityScale); |
|
|
|
break; |
|
|
|
case _FlingGestureKind.reverse: |
|
|
|
D.assert(this._dragExtent != 0.0f); |
|
|
|
D.assert(!this._moveController.isDismissed); |
|
|
|
this._dragExtent = flingVelocity.sign(); |
|
|
|
this._moveController.fling(velocity: -flingVelocity.abs() * _kFlingVelocityScale); |
|
|
|
break; |
|
|
|
case _FlingGestureKind.none: |
|
|
|
if (!this._moveController.isDismissed) { |
|
|
|
// we already know it's not completed, we check that above
|
|
|
|
if (this._moveController.value > |
|
|
|
(this.widget.dismissThresholds.getOrDefault(this._dismissDirection) ?? |
|
|
|
_kDismissThreshold)) { |
|
|
|
this._moveController.forward(); |
|
|
|
} |
|
|
|
else { |
|
|
|
this._moveController.reverse(); |
|
|
|
} |
|
|
|
} |
|
|
|
float flingVelocity = this._directionIsXAxis |
|
|
|
? details.velocity.pixelsPerSecond.dx |
|
|
|
: details.velocity.pixelsPerSecond.dy; |
|
|
|
switch (this._describeFlingGesture(details.velocity)) { |
|
|
|
case _FlingGestureKind.forward: |
|
|
|
D.assert(this._dragExtent != 0.0f); |
|
|
|
D.assert(!this._moveController.isDismissed); |
|
|
|
if ((this.widget.dismissThresholds.getOrDefault(this._dismissDirection) ?? _kDismissThreshold) >= 1.0) { |
|
|
|
this._moveController.reverse(); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
this._dragExtent = flingVelocity.sign(); |
|
|
|
this._moveController.fling(velocity: flingVelocity.abs() * _kFlingVelocityScale); |
|
|
|
break; |
|
|
|
case _FlingGestureKind.reverse: |
|
|
|
D.assert(this._dragExtent != 0.0); |
|
|
|
D.assert(!this._moveController.isDismissed); |
|
|
|
this._dragExtent = flingVelocity.sign(); |
|
|
|
this._moveController.fling(velocity: -flingVelocity.abs() * _kFlingVelocityScale); |
|
|
|
break; |
|
|
|
case _FlingGestureKind.none: |
|
|
|
if (!this._moveController.isDismissed) { |
|
|
|
// we already know it's not completed, we check that above
|
|
|
|
if (this._moveController.value > |
|
|
|
(this.widget.dismissThresholds.getOrDefault(this._dismissDirection) ?? _kDismissThreshold)) { |
|
|
|
this._moveController.forward(); |
|
|
|
} |
|
|
|
else { |
|
|
|
this._moveController.reverse(); |
|
|
|
} |
|
|
|
void _handleDismissStatusChanged(AnimationStatus status) { |
|
|
|
if (status == AnimationStatus.completed && !this._dragUnderway) { |
|
|
|
this._confirmStartResizeAnimation().Then((value) => { |
|
|
|
if (value) { |
|
|
|
this._startResizeAnimation(); |
|
|
|
} |
|
|
|
else { |
|
|
|
this._moveController.reverse(); |
|
|
|
break; |
|
|
|
this.updateKeepAlive(); |
|
|
|
}); |
|
|
|
void _handleDismissStatusChanged(AnimationStatus status) { |
|
|
|
if (status == AnimationStatus.completed && !this._dragUnderway) { |
|
|
|
this._startResizeAnimation(); |
|
|
|
IPromise<bool> _confirmStartResizeAnimation() { |
|
|
|
if (this.widget.confirmDismiss != null) { |
|
|
|
DismissDirection? direction = this._dismissDirection; |
|
|
|
D.assert(direction != null); |
|
|
|
return this.widget.confirmDismiss(direction); |
|
|
|
this.updateKeepAlive(); |
|
|
|
return Promise<bool>.Resolved(true); |
|
|
|
} |
|
|
|
|
|
|
|
void _startResizeAnimation() { |
|
|
|
|
|
|
: (GestureDragUpdateCallback) this._handleDragUpdate, |
|
|
|
onVerticalDragEnd: this._directionIsXAxis ? null : (GestureDragEndCallback) this._handleDragEnd, |
|
|
|
behavior: HitTestBehavior.opaque, |
|
|
|
child: content |
|
|
|
child: content, |
|
|
|
dragStartBehavior: this.widget.dragStartBehavior |
|
|
|
); |
|
|
|
} |
|
|
|
} |