Auto-sync: 20260313_230001
This commit is contained in:
parent
518cb22ec4
commit
321810a6b4
10 changed files with 444 additions and 95 deletions
BIN
.DS_Store
vendored
BIN
.DS_Store
vendored
Binary file not shown.
BIN
assets/audio/bgm/Music_Loop.mp3
Normal file
BIN
assets/audio/bgm/Music_Loop.mp3
Normal file
Binary file not shown.
BIN
assets/images/music_bg.jpg
Normal file
BIN
assets/images/music_bg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
BIN
lib/.DS_Store
vendored
BIN
lib/.DS_Store
vendored
Binary file not shown.
|
|
@ -5,7 +5,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
|
||||||
enum AppThemeType { doodle, wood, cyberpunk, arcade, grimorio }
|
enum AppThemeType { doodle, wood, cyberpunk, arcade, grimorio, music } // <-- Aggiunto 'music'
|
||||||
|
|
||||||
class ThemeColors {
|
class ThemeColors {
|
||||||
final Color background;
|
final Color background;
|
||||||
|
|
@ -49,6 +49,15 @@ class AppColors {
|
||||||
playerRed: Color(0xFFE91E63), playerBlue: Color(0xFF4FC3F7), text: Color(0xFFFFF3E0),
|
playerRed: Color(0xFFE91E63), playerBlue: Color(0xFF4FC3F7), text: Color(0xFFFFF3E0),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// --- NUOVO TEMA MUSICA ---
|
||||||
|
static const ThemeColors music = ThemeColors(
|
||||||
|
background: Color(0xFF120B29), // Viola scuro (stile Synthwave)
|
||||||
|
gridLine: Color(0xFF6A1B9A), // Viola elettrico
|
||||||
|
playerRed: Color(0xFFFF2A6D), // Rosa acceso
|
||||||
|
playerBlue: Color(0xFF05D5FF), // Ciano
|
||||||
|
text: Color(0xFFE0E0E0),
|
||||||
|
);
|
||||||
|
|
||||||
static ThemeColors getTheme(AppThemeType type) {
|
static ThemeColors getTheme(AppThemeType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AppThemeType.doodle: return doodle;
|
case AppThemeType.doodle: return doodle;
|
||||||
|
|
@ -56,6 +65,7 @@ class AppColors {
|
||||||
case AppThemeType.cyberpunk: return cyberpunk;
|
case AppThemeType.cyberpunk: return cyberpunk;
|
||||||
case AppThemeType.arcade: return arcade;
|
case AppThemeType.arcade: return arcade;
|
||||||
case AppThemeType.grimorio: return grimorio;
|
case AppThemeType.grimorio: return grimorio;
|
||||||
|
case AppThemeType.music: return music;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -68,6 +78,7 @@ class ThemeIcons {
|
||||||
case AppThemeType.cyberpunk: return FontAwesomeIcons.microchip;
|
case AppThemeType.cyberpunk: return FontAwesomeIcons.microchip;
|
||||||
case AppThemeType.arcade: return FontAwesomeIcons.coins;
|
case AppThemeType.arcade: return FontAwesomeIcons.coins;
|
||||||
case AppThemeType.grimorio: return FontAwesomeIcons.crown;
|
case AppThemeType.grimorio: return FontAwesomeIcons.crown;
|
||||||
|
case AppThemeType.music: return FontAwesomeIcons.compactDisc; // CD/Vinile per i punti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,6 +89,7 @@ class ThemeIcons {
|
||||||
case AppThemeType.cyberpunk: return FontAwesomeIcons.bug;
|
case AppThemeType.cyberpunk: return FontAwesomeIcons.bug;
|
||||||
case AppThemeType.arcade: return FontAwesomeIcons.ghost;
|
case AppThemeType.arcade: return FontAwesomeIcons.ghost;
|
||||||
case AppThemeType.grimorio: return FontAwesomeIcons.hatWizard;
|
case AppThemeType.grimorio: return FontAwesomeIcons.hatWizard;
|
||||||
|
case AppThemeType.music: return FontAwesomeIcons.volumeXmark; // Muto/Errore per la bomba
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +100,7 @@ class ThemeIcons {
|
||||||
case AppThemeType.cyberpunk: return FontAwesomeIcons.networkWired;
|
case AppThemeType.cyberpunk: return FontAwesomeIcons.networkWired;
|
||||||
case AppThemeType.arcade: return FontAwesomeIcons.shuffle;
|
case AppThemeType.arcade: return FontAwesomeIcons.shuffle;
|
||||||
case AppThemeType.grimorio: return FontAwesomeIcons.hurricane;
|
case AppThemeType.grimorio: return FontAwesomeIcons.hurricane;
|
||||||
|
case AppThemeType.music: return FontAwesomeIcons.sliders; // Fader da DJ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,6 +111,7 @@ class ThemeIcons {
|
||||||
case AppThemeType.cyberpunk: return FontAwesomeIcons.robot;
|
case AppThemeType.cyberpunk: return FontAwesomeIcons.robot;
|
||||||
case AppThemeType.arcade: return FontAwesomeIcons.gamepad;
|
case AppThemeType.arcade: return FontAwesomeIcons.gamepad;
|
||||||
case AppThemeType.grimorio: return FontAwesomeIcons.masksTheater;
|
case AppThemeType.grimorio: return FontAwesomeIcons.masksTheater;
|
||||||
|
case AppThemeType.music: return FontAwesomeIcons.headphones; // Cuffie per il Jolly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,14 +122,17 @@ class ThemeIcons {
|
||||||
case AppThemeType.cyberpunk: return FontAwesomeIcons.shieldHalved;
|
case AppThemeType.cyberpunk: return FontAwesomeIcons.shieldHalved;
|
||||||
case AppThemeType.arcade: return FontAwesomeIcons.powerOff;
|
case AppThemeType.arcade: return FontAwesomeIcons.powerOff;
|
||||||
case AppThemeType.grimorio: return FontAwesomeIcons.meteor;
|
case AppThemeType.grimorio: return FontAwesomeIcons.meteor;
|
||||||
|
case AppThemeType.music: return FontAwesomeIcons.pause; // Pausa per il blocco vuoto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static IconData ice(AppThemeType type) {
|
static IconData ice(AppThemeType type) {
|
||||||
|
if (type == AppThemeType.music) return FontAwesomeIcons.music; // Nota musicale ghiacciata
|
||||||
return FontAwesomeIcons.snowflake;
|
return FontAwesomeIcons.snowflake;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IconData multiplier(AppThemeType type) {
|
static IconData multiplier(AppThemeType type) {
|
||||||
|
if (type == AppThemeType.music) return FontAwesomeIcons.forwardFast; // Fast Forward per il x2
|
||||||
return FontAwesomeIcons.bolt;
|
return FontAwesomeIcons.bolt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +60,9 @@ class AudioService extends ChangeNotifier {
|
||||||
case AppThemeType.grimorio:
|
case AppThemeType.grimorio:
|
||||||
audioPath = 'audio/bgm/Grimorio_Astral.mp3';
|
audioPath = 'audio/bgm/Grimorio_Astral.mp3';
|
||||||
break;
|
break;
|
||||||
|
case AppThemeType.music:
|
||||||
|
audioPath = 'audio/bgm/Music_Loop.mp3'; // <-- DEVI INSERIRE QUESTO FILE IN ASSETS
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioPath.isNotEmpty) {
|
if (audioPath.isNotEmpty) {
|
||||||
|
|
@ -80,6 +83,7 @@ class AudioService extends ChangeNotifier {
|
||||||
String file = '';
|
String file = '';
|
||||||
switch (theme) {
|
switch (theme) {
|
||||||
case AppThemeType.arcade:
|
case AppThemeType.arcade:
|
||||||
|
case AppThemeType.music: // Usiamo l'effetto arcade o cyber per la musica
|
||||||
file = 'minimal_line.wav'; break;
|
file = 'minimal_line.wav'; break;
|
||||||
case AppThemeType.doodle:
|
case AppThemeType.doodle:
|
||||||
case AppThemeType.wood:
|
case AppThemeType.wood:
|
||||||
|
|
@ -103,6 +107,7 @@ class AudioService extends ChangeNotifier {
|
||||||
String file = '';
|
String file = '';
|
||||||
switch (theme) {
|
switch (theme) {
|
||||||
case AppThemeType.arcade:
|
case AppThemeType.arcade:
|
||||||
|
case AppThemeType.music:
|
||||||
file = 'minimal_box.wav'; break;
|
file = 'minimal_box.wav'; break;
|
||||||
case AppThemeType.doodle:
|
case AppThemeType.doodle:
|
||||||
case AppThemeType.wood:
|
case AppThemeType.wood:
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ TextStyle _getTextStyle(AppThemeType themeType, TextStyle baseStyle) {
|
||||||
));
|
));
|
||||||
} else if (themeType == AppThemeType.grimorio) {
|
} else if (themeType == AppThemeType.grimorio) {
|
||||||
return GoogleFonts.cinzelDecorative(textStyle: baseStyle.copyWith(fontWeight: FontWeight.bold));
|
return GoogleFonts.cinzelDecorative(textStyle: baseStyle.copyWith(fontWeight: FontWeight.bold));
|
||||||
|
} else if (themeType == AppThemeType.music) {
|
||||||
|
return GoogleFonts.audiowide(textStyle: baseStyle.copyWith(letterSpacing: 1.5));
|
||||||
}
|
}
|
||||||
return baseStyle;
|
return baseStyle;
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +81,7 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
if (myName.isEmpty) myName = "TU";
|
if (myName.isEmpty) myName = "TU";
|
||||||
|
|
||||||
String nameRed = controller.isOnline ? controller.onlineHostName.toUpperCase() : myName;
|
String nameRed = controller.isOnline ? controller.onlineHostName.toUpperCase() : myName;
|
||||||
String nameBlue = controller.isOnline ? controller.onlineGuestName.toUpperCase() : (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? "VERDE" : "BLU");
|
String nameBlue = controller.isOnline ? controller.onlineGuestName.toUpperCase() : (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? "VERDE" : "BLU");
|
||||||
if (controller.isVsCPU) nameBlue = "CPU";
|
if (controller.isVsCPU) nameBlue = "CPU";
|
||||||
|
|
||||||
String winnerText = ""; Color winnerColor = theme.text;
|
String winnerText = ""; Color winnerColor = theme.text;
|
||||||
|
|
@ -119,7 +121,7 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
color: Colors.green.withOpacity(0.15),
|
color: Colors.green.withOpacity(0.15),
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
border: Border.all(color: Colors.greenAccent, width: 1.5),
|
border: Border.all(color: Colors.greenAccent, width: 1.5),
|
||||||
boxShadow: themeType == AppThemeType.cyberpunk ? [const BoxShadow(color: Colors.greenAccent, blurRadius: 10, spreadRadius: -5)] : [],
|
boxShadow: (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) ? [const BoxShadow(color: Colors.greenAccent, blurRadius: 10, spreadRadius: -5)] : [],
|
||||||
),
|
),
|
||||||
child: Text("+ ${controller.lastMatchXP} XP", style: _getTextStyle(themeType, const TextStyle(color: Colors.greenAccent, fontWeight: FontWeight.w900, fontSize: 16, letterSpacing: 1.5))),
|
child: Text("+ ${controller.lastMatchXP} XP", style: _getTextStyle(themeType, const TextStyle(color: Colors.greenAccent, fontWeight: FontWeight.w900, fontSize: 16, letterSpacing: 1.5))),
|
||||||
),
|
),
|
||||||
|
|
@ -194,7 +196,7 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
titleText = "Nascondi il tuo Jolly!";
|
titleText = "Nascondi il tuo Jolly!";
|
||||||
subtitleText = "(Tocca qui per nascondere)";
|
subtitleText = "(Tocca qui per nascondere)";
|
||||||
} else {
|
} else {
|
||||||
String pName = gameController.jokerTurn == Player.red ? "ROSSO" : (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.aurora ? "VERDE" : "BLU");
|
String pName = gameController.jokerTurn == Player.red ? "ROSSO" : (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? "VERDE" : "BLU");
|
||||||
titleText = "TURNO GIOCATORE $pName";
|
titleText = "TURNO GIOCATORE $pName";
|
||||||
subtitleText = "Passa il dispositivo.\nL'avversario NON deve guardare!\n\n(Tocca qui quando sei pronto)";
|
subtitleText = "Passa il dispositivo.\nL'avversario NON deve guardare!\n\n(Tocca qui quando sei pronto)";
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +206,7 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Icon(ThemeIcons.joker(themeType), color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.aurora ? Colors.yellowAccent : theme.playerBlue, size: 50),
|
Icon(ThemeIcons.joker(themeType), color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? Colors.yellowAccent : theme.playerBlue, size: 50),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 15),
|
||||||
Text(
|
Text(
|
||||||
titleText,
|
titleText,
|
||||||
|
|
@ -229,8 +231,8 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (themeType == AppThemeType.cyberpunk) {
|
if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) {
|
||||||
return Container(decoration: BoxDecoration(color: Colors.black.withOpacity(0.9), borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.yellowAccent, width: 2), boxShadow: [const BoxShadow(color: Colors.yellowAccent, blurRadius: 15, spreadRadius: 0)]), child: content);
|
return Container(decoration: BoxDecoration(color: Colors.black.withOpacity(0.9), borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.purpleAccent, width: 2), boxShadow: [BoxShadow(color: Colors.purpleAccent.withOpacity(0.6), blurRadius: 15, spreadRadius: 0)]), child: content);
|
||||||
} else if (themeType == AppThemeType.doodle) {
|
} else if (themeType == AppThemeType.doodle) {
|
||||||
return Container(decoration: BoxDecoration(color: const Color(0xFFF9F9F9), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.black87, width: 3), boxShadow: const [BoxShadow(color: Colors.black26, offset: Offset(6, 6))]), child: content);
|
return Container(decoration: BoxDecoration(color: const Color(0xFFF9F9F9), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.black87, width: 3), boxShadow: const [BoxShadow(color: Colors.black26, offset: Offset(6, 6))]), child: content);
|
||||||
} else if (themeType == AppThemeType.wood) {
|
} else if (themeType == AppThemeType.wood) {
|
||||||
|
|
@ -289,8 +291,10 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
String? bgImage;
|
String? bgImage;
|
||||||
if (themeType == AppThemeType.wood) bgImage = 'assets/images/wood_bg.jpg';
|
if (themeType == AppThemeType.wood) bgImage = 'assets/images/wood_bg.jpg';
|
||||||
if (themeType == AppThemeType.doodle) bgImage = 'assets/images/doodle_bg.jpg';
|
if (themeType == AppThemeType.doodle) bgImage = 'assets/images/doodle_bg.jpg';
|
||||||
|
if (themeType == AppThemeType.cyberpunk) bgImage = 'assets/images/cyber_bg.jpg';
|
||||||
|
if (themeType == AppThemeType.music) bgImage = 'assets/images/music_bg.jpg';
|
||||||
|
|
||||||
Color indicatorColor = themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.aurora ? Colors.white : Colors.black;
|
Color indicatorColor = themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? Colors.white : Colors.black;
|
||||||
|
|
||||||
Widget emojiBar = const SizedBox();
|
Widget emojiBar = const SizedBox();
|
||||||
if (gameController.isOnline && !gameController.isGameOver) {
|
if (gameController.isOnline && !gameController.isGameOver) {
|
||||||
|
|
@ -298,9 +302,9 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
emojiBar = Container(
|
emojiBar = Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.aurora ? Colors.black.withOpacity(0.6) : Colors.white.withOpacity(0.8),
|
color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? Colors.black.withOpacity(0.6) : Colors.white.withOpacity(0.8),
|
||||||
borderRadius: BorderRadius.circular(30),
|
borderRadius: BorderRadius.circular(30),
|
||||||
border: Border.all(color: themeType == AppThemeType.cyberpunk ? theme.playerBlue.withOpacity(0.3) : Colors.white24, width: 2),
|
border: Border.all(color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music ? theme.playerBlue.withOpacity(0.3) : Colors.white24, width: 2),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -382,10 +386,10 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.4), offset: const Offset(0, 4), blurRadius: 5)]),
|
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.4), offset: const Offset(0, 4), blurRadius: 5)]),
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
style: TextButton.styleFrom(backgroundColor: bgImage != null || themeType == AppThemeType.arcade || themeType == AppThemeType.aurora ? Colors.black87 : theme.background, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20), side: BorderSide(color: Colors.white.withOpacity(0.1), width: 1))),
|
style: TextButton.styleFrom(backgroundColor: bgImage != null || themeType == AppThemeType.arcade ? Colors.black87 : theme.background, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20), side: BorderSide(color: Colors.white.withOpacity(0.1), width: 1))),
|
||||||
icon: Icon(Icons.exit_to_app, color: bgImage != null || themeType == AppThemeType.arcade || themeType == AppThemeType.aurora ? Colors.white : theme.text, size: 20),
|
icon: Icon(Icons.exit_to_app, color: bgImage != null || themeType == AppThemeType.arcade ? Colors.white : theme.text, size: 20),
|
||||||
onPressed: () { gameController.disconnectOnlineGame(); Navigator.pop(context); },
|
onPressed: () { gameController.disconnectOnlineGame(); Navigator.pop(context); },
|
||||||
label: Text("ESCI", style: _getTextStyle(themeType, TextStyle(color: bgImage != null || themeType == AppThemeType.arcade || themeType == AppThemeType.aurora ? Colors.white : theme.text, fontWeight: FontWeight.bold, fontSize: 12))),
|
label: Text("ESCI", style: _getTextStyle(themeType, TextStyle(color: bgImage != null || themeType == AppThemeType.arcade ? Colors.white : theme.text, fontWeight: FontWeight.bold, fontSize: 12))),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -406,23 +410,25 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
canPop: true,
|
canPop: true,
|
||||||
onPopInvoked: (didPop) { gameController.disconnectOnlineGame(); },
|
onPopInvoked: (didPop) { gameController.disconnectOnlineGame(); },
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
// L'impostazione dello sfondo dipende dal tema
|
backgroundColor: bgImage != null ? Colors.transparent : theme.background,
|
||||||
backgroundColor: themeType == AppThemeType.aurora ? Colors.transparent : (bgImage != null ? Colors.transparent : theme.background),
|
|
||||||
body: Container(
|
body: Container(
|
||||||
// GRADIENTE AURORA IN BACKGROUND!
|
decoration: bgImage != null ? BoxDecoration(image: DecorationImage(image: AssetImage(bgImage), fit: BoxFit.cover, colorFilter: themeType == AppThemeType.doodle ? ColorFilter.mode(Colors.white.withOpacity(0.7), BlendMode.lighten) : null)) : null,
|
||||||
decoration: themeType == AppThemeType.aurora
|
|
||||||
? const BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
colors: [Color(0xFF2A0845), Color(0xFFDD2476), Color(0xFFFF512F)],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: (bgImage != null ? BoxDecoration(image: DecorationImage(image: AssetImage(bgImage), fit: BoxFit.cover, colorFilter: themeType == AppThemeType.doodle ? ColorFilter.mode(Colors.white.withOpacity(0.7), BlendMode.lighten) : null)) : null),
|
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
// painter rimosso per supportare il nuovo sfondo a gradiente
|
painter: themeType == AppThemeType.doodle ? FullScreenGridPainter(Colors.black.withOpacity(0.06)) : null,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
|
if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music))
|
||||||
|
Positioned.fill(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topCenter, end: Alignment.bottomCenter,
|
||||||
|
colors: [Colors.black.withOpacity(0.3), Colors.black.withOpacity(0.8)]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
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)),
|
||||||
|
|
||||||
|
|
@ -434,7 +440,7 @@ class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
|
||||||
if (gameController.isSetupPhase && !_hideJokerMessage)
|
if (gameController.isSetupPhase && !_hideJokerMessage)
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.aurora
|
color: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music
|
||||||
? Colors.black.withOpacity(0.98)
|
? Colors.black.withOpacity(0.98)
|
||||||
: theme.background.withOpacity(0.98),
|
: theme.background.withOpacity(0.98),
|
||||||
child: Center(
|
child: Center(
|
||||||
|
|
@ -520,7 +526,7 @@ class _WinnerVFXOverlayState extends State<WinnerVFXOverlay> with SingleTickerPr
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initParticles(Size screenSize) {
|
void _initParticles(Size screenSize) {
|
||||||
int particleCount = widget.themeType == AppThemeType.cyberpunk || widget.themeType == AppThemeType.aurora ? 150 : 100;
|
int particleCount = widget.themeType == AppThemeType.cyberpunk || widget.themeType == AppThemeType.music ? 150 : 100;
|
||||||
if (widget.themeType == AppThemeType.arcade) particleCount = 80;
|
if (widget.themeType == AppThemeType.arcade) particleCount = 80;
|
||||||
if (widget.themeType == AppThemeType.grimorio) particleCount = 120;
|
if (widget.themeType == AppThemeType.grimorio) particleCount = 120;
|
||||||
|
|
||||||
|
|
@ -530,7 +536,7 @@ class _WinnerVFXOverlayState extends State<WinnerVFXOverlay> with SingleTickerPr
|
||||||
else if (widget.themeType == AppThemeType.wood) { palette = [Colors.orangeAccent, Colors.yellow, Colors.red, Colors.white]; }
|
else if (widget.themeType == AppThemeType.wood) { palette = [Colors.orangeAccent, Colors.yellow, Colors.red, Colors.white]; }
|
||||||
else if (widget.themeType == AppThemeType.arcade) { palette = [widget.winnerColor, Colors.white, Colors.greenAccent]; }
|
else if (widget.themeType == AppThemeType.arcade) { palette = [widget.winnerColor, Colors.white, Colors.greenAccent]; }
|
||||||
else if (widget.themeType == AppThemeType.grimorio) { palette = [widget.winnerColor, Colors.deepPurpleAccent, Colors.white]; }
|
else if (widget.themeType == AppThemeType.grimorio) { palette = [widget.winnerColor, Colors.deepPurpleAccent, Colors.white]; }
|
||||||
else if (widget.themeType == AppThemeType.aurora) { palette = [widget.winnerColor, Colors.white, Colors.orangeAccent, Colors.pinkAccent]; }
|
else if (widget.themeType == AppThemeType.music) { palette.add(Colors.pinkAccent); palette.add(Colors.cyanAccent); }
|
||||||
|
|
||||||
for (int i = 0; i < particleCount; i++) {
|
for (int i = 0; i < particleCount; i++) {
|
||||||
double speed = _rand.nextDouble() * 20 + 5;
|
double speed = _rand.nextDouble() * 20 + 5;
|
||||||
|
|
@ -543,7 +549,7 @@ class _WinnerVFXOverlayState extends State<WinnerVFXOverlay> with SingleTickerPr
|
||||||
setState(() {
|
setState(() {
|
||||||
for (var p in _particles) {
|
for (var p in _particles) {
|
||||||
p.x += p.vx; p.y += p.vy;
|
p.x += p.vx; p.y += p.vy;
|
||||||
if (widget.themeType == AppThemeType.cyberpunk || widget.themeType == AppThemeType.aurora) { p.vy += 0.1; p.vx *= 0.98; p.vy *= 0.98; }
|
if (widget.themeType == AppThemeType.cyberpunk || widget.themeType == AppThemeType.music) { p.vy += 0.1; p.vx *= 0.98; p.vy *= 0.98; }
|
||||||
else if (widget.themeType == AppThemeType.wood) { p.vy -= 0.2; p.x += math.sin(p.y * 0.05) * 2; }
|
else if (widget.themeType == AppThemeType.wood) { p.vy -= 0.2; p.x += math.sin(p.y * 0.05) * 2; }
|
||||||
else if (widget.themeType == AppThemeType.arcade) { p.vy += 0.3; p.spin = 0; p.angle = 0; }
|
else if (widget.themeType == AppThemeType.arcade) { p.vy += 0.3; p.spin = 0; p.angle = 0; }
|
||||||
else if (widget.themeType == AppThemeType.grimorio) { p.vy -= 0.1; p.x += math.sin(p.y * 0.02) * 1.5; p.size *= 0.995; }
|
else if (widget.themeType == AppThemeType.grimorio) { p.vy -= 0.1; p.x += math.sin(p.y * 0.02) * 1.5; p.size *= 0.995; }
|
||||||
|
|
@ -566,7 +572,7 @@ class _VFXPainter extends CustomPainter {
|
||||||
for (var p in particles) {
|
for (var p in particles) {
|
||||||
if (p.size < 0.5) continue;
|
if (p.size < 0.5) continue;
|
||||||
final paint = Paint()..color = p.color..style = PaintingStyle.fill;
|
final paint = Paint()..color = p.color..style = PaintingStyle.fill;
|
||||||
if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.aurora) { paint.maskFilter = const MaskFilter.blur(BlurStyle.solid, 4.0); }
|
if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) { paint.maskFilter = const MaskFilter.blur(BlurStyle.solid, 4.0); }
|
||||||
canvas.save(); canvas.translate(p.x, p.y); canvas.rotate(p.angle);
|
canvas.save(); canvas.translate(p.x, p.y); canvas.rotate(p.angle);
|
||||||
|
|
||||||
if (themeType == AppThemeType.doodle) {
|
if (themeType == AppThemeType.doodle) {
|
||||||
|
|
@ -603,7 +609,6 @@ class _BouncingEmojiState extends State<_BouncingEmoji> with SingleTickerProvide
|
||||||
@override Widget build(BuildContext context) { return AnimatedBuilder(animation: _anim, builder: (ctx, child) => Transform.translate(offset: Offset(0, _anim.value), child: Container(padding: const EdgeInsets.all(8), decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle, boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 5)]), child: Text(widget.emoji, style: const TextStyle(fontSize: 32))))); }
|
@override Widget build(BuildContext context) { return AnimatedBuilder(animation: _anim, builder: (ctx, child) => Transform.translate(offset: Offset(0, _anim.value), child: Container(padding: const EdgeInsets.all(8), decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle, boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 5)]), child: Text(widget.emoji, style: const TextStyle(fontSize: 32))))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mantengo la definizione per evitare buchi, ma ora Aurora usa il LinearGradient!
|
|
||||||
class FullScreenGridPainter extends CustomPainter {
|
class FullScreenGridPainter extends CustomPainter {
|
||||||
final Color gridColor; FullScreenGridPainter(this.gridColor);
|
final Color gridColor; FullScreenGridPainter(this.gridColor);
|
||||||
@override void paint(Canvas canvas, Size size) { final Paint paperGridPaint = Paint()..color = gridColor..strokeWidth = 1.0..style = PaintingStyle.stroke; double paperStep = 20.0; for (double i = 0; i <= size.width; i += paperStep) canvas.drawLine(Offset(i, 0), Offset(i, size.height), paperGridPaint); for (double i = 0; i <= size.height; i += paperStep) canvas.drawLine(Offset(0, i), Offset(size.width, i), paperGridPaint); }
|
@override void paint(Canvas canvas, Size size) { final Paint paperGridPaint = Paint()..color = gridColor..strokeWidth = 1.0..style = PaintingStyle.stroke; double paperStep = 20.0; for (double i = 0; i <= size.width; i += paperStep) canvas.drawLine(Offset(i, 0), Offset(i, size.height), paperGridPaint); for (double i = 0; i <= size.height; i += paperStep) canvas.drawLine(Offset(0, i), Offset(size.width, i), paperGridPaint); }
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
// Import separati e puliti
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import '../../logic/game_controller.dart';
|
import '../../logic/game_controller.dart';
|
||||||
import '../../models/game_board.dart';
|
import '../../models/game_board.dart';
|
||||||
import '../../core/theme_manager.dart';
|
import '../../core/theme_manager.dart';
|
||||||
|
|
@ -12,6 +12,20 @@ import '../../services/audio_service.dart';
|
||||||
import '../../core/app_colors.dart';
|
import '../../core/app_colors.dart';
|
||||||
import '../../services/storage_service.dart';
|
import '../../services/storage_service.dart';
|
||||||
|
|
||||||
|
TextStyle _getTextStyle(AppThemeType themeType, TextStyle baseStyle) {
|
||||||
|
if (themeType == AppThemeType.doodle) {
|
||||||
|
return GoogleFonts.permanentMarker(textStyle: baseStyle);
|
||||||
|
} else if (themeType == AppThemeType.arcade) {
|
||||||
|
return GoogleFonts.pressStart2p(textStyle: baseStyle.copyWith(
|
||||||
|
fontSize: baseStyle.fontSize != null ? baseStyle.fontSize! * 0.75 : null,
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
));
|
||||||
|
} else if (themeType == AppThemeType.grimorio) {
|
||||||
|
return GoogleFonts.cinzelDecorative(textStyle: baseStyle.copyWith(fontWeight: FontWeight.bold));
|
||||||
|
}
|
||||||
|
return baseStyle;
|
||||||
|
}
|
||||||
|
|
||||||
class ScoreBoard extends StatefulWidget {
|
class ScoreBoard extends StatefulWidget {
|
||||||
const ScoreBoard({super.key});
|
const ScoreBoard({super.key});
|
||||||
|
|
||||||
|
|
@ -50,7 +64,7 @@ class _ScoreBoardState extends State<ScoreBoard> {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.only(top: 10, bottom: 20, left: 20, right: 20),
|
padding: const EdgeInsets.only(top: 10, bottom: 20, left: 20, right: 20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: theme.background.withOpacity(0.95),
|
color: themeType == AppThemeType.doodle ? theme.background : theme.background.withOpacity(0.95),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.3),
|
color: Colors.black.withOpacity(0.3),
|
||||||
|
|
@ -66,20 +80,26 @@ class _ScoreBoardState extends State<ScoreBoard> {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
_PlayerScore(color: theme.playerRed, score: redScore, isTurn: isRedTurn, textColor: theme.text, title: nameRed),
|
_PlayerScore(color: theme.playerRed, score: redScore, isTurn: isRedTurn, textColor: theme.text, title: nameRed, themeType: themeType),
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"TETRAQ",
|
"TETRAQ",
|
||||||
style: TextStyle(
|
style: _getTextStyle(themeType, TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.w900,
|
||||||
color: theme.text,
|
color: theme.text,
|
||||||
letterSpacing: 4,
|
letterSpacing: 4,
|
||||||
shadows: [Shadow(color: Colors.black.withOpacity(0.3), offset: const Offset(1, 2), blurRadius: 2)]
|
shadows: themeType == AppThemeType.doodle
|
||||||
)
|
? [
|
||||||
|
// EFFETTO RILIEVO (Luce in alto a sx, ombra in basso a dx)
|
||||||
|
const Shadow(color: Colors.white, offset: Offset(-1.5, -1.5), blurRadius: 1),
|
||||||
|
Shadow(color: Colors.black.withOpacity(0.25), offset: const Offset(1.5, 1.5), blurRadius: 2),
|
||||||
|
]
|
||||||
|
: [Shadow(color: Colors.black.withOpacity(0.3), offset: const Offset(1, 2), blurRadius: 2)]
|
||||||
|
))
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(isMuted ? Icons.volume_off : Icons.volume_up, color: theme.text.withOpacity(0.7)),
|
icon: Icon(isMuted ? Icons.volume_off : Icons.volume_up, color: theme.text.withOpacity(0.7)),
|
||||||
|
|
@ -92,7 +112,7 @@ class _ScoreBoardState extends State<ScoreBoard> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
_PlayerScore(color: theme.playerBlue, score: blueScore, isTurn: !isRedTurn, textColor: theme.text, title: nameBlue),
|
_PlayerScore(color: theme.playerBlue, score: blueScore, isTurn: !isRedTurn, textColor: theme.text, title: nameBlue, themeType: themeType),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -105,15 +125,16 @@ class _PlayerScore extends StatelessWidget {
|
||||||
final bool isTurn;
|
final bool isTurn;
|
||||||
final Color textColor;
|
final Color textColor;
|
||||||
final String title;
|
final String title;
|
||||||
|
final AppThemeType themeType;
|
||||||
|
|
||||||
const _PlayerScore({required this.color, required this.score, required this.isTurn, required this.textColor, required this.title});
|
const _PlayerScore({required this.color, required this.score, required this.isTurn, required this.textColor, required this.title, required this.themeType});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(title, style: TextStyle(fontWeight: FontWeight.bold, color: isTurn ? color : textColor.withOpacity(0.5), fontSize: 12)),
|
Text(title, style: _getTextStyle(themeType, TextStyle(fontWeight: FontWeight.bold, color: isTurn ? color : textColor.withOpacity(0.5), fontSize: 12))),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
AnimatedContainer(
|
AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
|
|
@ -126,7 +147,7 @@ class _PlayerScore extends StatelessWidget {
|
||||||
BoxShadow(color: color.withOpacity(0.5), offset: const Offset(0, 4), blurRadius: 6)
|
BoxShadow(color: color.withOpacity(0.5), offset: const Offset(0, 4), blurRadius: 6)
|
||||||
] : [],
|
] : [],
|
||||||
),
|
),
|
||||||
child: Text('$score', style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: isTurn ? Colors.white : textColor.withOpacity(0.5))),
|
child: Text('$score', style: _getTextStyle(themeType, TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: isTurn ? Colors.white : textColor.withOpacity(0.5)))),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import 'dart:math' as math;
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; // Aggiunto per le nuove icone musicali
|
||||||
|
|
||||||
import '../../logic/game_controller.dart';
|
import '../../logic/game_controller.dart';
|
||||||
import '../../core/theme_manager.dart';
|
import '../../core/theme_manager.dart';
|
||||||
|
|
@ -36,6 +37,8 @@ TextStyle _getTextStyle(AppThemeType themeType, TextStyle baseStyle) {
|
||||||
));
|
));
|
||||||
} else if (themeType == AppThemeType.grimorio) {
|
} else if (themeType == AppThemeType.grimorio) {
|
||||||
return GoogleFonts.cinzelDecorative(textStyle: baseStyle.copyWith(fontWeight: FontWeight.bold));
|
return GoogleFonts.cinzelDecorative(textStyle: baseStyle.copyWith(fontWeight: FontWeight.bold));
|
||||||
|
} else if (themeType == AppThemeType.music) {
|
||||||
|
return GoogleFonts.audiowide(textStyle: baseStyle.copyWith(letterSpacing: 1.5));
|
||||||
}
|
}
|
||||||
return baseStyle;
|
return baseStyle;
|
||||||
}
|
}
|
||||||
|
|
@ -535,7 +538,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (themeType == AppThemeType.cyberpunk) dialogContent = _AnimatedCyberBorder(child: dialogContent);
|
if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) dialogContent = _AnimatedCyberBorder(child: dialogContent);
|
||||||
return Dialog(backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.all(20), child: dialogContent);
|
return Dialog(backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.all(20), child: dialogContent);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -754,8 +757,8 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [theme.background.withOpacity(0.95), theme.background.withOpacity(0.8)]),
|
gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [theme.background.withOpacity(0.95), theme.background.withOpacity(0.8)]),
|
||||||
borderRadius: BorderRadius.circular(25),
|
borderRadius: BorderRadius.circular(25),
|
||||||
border: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? null : Border.all(color: Colors.white.withOpacity(0.15), width: 1.5),
|
border: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? null : Border.all(color: Colors.white.withOpacity(0.15), width: 1.5),
|
||||||
boxShadow: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? [] : [BoxShadow(color: Colors.black.withOpacity(0.5), blurRadius: 20, offset: const Offset(4, 10))],
|
boxShadow: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? [] : [BoxShadow(color: Colors.black.withOpacity(0.5), blurRadius: 20, offset: const Offset(4, 10))],
|
||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
|
|
@ -851,7 +854,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (themeType == AppThemeType.cyberpunk) {
|
if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) {
|
||||||
dialogContent = _AnimatedCyberBorder(child: dialogContent);
|
dialogContent = _AnimatedCyberBorder(child: dialogContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1053,7 +1056,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (themeType == AppThemeType.cyberpunk) content = _AnimatedCyberBorder(child: content);
|
if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) content = _AnimatedCyberBorder(child: content);
|
||||||
return Dialog(backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.all(20), child: content);
|
return Dialog(backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.all(20), child: content);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -1134,8 +1137,8 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [theme.background.withOpacity(0.95), theme.background.withOpacity(0.8)]),
|
gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [theme.background.withOpacity(0.95), theme.background.withOpacity(0.8)]),
|
||||||
borderRadius: BorderRadius.circular(25),
|
borderRadius: BorderRadius.circular(25),
|
||||||
border: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? null : Border.all(color: Colors.white.withOpacity(0.15), width: 1.5),
|
border: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? null : Border.all(color: Colors.white.withOpacity(0.15), width: 1.5),
|
||||||
boxShadow: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade ? [] : [BoxShadow(color: Colors.black.withOpacity(0.5), blurRadius: 20, offset: const Offset(4, 10))],
|
boxShadow: themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? [] : [BoxShadow(color: Colors.black.withOpacity(0.5), blurRadius: 20, offset: const Offset(4, 10))],
|
||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
|
|
@ -1182,7 +1185,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (themeType == AppThemeType.cyberpunk) dialogContent = _AnimatedCyberBorder(child: dialogContent);
|
if (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music) dialogContent = _AnimatedCyberBorder(child: dialogContent);
|
||||||
return Dialog(backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), child: dialogContent);
|
return Dialog(backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), child: dialogContent);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1192,7 +1195,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
if (themeType == AppThemeType.cyberpunk) {
|
if (themeType == AppThemeType.cyberpunk) {
|
||||||
return _AnimatedCyberBorder(child: card);
|
return _AnimatedCyberBorder(child: card);
|
||||||
}
|
}
|
||||||
return card;
|
return card; // La card musicale ha già i propri effetti integrati
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -1208,8 +1211,8 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
|
|
||||||
String? bgImage;
|
String? bgImage;
|
||||||
if (themeType == AppThemeType.wood) bgImage = 'assets/images/wood_bg.jpg';
|
if (themeType == AppThemeType.wood) bgImage = 'assets/images/wood_bg.jpg';
|
||||||
if (themeType == AppThemeType.doodle) bgImage = 'assets/images/doodle_bg.jpg';
|
|
||||||
if (themeType == AppThemeType.cyberpunk) bgImage = 'assets/images/cyber_bg.jpg';
|
if (themeType == AppThemeType.cyberpunk) bgImage = 'assets/images/cyber_bg.jpg';
|
||||||
|
if (themeType == AppThemeType.music) bgImage = 'assets/images/music_bg.jpg';
|
||||||
|
|
||||||
int wins = StorageService.instance.wins;
|
int wins = StorageService.instance.wins;
|
||||||
int losses = StorageService.instance.losses;
|
int losses = StorageService.instance.losses;
|
||||||
|
|
@ -1306,9 +1309,9 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.emoji_events, color: Colors.amber.shade600, size: 20), const SizedBox(width: 6),
|
Icon(themeType == AppThemeType.music ? FontAwesomeIcons.microphone : Icons.emoji_events, color: Colors.amber.shade600, size: 16), const SizedBox(width: 6),
|
||||||
Text("$wins", style: _getTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.w900))), const SizedBox(width: 12),
|
Text("$wins", style: _getTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.w900))), const SizedBox(width: 12),
|
||||||
Icon(Icons.sentiment_very_dissatisfied, color: theme.playerRed.withOpacity(0.8), size: 20), const SizedBox(width: 6),
|
Icon(themeType == AppThemeType.music ? FontAwesomeIcons.compactDisc : Icons.sentiment_very_dissatisfied, color: theme.playerRed.withOpacity(0.8), size: 16), const SizedBox(width: 6),
|
||||||
Text("$losses", style: _getTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.w900))),
|
Text("$losses", style: _getTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.w900))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -1322,7 +1325,6 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
Center(
|
Center(
|
||||||
child: Transform.rotate(
|
child: Transform.rotate(
|
||||||
angle: themeType == AppThemeType.doodle ? -0.04 : 0,
|
angle: themeType == AppThemeType.doodle ? -0.04 : 0,
|
||||||
// --- IL TRUCCO DELLO SVILUPPATORE PROTETTO ---
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_debugTapCount++;
|
_debugTapCount++;
|
||||||
|
|
@ -1330,16 +1332,10 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
StorageService.instance.addXP(2000);
|
StorageService.instance.addXP(2000);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(content: Text("🛠 DEBUG MODE: +20 Livelli!", style: _getTextStyle(themeType, const TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), backgroundColor: Colors.purpleAccent, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)))
|
||||||
content: Text("🛠 DEBUG MODE: +20 Livelli!", style: _getTextStyle(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) {
|
} else if (_debugTapCount >= 7) {
|
||||||
_debugTapCount = 0; // Resetta il contatore
|
_debugTapCount = 0;
|
||||||
// APRE LA DASHBOARD SEGRETA!
|
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const AdminScreen()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -1352,7 +1348,12 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.w900,
|
||||||
color: themeType == AppThemeType.doodle ? inkColor : theme.text,
|
color: themeType == AppThemeType.doodle ? inkColor : theme.text,
|
||||||
letterSpacing: 10,
|
letterSpacing: 10,
|
||||||
shadows: themeType == AppThemeType.doodle || themeType == AppThemeType.arcade ? [] : [
|
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),
|
||||||
|
]
|
||||||
|
: themeType == AppThemeType.arcade || themeType == AppThemeType.music ? [] : [
|
||||||
BoxShadow(color: Colors.black.withOpacity(0.6), offset: const Offset(3, 6), blurRadius: 8),
|
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),
|
BoxShadow(color: theme.playerBlue.withOpacity(0.4), offset: const Offset(0, 0), blurRadius: 20),
|
||||||
]
|
]
|
||||||
|
|
@ -1365,7 +1366,38 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
|
||||||
// --- NUOVA LISTA BOTTONI ---
|
// --- GESTIONE DEI MENU IN BASE AL TEMA ---
|
||||||
|
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())); },
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_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),
|
||||||
|
_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),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(child: _MusicKnobCard(title: loc.leaderboardTitle, icon: FontAwesomeIcons.compactDisc, iconColor: Colors.amber, themeType: themeType, onTap: _showLeaderboardDialog)),
|
||||||
|
Expanded(child: _MusicKnobCard(title: loc.questsTitle, icon: FontAwesomeIcons.microphoneLines, themeType: themeType, onTap: _showDailyQuestsDialog)),
|
||||||
|
Expanded(child: _MusicKnobCard(title: loc.themesTitle, icon: FontAwesomeIcons.palette, themeType: themeType, onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const SettingsScreen())))),
|
||||||
|
Expanded(child: _MusicKnobCard(title: loc.tutorialTitle, icon: FontAwesomeIcons.bookOpen, themeType: themeType, onTap: _showTutorialDialog)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
] else ...[
|
||||||
|
// --- LISTA BOTTONI ORIGINALE ---
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -1395,6 +1427,7 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -1407,27 +1440,43 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||||
);
|
);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: bgImage != null ? Colors.transparent : theme.background,
|
backgroundColor: themeType == AppThemeType.doodle ? Colors.white : (bgImage != null ? Colors.transparent : theme.background),
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(color: theme.background),
|
Container(color: themeType == AppThemeType.doodle ? Colors.white : theme.background),
|
||||||
|
if (themeType == AppThemeType.doodle)
|
||||||
|
Positioned.fill(
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: FullScreenGridPainter(Colors.blue.withOpacity(0.15)),
|
||||||
|
),
|
||||||
|
),
|
||||||
if (bgImage != null)
|
if (bgImage != null)
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Image.asset(bgImage, fit: BoxFit.cover, alignment: Alignment.center),
|
child: Image.asset(bgImage, fit: BoxFit.cover, alignment: Alignment.center),
|
||||||
),
|
),
|
||||||
if (bgImage != null)
|
if (bgImage != null)
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: themeType == AppThemeType.cyberpunk
|
child: (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music)
|
||||||
? Container(
|
? Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
begin: Alignment.topCenter, end: Alignment.bottomCenter,
|
begin: Alignment.topCenter, end: Alignment.bottomCenter,
|
||||||
colors: [Colors.black.withOpacity(0.2), Colors.black.withOpacity(0.7)]
|
colors: [Colors.black.withOpacity(0.4), Colors.black.withOpacity(0.8)]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
if (themeType == AppThemeType.music)
|
||||||
|
Positioned.fill(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: _AudioCablesPainter(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
Positioned.fill(child: uiContent),
|
Positioned.fill(child: uiContent),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -1460,6 +1509,249 @@ class _TutorialStep extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- WIDGETS SPECIFICI TEMA MUSICA ---
|
||||||
|
|
||||||
|
class _MusicCassetteCard extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String subtitle;
|
||||||
|
final Color neonColor;
|
||||||
|
final double angle;
|
||||||
|
final IconData leftIcon;
|
||||||
|
final IconData rightIcon;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final AppThemeType themeType;
|
||||||
|
|
||||||
|
const _MusicCassetteCard({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
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Transform.rotate(
|
||||||
|
angle: angle,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Container(
|
||||||
|
height: 120,
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 10),
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFF22222A), // Materic plastic
|
||||||
|
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(
|
||||||
|
children: [
|
||||||
|
// Cassette Label
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: neonColor.withOpacity(0.15),
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
border: Border.all(color: neonColor.withOpacity(0.5), width: 1.5),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Padding(padding: const EdgeInsets.symmetric(horizontal: 12), child: Icon(leftIcon, color: neonColor, size: 28)),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
FittedBox(fit: BoxFit.scaleDown, child: Text(title, style: _getTextStyle(themeType, TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.w900, shadows: [Shadow(color: neonColor, blurRadius: 10)])))),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
FittedBox(fit: BoxFit.scaleDown, child: Text(subtitle, style: _getTextStyle(themeType, const TextStyle(color: Colors.white70, fontSize: 12, fontWeight: FontWeight.bold)))),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(padding: const EdgeInsets.symmetric(horizontal: 12), child: Icon(rightIcon, color: neonColor, size: 28)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
// Spools window
|
||||||
|
Container(
|
||||||
|
height: 35,
|
||||||
|
width: 180,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFF0D0D12),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: Border.all(color: Colors.white24, width: 1),
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
// Tape line connecting spools
|
||||||
|
Container(height: 2, width: 120, color: const Color(0xFF333333)),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
_buildSpool(),
|
||||||
|
_buildSpool(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSpool() {
|
||||||
|
return Container(
|
||||||
|
width: 26, height: 26,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.white70,
|
||||||
|
border: Border.all(color: Colors.black87, width: 5)
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
width: 6, height: 6,
|
||||||
|
decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.black),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MusicKnobCard extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final IconData icon;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final AppThemeType themeType;
|
||||||
|
final Color? iconColor;
|
||||||
|
|
||||||
|
const _MusicKnobCard({required this.title, required this.icon, required this.onTap, required this.themeType, this.iconColor});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 65, height: 65,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: const Color(0xFF222222), // Base plastic
|
||||||
|
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(
|
||||||
|
padding: const EdgeInsets.all(6.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
gradient: const SweepGradient(
|
||||||
|
colors: [
|
||||||
|
Color(0xFF555555), Color(0xFFAAAAAA), Color(0xFF555555),
|
||||||
|
Color(0xFF222222), Color(0xFF555555)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
border: Border.all(color: Colors.black54, width: 1),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Color(0xFF1A1A1A),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Icon(icon, color: iconColor ?? Colors.white70, size: 20),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
FittedBox(
|
||||||
|
fit: BoxFit.scaleDown,
|
||||||
|
child: Text(title, style: _getTextStyle(themeType, const TextStyle(color: Colors.white70, fontSize: 11, fontWeight: FontWeight.bold, letterSpacing: 1.0))),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AudioCablesPainter extends CustomPainter {
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
final paint = Paint()
|
||||||
|
..color = const Color(0xFF151515)
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = 8.0
|
||||||
|
..strokeCap = StrokeCap.round;
|
||||||
|
|
||||||
|
final highlight = Paint()
|
||||||
|
..color = const Color(0xFF3A3A3A)
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = 2.0
|
||||||
|
..strokeCap = StrokeCap.round;
|
||||||
|
|
||||||
|
void drawCable(Path path) {
|
||||||
|
canvas.drawPath(path, paint);
|
||||||
|
canvas.drawPath(path, highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cable 1
|
||||||
|
Path c1 = Path()..moveTo(-20, size.height * 0.2)..quadraticBezierTo(100, size.height * 0.25, 50, size.height * 0.4)..quadraticBezierTo(0, size.height * 0.5, -20, size.height * 0.55);
|
||||||
|
drawCable(c1);
|
||||||
|
|
||||||
|
// Cable 2
|
||||||
|
Path c2 = Path()..moveTo(size.width + 20, size.height * 0.4)..quadraticBezierTo(size.width - 100, size.height * 0.5, size.width - 50, size.height * 0.7)..quadraticBezierTo(size.width, size.height * 0.8, size.width + 20, size.height * 0.85);
|
||||||
|
drawCable(c2);
|
||||||
|
|
||||||
|
// Cable 3 (bottom)
|
||||||
|
Path c3 = Path()..moveTo(size.width * 0.2, size.height + 20)..quadraticBezierTo(size.width * 0.3, size.height - 80, size.width * 0.5, size.height - 60)..quadraticBezierTo(size.width * 0.7, size.height - 40, size.width * 0.8, size.height + 20);
|
||||||
|
drawCable(c3);
|
||||||
|
|
||||||
|
// Jack connector
|
||||||
|
_drawJack(canvas, Offset(80, size.height * 0.38), -0.5);
|
||||||
|
_drawJack(canvas, Offset(size.width - 60, size.height * 0.68), 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawJack(Canvas canvas, Offset pos, double angle) {
|
||||||
|
canvas.save();
|
||||||
|
canvas.translate(pos.dx, pos.dy);
|
||||||
|
canvas.rotate(angle);
|
||||||
|
|
||||||
|
// Cable end
|
||||||
|
canvas.drawRect(const Rect.fromLTWH(-15, -4, 15, 8), Paint()..color = const Color(0xFF151515));
|
||||||
|
|
||||||
|
// Base plastic
|
||||||
|
canvas.drawRRect(RRect.fromRectAndRadius(const Rect.fromLTWH(0, -6, 25, 12), const Radius.circular(2)), Paint()..color = const Color(0xFF222222));
|
||||||
|
canvas.drawRRect(RRect.fromRectAndRadius(const Rect.fromLTWH(2, -4, 21, 8), const Radius.circular(2)), Paint()..color = const Color(0xFF444444));
|
||||||
|
|
||||||
|
// Metal pin
|
||||||
|
canvas.drawRect(const Rect.fromLTWH(25, -2, 15, 4), Paint()..color = const Color(0xFFCCCCCC));
|
||||||
|
canvas.drawRect(const Rect.fromLTWH(40, -1.5, 5, 3), Paint()..color = const Color(0xFFAAAAAA)); // tip
|
||||||
|
|
||||||
|
// Rings
|
||||||
|
canvas.drawLine(const Offset(30, -2), const Offset(30, 2), Paint()..color = Colors.black..strokeWidth = 1.5);
|
||||||
|
canvas.drawLine(const Offset(35, -2), const Offset(35, 2), Paint()..color = Colors.black..strokeWidth = 1.5);
|
||||||
|
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- WIDGETS STANDARD ---
|
||||||
|
|
||||||
class _FeatureCard extends StatelessWidget {
|
class _FeatureCard extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final String subtitle;
|
final String subtitle;
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,15 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||||
requiredLevel: 15,
|
requiredLevel: 15,
|
||||||
currentLevel: playerLevel,
|
currentLevel: playerLevel,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
_ThemeCard(
|
||||||
|
title: "Musica",
|
||||||
|
subtitle: "Vinili, cassette e vibrazioni sonore",
|
||||||
|
type: AppThemeType.music,
|
||||||
|
previewColors: AppColors.music,
|
||||||
|
requiredLevel: 20, // Tema Esclusivo di Livello 20!
|
||||||
|
currentLevel: playerLevel,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue