diff --git a/lib/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart index 88399e5..c07e12d 100644 --- a/lib/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart +++ b/lib/presentation/pages/draw/pages/draw_detail/pages/draw_today_page.dart @@ -1,3 +1,4 @@ +import 'dart:math' show cos, sin; import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; @@ -17,16 +18,27 @@ class _DrawTodayPageState extends State late AnimationController _slideController; late AnimationController _scaleController; late AnimationController _pulseController; + late AnimationController _celebrationController; late Animation _fadeAnimation; late Animation _slideAnimation; late Animation _scaleAnimation; late Animation _pulseAnimation; + late Animation _celebrationAnimation; + + // Lottery Logic + String globalNumber = '849302'; + String userNumber = '849302'; // Change this to test winner/loser + bool isWinner = false; + bool hasCheckedResult = false; @override void initState() { super.initState(); + // Check if user is winner + isWinner = userNumber == globalNumber; + _fadeController = AnimationController( duration: Duration(milliseconds: 1200), vsync: this, @@ -47,6 +59,11 @@ class _DrawTodayPageState extends State vsync: this, ); + _celebrationController = AnimationController( + duration: Duration(milliseconds: 3000), + vsync: this, + ); + _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut), ); @@ -64,6 +81,10 @@ class _DrawTodayPageState extends State CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut), ); + _celebrationAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _celebrationController, curve: Curves.elasticOut), + ); + _startAnimations(); } @@ -77,6 +98,11 @@ class _DrawTodayPageState extends State await Future.delayed(Duration(milliseconds: 300)); _scaleController.forward(); + if (isWinner) { + await Future.delayed(Duration(milliseconds: 600)); + _celebrationController.forward(); + } + await Future.delayed(Duration(milliseconds: 800)); _pulseController.repeat(reverse: true); } @@ -87,9 +113,348 @@ class _DrawTodayPageState extends State _slideController.dispose(); _scaleController.dispose(); _pulseController.dispose(); + _celebrationController.dispose(); super.dispose(); } + void _checkMyNumber() { + setState(() { + hasCheckedResult = true; + }); + + if (isWinner) { + _showWinnerDialog(); + } else { + _showLoserDialog(); + } + } + + void _showWinnerDialog() { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return Dialog( + backgroundColor: Colors.transparent, + child: Container( + padding: EdgeInsets.all(24), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [AppColor.warning, AppColor.warning.withOpacity(0.8)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: AppColor.warning.withOpacity(0.5), + blurRadius: 30, + spreadRadius: 5, + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Animated Trophy + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: Duration(milliseconds: 1000), + curve: Curves.elasticOut, + builder: (context, value, child) { + return Transform.scale( + scale: value, + child: Transform.rotate( + angle: (1 - value) * 0.5, + child: Icon( + Icons.emoji_events_rounded, + color: AppColor.white, + size: 80, + ), + ), + ); + }, + ), + + SizedBox(height: 20), + + Text( + 'SELAMAT!', + style: AppStyle.h2.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w900, + letterSpacing: 2, + ), + ), + + SizedBox(height: 8), + + Text( + 'Kamu Pemenang Hari Ini!', + style: AppStyle.lg.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w600, + ), + ), + + SizedBox(height: 16), + + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.white.withOpacity(0.2), + borderRadius: BorderRadius.circular(16), + ), + child: Column( + children: [ + Text( + 'Nomor Pemenang', + style: AppStyle.sm.copyWith( + color: AppColor.white.withOpacity(0.8), + fontWeight: FontWeight.w600, + ), + ), + SizedBox(height: 8), + Text( + globalNumber, + style: TextStyle( + color: AppColor.white, + fontSize: 32, + fontWeight: FontWeight.w900, + letterSpacing: 8, + ), + ), + ], + ), + ), + + SizedBox(height: 20), + + Container( + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: AppColor.primary, + borderRadius: BorderRadius.circular(12), + ), + child: Text( + '🏆 Hadiah: 3KG Emas Batangan 🏆', + style: AppStyle.md.copyWith( + color: AppColor.white, + fontWeight: FontWeight.w700, + ), + ), + ), + + SizedBox(height: 24), + + Row( + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.of(context).pop(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: AppColor.white, + foregroundColor: AppColor.primary, + padding: EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text( + 'Tutup', + style: AppStyle.md.copyWith( + fontWeight: FontWeight.w600, + ), + ), + ), + ), + SizedBox(width: 12), + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.of(context).pop(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Tim kami akan menghubungimu segera!', + ), + backgroundColor: AppColor.success, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + behavior: SnackBarBehavior.floating, + ), + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: AppColor.primary, + foregroundColor: AppColor.white, + padding: EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text( + 'Klaim Hadiah', + style: AppStyle.md.copyWith( + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + ], + ), + ), + ); + }, + ); + } + + void _showLoserDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return Dialog( + backgroundColor: Colors.transparent, + child: Container( + padding: EdgeInsets.all(24), + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: AppColor.black.withOpacity(0.1), + blurRadius: 20, + spreadRadius: 0, + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.primary.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Icon( + Icons.close_rounded, + color: AppColor.primary, + size: 40, + ), + ), + + SizedBox(height: 16), + + Text( + 'Belum Beruntung', + style: AppStyle.lg.copyWith( + color: AppColor.primary, + fontWeight: FontWeight.w700, + ), + ), + + SizedBox(height: 8), + + Text( + 'Jangan menyerah! Coba lagi besok ya', + textAlign: TextAlign.center, + style: AppStyle.md.copyWith( + color: AppColor.textSecondary, + fontWeight: FontWeight.w500, + ), + ), + + SizedBox(height: 16), + + Container( + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: AppColor.primary.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Nomor Global:', + style: AppStyle.sm.copyWith( + color: AppColor.textSecondary, + fontWeight: FontWeight.w500, + ), + ), + Text( + globalNumber, + style: AppStyle.sm.copyWith( + color: AppColor.primary, + fontWeight: FontWeight.w700, + letterSpacing: 2, + ), + ), + ], + ), + SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Nomor Kamu:', + style: AppStyle.sm.copyWith( + color: AppColor.textSecondary, + fontWeight: FontWeight.w500, + ), + ), + Text( + userNumber, + style: AppStyle.sm.copyWith( + color: AppColor.textPrimary, + fontWeight: FontWeight.w700, + letterSpacing: 2, + ), + ), + ], + ), + ], + ), + ), + + SizedBox(height: 20), + + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + Navigator.of(context).pop(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: AppColor.primary, + foregroundColor: AppColor.white, + padding: EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text( + 'Oke, Sampai Jumpa Besok!', + style: AppStyle.md.copyWith(fontWeight: FontWeight.w600), + ), + ), + ), + ], + ), + ), + ); + }, + ); + } + Widget _buildTitle() { return SlideTransition( position: _slideAnimation, @@ -130,78 +495,111 @@ class _DrawTodayPageState extends State borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( - color: AppColor.black.withOpacity(0.08), + color: isWinner + ? AppColor.warning.withOpacity(0.3) + : AppColor.black.withOpacity(0.08), blurRadius: 30, spreadRadius: 0, offset: Offset(0, 15), ), ], ), - child: Padding( - padding: EdgeInsets.all(24), - child: Column( - children: [ - // Label - Container( - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), - decoration: BoxDecoration( - color: AppColor.primary.withOpacity(0.08), - borderRadius: BorderRadius.circular(20), - ), - child: Text( - 'NOMOR UNDIAN GLOBAL', - style: AppStyle.xs.copyWith( - color: AppColor.primary, - fontWeight: FontWeight.w700, - letterSpacing: 1, - ), + child: Stack( + children: [ + // Winner celebration overlay + if (isWinner) + Positioned.fill( + child: AnimatedBuilder( + animation: _celebrationAnimation, + builder: (context, child) { + return CustomPaint( + painter: WinnerCelebrationPainter( + _celebrationAnimation.value, + ), + ); + }, ), ), - SizedBox(height: 20), - - // Animated Number - AnimatedBuilder( - animation: _pulseAnimation, - builder: (context, child) { - return Transform.scale( - scale: _pulseAnimation.value, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 16, - ), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - AppColor.primary.withOpacity(0.05), - AppColor.primary.withOpacity(0.02), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: AppColor.primary.withOpacity(0.1), - width: 1, - ), - ), - child: Text( - '849302', - style: TextStyle( - color: AppColor.primary, - fontSize: 42, - fontWeight: FontWeight.w900, - letterSpacing: 12, - height: 1.0, - ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + children: [ + // Label + Container( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: isWinner + ? AppColor.warning.withOpacity(0.15) + : AppColor.primary.withOpacity(0.08), + borderRadius: BorderRadius.circular(20), + ), + child: Text( + isWinner ? '🎉 NOMOR PEMENANG 🎉' : 'NOMOR UNDIAN GLOBAL', + style: AppStyle.xs.copyWith( + color: isWinner ? AppColor.warning : AppColor.primary, + fontWeight: FontWeight.w700, + letterSpacing: 1, ), ), - ); - }, + ), + + SizedBox(height: 20), + + // Animated Number + AnimatedBuilder( + animation: _pulseAnimation, + builder: (context, child) { + return Transform.scale( + scale: _pulseAnimation.value, + child: Container( + width: double.infinity, + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 16, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: isWinner + ? [ + AppColor.warning.withOpacity(0.1), + AppColor.warning.withOpacity(0.05), + ] + : [ + AppColor.primary.withOpacity(0.05), + AppColor.primary.withOpacity(0.02), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: isWinner + ? AppColor.warning.withOpacity(0.3) + : AppColor.primary.withOpacity(0.1), + width: 1, + ), + ), + child: Text( + globalNumber, + style: TextStyle( + color: isWinner + ? AppColor.warning + : AppColor.primary, + fontSize: 42, + fontWeight: FontWeight.w900, + letterSpacing: 12, + height: 1.0, + ), + ), + ), + ); + }, + ), + ], ), - ], - ), + ), + ], ), ), ); @@ -310,6 +708,79 @@ class _DrawTodayPageState extends State padding: EdgeInsets.symmetric(horizontal: 20), child: Column( children: [ + // Check My Number Button + Container( + width: double.infinity, + margin: EdgeInsets.only(bottom: 12), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: hasCheckedResult ? null : _checkMyNumber, + borderRadius: BorderRadius.circular(16), + child: Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: hasCheckedResult + ? null + : LinearGradient( + colors: [ + AppColor.warning.withOpacity(0.8), + AppColor.warning, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + color: hasCheckedResult + ? AppColor.black.withOpacity(0.15) + : null, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: hasCheckedResult + ? AppColor.white.withOpacity(0.15) + : AppColor.warning.withOpacity(0.3), + width: 1, + ), + boxShadow: hasCheckedResult + ? null + : [ + BoxShadow( + color: AppColor.warning.withOpacity(0.3), + blurRadius: 15, + offset: Offset(0, 5), + ), + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + hasCheckedResult + ? Icons.check_circle_rounded + : Icons.casino_rounded, + color: hasCheckedResult + ? AppColor.white.withOpacity(0.5) + : AppColor.white, + size: 20, + ), + SizedBox(width: 8), + Text( + hasCheckedResult + ? 'Sudah Dicek' + : 'Cek Nomorku Sekarang!', + style: AppStyle.md.copyWith( + color: hasCheckedResult + ? AppColor.white.withOpacity(0.5) + : AppColor.white, + fontWeight: FontWeight.w700, + ), + ), + ], + ), + ), + ), + ), + ), + // Next Draw Card Container( width: double.infinity, @@ -389,7 +860,7 @@ class _DrawTodayPageState extends State ), SizedBox(width: 8), Text( - 'Cek tiket undianmu di menu Tiket Saya', + 'Nomormu hari ini: $userNumber', style: AppStyle.xs.copyWith( color: AppColor.white.withOpacity(0.9), fontWeight: FontWeight.w500, @@ -450,3 +921,29 @@ class _DrawTodayPageState extends State ); } } + +// Custom painter for winner celebration effect +class WinnerCelebrationPainter extends CustomPainter { + final double animationValue; + + WinnerCelebrationPainter(this.animationValue); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint()..style = PaintingStyle.fill; + + // Draw floating golden particles + for (int i = 0; i < 12; i++) { + final angle = (i * 30) * (3.14159 / 180); + final radius = animationValue * 50; + final x = size.width / 2 + radius * cos(angle); + final y = size.height / 2 + radius * sin(angle); + + paint.color = AppColor.warning.withOpacity(0.4 * animationValue); + canvas.drawCircle(Offset(x, y), 3 * animationValue, paint); + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => true; +}