draw updates

This commit is contained in:
Deep Koluguri 2025-11-13 11:07:45 -05:00
parent b1ecd70f8a
commit ac9a0389d1
2 changed files with 231 additions and 519 deletions

View File

@ -569,83 +569,45 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final winnerName = _winnerId != null
? widget.members.firstWhere((m) => m['id'] == _winnerId)['name']
: null;
return Container( return Container(
width: 300.w, width: 320.w,
height: 520.h, height: 520.h,
child: Column( child: Column(
children: [ 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( Expanded(
child: Container( child: Container(
width: 280.w, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.shade800, gradient: LinearGradient(
borderRadius: BorderRadius.circular(16.r), 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), border: Border.all(color: Colors.orange.shade400, width: 3.w),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.3), color: Colors.black.withOpacity(0.35),
blurRadius: 15.r, blurRadius: 18.r,
offset: Offset(0, 8.h), offset: Offset(0, 10.h),
), ),
], ],
), ),
child: Column(
children: [
// Slot Windows
Expanded(
child: Container( child: Container(
margin: EdgeInsets.all(16.w), margin: EdgeInsets.all(18.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black, color: Colors.black,
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(12.r),
), ),
child: Stack( child: Stack(
children: [ children: [
// Animated names
AnimatedBuilder( AnimatedBuilder(
animation: _slotAnimation, animation: _slotAnimation,
builder: (context, child) { builder: (context, child) {
@ -653,88 +615,72 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
children: List.generate(7, (index) { children: List.generate(7, (index) {
final displayIndex = index < _displayNames.length ? index : 0; final displayIndex = index < _displayNames.length ? index : 0;
final name = _displayNames[displayIndex]; final name = _displayNames[displayIndex];
final isWinner = _isComplete && index == 3; // Center position (middle of 7) final isWinner = _isComplete && index == 3;
final isCenterHighlight = _isAnimating && index == 3; // Always highlight center final isCenterHighlight = _isAnimating && index == 3;
return Expanded( return Expanded(
child: AnimatedBuilder( child: AnimatedBuilder(
animation: _pulseAnimation, animation: _pulseAnimation,
builder: (context, child) { 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<Color> colors = isWinner
? [Colors.green.shade500, Colors.green.shade600]
: isCenterHighlight
? [Colors.deepPurple.shade500, Colors.deepPurple.shade700]
: [Colors.blueGrey.shade700, Colors.blueGrey.shade900];
return AnimatedContainer( return AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 220),
curve: Curves.easeInOut, curve: Curves.easeInOut,
transform: Matrix4.identity() transform: Matrix4.identity()..scale(scale),
..scale(isCenterHighlight || isWinner ? 1.05 : 1.0),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
margin: EdgeInsets.symmetric(vertical: 2.h, horizontal: 4.w), margin: EdgeInsets.symmetric(
decoration: BoxDecoration( vertical: 6.h,
gradient: isWinner horizontal: 12.w,
? 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), decoration: BoxDecoration(
gradient: LinearGradient(
colors: colors,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(10.r),
border: Border.all( border: Border.all(
color: isWinner || isCenterHighlight color: Colors.white.withOpacity(isWinner || isCenterHighlight ? 0.7 : 0.15),
? Colors.white.withOpacity(0.6)
: Colors.white.withOpacity(0.1),
width: isWinner || isCenterHighlight ? 2.w : 1.w, width: isWinner || isCenterHighlight ? 2.w : 1.w,
), ),
boxShadow: isWinner boxShadow: [
? [
BoxShadow( BoxShadow(
color: Colors.green.shade300, color: Colors.black.withOpacity(0.4),
blurRadius: 12.r, blurRadius: isWinner ? 14.r : 6.r,
spreadRadius: 3.r, offset: Offset(0, 3.h),
),
]
: 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: Center(
child: Text( child: Text(
name.length > 15 ? '${name.substring(0, 15)}...' : name, name.length > 22 ? '${name.substring(0, 22)}' : name,
style: TextStyle( style: TextStyle(
fontSize: isWinner || isCenterHighlight ? 16.sp : 13.sp, fontSize: fontSize,
fontWeight: isWinner || isCenterHighlight fontWeight: weight,
? FontWeight.w900
: FontWeight.w600,
color: Colors.white, color: Colors.white,
letterSpacing: 0.5, letterSpacing: 0.6,
shadows: [ shadows: [
Shadow( Shadow(
color: Colors.black.withOpacity(0.5), color: Colors.black.withOpacity(0.5),
blurRadius: 3.r, blurRadius: 4.r,
offset: Offset(1, 1), offset: Offset(1.5, 1.5),
), ),
], ],
), ),
@ -752,103 +698,68 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
); );
}, },
), ),
// Winner highlight
if (_isComplete) if (_isComplete)
Positioned( Positioned(
top: 0, top: 0,
left: 0, left: 0,
right: 0, right: 0,
child: Container( child: Container(
height: 60.h, height: 70.h,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.green.shade400.withOpacity(0.3), color: Colors.green.shade400.withOpacity(0.35),
borderRadius: BorderRadius.circular(4.r), borderRadius: BorderRadius.circular(6.r),
), ),
child: Center(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(Icons.emoji_events, color: Colors.yellow, size: 24.w), Icon(Icons.emoji_events, color: Colors.yellowAccent, size: 26.w),
SizedBox(width: 8.w), SizedBox(width: 10.w),
Text( Text(
'WINNER!', 'WINNER',
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w900,
color: Colors.yellowAccent,
),
),
],
),
),
),
],
),
),
),
),
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),
),
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( style: TextStyle(
fontSize: 18.sp, fontSize: 18.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.w700,
color: Colors.yellow, color: Colors.green.shade700,
),
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
), ),
), ),
], ],
), ),
), ),
),
),
],
),
),
),
// 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,
),
)
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,
),
),
], ],
), ),
); );

View File

@ -1,16 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'animated_draw_wheel.dart';
import 'alternative_draw_animations.dart'; import 'alternative_draw_animations.dart';
import 'particle_draw_animation.dart';
enum DrawAnimationType {
spinningWheel,
cardFlip,
slotMachine,
numberRoulette,
particleSystem,
}
class DrawAnimationSelector extends StatefulWidget { class DrawAnimationSelector extends StatefulWidget {
final List<Map<String, dynamic>> members; final List<Map<String, dynamic>> members;
@ -35,28 +25,11 @@ class DrawAnimationSelector extends StatefulWidget {
} }
class _DrawAnimationSelectorState extends State<DrawAnimationSelector> { class _DrawAnimationSelectorState extends State<DrawAnimationSelector> {
DrawAnimationType _selectedAnimation = DrawAnimationType.cardFlip;
bool _isDrawStarted = false; bool _isDrawStarted = false;
@override @override
void initState() { void initState() {
super.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() { void _startDraw() {
@ -73,7 +46,7 @@ class _DrawAnimationSelectorState extends State<DrawAnimationSelector> {
Widget _buildAnimationSelector() { Widget _buildAnimationSelector() {
return Container( return Container(
padding: EdgeInsets.all(20.w), padding: EdgeInsets.all(24.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
@ -86,33 +59,58 @@ class _DrawAnimationSelectorState extends State<DrawAnimationSelector> {
], ],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text( Container(
'Choose Draw Animation', width: 72.w,
style: TextStyle( height: 72.w,
fontSize: 20.sp, decoration: BoxDecoration(
fontWeight: FontWeight.bold, color: Colors.purple.shade50,
color: Colors.grey.shade800, borderRadius: BorderRadius.circular(20.r),
),
child: Icon(
Icons.casino,
color: Colors.purple.shade600,
size: 36.w,
), ),
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Text( 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( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: Colors.grey.shade600, 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), SizedBox(height: 24.h),
// Start Button
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: ElevatedButton( child: ElevatedButton(
@ -131,7 +129,7 @@ class _DrawAnimationSelectorState extends State<DrawAnimationSelector> {
Icon(Icons.play_arrow, size: 20.w), Icon(Icons.play_arrow, size: 20.w),
SizedBox(width: 8.w), SizedBox(width: 8.w),
Text( Text(
'Start ${_getAnimationName(_selectedAnimation)}', 'Start Slot Machine',
style: TextStyle(fontSize: 16.sp), style: TextStyle(fontSize: 16.sp),
), ),
], ],
@ -143,221 +141,6 @@ class _DrawAnimationSelectorState extends State<DrawAnimationSelector> {
); );
} }
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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
@ -366,7 +149,14 @@ class _DrawAnimationSelectorState extends State<DrawAnimationSelector> {
children: [ children: [
if (!_isDrawStarted) _buildAnimationSelector(), if (!_isDrawStarted) _buildAnimationSelector(),
if (_isDrawStarted) ...[ 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(height: 20.h),
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
@ -378,9 +168,20 @@ class _DrawAnimationSelectorState extends State<DrawAnimationSelector> {
borderRadius: BorderRadius.circular(8.r), borderRadius: BorderRadius.circular(8.r),
), ),
), ),
child: Text( child: Row(
'Choose Different Animation', mainAxisAlignment: MainAxisAlignment.center,
style: TextStyle(fontSize: 14.sp), 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,
),
),
],
), ),
), ),
), ),