Auto-sync: 20260315_160000

This commit is contained in:
Paolo 2026-03-15 16:00:01 +01:00
parent 14c01e984c
commit 8caecd401e
12 changed files with 336 additions and 216 deletions

View file

@ -1,2 +1,2 @@
index.html,1773344753424,0d5d4b835a7d632ad11d249230a15561286f2bfcd1da8305c6fb294d37e5da09
404.html,1773344753356,05cbc6f94d7a69ce2e29646eab13be2c884e61ba93e3094df5028866876d18b3 404.html,1773344753356,05cbc6f94d7a69ce2e29646eab13be2c884e61ba93e3094df5028866876d18b3
index.html,1773586765860,5737ce966fa8786becaf7f36a32992cf44102fb3a217c226c30576c993b33e63

View file

@ -9,7 +9,8 @@ import 'package:cloud_firestore/cloud_firestore.dart';
import '../core/app_colors.dart'; import '../core/app_colors.dart';
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart'; // <-- NUOVO IMPORT import 'package:package_info_plus/package_info_plus.dart';
import 'package:device_info_plus/device_info_plus.dart'; // <-- NUOVO IMPORT
class StorageService { class StorageService {
static final StorageService instance = StorageService._internal(); static final StorageService instance = StorageService._internal();
@ -89,19 +90,39 @@ class StorageService {
// IDENTIFICA IL SISTEMA OPERATIVO E LA VERSIONE APP // IDENTIFICA IL SISTEMA OPERATIVO E LA VERSIONE APP
String currentPlatform = "Sconosciuta"; String currentPlatform = "Sconosciuta";
String appVersion = "N/D"; String appVersion = "N/D";
String deviceModel = "Sconosciuto"; // <-- NUOVO: MODELLO HARDWARE
if (!kIsWeb) { if (!kIsWeb) {
// Leggi Piattaforma base
if (Platform.isAndroid) currentPlatform = "Android"; if (Platform.isAndroid) currentPlatform = "Android";
else if (Platform.isIOS) currentPlatform = "iOS"; else if (Platform.isIOS) currentPlatform = "iOS";
else if (Platform.isMacOS) currentPlatform = "macOS"; else if (Platform.isMacOS) currentPlatform = "macOS";
else if (Platform.isWindows) currentPlatform = "Windows"; else if (Platform.isWindows) currentPlatform = "Windows";
// Leggi Versione App
try { try {
PackageInfo packageInfo = await PackageInfo.fromPlatform(); PackageInfo packageInfo = await PackageInfo.fromPlatform();
appVersion = "${packageInfo.version}+${packageInfo.buildNumber}"; appVersion = "${packageInfo.version}+${packageInfo.buildNumber}";
} catch(e) { } catch(e) {
debugPrint("Errore lettura versione: $e"); debugPrint("Errore lettura versione: $e");
} }
// Leggi Modello Hardware
try {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
deviceModel = "${androidInfo.manufacturer} ${androidInfo.model}"; // Es. samsung SM-S928B
} else if (Platform.isIOS) {
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
deviceModel = iosInfo.utsname.machine; // Es. iPhone13,2
} else if (Platform.isMacOS) {
MacOsDeviceInfo macInfo = await deviceInfo.macOsInfo;
deviceModel = macInfo.model; // Es. MacBookPro16,1
}
} catch(e) {
debugPrint("Errore lettura hardware: $e");
}
} }
// AGGIORNA IL TEMPO DI UTILIZZO // AGGIORNA IL TEMPO DI UTILIZZO
@ -109,7 +130,7 @@ class StorageService {
int now = DateTime.now().millisecondsSinceEpoch; int now = DateTime.now().millisecondsSinceEpoch;
int sessionSeconds = (now - _sessionStart) ~/ 1000; int sessionSeconds = (now - _sessionStart) ~/ 1000;
await _prefs.setInt('totalPlaytime', (_prefs.getInt('totalPlaytime') ?? 0) + sessionSeconds); await _prefs.setInt('totalPlaytime', (_prefs.getInt('totalPlaytime') ?? 0) + sessionSeconds);
_sessionStart = now; // resetta per la prossima misurazione _sessionStart = now;
} }
int totalPlaytime = _prefs.getInt('totalPlaytime') ?? 0; int totalPlaytime = _prefs.getInt('totalPlaytime') ?? 0;
@ -123,7 +144,8 @@ class StorageService {
'ip': lastIp, 'ip': lastIp,
'city': lastCity, 'city': lastCity,
'playtime': totalPlaytime, 'playtime': totalPlaytime,
'appVersion': appVersion, // <-- NUOVO: Salva la versione 'appVersion': appVersion,
'deviceModel': deviceModel, // Salva il modello hardware
}, SetOptions(merge: true)); }, SetOptions(merge: true));
} }
} catch(e) { } catch(e) {

View file

@ -33,7 +33,6 @@ class AdminScreen extends StatelessWidget {
return Center(child: Text("Nessun giocatore trovato nel database.", style: TextStyle(color: theme.text))); return Center(child: Text("Nessun giocatore trovato nel database.", style: TextStyle(color: theme.text)));
} }
// Ripristinata la lista completa senza nascondere PAOLO
final docs = snapshot.data!.docs; final docs = snapshot.data!.docs;
return ListView.builder( return ListView.builder(
@ -50,8 +49,9 @@ class AdminScreen extends StatelessWidget {
String platform = data['platform'] ?? 'Sconosciuta'; String platform = data['platform'] ?? 'Sconosciuta';
String ip = data['ip'] ?? 'N/D'; String ip = data['ip'] ?? 'N/D';
String city = data['city'] ?? 'N/D'; String city = data['city'] ?? 'N/D';
String appVersion = data['appVersion'] ?? 'N/D';
String deviceModel = data['deviceModel'] ?? 'N/D';
// --- CALCOLO TEMPO UTILIZZO (HH:MM) ---
int playtimeSec = data['playtime'] ?? 0; int playtimeSec = data['playtime'] ?? 0;
int hours = playtimeSec ~/ 3600; int hours = playtimeSec ~/ 3600;
int minutes = (playtimeSec % 3600) ~/ 60; int minutes = (playtimeSec % 3600) ~/ 60;
@ -109,6 +109,8 @@ class AdminScreen extends StatelessWidget {
Text("📍 Città: $city", style: TextStyle(color: theme.text, fontSize: 16)), Text("📍 Città: $city", style: TextStyle(color: theme.text, fontSize: 16)),
const SizedBox(height: 10), const SizedBox(height: 10),
Text("📱 OS: $platform", style: TextStyle(color: theme.text, fontSize: 16)), Text("📱 OS: $platform", style: TextStyle(color: theme.text, fontSize: 16)),
const SizedBox(height: 10),
Text("💻 Hardware: $deviceModel", style: TextStyle(color: theme.text, fontSize: 16)),
], ],
), ),
actions: [ actions: [
@ -140,7 +142,6 @@ class AdminScreen extends StatelessWidget {
const SizedBox(width: 10), const SizedBox(width: 10),
Text("Vittorie: $wins", style: TextStyle(color: Colors.amber.shade700, fontWeight: FontWeight.bold, fontSize: 12)), Text("Vittorie: $wins", style: TextStyle(color: Colors.amber.shade700, fontWeight: FontWeight.bold, fontSize: 12)),
const Spacer(), const Spacer(),
// --- TEMPO DI GIOCO ---
Icon(Icons.timer, color: theme.text.withOpacity(0.6), size: 16), Icon(Icons.timer, color: theme.text.withOpacity(0.6), size: 16),
const SizedBox(width: 4), const SizedBox(width: 4),
Text(playtimeStr, style: TextStyle(color: theme.text, fontWeight: FontWeight.bold, fontSize: 14)), Text(playtimeStr, style: TextStyle(color: theme.text, fontWeight: FontWeight.bold, fontSize: 14)),
@ -150,22 +151,36 @@ class AdminScreen extends StatelessWidget {
padding: EdgeInsets.symmetric(vertical: 8.0), padding: EdgeInsets.symmetric(vertical: 8.0),
child: Divider(), child: Divider(),
), ),
// QUI È DOVE AVVENIVA IL CRASH! Ora usiamo Expanded e FittedBox
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Column( Expanded(
crossAxisAlignment: CrossAxisAlignment.start, child: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Text("Registrato il:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10)), children: [
Text(createdStr, style: TextStyle(color: theme.text, fontSize: 12, fontWeight: FontWeight.bold)), FittedBox(fit: BoxFit.scaleDown, child: Text("Registrato il:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10))),
], FittedBox(fit: BoxFit.scaleDown, child: Text(createdStr, style: TextStyle(color: theme.text, fontSize: 12, fontWeight: FontWeight.bold))),
],
),
), ),
Column( Expanded(
crossAxisAlignment: CrossAxisAlignment.end, child: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.center,
Text("Ultimo Accesso:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10)), children: [
Text(lastActiveStr, style: TextStyle(color: Colors.green, fontSize: 12, fontWeight: FontWeight.bold)), FittedBox(fit: BoxFit.scaleDown, child: Text("Versione App:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10))),
], FittedBox(fit: BoxFit.scaleDown, child: Text("v. $appVersion", style: TextStyle(color: theme.playerBlue, fontSize: 12, fontWeight: FontWeight.bold))),
],
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FittedBox(fit: BoxFit.scaleDown, child: Text("Ultimo Accesso:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10))),
FittedBox(fit: BoxFit.scaleDown, child: Text(lastActiveStr, style: TextStyle(color: Colors.green, fontSize: 12, fontWeight: FontWeight.bold))),
],
),
), ),
], ],
) )

