321 lines
No EOL
14 KiB
Dart
321 lines
No EOL
14 KiB
Dart
// ===========================================================================
|
|
// FILE: lib/widgets/game_over_dialog.dart
|
|
// ===========================================================================
|
|
|
|
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';
|
|
import '../services/storage_service.dart';
|
|
import 'painters.dart';
|
|
|
|
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;
|
|
Color inkColor = const Color(0xFF111122);
|
|
|
|
int red = game.board.scoreRed;
|
|
int blue = game.board.scoreBlue;
|
|
|
|
bool playerBeatCPU = game.isVsCPU && red > blue;
|
|
|
|
String myName = StorageService.instance.playerName.toUpperCase();
|
|
if (myName.isEmpty) myName = "TU";
|
|
|
|
// --- LOGICA NOMI ---
|
|
String nameRed = myName;
|
|
String nameBlue = themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? "VERDE" : "BLU";
|
|
|
|
if (game.isOnline) {
|
|
nameRed = game.onlineHostName.toUpperCase();
|
|
nameBlue = game.onlineGuestName.toUpperCase();
|
|
} else if (game.isVsCPU) {
|
|
nameRed = myName;
|
|
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!";
|
|
winnerColor = themeType == AppThemeType.doodle ? inkColor : theme.text;
|
|
}
|
|
|
|
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),
|
|
decoration: BoxDecoration(
|
|
color: rewardColor.withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: rewardColor.withOpacity(0.5), width: 1.5),
|
|
),
|
|
child: Row(
|
|
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))),
|
|
],
|
|
)
|
|
)
|
|
]
|
|
),
|
|
);
|
|
}),
|
|
],
|
|
|
|
const SizedBox(height: 30),
|
|
|
|
// --- BOTTONI AZIONE ---
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
if (playerBeatCPU)
|
|
_buildPrimaryButton(
|
|
"PROSSIMO LIVELLO ➔",
|
|
winnerColor,
|
|
themeType,
|
|
inkColor,
|
|
() {
|
|
Navigator.pop(context);
|
|
game.increaseLevelAndRestart();
|
|
},
|
|
)
|
|
else if (game.isOnline)
|
|
_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(),
|
|
)
|
|
else
|
|
_buildPrimaryButton(
|
|
"RIGIOCA",
|
|
winnerColor == (themeType == AppThemeType.doodle ? inkColor : theme.text) ? theme.playerBlue : winnerColor,
|
|
themeType,
|
|
inkColor,
|
|
() {
|
|
Navigator.pop(context);
|
|
game.startNewGame(game.board.radius, vsCPU: game.isVsCPU);
|
|
},
|
|
),
|
|
|
|
const SizedBox(height: 12),
|
|
|
|
_buildSecondaryButton(
|
|
"TORNA AL MENU",
|
|
themeType,
|
|
inkColor,
|
|
theme,
|
|
() {
|
|
if (game.isOnline) {
|
|
game.disconnectOnlineGame();
|
|
}
|
|
Navigator.pop(context);
|
|
Navigator.pop(context);
|
|
},
|
|
),
|
|
],
|
|
)
|
|
],
|
|
);
|
|
|
|
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))),
|
|
);
|
|
}
|
|
} |