From 8efd3442c55492058580ac9df20740b7ff95830a Mon Sep 17 00:00:00 2001 From: jushutch Date: Thu, 10 Feb 2022 23:11:04 -0500 Subject: [PATCH 1/8] Include cardDeck and cardsSwiped in swipe callback functions --- example/lib/main.dart | 6 ++++-- lib/swiping_card_deck.dart | 12 ++++++++---- test/swiping_card_deck_test.dart | 32 +++++++++++++++++++++----------- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ed6f171..43f41a7 100755 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -20,8 +20,10 @@ class ExamplePage extends StatelessWidget { final SwipingCardDeck deck = SwipingCardDeck( cardDeck: getCardDeck(), onDeckEmpty: () => debugPrint("Card deck empty"), - onLeftSwipe: (Card card) => debugPrint("Swiped left!"), - onRightSwipe: (Card card) => debugPrint("Swiped right!"), + onLeftSwipe: (Card card, List cardDeck, int cardsSwiped) => + debugPrint("Swiped left!"), + onRightSwipe: (Card card, List cardDeck, int cardsSwiped) => + debugPrint("Swiped right!"), cardWidth: 200, swipeThreshold: MediaQuery.of(context).size.width / 3, minimumVelocity: 1000, diff --git a/lib/swiping_card_deck.dart b/lib/swiping_card_deck.dart index 4485b9a..c3e4818 100755 --- a/lib/swiping_card_deck.dart +++ b/lib/swiping_card_deck.dart @@ -32,10 +32,10 @@ class SwipingDeck extends StatelessWidget { List cardDeck; /// Callback function ran when a [Widget] is swiped left. - final Function(T) onLeftSwipe; + final Function(T, List, int) onLeftSwipe; /// Callback function ran when a [Widget] is swiped right. - final Function(T) onRightSwipe; + final Function(T, List, int) onRightSwipe; /// Callback function when the last [Widget] in the [cardDeck] is swiped. final Function() onDeckEmpty; @@ -62,6 +62,7 @@ class SwipingDeck extends StatelessWidget { late final Size screenSize; bool animationActive = false; + int cardsSwiped = 0; static const String left = "left"; static const String right = "right"; @@ -100,7 +101,8 @@ class SwipingDeck extends StatelessWidget { Future swipeLeft() async { if (animationActive || cardDeck.isEmpty) return; await _swipeCard(left, screenSize); - onLeftSwipe(cardDeck.last); + onLeftSwipe(cardDeck.last, cardDeck, cardsSwiped); + ++cardsSwiped; cardDeck.removeLast(); if (cardDeck.isEmpty) onDeckEmpty(); } @@ -114,7 +116,8 @@ class SwipingDeck extends StatelessWidget { Future swipeRight() async { if (animationActive || cardDeck.isEmpty) return; await _swipeCard(right, screenSize); - onRightSwipe(cardDeck.last); + onRightSwipe(cardDeck.last, cardDeck, cardsSwiped); + ++cardsSwiped; cardDeck.removeLast(); if (cardDeck.isEmpty) onDeckEmpty(); } @@ -135,5 +138,6 @@ class SwipingDeck extends StatelessWidget { await swipeDetector.swipeController.forward(); swipeDetector.swipeController.reset(); animationActive = false; + ++cardsSwiped; } } diff --git a/test/swiping_card_deck_test.dart b/test/swiping_card_deck_test.dart index 944cd4d..a0538a1 100755 --- a/test/swiping_card_deck_test.dart +++ b/test/swiping_card_deck_test.dart @@ -10,9 +10,9 @@ void main() { for (int i = 0; i < numCards; ++i) { cardDeck.add( Card( - color: Color((math.Random().nextDouble() * 0xFFFFFF).toInt()) - .withOpacity(1.0), - child: const SizedBox(height: 300, width: 200)), + color: Color((math.Random().nextDouble() * 0xFFFFFF).toInt()) + .withOpacity(1.0), + child: const SizedBox(height: 300, width: 200)), ); } return cardDeck; @@ -24,11 +24,17 @@ void main() { SwipingCardDeck mockDeck = SwipingCardDeck( cardDeck: cardDeck, onDeckEmpty: () => debugPrint("Card deck empty"), - onLeftSwipe: (dynamic card) => debugPrint("Swiped left!"), - onRightSwipe: (dynamic card) => debugPrint("Swiped right!"), + onLeftSwipe: (Card card, List cardDeck, int cardsSwiped) => + debugPrint("Swiped left!"), + onRightSwipe: (Card card, List cardDeck, int cardsSwiped) => + debugPrint("Swiped right!"), cardWidth: 200, ); - await tester.pumpWidget(MaterialApp(home: Scaffold(body: mockDeck,),)); + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: mockDeck, + ), + )); } testWidgets("SwipingCardDeck widget is created", (WidgetTester tester) async { @@ -43,13 +49,14 @@ void main() { expect(cardFinder, findsNWidgets(2)); }); - testWidgets("swipeLeft removes top card and runs callback", (WidgetTester tester) async { + testWidgets("swipeLeft removes top card and runs callback", + (WidgetTester tester) async { await _mountWidget(tester); Finder cardFinder = find.byType(Card); expect(cardFinder, findsNWidgets(2)); expect(tester.widget(cardFinder.first) as Card, cardDeck[1]); expect(tester.widget(cardFinder.last) as Card, cardDeck[0]); - + Finder deckFinder = find.byType(SwipingCardDeck); expect(deckFinder, findsOneWidget); @@ -61,7 +68,8 @@ void main() { expect(tester.widget(cardFinder.last) as Card, cardDeck[1]); }); - testWidgets("swipeRight removes top card and runs callback", (WidgetTester tester) async { + testWidgets("swipeRight removes top card and runs callback", + (WidgetTester tester) async { await _mountWidget(tester); Finder deckFinder = find.byType(SwipingCardDeck); expect(deckFinder, findsOneWidget); @@ -78,7 +86,8 @@ void main() { expect(tester.widget(cardFinder.last) as Card, cardDeck[1]); }); - testWidgets("Callback function is ran when deck is empty", (WidgetTester tester) async { + testWidgets("Callback function is ran when deck is empty", + (WidgetTester tester) async { await _mountWidget(tester); Finder deckFinder = find.byType(SwipingCardDeck); expect(deckFinder, findsOneWidget); @@ -93,7 +102,8 @@ void main() { expect(cardFinder, findsOneWidget); expect(tester.widget(cardFinder.first) as Card, cardDeck[numCards - 1]); - expectLater(() => deck.swipeLeft(), prints("Swiped left!\nCard deck empty\n")); + expectLater( + () => deck.swipeLeft(), prints("Swiped left!\nCard deck empty\n")); await tester.pumpAndSettle(); expect(cardFinder, findsNothing); From 5651362a27fe40912c63a0e2c51e3aece56f823f Mon Sep 17 00:00:00 2001 From: jushutch Date: Sun, 13 Feb 2022 00:30:33 -0500 Subject: [PATCH 2/8] Fix incrementing of cardsSwiped --- lib/swiping_card_deck.dart | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/swiping_card_deck.dart b/lib/swiping_card_deck.dart index c3e4818..d7e3186 100755 --- a/lib/swiping_card_deck.dart +++ b/lib/swiping_card_deck.dart @@ -101,8 +101,7 @@ class SwipingDeck extends StatelessWidget { Future swipeLeft() async { if (animationActive || cardDeck.isEmpty) return; await _swipeCard(left, screenSize); - onLeftSwipe(cardDeck.last, cardDeck, cardsSwiped); - ++cardsSwiped; + onLeftSwipe(cardDeck.last, cardDeck, ++cardsSwiped); cardDeck.removeLast(); if (cardDeck.isEmpty) onDeckEmpty(); } @@ -116,8 +115,7 @@ class SwipingDeck extends StatelessWidget { Future swipeRight() async { if (animationActive || cardDeck.isEmpty) return; await _swipeCard(right, screenSize); - onRightSwipe(cardDeck.last, cardDeck, cardsSwiped); - ++cardsSwiped; + onRightSwipe(cardDeck.last, cardDeck, ++cardsSwiped); cardDeck.removeLast(); if (cardDeck.isEmpty) onDeckEmpty(); } @@ -138,6 +136,5 @@ class SwipingDeck extends StatelessWidget { await swipeDetector.swipeController.forward(); swipeDetector.swipeController.reset(); animationActive = false; - ++cardsSwiped; } } From e160fb3a375bfab5a7bf0156dd3109acbb1261ac Mon Sep 17 00:00:00 2001 From: jushutch Date: Sun, 13 Feb 2022 00:30:52 -0500 Subject: [PATCH 3/8] Add tests for new callback features --- test/swiping_card_deck_test.dart | 95 +++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/test/swiping_card_deck_test.dart b/test/swiping_card_deck_test.dart index a0538a1..2350302 100755 --- a/test/swiping_card_deck_test.dart +++ b/test/swiping_card_deck_test.dart @@ -24,10 +24,14 @@ void main() { SwipingCardDeck mockDeck = SwipingCardDeck( cardDeck: cardDeck, onDeckEmpty: () => debugPrint("Card deck empty"), - onLeftSwipe: (Card card, List cardDeck, int cardsSwiped) => - debugPrint("Swiped left!"), - onRightSwipe: (Card card, List cardDeck, int cardsSwiped) => - debugPrint("Swiped right!"), + onLeftSwipe: (Card card, List cardDeck, int cardsSwiped) { + debugPrint("Swiped left!"); + debugPrint(cardsSwiped.toString()); + }, + onRightSwipe: (Card card, List cardDeck, int cardsSwiped) { + debugPrint("Swiped right!"); + debugPrint(cardsSwiped.toString()); + }, cardWidth: 200, ); await tester.pumpWidget(MaterialApp( @@ -61,7 +65,7 @@ void main() { expect(deckFinder, findsOneWidget); SwipingCardDeck deck = tester.widget(deckFinder); - expectLater(() => deck.swipeLeft(), prints("Swiped left!\n")); + expectLater(() => deck.swipeLeft(), prints("Swiped left!\n1\n")); await tester.pumpAndSettle(); expect(cardFinder, findsNWidgets(2)); expect(tester.widget(cardFinder.first) as Card, cardDeck[2]); @@ -79,7 +83,7 @@ void main() { expect(tester.widget(cardFinder.first) as Card, cardDeck[1]); expect(tester.widget(cardFinder.last) as Card, cardDeck[0]); - expectLater(() => deck.swipeRight(), prints("Swiped right!\n")); + expectLater(() => deck.swipeRight(), prints("Swiped right!\n1\n")); await tester.pumpAndSettle(); expect(cardFinder, findsNWidgets(2)); expect(tester.widget(cardFinder.first) as Card, cardDeck[2]); @@ -94,7 +98,7 @@ void main() { SwipingCardDeck deck = tester.widget(deckFinder); for (int i = 0; i < numCards - 1; ++i) { - deck.swipeLeft(); + expectLater(() => deck.swipeLeft(), prints("Swiped left!\n${i + 1}\n")); await tester.pumpAndSettle(); } @@ -102,10 +106,83 @@ void main() { expect(cardFinder, findsOneWidget); expect(tester.widget(cardFinder.first) as Card, cardDeck[numCards - 1]); - expectLater( - () => deck.swipeLeft(), prints("Swiped left!\nCard deck empty\n")); + expectLater(() => deck.swipeLeft(), + prints("Swiped left!\n$numCards\nCard deck empty\n")); await tester.pumpAndSettle(); expect(cardFinder, findsNothing); }); + + testWidgets("CardsSwiped is incremented correctly", + (WidgetTester tester) async { + await _mountWidget(tester); + Finder deckFinder = find.byType(SwipingCardDeck); + expect(deckFinder, findsOneWidget); + SwipingCardDeck deck = tester.widget(deckFinder); + + for (int i = 0; i < numCards - 1; ++i) { + expectLater(() => deck.swipeLeft(), prints("Swiped left!\n${i + 1}\n")); + await tester.pumpAndSettle(); + } + + Finder cardFinder = find.byType(Card); + expect(cardFinder, findsOneWidget); + expect(tester.widget(cardFinder.first) as Card, cardDeck[numCards - 1]); + }); + + testWidgets("CardDeck can be modified with both swipe callbacks", + (WidgetTester tester) async { + // Add a card to the beginning of a deck + void addCard(List deck) { + deck.insert( + 0, + const Card( + color: Colors.black, child: SizedBox(height: 300, width: 200)), + ); + } + + // SwipingCardDeck with swipe callbacks that modify the cardDeck + SwipingCardDeck mockDeck = SwipingCardDeck( + cardDeck: const [ + Card(color: Colors.black, child: SizedBox(height: 300, width: 200)) + ], + onDeckEmpty: () => debugPrint("Card deck empty"), + onLeftSwipe: (Card card, List cardDeck, int cardsSwiped) { + addCard(cardDeck); + debugPrint("Cards Swiped: $cardsSwiped"); + }, + onRightSwipe: (Card card, List cardDeck, int cardsSwiped) { + addCard(cardDeck); + debugPrint("Cards Swiped: $cardsSwiped"); + }, + cardWidth: 200, + ); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: mockDeck, + ), + )); + + Finder deckFinder = find.byType(SwipingCardDeck); + expect(deckFinder, findsOneWidget); + SwipingCardDeck deck = tester.widget(deckFinder); + int cardsSwiped = 0; + + // Alternate swiping directions + for (int i = 0; i < 100; ++i) { + ++cardsSwiped; + if (i % 2 == 0) { + expectLater( + () => deck.swipeLeft(), prints("Cards Swiped: $cardsSwiped\n")); + } else { + expectLater( + () => deck.swipeRight(), prints("Cards Swiped: $cardsSwiped\n")); + } + + await tester.pumpAndSettle(); + Finder cardFinder = find.byType(Card); + expect(cardFinder, findsOneWidget); + } + }); } From 36a0424f0069453043b6e67b3be076e03cfafa42 Mon Sep 17 00:00:00 2001 From: jushutch Date: Sun, 13 Feb 2022 00:53:02 -0500 Subject: [PATCH 4/8] Prepare v2.0.0-dev.0 release --- CHANGELOG.md | 4 ++++ README.md | 4 ++-- pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 851fee4..0681820 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-dev.0 + +- Add cardDeck and cardsSwiped parameters to onSwipe callback functions + ## 1.2.0 - Create generic SwipingDeck for swiping through other widgets diff --git a/README.md b/README.md index d1717a9..27a9234 100755 --- a/README.md +++ b/README.md @@ -69,8 +69,8 @@ SwipingCardDeck( ), ], onDeckEmpty: () => debugPrint("Card deck empty"), - onLeftSwipe: (Card card) => debugPrint("Swiped left!"), - onRightSwipe: (Card card) => debugPrint("Swiped right!"), + onLeftSwipe: (Card card, List cardDeck, int cardsSwiped) => debugPrint("Swiped left!"), + onRightSwipe: (Card card, List cardDeck, int cardsSwiped) => debugPrint("Swiped right!"), swipeThreshold: MediaQuery.of(context).size.width / 4, minimumVelocity: 1000, cardWidth: 200, diff --git a/pubspec.yaml b/pubspec.yaml index 12a2918..22261e7 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: swiping_card_deck description: A widget for swiping through a deck of cards with gestures or buttons. -version: 1.2.0 +version: 2.0.0-dev.0 repository: https://github.com/jushutch/swiping_card_deck environment: From ab3b8f224ea8f9eda6a925d98752fa30ba1b386e Mon Sep 17 00:00:00 2001 From: Justin Hutchins <44933935+jushutch@users.noreply.github.com> Date: Wed, 25 May 2022 01:49:18 -0400 Subject: [PATCH 5/8] Add new issue templates Add issue templates for bug reports and feature requests. --- .github/ISSUE_TEMPLATE/bug-report.md | 36 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature-request.md | 23 +++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request.md diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000..0a1a310 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,36 @@ +--- +name: Bug Report +about: Report unexpected behavior +title: '' +labels: bug +assignees: '' + +--- + +**Unexpected behavior :x:** + + +**Expected behavior :heavy_check_mark:** + + +**Reproducing :computer_mouse:** + + +1. Execute `flutter run` on the code sample +2. ... +3. ... + +
+Code sample + + +```dart +``` + +
+ +**Screenshots (optional) :camera_flash:** + + +**Potential fixes (optional) :wrench:** + diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000..6b26dbf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,23 @@ +--- +name: Feature Request +about: Suggest an improvement for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Complete the following checklist before opening this issue :heavy_check_mark:** + +- [ ] This improvement has not been suggested already +- [ ] This suggestion is not a solution to a bug +- [ ] I've read the [contributing guidelines](https://github.com/jushutch/swiping_card_deck/blob/36a0424f0069453043b6e67b3be076e03cfafa42/CONTRIBUTING.md) + +**The Idea :bulb:** + + +**Use Case :briefcase:** + + +**Implementation** (optional) :wrench: + From 8abcfa15a1342b402998db1b8e8add348c606eca Mon Sep 17 00:00:00 2001 From: Justin Hutchins <44933935+jushutch@users.noreply.github.com> Date: Wed, 25 May 2022 17:29:15 -0400 Subject: [PATCH 6/8] Add issue template for questions --- .github/ISSUE_TEMPLATE/feature-request.md | 2 +- .github/ISSUE_TEMPLATE/question.md | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/question.md diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 6b26dbf..8f01c69 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,6 +1,6 @@ --- name: Feature Request -about: Suggest an improvement for this project +about: Suggest an improvement title: '' labels: enhancement assignees: '' diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..e0bdbbc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,17 @@ +--- +name: Question +about: Ask a general question +title: '' +labels: question +assignees: '' + +--- + + + +**Before posting your question** :heavy_check_mark: + +- [ ] I acknowledge that I've read the [Code of Conduct](https://github.com/jushutch/swiping_card_deck/blob/ab3b8f224ea8f9eda6a925d98752fa30ba1b386e/CODE_OF_CONDUCT.md) + +**Question :grey_question:** + From 47e883f16ebc8b5073d9e4ae7a7e3850975cd292 Mon Sep 17 00:00:00 2001 From: jushutch Date: Wed, 25 May 2022 22:56:57 -0400 Subject: [PATCH 7/8] Add config for probot/stale app --- .github/stale.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100755 index 0000000..3854ab0 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,23 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 14 + +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: + - awaiting response + +# Label to use when marking an issue as stale +staleLabel: stale + +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because there has not been a response in 14 days. It will be closed if no further activity occurs in the next 7 days. If the previous discussion resolved your issue, please close the issue. Thank you again for contributing! :smile: + +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: > + This issue has been awaiting a response for 21 days and will now be automatically closed. If this is an error, leave a comment explaining why this is an error. Thank you for your patience and understanding! :raised_hands: + +# Limit to only `issues` or `pulls` +only: issues \ No newline at end of file From ac85efc5ff6cb211359768e112d70e5a073038ba Mon Sep 17 00:00:00 2001 From: Wale Date: Thu, 24 Nov 2022 15:49:23 +0100 Subject: [PATCH 8/8] created swip movement detector with direction --- lib/src/swiping_gesture_detector.dart | 92 ++++++++++++++++++--------- lib/swiping_card_deck.dart | 32 ++++++---- 2 files changed, 79 insertions(+), 45 deletions(-) diff --git a/lib/src/swiping_gesture_detector.dart b/lib/src/swiping_gesture_detector.dart index 10953da..aaa4068 100755 --- a/lib/src/swiping_gesture_detector.dart +++ b/lib/src/swiping_gesture_detector.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/physics.dart'; + //ignore: must_be_immutable class SwipingGestureDetector extends StatefulWidget { SwipingGestureDetector({ @@ -10,6 +11,7 @@ class SwipingGestureDetector extends StatefulWidget { required this.swipeLeft, required this.swipeRight, required this.cardWidth, + this.onMovement, this.minimumVelocity = 1000, this.rotationFactor = .8 / 3.14, this.swipeAnimationDuration = const Duration(milliseconds: 500), @@ -18,6 +20,7 @@ class SwipingGestureDetector extends StatefulWidget { final List cardDeck; final Function() swipeLeft, swipeRight; + final Function? onMovement; final double minimumVelocity; final double rotationFactor; final double swipeThreshold; @@ -38,7 +41,7 @@ class _SwipingGestureDetector extends State bool animationActive = false; late final AnimationController springController; late Animation spring; - + int threshold = 10; @override void initState() { super.initState(); @@ -73,35 +76,57 @@ class _SwipingGestureDetector extends State @override Widget build(BuildContext context) { final Size screenSize = MediaQuery.of(context).size; - return GestureDetector( - onPanUpdate: (DragUpdateDetails details) { - setState(() { - widget.dragAlignment += Alignment(details.delta.dx, details.delta.dy); - }); - }, - onPanStart: (DragStartDetails details) async { - if (animationActive) { - springController.stop(); - } - }, - onPanEnd: (DragEndDetails details) async { - double vx = details.velocity.pixelsPerSecond.dx; - if (vx >= widget.minimumVelocity || - widget.dragAlignment.x >= widget.swipeThreshold) { - await widget.swipeRight(); - } else if (vx <= -widget.minimumVelocity || - widget.dragAlignment.x <= -widget.swipeThreshold) { - await widget.swipeLeft(); - } else { - animateBackToDeck(details.velocity.pixelsPerSecond, screenSize); - } - setState(() { - widget.dragAlignment = Alignment.center; - }); - }, - child: Stack( - alignment: Alignment.center, - children: topTwoCards(), + return SafeArea( + child: GestureDetector( + onPanUpdate: (DragUpdateDetails details) { + // Identify the movement of the swipe and update the listener accordingly. + late SwipeDirection direction; + double x = widget.dragAlignment.x; + if(x.isNegative){ + if(-widget.swipeThreshold > x){ + direction = SwipeDirection.left; + }else{ + direction = SwipeDirection.none; + } + }else{ + if(widget.swipeThreshold < x){ + direction = SwipeDirection.right; + }else{ + direction = SwipeDirection.none; + } + } + + widget.onMovement!(direction); + + var left = + setState(() { + widget.dragAlignment += Alignment(details.delta.dx, details.delta.dy); + }); + }, + onPanStart: (DragStartDetails details) async { + if (animationActive) { + springController.stop(); + } + }, + onPanEnd: (DragEndDetails details) async { + double vx = details.velocity.pixelsPerSecond.dx; + if (vx >= widget.minimumVelocity || + widget.dragAlignment.x >= widget.swipeThreshold) { + await widget.swipeRight(); + } else if (vx <= -widget.minimumVelocity || + widget.dragAlignment.x <= -widget.swipeThreshold) { + await widget.swipeLeft(); + } else { + animateBackToDeck(details.velocity.pixelsPerSecond, screenSize); + } + setState(() { + widget.dragAlignment = Alignment.center; + }); + }, + child: Stack( + alignment: Alignment.center, + children: topTwoCards(), + ), ), ); } @@ -112,7 +137,7 @@ class _SwipingGestureDetector extends State const SizedBox( height: 0, width: 0, - ) + ), ]; } List cardDeck = []; @@ -170,3 +195,8 @@ class _SwipingGestureDetector extends State animationActive = false; } } + + +enum SwipeDirection{ + none, left, right; +} \ No newline at end of file diff --git a/lib/swiping_card_deck.dart b/lib/swiping_card_deck.dart index d7e3186..8d0642c 100755 --- a/lib/swiping_card_deck.dart +++ b/lib/swiping_card_deck.dart @@ -15,15 +15,16 @@ typedef SwipingCardDeck = SwipingDeck; class SwipingDeck extends StatelessWidget { SwipingDeck( {Key? key, - required this.cardDeck, - required this.onLeftSwipe, - required this.onRightSwipe, - required this.onDeckEmpty, - required this.cardWidth, - this.minimumVelocity = 1000, - this.rotationFactor = .8 / 3.14, - this.swipeThreshold, - this.swipeAnimationDuration = const Duration(milliseconds: 500)}) + required this.cardDeck, + required this.onLeftSwipe, + required this.onRightSwipe, + required this.onDeckEmpty, + required this.cardWidth, + this.minimumVelocity = 1000, + this.rotationFactor = .8 / 3.14, + this.onMovement, + this.swipeThreshold, + this.swipeAnimationDuration = const Duration(milliseconds: 500)}) : super(key: key) { cardDeck = cardDeck.reversed.toList(); } @@ -32,10 +33,10 @@ class SwipingDeck extends StatelessWidget { List cardDeck; /// Callback function ran when a [Widget] is swiped left. - final Function(T, List, int) onLeftSwipe; + final Function(T) onLeftSwipe; /// Callback function ran when a [Widget] is swiped right. - final Function(T, List, int) onRightSwipe; + final Function(T) onRightSwipe; /// Callback function when the last [Widget] in the [cardDeck] is swiped. final Function() onDeckEmpty; @@ -58,11 +59,13 @@ class SwipingDeck extends StatelessWidget { /// The [SwipingGestureDetector] used to control swipe animations. late final SwipingGestureDetector swipeDetector; + /// The listener [Function] function for swipe movement and direction. + late final Function? onMovement; + /// The [Size] of the screen. late final Size screenSize; bool animationActive = false; - int cardsSwiped = 0; static const String left = "left"; static const String right = "right"; @@ -73,6 +76,7 @@ class SwipingDeck extends StatelessWidget { cardDeck: cardDeck, swipeLeft: swipeLeft, swipeRight: swipeRight, + onMovement: onMovement, swipeThreshold: swipeThreshold ?? screenSize.width / 4, cardWidth: cardWidth, rotationFactor: rotationFactor, @@ -101,7 +105,7 @@ class SwipingDeck extends StatelessWidget { Future swipeLeft() async { if (animationActive || cardDeck.isEmpty) return; await _swipeCard(left, screenSize); - onLeftSwipe(cardDeck.last, cardDeck, ++cardsSwiped); + onLeftSwipe(cardDeck.last); cardDeck.removeLast(); if (cardDeck.isEmpty) onDeckEmpty(); } @@ -115,7 +119,7 @@ class SwipingDeck extends StatelessWidget { Future swipeRight() async { if (animationActive || cardDeck.isEmpty) return; await _swipeCard(right, screenSize); - onRightSwipe(cardDeck.last, cardDeck, ++cardsSwiped); + onRightSwipe(cardDeck.last); cardDeck.removeLast(); if (cardDeck.isEmpty) onDeckEmpty(); }