import 'package:flutter/material.dart';

/// Envolve [child] com um efeito de "aperto" ao toque: encolhe levemente
/// no pointer-down e volta ao tamanho normal com uma pequena mola ao soltar.
///
/// Usa [Listener] (eventos de ponteiro puros) em vez de [GestureDetector]
/// para não competir na arena de gestos com um `InkWell`/`Button` filho —
/// o toque real continua a ser tratado pelo widget interno normalmente.
class TapBounce extends StatefulWidget {
  const TapBounce({
    super.key,
    required this.child,
    this.scale = 0.94,
    this.duration = const Duration(milliseconds: 110),
  });

  final Widget child;
  final double scale;
  final Duration duration;

  @override
  State<TapBounce> createState() => _TapBounceState();
}

class _TapBounceState extends State<TapBounce>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller = AnimationController(
    vsync: this,
    duration: widget.duration,
  );
  late final Animation<double> _scale = Tween<double>(
    begin: 1.0,
    end: widget.scale,
  ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _press(PointerDownEvent _) => _controller.forward();

  void _release([PointerEvent? _]) => _controller.reverse();

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: _press,
      onPointerUp: _release,
      onPointerCancel: _release,
      child: AnimatedBuilder(
        animation: _scale,
        builder: (context, child) =>
            Transform.scale(scale: _scale.value, child: child),
        child: widget.child,
      ),
    );
  }
}
