2026-05-12 15:47:38 +07:00

167 lines
4.6 KiB
Dart

import 'package:flutter/material.dart';
import '../../../common/painter/wave_painter.dart';
import '../../../common/theme/theme.dart';
class ParticleCard extends StatelessWidget {
/// Content yang ditampilkan di atas particle background
final Widget child;
/// Gradient background card. Default pakai primaryGradient
final List<Color>? gradientColors;
/// Arah gradient. Default topLeft → bottomRight
final AlignmentGeometry gradientBegin;
final AlignmentGeometry gradientEnd;
/// Border radius card. Default 16
final double borderRadius;
/// Padding konten. Default 16 semua sisi
final EdgeInsetsGeometry? padding;
/// Height card. Null = wrap content
final double? height;
/// Opacity particle & wave. Default 1.0
final double decorationOpacity;
const ParticleCard({
super.key,
required this.child,
this.gradientColors,
this.gradientBegin = Alignment.topLeft,
this.gradientEnd = Alignment.bottomRight,
this.borderRadius = 16,
this.padding,
this.height,
this.decorationOpacity = 1.0,
});
@override
Widget build(BuildContext context) {
final colors = gradientColors ?? AppColor.primaryGradient;
return ClipRRect(
borderRadius: BorderRadius.circular(borderRadius),
child: Container(
height: height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),
gradient: LinearGradient(
colors: colors,
begin: gradientBegin,
end: gradientEnd,
),
boxShadow: [
BoxShadow(
color: colors.first.withOpacity(0.35),
blurRadius: 16,
offset: const Offset(0, 6),
),
],
),
child: Stack(
children: [
// --- Decorative background ---
Opacity(
opacity: decorationOpacity,
child: Stack(
children: [
// Circles kanan atas
Positioned(
top: -24,
right: -24,
child: _circle(120, AppColor.white, 0.10),
),
Positioned(
top: 28,
right: 16,
child: _circle(60, AppColor.white, 0.06),
),
Positioned(
top: 70,
right: -10,
child: _circle(36, AppColor.white, 0.08),
),
// Circles kiri bawah
Positioned(
bottom: -20,
left: -20,
child: _circle(90, AppColor.white, 0.06),
),
Positioned(
bottom: 20,
left: 40,
child: _circle(40, AppColor.white, 0.04),
),
// Sparkle icons
..._sparkles(context),
// Wave pattern
Positioned.fill(
child: CustomPaint(
painter: WavePainter(
animation: 0.0,
color: AppColor.white.withOpacity(0.08),
),
),
),
// Radial gradient overlay
Container(
decoration: BoxDecoration(
gradient: RadialGradient(
center: const Alignment(0.7, -0.5),
radius: 1.4,
colors: [
Colors.white.withOpacity(0.06),
Colors.transparent,
],
),
),
),
],
),
),
// --- Content ---
Padding(
padding: padding ?? const EdgeInsets.all(16),
child: child,
),
],
),
),
);
}
Widget _circle(double size, Color color, double opacity) {
return Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color.withOpacity(opacity),
),
);
}
List<Widget> _sparkles(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return List.generate(5, (i) {
return Positioned(
left: (i * 70.0) % (width - 20),
top: 10 + (i * 18.0),
child: Icon(
Icons.auto_awesome,
size: 8 + (i % 3) * 3.0,
color: AppColor.white.withOpacity(0.18),
),
);
});
}
}