BioFlux/lib/widgets/fluid_sphere_button.dart
2026-01-22 16:33:07 +08:00

138 lines
3.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'wave_painter.dart';
class FluidSphereButton extends StatefulWidget {
final double percentage;
final Color waterColor;
final VoidCallback onLongPressStart;
final VoidCallback onLongPressEnd;
const FluidSphereButton({
super.key,
required this.percentage,
required this.waterColor,
required this.onLongPressStart,
required this.onLongPressEnd,
});
@override
State<FluidSphereButton> createState() => _FluidSphereButtonState();
}
class _FluidSphereButtonState extends State<FluidSphereButton>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 4),
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onLongPress: widget.onLongPressStart,
onLongPressUp: widget.onLongPressEnd,
child: AnimatedContainer(
duration: const Duration(seconds: 1),
width: 260,
height: 260,
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: widget.waterColor.withOpacity(0.3),
blurRadius: 40,
offset: const Offset(0, 20),
),
BoxShadow(
color: Colors.white.withOpacity(0.9),
blurRadius: 20,
offset: const Offset(-10, -10),
),
],
),
child: ClipOval(
child: Stack(
children: [
Container(color: Colors.white.withOpacity(0.2)),
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return CustomPaint(
painter: WavePainter(
animationValue: _controller.value,
percentage: widget.percentage,
color: widget.waterColor,
),
size: Size.infinite,
);
},
),
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.white.withOpacity(0.6),
Colors.transparent,
Colors.transparent,
Colors.white.withOpacity(0.1),
],
stops: const [0.0, 0.4, 0.7, 1.0],
),
),
),
Positioned(
top: 30,
right: 30,
child: Container(
width: 40,
height: 20,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.4),
borderRadius: const BorderRadius.all(Radius.elliptical(40, 20)),
),
),
),
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"HOLD TO INFUSE",
style: GoogleFonts.montserrat(
color: widget.percentage > 0.6 ? Colors.white : Colors.black45,
fontSize: 10,
letterSpacing: 2.0,
fontWeight: FontWeight.w700,
),
),
],
),
),
],
),
),
),
);
}
}