View file

@ -328,7 +328,6 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
Expanded( Expanded(
child: Center( child: Center(
child: Padding( child: Padding(
// PADDING RIDOTTO AL MINIMO: permette alla griglia di guadagnare pixel preziosi per allargarsi/alzarsi!
padding: const EdgeInsets.symmetric(horizontal: 2.0, vertical: 2.0), padding: const EdgeInsets.symmetric(horizontal: 2.0, vertical: 2.0),
child: LayoutBuilder( child: LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
@ -344,7 +343,6 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
width: actualWidth, height: actualHeight, width: actualWidth, height: actualHeight,
child: Stack( child: Stack(
children: [ children: [
// --- IL VERO SFONDO SFOCATO SAGOMATO (ORA PER TUTTI I TEMI) ---
Positioned.fill( Positioned.fill(
child: ClipPath( child: ClipPath(
clipper: _ArenaClipper(gameController.board), clipper: _ArenaClipper(gameController.board),
@ -387,7 +385,6 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
), ),
Padding( Padding(
// PADDING RIDOTTO IN BASSO: 10 al posto di 20, per far esplodere la griglia verticalmente
padding: const EdgeInsets.only(bottom: 10.0, left: 20.0, right: 20.0, top: 5.0), padding: const EdgeInsets.only(bottom: 10.0, left: 20.0, right: 20.0, top: 5.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -437,10 +434,8 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
backgroundColor: themeType == AppThemeType.doodle ? Colors.white : (bgImage != null ? Colors.transparent : theme.background), backgroundColor: themeType == AppThemeType.doodle ? Colors.white : (bgImage != null ? Colors.transparent : theme.background),
body: Stack( body: Stack(
children: [ children: [
// 1. Sfondo base a tinta unita
Container(color: themeType == AppThemeType.doodle ? Colors.white : theme.background), Container(color: themeType == AppThemeType.doodle ? Colors.white : theme.background),
// 2. Griglia a quadretti (Doodle Theme)
if (themeType == AppThemeType.doodle) if (themeType == AppThemeType.doodle)
Positioned.fill( Positioned.fill(
child: CustomPaint( child: CustomPaint(
@ -448,19 +443,21 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
), ),
), ),
// 3. Immagine di Sfondo
if (bgImage != null) if (bgImage != null)
Positioned.fill( Positioned.fill(
child: Image.asset( child: Container(
bgImage, decoration: BoxDecoration(
fit: BoxFit.cover, image: DecorationImage(
alignment: Alignment.center, image: AssetImage(bgImage!),
color: themeType == AppThemeType.doodle ? Colors.white.withOpacity(0.5) : null, fit: BoxFit.cover,
colorBlendMode: themeType == AppThemeType.doodle ? BlendMode.lighten : null, colorFilter: themeType == AppThemeType.doodle
? ColorFilter.mode(Colors.white.withOpacity(0.5), BlendMode.lighten)
: null,
),
),
), ),
), ),
// 4. Patina scura (Cyberpunk, Music, Arcade e Grimorio)
if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music || themeType == AppThemeType.arcade || themeType == AppThemeType.grimorio)) if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music || themeType == AppThemeType.arcade || themeType == AppThemeType.grimorio))
Positioned.fill( Positioned.fill(
child: Container( child: Container(
@ -473,18 +470,14 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
), ),
), ),
// 5. Effetto "Furia" o Timeout
if (gameController.isTimeMode && !gameController.isCPUThinking && !gameController.isGameOver && gameController.timeLeft > 0 && gameController.timeLeft <= 5 && !gameController.isSetupPhase) if (gameController.isTimeMode && !gameController.isCPUThinking && !gameController.isGameOver && gameController.timeLeft > 0 && gameController.timeLeft <= 5 && !gameController.isSetupPhase)
Positioned.fill(child: BlitzBackgroundEffect(timeLeft: gameController.timeLeft, color: theme.playerRed, themeType: themeType)), Positioned.fill(child: BlitzBackgroundEffect(timeLeft: gameController.timeLeft, color: theme.playerRed, themeType: themeType)),
// 6. Testo degli Eventi
if (gameController.effectText.isNotEmpty) if (gameController.effectText.isNotEmpty)
Positioned.fill(child: SpecialEventBackgroundEffect(text: gameController.effectText, color: gameController.effectColor, themeType: themeType)), Positioned.fill(child: SpecialEventBackgroundEffect(text: gameController.effectText, color: gameController.effectColor, themeType: themeType)),
// 7. Il Gioco Vero e Proprio
Positioned.fill(child: gameContent), Positioned.fill(child: gameContent),
// 8. Schermata Passaggio Dispositivo
if (gameController.isSetupPhase && !_hideJokerMessage) if (gameController.isSetupPhase && !_hideJokerMessage)
Positioned.fill( Positioned.fill(
child: Container( child: Container(
@ -503,7 +496,6 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
), ),
), ),
// 9. Effetti di Vittoria
if (gameController.isGameOver && gameController.board.scoreRed != gameController.board.scoreBlue) if (gameController.isGameOver && gameController.board.scoreRed != gameController.board.scoreBlue)
Positioned.fill(child: IgnorePointer(child: WinnerVFXOverlay(winnerColor: gameController.board.scoreRed > gameController.board.scoreBlue ? theme.playerRed : theme.playerBlue, themeType: themeType))), Positioned.fill(child: IgnorePointer(child: WinnerVFXOverlay(winnerColor: gameController.board.scoreRed > gameController.board.scoreBlue ? theme.playerRed : theme.playerBlue, themeType: themeType))),
], ],
@ -543,7 +535,7 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
} }
// =========================================================================== // ===========================================================================
// CLIPPER MAGICO: Ritaglia l'effetto sfocatura sull'esatta forma dell'arena // CLIPPER MAGICO E ALTRI WIDGETS
// =========================================================================== // ===========================================================================
class _ArenaClipper extends CustomClipper<Path> { class _ArenaClipper extends CustomClipper<Path> {
final GameBoard board; final GameBoard board;
@ -568,9 +560,7 @@ class _ArenaClipper extends CustomClipper<Path> {
} }
return path; return path;
} }
@override bool shouldReclip(covariant _ArenaClipper oldClipper) => true;
@override
bool shouldReclip(covariant _ArenaClipper oldClipper) => true;
} }
class _Particle { class _Particle {
@ -636,7 +626,6 @@ class _WinnerVFXOverlayState extends State<WinnerVFXOverlay> with SingleTickerPr
} }
}); });
} }
@override void dispose() { _vfxController.dispose(); super.dispose(); } @override void dispose() { _vfxController.dispose(); super.dispose(); }
@override Widget build(BuildContext context) { return CustomPaint(painter: _VFXPainter(particles: _particles, themeType: widget.themeType), child: Container()); } @override Widget build(BuildContext context) { return CustomPaint(painter: _VFXPainter(particles: _particles, themeType: widget.themeType), child: Container()); }
} }
@ -679,7 +668,6 @@ class _BouncingEmoji extends StatefulWidget {
final String emoji; const _BouncingEmoji({required this.emoji}); final String emoji; const _BouncingEmoji({required this.emoji});
@override State<_BouncingEmoji> createState() => _BouncingEmojiState(); @override State<_BouncingEmoji> createState() => _BouncingEmojiState();
} }
class _BouncingEmojiState extends State<_BouncingEmoji> with SingleTickerProviderStateMixin { class _BouncingEmojiState extends State<_BouncingEmoji> with SingleTickerProviderStateMixin {
late AnimationController _ctrl; late Animation<double> _anim; late AnimationController _ctrl; late Animation<double> _anim;
@override void initState() { super.initState(); _ctrl = AnimationController(vsync: this, duration: const Duration(milliseconds: 500))..repeat(reverse: true); _anim = Tween<double>(begin: -10, end: 10).animate(CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut)); } @override void initState() { super.initState(); _ctrl = AnimationController(vsync: this, duration: const Duration(milliseconds: 500))..repeat(reverse: true); _anim = Tween<double>(begin: -10, end: 10).animate(CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut)); }

