fixed slot machine
This commit is contained in:
parent
004328489d
commit
a56c3e0922
|
|
@ -7,6 +7,7 @@ import '../../core/models/chit_group.dart';
|
||||||
import '../../shared/widgets/draw_animation_selector.dart';
|
import '../../shared/widgets/draw_animation_selector.dart';
|
||||||
import '../../shared/widgets/recording_overlay.dart';
|
import '../../shared/widgets/recording_overlay.dart';
|
||||||
import '../../core/services/screen_recording_service.dart';
|
import '../../core/services/screen_recording_service.dart';
|
||||||
|
import 'draw_animation_page.dart';
|
||||||
|
|
||||||
class CombinedDrawDialog extends StatefulWidget {
|
class CombinedDrawDialog extends StatefulWidget {
|
||||||
final ChitGroup group;
|
final ChitGroup group;
|
||||||
|
|
@ -130,13 +131,36 @@ class _CombinedDrawDialogState extends State<CombinedDrawDialog>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _startDraw() {
|
void _startDraw() async {
|
||||||
if (!_formKey.currentState!.validate()) return;
|
if (!_formKey.currentState!.validate()) return;
|
||||||
|
|
||||||
setState(() {
|
// Generate seeds before navigation
|
||||||
_isDrawStarted = true;
|
_generateSeeds();
|
||||||
_generateSeeds();
|
|
||||||
});
|
final month = int.parse(_monthController.text);
|
||||||
|
final year = int.parse(_yearController.text);
|
||||||
|
|
||||||
|
// Close this dialog and navigate to full-screen draw animation
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
final result = await Get.to(
|
||||||
|
() => DrawAnimationPage(
|
||||||
|
group: widget.group,
|
||||||
|
month: month,
|
||||||
|
year: year,
|
||||||
|
serverSeed: _serverSeed!,
|
||||||
|
nonce: _nonce!,
|
||||||
|
eligibleMembers: _eligibleMembers,
|
||||||
|
),
|
||||||
|
transition: Transition.fadeIn,
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
);
|
||||||
|
|
||||||
|
// If draw was successful, reload draws in parent
|
||||||
|
if (result == true) {
|
||||||
|
final chitGroupService = Get.find<ChitGroupService>();
|
||||||
|
await chitGroupService.loadGroupMonthlyDraws(widget.group.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _generateSeeds() {
|
void _generateSeeds() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,349 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import '../../core/services/chit_group_service.dart';
|
||||||
|
import '../../core/models/chit_group.dart';
|
||||||
|
import '../../shared/widgets/draw_animation_selector.dart';
|
||||||
|
|
||||||
|
class DrawAnimationPage extends StatefulWidget {
|
||||||
|
final ChitGroup group;
|
||||||
|
final int month;
|
||||||
|
final int year;
|
||||||
|
final String serverSeed;
|
||||||
|
final int nonce;
|
||||||
|
final List<Map<String, dynamic>> eligibleMembers;
|
||||||
|
|
||||||
|
const DrawAnimationPage({
|
||||||
|
super.key,
|
||||||
|
required this.group,
|
||||||
|
required this.month,
|
||||||
|
required this.year,
|
||||||
|
required this.serverSeed,
|
||||||
|
required this.nonce,
|
||||||
|
required this.eligibleMembers,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DrawAnimationPage> createState() => _DrawAnimationPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DrawAnimationPageState extends State<DrawAnimationPage>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late AnimationController _fadeController;
|
||||||
|
late Animation<double> _fadeAnimation;
|
||||||
|
bool _isComplete = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_fadeController = AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 800),
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
|
||||||
|
_fadeAnimation = Tween<double>(
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
).animate(CurvedAnimation(
|
||||||
|
parent: _fadeController,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
));
|
||||||
|
|
||||||
|
_fadeController.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_fadeController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onDrawComplete(String winnerId) async {
|
||||||
|
if (_isComplete) return;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isComplete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait a moment to show the winner
|
||||||
|
await Future.delayed(const Duration(seconds: 3));
|
||||||
|
|
||||||
|
// Save the draw result
|
||||||
|
final chitGroupService = Get.find<ChitGroupService>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await chitGroupService.createMonthlyDraw(
|
||||||
|
widget.group.id,
|
||||||
|
widget.month,
|
||||||
|
widget.year,
|
||||||
|
clientSeed: 'DRAW_${DateTime.now().millisecondsSinceEpoch}',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Navigate back with success
|
||||||
|
Get.back(result: true);
|
||||||
|
|
||||||
|
Get.snackbar(
|
||||||
|
'Draw Complete! 🎉',
|
||||||
|
'Winner has been selected successfully',
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
colorText: Colors.white,
|
||||||
|
duration: const Duration(seconds: 3),
|
||||||
|
snackPosition: SnackPosition.TOP,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Get.back(result: false);
|
||||||
|
|
||||||
|
Get.snackbar(
|
||||||
|
'Error',
|
||||||
|
'Failed to save draw result: ${e.toString()}',
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
duration: const Duration(seconds: 4),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () async {
|
||||||
|
// Prevent back button during animation
|
||||||
|
if (_isComplete) return true;
|
||||||
|
|
||||||
|
final result = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: const Text('Cancel Draw?'),
|
||||||
|
content: const Text('Are you sure you want to cancel the draw? This action cannot be undone.'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, false),
|
||||||
|
child: const Text('Continue Draw'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => Navigator.pop(context, true),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
child: const Text('Cancel Draw'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return result ?? false;
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
body: SafeArea(
|
||||||
|
child: FadeTransition(
|
||||||
|
opacity: _fadeAnimation,
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
colors: [
|
||||||
|
Colors.purple.shade900,
|
||||||
|
Colors.blue.shade900,
|
||||||
|
Colors.indigo.shade900,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Header
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(20.w),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
if (!_isComplete)
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.close,
|
||||||
|
color: Colors.white.withOpacity(0.8),
|
||||||
|
size: 28.w,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final result = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: const Text('Cancel Draw?'),
|
||||||
|
content: const Text('Are you sure you want to cancel the draw?'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, false),
|
||||||
|
child: const Text('Continue'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => Navigator.pop(context, true),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == true) {
|
||||||
|
Get.back(result: false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else
|
||||||
|
SizedBox(width: 48.w),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.group.name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24.sp,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 16.w,
|
||||||
|
vertical: 6.h,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white.withOpacity(0.2),
|
||||||
|
borderRadius: BorderRadius.circular(20.r),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.white.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'Month ${widget.month}/${widget.year}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 48.w),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Animation Area
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: DrawAnimationSelector(
|
||||||
|
members: widget.eligibleMembers,
|
||||||
|
onDrawComplete: _onDrawComplete,
|
||||||
|
serverSeed: widget.serverSeed,
|
||||||
|
clientSeed: 'DRAW_${DateTime.now().millisecondsSinceEpoch}',
|
||||||
|
nonce: widget.nonce,
|
||||||
|
animationDuration: const Duration(seconds: 8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(20.w),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.white.withOpacity(0.2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
_buildInfoItem(
|
||||||
|
'Eligible Members',
|
||||||
|
'${widget.eligibleMembers.length}',
|
||||||
|
Icons.people,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 1,
|
||||||
|
height: 30.h,
|
||||||
|
color: Colors.white.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
_buildInfoItem(
|
||||||
|
'Total Members',
|
||||||
|
'${widget.group.maxMembers}',
|
||||||
|
Icons.group,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 12.h),
|
||||||
|
Text(
|
||||||
|
'🎲 Provably Fair Draw',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
color: Colors.white.withOpacity(0.7),
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoItem(String label, String value, IconData icon) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
icon,
|
||||||
|
color: Colors.white.withOpacity(0.8),
|
||||||
|
size: 24.w,
|
||||||
|
),
|
||||||
|
SizedBox(height: 6.h),
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.sp,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
color: Colors.white.withOpacity(0.7),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -403,7 +403,6 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
|
||||||
String? _winnerId;
|
String? _winnerId;
|
||||||
List<String> _displayNames = [];
|
List<String> _displayNames = [];
|
||||||
Timer? _slotTimer;
|
Timer? _slotTimer;
|
||||||
int _currentSelectedIndex = 0;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -491,8 +490,6 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
|
||||||
setState(() {
|
setState(() {
|
||||||
// Shuffle the display names for effect
|
// Shuffle the display names for effect
|
||||||
_displayNames.shuffle();
|
_displayNames.shuffle();
|
||||||
// Update current selection pointer
|
|
||||||
_currentSelectedIndex = currentSpin % _displayNames.length;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_slotController.forward().then((_) {
|
_slotController.forward().then((_) {
|
||||||
|
|
@ -516,7 +513,6 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_displayNames.shuffle();
|
_displayNames.shuffle();
|
||||||
_currentSelectedIndex = currentSpin % _displayNames.length;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_slotController.forward().then((_) {
|
_slotController.forward().then((_) {
|
||||||
|
|
@ -531,15 +527,27 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _completeAnimation() {
|
void _completeAnimation() {
|
||||||
|
final winnerName = widget.members.firstWhere((m) => m['id'] == _winnerId)['name'];
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_isAnimating = false;
|
_isAnimating = false;
|
||||||
_isComplete = true;
|
_isComplete = true;
|
||||||
// Set the winner's name at the top
|
// Show winner in center position (index 2) with padding names
|
||||||
_displayNames = [widget.members.firstWhere((m) => m['id'] == _winnerId)['name']];
|
_displayNames = [
|
||||||
|
_displayNames.isNotEmpty ? _displayNames[0] : '',
|
||||||
|
_displayNames.length > 1 ? _displayNames[1] : '',
|
||||||
|
winnerName, // Center - the winner!
|
||||||
|
_displayNames.length > 3 ? _displayNames[3] : '',
|
||||||
|
_displayNames.length > 4 ? _displayNames[4] : '',
|
||||||
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
_pulseController.stop();
|
_pulseController.stop();
|
||||||
widget.onDrawComplete(_winnerId!);
|
|
||||||
|
// Delay callback slightly for visual effect
|
||||||
|
Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
|
widget.onDrawComplete(_winnerId!);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
String _generateHash(String input) {
|
String _generateHash(String input) {
|
||||||
|
|
@ -640,55 +648,97 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
|
||||||
animation: _slotAnimation,
|
animation: _slotAnimation,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return Column(
|
return Column(
|
||||||
children: _displayNames.take(5).map((name) {
|
children: List.generate(5, (index) {
|
||||||
final index = _displayNames.indexOf(name);
|
final displayIndex = index < _displayNames.length ? index : 0;
|
||||||
final isWinner = _isComplete && index == 0;
|
final name = _displayNames[displayIndex];
|
||||||
final isCurrentlySelected = _isAnimating && index == _currentSelectedIndex;
|
final isWinner = _isComplete && index == 2; // Center position
|
||||||
|
final isCenterHighlight = _isAnimating && index == 2; // Always highlight center
|
||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: AnimatedBuilder(
|
child: AnimatedBuilder(
|
||||||
animation: _pulseAnimation,
|
animation: _pulseAnimation,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return Transform.scale(
|
return AnimatedContainer(
|
||||||
scale: isCurrentlySelected ? _pulseAnimation.value : 1.0,
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
transform: Matrix4.identity()
|
||||||
|
..scale(isCenterHighlight || isWinner ? 1.05 : 1.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
margin: EdgeInsets.symmetric(vertical: 2.h),
|
margin: EdgeInsets.symmetric(vertical: 2.h, horizontal: 4.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isWinner
|
gradient: isWinner
|
||||||
? Colors.green.shade600
|
? LinearGradient(
|
||||||
: isCurrentlySelected
|
colors: [
|
||||||
? Colors.red.shade600
|
Colors.green.shade600,
|
||||||
: Colors.blue.shade600,
|
Colors.green.shade700,
|
||||||
borderRadius: BorderRadius.circular(4.r),
|
],
|
||||||
boxShadow: isWinner ? [
|
)
|
||||||
BoxShadow(
|
: isCenterHighlight
|
||||||
color: Colors.green.shade300,
|
? LinearGradient(
|
||||||
blurRadius: 8.r,
|
colors: [
|
||||||
spreadRadius: 2.r,
|
Colors.orange.shade600,
|
||||||
),
|
Colors.red.shade600,
|
||||||
] : isCurrentlySelected ? [
|
],
|
||||||
BoxShadow(
|
)
|
||||||
color: Colors.red.shade300,
|
: LinearGradient(
|
||||||
blurRadius: 6.r,
|
colors: [
|
||||||
spreadRadius: 1.r,
|
Colors.blue.shade700,
|
||||||
),
|
Colors.blue.shade800,
|
||||||
] : null,
|
],
|
||||||
|
),
|
||||||
|
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: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
name.length > 12 ? '${name.substring(0, 12)}...' : name,
|
name.length > 15 ? '${name.substring(0, 15)}...' : name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.sp,
|
fontSize: isWinner || isCenterHighlight ? 18.sp : 15.sp,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: isWinner || isCenterHighlight
|
||||||
|
? FontWeight.w900
|
||||||
|
: FontWeight.w600,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
shadows: isWinner ? [
|
letterSpacing: 0.5,
|
||||||
|
shadows: [
|
||||||
Shadow(
|
Shadow(
|
||||||
color: Colors.black.withOpacity(0.3),
|
color: Colors.black.withOpacity(0.5),
|
||||||
blurRadius: 2.r,
|
blurRadius: 3.r,
|
||||||
offset: Offset(1, 1),
|
offset: Offset(1, 1),
|
||||||
),
|
),
|
||||||
] : null,
|
],
|
||||||
),
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -696,7 +746,7 @@ class _SlotMachineDrawAnimationState extends State<SlotMachineDrawAnimation>
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue