Skip to content

Commit

Permalink
Dispatch drag cancel notification
Browse files Browse the repository at this point in the history
  • Loading branch information
fujidaiti committed Jul 23, 2024
1 parent b7b2195 commit 9c711a9
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 32 deletions.
7 changes: 7 additions & 0 deletions package/lib/src/foundation/sheet_activity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@ class DragSheetActivity extends SheetActivity
..didDragEnd(details)
..goBallistic(details.velocityY);
}

@override
void onDragCancel(SheetDragCancelDetails details) {
owner
..didDragCancel()
..goBallistic(0);
}
}

@internal
Expand Down
70 changes: 49 additions & 21 deletions package/lib/src/foundation/sheet_drag.dart
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,22 @@ class SheetDragEndDetails extends SheetDragDetails {
}
}

/// Details for when a sheet drag is canceled.
class SheetDragCancelDetails extends SheetDragDetails {
/// Creates details for when a sheet drag is canceled.
SheetDragCancelDetails({required super.axisDirection});
}

@internal
abstract class SheetDragControllerTarget {
VerticalDirection get dragAxisDirection;
// TODO: Rename to onDragUpdate.
void applyUserDragUpdate(SheetDragUpdateDetails details);
// TODO: Rename to onDragEnd.
void applyUserDragEnd(SheetDragEndDetails details);

void onDragCancel(SheetDragCancelDetails details);

/// Returns the minimum number of pixels that the sheet being dragged
/// will potentially consume for the given drag delta.
///
Expand Down Expand Up @@ -265,12 +275,18 @@ class SheetDragController implements Drag, ScrollActivityDelegate {
/// to avoid duplicating the code of [ScrollDragController].
late final ScrollDragController _impl;

// TODO: Remove unnecessary nullability.
SheetDragControllerTarget? _target;

// TODO: Rename to _gestureProxy.
SheetGestureTamperer? _gestureTamperer;

SheetDragDetails _lastDetails;
/// The details of the most recently observed drag event.
SheetDragDetails get lastDetails => _lastDetails;
SheetDragDetails _lastDetails;

/// The most recently observed [DragStartDetails], [DragUpdateDetails], or
/// [DragEndDetails] object.
dynamic get lastRawDetails => _impl.lastDetails;

void updateTarget(SheetDragControllerTarget delegate) {
Expand All @@ -296,29 +312,29 @@ class SheetDragController implements Drag, ScrollActivityDelegate {
_impl.cancel();
}

/// Called by the [ScrollDragController] in [Drag.end] and [Drag.cancel].
/// Called by the [ScrollDragController] in either [ScrollDragController.end]
/// or [ScrollDragController.cancel].
@override
void goBallistic(double velocity) {
var details = switch (_impl.lastDetails) {
final DragEndDetails details => SheetDragEndDetails(
axisDirection: _target!.dragAxisDirection,
velocityX: details.velocity.pixelsPerSecond.dx,
velocityY: -1 * velocity,
),
// Drag was canceled.
_ => SheetDragEndDetails(
axisDirection: _target!.dragAxisDirection,
velocityX: 0,
velocityY: 0,
),
};

if (_gestureTamperer case final tamper?) {
details = tamper.tamperWithDragEnd(details);
if (_impl.lastDetails case final DragEndDetails rawDetails) {
var endDetails = SheetDragEndDetails(
axisDirection: _target!.dragAxisDirection,
velocityX: rawDetails.velocity.pixelsPerSecond.dx,
velocityY: -1 * velocity,
);
if (_gestureTamperer case final tamper?) {
endDetails = tamper.tamperWithDragEnd(endDetails);
}
_lastDetails = endDetails;
_target!.applyUserDragEnd(endDetails);
} else {
final cancelDetails = SheetDragCancelDetails(
axisDirection: _target!.dragAxisDirection,
);
_lastDetails = cancelDetails;
_gestureTamperer?.onDragCancel(cancelDetails);
_target!.onDragCancel(cancelDetails);
}

_lastDetails = details;
_target!.applyUserDragEnd(details);
}

/// Called by the [ScrollDragController] in [Drag.update].
Expand Down Expand Up @@ -373,6 +389,18 @@ class SheetDragController implements Drag, ScrollActivityDelegate {

@mustCallSuper
void dispose() {
// If the controller is disposed without calling end() or cancel(),
// we assume that the drag has been canceled.
if (_lastDetails is! SheetDragCancelDetails &&
_lastDetails is! SheetDragEndDetails) {
final cancelDetails = SheetDragCancelDetails(
axisDirection: _target!.dragAxisDirection,
);
_lastDetails = cancelDetails;
_gestureTamperer?.onDragCancel(cancelDetails);
_target!.onDragCancel(cancelDetails);
}

_target = null;
_gestureTamperer = null;
_impl.dispose();
Expand Down
11 changes: 11 additions & 0 deletions package/lib/src/foundation/sheet_gesture_tamperer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:meta/meta.dart';
import 'sheet_drag.dart';

// TODO: Expose this as a public API.
// TODO: Rename to SheetGestureProxy.
@internal
class TamperSheetGesture extends StatefulWidget {
const TamperSheetGesture({
Expand Down Expand Up @@ -54,6 +55,7 @@ class _TamperSheetGestureState extends State<TamperSheetGesture> {
}
}

// TODO: Rename to SheetGestureProxyScope.
class _TamperSheetGestureScope extends InheritedWidget {
const _TamperSheetGestureScope({
required this.tamperer,
Expand All @@ -68,6 +70,7 @@ class _TamperSheetGestureScope extends InheritedWidget {
}

// TODO: Expose this as a public API.
// TODO: Rename to SheetGestureProxyMixin.
@internal
mixin SheetGestureTamperer {
SheetGestureTamperer? _parent;
Expand All @@ -79,12 +82,14 @@ mixin SheetGestureTamperer {

@useResult
@mustCallSuper
// TODO: Rename to onDragStart.
SheetDragStartDetails tamperWithDragStart(SheetDragStartDetails details) {
return _parent?.tamperWithDragStart(details) ?? details;
}

@useResult
@mustCallSuper
// TODO: Rename to onDragUpdate.
SheetDragUpdateDetails tamperWithDragUpdate(
SheetDragUpdateDetails details,
Offset minPotentialDeltaConsumption,
Expand All @@ -100,7 +105,13 @@ mixin SheetGestureTamperer {

@useResult
@mustCallSuper
// TODO: Rename to onDragEnd.
SheetDragEndDetails tamperWithDragEnd(SheetDragEndDetails details) {
return _parent?.tamperWithDragEnd(details) ?? details;
}

@mustCallSuper
void onDragCancel(SheetDragCancelDetails details) {
_parent?.onDragCancel(details);
}
}
41 changes: 30 additions & 11 deletions package/lib/src/modal/modal_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -302,28 +302,49 @@ class _SwipeDismissibleController with SheetGestureTamperer {

@override
SheetDragEndDetails tamperWithDragEnd(SheetDragEndDetails details) {
final wasHandled = _handleDragEnd(
velocity: details.velocity,
axisDirection: details.axisDirection,
);
return wasHandled
? super.tamperWithDragEnd(details.copyWith(velocityX: 0, velocityY: 0))
: super.tamperWithDragEnd(details);
}

@override
void onDragCancel(SheetDragCancelDetails details) {
super.onDragCancel(details);
_handleDragEnd(
axisDirection: details.axisDirection,
velocity: Velocity.zero,
);
}

bool _handleDragEnd({
required Velocity velocity,
required VerticalDirection axisDirection,
}) {
if (!_isUserGestureInProgress || transitionController.isAnimating) {
return super.tamperWithDragEnd(details);
return false;
}

final viewportHeight = _context.size!.height;
final draggedDistance = viewportHeight * (1 - transitionController.value);

final velocity = switch (details.axisDirection) {
VerticalDirection.up =>
details.velocity.pixelsPerSecond.dy / viewportHeight,
final effectiveVelocity = switch (axisDirection) {
VerticalDirection.up => velocity.pixelsPerSecond.dy / viewportHeight,
VerticalDirection.down =>
-1 * details.velocity.pixelsPerSecond.dy / viewportHeight,
-1 * velocity.pixelsPerSecond.dy / viewportHeight,
};

final bool invokePop;
if (MediaQuery.viewInsetsOf(_context).bottom > 0) {
// The on-screen keyboard is open.
invokePop = false;
} else if (velocity < 0) {
} else if (effectiveVelocity < 0) {
// Flings down.
invokePop = velocity.abs() > _minFlingVelocityToDismiss;
} else if (velocity.isApprox(0)) {
invokePop = effectiveVelocity.abs() > _minFlingVelocityToDismiss;
} else if (effectiveVelocity.isApprox(0)) {
assert(draggedDistance >= 0);
// Dragged down enough to dismiss.
invokePop = draggedDistance > _minDragDistanceToDismiss;
Expand Down Expand Up @@ -372,8 +393,6 @@ class _SwipeDismissibleController with SheetGestureTamperer {
route.onPopInvoked(didPop);
}

return super.tamperWithDragEnd(
details.copyWith(velocityX: 0, velocityY: 0),
);
return true;
}
}
10 changes: 10 additions & 0 deletions package/lib/src/scrollable/scrollable_sheet_activity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,16 @@ class DragScrollDrivenSheetActivity extends ScrollableSheetActivity
scrollPosition: scrollPosition,
);
}

@override
void onDragCancel(SheetDragCancelDetails details) {
owner
..didDragCancel()
..goBallisticWithScrollPosition(
velocity: 0,
scrollPosition: scrollPosition,
);
}
}

/// A [SheetActivity] that animates either a scrollable content of
Expand Down

0 comments on commit 9c711a9

Please sign in to comment.