View file

@ -747,10 +747,19 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
BoxDecoration _glassBoxDecoration(ThemeColors theme, AppThemeType themeType) { BoxDecoration _glassBoxDecoration(ThemeColors theme, AppThemeType themeType) {
return BoxDecoration( return BoxDecoration(
color: themeType == AppThemeType.doodle ? Colors.white : theme.text.withOpacity(0.05), color: themeType == AppThemeType.doodle ? Colors.white : null,
// Sfumatura bianca inserita come richiesto!
gradient: themeType == AppThemeType.doodle ? null : LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white.withOpacity(0.25),
Colors.white.withOpacity(0.05),
],
),
borderRadius: BorderRadius.circular(25), borderRadius: BorderRadius.circular(25),
border: Border.all( border: Border.all(
color: themeType == AppThemeType.doodle ? theme.text : Colors.white.withOpacity(0.2), color: themeType == AppThemeType.doodle ? theme.text : Colors.white.withOpacity(0.3),
width: themeType == AppThemeType.doodle ? 2 : 1.5, width: themeType == AppThemeType.doodle ? 2 : 1.5,
), ),
boxShadow: themeType == AppThemeType.doodle boxShadow: themeType == AppThemeType.doodle
@ -763,6 +772,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
Color inkColor = const Color(0xFF111122); Color inkColor = const Color(0xFF111122);
return Padding( return Padding(
// Padding ridotto al minimo
padding: const EdgeInsets.only(top: 5.0, left: 15.0, right: 15.0, bottom: 10.0), padding: const EdgeInsets.only(top: 5.0, left: 15.0, right: 15.0, bottom: 10.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -815,6 +825,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
Container(width: 1, height: 20, color: (themeType == AppThemeType.doodle ? inkColor : Colors.white).withOpacity(0.2)), Container(width: 1, height: 20, color: (themeType == AppThemeType.doodle ? inkColor : Colors.white).withOpacity(0.2)),
const SizedBox(width: 12), const SizedBox(width: 12),
// --- ICONA VOLUME REINTEGRATA ---
AnimatedBuilder( AnimatedBuilder(
animation: AudioService.instance, animation: AudioService.instance,
builder: (context, child) { builder: (context, child) {
@ -868,13 +879,16 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
if (playerName.isEmpty) playerName = "GUEST"; if (playerName.isEmpty) playerName = "GUEST";
int playerLevel = StorageService.instance.playerLevel; int playerLevel = StorageService.instance.playerLevel;
final double screenHeight = MediaQuery.of(context).size.height;
final double vScale = (screenHeight / 920.0).clamp(0.50, 1.0);
Widget uiContent = SafeArea( Widget uiContent = SafeArea(
child: Column( child: Column(
children: [ children: [
// 1. TOP BAR (Sempre visibile in alto) // 1. TOP BAR (Sempre visibile in alto)
_buildTopBar(context, theme, themeType, playerName, playerLevel), _buildTopBar(context, theme, themeType, playerName, playerLevel),
// 2. CONTENUTO SCORREVOLE (Logo + Bottoni) // 2. CONTENUTO SCORREVOLE (Logo + Bottoni) con altezze dinamiche!
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
@ -883,22 +897,24 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const SizedBox(height: 20), SizedBox(height: 20 * vScale),
Center( Center(
child: Transform.rotate( child: Transform.rotate(
angle: themeType == AppThemeType.doodle ? -0.04 : 0, angle: themeType == AppThemeType.doodle ? -0.04 : 0,
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
_debugTapCount++; if (playerName.toUpperCase() == 'PAOLO') {
if (_debugTapCount == 5) { _debugTapCount++;
StorageService.instance.addXP(2000); if (_debugTapCount == 5) {
setState(() {}); StorageService.instance.addXP(2000);
ScaffoldMessenger.of(context).showSnackBar( setState(() {});
SnackBar(content: Text("🛠 DEBUG MODE: +20 Livelli!", style: getSharedTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), backgroundColor: Colors.purpleAccent, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15))) ScaffoldMessenger.of(context).showSnackBar(
); SnackBar(content: Text("🛠 DEBUG MODE: +20 Livelli!", style: getSharedTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), backgroundColor: Colors.purpleAccent, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)))
} else if (_debugTapCount >= 7) { );
_debugTapCount = 0; } else if (_debugTapCount >= 7) {
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen())); _debugTapCount = 0;
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen()));
}
} }
}, },
child: FittedBox( child: FittedBox(
@ -906,29 +922,31 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
child: Text( child: Text(
loc.appTitle.toUpperCase(), loc.appTitle.toUpperCase(),
style: getSharedTextStyle(themeType, TextStyle( style: getSharedTextStyle(themeType, TextStyle(
fontSize: 65, fontSize: 65 * vScale,
fontWeight: FontWeight.w900, fontWeight: FontWeight.w900,
color: themeType == AppThemeType.doodle ? inkColor : theme.text, color: themeType == AppThemeType.doodle ? inkColor : theme.text,
letterSpacing: 10, letterSpacing: 10 * vScale,
shadows: themeType == AppThemeType.doodle shadows: themeType == AppThemeType.doodle
? [const Shadow(color: Colors.white, offset: Offset(-2.5, -2.5), blurRadius: 0), Shadow(color: Colors.black.withOpacity(0.25), offset: const Offset(2.5, 2.5), blurRadius: 1)] // Ombra chiara se il testo è scuro
: themeType == AppThemeType.arcade || themeType == AppThemeType.music ? [] : [BoxShadow(color: Colors.black.withOpacity(0.6), offset: const Offset(3, 6), blurRadius: 8), BoxShadow(color: theme.playerBlue.withOpacity(0.4), offset: const Offset(0, 0), blurRadius: 20)] ? [const Shadow(color: Colors.white, offset: Offset(2.5, 2.5), blurRadius: 2), const Shadow(color: Colors.white, offset: Offset(-2.5, -2.5), blurRadius: 2)]
// Ombra scura e visibile per tutti gli altri temi
: [Shadow(color: Colors.black.withOpacity(0.8), offset: const Offset(3, 4), blurRadius: 8), Shadow(color: theme.playerBlue.withOpacity(0.4), offset: const Offset(0, 0), blurRadius: 20)]
)) ))
), ),
), ),
), ),
), ),
), ),
const SizedBox(height: 40), SizedBox(height: 40 * vScale),
// --- MENU IN BASE AL TEMA --- // --- MENU IN BASE AL TEMA ---
if (themeType == AppThemeType.music) ...[ if (themeType == AppThemeType.music) ...[
MusicCassetteCard(title: loc.onlineTitle, subtitle: loc.onlineSub, neonColor: Colors.blueAccent, angle: -0.04, leftIcon: FontAwesomeIcons.sliders, rightIcon: FontAwesomeIcons.globe, themeType: themeType, onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) => const LobbyScreen())); }), MusicCassetteCard(title: loc.onlineTitle, subtitle: loc.onlineSub, neonColor: Colors.blueAccent, angle: -0.04, leftIcon: FontAwesomeIcons.sliders, rightIcon: FontAwesomeIcons.globe, themeType: themeType, onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) => const LobbyScreen())); }),
const SizedBox(height: 12), SizedBox(height: 12 * vScale),
MusicCassetteCard(title: loc.cpuTitle, subtitle: loc.cpuSub, neonColor: Colors.purpleAccent, angle: 0.03, leftIcon: FontAwesomeIcons.desktop, rightIcon: FontAwesomeIcons.music, themeType: themeType, onTap: () => _showMatchSetupDialog(true)), MusicCassetteCard(title: loc.cpuTitle, subtitle: loc.cpuSub, neonColor: Colors.purpleAccent, angle: 0.03, leftIcon: FontAwesomeIcons.desktop, rightIcon: FontAwesomeIcons.music, themeType: themeType, onTap: () => _showMatchSetupDialog(true)),
const SizedBox(height: 12), SizedBox(height: 12 * vScale),
MusicCassetteCard(title: loc.localTitle, subtitle: loc.localSub, neonColor: Colors.deepPurpleAccent, angle: -0.02, leftIcon: FontAwesomeIcons.headphones, rightIcon: FontAwesomeIcons.headphones, themeType: themeType, onTap: () => _showMatchSetupDialog(false)), MusicCassetteCard(title: loc.localTitle, subtitle: loc.localSub, neonColor: Colors.deepPurpleAccent, angle: -0.02, leftIcon: FontAwesomeIcons.headphones, rightIcon: FontAwesomeIcons.headphones, themeType: themeType, onTap: () => _showMatchSetupDialog(false)),
const SizedBox(height: 30), SizedBox(height: 30 * vScale),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -943,11 +961,11 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
_buildCyberCard(FeatureCard(title: loc.onlineTitle, subtitle: loc.onlineSub, icon: Icons.public, color: Colors.lightBlue.shade200, theme: theme, themeType: themeType, isFeatured: true, onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) => const LobbyScreen())); }), themeType), _buildCyberCard(FeatureCard(title: loc.onlineTitle, subtitle: loc.onlineSub, icon: Icons.public, color: Colors.lightBlue.shade200, theme: theme, themeType: themeType, isFeatured: true, onTap: () { Navigator.push(context, MaterialPageRoute(builder: (_) => const LobbyScreen())); }), themeType),
const SizedBox(height: 12), SizedBox(height: 12 * vScale),
_buildCyberCard(FeatureCard(title: loc.cpuTitle, subtitle: loc.cpuSub, icon: Icons.smart_toy, color: Colors.purple.shade200, theme: theme, themeType: themeType, onTap: () => _showMatchSetupDialog(true)), themeType), _buildCyberCard(FeatureCard(title: loc.cpuTitle, subtitle: loc.cpuSub, icon: Icons.smart_toy, color: Colors.purple.shade200, theme: theme, themeType: themeType, onTap: () => _showMatchSetupDialog(true)), themeType),
const SizedBox(height: 12), SizedBox(height: 12 * vScale),
_buildCyberCard(FeatureCard(title: loc.localTitle, subtitle: loc.localSub, icon: Icons.people_alt, color: Colors.red.shade200, theme: theme, themeType: themeType, onTap: () => _showMatchSetupDialog(false)), themeType), _buildCyberCard(FeatureCard(title: loc.localTitle, subtitle: loc.localSub, icon: Icons.people_alt, color: Colors.red.shade200, theme: theme, themeType: themeType, onTap: () => _showMatchSetupDialog(false)), themeType),
const SizedBox(height: 12), SizedBox(height: 12 * vScale),
Row( Row(
children: [ children: [
@ -957,7 +975,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
], ],
), ),
const SizedBox(height: 12), SizedBox(height: 12 * vScale),
Row( Row(
children: [ children: [
@ -969,7 +987,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
], ],
), ),
], ],
const SizedBox(height: 40), // Margine in fondo per assicurare che ci sia respiro SizedBox(height: 40 * vScale),
], ],
), ),
), ),
@ -981,31 +999,30 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
return Scaffold( return Scaffold(
backgroundColor: bgImage != null ? Colors.transparent : theme.background, backgroundColor: bgImage != null ? Colors.transparent : theme.background,
extendBodyBehindAppBar: true, // Rimosso l'AppBar vuoto che "spingeva" giù il SafeArea! extendBodyBehindAppBar: true,
body: Stack( body: Stack(
children: [ children: [
// 1. Sfondo base a tinta unita
Container(color: themeType == AppThemeType.doodle ? Colors.white : theme.background), Container(color: themeType == AppThemeType.doodle ? Colors.white : theme.background),
// 2. Immagine di Sfondo per tutti i temi che la supportano
if (bgImage != null) if (bgImage != null)
Positioned.fill( Positioned.fill(
child: Image.asset( child: Container(
bgImage, decoration: BoxDecoration(
fit: BoxFit.cover, image: DecorationImage(
alignment: Alignment.center, image: AssetImage(bgImage!),
fit: BoxFit.cover,
colorFilter: themeType == AppThemeType.doodle
? ColorFilter.mode(Colors.white.withOpacity(0.5), BlendMode.lighten)
: null,
),
),
), ),
), ),
// 3. Griglia a righe incrociate per il doodle
if (themeType == AppThemeType.doodle) if (themeType == AppThemeType.doodle)
Positioned.fill( Positioned.fill(
child: CustomPaint( child: CustomPaint(
painter: FullScreenGridPainter(Colors.blue.withOpacity(0.15)), painter: FullScreenGridPainter(Colors.blue.withOpacity(0.15)),
), ),
), ),
// 4. Patina scura (Cyberpunk, Music, Arcade e Grimorio)
if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music || themeType == AppThemeType.arcade || themeType == AppThemeType.grimorio)) if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music || themeType == AppThemeType.arcade || themeType == AppThemeType.grimorio))
Positioned.fill( Positioned.fill(
child: Container( child: Container(
@ -1017,8 +1034,6 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
), ),
), ),
), ),
// 5. Cavi musicali (Tema Musica)
if (themeType == AppThemeType.music) if (themeType == AppThemeType.music)
Positioned.fill( Positioned.fill(
child: IgnorePointer( child: IgnorePointer(
@ -1027,8 +1042,6 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
), ),
), ),
), ),
// 6. UI
Positioned.fill(child: uiContent), Positioned.fill(child: uiContent),
], ],
), ),

