diff --git a/example/android/build.gradle b/example/android/build.gradle index 3100ad2..c505a86 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 296b146..90f271d 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip diff --git a/example/pubspec.lock b/example/pubspec.lock index 282fd01..acaf6bf 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,42 +7,42 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" + version: "1.15.0" cupertino_icons: dependency: "direct main" description: @@ -56,7 +56,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" flutter: dependency: "direct main" description: flutter @@ -72,27 +72,34 @@ packages: description: flutter source: sdk version: "0.0.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" sky_engine: dependency: transitive description: flutter @@ -104,28 +111,28 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" swipe_to_action: dependency: "direct main" description: @@ -139,28 +146,28 @@ packages: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" sdks: - dart: ">=2.10.0-110 <=2.11.0-161.0.dev" - flutter: ">=1.20.0 <2.0.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=2.0.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 949bf5f..7683225 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -6,7 +6,7 @@ description: Demonstrates how to use the swipe_to_action plugin. publish_to: 'none' # Remove this line if you wish to publish to pub.dev environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index cd1463b..570e0e4 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -5,23 +5,4 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:swipe_to_action_example/main.dart'; - -void main() { - testWidgets('Verify Platform version', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that platform version is retrieved. - expect( - find.byWidgetPredicate( - (Widget widget) => widget is Text && - widget.data.startsWith('Running on:'), - ), - findsOneWidget, - ); - }); -} +void main() {} diff --git a/lib/src/swipeable.dart b/lib/src/swipeable.dart index 833a26d..021faec 100644 --- a/lib/src/swipeable.dart +++ b/lib/src/swipeable.dart @@ -31,6 +31,9 @@ enum SwipeDirection { /// The [Swipeable] can be swiped by dragging in the reading direction /// (e.g., from left to right in left-to-right languages). startToEnd, + + /// Called instead of null. + none, } class Swipeable extends StatefulWidget { @@ -43,12 +46,12 @@ class Swipeable extends StatefulWidget { /// state of the dismissed item. Using keys causes the widgets to sync /// according to their keys and avoids this pitfall. const Swipeable({ - @required Key key, - @required this.child, + required Key key, + required this.child, + required this.onSwipe, this.background, this.secondaryBackground, this.confirmSwipe, - this.onSwipe, this.direction = SwipeDirection.horizontal, this.dismissThresholds = const {}, this.maxOffset = 0.4, @@ -60,9 +63,7 @@ class Swipeable extends StatefulWidget { PointerDeviceKind.stylus, PointerDeviceKind.touch }, - }) : assert(key != null), - assert(secondaryBackground == null || background != null), - assert(dragStartBehavior != null), + }) : assert(secondaryBackground == null || background != null), super(key: key); /// The widget below this widget in the tree. @@ -73,12 +74,12 @@ class Swipeable extends StatefulWidget { /// A widget that is stacked behind the child. If secondaryBackground is also /// specified then this widget only appears when the child has been dragged /// to the right. - final Widget background; + final Widget? background; /// A widget that is stacked behind the child and is exposed when the child /// has been dragged to the left. It may only be specified when background /// has also been specified. - final Widget secondaryBackground; + final Widget? secondaryBackground; /// Gives the app an opportunity to confirm or veto a pending dismissal. /// @@ -87,7 +88,7 @@ class Swipeable extends StatefulWidget { /// /// If the returned Future completes to false or null the [onSwipe] /// callback will not run. - final ConfirmSwipeCallback confirmSwipe; + final ConfirmSwipeCallback? confirmSwipe; /// Called when the widget has been dismissed, after finishing resizing. final SwipeDirectionCallback onSwipe; @@ -159,9 +160,8 @@ class Swipeable extends StatefulWidget { class _SwipeableClipper extends CustomClipper { _SwipeableClipper({ - @required this.moveAnimation, - }) : assert(moveAnimation != null), - super(reclip: moveAnimation); + required this.moveAnimation, + }) : super(reclip: moveAnimation); final Animation moveAnimation; @@ -185,28 +185,27 @@ class _SwipeableClipper extends CustomClipper { enum _FlingGestureKind { none, forward, reverse } -class _SwipeableState extends State - with TickerProviderStateMixin, AutomaticKeepAliveClientMixin { +class _SwipeableState extends State with TickerProviderStateMixin, AutomaticKeepAliveClientMixin { @override void initState() { - super.initState(); - _moveController = - AnimationController(duration: widget.movementDuration, vsync: this) - ..addStatusListener(_handleDismissStatusChanged); + _moveController = AnimationController(duration: widget.movementDuration, vsync: this) + ..addStatusListener(_handleDismissStatusChanged); _updateMoveAnimation(); + + super.initState(); } - AnimationController _moveController; - Animation _moveAnimation; + late AnimationController _moveController; + late Animation _moveAnimation; double _dragExtent = 0.0; bool _dragUnderway = false; - Size _sizePriorToCollapse; + Size? _sizePriorToCollapse; bool _isTouch = true; @override - bool get wantKeepAlive => _moveController?.isAnimating == true; + bool get wantKeepAlive => _moveController.isAnimating == true; @override void dispose() { @@ -216,20 +215,14 @@ class _SwipeableState extends State SwipeDirection _extentToDirection(double extent) { if (extent == 0.0) { - return null; + return SwipeDirection.none; } switch (Directionality.of(context)) { case TextDirection.rtl: - return extent < 0 - ? SwipeDirection.startToEnd - : SwipeDirection.endToStart; + return extent < 0 ? SwipeDirection.startToEnd : SwipeDirection.endToStart; case TextDirection.ltr: - return extent > 0 - ? SwipeDirection.startToEnd - : SwipeDirection.endToStart; + return extent > 0 ? SwipeDirection.startToEnd : SwipeDirection.endToStart; } - assert(false); - return null; } SwipeDirection get _swipeDirection => _extentToDirection(_dragExtent); @@ -240,7 +233,7 @@ class _SwipeableState extends State double get _overallDragAxisExtent { final size = context.size; - return size.width; + return size?.width ?? 0.0; } void _handlePointerDown(PointerDownEvent event) { @@ -252,8 +245,7 @@ class _SwipeableState extends State void _handleDragStart(DragStartDetails details) { _dragUnderway = true; if (_moveController.isAnimating) { - _dragExtent = - _moveController.value * _overallDragAxisExtent * _dragExtent.sign; + _dragExtent = _moveController.value * _overallDragAxisExtent * _dragExtent.sign; _moveController.stop(); } else { _dragExtent = 0.0; @@ -269,9 +261,12 @@ class _SwipeableState extends State return; } - final delta = details.primaryDelta; + final delta = details.primaryDelta ?? 0.0; final oldDragExtent = _dragExtent; switch (widget.direction) { + case SwipeDirection.none: + return; + case SwipeDirection.horizontal: _dragExtent += delta; break; @@ -327,7 +322,6 @@ class _SwipeableState extends State } _FlingGestureKind _describeFlingGesture(Velocity velocity) { - assert(widget.direction != null); if (_dragExtent == 0.0) { // If it was a fling, then it was a fling that was let loose at the exact // middle of the range (i.e. when there's no displacement). In that case, @@ -340,14 +334,12 @@ class _SwipeableState extends State final vy = velocity.pixelsPerSecond.dy; SwipeDirection flingDirection; // Verify that the fling is in the generally right direction and fast enough. - if (vx.abs() - vy.abs() < _kMinFlingVelocityDelta || - vx.abs() < _kMinFlingVelocity) { + if (vx.abs() - vy.abs() < _kMinFlingVelocityDelta || vx.abs() < _kMinFlingVelocity) { return _FlingGestureKind.none; } assert(vx != 0.0); flingDirection = _extentToDirection(vx); - assert(_swipeDirection != null); if (flingDirection == _swipeDirection) { return _FlingGestureKind.forward; } @@ -359,8 +351,7 @@ class _SwipeableState extends State return; } _dragUnderway = false; - if (_moveController.isCompleted && - await _confirmStartSwipeAnimation() == true) { + if (_moveController.isCompleted && await _confirmStartSwipeAnimation() == true) { _startSwipeAnimation(); return; } @@ -369,28 +360,23 @@ class _SwipeableState extends State case _FlingGestureKind.forward: assert(_dragExtent != 0.0); assert(!_moveController.isDismissed); - if ((widget.dismissThresholds[_swipeDirection] ?? _kDismissThreshold) >= - 1.0) { + if ((widget.dismissThresholds[_swipeDirection] ?? _kDismissThreshold) >= 1.0) { await _moveController.reverse(); break; } _dragExtent = flingVelocity.sign; - await _moveController.fling( - velocity: flingVelocity.abs() * _kFlingVelocityScale); + await _moveController.fling(velocity: flingVelocity.abs() * _kFlingVelocityScale); break; case _FlingGestureKind.reverse: assert(_dragExtent != 0.0); assert(!_moveController.isDismissed); _dragExtent = flingVelocity.sign; - await _moveController.fling( - velocity: -flingVelocity.abs() * _kFlingVelocityScale); + await _moveController.fling(velocity: -flingVelocity.abs() * _kFlingVelocityScale); break; case _FlingGestureKind.none: if (!_moveController.isDismissed) { // we already know it's not completed, we check that above - if (_moveController.value > - (widget.dismissThresholds[_swipeDirection] ?? - _kDismissThreshold)) { + if (_moveController.value > (widget.dismissThresholds[_swipeDirection] ?? _kDismissThreshold)) { await _moveController.forward(); } else { await _moveController.reverse(); @@ -414,21 +400,18 @@ class _SwipeableState extends State Future _confirmStartSwipeAnimation() async { if (widget.confirmSwipe != null) { final direction = _swipeDirection; - assert(direction != null); - return widget.confirmSwipe(direction); + return widget.confirmSwipe!(direction); } return true; } void _startSwipeAnimation() { - assert(_moveController != null); assert(_moveController.isCompleted); assert(_sizePriorToCollapse == null); - if (widget.onSwipe != null) { - final direction = _swipeDirection; - assert(direction != null); - widget.onSwipe(direction); - } + + final direction = _swipeDirection; + widget.onSwipe(direction); + _moveController.reverse(); } diff --git a/pubspec.lock b/pubspec.lock index f019817..72a8f48 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,49 +7,49 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" + version: "1.15.0" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" flutter: dependency: "direct main" description: flutter @@ -65,27 +65,34 @@ packages: description: flutter source: sdk version: "0.0.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" sky_engine: dependency: transitive description: flutter @@ -97,56 +104,56 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" sdks: - dart: ">=2.10.0-110 <=2.11.0-161.0.dev" - flutter: ">=1.20.0 <2.0.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 2ef8cc6..84a7dba 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,8 +4,8 @@ version: 0.1.0 homepage: https://inex.dev/inex/swipe_to_action environment: - sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.20.0 <2.0.0" + sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.0.0" dependencies: flutter: