Skip to content

Commit

Permalink
feat: add SwipeDismissConfig for modals
Browse files Browse the repository at this point in the history
  • Loading branch information
ice-orion committed Aug 20, 2024
1 parent 05edf0e commit 9b860b8
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 40 deletions.
21 changes: 6 additions & 15 deletions package/lib/src/modal/cupertino.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter/rendering.dart';
import '../foundation/sheet_controller.dart';
import '../internal/double_utils.dart';
import 'modal_sheet.dart';
import 'swipe_dismiss_config.dart';

const _minimizedViewportScale = 0.92;
const _cupertinoBarrierColor = Color(0x18000000);
Expand Down Expand Up @@ -422,8 +423,7 @@ class CupertinoModalSheetPage<T> extends Page<T> {
this.barrierColor = _cupertinoBarrierColor,
this.transitionDuration = _cupertinoTransitionDuration,
this.transitionCurve = _cupertinoTransitionCurve,
this.minFlingVelocityToDismiss = 1.0,
this.minDragDistanceToDismiss = 100.0,
this.swipeDismissConfig = const SwipeDismissConfig(),
required this.child,
});

Expand All @@ -447,9 +447,7 @@ class CupertinoModalSheetPage<T> extends Page<T> {

final Curve transitionCurve;

final double minFlingVelocityToDismiss;

final double minDragDistanceToDismiss;
final SwipeDismissConfig swipeDismissConfig;

@override
Route<T> createRoute(BuildContext context) {
Expand Down Expand Up @@ -492,10 +490,7 @@ class _PageBasedCupertinoModalSheetRoute<T>
Duration get transitionDuration => _page.transitionDuration;

@override
double get minFlingVelocityToDismiss => _page.minFlingVelocityToDismiss;

@override
double get minDragDistanceToDismiss => _page.minDragDistanceToDismiss;
SwipeDismissConfig get swipeDismissConfig => _page.swipeDismissConfig;

@override
String get debugLabel => '${super.debugLabel}(${_page.name})';
Expand All @@ -516,8 +511,7 @@ class CupertinoModalSheetRoute<T> extends _BaseCupertinoModalSheetRoute<T> {
this.barrierColor = _cupertinoBarrierColor,
this.transitionDuration = _cupertinoTransitionDuration,
this.transitionCurve = _cupertinoTransitionCurve,
this.minFlingVelocityToDismiss = 1.0,
this.minDragDistanceToDismiss = 100.0,
this.swipeDismissConfig = const SwipeDismissConfig(),
});

final WidgetBuilder builder;
Expand All @@ -544,10 +538,7 @@ class CupertinoModalSheetRoute<T> extends _BaseCupertinoModalSheetRoute<T> {
final Curve transitionCurve;

@override
final double minFlingVelocityToDismiss;

@override
final double minDragDistanceToDismiss;
final SwipeDismissConfig swipeDismissConfig;

@override
Widget buildContent(BuildContext context) {
Expand Down
1 change: 1 addition & 0 deletions package/lib/src/modal/modal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export 'cupertino.dart'
CupertinoStackedTransition;
export 'modal_sheet.dart'
show ModalSheetPage, ModalSheetRoute, ModalSheetRouteMixin;
export 'swipe_dismiss_config.dart' show SwipeDismissConfig;
37 changes: 12 additions & 25 deletions package/lib/src/modal/modal_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import '../foundation/sheet_drag.dart';
import '../foundation/sheet_gesture_tamperer.dart';
import '../internal/float_comp.dart';
import 'swipe_dismiss_config.dart';

const _minReleasedPageForwardAnimationTime = 300; // Milliseconds.
const _releasedPageForwardAnimationCurve = Curves.fastLinearToSlowEaseIn;
Expand All @@ -24,8 +25,7 @@ class ModalSheetPage<T> extends Page<T> {
this.barrierColor = Colors.black54,
this.transitionDuration = const Duration(milliseconds: 300),
this.transitionCurve = Curves.fastEaseInToSlowEaseOut,
this.minFlingVelocityToDismiss = 1.0,
this.minDragDistanceToDismiss = 100.0,
this.swipeDismissConfig = const SwipeDismissConfig(),
required this.child,
});

Expand All @@ -49,9 +49,7 @@ class ModalSheetPage<T> extends Page<T> {

final Curve transitionCurve;

final double minFlingVelocityToDismiss;

final double minDragDistanceToDismiss;
final SwipeDismissConfig swipeDismissConfig;

@override
Route<T> createRoute(BuildContext context) {
Expand Down Expand Up @@ -93,10 +91,7 @@ class _PageBasedModalSheetRoute<T> extends PageRoute<T>
Duration get transitionDuration => _page.transitionDuration;

@override
double get minFlingVelocityToDismiss => _page.minFlingVelocityToDismiss;

@override
double get minDragDistanceToDismiss => _page.minDragDistanceToDismiss;
SwipeDismissConfig get swipeDismissConfig => _page.swipeDismissConfig;

@override
String get debugLabel => '${super.debugLabel}(${_page.name})';
Expand All @@ -117,8 +112,7 @@ class ModalSheetRoute<T> extends PageRoute<T> with ModalSheetRouteMixin<T> {
this.swipeDismissible = false,
this.transitionDuration = const Duration(milliseconds: 300),
this.transitionCurve = Curves.fastEaseInToSlowEaseOut,
this.minFlingVelocityToDismiss = 1.0,
this.minDragDistanceToDismiss = 100.0,
this.swipeDismissConfig = const SwipeDismissConfig(),
});

final WidgetBuilder builder;
Expand All @@ -145,10 +139,7 @@ class ModalSheetRoute<T> extends PageRoute<T> with ModalSheetRouteMixin<T> {
final Curve transitionCurve;

@override
final double minFlingVelocityToDismiss;

@override
final double minDragDistanceToDismiss;
final SwipeDismissConfig swipeDismissConfig;

@override
Widget buildContent(BuildContext context) {
Expand All @@ -159,8 +150,7 @@ class ModalSheetRoute<T> extends PageRoute<T> with ModalSheetRouteMixin<T> {
mixin ModalSheetRouteMixin<T> on ModalRoute<T> {
bool get swipeDismissible;
Curve get transitionCurve;
double get minFlingVelocityToDismiss;
double get minDragDistanceToDismiss;
SwipeDismissConfig get swipeDismissConfig;

@override
bool get opaque => false;
Expand All @@ -169,8 +159,7 @@ mixin ModalSheetRouteMixin<T> on ModalRoute<T> {
late final _swipeDismissibleController = _SwipeDismissibleController(
route: this,
transitionController: controller!,
minFlingVelocityToDismiss: minFlingVelocityToDismiss,
minDragDistanceToDismiss: minDragDistanceToDismiss,
swipeDismissConfig: swipeDismissConfig,
);

Widget buildContent(BuildContext context);
Expand Down Expand Up @@ -248,14 +237,12 @@ class _SwipeDismissibleController with SheetGestureTamperer {
_SwipeDismissibleController({
required this.route,
required this.transitionController,
required this.minFlingVelocityToDismiss,
required this.minDragDistanceToDismiss,
required this.swipeDismissConfig,
});

final ModalRoute<dynamic> route;
final AnimationController transitionController;
final double minFlingVelocityToDismiss;
final double minDragDistanceToDismiss;
final SwipeDismissConfig swipeDismissConfig;

BuildContext get _context => route.subtreeContext!;

Expand Down Expand Up @@ -370,12 +357,12 @@ class _SwipeDismissibleController with SheetGestureTamperer {
invokePop = false;
} else if (effectiveVelocity < 0) {
// Flings down.
invokePop = effectiveVelocity.abs() > minFlingVelocityToDismiss;
invokePop = effectiveVelocity.abs() > swipeDismissConfig.minFlingVelocity;
} else if (FloatComp.velocity(MediaQuery.devicePixelRatioOf(_context))
.isApprox(effectiveVelocity, 0)) {
assert(draggedDistance >= 0);
// Dragged down enough to dismiss.
invokePop = draggedDistance > minDragDistanceToDismiss;
invokePop = draggedDistance > swipeDismissConfig.minDragDistance;
} else {
// Flings up.
invokePop = false;
Expand Down
33 changes: 33 additions & 0 deletions package/lib/src/modal/swipe_dismiss_config.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/// Configuration class for handling swipe-to-dismiss gestures.
///
/// The [SwipeDismissConfig] class provides parameters to control the behavior
/// of swipe-to-dismiss interactions for modals. It defines the minimum velocity
/// required for the swipe gesture ([minFlingVelocity]) and the minimum distance
/// the user needs to drag ([minDragDistance]) for a swipe to result in a dismissal.
class SwipeDismissConfig {
const SwipeDismissConfig({
this.minFlingVelocity = 1.0,
this.minDragDistance = 300.0,
});

/// The minimum velocity that a fling gesture must reach to trigger a dismissal.
final double minFlingVelocity;

/// The minimum distance that must be dragged before the modal is dismissed.
final double minDragDistance;

@override
bool operator ==(covariant SwipeDismissConfig other) {
if (identical(this, other)) return true;

return
other.minFlingVelocity == minFlingVelocity &&
other.minDragDistance == minDragDistance;
}

@override
int get hashCode => minFlingVelocity.hashCode ^ minDragDistance.hashCode;

@override
String toString() => 'SwipeDismissConfig(minFlingVelocity: $minFlingVelocity, minDragDistance: $minDragDistance)';
}

0 comments on commit 9b860b8

Please sign in to comment.