Compare commits
3 Commits
main
...
new-card-s
| Author | SHA1 | Date |
|---|---|---|
|
|
9c3d16ce94 | |
|
|
d63bcd5c76 | |
|
|
5fb6777279 |
|
|
@ -1,3 +1,8 @@
|
|||
## [7.1.0]
|
||||
|
||||
- Adds support for tapping a card
|
||||
- `onTap` callback containing currentIndex.
|
||||
|
||||
## [7.0.2]
|
||||
|
||||
- Added `CardAnimation.animateToAngle` helper to animate swipe the card to any given angle between 0-360°.
|
||||
|
|
|
|||
|
|
@ -15,16 +15,36 @@ class CardSwiperController {
|
|||
_eventController.add(ControllerSwipeEvent(direction));
|
||||
}
|
||||
|
||||
// Undo the last swipe
|
||||
/// Undo the last swipe
|
||||
void undo() {
|
||||
_eventController.add(const ControllerUndoEvent());
|
||||
}
|
||||
|
||||
// Change the top card to a specific index.
|
||||
/// Change the top card to a specific index.
|
||||
void moveTo(int index) {
|
||||
_eventController.add(ControllerMoveEvent(index));
|
||||
}
|
||||
|
||||
/// We have a new list of card data for this state machine to handle
|
||||
/// 1. Set the length of the card list
|
||||
/// 2. Move index to 0 (restart stack to first card)
|
||||
void newStack(int length) {
|
||||
_eventController.add(ControllerNewStackEvent(length));
|
||||
}
|
||||
|
||||
/// We have a new added cards to the end
|
||||
/// 0. Keep internal index the same (undo will work, can go backwards)
|
||||
/// 1. Set the internal length of the card list
|
||||
/// 2. Check if we need to redraw, if we are at end of card list
|
||||
// void appendStack(int length) {
|
||||
// _eventController.add(ControllerNewStackEvent(length));
|
||||
// }
|
||||
|
||||
/// Set the length only, user can moveTo(0), or other actions
|
||||
// void modifiedStack(int length) {
|
||||
// _eventController.add(ControllerNewStackEvent(length));
|
||||
// }
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _eventController.close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,3 +17,8 @@ class ControllerMoveEvent extends ControllerEvent {
|
|||
final int index;
|
||||
const ControllerMoveEvent(this.index);
|
||||
}
|
||||
|
||||
class ControllerNewStackEvent extends ControllerEvent {
|
||||
final int length;
|
||||
const ControllerNewStackEvent(this.length);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,4 +36,4 @@ typedef CardSwiperOnUndo = bool Function(
|
|||
CardSwiperDirection direction,
|
||||
);
|
||||
|
||||
typedef CardSwiperOnTap = FutureOr<void> Function();
|
||||
typedef CardSwiperOnTap = FutureOr<void> Function(int currentIndex);
|
||||
|
|
|
|||
|
|
@ -159,10 +159,10 @@ class CardSwiper extends StatefulWidget {
|
|||
scale >= 0 && scale <= 1,
|
||||
'scale must be between 0 and 1',
|
||||
),
|
||||
assert(
|
||||
numberOfCardsDisplayed >= 1 && numberOfCardsDisplayed <= cardsCount,
|
||||
'you must display at least one card, and no more than [cardsCount]',
|
||||
),
|
||||
// assert(
|
||||
// numberOfCardsDisplayed >= 1 && numberOfCardsDisplayed <= cardsCount,
|
||||
// 'you must display at least one card, and no more than [cardsCount]',
|
||||
// ),
|
||||
assert(
|
||||
initialIndex >= 0 && initialIndex < cardsCount,
|
||||
'initialIndex must be between 0 and [cardsCount]',
|
||||
|
|
|
|||
|
|
@ -22,10 +22,20 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
|
||||
StreamSubscription<ControllerEvent>? controllerSubscription;
|
||||
|
||||
late NullableCardBuilder _cardBuilder;
|
||||
late int _cardsCount;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
debugPrint('[WTF] _CardSwiperState.initState !!!');
|
||||
debugPrint('[WTF] _CardSwiperState.initState !!!');
|
||||
debugPrint('[WTF] _CardSwiperState.initState !!!');
|
||||
|
||||
_cardBuilder = widget.cardBuilder;
|
||||
_cardsCount = widget.cardsCount;
|
||||
|
||||
_undoableIndex.state = widget.initialIndex;
|
||||
|
||||
controllerSubscription =
|
||||
|
|
@ -67,6 +77,11 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
|
||||
@override
|
||||
void dispose() {
|
||||
|
||||
debugPrint('[WTF] _CardSwiperState.dispose !!!');
|
||||
debugPrint('[WTF] _CardSwiperState.dispose !!!');
|
||||
debugPrint('[WTF] _CardSwiperState.dispose !!!');
|
||||
|
||||
_animationController.dispose();
|
||||
controllerSubscription?.cancel();
|
||||
super.dispose();
|
||||
|
|
@ -104,7 +119,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
angle: _cardAnimation.angle,
|
||||
child: ConstrainedBox(
|
||||
constraints: constraints,
|
||||
child: widget.cardBuilder(
|
||||
child: _cardBuilder(
|
||||
context,
|
||||
_currentIndex!,
|
||||
(100 * _cardAnimation.left / widget.threshold).ceil(),
|
||||
|
|
@ -116,7 +131,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
if (widget.isDisabled) {
|
||||
await widget.onTapDisabled?.call();
|
||||
}
|
||||
await widget.onTap?.call();
|
||||
await widget.onTap?.call(_currentIndex!);
|
||||
},
|
||||
onPanStart: (tapInfo) {
|
||||
if (!widget.isDisabled) {
|
||||
|
|
@ -155,7 +170,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
scale: _cardAnimation.scale - ((1 - widget.scale) * (index - 1)),
|
||||
child: ConstrainedBox(
|
||||
constraints: constraints,
|
||||
child: widget.cardBuilder(context, getValidIndexOffset(index)!, 0, 0),
|
||||
child: _cardBuilder(context, getValidIndexOffset(index)!, 0, 0),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -166,6 +181,8 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
ControllerSwipeEvent(:final direction) => _swipe(direction),
|
||||
ControllerUndoEvent() => _undo(),
|
||||
ControllerMoveEvent(:final index) => _moveTo(index),
|
||||
// controller
|
||||
ControllerNewStackEvent(:final length) => _newCardStack(length)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -189,7 +206,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
}
|
||||
|
||||
Future<void> _handleCompleteSwipe() async {
|
||||
final isLastCard = _currentIndex! == widget.cardsCount - 1;
|
||||
final isLastCard = _currentIndex! == _cardsCount - 1;
|
||||
final shouldCancelSwipe = await widget.onSwipe
|
||||
?.call(_currentIndex!, _nextIndex, _detectedDirection) ==
|
||||
false;
|
||||
|
|
@ -286,14 +303,20 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
}
|
||||
|
||||
void _moveTo(int index) {
|
||||
debugPrint('[WTF] _moveTo() index: $index currentIndex: $_currentIndex cardsCount: $_cardsCount');
|
||||
if (index == _currentIndex) return;
|
||||
if (index < 0 || index >= widget.cardsCount) return;
|
||||
if (index < 0 || index >= _cardsCount) return;
|
||||
|
||||
setState(() {
|
||||
_undoableIndex.state = index;
|
||||
});
|
||||
}
|
||||
|
||||
void _newCardStack(int length) {
|
||||
_cardsCount = length;
|
||||
_moveTo(0); // move to first card, and force redraw if necessary
|
||||
}
|
||||
|
||||
int numberOfCardsOnScreen() {
|
||||
if (widget.isLoop) {
|
||||
return widget.numberOfCardsDisplayed;
|
||||
|
|
@ -304,7 +327,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
|
||||
return math.min(
|
||||
widget.numberOfCardsDisplayed,
|
||||
widget.cardsCount - _currentIndex!,
|
||||
_cardsCount - _currentIndex!,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -314,9 +337,9 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
}
|
||||
|
||||
final index = _currentIndex! + offset;
|
||||
if (!widget.isLoop && !index.isBetween(0, widget.cardsCount - 1)) {
|
||||
if (!widget.isLoop && !index.isBetween(0, _cardsCount - 1)) {
|
||||
return null;
|
||||
}
|
||||
return index % widget.cardsCount;
|
||||
return index % _cardsCount;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ name: flutter_card_swiper
|
|||
description: This is a Tinder-like card swiper package. It allows you to swipe left, right, up, and down and define your own business logic for each direction.
|
||||
homepage: https://github.com/ricardodalarme/flutter_card_swiper
|
||||
issue_tracker: https://github.com/ricardodalarme/flutter_card_swiper/issues
|
||||
version: 7.0.2
|
||||
version: 7.1.0
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
|
|
|||
|
|
@ -635,27 +635,28 @@ void main() {
|
|||
expect(find.card(0), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('when tapping a card, expect callback', (WidgetTester tester) async {
|
||||
testWidgets('when tapping a card, expect callback',
|
||||
(WidgetTester tester) async {
|
||||
final swiperKey = GlobalKey();
|
||||
var isCalled = false;
|
||||
var index = -1;
|
||||
|
||||
await tester.pumpApp(
|
||||
CardSwiper(
|
||||
key: swiperKey,
|
||||
cardsCount: 3,
|
||||
numberOfCardsDisplayed: 1,
|
||||
onTap: () {
|
||||
isCalled = true;
|
||||
initialIndex: 2,
|
||||
onTap: (currentIndex) {
|
||||
index = currentIndex;
|
||||
},
|
||||
cardBuilder: genericBuilder,
|
||||
),
|
||||
);
|
||||
|
||||
await tester.dragDown(swiperKey);
|
||||
await tester.tap(find.byKey(swiperKey));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(isCalled, true);
|
||||
expect(index, 2);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue