getPresentationWidgetsSwipeActionButtonTemplate function

String getPresentationWidgetsSwipeActionButtonTemplate(
  1. 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: SvgWidget(
              assetName: AppAssets.profileRejectIcon,
              width: 40.sp,
              height: 40.sp,
            ),
          ),

          /// ✅ Accept Icon
          Positioned(
            right: 55.sp,
            child: SvgWidget(
              assetName: AppAssets.profileAcceptIcon,
              width: 40.sp,
              height: 40.sp,
            ),
          ),

          /// 🎯 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: SvgWidget(
                assetName: AppAssets.profileSwipeIcon,
                width: 65.sp,
                height: 65.sp,
              ),
            ),
          ),
        ],
      ),
    );
  }
}''';
}