View file

@ -631,31 +631,50 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
body: Stack( body: Stack(
children: [ children: [
Container(color: themeType == AppThemeType.doodle ? Colors.white : theme.background), Container(color: themeType == AppThemeType.doodle ? Colors.white : theme.background),
if (bgImage != null)
Positioned.fill(
child: Image.asset(
bgImage,
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music || themeType == AppThemeType.arcade || themeType == AppThemeType.grimorio))
Positioned.fill(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter, end: Alignment.bottomCenter,
colors: [Colors.black.withOpacity(0.6), Colors.black.withOpacity(0.9)]
)
),
),
),
if (themeType == AppThemeType.doodle) if (themeType == AppThemeType.doodle)
Positioned.fill( Positioned.fill(
child: CustomPaint( child: CustomPaint(
painter: FullScreenGridPainter(Colors.blue.withOpacity(0.15)), painter: FullScreenGridPainter(Colors.blue.withOpacity(0.15)),
), ),
), ),
if (bgImage != null)
Positioned.fill(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(bgImage!),
fit: BoxFit.cover,
colorFilter: themeType == AppThemeType.doodle
? ColorFilter.mode(Colors.white.withOpacity(0.5), BlendMode.lighten)
: null,
),
),
),
),
if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music || themeType == AppThemeType.arcade || themeType == AppThemeType.grimorio))
Positioned.fill(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter, end: Alignment.bottomCenter,
colors: [Colors.black.withOpacity(0.4), Colors.black.withOpacity(0.8)]
)
),
),
),
if (themeType == AppThemeType.music)
Positioned.fill(
child: IgnorePointer(
child: CustomPaint(
painter: AudioCablesPainter(),
),
),
),
Positioned.fill(child: uiContent), Positioned.fill(child: uiContent),
], ],
), ),

