Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add swipe dismiss sensitivity params for modals #222

Merged
merged 23 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
05edf0e
feat: add dismiss configuration params to modals
ice-orion Aug 20, 2024
9b860b8
feat: add SwipeDismissConfig for modals
ice-orion Aug 20, 2024
c370e7d
Merge branch 'main' into feature/modal-dismiss-params
ice-orion Aug 20, 2024
fdceb2c
refactor: rename SwipeDismissConfig, remove util class methods
ice-orion Aug 22, 2024
cc59aed
chore: format code
ice-orion Aug 23, 2024
81b7145
chore: bump version to 0.10.0, add swipeDismissSensitivity example usage
ice-orion Aug 23, 2024
836ce27
Rename swipeDismissSensitivity → sensitivity
fujidaiti Aug 23, 2024
b3b053d
Fix 80-chars warning
fujidaiti Aug 23, 2024
896d56a
format
fujidaiti Aug 23, 2024
a9a1c80
Use raw velocity rather than ratio for threshold
fujidaiti Aug 23, 2024
4c045b0
Revert "Use raw velocity rather than ratio for threshold"
fujidaiti Aug 23, 2024
42fe562
Rename minFlingVelocity to minFlingVelocityRatio
fujidaiti Aug 23, 2024
20e59a6
Tweak default ratio threshold
fujidaiti Aug 23, 2024
5e45637
Doc improvement
fujidaiti Aug 23, 2024
587ee6d
Doc improvement
fujidaiti Aug 23, 2024
6e246ea
Merge branch 'main' into feature/modal-dismiss-params
fujidaiti Aug 23, 2024
2a613ec
Merge branch 'main' into feature/modal-dismiss-params
fujidaiti Aug 31, 2024
85d9544
Update changelog
fujidaiti Aug 31, 2024
b103ce5
Add unit tests
fujidaiti Aug 31, 2024
f5d4b9e
Tweak default sensitivity
fujidaiti Aug 31, 2024
e7d91c8
Update examples
fujidaiti Aug 31, 2024
4098310
Mention new api in readme
fujidaiti Aug 31, 2024
91c0be3
Format
fujidaiti Aug 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 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,6 +423,7 @@ class CupertinoModalSheetPage<T> extends Page<T> {
this.barrierColor = _cupertinoBarrierColor,
this.transitionDuration = _cupertinoTransitionDuration,
this.transitionCurve = _cupertinoTransitionCurve,
this.swipeDismissConfig = const SwipeDismissConfig(),
required this.child,
});

Expand All @@ -445,6 +447,8 @@ class CupertinoModalSheetPage<T> extends Page<T> {

final Curve transitionCurve;

final SwipeDismissConfig swipeDismissConfig;

@override
Route<T> createRoute(BuildContext context) {
return _PageBasedCupertinoModalSheetRoute(
Expand Down Expand Up @@ -485,6 +489,9 @@ class _PageBasedCupertinoModalSheetRoute<T>
@override
Duration get transitionDuration => _page.transitionDuration;

@override
SwipeDismissConfig get swipeDismissConfig => _page.swipeDismissConfig;

@override
String get debugLabel => '${super.debugLabel}(${_page.name})';

Expand All @@ -504,6 +511,7 @@ class CupertinoModalSheetRoute<T> extends _BaseCupertinoModalSheetRoute<T> {
this.barrierColor = _cupertinoBarrierColor,
this.transitionDuration = _cupertinoTransitionDuration,
this.transitionCurve = _cupertinoTransitionCurve,
this.swipeDismissConfig = const SwipeDismissConfig(),
});

final WidgetBuilder builder;
Expand All @@ -529,6 +537,9 @@ class CupertinoModalSheetRoute<T> extends _BaseCupertinoModalSheetRoute<T> {
@override
final Curve transitionCurve;

@override
final SwipeDismissConfig swipeDismissConfig;

@override
Widget buildContent(BuildContext context) {
return builder(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;
21 changes: 17 additions & 4 deletions package/lib/src/modal/modal_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ 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 _minFlingVelocityToDismiss = 1.0;
const _minDragDistanceToDismiss = 100.0; // Logical pixels.
const _minReleasedPageForwardAnimationTime = 300; // Milliseconds.
const _releasedPageForwardAnimationCurve = Curves.fastLinearToSlowEaseIn;

Expand All @@ -26,6 +25,7 @@ class ModalSheetPage<T> extends Page<T> {
this.barrierColor = Colors.black54,
this.transitionDuration = const Duration(milliseconds: 300),
this.transitionCurve = Curves.fastEaseInToSlowEaseOut,
this.swipeDismissConfig = const SwipeDismissConfig(),
required this.child,
});

Expand All @@ -49,6 +49,8 @@ class ModalSheetPage<T> extends Page<T> {

final Curve transitionCurve;

final SwipeDismissConfig swipeDismissConfig;

@override
Route<T> createRoute(BuildContext context) {
return _PageBasedModalSheetRoute(
Expand Down Expand Up @@ -88,6 +90,9 @@ class _PageBasedModalSheetRoute<T> extends PageRoute<T>
@override
Duration get transitionDuration => _page.transitionDuration;

@override
SwipeDismissConfig get swipeDismissConfig => _page.swipeDismissConfig;

@override
String get debugLabel => '${super.debugLabel}(${_page.name})';

Expand All @@ -107,6 +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.swipeDismissConfig = const SwipeDismissConfig(),
});

final WidgetBuilder builder;
Expand All @@ -132,6 +138,9 @@ class ModalSheetRoute<T> extends PageRoute<T> with ModalSheetRouteMixin<T> {
@override
final Curve transitionCurve;

@override
final SwipeDismissConfig swipeDismissConfig;

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

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

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

final ModalRoute<dynamic> route;
final AnimationController transitionController;
final SwipeDismissConfig swipeDismissConfig;

BuildContext get _context => route.subtreeContext!;

Expand Down Expand Up @@ -344,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 {
fujidaiti marked this conversation as resolved.
Show resolved Hide resolved
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)';
}
fujidaiti marked this conversation as resolved.
Show resolved Hide resolved
Loading