// wheel_painter.dart - Fixed implementation with consistent positioning import 'dart:math' as math; import 'package:flutter/material.dart'; import '../../domain/game/game.dart'; class WheelPainter extends CustomPainter { final List gamePrizes; final Color Function(GamePrize prize, int index) getPrizeColor; WheelPainter({required this.gamePrizes, required this.getPrizeColor}); @override void paint(Canvas canvas, Size size) { if (gamePrizes.isEmpty) return; final center = Offset(size.width / 2, size.height / 2); final radius = size.width / 2; final sectionAngle = 2 * math.pi / gamePrizes.length; // Draw outer white border final outerBorderPaint = Paint() ..color = Colors.white ..style = PaintingStyle.fill; canvas.drawCircle(center, radius, outerBorderPaint); // Draw blue border ring final blueBorderPaint = Paint() ..color = const Color(0xFF3B82F6) ..style = PaintingStyle.fill; canvas.drawCircle(center, radius - 8, blueBorderPaint); // Draw inner white circle final innerWhitePaint = Paint() ..color = Colors.white ..style = PaintingStyle.fill; canvas.drawCircle(center, radius - 20, innerWhitePaint); // Draw sections - KONSISTEN dengan logic spin for (int i = 0; i < gamePrizes.length; i++) { final prize = gamePrizes[i]; // Section 0 di top (-π/2), section 1 di kanan atas, dst (clockwise) final startAngle = (-math.pi / 2) + (i * sectionAngle); // Section background final sectionPaint = Paint() ..color = getPrizeColor(prize, i) ..style = PaintingStyle.fill; canvas.drawArc( Rect.fromCircle(center: center, radius: radius - 22), startAngle, sectionAngle, true, sectionPaint, ); // Draw prize text final textAngle = startAngle + sectionAngle / 2; final textPosition = Offset( center.dx + (radius - 80) * math.cos(textAngle), center.dy + (radius - 80) * math.sin(textAngle), ); canvas.save(); canvas.translate(textPosition.dx, textPosition.dy); canvas.rotate(textAngle + math.pi / 2); final textPainter = TextPainter( text: TextSpan( text: prize.name, style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, ), ), textDirection: TextDirection.ltr, textAlign: TextAlign.center, ); textPainter.layout(maxWidth: 100); textPainter.paint( canvas, Offset(-textPainter.width / 2, -textPainter.height / 2), ); canvas.restore(); // DEBUG: Draw section number final numberPosition = Offset( center.dx + (radius - 50) * math.cos(textAngle), center.dy + (radius - 50) * math.sin(textAngle), ); canvas.drawCircle(numberPosition, 15, Paint()..color = Colors.white); final numberPainter = TextPainter( text: TextSpan( text: i.toString(), style: const TextStyle( color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold, ), ), textDirection: TextDirection.ltr, ); numberPainter.layout(); numberPainter.paint( canvas, Offset( numberPosition.dx - numberPainter.width / 2, numberPosition.dy - numberPainter.height / 2, ), ); } // Draw white dots final dotPaint = Paint() ..color = Colors.white ..style = PaintingStyle.fill; for (int i = 0; i < 24; i++) { final dotAngle = (2 * math.pi / 24) * i; final dotPosition = Offset( center.dx + (radius - 14) * math.cos(dotAngle), center.dy + (radius - 14) * math.sin(dotAngle), ); canvas.drawCircle(dotPosition, 3, dotPaint); } // Draw section dividers final dividerPaint = Paint() ..color = Colors.white ..style = PaintingStyle.stroke ..strokeWidth = 2; for (int i = 0; i < gamePrizes.length; i++) { final angle = (-math.pi / 2) + (i * sectionAngle); final lineStart = Offset( center.dx + (radius - 110) * math.cos(angle), center.dy + (radius - 110) * math.sin(angle), ); final lineEnd = Offset( center.dx + (radius - 22) * math.cos(angle), center.dy + (radius - 22) * math.sin(angle), ); canvas.drawLine(lineStart, lineEnd, dividerPaint); } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; }