import 'dart:math'; import 'package:fikoyt_sistem/apps/core/base_window.dart'; import 'package:fikoyt_ui/fikoyt_ui.dart'; import 'package:flutter/material.dart'; class LiquidBlob extends StatefulWidget { final double size; final Color baseColor; final Color secondaryColor; final Duration duration; final double waveStrength; final double interactionStrength; const LiquidBlob({ super.key, this.size = 200, this.baseColor = Colors.greenAccent, this.secondaryColor = Colors.lightGreenAccent, this.duration = const Duration(seconds: 10), this.waveStrength = 10, this.interactionStrength = 24, }); @override State createState() => _LiquidBlobState(); } class _LiquidBlobState extends State with TickerProviderStateMixin { late AnimationController _controller; late Animation _colorAnimation; bool _isPressed = false; @override void initState() { super.initState(); _controller = AnimationController(duration: widget.duration, vsync: this)..repeat(reverse: false); _colorAnimation = ColorTween( begin: widget.baseColor, end: widget.secondaryColor, ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOutSine)); } void _setPressed(bool val) { setState(() { _isPressed = val; }); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return GestureDetector( onTapDown: (_) => _setPressed(true), onTapUp: (_) => _setPressed(false), onTapCancel: () => _setPressed(false), child: AnimatedBuilder( animation: _controller, builder: (_, __) { final wave = _isPressed ? widget.interactionStrength : widget.waveStrength; return CustomPaint( painter: LiquidPainter(progress: _controller.value, color: widget.baseColor, waveStrength: wave), child: AnimatedScale( scale: _isPressed ? 1.1 : 1.0, duration: const Duration(milliseconds: 200), curve: Curves.easeOutBack, child: SizedBox( width: widget.size, height: widget.size, child: Center( child: Image.asset("packages/fikoyt_ui/assets/core/icons/logo.png", height: 128).animate( effects: [RotateEffect(duration: const Duration(seconds: 20))], onComplete: (controller) { controller.loop(); }, ), ), ), ), ); }, ), ); } } class LiquidPainter extends CustomPainter { final double progress; final Color color; final double waveStrength; LiquidPainter({required this.progress, required this.color, required this.waveStrength}); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final baseRadius = size.width / 2.2; drawBlob(canvas, center, baseRadius, 18, color.withOpacity(0.9), progress, 1.0); drawBlob(canvas, center, baseRadius - 12, 24, color.withOpacity(0.3), -progress, 0.95); } void drawBlob(Canvas canvas, Offset center, double baseRadius, int points, Color color, double offset, double scale) { final path = Path(); final angleStep = 2 * pi / points; final List pointsList = []; for (int i = 0; i < points; i++) { final angle = angleStep * i; final wobble = sin(angle * 5 + offset * 2 * pi) * waveStrength; final r = baseRadius + wobble; final x = center.dx + r * cos(angle) * scale; final y = center.dy + r * sin(angle) * scale; pointsList.add(Offset(x, y)); } for (int i = 0; i < pointsList.length; i++) { final current = pointsList[i]; final next = pointsList[(i + 1) % pointsList.length]; final control = Offset.lerp(current, next, 0.5)!; if (i == 0) { path.moveTo(current.dx, current.dy); } path.quadraticBezierTo(control.dx, control.dy, next.dx, next.dy); } path.close(); final paint = Paint() ..shader = RadialGradient( colors: [color, Colors.transparent], center: Alignment.center, radius: 1.0, ).createShader(Rect.fromCircle(center: center, radius: baseRadius * 1.3)) ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 1) ..style = PaintingStyle.fill; canvas.drawPath(path, paint); } @override bool shouldRepaint(covariant LiquidPainter oldDelegate) => true; }