Auto-sync: 20260312_140000
This commit is contained in:
parent
50f67320a5
commit
384a9d7bd7
4 changed files with 204 additions and 99 deletions
137
ios/Podfile.lock
137
ios/Podfile.lock
|
|
@ -1190,6 +1190,10 @@ PODS:
|
|||
- abseil/xcprivacy (1.20240722.0)
|
||||
- app_links (7.0.0):
|
||||
- Flutter
|
||||
- AppCheckCore (11.2.0):
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- audioplayers_darwin (0.0.1):
|
||||
- Flutter
|
||||
- BoringSSL-GRPC (0.0.37):
|
||||
|
|
@ -1199,32 +1203,60 @@ PODS:
|
|||
- BoringSSL-GRPC/Interface (= 0.0.37)
|
||||
- BoringSSL-GRPC/Interface (0.0.37)
|
||||
- cloud_firestore (6.1.2):
|
||||
- Firebase/Firestore (= 12.8.0)
|
||||
- Firebase/Firestore (= 12.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- Firebase/CoreOnly (12.8.0):
|
||||
- FirebaseCore (~> 12.8.0)
|
||||
- Firebase/Firestore (12.8.0):
|
||||
- Firebase/Auth (12.9.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseFirestore (~> 12.8.0)
|
||||
- firebase_core (4.4.0):
|
||||
- Firebase/CoreOnly (= 12.8.0)
|
||||
- FirebaseAuth (~> 12.9.0)
|
||||
- Firebase/CoreOnly (12.9.0):
|
||||
- FirebaseCore (~> 12.9.0)
|
||||
- Firebase/Firestore (12.9.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseFirestore (~> 12.9.0)
|
||||
- firebase_app_check (0.4.1-5):
|
||||
- Firebase/CoreOnly (~> 12.9.0)
|
||||
- firebase_core
|
||||
- FirebaseAppCheck (~> 12.9.0)
|
||||
- Flutter
|
||||
- FirebaseAppCheckInterop (12.8.0)
|
||||
- FirebaseCore (12.8.0):
|
||||
- FirebaseCoreInternal (~> 12.8.0)
|
||||
- firebase_auth (6.1.4):
|
||||
- Firebase/Auth (= 12.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_core (4.5.0):
|
||||
- Firebase/CoreOnly (= 12.9.0)
|
||||
- Flutter
|
||||
- FirebaseAppCheck (12.9.0):
|
||||
- AppCheckCore (~> 11.0)
|
||||
- FirebaseAppCheckInterop (~> 12.9.0)
|
||||
- FirebaseCore (~> 12.9.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
- FirebaseAppCheckInterop (12.9.0)
|
||||
- FirebaseAuth (12.9.0):
|
||||
- FirebaseAppCheckInterop (~> 12.9.0)
|
||||
- FirebaseAuthInterop (~> 12.9.0)
|
||||
- FirebaseCore (~> 12.9.0)
|
||||
- FirebaseCoreExtension (~> 12.9.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GTMSessionFetcher/Core (< 6.0, >= 3.4)
|
||||
- RecaptchaInterop (~> 101.0)
|
||||
- FirebaseAuthInterop (12.9.0)
|
||||
- FirebaseCore (12.9.0):
|
||||
- FirebaseCoreInternal (~> 12.9.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/Logger (~> 8.1)
|
||||
- FirebaseCoreExtension (12.8.0):
|
||||
- FirebaseCore (~> 12.8.0)
|
||||
- FirebaseCoreInternal (12.8.0):
|
||||
- FirebaseCoreExtension (12.9.0):
|
||||
- FirebaseCore (~> 12.9.0)
|
||||
- FirebaseCoreInternal (12.9.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- FirebaseFirestore (12.8.0):
|
||||
- FirebaseCore (~> 12.8.0)
|
||||
- FirebaseCoreExtension (~> 12.8.0)
|
||||
- FirebaseFirestoreInternal (~> 12.8.0)
|
||||
- FirebaseSharedSwift (~> 12.8.0)
|
||||
- FirebaseFirestoreInternal (12.8.0):
|
||||
- FirebaseFirestore (12.9.0):
|
||||
- FirebaseCore (~> 12.9.0)
|
||||
- FirebaseCoreExtension (~> 12.9.0)
|
||||
- FirebaseFirestoreInternal (~> 12.9.0)
|
||||
- FirebaseSharedSwift (~> 12.9.0)
|
||||
- FirebaseFirestoreInternal (12.9.0):
|
||||
- abseil/algorithm (~> 1.20240722.0)
|
||||
- abseil/base (~> 1.20240722.0)
|
||||
- abseil/container/flat_hash_map (~> 1.20240722.0)
|
||||
|
|
@ -1233,22 +1265,38 @@ PODS:
|
|||
- abseil/strings/strings (~> 1.20240722.0)
|
||||
- abseil/time (~> 1.20240722.0)
|
||||
- abseil/types (~> 1.20240722.0)
|
||||
- FirebaseAppCheckInterop (~> 12.8.0)
|
||||
- FirebaseCore (~> 12.8.0)
|
||||
- FirebaseAppCheckInterop (~> 12.9.0)
|
||||
- FirebaseCore (~> 12.9.0)
|
||||
- "gRPC-C++ (~> 1.69.0)"
|
||||
- gRPC-Core (~> 1.69.0)
|
||||
- leveldb-library (~> 1.22)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseSharedSwift (12.8.0)
|
||||
- FirebaseSharedSwift (12.9.0)
|
||||
- Flutter (1.0.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (8.1.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Environment (8.1.0):
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Logger (8.1.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Network (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (8.1.0)":
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Privacy (8.1.0)
|
||||
- GoogleUtilities/Reachability (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/UserDefaults (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- "gRPC-C++ (1.69.0)":
|
||||
- "gRPC-C++/Implementation (= 1.69.0)"
|
||||
- "gRPC-C++/Interface (= 1.69.0)"
|
||||
|
|
@ -1341,12 +1389,15 @@ PODS:
|
|||
- gRPC-Core/Privacy (= 1.69.0)
|
||||
- gRPC-Core/Interface (1.69.0)
|
||||
- gRPC-Core/Privacy (1.69.0)
|
||||
- GTMSessionFetcher/Core (5.1.0)
|
||||
- leveldb-library (1.22.6)
|
||||
- nanopb (3.30910.0):
|
||||
- nanopb/decode (= 3.30910.0)
|
||||
- nanopb/encode (= 3.30910.0)
|
||||
- nanopb/decode (3.30910.0)
|
||||
- nanopb/encode (3.30910.0)
|
||||
- PromisesObjC (2.4.0)
|
||||
- RecaptchaInterop (101.0.0)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
|
|
@ -1357,6 +1408,8 @@ DEPENDENCIES:
|
|||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||
- audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`)
|
||||
- cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`)
|
||||
- firebase_app_check (from `.symlinks/plugins/firebase_app_check/ios`)
|
||||
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
|
|
@ -1365,9 +1418,13 @@ DEPENDENCIES:
|
|||
SPEC REPOS:
|
||||
trunk:
|
||||
- abseil
|
||||
- AppCheckCore
|
||||
- BoringSSL-GRPC
|
||||
- Firebase
|
||||
- FirebaseAppCheck
|
||||
- FirebaseAppCheckInterop
|
||||
- FirebaseAuth
|
||||
- FirebaseAuthInterop
|
||||
- FirebaseCore
|
||||
- FirebaseCoreExtension
|
||||
- FirebaseCoreInternal
|
||||
|
|
@ -1377,8 +1434,11 @@ SPEC REPOS:
|
|||
- GoogleUtilities
|
||||
- "gRPC-C++"
|
||||
- gRPC-Core
|
||||
- GTMSessionFetcher
|
||||
- leveldb-library
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- RecaptchaInterop
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
app_links:
|
||||
|
|
@ -1387,6 +1447,10 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/audioplayers_darwin/ios"
|
||||
cloud_firestore:
|
||||
:path: ".symlinks/plugins/cloud_firestore/ios"
|
||||
firebase_app_check:
|
||||
:path: ".symlinks/plugins/firebase_app_check/ios"
|
||||
firebase_auth:
|
||||
:path: ".symlinks/plugins/firebase_auth/ios"
|
||||
firebase_core:
|
||||
:path: ".symlinks/plugins/firebase_core/ios"
|
||||
Flutter:
|
||||
|
|
@ -1399,24 +1463,33 @@ EXTERNAL SOURCES:
|
|||
SPEC CHECKSUMS:
|
||||
abseil: a05cc83bf02079535e17169a73c5be5ba47f714b
|
||||
app_links: a754cbec3c255bd4bbb4d236ecc06f28cd9a7ce8
|
||||
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
|
||||
audioplayers_darwin: ccf9c770ee768abb07e26d90af093f7bab1c12ab
|
||||
BoringSSL-GRPC: dded2a44897e45f28f08ae87a55ee4bcd19bc508
|
||||
cloud_firestore: 4bd00c3464706d9e09dabac0bb8e9610456109f5
|
||||
Firebase: 9a58fdbc9d8655ed7b79a19cf9690bb007d3d46d
|
||||
firebase_core: ee30637e6744af8e0c12a6a1e8a9718506ec2398
|
||||
FirebaseAppCheckInterop: ba3dc604a89815379e61ec2365101608d365cf7d
|
||||
FirebaseCore: 0dbad74bda10b8fb9ca34ad8f375fb9dd3ebef7c
|
||||
FirebaseCoreExtension: 6605938d51f765d8b18bfcafd2085276a252bee2
|
||||
FirebaseCoreInternal: fe5fa466aeb314787093a7dce9f0beeaad5a2a21
|
||||
FirebaseFirestore: 67f23000ca238ccbab79127ed59636a9a2689e74
|
||||
FirebaseFirestoreInternal: a0e7382af3d208898dcd1d4d52d8a7870632e881
|
||||
FirebaseSharedSwift: f57ed48f4542b2d7eb4738f4f23ba443f78b3780
|
||||
cloud_firestore: 81f6c428ecee874dc3808afe0e0c48a87beb5bdf
|
||||
Firebase: 065f2bb395062046623036d8e6dc857bc2521d56
|
||||
firebase_app_check: 33f1df6830ec8ebadee0db0120956c44a65c7213
|
||||
firebase_auth: fecf9fe293464b52063f5f2a7110e63ff2ab3403
|
||||
firebase_core: afac1aac13c931e0401c7e74ed1276112030efab
|
||||
FirebaseAppCheck: 94dae4d9bb682bdef85a778b0c1024a4613f1e89
|
||||
FirebaseAppCheckInterop: 4bade10286cc977e516f75d2d8312cbdfa534789
|
||||
FirebaseAuth: 3a39f6436c21ebfd7919b698228b4f89ff94c23b
|
||||
FirebaseAuthInterop: f8f6ff72dc24621906497fbe5cf3c42ee815e59c
|
||||
FirebaseCore: 428912f751178b06bef0a1793effeb4a5e09a9b8
|
||||
FirebaseCoreExtension: e911052d59cd0da237a45d706fc0f81654f035c1
|
||||
FirebaseCoreInternal: b321eafae5362113bc182956fafc9922cfc77b72
|
||||
FirebaseFirestore: d8b76ca1feb4ca0b0f078c45f7d1bd8014a49ef1
|
||||
FirebaseFirestoreInternal: 02341a9ba87f6309227b04685022a5e16307bbf7
|
||||
FirebaseSharedSwift: 9d2fa84a46676302b89dbd5e6e62bce2fe376909
|
||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
"gRPC-C++": cc207623316fb041a7a3e774c252cf68a058b9e8
|
||||
gRPC-Core: 860978b7db482de8b4f5e10677216309b5ff6330
|
||||
GTMSessionFetcher: b8ab00db932816e14b0a0664a08cb73dda6d164b
|
||||
leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||
|
||||
|
|
|
|||
|
|
@ -912,10 +912,10 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
|||
final docs = snapshot.data!.docs;
|
||||
return ListView.builder(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: docs.length, // <--- ECCO LA RIGA MAGICA AGGIUNTA!
|
||||
itemBuilder: (context, index) {
|
||||
var data = docs[index].data() as Map<String, dynamic>;
|
||||
|
||||
// Ora controlliamo se l'ID del documento su Firebase è uguale al nostro ID segreto!
|
||||
String? myUid = FirebaseAuth.instance.currentUser?.uid;
|
||||
bool isMe = docs[index].id == myUid;
|
||||
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ class _NeonActionButton extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (themeType == AppThemeType.doodle) {
|
||||
double tilt = (label == "UNISCITI") ? -0.015 : 0.02;
|
||||
double tilt = (label == "UNISCITI" || label == "ANNULLA") ? -0.015 : 0.02;
|
||||
return Transform.rotate(
|
||||
angle: tilt,
|
||||
child: GestureDetector(
|
||||
|
|
@ -428,7 +428,13 @@ class _NeonActionButton extends StatelessWidget {
|
|||
boxShadow: [BoxShadow(color: theme.text.withOpacity(0.9), offset: const Offset(4, 4), blurRadius: 0)],
|
||||
),
|
||||
child: Center(
|
||||
child: Text(label, style: _getTextStyle(themeType, const TextStyle(fontSize: 20, fontWeight: FontWeight.w900, letterSpacing: 3.0, color: Colors.white))),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Text(label, style: _getTextStyle(themeType, const TextStyle(fontSize: 20, fontWeight: FontWeight.w900, letterSpacing: 3.0, color: Colors.white))),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -449,7 +455,13 @@ class _NeonActionButton extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Text(label, style: _getTextStyle(themeType, const TextStyle(fontSize: 16, fontWeight: FontWeight.w900, letterSpacing: 2.0, color: Colors.white, shadows: [Shadow(color: Colors.black, blurRadius: 2, offset: Offset(1, 1))]))),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Text(label, style: _getTextStyle(themeType, const TextStyle(fontSize: 16, fontWeight: FontWeight.w900, letterSpacing: 2.0, color: Colors.white, shadows: [Shadow(color: Colors.black, blurRadius: 2, offset: Offset(1, 1))]))),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -512,7 +524,6 @@ 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;
|
||||
|
||||
|
|
@ -530,17 +541,20 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
String? _myRoomCode;
|
||||
String _playerName = '';
|
||||
|
||||
// Variabile per gestire l'effetto "sipario"
|
||||
bool _isCreatingRoom = false;
|
||||
|
||||
int _selectedRadius = 4;
|
||||
ArenaShape _selectedShape = ArenaShape.classic;
|
||||
bool _isTimeMode = true;
|
||||
bool _isPublicRoom = true;
|
||||
|
||||
bool _roomStarted = false; // Flag per capire se il gioco è effettivamente iniziato
|
||||
bool _roomStarted = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this); // Attiviamo la sentinella
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
_codeController = TextEditingController();
|
||||
_playerName = StorageService.instance.playerName;
|
||||
|
||||
|
|
@ -553,13 +567,12 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this); // Rimuoviamo la sentinella
|
||||
_cleanupGhostRoom(); // Se l'utente chiude la schermata, spazziamo via la stanza
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
_cleanupGhostRoom();
|
||||
_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) {
|
||||
|
|
@ -567,11 +580,10 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
}
|
||||
}
|
||||
|
||||
// La funzione "Spazzino"
|
||||
void _cleanupGhostRoom() {
|
||||
if (_myRoomCode != null && !_roomStarted) {
|
||||
FirebaseFirestore.instance.collection('games').doc(_myRoomCode).delete();
|
||||
_myRoomCode = null; // Evitiamo che venga chiamata due volte
|
||||
_myRoomCode = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -692,7 +704,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
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!
|
||||
_roomStarted = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
Navigator.pop(context);
|
||||
context.read<GameController>().startNewGame(_selectedRadius, isOnline: true, roomCode: code, isHost: true, shape: _selectedShape, timeMode: _isTimeMode);
|
||||
|
|
@ -701,12 +713,11 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
_cleanupGhostRoom();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Dialog(
|
||||
|
|
@ -719,7 +730,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
const SizedBox(height: 20),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_cleanupGhostRoom(); // Spazza via la stanza se clicca ANNULLA
|
||||
_cleanupGhostRoom();
|
||||
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)]))),
|
||||
|
|
@ -746,9 +757,9 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
if (themeType == AppThemeType.cyberpunk) bgImage = 'assets/images/cyber_bg.jpg';
|
||||
|
||||
bool isChaosUnlocked = true;
|
||||
|
||||
Color doodlePenColor = const Color(0xFF00008B);
|
||||
|
||||
// --- PANNELLO IMPOSTAZIONI STANZA ---
|
||||
Widget hostPanel = Transform.rotate(
|
||||
angle: themeType == AppThemeType.doodle ? 0.01 : 0,
|
||||
child: Container(
|
||||
|
|
@ -823,7 +834,9 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
|
||||
Widget uiContent = SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
|
||||
physics: const BouncingScrollPhysics(),
|
||||
// Padding inferiore aumentato a 60 per evitare il taglio dei pulsanti
|
||||
padding: EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0, bottom: MediaQuery.of(context).padding.bottom + 60.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
|
|
@ -850,49 +863,76 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
hostPanel,
|
||||
const SizedBox(height: 15),
|
||||
_NeonActionButton(label: "CREA PARTITA", color: theme.playerRed, onTap: _createRoom, theme: theme, themeType: themeType),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child: Text("OPPURE", style: _getTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), fontWeight: FontWeight.bold, letterSpacing: 2.0, fontSize: 13)))),
|
||||
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
Transform.rotate(
|
||||
angle: themeType == AppThemeType.doodle ? 0.02 : 0,
|
||||
child: Container(
|
||||
decoration: themeType == AppThemeType.doodle ? BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), bottomRight: Radius.circular(20), topRight: Radius.circular(5), bottomLeft: Radius.circular(5)),
|
||||
border: Border.all(color: theme.text, width: 2.5),
|
||||
boxShadow: [BoxShadow(color: theme.text.withOpacity(0.8), offset: const Offset(5, 5), blurRadius: 0)],
|
||||
) : BoxDecoration(
|
||||
boxShadow: [BoxShadow(color: theme.playerBlue.withOpacity(0.15), blurRadius: 15, spreadRadius: 1)]
|
||||
),
|
||||
child: TextField(
|
||||
controller: _codeController, textCapitalization: TextCapitalization.characters, textAlign: TextAlign.center, maxLength: 5,
|
||||
style: _getTextStyle(themeType, TextStyle(fontSize: 28, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 12, shadows: themeType == AppThemeType.doodle ? [] : [Shadow(color: theme.playerBlue.withOpacity(0.5), blurRadius: 8)])),
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
hintText: "CODICE", hintStyle: _getTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.3), letterSpacing: 10, fontSize: 20)), counterText: "",
|
||||
filled: themeType != AppThemeType.doodle,
|
||||
fillColor: themeType == AppThemeType.cyberpunk ? Colors.black.withOpacity(0.85) : theme.text.withOpacity(0.05),
|
||||
enabledBorder: themeType == AppThemeType.doodle ? InputBorder.none : OutlineInputBorder(borderSide: BorderSide(color: theme.gridLine.withOpacity(0.5), width: 2.0), borderRadius: BorderRadius.circular(15)),
|
||||
focusedBorder: themeType == AppThemeType.doodle ? InputBorder.none : OutlineInputBorder(borderSide: BorderSide(color: theme.playerBlue, width: 3.0), borderRadius: BorderRadius.circular(15)),
|
||||
// --- L'EFFETTO SIPARIO CON ANIMATED SIZE ---
|
||||
AnimatedSize(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
alignment: Alignment.topCenter,
|
||||
child: _isCreatingRoom
|
||||
? Column( // MENU CREAZIONE (Aperto)
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
hostPanel,
|
||||
const SizedBox(height: 15),
|
||||
Row(
|
||||
children: [
|
||||
Expanded( // Entrambi in un Expanded "liscio" si dividono il 50% di spazio
|
||||
child: _NeonActionButton(label: "AVVIA", color: theme.playerRed, onTap: _createRoom, theme: theme, themeType: themeType),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded( // Entrambi in un Expanded "liscio" si dividono il 50% di spazio
|
||||
child: _NeonActionButton(label: "ANNULLA", color: Colors.grey.shade600, onTap: () => setState(() => _isCreatingRoom = false), theme: theme, themeType: themeType),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column( // MENU BASE (Chiuso)
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_NeonActionButton(label: "CREA PARTITA", color: theme.playerRed, onTap: () { FocusScope.of(context).unfocus(); setState(() => _isCreatingRoom = true); }, theme: theme, themeType: themeType),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child: Text("OPPURE", style: _getTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), fontWeight: FontWeight.bold, letterSpacing: 2.0, fontSize: 13)))),
|
||||
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
Transform.rotate(
|
||||
angle: themeType == AppThemeType.doodle ? 0.02 : 0,
|
||||
child: Container(
|
||||
decoration: themeType == AppThemeType.doodle ? BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), bottomRight: Radius.circular(20), topRight: Radius.circular(5), bottomLeft: Radius.circular(5)),
|
||||
border: Border.all(color: theme.text, width: 2.5),
|
||||
boxShadow: [BoxShadow(color: theme.text.withOpacity(0.8), offset: const Offset(5, 5), blurRadius: 0)],
|
||||
) : BoxDecoration(
|
||||
boxShadow: [BoxShadow(color: theme.playerBlue.withOpacity(0.15), blurRadius: 15, spreadRadius: 1)]
|
||||
),
|
||||
child: TextField(
|
||||
controller: _codeController, textCapitalization: TextCapitalization.characters, textAlign: TextAlign.center, maxLength: 5,
|
||||
style: _getTextStyle(themeType, TextStyle(fontSize: 28, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 12, shadows: themeType == AppThemeType.doodle ? [] : [Shadow(color: theme.playerBlue.withOpacity(0.5), blurRadius: 8)])),
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
hintText: "CODICE", hintStyle: _getTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.3), letterSpacing: 10, fontSize: 20)), counterText: "",
|
||||
filled: themeType != AppThemeType.doodle,
|
||||
fillColor: themeType == AppThemeType.cyberpunk ? Colors.black.withOpacity(0.85) : theme.text.withOpacity(0.05),
|
||||
enabledBorder: themeType == AppThemeType.doodle ? InputBorder.none : OutlineInputBorder(borderSide: BorderSide(color: theme.gridLine.withOpacity(0.5), width: 2.0), borderRadius: BorderRadius.circular(15)),
|
||||
focusedBorder: themeType == AppThemeType.doodle ? InputBorder.none : OutlineInputBorder(borderSide: BorderSide(color: theme.playerBlue, width: 3.0), borderRadius: BorderRadius.circular(15)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
_NeonActionButton(label: "UNISCITI", color: theme.playerBlue, onTap: () => _joinRoomByCode(_codeController.text), theme: theme, themeType: themeType),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
_NeonActionButton(label: "UNISCITI", color: theme.playerBlue, onTap: () => _joinRoomByCode(_codeController.text), theme: theme, themeType: themeType),
|
||||
|
||||
const SizedBox(height: 25),
|
||||
Row(
|
||||
|
|
@ -919,20 +959,14 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
);
|
||||
}
|
||||
|
||||
DateTime now = DateTime.now(); // Tempo attuale
|
||||
DateTime now = DateTime.now();
|
||||
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;
|
||||
|
|
@ -941,7 +975,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
return true; // Se passa i test, mostrala!
|
||||
return true;
|
||||
}).toList();
|
||||
|
||||
if (docs.isEmpty) {
|
||||
|
|
@ -951,7 +985,6 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
);
|
||||
}
|
||||
|
||||
// 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?;
|
||||
|
|
@ -972,7 +1005,6 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
|||
String shapeStr = data['shape'] ?? 'classic';
|
||||
bool time = data['timeMode'] ?? true;
|
||||
|
||||
// Formattazione del nome della forma
|
||||
String prettyShape = "Rombo";
|
||||
if (shapeStr == 'cross') prettyShape = "Croce";
|
||||
else if (shapeStr == 'donut') prettyShape = "Buco";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
name: tetraq
|
||||
description: A new Flutter project.
|
||||
publish_to: 'none'
|
||||
version: 1.1.3+5
|
||||
version: 1.1.4+6
|
||||
environment:
|
||||
sdk: ^3.10.7
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue