Auto-sync: 20260315_160000
This commit is contained in:
parent
14c01e984c
commit
8caecd401e
12 changed files with 336 additions and 216 deletions
|
|
@ -1,2 +1,2 @@
|
||||||
index.html,1773344753424,0d5d4b835a7d632ad11d249230a15561286f2bfcd1da8305c6fb294d37e5da09
|
|
||||||
404.html,1773344753356,05cbc6f94d7a69ce2e29646eab13be2c884e61ba93e3094df5028866876d18b3
|
404.html,1773344753356,05cbc6f94d7a69ce2e29646eab13be2c884e61ba93e3094df5028866876d18b3
|
||||||
|
index.html,1773586765860,5737ce966fa8786becaf7f36a32992cf44102fb3a217c226c30576c993b33e63
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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,23 +151,37 @@ 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(
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("Registrato il:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10)),
|
FittedBox(fit: BoxFit.scaleDown, child: Text("Registrato il:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10))),
|
||||||
Text(createdStr, style: TextStyle(color: theme.text, fontSize: 12, fontWeight: FontWeight.bold)),
|
FittedBox(fit: BoxFit.scaleDown, child: Text(createdStr, style: TextStyle(color: theme.text, fontSize: 12, fontWeight: FontWeight.bold))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Column(
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
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,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text("Ultimo Accesso:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10)),
|
FittedBox(fit: BoxFit.scaleDown, child: Text("Ultimo Accesso:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10))),
|
||||||
Text(lastActiveStr, style: TextStyle(color: Colors.green, fontSize: 12, fontWeight: FontWeight.bold)),
|
FittedBox(fit: BoxFit.scaleDown, child: Text(lastActiveStr, style: TextStyle(color: Colors.green, fontSize: 12, fontWeight: FontWeight.bold))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage(bgImage!),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
alignment: Alignment.center,
|
colorFilter: themeType == AppThemeType.doodle
|
||||||
color: themeType == AppThemeType.doodle ? Colors.white.withOpacity(0.5) : null,
|
? ColorFilter.mode(Colors.white.withOpacity(0.5), BlendMode.lighten)
|
||||||
colorBlendMode: themeType == AppThemeType.doodle ? BlendMode.lighten : null,
|
: 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)); }
|
||||||
|
|
|
||||||
|
|
@ -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,12 +897,13 @@ 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: () {
|
||||||
|
if (playerName.toUpperCase() == 'PAOLO') {
|
||||||
_debugTapCount++;
|
_debugTapCount++;
|
||||||
if (_debugTapCount == 5) {
|
if (_debugTapCount == 5) {
|
||||||
StorageService.instance.addXP(2000);
|
StorageService.instance.addXP(2000);
|
||||||
|
|
@ -900,35 +915,38 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
_debugTapCount = 0;
|
_debugTapCount = 0;
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
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(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage(bgImage!),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
alignment: Alignment.center,
|
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),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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)))
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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"))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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…</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',
|
// Se è Android
|
||||||
'functions',
|
if (/android/i.test(userAgent)) {
|
||||||
'messaging',
|
window.location.href = "https://play.google.com/store/apps/details?id=com.amastra.tetraq";
|
||||||
'storage',
|
return;
|
||||||
'analytics',
|
}
|
||||||
'remoteConfig',
|
|
||||||
'performance',
|
// Se è da PC (o non riconosciuto), lo mandiamo alla tua pagina Google Sites
|
||||||
].filter(feature => typeof app[feature] === 'function');
|
window.location.href = "https://sites.google.com/view/tetraq/home-page";
|
||||||
loadEl.textContent = `Firebase SDK loaded with ${features.join(', ')}`;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
loadEl.textContent = 'Error loading the Firebase SDK, check the console.';
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</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>
|
</html>
|
||||||
24
pubspec.lock
24
pubspec.lock
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue