From 384a9d7bd7285d54efce26a9b15c04566fc3ae82 Mon Sep 17 00:00:00 2001 From: Paolo Date: Thu, 12 Mar 2026 14:00:01 +0100 Subject: [PATCH] Auto-sync: 20260312_140000 --- ios/Podfile.lock | 137 ++++++++++++++++------ lib/ui/home/home_screen.dart | 2 +- lib/ui/multiplayer/lobby_screen.dart | 162 ++++++++++++++++----------- pubspec.yaml | 2 +- 4 files changed, 204 insertions(+), 99 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index bd62485..461220c 100644 --- a/ios/Podfile.lock +++ b/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 diff --git a/lib/ui/home/home_screen.dart b/lib/ui/home/home_screen.dart index 6677b04..c8627a4 100644 --- a/lib/ui/home/home_screen.dart +++ b/lib/ui/home/home_screen.dart @@ -912,10 +912,10 @@ class _HomeScreenState extends State 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; - // 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; diff --git a/lib/ui/multiplayer/lobby_screen.dart b/lib/ui/multiplayer/lobby_screen.dart index 37fce8b..a55441d 100644 --- a/lib/ui/multiplayer/lobby_screen.dart +++ b/lib/ui/multiplayer/lobby_screen.dart @@ -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 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 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 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 with WidgetsBindingObserver { if (snapshot.hasData && snapshot.data!.exists) { var data = snapshot.data!.data() as Map; 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().startNewGame(_selectedRadius, isOnline: true, roomCode: code, isHost: true, shape: _selectedShape, timeMode: _isTimeMode); @@ -701,12 +713,11 @@ class _LobbyScreenState extends State 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 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 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 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 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 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; - - // 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 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 with WidgetsBindingObserver { ); } - // Ordiniamo le stanze valide dalla più recente docs.sort((a, b) { Timestamp? tA = (a.data() as Map)['createdAt'] as Timestamp?; Timestamp? tB = (b.data() as Map)['createdAt'] as Timestamp?; @@ -972,7 +1005,6 @@ class _LobbyScreenState extends State 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"; diff --git a/pubspec.yaml b/pubspec.yaml index 45b47ed..e042f19 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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