// =========================================================================== // FILE: lib/ui/home/dialogs/dialog.dart // =========================================================================== import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import '../../../core/theme_manager.dart'; import '../../../core/app_colors.dart'; import '../../../l10n/app_localizations.dart'; import '../../../widgets/painters.dart'; import '../../../widgets/cyber_border.dart'; // =========================================================================== // 1. DIALOGO MISSIONI (QUESTS) // =========================================================================== class QuestsDialog extends StatelessWidget { const QuestsDialog({super.key}); @override Widget build(BuildContext context) { final themeManager = context.watch(); final theme = themeManager.currentColors; final themeType = themeManager.currentThemeType; final loc = AppLocalizations.of(context)!; return FutureBuilder( future: SharedPreferences.getInstance(), builder: (context, snapshot) { if (!snapshot.hasData) return const SizedBox(); final prefs = snapshot.data!; return Dialog( backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.all(20), child: Container( padding: const EdgeInsets.all(25.0), decoration: BoxDecoration( gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [theme.background.withOpacity(0.95), theme.background.withOpacity(0.8)]), borderRadius: BorderRadius.circular(25), border: Border.all(color: theme.playerBlue.withOpacity(0.5), width: 2), boxShadow: [BoxShadow(color: theme.playerBlue.withOpacity(0.2), blurRadius: 20, spreadRadius: 5)] ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.assignment_turned_in, size: 50, color: theme.playerBlue), const SizedBox(height: 10), Text(loc.questsTitle, style: getSharedTextStyle(themeType, TextStyle(fontSize: 22, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 1.5))), const SizedBox(height: 25), ...List.generate(3, (index) { int i = index + 1; int type = prefs.getInt('q${i}_type') ?? 0; int prog = prefs.getInt('q${i}_prog') ?? 0; int target = prefs.getInt('q${i}_target') ?? 1; String title = ""; IconData icon = Icons.star; if (type == 0) { title = "Vinci partite Online"; icon = Icons.public; } else if (type == 1) { title = "Vinci contro la CPU"; icon = Icons.smart_toy; } else { title = "Gioca in Arene Speciali"; icon = Icons.extension; } bool completed = prog >= target; double percent = (prog / target).clamp(0.0, 1.0); return Container( margin: const EdgeInsets.only(bottom: 15), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: completed ? Colors.green.withOpacity(0.1) : theme.text.withOpacity(0.05), borderRadius: BorderRadius.circular(15), border: Border.all(color: completed ? Colors.green : theme.gridLine.withOpacity(0.3)), ), child: Row( children: [ Icon(icon, color: completed ? Colors.green : theme.text.withOpacity(0.6), size: 30), const SizedBox(width: 15), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: getSharedTextStyle(themeType, TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: completed ? Colors.green : theme.text))), const SizedBox(height: 6), ClipRRect( borderRadius: BorderRadius.circular(10), child: LinearProgressIndicator(value: percent, backgroundColor: theme.gridLine.withOpacity(0.2), color: completed ? Colors.green : theme.playerBlue, minHeight: 8), ) ], ), ), const SizedBox(width: 10), Text("$prog / $target", style: getSharedTextStyle(themeType, TextStyle(fontWeight: FontWeight.bold, color: theme.text.withOpacity(0.6)))), ], ), ); }), const SizedBox(height: 15), SizedBox( width: double.infinity, height: 50, child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: theme.playerBlue, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15))), onPressed: () => Navigator.pop(context), child: const Text("CHIUDI", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w900, letterSpacing: 2)), ), ) ], ), ), ); } ); } } // =========================================================================== // 2. DIALOGO CLASSIFICA (LEADERBOARD) // =========================================================================== class LeaderboardDialog extends StatelessWidget { const LeaderboardDialog({super.key}); @override Widget build(BuildContext context) { final themeManager = context.watch(); final theme = themeManager.currentColors; final themeType = themeManager.currentThemeType; final loc = AppLocalizations.of(context)!; Widget content = Container( padding: const EdgeInsets.all(20.0), decoration: BoxDecoration( gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [theme.background.withOpacity(0.95), theme.background.withOpacity(0.8)]), borderRadius: BorderRadius.circular(25), border: Border.all(color: Colors.amber.withOpacity(0.8), width: 2), boxShadow: [BoxShadow(color: Colors.amber.withOpacity(0.2), blurRadius: 20, spreadRadius: 5)] ), child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.emoji_events, size: 50, color: Colors.amber), const SizedBox(height: 10), Text(loc.leaderboardTitle, style: getSharedTextStyle(themeType, TextStyle(fontSize: 20, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 1.5))), const SizedBox(height: 20), SizedBox( height: 350, child: StreamBuilder( stream: FirebaseFirestore.instance.collection('leaderboard').orderBy('xp', descending: true).limit(50).snapshots(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator(color: theme.playerBlue)); } if (!snapshot.hasData || snapshot.data!.docs.isEmpty) { return Center(child: Text("Ancora nessun campione...", style: TextStyle(color: theme.text.withOpacity(0.5)))); } final docs = snapshot.data!.docs; return ListView.builder( physics: const BouncingScrollPhysics(), itemCount: docs.length, itemBuilder: (context, index) { var data = docs[index].data() as Map; String? myUid = FirebaseAuth.instance.currentUser?.uid; bool isMe = docs[index].id == myUid; return Container( margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( color: isMe ? theme.playerBlue.withOpacity(0.2) : theme.text.withOpacity(0.05), borderRadius: BorderRadius.circular(10), border: isMe ? Border.all(color: theme.playerBlue, width: 1.5) : null ), child: Row( children: [ Text("#${index + 1}", style: getSharedTextStyle(themeType, TextStyle(fontWeight: FontWeight.w900, color: index == 0 ? Colors.amber : (index == 1 ? Colors.grey.shade400 : (index == 2 ? Colors.brown.shade300 : theme.text.withOpacity(0.5)))))), const SizedBox(width: 15), Expanded(child: Text(data['name'] ?? 'Unknown', style: getSharedTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: isMe ? FontWeight.w900 : FontWeight.bold, color: theme.text)))), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text("Lv. ${data['level'] ?? 1}", style: TextStyle(color: theme.playerRed, fontWeight: FontWeight.bold, fontSize: 12)), Text("${data['xp'] ?? 0} XP", style: TextStyle(color: theme.text.withOpacity(0.6), fontSize: 10)), ], ) ], ), ); } ); } ), ), const SizedBox(height: 15), SizedBox( width: double.infinity, height: 50, child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.amber.shade700, foregroundColor: Colors.black, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15))), onPressed: () => Navigator.pop(context), child: const Text("CHIUDI", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w900, letterSpacing: 2)), ), ) ], ), ); if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) { content = AnimatedCyberBorder(child: content); } return Dialog(backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.all(20), child: content); } } // =========================================================================== // 3. DIALOGO TUTORIAL // =========================================================================== class TutorialDialog extends StatelessWidget { const TutorialDialog({super.key}); @override Widget build(BuildContext context) { final themeManager = context.watch(); final theme = themeManager.currentColors; final themeType = themeManager.currentThemeType; Color inkColor = const Color(0xFF111122); String goldLabel = themeType == AppThemeType.grimorio ? "CORONA:" : "ORO:"; String bombLabel = themeType == AppThemeType.grimorio ? "STREGA:" : "BOMBA:"; String jokerLabel = themeType == AppThemeType.grimorio ? "GIULLARE:" : "JOLLY:"; Widget dialogContent = themeType == AppThemeType.doodle ? Transform.rotate( angle: -0.01, child: CustomPaint( painter: DoodleBackgroundPainter(fillColor: Colors.yellow.shade50, strokeColor: inkColor, seed: 400), child: Padding( padding: const EdgeInsets.all(25.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Center(child: Text("COME GIOCARE", style: getSharedTextStyle(themeType, TextStyle(fontSize: 28, fontWeight: FontWeight.w900, color: inkColor, letterSpacing: 2)))), const SizedBox(height: 20), TutorialStep(icon: Icons.line_axis, text: "Chiudi i 4 lati di un quadrato per conquistare 1 punto e avere una mossa extra!", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 15), TutorialStep(icon: Icons.lens_blur, text: "Ma presta attenzione! Ogni quadrato nasconde un'insidia o un regalo!", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 15), const Divider(color: Colors.black26, thickness: 2), const SizedBox(height: 10), Center(child: Text("GLOSSARIO ARENA", style: getSharedTextStyle(themeType, TextStyle(fontSize: 18, fontWeight: FontWeight.w900, color: inkColor)))), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.gold(themeType), iconColor: Colors.amber.shade700, text: "$goldLabel Chiudilo per ottenere +2 Punti.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.bomb(themeType), iconColor: Colors.deepPurple, text: "$bombLabel Non chiuderlo! Perderai -1 Punto.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.swap(themeType), iconColor: Colors.purpleAccent, text: "SCAMBIO: Inverte istantaneamente i punteggi dei giocatori.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.joker(themeType), iconColor: Colors.green.shade600, text: "$jokerLabel Scegli dove nasconderlo a inizio partita. Se lo chiudi tu +2, se lo chiude l'avversario -1!", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.ice(themeType), iconColor: Colors.cyanAccent, text: "GHIACCIO: Devi cliccarlo due volte per poterlo rompere e chiudere.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.multiplier(themeType), iconColor: Colors.yellowAccent, text: "x2: Non dà punti, ma raddoppia il punteggio della prossima casella che chiudi!", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.block(themeType), iconColor: Colors.grey, text: "BUCO NERO: Questa casella non esiste. Se la chiudi perdi il turno.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 25), Center( child: GestureDetector( onTap: () => Navigator.pop(context), child: CustomPaint( painter: DoodleBackgroundPainter(fillColor: Colors.red.shade200, strokeColor: inkColor, seed: 401), child: Container( height: 50, width: 150, alignment: Alignment.center, child: Text("HO CAPITO!", style: getSharedTextStyle(themeType, TextStyle(fontSize: 18, fontWeight: FontWeight.w900, color: inkColor))), ), ), ), ) ], ), ), ), ) : Container( padding: const EdgeInsets.all(25.0), decoration: BoxDecoration( gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [theme.background.withOpacity(0.95), theme.background.withOpacity(0.8)]), borderRadius: BorderRadius.circular(25), border: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? null : Border.all(color: Colors.white.withOpacity(0.15), width: 1.5), boxShadow: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? [] : [BoxShadow(color: Colors.black.withOpacity(0.5), blurRadius: 20, offset: const Offset(4, 10))], ), child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Center(child: Text("COME GIOCARE", style: getSharedTextStyle(themeType, TextStyle(fontSize: 24, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 2)))), const SizedBox(height: 20), TutorialStep(icon: Icons.grid_4x4, text: "Chiudi i 4 lati di un quadrato per conquistare 1 punto e avere una mossa extra!", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 15), TutorialStep(icon: Icons.lens_blur, text: "Ma presta attenzione! Ogni quadrato nasconde un'insidia o un regalo!", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 15), const Divider(color: Colors.white24, thickness: 1.5), const SizedBox(height: 10), Center(child: Text("GLOSSARIO ARENA", style: getSharedTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.w900, color: theme.text.withOpacity(0.7), letterSpacing: 1.5)))), const SizedBox(height: 15), TutorialStep(icon: ThemeIcons.gold(themeType), iconColor: Colors.amber, text: "$goldLabel Chiudilo per ottenere +2 Punti.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.bomb(themeType), iconColor: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? Colors.greenAccent : Colors.deepPurple, text: "$bombLabel Non chiuderlo! Perderai -1 Punto.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.swap(themeType), iconColor: Colors.purpleAccent, text: "SCAMBIO: Inverte istantaneamente i punteggi dei giocatori.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.joker(themeType), iconColor: theme.playerBlue, text: "$jokerLabel Scegli dove nasconderlo a inizio partita. Se lo chiudi tu +2, se lo chiude l'avversario -1!", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.ice(themeType), iconColor: Colors.cyanAccent, text: "GHIACCIO: Devi cliccarlo due volte per poterlo rompere e chiudere.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.multiplier(themeType), iconColor: Colors.yellowAccent, text: "x2: Non dà punti, ma raddoppia il punteggio della prossima casella che chiudi!", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 10), TutorialStep(icon: ThemeIcons.block(themeType), iconColor: Colors.grey, text: "BUCO NERO: Questa casella non esiste. Se la chiudi perdi il turno.", themeType: themeType, inkColor: inkColor, theme: theme), const SizedBox(height: 30), SizedBox( width: double.infinity, height: 50, child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: theme.playerBlue, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15))), onPressed: () => Navigator.pop(context), child: const Text("CHIUDI", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w900, letterSpacing: 2)), ), ) ], ), ), ); if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) { dialogContent = AnimatedCyberBorder(child: dialogContent); } return Dialog(backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), child: dialogContent); } } class TutorialStep extends StatelessWidget { final IconData icon; final Color? iconColor; final String text; final AppThemeType themeType; final Color inkColor; final ThemeColors theme; const TutorialStep({super.key, required this.icon, this.iconColor, required this.text, required this.themeType, required this.inkColor, required this.theme}); @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(icon, color: iconColor ?? (themeType == AppThemeType.doodle ? inkColor : theme.playerBlue), size: 28), const SizedBox(width: 15), Expanded( child: Text(text, style: getSharedTextStyle(themeType, TextStyle(fontSize: 14, color: themeType == AppThemeType.doodle ? inkColor : theme.text.withOpacity(0.8), height: 1.3))), ), ], ); } }