541 lines
No EOL
28 KiB
Dart
541 lines
No EOL
28 KiB
Dart
// ===========================================================================
|
|
// FILE: lib/ui/home/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';
|
|
import '../../services/storage_service.dart';
|
|
|
|
// ===========================================================================
|
|
// 1. DIALOGO MISSIONI (QUESTS)
|
|
// ===========================================================================
|
|
class QuestsDialog extends StatelessWidget {
|
|
const QuestsDialog({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final themeManager = context.watch<ThemeManager>();
|
|
final theme = themeManager.currentColors;
|
|
final themeType = themeManager.currentThemeType;
|
|
final loc = AppLocalizations.of(context)!;
|
|
|
|
return FutureBuilder<SharedPreferences>(
|
|
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) CON CALLBACK SFIDA
|
|
// ===========================================================================
|
|
class LeaderboardDialog extends StatelessWidget {
|
|
final Function(String uid, String name)? onChallenge; // <-- Aggiunto Callback per inviare i dati alla HomeScreen
|
|
|
|
const LeaderboardDialog({super.key, this.onChallenge});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final themeManager = context.watch<ThemeManager>();
|
|
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<QuerySnapshot>(
|
|
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 rawDocs = snapshot.data!.docs;
|
|
final filteredDocs = rawDocs.where((doc) {
|
|
var data = doc.data() as Map<String, dynamic>;
|
|
String name = (data['name'] ?? '').toString().toUpperCase();
|
|
return name != 'PAOLO';
|
|
}).toList();
|
|
|
|
if (filteredDocs.isEmpty) {
|
|
return Center(child: Text("Ancora nessun campione...", style: TextStyle(color: theme.text.withOpacity(0.5))));
|
|
}
|
|
|
|
return ListView.builder(
|
|
physics: const BouncingScrollPhysics(),
|
|
itemCount: filteredDocs.length,
|
|
itemBuilder: (context, index) {
|
|
var doc = filteredDocs[index];
|
|
var data = doc.data() as Map<String, dynamic>;
|
|
String? myUid = FirebaseAuth.instance.currentUser?.uid;
|
|
bool isMe = doc.id == myUid;
|
|
String playerName = data['name'] ?? 'Unknown';
|
|
|
|
bool isOnline = false;
|
|
if (data['lastActive'] != null) {
|
|
Timestamp lastActive = data['lastActive'];
|
|
int diffInSeconds = DateTime.now().difference(lastActive.toDate()).inSeconds;
|
|
if (diffInSeconds.abs() < 180) isOnline = true;
|
|
}
|
|
|
|
return StatefulBuilder(
|
|
builder: (context, setStateItem) {
|
|
bool isFav = StorageService.instance.isFavorite(doc.id);
|
|
|
|
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: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Flexible(
|
|
child: Text(
|
|
playerName,
|
|
style: getSharedTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: isMe ? FontWeight.w900 : FontWeight.bold, color: theme.text)),
|
|
overflow: TextOverflow.ellipsis,
|
|
)
|
|
),
|
|
|
|
if (isFav && !isMe && isOnline) ...[
|
|
const SizedBox(width: 8),
|
|
PulsingChallengeButton(
|
|
themeType: themeType,
|
|
onTap: () {
|
|
Navigator.pop(context);
|
|
// Chiama la funzione passata dalla HomeScreen!
|
|
if (onChallenge != null) {
|
|
onChallenge!(doc.id, playerName);
|
|
}
|
|
},
|
|
),
|
|
]
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(width: 10),
|
|
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)),
|
|
],
|
|
),
|
|
|
|
if (!isMe) ...[
|
|
const SizedBox(width: 8),
|
|
GestureDetector(
|
|
onTap: () async {
|
|
await StorageService.instance.toggleFavorite(doc.id, playerName);
|
|
setStateItem(() {});
|
|
},
|
|
child: Icon(isFav ? Icons.star : Icons.star_border, color: Colors.amber, size: 24),
|
|
)
|
|
]
|
|
],
|
|
),
|
|
);
|
|
}
|
|
);
|
|
}
|
|
);
|
|
}
|
|
),
|
|
),
|
|
|
|
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<ThemeManager>();
|
|
final theme = themeManager.currentColors;
|
|
final themeType = themeManager.currentThemeType;
|
|
Color inkColor = const Color(0xFF111122);
|
|
|
|
String goldLabel = "ORO:";
|
|
String bombLabel = "BOMBA:";
|
|
String swapLabel = "SCAMBIO:";
|
|
String jokerLabel = "JOLLY:";
|
|
String iceLabel = "GHIACCIO:";
|
|
String multiplierLabel = "x2:";
|
|
String blockLabel = "BUCO NERO:";
|
|
|
|
if (themeType == AppThemeType.grimorio) {
|
|
goldLabel = "CORONA:";
|
|
bombLabel = "STREGA:";
|
|
jokerLabel = "GIULLARE:";
|
|
swapLabel = "TORNADO:";
|
|
multiplierLabel = "FULMINE:";
|
|
blockLabel = "METEORITE:";
|
|
} else if (themeType == AppThemeType.music) {
|
|
goldLabel = "DISCO D'ORO:";
|
|
bombLabel = "MUTO:";
|
|
jokerLabel = "DJ:";
|
|
swapLabel = "MIXER:";
|
|
iceLabel = "NOTA:";
|
|
multiplierLabel = "AVANTI VELOCE:";
|
|
blockLabel = "PAUSA:";
|
|
} else if (themeType == AppThemeType.arcade) {
|
|
goldLabel = "GETTONE:";
|
|
bombLabel = "FANTASMA:";
|
|
jokerLabel = "GAMEPAD:";
|
|
swapLabel = "SHUFFLE:";
|
|
blockLabel = "POWER OFF:";
|
|
} else if (themeType == AppThemeType.cyberpunk) {
|
|
goldLabel = "CHIP:";
|
|
bombLabel = "VIRUS:";
|
|
jokerLabel = "BOT:";
|
|
swapLabel = "NETWORK:";
|
|
blockLabel = "FIREWALL:";
|
|
} else if (themeType == AppThemeType.doodle) {
|
|
bombLabel = "VIRUS:";
|
|
}
|
|
|
|
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: "$swapLabel 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: "$iceLabel 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: "$multiplierLabel 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: "$blockLabel 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: "$swapLabel 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: "$iceLabel 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: "$multiplierLabel 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: "$blockLabel 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))),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
// ===========================================================================
|
|
// 4. WIDGET ANIMATO PER TASTO SFIDA
|
|
// ===========================================================================
|
|
class PulsingChallengeButton extends StatefulWidget {
|
|
final VoidCallback onTap;
|
|
final AppThemeType themeType;
|
|
|
|
const PulsingChallengeButton({super.key, required this.onTap, required this.themeType});
|
|
|
|
@override
|
|
State<PulsingChallengeButton> createState() => _PulsingChallengeButtonState();
|
|
}
|
|
|
|
class _PulsingChallengeButtonState extends State<PulsingChallengeButton> with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
late Animation<double> _animation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 900))..repeat(reverse: true);
|
|
_animation = Tween<double>(begin: 0.3, end: 1.0).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final Color softGreen = Colors.green.shade400;
|
|
|
|
return GestureDetector(
|
|
onTap: widget.onTap,
|
|
child: FadeTransition(
|
|
opacity: _animation,
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
decoration: BoxDecoration(
|
|
color: softGreen.withOpacity(0.15),
|
|
border: Border.all(color: softGreen, width: 1.5),
|
|
borderRadius: BorderRadius.circular(6),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(Icons.circle, color: softGreen, size: 8),
|
|
const SizedBox(width: 4),
|
|
Text(
|
|
"SFIDA",
|
|
style: getSharedTextStyle(widget.themeType, TextStyle(color: softGreen, fontSize: 10, fontWeight: FontWeight.bold))
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
} |