397 lines
12 KiB
Dart
397 lines
12 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../../../../../../common/theme/theme.dart';
|
|
|
|
class HomeLotteryBanner extends StatefulWidget {
|
|
const HomeLotteryBanner({
|
|
super.key,
|
|
this.onTap,
|
|
this.title = "🎰 UNDIAN BERHADIAH",
|
|
this.subtitle = "Kumpulkan voucher untuk menang hadiah menarik!",
|
|
this.showAnimation = true,
|
|
this.actionText = "IKUTI SEKARANG",
|
|
});
|
|
|
|
final VoidCallback? onTap;
|
|
final String title;
|
|
final String subtitle;
|
|
final bool showAnimation;
|
|
final String actionText;
|
|
|
|
@override
|
|
State<HomeLotteryBanner> createState() => _HomeLotteryBannerState();
|
|
}
|
|
|
|
class _HomeLotteryBannerState extends State<HomeLotteryBanner>
|
|
with TickerProviderStateMixin {
|
|
late AnimationController _pulseController;
|
|
late AnimationController _shimmerController;
|
|
late AnimationController _floatingController;
|
|
late Animation<double> _pulseAnimation;
|
|
late Animation<double> _shimmerAnimation;
|
|
late Animation<double> _floatingAnimation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
if (widget.showAnimation) {
|
|
// Pulse animation for the whole banner
|
|
_pulseController = AnimationController(
|
|
duration: const Duration(seconds: 2),
|
|
vsync: this,
|
|
);
|
|
|
|
// Shimmer effect for the gradient
|
|
_shimmerController = AnimationController(
|
|
duration: const Duration(seconds: 3),
|
|
vsync: this,
|
|
);
|
|
|
|
// Floating animation for the icon
|
|
_floatingController = AnimationController(
|
|
duration: const Duration(seconds: 4),
|
|
vsync: this,
|
|
);
|
|
|
|
_pulseAnimation = Tween<double>(begin: 1.0, end: 1.02).animate(
|
|
CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut),
|
|
);
|
|
|
|
_shimmerAnimation = Tween<double>(begin: -2.0, end: 2.0).animate(
|
|
CurvedAnimation(parent: _shimmerController, curve: Curves.easeInOut),
|
|
);
|
|
|
|
_floatingAnimation = Tween<double>(begin: -5.0, end: 5.0).animate(
|
|
CurvedAnimation(parent: _floatingController, curve: Curves.easeInOut),
|
|
);
|
|
|
|
_pulseController.repeat(reverse: true);
|
|
_shimmerController.repeat(reverse: true);
|
|
_floatingController.repeat(reverse: true);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
if (widget.showAnimation) {
|
|
_pulseController.dispose();
|
|
_shimmerController.dispose();
|
|
_floatingController.dispose();
|
|
}
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget banner = Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(20),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: AppColor.primary.withOpacity(0.4),
|
|
blurRadius: 20,
|
|
offset: const Offset(0, 8),
|
|
spreadRadius: 0,
|
|
),
|
|
BoxShadow(
|
|
color: Colors.orange.withOpacity(0.2),
|
|
blurRadius: 40,
|
|
offset: const Offset(0, 16),
|
|
spreadRadius: 0,
|
|
),
|
|
],
|
|
),
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.circular(20),
|
|
child: Stack(
|
|
children: [
|
|
// Main gradient background
|
|
Container(
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
colors: [
|
|
AppColor.primary,
|
|
Colors.orange.shade600,
|
|
Colors.red.shade500,
|
|
],
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
stops: const [0.0, 0.6, 1.0],
|
|
),
|
|
),
|
|
child: Column(
|
|
children: [
|
|
// Top section with icon and text
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
// Animated floating icon with multiple effects
|
|
widget.showAnimation
|
|
? AnimatedBuilder(
|
|
animation: _floatingAnimation,
|
|
builder: (context, child) {
|
|
return Transform.translate(
|
|
offset: Offset(0, _floatingAnimation.value),
|
|
child: _buildIcon(),
|
|
);
|
|
},
|
|
)
|
|
: _buildIcon(),
|
|
|
|
const SizedBox(width: 20),
|
|
|
|
// Enhanced text section - now expanded fully
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
widget.title,
|
|
style: const TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w900,
|
|
color: Colors.white,
|
|
letterSpacing: 0.5,
|
|
shadows: [
|
|
Shadow(
|
|
offset: Offset(0, 2),
|
|
blurRadius: 4,
|
|
color: Colors.black26,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
widget.subtitle,
|
|
style: TextStyle(
|
|
fontSize: 13,
|
|
color: Colors.white.withOpacity(0.95),
|
|
height: 1.2,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// Bottom action button - full width
|
|
_buildActionButton(),
|
|
],
|
|
),
|
|
),
|
|
|
|
// Shimmer overlay effect
|
|
if (widget.showAnimation)
|
|
AnimatedBuilder(
|
|
animation: _shimmerAnimation,
|
|
builder: (context, child) {
|
|
return Positioned.fill(
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
colors: [
|
|
Colors.transparent,
|
|
Colors.white.withOpacity(0.1),
|
|
Colors.transparent,
|
|
],
|
|
stops: const [0.0, 0.5, 1.0],
|
|
begin: Alignment(_shimmerAnimation.value, -1),
|
|
end: Alignment(_shimmerAnimation.value + 0.5, 1),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
|
|
// Decorative dots pattern
|
|
Positioned(
|
|
top: -20,
|
|
right: -20,
|
|
child: Container(
|
|
width: 100,
|
|
height: 100,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.white.withOpacity(0.05),
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
bottom: -10,
|
|
left: -30,
|
|
child: Container(
|
|
width: 60,
|
|
height: 60,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.orange.withOpacity(0.1),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
// Wrap with gesture detector and animations
|
|
if (widget.onTap != null) {
|
|
banner = GestureDetector(onTap: widget.onTap, child: banner);
|
|
}
|
|
|
|
if (widget.showAnimation) {
|
|
return AnimatedBuilder(
|
|
animation: _pulseAnimation,
|
|
builder: (context, child) {
|
|
return Transform.scale(scale: _pulseAnimation.value, child: banner);
|
|
},
|
|
);
|
|
}
|
|
|
|
return banner;
|
|
}
|
|
|
|
Widget _buildIcon() {
|
|
return Container(
|
|
width: 64,
|
|
height: 64,
|
|
decoration: BoxDecoration(
|
|
gradient: RadialGradient(
|
|
colors: [
|
|
Colors.yellow.shade300,
|
|
Colors.orange.shade400,
|
|
Colors.red.shade500,
|
|
],
|
|
),
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.orange.withOpacity(0.6),
|
|
blurRadius: 12,
|
|
spreadRadius: 2,
|
|
),
|
|
BoxShadow(
|
|
color: Colors.yellow.withOpacity(0.3),
|
|
blurRadius: 20,
|
|
spreadRadius: 4,
|
|
),
|
|
],
|
|
),
|
|
child: Stack(
|
|
children: [
|
|
const Center(
|
|
child: Icon(
|
|
Icons.casino,
|
|
color: Colors.white,
|
|
size: 32,
|
|
shadows: [
|
|
Shadow(
|
|
offset: Offset(0, 2),
|
|
blurRadius: 4,
|
|
color: Colors.black26,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
// Sparkle effects
|
|
Positioned(
|
|
top: 8,
|
|
right: 8,
|
|
child: Container(
|
|
width: 8,
|
|
height: 8,
|
|
decoration: const BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.white,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.white,
|
|
blurRadius: 4,
|
|
spreadRadius: 1,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
bottom: 10,
|
|
left: 10,
|
|
child: Container(
|
|
width: 4,
|
|
height: 4,
|
|
decoration: const BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.white70,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildActionButton() {
|
|
return Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
colors: [Colors.white, Colors.yellow.shade100],
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
),
|
|
borderRadius: BorderRadius.circular(25),
|
|
border: Border.all(color: Colors.white.withOpacity(0.3), width: 1),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.2),
|
|
blurRadius: 8,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
BoxShadow(
|
|
color: Colors.white.withOpacity(0.5),
|
|
blurRadius: 4,
|
|
offset: const Offset(0, -1),
|
|
),
|
|
],
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
widget.actionText,
|
|
style: TextStyle(
|
|
color: AppColor.primary,
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w800,
|
|
letterSpacing: 0.5,
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
Container(
|
|
padding: const EdgeInsets.all(3),
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: AppColor.primary.withOpacity(0.1),
|
|
),
|
|
child: Icon(
|
|
Icons.arrow_forward_rounded,
|
|
color: AppColor.primary,
|
|
size: 16,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|