tetraq/lib/widgets/game_over_dialog.dart

321 lines
14 KiB
Dart
Raw Normal View History

2026-03-11 22:00:01 +01:00
// ===========================================================================
// FILE: lib/widgets/game_over_dialog.dart
// ===========================================================================
2026-02-27 23:35:54 +01:00
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../logic/game_controller.dart';
import '../core/theme_manager.dart';
import '../core/app_colors.dart';
2026-03-11 22:00:01 +01:00
import '../services/storage_service.dart';
2026-03-23 01:00:01 +01:00
import 'painters.dart';
2026-02-27 23:35:54 +01:00
class GameOverDialog extends StatelessWidget {
const GameOverDialog({super.key});
@override
Widget build(BuildContext context) {
final game = context.read<GameController>();
final themeManager = context.read<ThemeManager>();
final theme = themeManager.currentColors;
final themeType = themeManager.currentThemeType;
2026-03-23 01:00:01 +01:00
Color inkColor = const Color(0xFF111122);
2026-02-27 23:35:54 +01:00
int red = game.board.scoreRed;
int blue = game.board.scoreBlue;
bool playerBeatCPU = game.isVsCPU && red > blue;
2026-03-11 22:00:01 +01:00
String myName = StorageService.instance.playerName.toUpperCase();
if (myName.isEmpty) myName = "TU";
2026-02-27 23:35:54 +01:00
// --- LOGICA NOMI ---
2026-03-11 22:00:01 +01:00
String nameRed = myName;
String nameBlue = themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? "VERDE" : "BLU";
2026-02-27 23:35:54 +01:00
if (game.isOnline) {
nameRed = game.onlineHostName.toUpperCase();
nameBlue = game.onlineGuestName.toUpperCase();
} else if (game.isVsCPU) {
2026-03-11 22:00:01 +01:00
nameRed = myName;
2026-02-27 23:35:54 +01:00
nameBlue = "CPU";
}
// --- DETERMINA IL VINCITORE ---
String winnerText = "";
Color winnerColor = theme.text;
if (red > blue) {
winnerText = "VINCE $nameRed!";
winnerColor = theme.playerRed;
} else if (blue > red) {
winnerText = "VINCE $nameBlue!";
winnerColor = theme.playerBlue;
} else {
winnerText = "PAREGGIO!";
2026-03-23 01:00:01 +01:00
winnerColor = themeType == AppThemeType.doodle ? inkColor : theme.text;
2026-02-27 23:35:54 +01:00
}
2026-03-23 01:00:01 +01:00
Widget dialogContent = Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(winnerText, textAlign: TextAlign.center, style: getSharedTextStyle(themeType, TextStyle(fontSize: 26, fontWeight: FontWeight.w900, color: winnerColor))),
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(
color: themeType == AppThemeType.doodle ? Colors.transparent : theme.text.withOpacity(0.05),
borderRadius: BorderRadius.circular(15),
border: themeType == AppThemeType.doodle ? Border.all(color: inkColor.withOpacity(0.3), width: 1.5) : null,
),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text("$nameRed: $red", style: getSharedTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: theme.playerRed))),
Text(" - ", style: getSharedTextStyle(themeType, TextStyle(fontSize: 18, color: themeType == AppThemeType.doodle ? inkColor : theme.text))),
Text("$nameBlue: $blue", style: getSharedTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: theme.playerBlue))),
],
),
),
),
if (game.lastMatchXP > 0) ...[
const SizedBox(height: 15),
Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
color: Colors.green.withOpacity(0.15),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: themeType == AppThemeType.doodle ? Colors.green.shade700 : Colors.greenAccent, width: 1.5),
boxShadow: (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) ? [const BoxShadow(color: Colors.greenAccent, blurRadius: 10, spreadRadius: -5)] : [],
),
child: Text("+ ${game.lastMatchXP} XP", style: getSharedTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? Colors.green.shade700 : Colors.greenAccent, fontWeight: FontWeight.w900, fontSize: 16, letterSpacing: 1.5))),
),
],
if (game.isVsCPU) ...[
const SizedBox(height: 15),
Text("Difficoltà CPU: Livello ${game.cpuLevel}", style: getSharedTextStyle(themeType, TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: themeType == AppThemeType.doodle ? inkColor.withOpacity(0.7) : theme.text.withOpacity(0.7)))),
],
if (game.isOnline) ...[
const SizedBox(height: 20),
if (game.rematchRequested && !game.opponentWantsRematch)
Text("In attesa di $nameBlue...", style: getSharedTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? Colors.orange.shade700 : Colors.amber, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic))),
if (game.opponentWantsRematch && !game.rematchRequested)
Text("$nameBlue vuole la rivincita!", style: getSharedTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? Colors.green.shade700 : Colors.greenAccent, fontWeight: FontWeight.bold))),
if (game.rematchRequested && game.opponentWantsRematch)
Text("Avvio nuova partita...", style: getSharedTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? Colors.green.shade800 : Colors.green, fontWeight: FontWeight.bold))),
],
// --- SEZIONE LEVEL UP E ROADMAP DINAMICA ---
if (game.hasLeveledUp && game.unlockedRewards.isNotEmpty) ...[
const SizedBox(height: 30),
Divider(color: themeType == AppThemeType.doodle ? inkColor.withOpacity(0.3) : theme.text.withOpacity(0.2)),
const SizedBox(height: 15),
Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 20),
decoration: BoxDecoration(
color: themeType == AppThemeType.doodle ? Colors.amber.withOpacity(0.1) : Colors.amber.withOpacity(0.2),
borderRadius: BorderRadius.circular(30),
border: Border.all(color: themeType == AppThemeType.doodle ? Colors.amber.shade700 : Colors.amber, width: 2)
),
child: Text("🎉 LIVELLO ${game.newlyReachedLevel}! 🎉", style: getSharedTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? Colors.amber.shade700 : Colors.amber, fontWeight: FontWeight.w900, fontSize: 18))),
),
const SizedBox(height: 15),
...game.unlockedRewards.map((reward) {
Color rewardColor = themeType == AppThemeType.doodle ? (reward['color'] as Color).withOpacity(0.8) : reward['color'];
return Container(
margin: const EdgeInsets.only(bottom: 10),
padding: const EdgeInsets.all(12),
2026-03-20 14:00:00 +01:00
decoration: BoxDecoration(
2026-03-23 01:00:01 +01:00
color: rewardColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: rewardColor.withOpacity(0.5), width: 1.5),
2026-03-20 14:00:00 +01:00
),
child: Row(
2026-03-23 01:00:01 +01:00
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: rewardColor.withOpacity(0.2),
shape: BoxShape.circle,
),
child: Icon(reward['icon'], color: rewardColor, size: 28),
),
const SizedBox(width: 15),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(reward['title'], style: getSharedTextStyle(themeType, TextStyle(color: rewardColor, fontWeight: FontWeight.w900, fontSize: 16))),
const SizedBox(height: 4),
Text(reward['desc'], style: getSharedTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? inkColor.withOpacity(0.9) : theme.text.withOpacity(0.9), fontSize: 12, height: 1.3))),
],
)
)
]
2026-03-20 14:00:00 +01:00
),
2026-03-23 01:00:01 +01:00
);
}),
],
2026-02-27 23:35:54 +01:00
2026-03-23 01:00:01 +01:00
const SizedBox(height: 30),
// --- BOTTONI AZIONE ---
2026-02-27 23:35:54 +01:00
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (playerBeatCPU)
2026-03-23 01:00:01 +01:00
_buildPrimaryButton(
"PROSSIMO LIVELLO ➔",
winnerColor,
themeType,
inkColor,
() {
2026-02-27 23:35:54 +01:00
Navigator.pop(context);
game.increaseLevelAndRestart();
},
)
else if (game.isOnline)
2026-03-23 01:00:01 +01:00
_buildPrimaryButton(
game.opponentWantsRematch ? "ACCETTA RIVINCITA" : "CHIEDI RIVINCITA",
game.rematchRequested ? Colors.grey : (winnerColor == (themeType == AppThemeType.doodle ? inkColor : theme.text) ? theme.playerBlue : winnerColor),
themeType,
inkColor,
game.rematchRequested ? () {} : () => game.requestRematch(),
2026-02-27 23:35:54 +01:00
)
else
2026-03-23 01:00:01 +01:00
_buildPrimaryButton(
"RIGIOCA",
winnerColor == (themeType == AppThemeType.doodle ? inkColor : theme.text) ? theme.playerBlue : winnerColor,
themeType,
inkColor,
() {
2026-02-27 23:35:54 +01:00
Navigator.pop(context);
game.startNewGame(game.board.radius, vsCPU: game.isVsCPU);
},
),
const SizedBox(height: 12),
2026-03-23 01:00:01 +01:00
_buildSecondaryButton(
"TORNA AL MENU",
themeType,
inkColor,
theme,
() {
2026-02-27 23:35:54 +01:00
if (game.isOnline) {
game.disconnectOnlineGame();
}
Navigator.pop(context);
Navigator.pop(context);
},
),
],
)
],
);
2026-03-23 01:00:01 +01:00
if (themeType == AppThemeType.doodle) {
dialogContent = Transform.rotate(
angle: 0.015,
child: CustomPaint(
painter: DoodleBackgroundPainter(fillColor: Colors.white.withOpacity(0.95), strokeColor: inkColor, seed: 500),
child: Padding(
padding: const EdgeInsets.all(25.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("FINE PARTITA", textAlign: TextAlign.center, style: getSharedTextStyle(themeType, TextStyle(fontSize: 22, fontWeight: FontWeight.w900, color: inkColor, letterSpacing: 2))),
const SizedBox(height: 20),
dialogContent,
],
),
),
),
);
} else {
dialogContent = Container(
padding: const EdgeInsets.all(25.0),
decoration: BoxDecoration(
color: theme.background,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: winnerColor.withOpacity(0.5), width: 2),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("FINE PARTITA", textAlign: TextAlign.center, style: getSharedTextStyle(themeType, TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: theme.text))),
const SizedBox(height: 20),
dialogContent,
],
),
);
}
return Dialog(
backgroundColor: Colors.transparent,
insetPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
child: dialogContent,
);
}
Widget _buildPrimaryButton(String label, Color color, AppThemeType themeType, Color inkColor, VoidCallback onTap) {
if (themeType == AppThemeType.doodle) {
return GestureDetector(
onTap: onTap,
child: CustomPaint(
painter: DoodleBackgroundPainter(fillColor: color, strokeColor: inkColor, seed: label.length * 7),
child: Container(
height: 55,
alignment: Alignment.center,
child: Text(label, style: getSharedTextStyle(themeType, const TextStyle(fontSize: 16, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 1.5))),
),
),
);
}
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: color,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
elevation: 5,
),
onPressed: onTap,
child: Text(label, style: getSharedTextStyle(themeType, const TextStyle(fontWeight: FontWeight.bold, fontSize: 16, letterSpacing: 1.5))),
);
}
Widget _buildSecondaryButton(String label, AppThemeType themeType, Color inkColor, ThemeColors theme, VoidCallback onTap) {
if (themeType == AppThemeType.doodle) {
return GestureDetector(
onTap: onTap,
child: CustomPaint(
painter: DoodleBackgroundPainter(fillColor: Colors.transparent, strokeColor: inkColor.withOpacity(0.5), seed: label.length * 3),
child: Container(
height: 55,
alignment: Alignment.center,
child: Text(label, style: getSharedTextStyle(themeType, TextStyle(fontSize: 14, fontWeight: FontWeight.w900, color: inkColor, letterSpacing: 1.5))),
),
),
);
}
return OutlinedButton(
style: OutlinedButton.styleFrom(
foregroundColor: theme.text,
side: BorderSide(color: theme.text.withOpacity(0.3), width: 2),
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
),
onPressed: onTap,
child: Text(label, style: getSharedTextStyle(themeType, TextStyle(fontWeight: FontWeight.bold, color: theme.text, fontSize: 14, letterSpacing: 1.5))),
);
2026-02-27 23:35:54 +01:00
}
}