Auto-sync: 20260321_110000
This commit is contained in:
parent
5b99d5f0bb
commit
c990085df7
4 changed files with 37 additions and 41 deletions
|
|
@ -122,7 +122,7 @@ class QuestsDialog extends StatelessWidget {
|
|||
// 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
|
||||
final Function(String uid, String name)? onChallenge;
|
||||
|
||||
const LeaderboardDialog({super.key, this.onChallenge});
|
||||
|
||||
|
|
@ -165,7 +165,8 @@ class LeaderboardDialog extends StatelessWidget {
|
|||
final filteredDocs = rawDocs.where((doc) {
|
||||
var data = doc.data() as Map<String, dynamic>;
|
||||
String name = (data['name'] ?? '').toString().toUpperCase();
|
||||
return name != 'PAOLO';
|
||||
// Nascondiamo PIPPO dalla classifica
|
||||
return name != 'PIPPO';
|
||||
}).toList();
|
||||
|
||||
if (filteredDocs.isEmpty) {
|
||||
|
|
@ -224,7 +225,6 @@ class LeaderboardDialog extends StatelessWidget {
|
|||
themeType: themeType,
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
// Chiama la funzione passata dalla HomeScreen!
|
||||
if (onChallenge != null) {
|
||||
onChallenge!(doc.id, playerName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import '../../l10n/app_localizations.dart';
|
|||
import '../../widgets/painters.dart';
|
||||
import '../../widgets/cyber_border.dart';
|
||||
import '../game/game_screen.dart';
|
||||
import '../multiplayer/lobby_screen.dart';
|
||||
import '../multiplayer/lobby_widgets.dart';
|
||||
|
||||
class HomeModals {
|
||||
|
|
@ -62,25 +61,16 @@ class HomeModals {
|
|||
final fakeEmail = "${name.toLowerCase().replaceAll(' ', '')}@tetraq.game";
|
||||
final currentUser = FirebaseAuth.instance.currentUser;
|
||||
|
||||
// CATTURIAMO IL FANTASMA: Se siamo in un account anonimo provvisorio, ci salviamo il suo ID
|
||||
final ghostUid = (currentUser != null && currentUser.isAnonymous) ? currentUser.uid : null;
|
||||
|
||||
try {
|
||||
if (isLogin) {
|
||||
// ==========================================
|
||||
// 1. TENTA IL LOGIN UFFICIALE
|
||||
// ==========================================
|
||||
|
||||
// --- LA MOSSA DEL NINJA: ELIMINIAMO IL GHOST PRIMA DEL LOGIN ---
|
||||
// Lo eliminiamo ORA perché abbiamo ancora i permessi dell'utente anonimo.
|
||||
if (ghostUid != null) {
|
||||
await FirebaseFirestore.instance.collection('leaderboard').doc(ghostUid).delete().catchError((e) => null);
|
||||
}
|
||||
|
||||
// Ora effettuiamo l'accesso
|
||||
await FirebaseAuth.instance.signInWithEmailAndPassword(email: fakeEmail, password: password);
|
||||
|
||||
// Recupera i dati storici dal Cloud per sovrascrivere quelli in locale
|
||||
final doc = await FirebaseFirestore.instance.collection('leaderboard').doc(FirebaseAuth.instance.currentUser!.uid).get();
|
||||
if (doc.exists) {
|
||||
final data = doc.data() as Map<String, dynamic>;
|
||||
|
|
@ -95,22 +85,16 @@ class HomeModals {
|
|||
}
|
||||
|
||||
} else {
|
||||
// ==========================================
|
||||
// 2. TENTA LA REGISTRAZIONE / UPGRADE
|
||||
// ==========================================
|
||||
if (currentUser != null && currentUser.isAnonymous) {
|
||||
// L'utente aveva un account anonimo, lo promuoviamo ad account con password
|
||||
final credential = EmailAuthProvider.credential(email: fakeEmail, password: password);
|
||||
await currentUser.linkWithCredential(credential);
|
||||
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Profilo Cloud protetto con successo!"), backgroundColor: Colors.green));
|
||||
} else {
|
||||
// Se per caso si trova senza nessun account, ne creiamo uno nuovo
|
||||
await FirebaseAuth.instance.createUserWithEmailAndPassword(email: fakeEmail, password: password);
|
||||
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Account creato con successo!"), backgroundColor: Colors.green));
|
||||
}
|
||||
}
|
||||
|
||||
// Salva il nome e lancia il sync
|
||||
await StorageService.instance.savePlayerName(name);
|
||||
StorageService.instance.syncLeaderboard();
|
||||
|
||||
|
|
@ -123,7 +107,6 @@ class HomeModals {
|
|||
msg = "Nome già registrato!\nSe sei tu, clicca su ACCEDI.";
|
||||
} else if (e.code == 'user-not-found' || e.code == 'wrong-password' || e.code == 'invalid-credential') {
|
||||
msg = "Nome o Password errati!";
|
||||
// Siccome avevamo cancellato il ghost prima, se il login fallisce lo ricreiamo per non perdere i dati locali
|
||||
if (isLogin && ghostUid != null) StorageService.instance.syncLeaderboard();
|
||||
} else if (e.code == 'requires-recent-login') {
|
||||
msg = "Errore di sessione. Riavvia l'app.";
|
||||
|
|
@ -534,7 +517,6 @@ class HomeModals {
|
|||
),
|
||||
const SizedBox(height: 25), Divider(color: inkColor.withOpacity(0.3), thickness: 2.5), const SizedBox(height: 20),
|
||||
|
||||
// TEMPO È ORA ESCLUSIVO PER IL MULTIPLAYER
|
||||
Text("TEMPO", style: getSharedTextStyle(themeType, TextStyle(fontSize: 14, fontWeight: FontWeight.w900, color: inkColor.withOpacity(0.6), letterSpacing: 1.5))), const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
|||
_checkClipboardForInvite();
|
||||
_listenToFavoritesOnline();
|
||||
} else if (state == AppLifecycleState.detached) {
|
||||
// --- FIX BUG WHATSAPP: Rimossa l'eliminazione della stanza durante lo stato "paused" ---
|
||||
_cleanupGhostRoom();
|
||||
}
|
||||
}
|
||||
|
|
@ -581,8 +580,8 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
|||
onTap: () async {
|
||||
_debugTapCount++;
|
||||
|
||||
// CHEAT LOCALE VIVO SOLO IN DEBUG MODE
|
||||
if (kDebugMode && playerName.toUpperCase() == 'PAOLO' && _debugTapCount == 5) {
|
||||
// CHEAT LOCALE VIVO SOLO IN DEBUG MODE (ORA CON PIPPO!)
|
||||
if (kDebugMode && playerName.toUpperCase() == 'PIPPO' && _debugTapCount == 5) {
|
||||
StorageService.instance.addXP(2000);
|
||||
setState(() {});
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
@ -593,7 +592,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
|||
else if (_debugTapCount >= 7) {
|
||||
_debugTapCount = 0;
|
||||
|
||||
if (kDebugMode && playerName.toUpperCase() == 'PAOLO') {
|
||||
if (kDebugMode && playerName.toUpperCase() == 'PIPPO') {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen()));
|
||||
} else {
|
||||
bool isAdmin = await StorageService.instance.isUserAdmin();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:tetraq/l10n/app_localizations.dart'; // <-- IMPORT DEL DIZIONARIO!
|
||||
import 'package:tetraq/l10n/app_localizations.dart';
|
||||
|
||||
import '../../logic/game_controller.dart';
|
||||
import '../../models/game_board.dart';
|
||||
|
|
@ -16,8 +16,8 @@ import '../../core/app_colors.dart';
|
|||
import '../../services/multiplayer_service.dart';
|
||||
import '../../services/storage_service.dart';
|
||||
import '../game/game_screen.dart';
|
||||
import '../../widgets/painters.dart';
|
||||
import '../../widgets/cyber_border.dart';
|
||||
import '../../widgets/painters.dart'; // <--- ECCO L'IMPORT MANCANTE!
|
||||
import 'lobby_widgets.dart';
|
||||
|
||||
class LobbyScreen extends StatefulWidget {
|
||||
|
|
@ -45,7 +45,6 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
String _timeModeSetting = 'fixed';
|
||||
|
||||
bool _isPublicRoom = true;
|
||||
|
||||
bool _roomStarted = false;
|
||||
|
||||
@override
|
||||
|
|
@ -220,17 +219,17 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) {
|
||||
final theme = context.watch<ThemeManager>().currentColors;
|
||||
final themeType = context.read<ThemeManager>().currentThemeType;
|
||||
builder: (dialogContext) {
|
||||
final theme = dialogContext.watch<ThemeManager>().currentColors;
|
||||
final themeType = dialogContext.read<ThemeManager>().currentThemeType;
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
|
||||
Widget dialogContent = Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircularProgressIndicator(color: theme.playerRed), const SizedBox(height: 25),
|
||||
Text(loc.codeHint, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: theme.text.withOpacity(0.6), letterSpacing: 2))),
|
||||
Text(code, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 40, fontWeight: FontWeight.w900, color: theme.playerRed, letterSpacing: 8, shadows: themeType == AppThemeType.doodle ? [] : [Shadow(color: theme.playerRed.withOpacity(0.5), blurRadius: 10)]))),
|
||||
Text(loc.codeHint, style: getSharedTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: theme.text.withOpacity(0.6), letterSpacing: 2))),
|
||||
Text(code, style: getSharedTextStyle(themeType, TextStyle(fontSize: 40, fontWeight: FontWeight.w900, color: theme.playerRed, letterSpacing: 8, shadows: themeType == AppThemeType.doodle ? [] : [Shadow(color: theme.playerRed.withOpacity(0.5), blurRadius: 10)]))),
|
||||
const SizedBox(height: 25),
|
||||
Transform.rotate(
|
||||
angle: themeType == AppThemeType.doodle ? 0.02 : 0,
|
||||
|
|
@ -247,9 +246,9 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
child: Column(
|
||||
children: [
|
||||
Icon(_isPublicRoom ? Icons.podcasts : Icons.share, color: theme.playerBlue, size: 32), const SizedBox(height: 12),
|
||||
Text(_isPublicRoom ? "Sei in Bacheca!" : "Condividi link", textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(color: theme.text, fontWeight: FontWeight.w900, fontSize: 18))),
|
||||
Text(_isPublicRoom ? "Sei in Bacheca!" : "Invito inviato", textAlign: TextAlign.center, style: getSharedTextStyle(themeType, TextStyle(color: theme.text, fontWeight: FontWeight.w900, fontSize: 18))),
|
||||
const SizedBox(height: 8),
|
||||
Text(_isPublicRoom ? "Aspettiamo che uno sfidante si unisca dalla lobby pubblica." : "Condividi il codice. La partita inizierà appena si unirà.", textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.8), fontSize: 14, height: 1.5))),
|
||||
Text(_isPublicRoom ? "Aspettiamo che uno sfidante si unisca dalla lobby pubblica." : "Attendi che il tuo amico accetti la sfida. Non chiudere questa finestra.", textAlign: TextAlign.center, style: getSharedTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.8), fontSize: 14, height: 1.5))),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -274,13 +273,13 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
|
||||
return StreamBuilder<DocumentSnapshot>(
|
||||
stream: _multiplayerService.listenToRoom(code),
|
||||
builder: (context, snapshot) {
|
||||
builder: (ctx, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data!.exists) {
|
||||
var data = snapshot.data!.data() as Map<String, dynamic>;
|
||||
if (data['status'] == 'playing') {
|
||||
_roomStarted = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(ctx);
|
||||
context.read<GameController>().startNewGame(_selectedRadius, isOnline: true, roomCode: code, isHost: true, shape: _selectedShape, timeMode: _timeModeSetting);
|
||||
Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => const GameScreen()));
|
||||
});
|
||||
|
|
@ -292,7 +291,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
onPopInvoked: (didPop) {
|
||||
if (didPop) return;
|
||||
_cleanupGhostRoom();
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(ctx);
|
||||
},
|
||||
child: Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
|
|
@ -305,9 +304,9 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
TextButton(
|
||||
onPressed: () {
|
||||
_cleanupGhostRoom();
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(ctx);
|
||||
},
|
||||
child: Text(loc.btnCancel.toUpperCase(), style: getLobbyTextStyle(themeType, TextStyle(color: Colors.red, fontWeight: FontWeight.w900, fontSize: 20, letterSpacing: 2.0, shadows: themeType == AppThemeType.doodle ? [] : [const Shadow(color: Colors.black, blurRadius: 2)]))),
|
||||
child: Text(loc.btnCancel.toUpperCase(), style: getSharedTextStyle(themeType, TextStyle(color: Colors.red, fontWeight: FontWeight.w900, fontSize: 20, letterSpacing: 2.0, shadows: themeType == AppThemeType.doodle ? [] : [const Shadow(color: Colors.black, blurRadius: 2)]))),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -350,7 +349,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
final themeManager = context.watch<ThemeManager>();
|
||||
final themeType = themeManager.currentThemeType;
|
||||
final theme = themeManager.currentColors;
|
||||
final loc = AppLocalizations.of(context)!; // <-- CHIAMATA AL DIZIONARIO
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
|
||||
String? bgImage;
|
||||
if (themeType == AppThemeType.doodle) bgImage = 'assets/images/doodle_bg.jpg';
|
||||
|
|
@ -732,3 +731,19 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FullScreenGridPainter extends CustomPainter {
|
||||
final Color gridColor;
|
||||
FullScreenGridPainter(this.gridColor);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final Paint paperGridPaint = Paint()..color = gridColor..strokeWidth = 1.0..style = PaintingStyle.stroke;
|
||||
double paperStep = 20.0;
|
||||
for (double i = 0; i <= size.width; i += paperStep) canvas.drawLine(Offset(i, 0), Offset(i, size.height), paperGridPaint);
|
||||
for (double i = 0; i <= size.height; i += paperStep) canvas.drawLine(Offset(0, i), Offset(size.width, i), paperGridPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||
}
|
||||
Loading…
Reference in a new issue