Ferish Wheel and Music

This commit is contained in:
efrilm
2025-09-18 14:53:39 +07:00
parent 73918430b2
commit 909c312af0
28 changed files with 970 additions and 1422 deletions
@@ -6,12 +6,30 @@ import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'dart:math' as math;
import '../../../../application/auth/auth_bloc.dart';
import '../../../../application/game/game_price_loader/game_prize_loader_bloc.dart';
import '../../../../application/game/ferris_wheel_loader/ferris_wheel_loader_bloc.dart';
import '../../../../common/theme/theme.dart';
import '../../../../common/painter/wheel_painter.dart';
import '../../../../injection.dart';
import '../../../../domain/game/game.dart';
import 'data/model.dart';
// Simple models for UI state
class PrizeHistory {
final String prize;
final DateTime dateTime;
final int value;
final Color color;
final IconData icon;
final String? gamePrizeId;
PrizeHistory({
required this.prize,
required this.dateTime,
required this.value,
required this.color,
required this.icon,
this.gamePrizeId,
});
}
@RoutePage()
class FerrisWheelPage extends StatefulWidget implements AutoRouteWrapper {
@@ -22,12 +40,9 @@ class FerrisWheelPage extends StatefulWidget implements AutoRouteWrapper {
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (context) => getIt<GamePrizeLoaderBloc>()
..add(
const GamePrizeLoaderEvent.fetched(
'28d5aed3-4c1b-4b7b-bad5-67cdd4919dc2',
),
),
create: (context) =>
getIt<FerrisWheelLoaderBloc>()
..add(const FerrisWheelLoaderEvent.fetched()),
child: this,
);
}
@@ -84,12 +99,10 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
void _initializeAudio() async {
try {
await _bgmPlayer.setSource(
AssetSource('audio/carnival/bgm/carnival_main_theme.mp3'),
);
await _bgmPlayer.setSource(AssetSource('audio/carnaval_main_theme.mp3'));
await _bgmPlayer.setReleaseMode(ReleaseMode.loop);
await _bgmPlayer.setVolume(0.5);
if (_isMusicEnabled) _bgmPlayer.resume();
if (_isMusicEnabled) await _bgmPlayer.resume();
} catch (e) {
print('Error initializing audio: $e');
}
@@ -107,23 +120,10 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
}
}
void _playButtonTap() =>
_playSound('audio/carnival/sfx/button_tap.mp3', volume: 0.3);
void _playTokenSound() =>
_playSound('audio/carnival/sfx/token_sound.mp3', volume: 0.5);
void _playWheelSpin() =>
_playSound('audio/carnival/sfx/wheel_spin.mp3', volume: 0.8);
void _playWinSound(GamePrize prize) {
int prizeValue = prize.metadata['value'] ?? prize.weight;
if (prizeValue >= 1000000) {
_playSound('audio/carnival/sfx/win_big.mp3', volume: 0.9);
} else if (prizeValue >= 5000) {
_playSound('audio/carnival/sfx/win_medium.mp3', volume: 0.8);
} else {
_playSound('audio/carnival/sfx/win_small.mp3', volume: 0.7);
}
}
void _playButtonTap() => _playSound('audio/button_tap.mp3', volume: 0.3);
void _playTokenSound() => _playSound('audio/token_sound.mp3', volume: 0.5);
void _playWheelSpin() => _playSound('audio/wheel_spin.mp3', volume: 0.8);
void _playWinSound() => _playSound('audio/win_medium.mp3', volume: 0.8);
void _toggleSound() {
setState(() => _isSoundEnabled = !_isSoundEnabled);
@@ -170,66 +170,48 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
int _selectPrizeWithWeight() {
if (gamePrizes.isEmpty) return 0;
final availablePrizes = gamePrizes
.asMap()
.entries
.where((entry) => entry.value.stock > 0)
.toList();
// Jika GamePrize memiliki properti weight, gunakan ini:
// List<int> weights = gamePrizes.map((prize) => prize.weight ?? 1).toList();
if (availablePrizes.isEmpty) {
return math.Random().nextInt(gamePrizes.length);
// Untuk sementara, gunakan bobot default yang berbeda
// Hadiah langka (index awal) memiliki bobot lebih kecil
List<int> weights = [];
for (int i = 0; i < gamePrizes.length; i++) {
// Bobot menurun: hadiah pertama langka, hadiah terakhir mudah didapat
int weight = gamePrizes.length - i;
weights.add(weight);
}
int totalWeight = availablePrizes
.map((entry) => entry.value.weight)
.reduce((a, b) => a + b);
// Hitung total bobot
int totalWeight = weights.reduce((a, b) => a + b);
if (totalWeight <= 0) {
final randomEntry =
availablePrizes[math.Random().nextInt(availablePrizes.length)];
return randomEntry.key;
}
// Generate random number
int randomNum = math.Random().nextInt(totalWeight);
int randomWeight = math.Random().nextInt(totalWeight);
// Tentukan hadiah berdasarkan bobot
int currentWeight = 0;
for (final entry in availablePrizes) {
currentWeight += entry.value.weight;
if (randomWeight < currentWeight) {
return entry.key;
for (int i = 0; i < gamePrizes.length; i++) {
currentWeight += weights[i];
if (randomNum < currentWeight) {
return i;
}
}
return availablePrizes.last.key;
// Fallback (seharusnya tidak pernah terjadi)
return gamePrizes.length - 1;
}
Color _getPrizeColor(GamePrize prize, int index) {
final colorName = prize.metadata['color'] as String?;
switch (colorName?.toLowerCase()) {
case 'primary':
return AppColor.primary;
case 'info':
return AppColor.info;
case 'warning':
return AppColor.warning;
case 'success':
return AppColor.success;
case 'error':
return AppColor.error;
case 'secondary':
return AppColor.secondary;
default:
final colors = [
AppColor.primary,
AppColor.info,
AppColor.warning,
AppColor.success,
AppColor.primaryDark,
AppColor.secondary,
AppColor.error,
];
return colors[index % colors.length];
}
final colors = [
AppColor.primary,
AppColor.info,
AppColor.warning,
AppColor.success,
AppColor.primaryDark,
AppColor.secondary,
AppColor.error,
];
return colors[index % colors.length];
}
void _spinWheel() {
@@ -245,23 +227,25 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
});
_idleRotationController.stop();
_idleRotationController.reset();
int targetSection = _selectPrizeWithWeight();
int selectedPrizeIndex = _selectPrizeWithWeight();
double sectionAngle = (2 * math.pi) / gamePrizes.length;
double targetAngle = (targetSection * sectionAngle) + (sectionAngle / 2);
double baseRotations = 4 + math.Random().nextDouble() * 3;
double currentIdleRotation = _idleRotationAnimation?.value ?? 0.0;
double finalRotation =
currentRotation +
currentIdleRotation +
(baseRotations * 2 * math.pi) +
targetAngle;
double currentPos = currentRotation;
_spinAnimation =
Tween<double>(
begin: currentRotation + currentIdleRotation,
end: finalRotation,
).animate(
// TAMBAH offset ke tengah section (bukan garis)
double targetForSelectedSection =
-(selectedPrizeIndex * sectionAngle) - (sectionAngle / 2);
double spins = 6 * 2 * math.pi;
double finalRotation = currentPos + spins + targetForSelectedSection;
while (finalRotation <= currentPos + spins) {
finalRotation += 2 * math.pi;
}
_spinAnimation = Tween<double>(begin: currentPos, end: finalRotation)
.animate(
CurvedAnimation(
parent: _rotationController,
curve: Curves.easeOutCubic,
@@ -270,27 +254,20 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
_rotationController.reset();
_rotationController.animateTo(1.0).then((_) {
final wonPrize = gamePrizes[targetSection];
_playWinSound(wonPrize);
final wonPrize = gamePrizes[selectedPrizeIndex];
_playWinSound();
setState(() {
currentRotation = finalRotation;
isSpinning = false;
resultText = 'Selamat! Anda mendapat ${wonPrize.name}!';
if (wonPrize.stock > 0) {
gamePrizes[targetSection] = wonPrize.copyWith(
stock: wonPrize.stock - 1,
);
}
prizeHistory.insert(
0,
PrizeHistory(
prize: wonPrize.name,
dateTime: DateTime.now(),
value: wonPrize.metadata['value'] ?? wonPrize.weight,
color: _getPrizeColor(wonPrize, targetSection),
value: 100,
color: _getPrizeColor(wonPrize, selectedPrizeIndex),
icon: Icons.card_giftcard,
gamePrizeId: wonPrize.id,
),
@@ -298,7 +275,6 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
});
_showWinDialog(wonPrize);
_idleRotationController.reset();
_idleRotationController.repeat();
});
}
@@ -363,15 +339,6 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
color: AppColor.textWhite,
),
),
if (wonPrize.stock >= 0) ...[
const SizedBox(height: 8),
Text(
'Stok tersisa: ${wonPrize.stock}',
style: AppStyle.sm.copyWith(
color: AppColor.textWhite.withOpacity(0.8),
),
),
],
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
@@ -406,7 +373,7 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
@override
Widget build(BuildContext context) {
return BlocBuilder<GamePrizeLoaderBloc, GamePrizeLoaderState>(
return BlocBuilder<FerrisWheelLoaderBloc, FerrisWheelLoaderState>(
builder: (context, state) {
if (state.isFetching) {
return Scaffold(
@@ -425,10 +392,10 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
);
}
if (gamePrizes.isEmpty && state.gamePrize.isNotEmpty) {
if (gamePrizes.isEmpty && state.ferrisWheel.prizes.isNotEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
gamePrizes = state.gamePrize;
gamePrizes = state.ferrisWheel.prizes;
});
});
}
@@ -445,100 +412,9 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
child: SafeArea(
child: Column(
children: [
// Header
Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
IconButton(
onPressed: () {
_playButtonTap();
context.router.back();
},
icon: Icon(
Icons.close,
color: AppColor.textWhite,
size: 28,
),
),
Expanded(
child: Text(
'SPIN & WIN',
style: AppStyle.h6.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textWhite,
letterSpacing: 2,
),
),
),
IconButton(
onPressed: _toggleMusic,
icon: Icon(
_isMusicEnabled
? Icons.volume_up
: Icons.volume_off,
color: AppColor.textWhite,
),
),
IconButton(
onPressed: _toggleSound,
icon: Icon(
_isSoundEnabled
? Icons.graphic_eq
: Icons.volume_mute,
color: AppColor.textWhite,
),
),
],
),
),
// Tab Selector
Container(
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(25),
),
child: Row(
children: [
for (int i = 0; i < 3; i++)
Expanded(
child: GestureDetector(
onTap: () {
_playButtonTap();
setState(() => currentTabIndex = i);
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 12,
),
decoration: BoxDecoration(
color: currentTabIndex == i
? AppColor.white
: Colors.transparent,
borderRadius: BorderRadius.circular(25),
),
child: Text(
['Spin Wheel', 'Daftar Hadiah', 'Riwayat'][i],
textAlign: TextAlign.center,
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: currentTabIndex == i
? AppColor.primary
: AppColor.textWhite,
),
),
),
),
),
],
),
),
_buildHeader(),
_buildTabSelector(),
const SizedBox(height: 20),
// Content Area
Expanded(
child: currentTabIndex == 0
? _buildMainContent()
@@ -555,254 +431,256 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
);
}
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
IconButton(
onPressed: () {
_playButtonTap();
context.router.back();
},
icon: Icon(Icons.close, color: AppColor.textWhite, size: 28),
),
Expanded(
child: Text(
'SPIN & WIN',
style: AppStyle.h6.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textWhite,
letterSpacing: 2,
),
),
),
IconButton(
onPressed: _toggleMusic,
icon: Icon(
_isMusicEnabled ? Icons.volume_up : Icons.volume_off,
color: AppColor.textWhite,
),
),
IconButton(
onPressed: _toggleSound,
icon: Icon(
_isSoundEnabled ? Icons.graphic_eq : Icons.volume_mute,
color: AppColor.textWhite,
),
),
],
),
);
}
Widget _buildTabSelector() {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(25),
),
child: Row(
children: [
for (int i = 0; i < 3; i++)
Expanded(
child: GestureDetector(
onTap: () {
_playButtonTap();
setState(() => currentTabIndex = i);
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
color: currentTabIndex == i
? AppColor.white
: Colors.transparent,
borderRadius: BorderRadius.circular(25),
),
child: Text(
['Spin Wheel', 'Daftar Hadiah', 'Riwayat'][i],
textAlign: TextAlign.center,
style: AppStyle.md.copyWith(
fontWeight: FontWeight.bold,
color: currentTabIndex == i
? AppColor.primary
: AppColor.textWhite,
),
),
),
),
),
],
),
);
}
Widget _buildMainContent() {
return Column(
children: [
// User Info Card
Container(
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: AppColor.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BlocBuilder<AuthBloc, AuthState>(
builder: (context, auth) {
return Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: AppColor.primary,
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
'G',
style: AppStyle.lg.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
auth.user.name,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
Text(
auth.user.phoneNumber,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
],
),
],
);
},
),
Row(
children: [
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: AppColor.warning,
shape: BoxShape.circle,
),
child: Icon(
Icons.circle,
size: 12,
color: AppColor.textWhite,
),
),
const SizedBox(width: 8),
Text(
'Token: $tokens',
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
],
),
],
),
),
_buildUserInfoCard(),
Text(
resultText,
style: AppStyle.md.copyWith(color: AppColor.textWhite),
),
const SizedBox(height: 20),
// Wheel Section
Expanded(
child: Center(
child: gamePrizes.isEmpty
? SpinKitFadingCircle(color: AppColor.textWhite, size: 36)
: Stack(
alignment: Alignment.center,
: _buildWheelSection(),
),
),
_buildBottomBanner(),
],
);
}
Widget _buildUserInfoCard() {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: AppColor.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BlocBuilder<AuthBloc, AuthState>(
builder: (context, auth) {
return Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: AppColor.primary,
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
'G',
style: AppStyle.lg.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Glow Effect
AnimatedBuilder(
animation: _glowController,
builder: (context, child) => Container(
width: 340,
height: 340,
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColor.white.withOpacity(
0.3 + 0.2 * _glowController.value,
),
blurRadius: 40,
spreadRadius: 10,
),
],
),
Text(
auth.user.name,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
// Spinning Wheel
AnimatedBuilder(
animation: isSpinning
? _rotationController
: _idleRotationController,
builder: (context, child) {
double rotationAngle = isSpinning
? (_spinAnimation?.value ?? currentRotation)
: (currentRotation +
(_idleRotationAnimation?.value ?? 0.0));
return Transform.rotate(
angle: rotationAngle,
child: CustomPaint(
size: const Size(320, 320),
painter: WheelPainter(
gamePrizes: gamePrizes,
getPrizeColor: _getPrizeColor,
),
),
);
},
),
// Spin Button
AnimatedBuilder(
animation:
_pulseAnimation ??
const AlwaysStoppedAnimation(1.0),
builder: (context, child) => Transform.scale(
scale: _pulseAnimation?.value ?? 1.0,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [AppColor.warning, AppColor.warning],
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColor.black.withOpacity(0.3),
blurRadius: 15,
offset: const Offset(0, 6),
),
BoxShadow(
color: AppColor.warning.withOpacity(0.5),
blurRadius: 20,
spreadRadius:
(_pulseAnimation?.value ?? 1.0) * 5,
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(50),
onTap: _spinWheel,
child: Center(
child: Text(
'SPIN',
style: AppStyle.lg.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
letterSpacing: 1,
),
),
),
),
),
),
),
),
// Pointer
Positioned(
top: 30,
child: Container(
width: 0,
height: 0,
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 15,
color: Colors.transparent,
),
right: BorderSide(
width: 15,
color: Colors.transparent,
),
bottom: BorderSide(
width: 30,
color: AppColor.error,
),
),
),
Text(
auth.user.phoneNumber,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
],
),
],
);
},
),
Row(
children: [
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: AppColor.warning,
shape: BoxShape.circle,
),
child: Icon(Icons.circle, size: 12, color: AppColor.textWhite),
),
const SizedBox(width: 8),
Text(
'Token: $tokens',
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
],
),
],
),
);
}
Widget _buildWheelSection() {
return Stack(
alignment: Alignment.center,
children: [
// Glow Effect
AnimatedBuilder(
animation: _glowController,
builder: (context, child) => Container(
width: 340,
height: 340,
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColor.white.withOpacity(
0.3 + 0.2 * _glowController.value,
),
blurRadius: 40,
spreadRadius: 10,
),
],
),
),
),
// Spinning Wheel
AnimatedBuilder(
animation: isSpinning ? _rotationController : _idleRotationController,
builder: (context, child) {
double rotationAngle = isSpinning
? (_spinAnimation?.value ?? currentRotation)
: (currentRotation + (_idleRotationAnimation?.value ?? 0.0));
// Bottom Banner
Container(
margin: const EdgeInsets.all(20),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [AppColor.warning, AppColor.warning],
),
borderRadius: BorderRadius.circular(15),
),
child: Text(
'Spin 30x lagi buat mainin spesial spin',
textAlign: TextAlign.center,
style: AppStyle.lg.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
return Transform.rotate(
angle: rotationAngle,
child: CustomPaint(
size: const Size(320, 320),
painter: WheelPainter(
gamePrizes: gamePrizes,
getPrizeColor: _getPrizeColor,
),
),
);
},
),
// Spin Button
_buildSpinButton(),
// Pointer
Positioned(
top: 30,
child: Container(
width: 0,
height: 0,
decoration: BoxDecoration(
border: Border(
left: BorderSide(width: 15, color: Colors.transparent),
right: BorderSide(width: 15, color: Colors.transparent),
bottom: BorderSide(width: 30, color: AppColor.error),
),
),
),
),
@@ -810,6 +688,73 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
);
}
Widget _buildSpinButton() {
return AnimatedBuilder(
animation: _pulseAnimation ?? const AlwaysStoppedAnimation(1.0),
builder: (context, child) => Transform.scale(
scale: _pulseAnimation?.value ?? 1.0,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [AppColor.warning, AppColor.warning],
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColor.black.withOpacity(0.3),
blurRadius: 15,
offset: const Offset(0, 6),
),
BoxShadow(
color: AppColor.warning.withOpacity(0.5),
blurRadius: 20,
spreadRadius: (_pulseAnimation?.value ?? 1.0) * 5,
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(50),
onTap: _spinWheel,
child: Center(
child: Text(
'SPIN',
style: AppStyle.lg.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
letterSpacing: 1,
),
),
),
),
),
),
),
);
}
Widget _buildBottomBanner() {
return Container(
margin: const EdgeInsets.all(20),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(colors: [AppColor.warning, AppColor.warning]),
borderRadius: BorderRadius.circular(15),
),
child: Text(
'Spin 30x lagi buat mainin spesial spin',
textAlign: TextAlign.center,
style: AppStyle.lg.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
),
),
);
}
Widget _buildPrizeListContent() {
return Container(
margin: const EdgeInsets.all(20),
@@ -892,17 +837,15 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
),
),
Text(
'Nilai: ${prize.metadata['value'] ?? prize.weight}',
'ID: ${prize.id}',
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
Text(
'Stok: ${prize.stock}/${prize.maxStock}',
'Game ID: ${prize.gameId}',
style: AppStyle.xs.copyWith(
color: prize.stock > 0
? AppColor.success
: AppColor.error,
color: AppColor.textSecondary,
),
),
],
@@ -921,7 +864,7 @@ class _FerrisWheelPageState extends State<FerrisWheelPage>
borderRadius: BorderRadius.circular(15),
),
child: Text(
'Weight: ${prize.weight}',
'Hadiah',
style: AppStyle.xs.copyWith(
color: _getPrizeColor(prize, index),
fontWeight: FontWeight.bold,