View file

@ -16,53 +16,101 @@ class MusicCassetteCard extends StatelessWidget {
final VoidCallback onTap; final VoidCallback onTap;
final AppThemeType themeType; final AppThemeType themeType;
const MusicCassetteCard({super.key, required this.title, required this.subtitle, required this.neonColor, required this.angle, required this.leftIcon, required this.rightIcon, required this.onTap, required this.themeType}); const MusicCassetteCard({
super.key,
required this.title,
required this.subtitle,
required this.neonColor,
required this.angle,
required this.leftIcon,
required this.rightIcon,
required this.onTap,
required this.themeType
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Calcoliamo la scala in base all'altezza dello schermo per strizzare la cassetta
final double screenHeight = MediaQuery.of(context).size.height;
final double vScale = (screenHeight / 850.0).clamp(0.65, 1.0);
return Transform.rotate( return Transform.rotate(
angle: angle, angle: angle,
child: GestureDetector( child: GestureDetector(
onTap: onTap, onTap: onTap,
child: Container( child: Container(
// Aumentato leggermente l'altezza a 125 per evitare l'overflow height: 125 * vScale, // Altezza dinamica!
height: 125, margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 10), padding: const EdgeInsets.all(12), margin: EdgeInsets.symmetric(vertical: 8 * vScale, horizontal: 10),
padding: EdgeInsets.all(12 * vScale),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFF22222A), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.black87, width: 2), color: const Color(0xFF22222A),
boxShadow: [ BoxShadow(color: neonColor.withOpacity(0.5), blurRadius: 25, spreadRadius: 2), const BoxShadow(color: Colors.black54, offset: Offset(5, 10), blurRadius: 15) ] borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.black87, width: 2),
boxShadow: [
BoxShadow(color: neonColor.withOpacity(0.5), blurRadius: 25, spreadRadius: 2),
const BoxShadow(color: Colors.black54, offset: Offset(5, 10), blurRadius: 15)
]
), ),
child: Column( child: Column(
children: [ children: [
Expanded( Expanded(
child: Container( child: Container(
decoration: BoxDecoration(color: neonColor.withOpacity(0.15), borderRadius: BorderRadius.circular(4), border: Border.all(color: neonColor.withOpacity(0.5), width: 1.5)), decoration: BoxDecoration(
color: neonColor.withOpacity(0.15),
borderRadius: BorderRadius.circular(4),
border: Border.all(color: neonColor.withOpacity(0.5), width: 1.5)
),
child: Row( child: Row(
children: [ children: [
Padding(padding: const EdgeInsets.symmetric(horizontal: 12), child: Icon(leftIcon, color: neonColor, size: 28)), Padding(
padding: EdgeInsets.symmetric(horizontal: 12 * vScale),
child: Icon(leftIcon, color: neonColor, size: 28 * vScale)
),
Expanded( Expanded(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
// Aggiunto minAxisSize per far stare il contenuto stretto
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Flexible(child: FittedBox(fit: BoxFit.scaleDown, child: Text(title, style: getSharedTextStyle(themeType, TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.w900, shadows: [Shadow(color: neonColor, blurRadius: 10)]))))), Flexible(
Flexible(child: FittedBox(fit: BoxFit.scaleDown, child: Text(subtitle, style: getSharedTextStyle(themeType, const TextStyle(color: Colors.white70, fontSize: 11, fontWeight: FontWeight.bold))))), child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(title, style: getSharedTextStyle(themeType, TextStyle(color: Colors.white, fontSize: 20 * vScale, fontWeight: FontWeight.w900, shadows: [Shadow(color: neonColor, blurRadius: 10)])))
)
),
Flexible(
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(subtitle, style: getSharedTextStyle(themeType, TextStyle(color: Colors.white70, fontSize: 11 * vScale, fontWeight: FontWeight.bold)))
)
),
], ],
), ),
), ),
Padding(padding: const EdgeInsets.symmetric(horizontal: 12), child: Icon(rightIcon, color: neonColor, size: 28)), Padding(
padding: EdgeInsets.symmetric(horizontal: 12 * vScale),
child: Icon(rightIcon, color: neonColor, size: 28 * vScale)
),
], ],
), ),
), ),
), ),
const SizedBox(height: 10), SizedBox(height: 10 * vScale),
Container( Container(
height: 35, width: 180, decoration: BoxDecoration(color: const Color(0xFF0D0D12), borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.white24, width: 1)), height: 35 * vScale,
width: 180 * vScale,
decoration: BoxDecoration(
color: const Color(0xFF0D0D12),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.white24, width: 1)
),
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
Container(height: 2, width: 120, color: const Color(0xFF333333)), Container(height: 2, width: 120 * vScale, color: const Color(0xFF333333)),
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildSpool(), _buildSpool() ]), Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ _buildSpool(vScale), _buildSpool(vScale) ]
),
], ],
), ),
), ),
@ -73,10 +121,22 @@ class MusicCassetteCard extends StatelessWidget {
); );
} }
Widget _buildSpool() { Widget _buildSpool(double vScale) {
return Container( return Container(
width: 26, height: 26, decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.white70, border: Border.all(color: Colors.black87, width: 5)), width: 26 * vScale,
child: Center(child: Container(width: 6, height: 6, decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.black))), height: 26 * vScale,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white70,
border: Border.all(color: Colors.black87, width: 5 * vScale)
),
child: Center(
child: Container(
width: 6 * vScale,
height: 6 * vScale,
decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.black)
)
),
); );
} }
} }
@ -88,40 +148,61 @@ class MusicKnobCard extends StatelessWidget {
final AppThemeType themeType; final AppThemeType themeType;
final Color? iconColor; final Color? iconColor;
const MusicKnobCard({super.key, required this.title, required this.icon, required this.onTap, required this.themeType, this.iconColor}); const MusicKnobCard({
super.key,
required this.title,
required this.icon,
required this.onTap,
required this.themeType,
this.iconColor
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Adattiamo anche le manopole in base all'altezza dello schermo
final double screenHeight = MediaQuery.of(context).size.height;
final double vScale = (screenHeight / 850.0).clamp(0.65, 1.0);
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: onTap,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Container( Container(
width: 65, height: 65, width: 65 * vScale,
height: 65 * vScale,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, color: const Color(0xFF222222), border: Border.all(color: const Color(0xFF111111), width: 2), shape: BoxShape.circle,
boxShadow: const [BoxShadow(color: Colors.black87, blurRadius: 10, offset: Offset(2, 6)), BoxShadow(color: Colors.white12, blurRadius: 2, offset: Offset(-1, -1))], color: const Color(0xFF222222),
border: Border.all(color: const Color(0xFF111111), width: 2),
boxShadow: const [
BoxShadow(color: Colors.black87, blurRadius: 10, offset: Offset(2, 6)),
BoxShadow(color: Colors.white12, blurRadius: 2, offset: Offset(-1, -1))
],
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(6.0), padding: EdgeInsets.all(6.0 * vScale),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, border: Border.all(color: Colors.black54, width: 1), shape: BoxShape.circle,
border: Border.all(color: Colors.black54, width: 1),
gradient: const SweepGradient(colors: [Color(0xFF555555), Color(0xFFAAAAAA), Color(0xFF555555), Color(0xFF222222), Color(0xFF555555)]), gradient: const SweepGradient(colors: [Color(0xFF555555), Color(0xFFAAAAAA), Color(0xFF555555), Color(0xFF222222), Color(0xFF555555)]),
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(4.0), padding: EdgeInsets.all(4.0 * vScale),
child: Container( child: Container(
decoration: const BoxDecoration(shape: BoxShape.circle, color: Color(0xFF1A1A1A)), decoration: const BoxDecoration(shape: BoxShape.circle, color: Color(0xFF1A1A1A)),
child: Center(child: Icon(icon, color: iconColor ?? Colors.white70, size: 20)), child: Center(child: Icon(icon, color: iconColor ?? Colors.white70, size: 20 * vScale)),
), ),
), ),
), ),
), ),
), ),
const SizedBox(height: 10), SizedBox(height: 10 * vScale),
FittedBox(fit: BoxFit.scaleDown, child: Text(title, style: getSharedTextStyle(themeType, const TextStyle(color: Colors.white70, fontSize: 11, fontWeight: FontWeight.bold, letterSpacing: 1.0)))), FittedBox(
fit: BoxFit.scaleDown,
child: Text(title, style: getSharedTextStyle(themeType, TextStyle(color: Colors.white70, fontSize: 11 * vScale, fontWeight: FontWeight.bold, letterSpacing: 1.0)))
),
], ],
), ),
); );

