import 'package:wonders/common_libs.dart'; class EightWaySwipeDetector extends StatefulWidget { const EightWaySwipeDetector({super.key, required this.child, this.threshold = 50, required this.onSwipe}); final Widget child; final double threshold; final void Function(Offset dir)? onSwipe; @override State createState() => _EightWaySwipeDetectorState(); } class _EightWaySwipeDetectorState extends State { Offset _startPos = Offset.zero; Offset _endPos = Offset.zero; bool _isSwiping = false; void _resetSwipe() { _startPos = _endPos = Offset.zero; _isSwiping = false; } void _maybeTriggerSwipe() { // Exit early if we're not currently swiping if (_isSwiping == false) return; // Get the distance of the swipe Offset moveDelta = _endPos - _startPos; final distance = moveDelta.distance; // Trigger swipe if threshold has been exceeded, if threshold is < 1, use 1 as a minimum value. if (distance >= max(widget.threshold, 1)) { // Normalize the dx/dy values between -1 and 1 moveDelta /= distance; // Round the dx/dy values to snap them to -1, 0 or 1, creating an 8-way directional vector. Offset dir = Offset( moveDelta.dx.roundToDouble(), moveDelta.dy.roundToDouble(), ); widget.onSwipe?.call(dir); _resetSwipe(); } } void _handleSwipeStart(d) { _isSwiping = true; _startPos = _endPos = d.localPosition; } void _handleSwipeUpdate(d) { _endPos = d.localPosition; _maybeTriggerSwipe(); } void _handleSwipeEnd(d) { _maybeTriggerSwipe(); _resetSwipe(); } @override Widget build(BuildContext context) { return GestureDetector( behavior: HitTestBehavior.translucent, onPanStart: _handleSwipeStart, onPanUpdate: _handleSwipeUpdate, onPanCancel: _resetSwipe, onPanEnd: _handleSwipeEnd, child: widget.child); } }