From 88f1520b5b5b8de834480586ce66d3122b8208e5 Mon Sep 17 00:00:00 2001 From: Paolo Date: Tue, 24 Mar 2026 15:00:01 +0100 Subject: [PATCH] Auto-sync: 20260324_150000 --- .DS_Store | Bin 14340 -> 14340 bytes ios/.DS_Store | Bin 8196 -> 8196 bytes lib/ui/game/game_screen.dart | 15 ++++-- lib/ui/multiplayer/lobby_screen.dart | 70 ++++++++++++++++++++------- 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/.DS_Store b/.DS_Store index 887f61bf35d57d4ac1659d2148cdb1d80f6148df..fb20088f18c597f50b1acdde0271394b217b4f61 100644 GIT binary patch delta 14 VcmZoEXerpRL5q=b^G2;;UH~oE1!DjJ delta 14 VcmZoEXerpRL5q=L^G2;;UH~o81!4dI diff --git a/ios/.DS_Store b/ios/.DS_Store index cab77ac2d01a85258a5566dcfca6e01acd013bee..7482551c036e0ca3a4f37be3121358c2a58d067c 100644 GIT binary patch delta 53 zcmZp1XmOa}&nUMsU^hRb++-esO`Ivk$vH{+`8kZ6*9b^3B5}6}{$$$xP(+y<0OEKO ATL1t6 delta 38 ucmZp1XmOa}&nUAoU^hRb%w!&cO`C5DurY4_A^4JM^ID!L=FRL9f7t;DD-E{* diff --git a/lib/ui/game/game_screen.dart b/lib/ui/game/game_screen.dart index c2464cc..e15d4c3 100644 --- a/lib/ui/game/game_screen.dart +++ b/lib/ui/game/game_screen.dart @@ -57,8 +57,11 @@ class _GameScreenState extends State with TickerProviderStateMixin { @override void dispose() { _blinkController.dispose(); super.dispose(); } - // --- NUOVO DIALOG: CONFERMA USCITA (ANTI-FUGA) --- + // --- DIALOG: CONFERMA USCITA (ANTI-FUGA) AGGIORNATO --- void _showExitConfirmationDialog(BuildContext context, GameController gameController, ThemeColors theme, AppThemeType themeType) { + // Determiniamo se è una partita locale (no CPU e no Online) + bool isLocalMatch = !gameController.isOnline && !gameController.isVsCPU; + showDialog( context: context, builder: (ctx) => AlertDialog( @@ -80,7 +83,9 @@ class _GameScreenState extends State with TickerProviderStateMixin { ], ), content: Text( - "Se esci ora, la partita verrà registrata automaticamente come una SCONFITTA.\n\nSei sicuro di voler fuggire?", + isLocalMatch + ? "Sei sicuro di voler interrompere la partita locale in corso?" // Testo per partite in locale + : "Se esci ora, la partita verrà registrata automaticamente come una SCONFITTA.\n\nSei sicuro di voler fuggire?", // Testo minaccioso per partite classificate style: _getTextStyle(themeType, TextStyle(color: theme.text, fontSize: 15, height: 1.4)), ), actions: [ @@ -95,8 +100,10 @@ class _GameScreenState extends State with TickerProviderStateMixin { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), onPressed: () { - // 1. Assegna la sconfitta! - StorageService.instance.addLoss(); + // 1. Assegna la sconfitta SOLO se non è una partita in locale! + if (!isLocalMatch) { + StorageService.instance.addLoss(); + } // 2. Disconnette e pulisce gameController.disconnectOnlineGame(); // 3. Chiude il dialog diff --git a/lib/ui/multiplayer/lobby_screen.dart b/lib/ui/multiplayer/lobby_screen.dart index badfcd5..32ec321 100644 --- a/lib/ui/multiplayer/lobby_screen.dart +++ b/lib/ui/multiplayer/lobby_screen.dart @@ -3,6 +3,7 @@ // =========================================================================== import 'dart:ui'; +import 'dart:math'; // <--- AGGIUNTO PER IL RANDOM DELL'INVITO import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; @@ -17,8 +18,9 @@ import '../../services/multiplayer_service.dart'; import '../../services/storage_service.dart'; import '../game/game_screen.dart'; import '../../widgets/cyber_border.dart'; -import '../../widgets/painters.dart'; // <--- ECCO L'IMPORT MANCANTE! +import '../../widgets/painters.dart'; import 'lobby_widgets.dart'; +import '../home/home_modals.dart'; // <--- AGGIUNTO PER IL DIALOG DELLE IMPOSTAZIONI class LobbyScreen extends StatefulWidget { final String? initialRoomCode; @@ -104,27 +106,62 @@ class _LobbyScreenState extends State with WidgetsBindingObserver { } } - Future _createRoomAndInvite(String targetUid, String targetName) async { - if (_isLoading) return; + // --- NUOVA LOGICA: FLOW PER SFIDA DIRETTA (Allineato con HomeScreen) --- + void _startDirectChallengeFlow(String targetUid, String targetName) { + HomeModals.showChallengeSetupDialog( + context, + targetName, + (int radius, ArenaShape shape, String timeMode) { + _executeSendChallenge(targetUid, targetName, radius, shape, timeMode); + } + ); + } + + Future _executeSendChallenge(String targetUid, String targetName, int radius, ArenaShape shape, String timeMode) async { setState(() => _isLoading = true); + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + final rnd = Random(); + String roomCode = String.fromCharCodes(Iterable.generate(5, (_) => chars.codeUnitAt(rnd.nextInt(chars.length)))); + try { - String code = await _multiplayerService.createGameRoom( - _selectedRadius, _playerName, _selectedShape.name, _timeModeSetting, isPublic: _isPublicRoom - ); + int gameSeed = rnd.nextInt(9999999); - await _multiplayerService.sendInvite(targetUid, code, _playerName); + await FirebaseFirestore.instance.collection('games').doc(roomCode).set({ + 'status': 'waiting', + 'hostName': StorageService.instance.playerName, + 'hostUid': FirebaseAuth.instance.currentUser?.uid, + 'radius': radius, + 'shape': shape.name, + 'timeMode': timeMode, + 'isPublic': false, + 'createdAt': FieldValue.serverTimestamp(), + 'players': [FirebaseAuth.instance.currentUser?.uid], + 'turn': 0, + 'moves': [], + 'seed': gameSeed, + }); - if (!mounted) return; - setState(() { _myRoomCode = code; _isLoading = false; _roomStarted = false; }); + await FirebaseFirestore.instance.collection('invites').add({ + 'toUid': targetUid, + 'fromName': StorageService.instance.playerName, + 'roomCode': roomCode, + 'timestamp': FieldValue.serverTimestamp(), + }); - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Sfida inviata a $targetName!"), backgroundColor: Colors.green)); - _showWaitingDialog(code); + setState(() => _isLoading = false); + if (mounted) { + _showWaitingDialog(roomCode); // Usiamo il dialog interno della lobby + } } catch (e) { - if (mounted) { setState(() => _isLoading = false); _showError("Errore durante la creazione della partita."); } + setState(() => _isLoading = false); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Errore: $e", style: const TextStyle(color: Colors.white)), backgroundColor: Colors.red)); + } } } + // ----------------------------------------------------------------------- Future _joinRoomByCode(String code) async { if (_isLoading) return; @@ -193,7 +230,6 @@ class _LobbyScreenState extends State with WidgetsBindingObserver { ) ) : StreamBuilder( - // Interroghiamo Firebase solo per gli UID dei nostri preferiti (max 10 per limiti di Firestore) stream: FirebaseFirestore.instance.collection('leaderboard') .where(FieldPath.documentId, whereIn: favs.map((f) => f['uid']).take(10).toList()) .snapshots(), @@ -202,7 +238,6 @@ class _LobbyScreenState extends State with WidgetsBindingObserver { return Center(child: CircularProgressIndicator(color: theme.playerBlue)); } - // Mappiamo i risultati di Firebase per un accesso rapido Map> liveData = {}; for (var doc in snapshot.data!.docs) { liveData[doc.id] = doc.data() as Map; @@ -219,7 +254,6 @@ class _LobbyScreenState extends State with WidgetsBindingObserver { if (liveData.containsKey(uid) && liveData[uid]!['lastActive'] != null) { Timestamp lastActive = liveData[uid]!['lastActive']; int diffInSeconds = DateTime.now().difference(lastActive.toDate()).inSeconds; - // Se ha fatto un'azione negli ultimi 3 minuti, lo consideriamo online if (diffInSeconds.abs() < 180) isOnline = true; } @@ -245,7 +279,8 @@ class _LobbyScreenState extends State with WidgetsBindingObserver { ), onPressed: () { Navigator.pop(ctx); - _createRoomAndInvite(uid, name); + // --- ORA USA IL FLUSSO SICURO CON LE IMPOSTAZIONI --- + _startDirectChallengeFlow(uid, name); }, child: Text("SFIDA", style: getLobbyTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), ) @@ -273,6 +308,7 @@ class _LobbyScreenState extends State with WidgetsBindingObserver { } ); } + void _showWaitingDialog(String code) { showDialog( context: context, @@ -804,4 +840,4 @@ class FullScreenGridPainter extends CustomPainter { @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; -} \ No newline at end of file +}