diff --git a/package/CHANGELOG.md b/package/CHANGELOG.md index 5b5549b7..44637144 100644 --- a/package/CHANGELOG.md +++ b/package/CHANGELOG.md @@ -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) diff --git a/package/lib/src/foundation/sheet_activity.dart b/package/lib/src/foundation/sheet_activity.dart index 34c813a3..9cd93341 100644 --- a/package/lib/src/foundation/sheet_activity.dart +++ b/package/lib/src/foundation/sheet_activity.dart @@ -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; @@ -24,6 +25,8 @@ abstract class SheetActivity extends ChangeNotifier { double get velocity => 0.0; + SheetStatus get status; + @mustCallSuper void initWith(SheetExtent delegate) { assert( @@ -147,7 +150,7 @@ abstract class SheetActivity extends ChangeNotifier { } class AnimatedSheetActivity extends SheetActivity - with DrivenSheetActivityMixin { + with ControlledSheetActivityMixin { AnimatedSheetActivity({ required this.from, required this.to, @@ -178,7 +181,7 @@ class AnimatedSheetActivity extends SheetActivity } class BallisticSheetActivity extends SheetActivity - with DrivenSheetActivityMixin { + with ControlledSheetActivityMixin { BallisticSheetActivity({ required this.simulation, }); @@ -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; @@ -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); @@ -246,6 +255,9 @@ mixin DrivenSheetActivityMixin on SheetActivity { } mixin UserControlledSheetActivityMixin on SheetActivity { + @override + SheetStatus get status => SheetStatus.userControlled; + @override void didFinalizeDimensions( Size? oldContentDimensions, diff --git a/package/lib/src/foundation/sheet_extent.dart b/package/lib/src/foundation/sheet_extent.dart index f4be8915..21a3703d 100644 --- a/package/lib/src/foundation/sheet_extent.dart +++ b/package/lib/src/foundation/sheet_extent.dart @@ -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. /// @@ -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; @@ -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; @@ -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, @@ -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, @@ -520,6 +524,9 @@ class SheetMetricsSnapshot with MaybeSheetMetrics, SheetMetrics { ); } + @override + final SheetStatus status; + @override final double pixels; @@ -539,7 +546,9 @@ 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, @@ -547,6 +556,7 @@ class SheetMetricsSnapshot with MaybeSheetMetrics, SheetMetrics { ViewportDimensions? viewportDimensions, }) { return SheetMetricsSnapshot( + status: status ?? this.status, pixels: pixels ?? this.pixels, minPixels: minPixels ?? this.minPixels, maxPixels: maxPixels ?? this.maxPixels, @@ -593,6 +603,9 @@ class _SheetMetricsRef with MaybeSheetMetrics, SheetMetrics { final MaybeSheetMetrics _source; + @override + SheetStatus get status => _source.status; + @override double get pixels => _source.pixels!; diff --git a/package/lib/src/foundation/sheet_status.dart b/package/lib/src/foundation/sheet_status.dart new file mode 100644 index 00000000..62ebd32b --- /dev/null +++ b/package/lib/src/foundation/sheet_status.dart @@ -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, +} diff --git a/package/lib/src/modal/modal_sheet.dart b/package/lib/src/modal/modal_sheet.dart index cbdc2d0d..aa1d1ae4 100644 --- a/package/lib/src/modal/modal_sheet.dart +++ b/package/lib/src/modal/modal_sheet.dart @@ -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'; @@ -185,6 +186,40 @@ mixin ModalSheetRouteMixin on ModalRoute { 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 { @@ -231,7 +266,7 @@ class _SheetDismissibleState extends State { super.didChangeDependencies(); _gestureRecognizer.gestureSettings = MediaQuery.maybeGestureSettingsOf(context); - _sheetController = DefaultSheetController.of(context); + _sheetController = SheetControllerScope.of(context); assert( ModalRoute.of(context) is ModalSheetRouteMixin, diff --git a/package/lib/src/navigation/navigation_route.dart b/package/lib/src/navigation/navigation_route.dart index dd5e60d1..44daf37a 100644 --- a/package/lib/src/navigation/navigation_route.dart +++ b/package/lib/src/navigation/navigation_route.dart @@ -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 on NavigationSheetRoute { @@ -109,6 +110,9 @@ class _SheetExtentBox extends ChangeNotifier super.dispose(); } + @override + SheetStatus get status => _source?.status ?? SheetStatus.stable; + @override double? get pixels => _source?.pixels; diff --git a/package/lib/src/navigation/navigation_sheet.dart b/package/lib/src/navigation/navigation_sheet.dart index df1963ed..4d9d6400 100644 --- a/package/lib/src/navigation/navigation_sheet.dart +++ b/package/lib/src/navigation/navigation_sheet.dart @@ -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; @@ -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); } @@ -237,6 +239,9 @@ class _TransitionSheetActivity extends SheetActivity { late final Animation _curvedAnimation; + @override + SheetStatus get status => SheetStatus.controlled; + @override void initWith(SheetExtent target) { super.initWith(target); @@ -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) { diff --git a/package/lib/src/scrollable/scrollable_sheet_extent.dart b/package/lib/src/scrollable/scrollable_sheet_extent.dart index f1eaed2d..76baee54 100644 --- a/package/lib/src/scrollable/scrollable_sheet_extent.dart +++ b/package/lib/src/scrollable/scrollable_sheet_extent.dart @@ -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'; @@ -242,6 +243,9 @@ class _ContentIdleScrollDrivenSheetActivity final Extent initialExtent; + @override + SheetStatus get status => SheetStatus.stable; + @override void didChangeContentDimensions(Size? oldDimensions) { super.didChangeContentDimensions(oldDimensions); @@ -288,6 +292,9 @@ class _ContentUserScrollDrivenSheetActivity class _ContentBallisticScrollDrivenSheetActivity extends _ContentScrollDrivenSheetActivity { + @override + SheetStatus get status => SheetStatus.controlled; + @override DelegationResult applyBallisticScrollOffset( double delta, diff --git a/package/pubspec.yaml b/package/pubspec.yaml index 6d4ca227..b13964bd 100644 --- a/package/pubspec.yaml +++ b/package/pubspec.yaml @@ -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: diff --git a/package/test/foundation/sheet_physics_test.dart b/package/test/foundation/sheet_physics_test.dart index f652a9b8..0f622016 100644 --- a/package/test/foundation/sheet_physics_test.dart +++ b/package/test/foundation/sheet_physics_test.dart @@ -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,