Auto-sync: 20260311_230000
This commit is contained in:
parent
5aa831f750
commit
50f67320a5
2 changed files with 92 additions and 21 deletions
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
import 'dart:math';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class MultiplayerService {
|
||||
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
|
||||
CollectionReference get _gamesCollection => _firestore.collection('games');
|
||||
|
||||
|
|
@ -25,6 +27,7 @@ class MultiplayerService {
|
|||
'moves': [],
|
||||
'seed': randomSeed,
|
||||
'hostName': hostName,
|
||||
'hostUid': _auth.currentUser?.uid, // NUOVO: Salviamo l'ID univoco del creatore
|
||||
'guestName': '',
|
||||
'shape': shapeName,
|
||||
'timeMode': isTimeMode,
|
||||
|
|
@ -52,7 +55,6 @@ class MultiplayerService {
|
|||
return null;
|
||||
}
|
||||
|
||||
// QUERY BLINDATA: Chiede a Firebase solo le stanze waiting E pubbliche
|
||||
Stream<QuerySnapshot> getPublicRooms() {
|
||||
return _gamesCollection
|
||||
.where('status', isEqualTo: 'waiting')
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'dart:ui';
|
|||
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 'dart:math' as math;
|
||||
import '../../logic/game_controller.dart';
|
||||
import '../../models/game_board.dart';
|
||||
|
|
@ -511,6 +512,7 @@ class _CyberBorderPainter extends CustomPainter {
|
|||
bool shouldRepaint(covariant _CyberBorderPainter oldDelegate) => oldDelegate.animationValue != animationValue;
|
||||
}
|
||||
|
||||
// NUOVO: Aggiunto WidgetsBindingObserver per intercettare l'app in background
|
||||
class LobbyScreen extends StatefulWidget {
|
||||
final String? initialRoomCode;
|
||||
|
||||
|
|
@ -520,7 +522,7 @@ class LobbyScreen extends StatefulWidget {
|
|||
State<LobbyScreen> createState() => _LobbyScreenState();
|
||||
}
|
||||
|
||||
class _LobbyScreenState extends State<LobbyScreen> {
|
||||
class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||
final MultiplayerService _multiplayerService = MultiplayerService();
|
||||
late TextEditingController _codeController;
|
||||
|
||||
|
|
@ -531,11 +533,14 @@ class _LobbyScreenState extends State<LobbyScreen> {
|
|||
int _selectedRadius = 4;
|
||||
ArenaShape _selectedShape = ArenaShape.classic;
|
||||
bool _isTimeMode = true;
|
||||
bool _isPublicRoom = true; // Di default la stanza è visibile a tutti
|
||||
bool _isPublicRoom = true;
|
||||
|
||||
bool _roomStarted = false; // Flag per capire se il gioco è effettivamente iniziato
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this); // Attiviamo la sentinella
|
||||
_codeController = TextEditingController();
|
||||
_playerName = StorageService.instance.playerName;
|
||||
|
||||
|
|
@ -547,7 +552,28 @@ class _LobbyScreenState extends State<LobbyScreen> {
|
|||
}
|
||||
|
||||
@override
|
||||
void dispose() { _codeController.dispose(); super.dispose(); }
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this); // Rimuoviamo la sentinella
|
||||
_cleanupGhostRoom(); // Se l'utente chiude la schermata, spazziamo via la stanza
|
||||
_codeController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// Intercetta quando l'app viene messa in background o chiusa!
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.paused || state == AppLifecycleState.detached) {
|
||||
_cleanupGhostRoom();
|
||||
}
|
||||
}
|
||||
|
||||
// La funzione "Spazzino"
|
||||
void _cleanupGhostRoom() {
|
||||
if (_myRoomCode != null && !_roomStarted) {
|
||||
FirebaseFirestore.instance.collection('games').doc(_myRoomCode).delete();
|
||||
_myRoomCode = null; // Evitiamo che venga chiamata due volte
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _createRoom() async {
|
||||
if (_isLoading) return;
|
||||
|
|
@ -559,7 +585,7 @@ class _LobbyScreenState extends State<LobbyScreen> {
|
|||
);
|
||||
|
||||
if (!mounted) return;
|
||||
setState(() { _myRoomCode = code; _isLoading = false; });
|
||||
setState(() { _myRoomCode = code; _isLoading = false; _roomStarted = false; });
|
||||
|
||||
if (!_isPublicRoom) {
|
||||
_multiplayerService.shareInviteLink(code);
|
||||
|
|
@ -666,6 +692,7 @@ class _LobbyScreenState extends State<LobbyScreen> {
|
|||
if (snapshot.hasData && snapshot.data!.exists) {
|
||||
var data = snapshot.data!.data() as Map<String, dynamic>;
|
||||
if (data['status'] == 'playing') {
|
||||
_roomStarted = true; // Il gioco è iniziato, non dobbiamo più cancellare la stanza!
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
Navigator.pop(context);
|
||||
context.read<GameController>().startNewGame(_selectedRadius, isOnline: true, roomCode: code, isHost: true, shape: _selectedShape, timeMode: _isTimeMode);
|
||||
|
|
@ -674,19 +701,31 @@ class _LobbyScreenState extends State<LobbyScreen> {
|
|||
}
|
||||
}
|
||||
|
||||
return Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
insetPadding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
dialogContent,
|
||||
const SizedBox(height: 20),
|
||||
TextButton(
|
||||
onPressed: () { FirebaseFirestore.instance.collection('games').doc(code).delete(); Navigator.pop(context); },
|
||||
child: Text("ANNULLA", style: _getTextStyle(themeType, TextStyle(color: Colors.red, fontWeight: FontWeight.w900, fontSize: 20, letterSpacing: 2.0, shadows: themeType == AppThemeType.doodle ? [] : [const Shadow(color: Colors.black, blurRadius: 2)]))),
|
||||
),
|
||||
],
|
||||
// NUOVO: PopScope intercetta lo swipe indietro e il tasto back di Android
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) {
|
||||
if (didPop) return;
|
||||
_cleanupGhostRoom(); // Spazza via la stanza se l'utente striscia per tornare indietro
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
insetPadding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
dialogContent,
|
||||
const SizedBox(height: 20),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_cleanupGhostRoom(); // Spazza via la stanza se clicca ANNULLA
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text("ANNULLA", style: _getTextStyle(themeType, TextStyle(color: Colors.red, fontWeight: FontWeight.w900, fontSize: 20, letterSpacing: 2.0, shadows: themeType == AppThemeType.doodle ? [] : [const Shadow(color: Colors.black, blurRadius: 2)]))),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
@ -869,7 +908,6 @@ class _LobbyScreenState extends State<LobbyScreen> {
|
|||
StreamBuilder<QuerySnapshot>(
|
||||
stream: _multiplayerService.getPublicRooms(),
|
||||
builder: (context, snapshot) {
|
||||
// RIMOZIONE DELL'ERRORE ROSSO DALLA SCHERMATA
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Padding(padding: const EdgeInsets.all(20), child: Center(child: CircularProgressIndicator(color: theme.playerBlue)));
|
||||
}
|
||||
|
|
@ -881,8 +919,39 @@ class _LobbyScreenState extends State<LobbyScreen> {
|
|||
);
|
||||
}
|
||||
|
||||
// Ordiniamo le stanze dalla più recente
|
||||
var docs = snapshot.data!.docs;
|
||||
DateTime now = DateTime.now(); // Tempo attuale
|
||||
String? myUid = FirebaseAuth.instance.currentUser?.uid;
|
||||
|
||||
// FILTRO LOCALE E SCADENZA (15 MINUTI)
|
||||
var docs = snapshot.data!.docs.where((doc) {
|
||||
var data = doc.data() as Map<String, dynamic>;
|
||||
|
||||
// 1. Deve essere pubblica
|
||||
if (data['isPublic'] != true) return false;
|
||||
|
||||
// 2. Non devo vedere la mia stessa stanza
|
||||
if (data['hostUid'] != null && data['hostUid'] == myUid) return false;
|
||||
|
||||
// 3. Non deve essere una "Stanza Fantasma" (più vecchia di 15 minuti)
|
||||
Timestamp? createdAt = data['createdAt'] as Timestamp?;
|
||||
if (createdAt != null) {
|
||||
int ageInMinutes = now.difference(createdAt.toDate()).inMinutes;
|
||||
if (ageInMinutes > 15) {
|
||||
FirebaseFirestore.instance.collection('games').doc(doc.id).delete();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true; // Se passa i test, mostrala!
|
||||
}).toList();
|
||||
|
||||
if (docs.isEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0),
|
||||
child: Center(child: Text("Nessuna stanza pubblica al momento.\nCreane una tu!", textAlign: TextAlign.center, style: _getTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.6), height: 1.5)))),
|
||||
);
|
||||
}
|
||||
|
||||
// Ordiniamo le stanze valide dalla più recente
|
||||
docs.sort((a, b) {
|
||||
Timestamp? tA = (a.data() as Map<String, dynamic>)['createdAt'] as Timestamp?;
|
||||
Timestamp? tB = (b.data() as Map<String, dynamic>)['createdAt'] as Timestamp?;
|
||||
|
|
|
|||
Loading…
Reference in a new issue