getPresentationWidgetsSwipeActionButtonTemplate function
String
getPresentationWidgetsSwipeActionButtonTemplate(
- String projectName
)
Implementation
String getPresentationWidgetsSwipeActionButtonTemplate(String projectName) {
return '''
import 'package:flutter/material.dart';
import 'package:${projectName}/core/constants/app_assets.dart';
import 'package:${projectName}/core/utils/responsive_size.dart';
import 'package:${projectName}/presentation/widgets/common_svg_widget.dart';
class SwipeActionButtons extends StatefulWidget {
final VoidCallback? onAccept;
final VoidCallback? onReject;
const SwipeActionButtons({
super.key,
this.onAccept,
this.onReject,
});
@override
State<SwipeActionButtons> createState() => _SwipeActionButtonsState();
}
class _SwipeActionButtonsState extends State<SwipeActionButtons>
with SingleTickerProviderStateMixin {
double position = 0;
bool isLocked = false;
late AnimationController _hintController;
late Animation<double> _hintAnimation;
bool _isUserDragging = false;
bool _isDisposed = false;
@override
void initState() {
super.initState();
_hintController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 800),
);
_hintAnimation = Tween<double>(begin: 0, end: 0).animate(_hintController);
_startHintLoop();
}
/// 🔥 VERY IMPORTANT: Reset when widget changes (fix reuse issue)
@override
void didUpdateWidget(covariant SwipeActionButtons oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.key != widget.key) {
_resetInternal();
}
}
void _resetInternal() {
if (!mounted) return;
setState(() {
position = 0;
isLocked = false;
_isUserDragging = false;
});
}
void _startHintLoop() async {
const offset = 12.0;
for (int i = 0; i < 2; i++) {
if (!mounted || _isDisposed) return;
await _animateTo(offset);
await Future.delayed(const Duration(milliseconds: 400));
await _animateTo(0);
await Future.delayed(const Duration(milliseconds: 400));
await _animateTo(-offset);
await Future.delayed(const Duration(milliseconds: 400));
await _animateTo(0);
await Future.delayed(const Duration(milliseconds: 600));
}
}
Future<void> _animateTo(double target) async {
if (!mounted || _isDisposed) return;
final tween = Tween<double>(begin: position, end: target);
final animation = tween.animate(
CurvedAnimation(parent: _hintController, curve: Curves.easeInOut),
);
setState(() {
_hintAnimation = animation;
});
_hintController.reset();
if (!_isDisposed) {
await _hintController.forward();
}
}
@override
void dispose() {
_isDisposed = true;
_hintController.dispose();
super.dispose();
}
void _onDragUpdate(DragUpdateDetails details) {
if (isLocked) return;
_isUserDragging = true;
setState(() {
position += details.delta.dx;
position = position.clamp(-120, 120); // cleaner
});
}
void _onDragEnd() {
_isUserDragging = false;
if (position > 80) {
/// ✅ Accept
setState(() {
position = 120;
isLocked = true;
});
widget.onAccept?.call();
} else if (position < -80) {
/// ❌ Reject
setState(() {
position = -120;
isLocked = true;
});
widget.onReject?.call();
} else {
/// 🔁 Reset to center
_resetInternal();
}
}
/// 🔁 External reset (optional use)
void reset() => _resetInternal();
@override
Widget build(BuildContext context) {
return SizedBox(
width: 100.sw,
height: 80,
child: Stack(
alignment: Alignment.center,
children: [
/// ❌ Reject Icon
Positioned(
left: 55.sp,
child: Icon(
Icons.cancel,
),
),
/// ✅ Accept Icon
Positioned(
right: 55.sp,
child: Icon(
Icons.favorite_outline,
),
),
/// 🎯 Draggable Button
AnimatedBuilder(
animation: _hintAnimation,
builder: (context, child) {
final hintOffset =
(!_isUserDragging && !isLocked) ? _hintAnimation.value : 0;
return Transform.translate(
offset: Offset(position + hintOffset, 0),
child: child,
);
},
child: GestureDetector(
onHorizontalDragUpdate: _onDragUpdate,
onHorizontalDragEnd: (_) => _onDragEnd(),
child: Icon(
Icons.add_circle,
),
),
),
],
),
);
}
}''';
}