Skip to content

Commit

Permalink
Prevent modal sheet from poping while dragging (#62)
Browse files Browse the repository at this point in the history
This PR fixes #54.

A modal sheet can now be dismissed by clicking the barrier ONLY when its
status is `SheetStatus.stable` and the pull-to-dismiss action is not
running.
  • Loading branch information
fujidaiti authored Mar 8, 2024
1 parent 3923fc7 commit 77ce339
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 12 deletions.
4 changes: 4 additions & 0 deletions package/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 0.3.4 Mar 9, 2024

- Fix crash when clicking on the modal barrier while dragging the sheet (#54)

## 0.3.3 Feb 29, 2024

- Add `InterpolationSimulation` (#55)
Expand Down
20 changes: 16 additions & 4 deletions package/lib/src/foundation/sheet_activity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:smooth_sheets/src/foundation/notification.dart';
import 'package:smooth_sheets/src/foundation/sheet_extent.dart';
import 'package:smooth_sheets/src/foundation/sheet_status.dart';

abstract class SheetActivity extends ChangeNotifier {
bool _mounted = false;
Expand All @@ -24,6 +25,8 @@ abstract class SheetActivity extends ChangeNotifier {

double get velocity => 0.0;

SheetStatus get status;

@mustCallSuper
void initWith(SheetExtent delegate) {
assert(
Expand Down Expand Up @@ -147,7 +150,7 @@ abstract class SheetActivity extends ChangeNotifier {
}

class AnimatedSheetActivity extends SheetActivity
with DrivenSheetActivityMixin {
with ControlledSheetActivityMixin {
AnimatedSheetActivity({
required this.from,
required this.to,
Expand Down Expand Up @@ -178,7 +181,7 @@ class AnimatedSheetActivity extends SheetActivity
}

class BallisticSheetActivity extends SheetActivity
with DrivenSheetActivityMixin {
with ControlledSheetActivityMixin {
BallisticSheetActivity({
required this.simulation,
});
Expand All @@ -201,9 +204,12 @@ class BallisticSheetActivity extends SheetActivity
}
}

class IdleSheetActivity extends SheetActivity {}
class IdleSheetActivity extends SheetActivity {
@override
SheetStatus get status => SheetStatus.stable;
}

mixin DrivenSheetActivityMixin on SheetActivity {
mixin ControlledSheetActivityMixin on SheetActivity {
late final AnimationController controller;
late double _lastAnimatedValue;

Expand All @@ -217,6 +223,9 @@ mixin DrivenSheetActivityMixin on SheetActivity {
@override
double get velocity => controller.velocity;

@override
SheetStatus get status => SheetStatus.controlled;

@override
void initWith(SheetExtent delegate) {
super.initWith(delegate);
Expand Down Expand Up @@ -246,6 +255,9 @@ mixin DrivenSheetActivityMixin on SheetActivity {
}

mixin UserControlledSheetActivityMixin on SheetActivity {
@override
SheetStatus get status => SheetStatus.userControlled;

@override
void didFinalizeDimensions(
Size? oldContentDimensions,
Expand Down
25 changes: 19 additions & 6 deletions package/lib/src/foundation/sheet_extent.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import 'package:flutter/widgets.dart';
import 'package:smooth_sheets/src/draggable/draggable_sheet.dart';
import 'package:smooth_sheets/src/foundation/sheet_activity.dart';
import 'package:smooth_sheets/src/foundation/sheet_controller.dart';
import 'package:smooth_sheets/src/foundation/sheet_physics.dart';
import 'package:smooth_sheets/smooth_sheets.dart';
import 'package:smooth_sheets/src/foundation/sheet_status.dart';
import 'package:smooth_sheets/src/internal/double_utils.dart';
import 'package:smooth_sheets/src/scrollable/scrollable_sheet.dart';
import 'package:smooth_sheets/src/scrollable/scrollable_sheet_extent.dart';

/// A representation of a visible height of the sheet.
///
Expand Down Expand Up @@ -162,6 +158,9 @@ abstract class SheetExtent with ChangeNotifier, MaybeSheetMetrics {
return SheetMetricsSnapshot.from(metrics);
}

@override
SheetStatus get status => _activity!.status;

@override
double? get pixels => _activity!.pixels;

Expand Down Expand Up @@ -398,6 +397,9 @@ class ViewportDimensions {

/// A description of the state of a sheet.
mixin MaybeSheetMetrics {
/// The current status of the sheet.
SheetStatus get status;

/// The current extent of the sheet.
double? get pixels;

Expand Down Expand Up @@ -502,6 +504,7 @@ mixin SheetMetrics on MaybeSheetMetrics {
class SheetMetricsSnapshot with MaybeSheetMetrics, SheetMetrics {
/// Creates an immutable description of the sheet's state.
const SheetMetricsSnapshot({
required this.status,
required this.pixels,
required this.minPixels,
required this.maxPixels,
Expand All @@ -512,6 +515,7 @@ class SheetMetricsSnapshot with MaybeSheetMetrics, SheetMetrics {
/// Creates a snapshot of the given [SheetMetrics].
factory SheetMetricsSnapshot.from(SheetMetrics other) {
return SheetMetricsSnapshot(
status: other.status,
pixels: other.pixels,
minPixels: other.minPixels,
maxPixels: other.maxPixels,
Expand All @@ -520,6 +524,9 @@ class SheetMetricsSnapshot with MaybeSheetMetrics, SheetMetrics {
);
}

@override
final SheetStatus status;

@override
final double pixels;

Expand All @@ -539,14 +546,17 @@ class SheetMetricsSnapshot with MaybeSheetMetrics, SheetMetrics {
bool get hasPixels => true;

/// Creates a copy of this object with the given fields replaced.
SheetMetricsSnapshot copyWith({
SheetStatus? status,
double? pixels,
double? minPixels,
double? maxPixels,
Size? contentDimensions,
ViewportDimensions? viewportDimensions,
}) {
return SheetMetricsSnapshot(
status: status ?? this.status,
pixels: pixels ?? this.pixels,
minPixels: minPixels ?? this.minPixels,
maxPixels: maxPixels ?? this.maxPixels,
Expand Down Expand Up @@ -593,6 +603,9 @@ class _SheetMetricsRef with MaybeSheetMetrics, SheetMetrics {

final MaybeSheetMetrics _source;

@override
SheetStatus get status => _source.status;

@override
double get pixels => _source.pixels!;

Expand Down
11 changes: 11 additions & 0 deletions package/lib/src/foundation/sheet_status.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// The status of a sheet.
enum SheetStatus {
/// The sheet is resting at a natural position.
stable,

/// The sheet position is controlled by a programmatic way such as animation.
controlled,

/// The sheet position is controlled by a user gesture such as dragging.
userControlled,
}
37 changes: 36 additions & 1 deletion package/lib/src/modal/modal_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:smooth_sheets/src/foundation/sheet_controller.dart';
import 'package:smooth_sheets/src/foundation/sheet_status.dart';
import 'package:smooth_sheets/src/internal/double_utils.dart';
import 'package:smooth_sheets/src/internal/monodrag.dart';

Expand Down Expand Up @@ -185,6 +186,40 @@ mixin ModalSheetRouteMixin<T> on ModalRoute<T> {
child: child,
);
}

@override
Widget buildModalBarrier() {
void onDismiss() {
if (animation!.status == AnimationStatus.completed &&
sheetController.metrics?.status == SheetStatus.stable) {
navigator?.maybePop();
}
}

final barrierColor = this.barrierColor;
if (barrierColor != null && barrierColor.alpha != 0 && !offstage) {
assert(barrierColor != barrierColor.withOpacity(0.0));
return AnimatedModalBarrier(
onDismiss: onDismiss,
dismissible: barrierDismissible,
semanticsLabel: barrierLabel,
barrierSemanticsDismissible: semanticsDismissible,
color: animation!.drive(
ColorTween(
begin: barrierColor.withOpacity(0.0),
end: barrierColor,
).chain(CurveTween(curve: barrierCurve)),
),
);
} else {
return ModalBarrier(
onDismiss: onDismiss,
dismissible: barrierDismissible,
semanticsLabel: barrierLabel,
barrierSemanticsDismissible: semanticsDismissible,
);
}
}
}

class SheetDismissible extends StatefulWidget {
Expand Down Expand Up @@ -231,7 +266,7 @@ class _SheetDismissibleState extends State<SheetDismissible> {
super.didChangeDependencies();
_gestureRecognizer.gestureSettings =
MediaQuery.maybeGestureSettingsOf(context);
_sheetController = DefaultSheetController.of(context);
_sheetController = SheetControllerScope.of(context);

assert(
ModalRoute.of(context) is ModalSheetRouteMixin<dynamic>,
Expand Down
4 changes: 4 additions & 0 deletions package/lib/src/navigation/navigation_route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:smooth_sheets/src/foundation/framework.dart';
import 'package:smooth_sheets/src/foundation/sheet_activity.dart';
import 'package:smooth_sheets/src/foundation/sheet_extent.dart';
import 'package:smooth_sheets/src/foundation/sheet_status.dart';
import 'package:smooth_sheets/src/navigation/navigation_sheet.dart';

mixin NavigationSheetRouteMixin<T> on NavigationSheetRoute<T> {
Expand Down Expand Up @@ -109,6 +110,9 @@ class _SheetExtentBox extends ChangeNotifier
super.dispose();
}

@override
SheetStatus get status => _source?.status ?? SheetStatus.stable;

@override
double? get pixels => _source?.pixels;

Expand Down
8 changes: 8 additions & 0 deletions package/lib/src/navigation/navigation_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:smooth_sheets/src/foundation/sheet_activity.dart';
import 'package:smooth_sheets/src/foundation/sheet_controller.dart';
import 'package:smooth_sheets/src/foundation/sheet_extent.dart';
import 'package:smooth_sheets/src/foundation/sheet_physics.dart';
import 'package:smooth_sheets/src/foundation/sheet_status.dart';
import 'package:smooth_sheets/src/internal/transition_observer.dart';

typedef NavigationSheetTransitionObserver = TransitionObserver;
Expand Down Expand Up @@ -128,6 +129,7 @@ abstract class NavigationSheetExtentDelegate implements Listenable {
double? get pixels;
double? get minPixels;
double? get maxPixels;
SheetStatus get status;
void applyNewViewportDimensions(ViewportDimensions viewportDimensions);
void beginActivity(SheetActivity activity);
}
Expand Down Expand Up @@ -237,6 +239,9 @@ class _TransitionSheetActivity extends SheetActivity {

late final Animation<double> _curvedAnimation;

@override
SheetStatus get status => SheetStatus.controlled;

@override
void initWith(SheetExtent target) {
super.initWith(target);
Expand Down Expand Up @@ -268,6 +273,9 @@ class _ProxySheetActivity extends SheetActivity {

final NavigationSheetExtentDelegate target;

@override
SheetStatus get status => target.status;

@override
double? get pixels {
if (target.pixels != null) {
Expand Down
7 changes: 7 additions & 0 deletions package/lib/src/scrollable/scrollable_sheet_extent.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:smooth_sheets/src/foundation/sheet_activity.dart';
import 'package:smooth_sheets/src/foundation/sheet_extent.dart';
import 'package:smooth_sheets/src/foundation/sheet_physics.dart';
import 'package:smooth_sheets/src/foundation/sheet_status.dart';
import 'package:smooth_sheets/src/foundation/sized_content_sheet.dart';
import 'package:smooth_sheets/src/internal/double_utils.dart';
import 'package:smooth_sheets/src/internal/into.dart';
Expand Down Expand Up @@ -242,6 +243,9 @@ class _ContentIdleScrollDrivenSheetActivity

final Extent initialExtent;

@override
SheetStatus get status => SheetStatus.stable;

@override
void didChangeContentDimensions(Size? oldDimensions) {
super.didChangeContentDimensions(oldDimensions);
Expand Down Expand Up @@ -288,6 +292,9 @@ class _ContentUserScrollDrivenSheetActivity

class _ContentBallisticScrollDrivenSheetActivity
extends _ContentScrollDrivenSheetActivity {
@override
SheetStatus get status => SheetStatus.controlled;

@override
DelegationResult<double> applyBallisticScrollOffset(
double delta,
Expand Down
2 changes: 1 addition & 1 deletion package/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: smooth_sheets
description: Sheet widgets with smooth motion and great flexibility. Also supports nested navigation in both imperative and declarative ways.
version: 0.3.3
version: 0.3.4
repository: https://github.com/fujidaiti/smooth_sheets

environment:
Expand Down
2 changes: 2 additions & 0 deletions package/test/foundation/sheet_physics_test.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:smooth_sheets/smooth_sheets.dart';
import 'package:smooth_sheets/src/foundation/sheet_status.dart';

class _SheetPhysicsWithDefaultConfiguration extends SheetPhysics {
const _SheetPhysicsWithDefaultConfiguration();
}

const _referenceSheetMetrics = SheetMetricsSnapshot(
status: SheetStatus.stable,
minPixels: 0,
maxPixels: 600,
pixels: 600,
Expand Down

0 comments on commit 77ce339

Please sign in to comment.