From ac9a0389d13116a936ef8231e591c43ba36683d3 Mon Sep 17 00:00:00 2001 From: Deep Koluguri Date: Thu, 13 Nov 2025 11:07:45 -0500 Subject: [PATCH] draw updates --- .../widgets/alternative_draw_animations.dart | 421 +++++++----------- .../widgets/draw_animation_selector.dart | 329 +++----------- 2 files changed, 231 insertions(+), 519 deletions(-) diff --git a/luckychit/lib/shared/widgets/alternative_draw_animations.dart b/luckychit/lib/shared/widgets/alternative_draw_animations.dart index 6392cbc..8a5260c 100644 --- a/luckychit/lib/shared/widgets/alternative_draw_animations.dart +++ b/luckychit/lib/shared/widgets/alternative_draw_animations.dart @@ -569,284 +569,195 @@ class _SlotMachineDrawAnimationState extends State @override Widget build(BuildContext context) { + final winnerName = _winnerId != null + ? widget.members.firstWhere((m) => m['id'] == _winnerId)['name'] + : null; + return Container( - width: 300.w, + width: 320.w, height: 520.h, child: Column( children: [ - // Title - Text( - 'Slot Machine Draw', - style: TextStyle( - fontSize: 20.sp, - fontWeight: FontWeight.bold, - color: Colors.orange.shade700, - ), - ), - SizedBox(height: 20.h), - - // Pointer/Indicator - Container( - width: 280.w, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.keyboard_arrow_down, - color: Colors.red.shade600, - size: 30.w, - ), - SizedBox(width: 8.w), - Text( - _isAnimating ? 'Selecting...' : 'Winner!', - style: TextStyle( - fontSize: 14.sp, - fontWeight: FontWeight.bold, - color: _isAnimating ? Colors.orange.shade600 : Colors.green.shade600, - ), - ), - SizedBox(width: 8.w), - Icon( - Icons.keyboard_arrow_down, - color: Colors.red.shade600, - size: 30.w, - ), - ], - ), - ), - - SizedBox(height: 10.h), - - // Slot Machine Display Expanded( child: Container( - width: 280.w, + width: double.infinity, decoration: BoxDecoration( - color: Colors.grey.shade800, - borderRadius: BorderRadius.circular(16.r), + gradient: LinearGradient( + colors: [ + Colors.grey.shade900, + Colors.grey.shade800, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + borderRadius: BorderRadius.circular(20.r), border: Border.all(color: Colors.orange.shade400, width: 3.w), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.3), - blurRadius: 15.r, - offset: Offset(0, 8.h), + color: Colors.black.withOpacity(0.35), + blurRadius: 18.r, + offset: Offset(0, 10.h), ), ], ), - child: Column( - children: [ - // Slot Windows - Expanded( - child: Container( - margin: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(8.r), - ), - child: Stack( - children: [ - // Animated names - AnimatedBuilder( - animation: _slotAnimation, - builder: (context, child) { - return Column( - children: List.generate(7, (index) { - final displayIndex = index < _displayNames.length ? index : 0; - final name = _displayNames[displayIndex]; - final isWinner = _isComplete && index == 3; // Center position (middle of 7) - final isCenterHighlight = _isAnimating && index == 3; // Always highlight center - - return Expanded( - child: AnimatedBuilder( - animation: _pulseAnimation, - builder: (context, child) { - return AnimatedContainer( - duration: const Duration(milliseconds: 200), - curve: Curves.easeInOut, - transform: Matrix4.identity() - ..scale(isCenterHighlight || isWinner ? 1.05 : 1.0), - child: Container( - width: double.infinity, - margin: EdgeInsets.symmetric(vertical: 2.h, horizontal: 4.w), - decoration: BoxDecoration( - gradient: isWinner - ? LinearGradient( - colors: [ - Colors.green.shade600, - Colors.green.shade700, - ], - ) - : isCenterHighlight - ? LinearGradient( - colors: [ - Colors.orange.shade600, - Colors.red.shade600, - ], - ) - : LinearGradient( - colors: [ - Colors.blue.shade700, - Colors.blue.shade800, - ], - ), - borderRadius: BorderRadius.circular(8.r), - border: Border.all( - color: isWinner || isCenterHighlight - ? Colors.white.withOpacity(0.6) - : Colors.white.withOpacity(0.1), - width: isWinner || isCenterHighlight ? 2.w : 1.w, - ), - boxShadow: isWinner - ? [ - BoxShadow( - color: Colors.green.shade300, - blurRadius: 12.r, - spreadRadius: 3.r, - ), - ] - : isCenterHighlight - ? [ - BoxShadow( - color: Colors.orange.shade300.withOpacity(0.6), - blurRadius: 8.r, - spreadRadius: 2.r, - ), - ] - : [ - BoxShadow( - color: Colors.black.withOpacity(0.3), - blurRadius: 4.r, - offset: Offset(0, 2.h), - ), - ], - ), - child: Center( - child: Text( - name.length > 15 ? '${name.substring(0, 15)}...' : name, - style: TextStyle( - fontSize: isWinner || isCenterHighlight ? 16.sp : 13.sp, - fontWeight: isWinner || isCenterHighlight - ? FontWeight.w900 - : FontWeight.w600, - color: Colors.white, - letterSpacing: 0.5, - shadows: [ - Shadow( - color: Colors.black.withOpacity(0.5), - blurRadius: 3.r, - offset: Offset(1, 1), - ), - ], - ), - textAlign: TextAlign.center, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), + child: Container( + margin: EdgeInsets.all(18.w), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(12.r), + ), + child: Stack( + children: [ + AnimatedBuilder( + animation: _slotAnimation, + builder: (context, child) { + return Column( + children: List.generate(7, (index) { + final displayIndex = index < _displayNames.length ? index : 0; + final name = _displayNames[displayIndex]; + final isWinner = _isComplete && index == 3; + final isCenterHighlight = _isAnimating && index == 3; + + return Expanded( + child: AnimatedBuilder( + animation: _pulseAnimation, + builder: (context, child) { + final double scale = isWinner || isCenterHighlight ? 1.08 : 1.0; + final double fontSize = isWinner + ? 24.sp + : isCenterHighlight + ? 20.sp + : 18.sp; + final FontWeight weight = isWinner + ? FontWeight.w900 + : isCenterHighlight + ? FontWeight.w800 + : FontWeight.w700; + final List colors = isWinner + ? [Colors.green.shade500, Colors.green.shade600] + : isCenterHighlight + ? [Colors.deepPurple.shade500, Colors.deepPurple.shade700] + : [Colors.blueGrey.shade700, Colors.blueGrey.shade900]; + + return AnimatedContainer( + duration: const Duration(milliseconds: 220), + curve: Curves.easeInOut, + transform: Matrix4.identity()..scale(scale), + child: Container( + width: double.infinity, + margin: EdgeInsets.symmetric( + vertical: 6.h, + horizontal: 12.w, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: colors, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(10.r), + border: Border.all( + color: Colors.white.withOpacity(isWinner || isCenterHighlight ? 0.7 : 0.15), + width: isWinner || isCenterHighlight ? 2.w : 1.w, + ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.4), + blurRadius: isWinner ? 14.r : 6.r, + offset: Offset(0, 3.h), ), - ); - }, - ), - ); - }), - ); - }, - ), - - // Winner highlight - if (_isComplete) - Positioned( - top: 0, - left: 0, - right: 0, - child: Container( - height: 60.h, - decoration: BoxDecoration( - color: Colors.green.shade400.withOpacity(0.3), - borderRadius: BorderRadius.circular(4.r), - ), - child: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.emoji_events, color: Colors.yellow, size: 24.w), - SizedBox(width: 8.w), - Text( - 'WINNER!', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - color: Colors.yellow, + ], + ), + child: Center( + child: Text( + name.length > 22 ? '${name.substring(0, 22)}…' : name, + style: TextStyle( + fontSize: fontSize, + fontWeight: weight, + color: Colors.white, + letterSpacing: 0.6, + shadows: [ + Shadow( + color: Colors.black.withOpacity(0.5), + blurRadius: 4.r, + offset: Offset(1.5, 1.5), + ), + ], + ), + textAlign: TextAlign.center, + maxLines: 1, + overflow: TextOverflow.ellipsis, ), ), - ], - ), + ), + ); + }, + ), + ); + }), + ); + }, + ), + if (_isComplete) + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + height: 70.h, + decoration: BoxDecoration( + color: Colors.green.shade400.withOpacity(0.35), + borderRadius: BorderRadius.circular(6.r), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.emoji_events, color: Colors.yellowAccent, size: 26.w), + SizedBox(width: 10.w), + Text( + 'WINNER', + style: TextStyle( + fontSize: 20.sp, + fontWeight: FontWeight.w900, + color: Colors.yellowAccent, ), ), - ), - ], + ], + ), + ), ), - ), - ), - - // Slot Machine Controls - Container( - padding: EdgeInsets.all(16.w), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Container( - width: 40.w, - height: 40.w, - decoration: BoxDecoration( - color: Colors.red.shade600, - shape: BoxShape.circle, - ), - child: Icon(Icons.stop, color: Colors.white, size: 20.w), - ), - Container( - width: 40.w, - height: 40.w, - decoration: BoxDecoration( - color: Colors.green.shade600, - shape: BoxShape.circle, - ), - child: Icon(Icons.play_arrow, color: Colors.white, size: 20.w), - ), - Container( - width: 40.w, - height: 40.w, - decoration: BoxDecoration( - color: Colors.blue.shade600, - shape: BoxShape.circle, - ), - child: Icon(Icons.pause, color: Colors.white, size: 20.w), - ), - ], - ), - ), - ], + ], + ), ), ), ), - - // Status - SizedBox(height: 20.h), - if (_isAnimating) - Text( - 'Slot machine spinning...', - style: TextStyle( - fontSize: 16.sp, - color: Colors.orange.shade600, + SizedBox(height: 16.h), + if (_isComplete && winnerName != null) + Container( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.h), + decoration: BoxDecoration( + color: Colors.green.shade50, + borderRadius: BorderRadius.circular(12.r), ), - ) - else if (_isComplete) - Text( - 'Winner: ${widget.members.firstWhere((m) => m['id'] == _winnerId)['name']}', - style: TextStyle( - fontSize: 16.sp, - color: Colors.green.shade600, - fontWeight: FontWeight.bold, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.emoji_events, color: Colors.green.shade600, size: 20.w), + SizedBox(width: 8.w), + Flexible( + child: Text( + winnerName, + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w700, + color: Colors.green.shade700, + ), + textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + ], ), ), ], diff --git a/luckychit/lib/shared/widgets/draw_animation_selector.dart b/luckychit/lib/shared/widgets/draw_animation_selector.dart index 09e46cf..f59eb0d 100644 --- a/luckychit/lib/shared/widgets/draw_animation_selector.dart +++ b/luckychit/lib/shared/widgets/draw_animation_selector.dart @@ -1,16 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'animated_draw_wheel.dart'; import 'alternative_draw_animations.dart'; -import 'particle_draw_animation.dart'; - -enum DrawAnimationType { - spinningWheel, - cardFlip, - slotMachine, - numberRoulette, - particleSystem, -} class DrawAnimationSelector extends StatefulWidget { final List> members; @@ -35,28 +25,11 @@ class DrawAnimationSelector extends StatefulWidget { } class _DrawAnimationSelectorState extends State { - DrawAnimationType _selectedAnimation = DrawAnimationType.cardFlip; bool _isDrawStarted = false; @override void initState() { super.initState(); - // Auto-select best animation based on member count - _selectBestAnimation(); - } - - void _selectBestAnimation() { - final memberCount = widget.members.length; - - if (memberCount <= 8) { - _selectedAnimation = DrawAnimationType.spinningWheel; - } else if (memberCount <= 20) { - _selectedAnimation = DrawAnimationType.cardFlip; - } else if (memberCount <= 50) { - _selectedAnimation = DrawAnimationType.slotMachine; - } else { - _selectedAnimation = DrawAnimationType.particleSystem; - } } void _startDraw() { @@ -73,7 +46,7 @@ class _DrawAnimationSelectorState extends State { Widget _buildAnimationSelector() { return Container( - padding: EdgeInsets.all(20.w), + padding: EdgeInsets.all(24.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16.r), @@ -86,33 +59,58 @@ class _DrawAnimationSelectorState extends State { ], ), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - 'Choose Draw Animation', - style: TextStyle( - fontSize: 20.sp, - fontWeight: FontWeight.bold, - color: Colors.grey.shade800, + Container( + width: 72.w, + height: 72.w, + decoration: BoxDecoration( + color: Colors.purple.shade50, + borderRadius: BorderRadius.circular(20.r), + ), + child: Icon( + Icons.casino, + color: Colors.purple.shade600, + size: 36.w, ), ), SizedBox(height: 16.h), - Text( - 'Members: ${widget.members.length}', + 'Slot Machine Draw', + style: TextStyle( + fontSize: 22.sp, + fontWeight: FontWeight.w700, + color: Colors.grey.shade800, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 12.h), + Text( + 'Our signature animation for dramatic, high-energy winner reveals.', style: TextStyle( fontSize: 14.sp, color: Colors.grey.shade600, + height: 1.4, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 16.h), + Container( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.h), + decoration: BoxDecoration( + color: Colors.purple.shade50, + borderRadius: BorderRadius.circular(12.r), + ), + child: Text( + 'Members in draw: ${widget.members.length}', + style: TextStyle( + fontSize: 13.sp, + fontWeight: FontWeight.w600, + color: Colors.purple.shade600, + ), ), ), - SizedBox(height: 20.h), - - // Animation Options - ...DrawAnimationType.values.map((type) => _buildAnimationOption(type)), - SizedBox(height: 24.h), - - // Start Button SizedBox( width: double.infinity, child: ElevatedButton( @@ -131,7 +129,7 @@ class _DrawAnimationSelectorState extends State { Icon(Icons.play_arrow, size: 20.w), SizedBox(width: 8.w), Text( - 'Start ${_getAnimationName(_selectedAnimation)}', + 'Start Slot Machine', style: TextStyle(fontSize: 16.sp), ), ], @@ -143,221 +141,6 @@ class _DrawAnimationSelectorState extends State { ); } - Widget _buildAnimationOption(DrawAnimationType type) { - final isSelected = _selectedAnimation == type; - final isRecommended = _isRecommendedAnimation(type); - - return Container( - margin: EdgeInsets.only(bottom: 12.h), - child: InkWell( - onTap: () { - setState(() { - _selectedAnimation = type; - }); - }, - borderRadius: BorderRadius.circular(12.r), - child: Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: isSelected ? Colors.purple.shade50 : Colors.grey.shade50, - borderRadius: BorderRadius.circular(12.r), - border: Border.all( - color: isSelected ? Colors.purple.shade300 : Colors.grey.shade300, - width: 2.w, - ), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 24.w, - height: 24.w, - margin: EdgeInsets.only(top: 2.h), - decoration: BoxDecoration( - color: isSelected ? Colors.purple.shade600 : Colors.grey.shade400, - shape: BoxShape.circle, - ), - child: isSelected - ? Icon(Icons.check, color: Colors.white, size: 16.w) - : null, - ), - SizedBox(width: 12.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Flexible( - child: Text( - _getAnimationName(type), - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isSelected ? Colors.purple.shade800 : Colors.grey.shade800, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - if (isRecommended) ...[ - SizedBox(width: 6.w), - Container( - padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h), - decoration: BoxDecoration( - color: Colors.green.shade100, - borderRadius: BorderRadius.circular(12.r), - ), - child: Text( - 'Recommended', - style: TextStyle( - fontSize: 10.sp, - color: Colors.green.shade700, - fontWeight: FontWeight.w500, - ), - ), - ), - ], - ], - ), - SizedBox(height: 6.h), - Text( - _getAnimationDescription(type), - style: TextStyle( - fontSize: 12.sp, - color: Colors.grey.shade600, - height: 1.3, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - SizedBox(width: 12.w), - Icon( - _getAnimationIcon(type), - color: isSelected ? Colors.purple.shade600 : Colors.grey.shade400, - size: 28.w, - ), - ], - ), - ), - ), - ); - } - - bool _isRecommendedAnimation(DrawAnimationType type) { - final memberCount = widget.members.length; - - switch (type) { - case DrawAnimationType.spinningWheel: - return memberCount <= 8; - case DrawAnimationType.cardFlip: - return memberCount > 8 && memberCount <= 20; - case DrawAnimationType.slotMachine: - return memberCount > 20 && memberCount <= 50; - case DrawAnimationType.numberRoulette: - return memberCount > 20 && memberCount <= 100; - case DrawAnimationType.particleSystem: - return memberCount > 50; - } - } - - String _getAnimationName(DrawAnimationType type) { - switch (type) { - case DrawAnimationType.spinningWheel: - return 'Spinning Wheel'; - case DrawAnimationType.cardFlip: - return 'Card Flip'; - case DrawAnimationType.slotMachine: - return 'Slot Machine'; - case DrawAnimationType.numberRoulette: - return 'Number Roulette'; - case DrawAnimationType.particleSystem: - return 'Particle System'; - } - } - - String _getAnimationDescription(DrawAnimationType type) { - switch (type) { - case DrawAnimationType.spinningWheel: - return 'Classic spinning wheel - Best for small groups (≤8 members)'; - case DrawAnimationType.cardFlip: - return 'Cards flipping rapidly - Great for medium groups (9-20 members)'; - case DrawAnimationType.slotMachine: - return 'Slot machine style - Perfect for large groups (21-50 members)'; - case DrawAnimationType.numberRoulette: - return 'Number roulette wheel - Good for very large groups (21-100 members)'; - case DrawAnimationType.particleSystem: - return 'Particle effects - Best for massive groups (50+ members)'; - } - } - - IconData _getAnimationIcon(DrawAnimationType type) { - switch (type) { - case DrawAnimationType.spinningWheel: - return Icons.casino; - case DrawAnimationType.cardFlip: - return Icons.style; - case DrawAnimationType.slotMachine: - return Icons.games; - case DrawAnimationType.numberRoulette: - return Icons.timeline; - case DrawAnimationType.particleSystem: - return Icons.auto_awesome; - } - } - - Widget _buildSelectedAnimation() { - switch (_selectedAnimation) { - case DrawAnimationType.spinningWheel: - return AnimatedDrawWheel( - members: widget.members, - onDrawComplete: widget.onDrawComplete, - serverSeed: widget.serverSeed, - clientSeed: widget.clientSeed, - nonce: widget.nonce, - ); - case DrawAnimationType.cardFlip: - return CardFlipDrawAnimation( - members: widget.members, - onDrawComplete: widget.onDrawComplete, - serverSeed: widget.serverSeed, - clientSeed: widget.clientSeed, - nonce: widget.nonce, - animationDuration: widget.animationDuration, - ); - case DrawAnimationType.slotMachine: - return SlotMachineDrawAnimation( - members: widget.members, - onDrawComplete: widget.onDrawComplete, - serverSeed: widget.serverSeed, - clientSeed: widget.clientSeed, - nonce: widget.nonce, - animationDuration: widget.animationDuration, - ); - case DrawAnimationType.numberRoulette: - return NumberRouletteDrawAnimation( - members: widget.members, - onDrawComplete: widget.onDrawComplete, - serverSeed: widget.serverSeed, - clientSeed: widget.clientSeed, - nonce: widget.nonce, - animationDuration: widget.animationDuration, - ); - case DrawAnimationType.particleSystem: - return ParticleDrawAnimation( - members: widget.members, - onDrawComplete: widget.onDrawComplete, - serverSeed: widget.serverSeed, - clientSeed: widget.clientSeed, - nonce: widget.nonce, - animationDuration: widget.animationDuration, - ); - } - } - @override Widget build(BuildContext context) { return Container( @@ -366,7 +149,14 @@ class _DrawAnimationSelectorState extends State { children: [ if (!_isDrawStarted) _buildAnimationSelector(), if (_isDrawStarted) ...[ - _buildSelectedAnimation(), + SlotMachineDrawAnimation( + members: widget.members, + onDrawComplete: widget.onDrawComplete, + serverSeed: widget.serverSeed, + clientSeed: widget.clientSeed, + nonce: widget.nonce, + animationDuration: widget.animationDuration, + ), SizedBox(height: 20.h), SizedBox( width: double.infinity, @@ -378,9 +168,20 @@ class _DrawAnimationSelectorState extends State { borderRadius: BorderRadius.circular(8.r), ), ), - child: Text( - 'Choose Different Animation', - style: TextStyle(fontSize: 14.sp), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.refresh, size: 18.w, color: Colors.purple.shade600), + SizedBox(width: 6.w), + Text( + 'Spin Again', + style: TextStyle( + fontSize: 14.sp, + fontWeight: FontWeight.w600, + color: Colors.purple.shade600, + ), + ), + ], ), ), ),