import 'package:flutter/material.dart'; import '../core/app_colors.dart'; class SwipeDeleteTile extends StatefulWidget { final Widget child; final VoidCallback onDelete; final VoidCallback? onTap; final EdgeInsetsGeometry margin; const SwipeDeleteTile({ super.key, required this.child, required this.onDelete, this.onTap, this.margin = const EdgeInsets.symmetric(horizontal: 16, vertical: 4), }); @override State createState() => _SwipeDeleteTileState(); } class _SwipeDeleteTileState extends State with SingleTickerProviderStateMixin { double _dx = 0; static const _maxSlide = 80.0; static const _threshold = 24.0; void _onDragUpdate(DragUpdateDetails d) { setState(() => _dx = (_dx + d.delta.dx).clamp(-_maxSlide, 0.0)); } void _onDragEnd(DragEndDetails d) { setState(() => _dx = _dx < -_threshold ? -_maxSlide : 0); } @override Widget build(BuildContext context) { final isSwiped = _dx < 0; return Padding( padding: widget.margin, child: Stack( children: [ Positioned.fill( child: Container( decoration: BoxDecoration( color: AppColors.error, borderRadius: BorderRadius.circular(16), ), child: const Align( alignment: Alignment.centerRight, child: Padding( padding: EdgeInsets.only(right: 20), child: Icon( Icons.delete_outline, color: AppColors.textOnGradient, size: 28, ), ), ), ), ), GestureDetector( behavior: isSwiped ? HitTestBehavior.opaque : HitTestBehavior.deferToChild, onTap: isSwiped ? () { widget.onDelete(); setState(() => _dx = 0); } : widget.onTap, onHorizontalDragUpdate: _onDragUpdate, onHorizontalDragEnd: _onDragEnd, child: Transform.translate( offset: Offset(_dx, 0), child: isSwiped ? AbsorbPointer(absorbing: true, child: widget.child) : widget.child, ), ), ], ), ); } }