View file

@ -8,6 +8,7 @@ import Foundation
import app_links import app_links
import audioplayers_darwin import audioplayers_darwin
import cloud_firestore import cloud_firestore
import device_info_plus
import firebase_app_check import firebase_app_check
import firebase_auth import firebase_auth
import firebase_core import firebase_core
@ -19,6 +20,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FLTFirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAppCheckPlugin")) FLTFirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAppCheckPlugin"))
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))

View file

@ -1207,6 +1207,8 @@ PODS:
- Firebase/Firestore (~> 12.9.0) - Firebase/Firestore (~> 12.9.0)
- firebase_core - firebase_core
- FlutterMacOS - FlutterMacOS
- device_info_plus (0.0.1):
- FlutterMacOS
- Firebase/AppCheck (12.9.0): - Firebase/AppCheck (12.9.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseAppCheck (~> 12.9.0) - FirebaseAppCheck (~> 12.9.0)
@ -1414,6 +1416,7 @@ DEPENDENCIES:
- app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`)
- audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`) - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`)
- cloud_firestore (from `Flutter/ephemeral/.symlinks/plugins/cloud_firestore/macos`) - cloud_firestore (from `Flutter/ephemeral/.symlinks/plugins/cloud_firestore/macos`)
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
- firebase_app_check (from `Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos`) - firebase_app_check (from `Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos`)
- firebase_auth (from `Flutter/ephemeral/.symlinks/plugins/firebase_auth/macos`) - firebase_auth (from `Flutter/ephemeral/.symlinks/plugins/firebase_auth/macos`)
- firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`) - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`)
@ -1453,6 +1456,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos :path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos
cloud_firestore: cloud_firestore:
:path: Flutter/ephemeral/.symlinks/plugins/cloud_firestore/macos :path: Flutter/ephemeral/.symlinks/plugins/cloud_firestore/macos
device_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
firebase_app_check: firebase_app_check:
:path: Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos :path: Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos
firebase_auth: firebase_auth:
@ -1475,6 +1480,7 @@ SPEC CHECKSUMS:
audioplayers_darwin: 761f2948df701d05b5db603220c384fb55720012 audioplayers_darwin: 761f2948df701d05b5db603220c384fb55720012
BoringSSL-GRPC: dded2a44897e45f28f08ae87a55ee4bcd19bc508 BoringSSL-GRPC: dded2a44897e45f28f08ae87a55ee4bcd19bc508
cloud_firestore: a2a9382e6cc4dd07345748b904b3b194ea46be44 cloud_firestore: a2a9382e6cc4dd07345748b904b3b194ea46be44
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76
Firebase: 065f2bb395062046623036d8e6dc857bc2521d56 Firebase: 065f2bb395062046623036d8e6dc857bc2521d56
firebase_app_check: 1ea404b52b0910bf632b1ea2e00ceb8d1730cb44 firebase_app_check: 1ea404b52b0910bf632b1ea2e00ceb8d1730cb44
firebase_auth: 8db6796451d9aa44d4cc49b3e757865c65ce170f firebase_auth: 8db6796451d9aa44d4cc49b3e757865c65ce170f

View file

@ -1,89 +1,38 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="it">
<head> <head>
<meta charset="utf-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to Firebase Hosting</title>
<!-- update the version number as needed --> <title>Gioca a TetraQ!</title>
<script defer src="/__/firebase/12.10.0/firebase-app-compat.js"></script> <meta property="og:title" content="Gioca a TetraQ!">
<!-- include only the Firebase features as you need --> <meta property="og:description" content="Sfida i tuoi amici nell'arena al neon. Unisciti alla partita!">
<script defer src="/__/firebase/12.10.0/firebase-auth-compat.js"></script>
<script defer src="/__/firebase/12.10.0/firebase-database-compat.js"></script>
<script defer src="/__/firebase/12.10.0/firebase-firestore-compat.js"></script>
<script defer src="/__/firebase/12.10.0/firebase-functions-compat.js"></script>
<script defer src="/__/firebase/12.10.0/firebase-messaging-compat.js"></script>
<script defer src="/__/firebase/12.10.0/firebase-storage-compat.js"></script>
<script defer src="/__/firebase/12.10.0/firebase-analytics-compat.js"></script>
<script defer src="/__/firebase/12.10.0/firebase-remote-config-compat.js"></script>
<script defer src="/__/firebase/12.10.0/firebase-performance-compat.js"></script>
<!--
initialize the SDK after all desired features are loaded, set useEmulator to false
to avoid connecting the SDK to running emulators.
-->
<script defer src="/__/firebase/init.js?useEmulator=true"></script>
<style media="screen"> <meta property="og:image" content="https://upload.wikimedia.org/wikipedia/commons/c/ca/1x1.png">
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px; border-radius: 3px; }
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
@media (max-width: 600px) {
body, #message { margin-top: 0; background: white; box-shadow: none; }
body { border-top: 16px solid #ffa100; }
}
</style>
</head>
<body>
<div id="message">
<h2>Welcome</h2>
<h1>Firebase Hosting Setup Complete</h1>
<p>You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!</p>
<a target="_blank" href="https://firebase.google.com/docs/hosting/">Open Hosting Documentation</a>
</div>
<p id="load">Firebase SDK Loading&hellip;</p>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { function redirect() {
const loadEl = document.querySelector('#load'); var userAgent = navigator.userAgent || navigator.vendor || window.opera;
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
// // The Firebase SDK is initialized and available here!
//
// firebase.auth().onAuthStateChanged(user => { });
// firebase.database().ref('/path/to/ref').on('value', snapshot => { });
// firebase.firestore().doc('/foo/bar').get().then(() => { });
// firebase.functions().httpsCallable('yourFunction')().then(() => { });
// firebase.messaging().requestPermission().then(() => { });
// firebase.storage().ref('/path/to/ref').getDownloadURL().then(() => { });
// firebase.analytics(); // call to activate
// firebase.analytics().logEvent('tutorial_completed');
// firebase.performance(); // call to activate
//
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
try { // Se è iOS
let app = firebase.app(); if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
let features = [ window.location.href = "https://apps.apple.com/it/app/tetraq/id6759522394";
'auth', return;
'database',
'firestore',
'functions',
'messaging',
'storage',
'analytics',
'remoteConfig',
'performance',
].filter(feature => typeof app[feature] === 'function');
loadEl.textContent = `Firebase SDK loaded with ${features.join(', ')}`;
} catch (e) {
console.error(e);
loadEl.textContent = 'Error loading the Firebase SDK, check the console.';
} }
}); // Se è Android
</script> if (/android/i.test(userAgent)) {
</body> window.location.href = "https://play.google.com/store/apps/details?id=com.amastra.tetraq";
</html> return;
}
// Se è da PC (o non riconosciuto), lo mandiamo alla tua pagina Google Sites
window.location.href = "https://sites.google.com/view/tetraq/home-page";
}
</script>
</head>
<body onload="redirect()" style="background-color: #0A001A; color: white;">
<h3 style="text-align: center; font-family: sans-serif; margin-top: 50px;">
Apertura in corso... 🚀
</h3>
</body>
</html>

View file

@ -233,6 +233,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.8" version: "1.0.8"
device_info_plus:
dependency: "direct main"
description:
name: device_info_plus
sha256: "4df8babf73058181227e18b08e6ea3520cf5fc5d796888d33b7cb0f33f984b7c"
url: "https://pub.dev"
source: hosted
version: "12.3.0"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
url: "https://pub.dev"
source: hosted
version: "7.0.3"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -890,6 +906,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.15.0" version: "5.15.0"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View file

@ -26,6 +26,7 @@ dependencies:
font_awesome_flutter: ^10.12.0 font_awesome_flutter: ^10.12.0
firebase_app_check: ^0.4.1+5 firebase_app_check: ^0.4.1+5
package_info_plus: ^9.0.0 package_info_plus: ^9.0.0
device_info_plus: ^12.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: