Auto-sync: 20260321_000000
This commit is contained in:
parent
209027b221
commit
5b99d5f0bb
18 changed files with 619 additions and 133 deletions
BIN
.DS_Store
vendored
BIN
.DS_Store
vendored
Binary file not shown.
|
|
@ -5,8 +5,8 @@
|
||||||
<application
|
<application
|
||||||
android:label="tetraq"
|
android:label="tetraq"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher"
|
||||||
<activity
|
android:usesCleartextTraffic="true"> <activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
|
|
|
||||||
|
|
@ -58,5 +58,11 @@
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
@ -19,5 +19,18 @@
|
||||||
"joinMatch": "JOIN",
|
"joinMatch": "JOIN",
|
||||||
"gameOver": "GAME OVER",
|
"gameOver": "GAME OVER",
|
||||||
"mainMenu": "BACK TO MENU",
|
"mainMenu": "BACK TO MENU",
|
||||||
"exit": "EXIT"
|
"exit": "EXIT",
|
||||||
|
"roomSettings": "ROOM SETTINGS",
|
||||||
|
"arenaShape": "ARENA SHAPE",
|
||||||
|
"arenaSize": "SIZE",
|
||||||
|
"timeAndOptions": "TIME & OPTIONS",
|
||||||
|
"timeLabel": "TIME",
|
||||||
|
"btnStart": "START",
|
||||||
|
"btnCancel": "CANCEL",
|
||||||
|
"wordOr": "OR",
|
||||||
|
"codeHint": "CODE",
|
||||||
|
"publicLobbyTitle": "PUBLIC LOBBY",
|
||||||
|
"emptyLobbyMsg": "No public rooms right now.\nCreate one!",
|
||||||
|
"roomOf": "Room of",
|
||||||
|
"btnEnter": "ENTER"
|
||||||
}
|
}
|
||||||
|
|
@ -19,5 +19,18 @@
|
||||||
"joinMatch": "UNISCITI",
|
"joinMatch": "UNISCITI",
|
||||||
"gameOver": "FINE PARTITA",
|
"gameOver": "FINE PARTITA",
|
||||||
"mainMenu": "TORNA AL MENU",
|
"mainMenu": "TORNA AL MENU",
|
||||||
"exit": "ESCI"
|
"exit": "ESCI",
|
||||||
|
"roomSettings": "IMPOSTAZIONI STANZA",
|
||||||
|
"arenaShape": "FORMA ARENA",
|
||||||
|
"arenaSize": "GRANDEZZA",
|
||||||
|
"timeAndOptions": "TEMPO E OPZIONI",
|
||||||
|
"timeLabel": "TEMPO",
|
||||||
|
"btnStart": "AVVIA",
|
||||||
|
"btnCancel": "ANNULLA",
|
||||||
|
"wordOr": "OPPURE",
|
||||||
|
"codeHint": "CODICE",
|
||||||
|
"publicLobbyTitle": "LOBBY PUBBLICA",
|
||||||
|
"emptyLobbyMsg": "Nessuna stanza pubblica al momento.\nCreane una tu!",
|
||||||
|
"roomOf": "Stanza di",
|
||||||
|
"btnEnter": "ENTRA"
|
||||||
}
|
}
|
||||||
|
|
@ -229,6 +229,84 @@ abstract class AppLocalizations {
|
||||||
/// In it, this message translates to:
|
/// In it, this message translates to:
|
||||||
/// **'ESCI'**
|
/// **'ESCI'**
|
||||||
String get exit;
|
String get exit;
|
||||||
|
|
||||||
|
/// No description provided for @roomSettings.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'IMPOSTAZIONI STANZA'**
|
||||||
|
String get roomSettings;
|
||||||
|
|
||||||
|
/// No description provided for @arenaShape.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'FORMA ARENA'**
|
||||||
|
String get arenaShape;
|
||||||
|
|
||||||
|
/// No description provided for @arenaSize.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'GRANDEZZA'**
|
||||||
|
String get arenaSize;
|
||||||
|
|
||||||
|
/// No description provided for @timeAndOptions.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'TEMPO E OPZIONI'**
|
||||||
|
String get timeAndOptions;
|
||||||
|
|
||||||
|
/// No description provided for @timeLabel.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'TEMPO'**
|
||||||
|
String get timeLabel;
|
||||||
|
|
||||||
|
/// No description provided for @btnStart.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'AVVIA'**
|
||||||
|
String get btnStart;
|
||||||
|
|
||||||
|
/// No description provided for @btnCancel.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'ANNULLA'**
|
||||||
|
String get btnCancel;
|
||||||
|
|
||||||
|
/// No description provided for @wordOr.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'OPPURE'**
|
||||||
|
String get wordOr;
|
||||||
|
|
||||||
|
/// No description provided for @codeHint.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'CODICE'**
|
||||||
|
String get codeHint;
|
||||||
|
|
||||||
|
/// No description provided for @publicLobbyTitle.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'LOBBY PUBBLICA'**
|
||||||
|
String get publicLobbyTitle;
|
||||||
|
|
||||||
|
/// No description provided for @emptyLobbyMsg.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'Nessuna stanza pubblica al momento.\nCreane una tu!'**
|
||||||
|
String get emptyLobbyMsg;
|
||||||
|
|
||||||
|
/// No description provided for @roomOf.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'Stanza di'**
|
||||||
|
String get roomOf;
|
||||||
|
|
||||||
|
/// No description provided for @btnEnter.
|
||||||
|
///
|
||||||
|
/// In it, this message translates to:
|
||||||
|
/// **'ENTRA'**
|
||||||
|
String get btnEnter;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,44 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get exit => 'BEENDEN';
|
String get exit => 'BEENDEN';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomSettings => 'IMPOSTAZIONI STANZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaShape => 'FORMA ARENA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaSize => 'GRANDEZZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeAndOptions => 'TEMPO E OPZIONI';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeLabel => 'TEMPO';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnStart => 'AVVIA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnCancel => 'ANNULLA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wordOr => 'OPPURE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codeHint => 'CODICE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publicLobbyTitle => 'LOBBY PUBBLICA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyLobbyMsg =>
|
||||||
|
'Nessuna stanza pubblica al momento.\nCreane una tu!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomOf => 'Stanza di';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnEnter => 'ENTRA';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,43 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get exit => 'EXIT';
|
String get exit => 'EXIT';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomSettings => 'ROOM SETTINGS';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaShape => 'ARENA SHAPE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaSize => 'SIZE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeAndOptions => 'TIME & OPTIONS';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeLabel => 'TIME';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnStart => 'START';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnCancel => 'CANCEL';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wordOr => 'OR';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codeHint => 'CODE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publicLobbyTitle => 'PUBLIC LOBBY';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyLobbyMsg => 'No public rooms right now.\nCreate one!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomOf => 'Room of';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnEnter => 'ENTER';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,44 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get exit => 'SALIR';
|
String get exit => 'SALIR';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomSettings => 'IMPOSTAZIONI STANZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaShape => 'FORMA ARENA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaSize => 'GRANDEZZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeAndOptions => 'TEMPO E OPZIONI';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeLabel => 'TEMPO';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnStart => 'AVVIA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnCancel => 'ANNULLA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wordOr => 'OPPURE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codeHint => 'CODICE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publicLobbyTitle => 'LOBBY PUBBLICA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyLobbyMsg =>
|
||||||
|
'Nessuna stanza pubblica al momento.\nCreane una tu!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomOf => 'Stanza di';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnEnter => 'ENTRA';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,44 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get exit => 'QUITTER';
|
String get exit => 'QUITTER';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomSettings => 'IMPOSTAZIONI STANZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaShape => 'FORMA ARENA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaSize => 'GRANDEZZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeAndOptions => 'TEMPO E OPZIONI';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeLabel => 'TEMPO';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnStart => 'AVVIA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnCancel => 'ANNULLA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wordOr => 'OPPURE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codeHint => 'CODICE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publicLobbyTitle => 'LOBBY PUBBLICA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyLobbyMsg =>
|
||||||
|
'Nessuna stanza pubblica al momento.\nCreane una tu!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomOf => 'Stanza di';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnEnter => 'ENTRA';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,44 @@ class AppLocalizationsIt extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get exit => 'ESCI';
|
String get exit => 'ESCI';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomSettings => 'IMPOSTAZIONI STANZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaShape => 'FORMA ARENA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaSize => 'GRANDEZZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeAndOptions => 'TEMPO E OPZIONI';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeLabel => 'TEMPO';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnStart => 'AVVIA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnCancel => 'ANNULLA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wordOr => 'OPPURE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codeHint => 'CODICE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publicLobbyTitle => 'LOBBY PUBBLICA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyLobbyMsg =>
|
||||||
|
'Nessuna stanza pubblica al momento.\nCreane una tu!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomOf => 'Stanza di';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnEnter => 'ENTRA';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,44 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get exit => 'SAIR';
|
String get exit => 'SAIR';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomSettings => 'IMPOSTAZIONI STANZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaShape => 'FORMA ARENA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaSize => 'GRANDEZZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeAndOptions => 'TEMPO E OPZIONI';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeLabel => 'TEMPO';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnStart => 'AVVIA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnCancel => 'ANNULLA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wordOr => 'OPPURE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codeHint => 'CODICE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publicLobbyTitle => 'LOBBY PUBBLICA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyLobbyMsg =>
|
||||||
|
'Nessuna stanza pubblica al momento.\nCreane una tu!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomOf => 'Stanza di';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnEnter => 'ENTRA';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,44 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get exit => 'ВЫХОД';
|
String get exit => 'ВЫХОД';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomSettings => 'IMPOSTAZIONI STANZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaShape => 'FORMA ARENA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaSize => 'GRANDEZZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeAndOptions => 'TEMPO E OPZIONI';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeLabel => 'TEMPO';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnStart => 'AVVIA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnCancel => 'ANNULLA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wordOr => 'OPPURE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codeHint => 'CODICE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publicLobbyTitle => 'LOBBY PUBBLICA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyLobbyMsg =>
|
||||||
|
'Nessuna stanza pubblica al momento.\nCreane una tu!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomOf => 'Stanza di';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnEnter => 'ENTRA';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,44 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get exit => '退出';
|
String get exit => '退出';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomSettings => 'IMPOSTAZIONI STANZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaShape => 'FORMA ARENA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get arenaSize => 'GRANDEZZA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeAndOptions => 'TEMPO E OPZIONI';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get timeLabel => 'TEMPO';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnStart => 'AVVIA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnCancel => 'ANNULLA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wordOr => 'OPPURE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codeHint => 'CODICE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publicLobbyTitle => 'LOBBY PUBBLICA';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyLobbyMsg =>
|
||||||
|
'Nessuna stanza pubblica al momento.\nCreane una tu!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomOf => 'Stanza di';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get btnEnter => 'ENTRA';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,21 +64,48 @@ class StorageService {
|
||||||
|
|
||||||
int get totalXP => _prefs.getInt('totalXP') ?? 0;
|
int get totalXP => _prefs.getInt('totalXP') ?? 0;
|
||||||
|
|
||||||
|
// --- SICUREZZA XP: Inviamo solo INCREMENTI al server ---
|
||||||
Future<void> addXP(int xp) async {
|
Future<void> addXP(int xp) async {
|
||||||
|
// Aggiorniamo il locale per la UI
|
||||||
await _prefs.setInt('totalXP', totalXP + xp);
|
await _prefs.setInt('totalXP', totalXP + xp);
|
||||||
syncLeaderboard();
|
|
||||||
|
// Aggiorniamo il server in modo sicuro tramite incremento relativo
|
||||||
|
final user = FirebaseAuth.instance.currentUser;
|
||||||
|
if (user != null) {
|
||||||
|
await FirebaseFirestore.instance.collection('leaderboard').doc(user.uid).set({
|
||||||
|
'xp': FieldValue.increment(xp),
|
||||||
|
'level': playerLevel,
|
||||||
|
}, SetOptions(merge: true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int get playerLevel => (totalXP / 100).floor() + 1;
|
int get playerLevel => (totalXP / 100).floor() + 1;
|
||||||
|
|
||||||
int get wins => _prefs.getInt('wins') ?? 0;
|
int get wins => _prefs.getInt('wins') ?? 0;
|
||||||
|
|
||||||
|
// --- SICUREZZA WINS: Inviamo solo INCREMENTI al server ---
|
||||||
Future<void> addWin() async {
|
Future<void> addWin() async {
|
||||||
await _prefs.setInt('wins', wins + 1);
|
await _prefs.setInt('wins', wins + 1);
|
||||||
syncLeaderboard();
|
final user = FirebaseAuth.instance.currentUser;
|
||||||
|
if (user != null) {
|
||||||
|
await FirebaseFirestore.instance.collection('leaderboard').doc(user.uid).set({
|
||||||
|
'wins': FieldValue.increment(1),
|
||||||
|
}, SetOptions(merge: true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int get losses => _prefs.getInt('losses') ?? 0;
|
int get losses => _prefs.getInt('losses') ?? 0;
|
||||||
Future<void> addLoss() async => await _prefs.setInt('losses', losses + 1);
|
|
||||||
|
// --- SICUREZZA LOSSES: Inviamo solo INCREMENTI al server ---
|
||||||
|
Future<void> addLoss() async {
|
||||||
|
await _prefs.setInt('losses', losses + 1);
|
||||||
|
final user = FirebaseAuth.instance.currentUser;
|
||||||
|
if (user != null) {
|
||||||
|
await FirebaseFirestore.instance.collection('leaderboard').doc(user.uid).set({
|
||||||
|
'losses': FieldValue.increment(1),
|
||||||
|
}, SetOptions(merge: true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int get cpuLevel => _prefs.getInt('cpuLevel') ?? 1;
|
int get cpuLevel => _prefs.getInt('cpuLevel') ?? 1;
|
||||||
Future<void> saveCpuLevel(int level) async => await _prefs.setInt('cpuLevel', level);
|
Future<void> saveCpuLevel(int level) async => await _prefs.setInt('cpuLevel', level);
|
||||||
|
|
@ -89,30 +116,25 @@ class StorageService {
|
||||||
syncLeaderboard();
|
syncLeaderboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- SINCRONIZZAZIONE LEADERBOARD AGGIORNATA ---
|
|
||||||
Future<void> syncLeaderboard() async {
|
Future<void> syncLeaderboard() async {
|
||||||
try {
|
try {
|
||||||
final user = FirebaseAuth.instance.currentUser;
|
final user = FirebaseAuth.instance.currentUser;
|
||||||
|
|
||||||
// BLOCCO TOTALE: Se non sei loggato, niente database!
|
|
||||||
if (user == null) return;
|
if (user == null) return;
|
||||||
|
|
||||||
String name = playerName;
|
String name = playerName;
|
||||||
if (name.isEmpty) name = "GIOCATORE"; // Fallback di sicurezza
|
if (name.isEmpty) name = "GIOCATORE";
|
||||||
|
|
||||||
String targetUid = user.uid;
|
String targetUid = user.uid;
|
||||||
|
|
||||||
// Prepara i dati base
|
// --- SICUREZZA: Non inviamo PIÙ i valori assoluti di xp, wins e losses! ---
|
||||||
|
// Vengono aggiornati solo dagli incrementi protetti nelle funzioni sopra.
|
||||||
Map<String, dynamic> dataToSave = {
|
Map<String, dynamic> dataToSave = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'xp': totalXP,
|
|
||||||
'level': playerLevel,
|
'level': playerLevel,
|
||||||
'wins': wins,
|
|
||||||
'losses': losses,
|
|
||||||
'lastActive': FieldValue.serverTimestamp(),
|
'lastActive': FieldValue.serverTimestamp(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// IL TRUCCO: Aggiungiamo la data di registrazione estraendola da Firebase Auth!
|
|
||||||
if (user.metadata.creationTime != null) {
|
if (user.metadata.creationTime != null) {
|
||||||
dataToSave['accountCreated'] = Timestamp.fromDate(user.metadata.creationTime!);
|
dataToSave['accountCreated'] = Timestamp.fromDate(user.metadata.creationTime!);
|
||||||
}
|
}
|
||||||
|
|
@ -124,6 +146,19 @@ class StorageService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> isUserAdmin() async {
|
||||||
|
try {
|
||||||
|
final user = FirebaseAuth.instance.currentUser;
|
||||||
|
if (user == null) return false;
|
||||||
|
|
||||||
|
final doc = await FirebaseFirestore.instance.collection('admins').doc(user.uid).get();
|
||||||
|
return doc.exists;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Errore verifica admin: $e");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<Map<String, String>> get favorites {
|
List<Map<String, String>> get favorites {
|
||||||
List<String> favs = _prefs.getStringList('favorites') ?? [];
|
List<String> favs = _prefs.getStringList('favorites') ?? [];
|
||||||
return favs.map((e) => Map<String, String>.from(jsonDecode(e))).toList();
|
return favs.map((e) => Map<String, String>.from(jsonDecode(e))).toList();
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'dart:math';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||||
import 'package:firebase_auth/firebase_auth.dart';
|
import 'package:firebase_auth/firebase_auth.dart';
|
||||||
|
|
@ -64,7 +65,6 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
// MODIFICA QUI: Invece di currentUser == null, controlliamo se il nome è vuoto!
|
|
||||||
if (StorageService.instance.playerName.isEmpty) {
|
if (StorageService.instance.playerName.isEmpty) {
|
||||||
HomeModals.showNameDialog(context, () {
|
HomeModals.showNameDialog(context, () {
|
||||||
StorageService.instance.syncLeaderboard();
|
StorageService.instance.syncLeaderboard();
|
||||||
|
|
@ -81,6 +81,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
_initDeepLinks();
|
_initDeepLinks();
|
||||||
_listenToFavoritesOnline();
|
_listenToFavoritesOnline();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _checkThemeSafety() {
|
void _checkThemeSafety() {
|
||||||
String themeStr = StorageService.instance.getTheme();
|
String themeStr = StorageService.instance.getTheme();
|
||||||
bool exists = AppThemeType.values.any((e) => e.toString() == themeStr);
|
bool exists = AppThemeType.values.any((e) => e.toString() == themeStr);
|
||||||
|
|
@ -104,7 +105,8 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
if (state == AppLifecycleState.resumed) {
|
if (state == AppLifecycleState.resumed) {
|
||||||
_checkClipboardForInvite();
|
_checkClipboardForInvite();
|
||||||
_listenToFavoritesOnline();
|
_listenToFavoritesOnline();
|
||||||
} else if (state == AppLifecycleState.paused || state == AppLifecycleState.detached) {
|
} else if (state == AppLifecycleState.detached) {
|
||||||
|
// --- FIX BUG WHATSAPP: Rimossa l'eliminazione della stanza durante lo stato "paused" ---
|
||||||
_cleanupGhostRoom();
|
_cleanupGhostRoom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +200,6 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
late OverlayEntry entry;
|
late OverlayEntry entry;
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
|
|
||||||
// --- FIX OVERLAP POPUP: Più in basso (85) ---
|
|
||||||
entry = OverlayEntry(
|
entry = OverlayEntry(
|
||||||
builder: (context) => Positioned(
|
builder: (context) => Positioned(
|
||||||
top: MediaQuery.of(context).padding.top + 85,
|
top: MediaQuery.of(context).padding.top + 85,
|
||||||
|
|
@ -577,18 +578,38 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
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: () async {
|
||||||
if (playerName.toUpperCase() == 'PAOLO') {
|
|
||||||
_debugTapCount++;
|
_debugTapCount++;
|
||||||
if (_debugTapCount == 5) {
|
|
||||||
|
// CHEAT LOCALE VIVO SOLO IN DEBUG MODE
|
||||||
|
if (kDebugMode && playerName.toUpperCase() == 'PAOLO' && _debugTapCount == 5) {
|
||||||
StorageService.instance.addXP(2000);
|
StorageService.instance.addXP(2000);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
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)))
|
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) {
|
}
|
||||||
|
// ACCESSO DASHBOARD
|
||||||
|
else if (_debugTapCount >= 7) {
|
||||||
_debugTapCount = 0;
|
_debugTapCount = 0;
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => AdminScreen()));
|
|
||||||
|
if (kDebugMode && playerName.toUpperCase() == 'PAOLO') {
|
||||||
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen()));
|
||||||
|
} else {
|
||||||
|
bool isAdmin = await StorageService.instance.isUserAdmin();
|
||||||
|
|
||||||
|
if (isAdmin && mounted) {
|
||||||
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen()));
|
||||||
|
} else if (mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text("Accesso Negato: Non sei un Amministratore 🛑", style: getSharedTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.bold))),
|
||||||
|
backgroundColor: Colors.redAccent,
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -791,7 +812,6 @@ class _FavoriteOnlinePopupState extends State<FavoriteOnlinePopup> with SingleTi
|
||||||
position: _offsetAnimation,
|
position: _offsetAnimation,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
// --- FIX OVERLAP POPUP: Aggiunta Elevation Altissima (100) ---
|
|
||||||
elevation: 100,
|
elevation: 100,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||||
import 'package:firebase_auth/firebase_auth.dart';
|
import 'package:firebase_auth/firebase_auth.dart';
|
||||||
|
import 'package:tetraq/l10n/app_localizations.dart'; // <-- IMPORT DEL DIZIONARIO!
|
||||||
|
|
||||||
import '../../logic/game_controller.dart';
|
import '../../logic/game_controller.dart';
|
||||||
import '../../models/game_board.dart';
|
import '../../models/game_board.dart';
|
||||||
|
|
@ -71,7 +72,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
if (state == AppLifecycleState.paused || state == AppLifecycleState.detached) {
|
if (state == AppLifecycleState.detached) {
|
||||||
_cleanupGhostRoom();
|
_cleanupGhostRoom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -222,12 +223,13 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final theme = context.watch<ThemeManager>().currentColors;
|
final theme = context.watch<ThemeManager>().currentColors;
|
||||||
final themeType = context.read<ThemeManager>().currentThemeType;
|
final themeType = context.read<ThemeManager>().currentThemeType;
|
||||||
|
final loc = AppLocalizations.of(context)!;
|
||||||
|
|
||||||
Widget dialogContent = Column(
|
Widget dialogContent = Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
CircularProgressIndicator(color: theme.playerRed), const SizedBox(height: 25),
|
CircularProgressIndicator(color: theme.playerRed), const SizedBox(height: 25),
|
||||||
Text("CODICE STANZA", style: getLobbyTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: theme.text.withOpacity(0.6), letterSpacing: 2))),
|
Text(loc.codeHint, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: theme.text.withOpacity(0.6), letterSpacing: 2))),
|
||||||
Text(code, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 40, fontWeight: FontWeight.w900, color: theme.playerRed, letterSpacing: 8, shadows: themeType == AppThemeType.doodle ? [] : [Shadow(color: theme.playerRed.withOpacity(0.5), blurRadius: 10)]))),
|
Text(code, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 40, fontWeight: FontWeight.w900, color: theme.playerRed, letterSpacing: 8, shadows: themeType == AppThemeType.doodle ? [] : [Shadow(color: theme.playerRed.withOpacity(0.5), blurRadius: 10)]))),
|
||||||
const SizedBox(height: 25),
|
const SizedBox(height: 25),
|
||||||
Transform.rotate(
|
Transform.rotate(
|
||||||
|
|
@ -305,7 +307,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
_cleanupGhostRoom();
|
_cleanupGhostRoom();
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
child: Text("ANNULLA", style: getLobbyTextStyle(themeType, TextStyle(color: Colors.red, fontWeight: FontWeight.w900, fontSize: 20, letterSpacing: 2.0, shadows: themeType == AppThemeType.doodle ? [] : [const Shadow(color: Colors.black, blurRadius: 2)]))),
|
child: Text(loc.btnCancel.toUpperCase(), style: getLobbyTextStyle(themeType, TextStyle(color: Colors.red, fontWeight: FontWeight.w900, fontSize: 20, letterSpacing: 2.0, shadows: themeType == AppThemeType.doodle ? [] : [const Shadow(color: Colors.black, blurRadius: 2)]))),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -348,6 +350,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
final themeManager = context.watch<ThemeManager>();
|
final themeManager = context.watch<ThemeManager>();
|
||||||
final themeType = themeManager.currentThemeType;
|
final themeType = themeManager.currentThemeType;
|
||||||
final theme = themeManager.currentColors;
|
final theme = themeManager.currentColors;
|
||||||
|
final loc = AppLocalizations.of(context)!; // <-- CHIAMATA AL DIZIONARIO
|
||||||
|
|
||||||
String? bgImage;
|
String? bgImage;
|
||||||
if (themeType == AppThemeType.doodle) bgImage = 'assets/images/doodle_bg.jpg';
|
if (themeType == AppThemeType.doodle) bgImage = 'assets/images/doodle_bg.jpg';
|
||||||
|
|
@ -369,7 +372,6 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
panelBackgroundColor = Colors.black.withOpacity(0.4);
|
panelBackgroundColor = Colors.black.withOpacity(0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget hostPanel = Transform.rotate(
|
Widget hostPanel = Transform.rotate(
|
||||||
angle: themeType == AppThemeType.doodle ? 0.01 : 0,
|
angle: themeType == AppThemeType.doodle ? 0.01 : 0,
|
||||||
child: Container(
|
child: Container(
|
||||||
|
|
@ -387,10 +389,10 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Center(child: Text("IMPOSTAZIONI STANZA", textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 12, fontWeight: FontWeight.w900, color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.6), letterSpacing: 2.0)))),
|
Center(child: Text(loc.roomSettings, textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 12, fontWeight: FontWeight.w900, color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.6), letterSpacing: 2.0)))),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
Text("FORMA ARENA", style: getLobbyTextStyle(themeType, TextStyle(fontSize: 10, fontWeight: FontWeight.w900, color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), letterSpacing: 1.5))),
|
Text(loc.arenaShape, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 10, fontWeight: FontWeight.w900, color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), letterSpacing: 1.5))),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -412,7 +414,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
Divider(color: themeType == AppThemeType.doodle ? theme.text.withOpacity(0.5) : Colors.white.withOpacity(0.05), thickness: themeType == AppThemeType.doodle ? 2.5 : 1.5),
|
Divider(color: themeType == AppThemeType.doodle ? theme.text.withOpacity(0.5) : Colors.white.withOpacity(0.05), thickness: themeType == AppThemeType.doodle ? 2.5 : 1.5),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
Text("GRANDEZZA", style: getLobbyTextStyle(themeType, TextStyle(fontSize: 10, fontWeight: FontWeight.w900, color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), letterSpacing: 1.5))),
|
Text(loc.arenaSize, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 10, fontWeight: FontWeight.w900, color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), letterSpacing: 1.5))),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
|
@ -428,7 +430,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
Divider(color: themeType == AppThemeType.doodle ? theme.text.withOpacity(0.5) : Colors.white.withOpacity(0.05), thickness: themeType == AppThemeType.doodle ? 2.5 : 1.5),
|
Divider(color: themeType == AppThemeType.doodle ? theme.text.withOpacity(0.5) : Colors.white.withOpacity(0.05), thickness: themeType == AppThemeType.doodle ? 2.5 : 1.5),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
Text("TEMPO E OPZIONI", style: getLobbyTextStyle(themeType, TextStyle(fontSize: 10, fontWeight: FontWeight.w900, color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), letterSpacing: 1.5))),
|
Text(loc.timeAndOptions, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 10, fontWeight: FontWeight.w900, color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), letterSpacing: 1.5))),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -470,7 +472,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text("MULTIPLAYER", textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 20, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 2))),
|
child: Text(loc.onlineTitle.toUpperCase(), textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(fontSize: 20, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 2))),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 48),
|
const SizedBox(width: 48),
|
||||||
],
|
],
|
||||||
|
|
@ -490,11 +492,11 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: NeonActionButton(label: "AVVIA", color: theme.playerRed, onTap: _createRoom, theme: theme, themeType: themeType),
|
child: NeonActionButton(label: loc.btnStart.toUpperCase(), color: theme.playerRed, onTap: _createRoom, theme: theme, themeType: themeType),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: NeonActionButton(label: "ANNULLA", color: Colors.grey.shade600, onTap: () => setState(() => _isCreatingRoom = false), theme: theme, themeType: themeType),
|
child: NeonActionButton(label: loc.btnCancel.toUpperCase(), color: Colors.grey.shade600, onTap: () => setState(() => _isCreatingRoom = false), theme: theme, themeType: themeType),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -503,12 +505,12 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
: Column(
|
: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
NeonActionButton(label: "CREA PARTITA", color: theme.playerRed, onTap: () { FocusScope.of(context).unfocus(); setState(() => _isCreatingRoom = true); }, theme: theme, themeType: themeType),
|
NeonActionButton(label: loc.createMatch.toUpperCase(), color: theme.playerRed, onTap: () { FocusScope.of(context).unfocus(); setState(() => _isCreatingRoom = true); }, theme: theme, themeType: themeType),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
||||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child: Text("OPPURE", style: getLobbyTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), fontWeight: FontWeight.bold, letterSpacing: 2.0, fontSize: 13)))),
|
Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child: Text(loc.wordOr.toUpperCase(), style: getLobbyTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), fontWeight: FontWeight.bold, letterSpacing: 2.0, fontSize: 13)))),
|
||||||
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -530,7 +532,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
style: getLobbyTextStyle(themeType, TextStyle(fontSize: 28, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 12, shadows: themeType == AppThemeType.doodle ? [] : [Shadow(color: theme.playerBlue.withOpacity(0.5), blurRadius: 8)])),
|
style: getLobbyTextStyle(themeType, TextStyle(fontSize: 28, fontWeight: FontWeight.w900, color: theme.text, letterSpacing: 12, shadows: themeType == AppThemeType.doodle ? [] : [Shadow(color: theme.playerBlue.withOpacity(0.5), blurRadius: 8)])),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
hintText: "CODICE", hintStyle: getLobbyTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.3), letterSpacing: 10, fontSize: 20)), counterText: "",
|
hintText: loc.codeHint.toUpperCase(), hintStyle: getLobbyTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.3), letterSpacing: 10, fontSize: 20)), counterText: "",
|
||||||
filled: themeType != AppThemeType.doodle,
|
filled: themeType != AppThemeType.doodle,
|
||||||
fillColor: themeType == AppThemeType.cyberpunk ? Colors.black.withOpacity(0.85) : theme.text.withOpacity(0.05),
|
fillColor: themeType == AppThemeType.cyberpunk ? Colors.black.withOpacity(0.85) : theme.text.withOpacity(0.05),
|
||||||
enabledBorder: themeType == AppThemeType.doodle ? InputBorder.none : OutlineInputBorder(borderSide: BorderSide(color: theme.gridLine.withOpacity(0.5), width: 2.0), borderRadius: BorderRadius.circular(15)),
|
enabledBorder: themeType == AppThemeType.doodle ? InputBorder.none : OutlineInputBorder(borderSide: BorderSide(color: theme.gridLine.withOpacity(0.5), width: 2.0), borderRadius: BorderRadius.circular(15)),
|
||||||
|
|
@ -540,7 +542,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 15),
|
||||||
NeonActionButton(label: "UNISCITI", color: theme.playerBlue, onTap: () => _joinRoomByCode(_codeController.text), theme: theme, themeType: themeType),
|
NeonActionButton(label: loc.joinMatch.toUpperCase(), color: theme.playerBlue, onTap: () => _joinRoomByCode(_codeController.text), theme: theme, themeType: themeType),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -549,7 +551,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
||||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child: Text("LOBBY PUBBLICA", style: getLobbyTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), fontWeight: FontWeight.bold, letterSpacing: 2.0, fontSize: 13)))),
|
Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child: Text(loc.publicLobbyTitle.toUpperCase(), style: getLobbyTextStyle(themeType, TextStyle(color: themeType == AppThemeType.doodle ? theme.text : theme.text.withOpacity(0.5), fontWeight: FontWeight.bold, letterSpacing: 2.0, fontSize: 13)))),
|
||||||
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
Expanded(child: Divider(color: theme.text.withOpacity(0.4), thickness: themeType == AppThemeType.doodle ? 2 : 1.0)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -565,7 +567,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
|
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 40.0),
|
padding: const EdgeInsets.symmetric(vertical: 40.0),
|
||||||
child: Center(child: Text("Nessuna stanza pubblica al momento.\nCreane una tu!", textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.6), height: 1.5, fontSize: 16)))),
|
child: Center(child: Text(loc.emptyLobbyMsg, textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.6), height: 1.5, fontSize: 16)))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -591,7 +593,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
if (docs.isEmpty) {
|
if (docs.isEmpty) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 40.0),
|
padding: const EdgeInsets.symmetric(vertical: 40.0),
|
||||||
child: Center(child: Text("Nessuna stanza pubblica al momento.\nCreane una tu!", textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.6), height: 1.5, fontSize: 16)))),
|
child: Center(child: Text(loc.emptyLobbyMsg, textAlign: TextAlign.center, style: getLobbyTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.6), height: 1.5, fontSize: 16)))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -610,7 +612,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
var doc = docs[index];
|
var doc = docs[index];
|
||||||
var data = doc.data() as Map<String, dynamic>;
|
var data = doc.data() as Map<String, dynamic>;
|
||||||
String host = data['hostName'] ?? 'Sconosciuto';
|
String host = data['hostName'] ?? 'Guest';
|
||||||
int r = data['radius'] ?? 4;
|
int r = data['radius'] ?? 4;
|
||||||
String shapeStr = data['shape'] ?? 'classic';
|
String shapeStr = data['shape'] ?? 'classic';
|
||||||
|
|
||||||
|
|
@ -644,7 +646,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("Stanza di $host", style: getLobbyTextStyle(themeType, TextStyle(color: theme.text, fontWeight: FontWeight.bold, fontSize: 18))),
|
Text("${loc.roomOf} $host", style: getLobbyTextStyle(themeType, TextStyle(color: theme.text, fontWeight: FontWeight.bold, fontSize: 18))),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Text("Raggio: $r • $prettyShape • $prettyTime", style: getLobbyTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.6), fontSize: 12))),
|
Text("Raggio: $r • $prettyShape • $prettyTime", style: getLobbyTextStyle(themeType, TextStyle(color: theme.text.withOpacity(0.6), fontSize: 12))),
|
||||||
],
|
],
|
||||||
|
|
@ -659,7 +661,7 @@ class _LobbyScreenState extends State<LobbyScreen> with WidgetsBindingObserver {
|
||||||
side: themeType == AppThemeType.doodle ? BorderSide(color: theme.text, width: 2) : BorderSide.none,
|
side: themeType == AppThemeType.doodle ? BorderSide(color: theme.text, width: 2) : BorderSide.none,
|
||||||
),
|
),
|
||||||
onPressed: () => _joinRoomByCode(doc.id),
|
onPressed: () => _joinRoomByCode(doc.id),
|
||||||
child: Text("ENTRA", style: getLobbyTextStyle(themeType, const TextStyle(fontWeight: FontWeight.w900, letterSpacing: 1.0))),
|
child: Text(loc.btnEnter.toUpperCase(), style: getLobbyTextStyle(themeType, const TextStyle(fontWeight: FontWeight.w900, letterSpacing: 1.0))),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
name: tetraq
|
name: tetraq
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 1.1.5+7
|
version: 1.1.6+8
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.10.7
|
sdk: ^3.10.7
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue