diff --git a/assets/images/arcade.jpg b/assets/images/arcade.jpg new file mode 100644 index 0000000..3ff7a53 Binary files /dev/null and b/assets/images/arcade.jpg differ diff --git a/lib/ui/game/game_screen.dart b/lib/ui/game/game_screen.dart index 8b93296..c98bd71 100644 --- a/lib/ui/game/game_screen.dart +++ b/lib/ui/game/game_screen.dart @@ -291,9 +291,10 @@ class _GameScreenState extends State with TickerProviderStateMixin { String? bgImage; if (themeType == AppThemeType.wood) bgImage = 'assets/images/wood_bg.jpg'; - if (themeType == AppThemeType.doodle) bgImage = 'assets/images/doodle_bg.jpg'; // Questo è lo sfondo carta + 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'; + if (themeType == AppThemeType.arcade) bgImage = 'assets/images/arcade.jpg'; // <-- SFONDO ARCADE AGGIUNTO Color indicatorColor = themeType == AppThemeType.cyberpunk || themeType == AppThemeType.arcade || themeType == AppThemeType.music ? Colors.white : Colors.black; @@ -429,23 +430,13 @@ class _GameScreenState extends State with TickerProviderStateMixin { canPop: true, onPopInvoked: (didPop) { gameController.disconnectOnlineGame(); }, child: Scaffold( - backgroundColor: Colors.transparent, // Assicuriamo che la scaffold base sia trasparente + backgroundColor: themeType == AppThemeType.doodle ? Colors.white : (bgImage != null ? Colors.transparent : theme.background), body: Stack( children: [ - // 1. Sfondo base a tinta unita (In caso non ci sia l'immagine) + // 1. Sfondo base a tinta unita Container(color: themeType == AppThemeType.doodle ? Colors.white : theme.background), - // 2. Immagine di Sfondo per tutti i temi che la supportano - if (bgImage != null) - Positioned.fill( - child: Image.asset( - bgImage, - fit: BoxFit.cover, - alignment: Alignment.center, - ), - ), - - // 3. Griglia a righe incrociate per il doodle (Sopra l'immagine di carta) + // 2. Griglia a quadretti (Doodle Theme) if (themeType == AppThemeType.doodle) Positioned.fill( child: CustomPaint( @@ -453,8 +444,20 @@ class _GameScreenState extends State with TickerProviderStateMixin { ), ), - // 4. Patina scura (Cyberpunk e Music) per far risaltare il neon - if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music)) + // 3. Immagine di Sfondo + if (bgImage != null) + Positioned.fill( + child: Image.asset( + bgImage, + fit: BoxFit.cover, + alignment: Alignment.center, + color: themeType == AppThemeType.doodle ? Colors.white.withOpacity(0.5) : null, + colorBlendMode: themeType == AppThemeType.doodle ? BlendMode.lighten : null, + ), + ), + + // 4. Patina scura (Cyberpunk, Music, Arcade) + if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music || themeType == AppThemeType.arcade)) Positioned.fill( child: Container( decoration: BoxDecoration( diff --git a/lib/ui/home/home_screen.dart b/lib/ui/home/home_screen.dart index 503a27a..f7f9a48 100644 --- a/lib/ui/home/home_screen.dart +++ b/lib/ui/home/home_screen.dart @@ -6,7 +6,6 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/foundation.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'dart:async'; @@ -29,321 +28,9 @@ import '../../widgets/painters.dart'; import '../../widgets/cyber_border.dart'; import '../../widgets/music_theme_widgets.dart'; import '../../widgets/home_buttons.dart'; +import '../../widgets/custom_settings_button.dart'; // <--- IMPORTIAMO I NOSTRI BOTTONI import 'dialog.dart'; -// =========================================================================== -// WIDGET LOCALI PER IL SETUP DELLA PARTITA -// =========================================================================== -class _NeonShapeButton extends StatelessWidget { - final IconData icon; final String label; final bool isSelected; - final ThemeColors theme; final AppThemeType themeType; final VoidCallback onTap; - final bool isLocked; final bool isSpecial; - - const _NeonShapeButton({required this.icon, required this.label, required this.isSelected, required this.theme, required this.themeType, required this.onTap, this.isLocked = false, this.isSpecial = false}); - - Color _getDoodleColor() { - switch (label) { - case 'Rombo': return Colors.lightBlue.shade200; - case 'Croce': return Colors.green.shade200; - case 'Buco': return Colors.pink.shade200; - case 'Clessidra': return Colors.purple.shade200; - case 'Caos': return Colors.grey.shade300; - default: return Colors.lightBlue.shade200; - } - } - - @override - Widget build(BuildContext context) { - if (themeType == AppThemeType.doodle) { - Color doodleColor = isLocked ? Colors.grey : _getDoodleColor(); - Color inkColor = const Color(0xFF111122); - double tilt = (label.length % 2 == 0) ? -0.05 : 0.04; - - return Transform.rotate( - angle: tilt, - child: GestureDetector( - onTap: isLocked ? null : onTap, - child: CustomPaint( - painter: DoodleBackgroundPainter(fillColor: isSelected ? doodleColor : Colors.white.withOpacity(0.8), strokeColor: inkColor, seed: label.length * 3), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(isLocked ? Icons.lock : icon, color: inkColor, size: 24), - const SizedBox(height: 2), - Text(isLocked ? "Liv. 10" : label, style: getSharedTextStyle(themeType, TextStyle(color: inkColor, fontSize: 11, fontWeight: FontWeight.w900, letterSpacing: 0.5))), - ], - ), - ), - ), - ), - ); - } - - Color mainColor = isSpecial && !isLocked ? Colors.purpleAccent : theme.playerBlue; - return GestureDetector( - onTap: isLocked ? null : onTap, - child: AnimatedContainer( - duration: const Duration(milliseconds: 250), curve: Curves.easeOutCubic, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), transform: Matrix4.translationValues(0, isSelected ? 2 : 0, 0), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), border: Border.all(color: isLocked ? Colors.transparent : (isSelected ? mainColor : Colors.white.withOpacity(0.1)), width: isSelected ? 2 : 1), - gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isLocked ? [Colors.grey.withOpacity(0.1), Colors.black.withOpacity(0.2)] : isSelected ? [mainColor.withOpacity(0.3), mainColor.withOpacity(0.1)] : [theme.text.withOpacity(0.1), theme.text.withOpacity(0.02)]), - boxShadow: isLocked ? [] : isSelected ? [BoxShadow(color: mainColor.withOpacity(0.5), blurRadius: 15, spreadRadius: 1, offset: const Offset(0, 0))] : [BoxShadow(color: Colors.black.withOpacity(0.4), blurRadius: 6, offset: const Offset(2, 4)), BoxShadow(color: Colors.white.withOpacity(0.05), blurRadius: 2, offset: const Offset(-1, -1))], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(isLocked ? Icons.lock : icon, color: isLocked ? Colors.grey.withOpacity(0.5) : (isSelected ? Colors.white : theme.text.withOpacity(0.6)), size: 24), - const SizedBox(height: 6), - Text(isLocked ? "Liv. 10" : label, style: getSharedTextStyle(themeType, TextStyle(color: isLocked ? Colors.grey.withOpacity(0.5) : (isSelected ? Colors.white : theme.text.withOpacity(0.6)), fontSize: 11, fontWeight: isSelected ? FontWeight.w900 : FontWeight.bold))), - ], - ), - ), - ); - } -} - -class _NeonSizeButton extends StatelessWidget { - final String label; final bool isSelected; final ThemeColors theme; final AppThemeType themeType; final VoidCallback onTap; - const _NeonSizeButton({required this.label, required this.isSelected, required this.theme, required this.themeType, required this.onTap}); - - @override - Widget build(BuildContext context) { - if (themeType == AppThemeType.doodle) { - Color doodleColor = label == 'MAX' ? Colors.red.shade200 : Colors.cyan.shade100; Color inkColor = const Color(0xFF111122); double tilt = (label == 'M' || label == 'MAX') ? 0.05 : -0.04; - return Transform.rotate( - angle: tilt, - child: GestureDetector( - onTap: onTap, - child: CustomPaint(painter: DoodleBackgroundPainter(fillColor: isSelected ? doodleColor : Colors.white.withOpacity(0.8), strokeColor: inkColor, seed: label.codeUnitAt(0), isCircle: true), child: SizedBox(width: 50, height: 50, child: Center(child: Text(label, style: getSharedTextStyle(themeType, TextStyle(color: inkColor, fontSize: 18, fontWeight: FontWeight.w900)))))), - ), - ); - } - return GestureDetector( - onTap: onTap, - child: AnimatedContainer( - duration: const Duration(milliseconds: 250), curve: Curves.easeOutCubic, width: 50, height: 50, transform: Matrix4.translationValues(0, isSelected ? 2 : 0, 0), - decoration: BoxDecoration( - shape: BoxShape.circle, border: Border.all(color: isSelected ? theme.playerRed : Colors.white.withOpacity(0.1), width: isSelected ? 2 : 1), - gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isSelected ? [theme.playerRed.withOpacity(0.3), theme.playerRed.withOpacity(0.1)] : [theme.text.withOpacity(0.1), theme.text.withOpacity(0.02)]), - boxShadow: isSelected ? [BoxShadow(color: theme.playerRed.withOpacity(0.5), blurRadius: 15, spreadRadius: 1)] : [BoxShadow(color: Colors.black.withOpacity(0.4), blurRadius: 6, offset: const Offset(2, 4)), BoxShadow(color: Colors.white.withOpacity(0.05), blurRadius: 2, offset: const Offset(-1, -1))], - ), - child: Center(child: Text(label, style: getSharedTextStyle(themeType, TextStyle(color: isSelected ? Colors.white : theme.text.withOpacity(0.6), fontSize: 14, fontWeight: isSelected ? FontWeight.w900 : FontWeight.bold)))), - ), - ); - } -} - -class _NeonTimeSwitch extends StatelessWidget { - final bool isTimeMode; final ThemeColors theme; final AppThemeType themeType; final VoidCallback onTap; - const _NeonTimeSwitch({required this.isTimeMode, required this.theme, required this.themeType, required this.onTap}); - - @override - Widget build(BuildContext context) { - if (themeType == AppThemeType.doodle) { - Color doodleColor = Colors.orange.shade200; Color inkColor = const Color(0xFF111122); - return Transform.rotate( - angle: -0.015, - child: GestureDetector( - onTap: onTap, - child: CustomPaint( - painter: DoodleBackgroundPainter(fillColor: isTimeMode ? doodleColor : Colors.white.withOpacity(0.8), strokeColor: inkColor, seed: 42), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), - child: Row( - mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(isTimeMode ? Icons.timer : Icons.timer_off, color: inkColor, size: 28), const SizedBox(width: 12), - Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [Text(isTimeMode ? 'A TEMPO' : 'RELAX', style: getSharedTextStyle(themeType, TextStyle(color: inkColor, fontWeight: FontWeight.w900, fontSize: 16, letterSpacing: 2.0))), Text(isTimeMode ? '15 sec a mossa' : 'Nessun limite', style: getSharedTextStyle(themeType, TextStyle(color: inkColor.withOpacity(0.8), fontSize: 13, fontWeight: FontWeight.bold)))]), - ], - ), - ), - ), - ), - ); - } - return GestureDetector( - onTap: onTap, - child: AnimatedContainer( - duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), border: Border.all(color: isTimeMode ? Colors.amber : Colors.white.withOpacity(0.1), width: isTimeMode ? 2 : 1), - gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isTimeMode ? [Colors.amber.withOpacity(0.25), Colors.amber.withOpacity(0.05)] : [theme.text.withOpacity(0.1), theme.text.withOpacity(0.02)]), - boxShadow: isTimeMode ? [BoxShadow(color: Colors.amber.withOpacity(0.3), blurRadius: 15, spreadRadius: 2)] : [BoxShadow(color: Colors.black.withOpacity(0.4), blurRadius: 6, offset: const Offset(2, 4)), BoxShadow(color: Colors.white.withOpacity(0.05), blurRadius: 2, offset: const Offset(-1, -1))], - ), - child: Row( - mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(isTimeMode ? Icons.timer : Icons.timer_off, color: isTimeMode ? Colors.amber : theme.text.withOpacity(0.5), size: 28), const SizedBox(width: 12), - Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [Text(isTimeMode ? 'A TEMPO' : 'RELAX', style: getSharedTextStyle(themeType, TextStyle(color: isTimeMode ? Colors.white : theme.text.withOpacity(0.5), fontWeight: FontWeight.w900, fontSize: 14, letterSpacing: 1.5))), Text(isTimeMode ? '15 sec a mossa' : 'Nessun limite', style: getSharedTextStyle(themeType, TextStyle(color: isTimeMode ? Colors.amber.shade200 : theme.text.withOpacity(0.4), fontSize: 11, fontWeight: FontWeight.bold)))]), - ], - ), - ), - ); - } -} - -class _NeonPrivacySwitch extends StatelessWidget { - final bool isPublic; - final ThemeColors theme; - final AppThemeType themeType; - final VoidCallback onTap; - - const _NeonPrivacySwitch({required this.isPublic, required this.theme, required this.themeType, required this.onTap}); - - @override - Widget build(BuildContext context) { - if (themeType == AppThemeType.doodle) { - Color doodleColor = isPublic ? Colors.green.shade600 : Colors.red.shade600; - return Transform.rotate( - angle: 0.015, - child: GestureDetector( - onTap: onTap, - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - transform: Matrix4.translationValues(0, isPublic ? 3 : 0, 0), - decoration: BoxDecoration( - color: isPublic ? doodleColor : Colors.white, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(15), topRight: Radius.circular(8), - bottomLeft: Radius.circular(6), bottomRight: Radius.circular(15), - ), - border: Border.all(color: isPublic ? theme.text : doodleColor.withOpacity(0.5), width: 2.5), - boxShadow: [BoxShadow(color: isPublic ? theme.text.withOpacity(0.8) : doodleColor.withOpacity(0.2), offset: const Offset(4, 5), blurRadius: 0)], - ), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(isPublic ? Icons.public : Icons.lock, color: isPublic ? Colors.white : doodleColor, size: 20), - const SizedBox(width: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text(isPublic ? 'PUBBLICA' : 'PRIVATA', style: getSharedTextStyle(themeType, TextStyle(color: isPublic ? Colors.white : doodleColor, fontWeight: FontWeight.w900, fontSize: 12, letterSpacing: 1.0))), - Text(isPublic ? 'In Bacheca' : 'Solo Codice', style: getSharedTextStyle(themeType, TextStyle(color: isPublic ? Colors.white : doodleColor.withOpacity(0.8), fontSize: 9, fontWeight: FontWeight.bold))), - ], - ), - ], - ), - ), - ), - ); - } - - return GestureDetector( - onTap: onTap, - child: AnimatedContainer( - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: isPublic - ? [Colors.greenAccent.withOpacity(0.25), Colors.greenAccent.withOpacity(0.05)] - : [theme.playerRed.withOpacity(0.25), theme.playerRed.withOpacity(0.05)], - ), - border: Border.all(color: isPublic ? Colors.greenAccent : theme.playerRed, width: isPublic ? 2 : 1), - boxShadow: isPublic - ? [BoxShadow(color: Colors.greenAccent.withOpacity(0.3), blurRadius: 15, spreadRadius: 2)] - : [BoxShadow(color: Colors.black.withOpacity(0.4), blurRadius: 6, offset: const Offset(2, 4))], - ), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(isPublic ? Icons.public : Icons.lock, color: isPublic ? Colors.greenAccent : theme.playerRed, size: 20), - const SizedBox(width: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text(isPublic ? 'PUBBLICA' : 'PRIVATA', style: getSharedTextStyle(themeType, TextStyle(color: isPublic ? Colors.white : theme.text.withOpacity(0.8), fontWeight: FontWeight.w900, fontSize: 11, letterSpacing: 1.5))), - Text(isPublic ? 'Tutti ti vedono' : 'Solo con Codice', style: getSharedTextStyle(themeType, TextStyle(color: isPublic ? Colors.greenAccent.shade200 : theme.playerRed.withOpacity(0.7), fontSize: 9, fontWeight: FontWeight.bold))), - ], - ), - ], - ), - ), - ); - } -} - -class _NeonActionButton extends StatelessWidget { - final String label; - final Color color; - final VoidCallback onTap; - final ThemeColors theme; - final AppThemeType themeType; - - const _NeonActionButton({required this.label, required this.color, required this.onTap, required this.theme, required this.themeType}); - - @override - Widget build(BuildContext context) { - if (themeType == AppThemeType.doodle) { - double tilt = (label == "UNISCITI" || label == "ANNULLA") ? -0.015 : 0.02; - return Transform.rotate( - angle: tilt, - child: GestureDetector( - onTap: onTap, - child: Container( - height: 50, - decoration: BoxDecoration( - color: color, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(10), topRight: Radius.circular(20), - bottomLeft: Radius.circular(25), bottomRight: Radius.circular(10), - ), - border: Border.all(color: theme.text, width: 3.0), - boxShadow: [BoxShadow(color: theme.text.withOpacity(0.9), offset: const Offset(4, 4), blurRadius: 0)], - ), - child: Center( - child: FittedBox( - fit: BoxFit.scaleDown, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Text(label, style: getSharedTextStyle(themeType, TextStyle(fontSize: 20, fontWeight: FontWeight.w900, letterSpacing: 3.0, color: Colors.white))), - ), - ), - ), - ), - ), - ); - } - - return GestureDetector( - onTap: onTap, - child: Container( - height: 50, - decoration: BoxDecoration( - gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [color.withOpacity(0.9), color.withOpacity(0.6)]), - borderRadius: BorderRadius.circular(15), - border: Border.all(color: Colors.white.withOpacity(0.3), width: 1.5), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.5), offset: const Offset(4, 8), blurRadius: 12), - BoxShadow(color: color.withOpacity(0.3), offset: const Offset(0, 0), blurRadius: 15, spreadRadius: 1), - ], - ), - child: Center( - child: FittedBox( - fit: BoxFit.scaleDown, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Text(label, style: getSharedTextStyle(themeType, TextStyle(fontSize: 16, fontWeight: FontWeight.w900, letterSpacing: 2.0, color: Colors.white, shadows: const [Shadow(color: Colors.black, blurRadius: 2, offset: Offset(1, 1))]))), - ), - ), - ), - ), - ); - } -} - // =========================================================================== // CLASSE PRINCIPALE HOME // =========================================================================== @@ -765,11 +452,11 @@ class _HomeScreenState extends State with WidgetsBindingObserver { Wrap( spacing: 12, runSpacing: 12, alignment: WrapAlignment.center, children: [ - _NeonShapeButton(icon: Icons.diamond_outlined, label: 'Rombo', isSelected: localShape == ArenaShape.classic, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.classic)), - _NeonShapeButton(icon: Icons.add, label: 'Croce', isSelected: localShape == ArenaShape.cross, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.cross)), - _NeonShapeButton(icon: Icons.donut_large, label: 'Buco', isSelected: localShape == ArenaShape.donut, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.donut)), - _NeonShapeButton(icon: Icons.hourglass_bottom, label: 'Clessidra', isSelected: localShape == ArenaShape.hourglass, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.hourglass)), - _NeonShapeButton(icon: Icons.all_inclusive, label: 'Caos', isSelected: localShape == ArenaShape.chaos, theme: theme, themeType: themeType, isSpecial: true, isLocked: !isChaosUnlocked, onTap: () => setStateDialog(() => localShape = ArenaShape.chaos)), + NeonShapeButton(icon: Icons.diamond_outlined, label: 'Rombo', isSelected: localShape == ArenaShape.classic, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.classic)), + NeonShapeButton(icon: Icons.add, label: 'Croce', isSelected: localShape == ArenaShape.cross, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.cross)), + NeonShapeButton(icon: Icons.donut_large, label: 'Buco', isSelected: localShape == ArenaShape.donut, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.donut)), + NeonShapeButton(icon: Icons.hourglass_bottom, label: 'Clessidra', isSelected: localShape == ArenaShape.hourglass, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.hourglass)), + NeonShapeButton(icon: Icons.all_inclusive, label: 'Caos', isSelected: localShape == ArenaShape.chaos, theme: theme, themeType: themeType, isSpecial: true, isLocked: !isChaosUnlocked, onTap: () => setStateDialog(() => localShape = ArenaShape.chaos)), ], ), const SizedBox(height: 25), Divider(color: inkColor.withOpacity(0.3), thickness: 2.5), const SizedBox(height: 20), @@ -778,17 +465,17 @@ class _HomeScreenState extends State with WidgetsBindingObserver { Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - _NeonSizeButton(label: 'S', isSelected: localRadius == 3, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 3)), - _NeonSizeButton(label: 'M', isSelected: localRadius == 4, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 4)), - _NeonSizeButton(label: 'L', isSelected: localRadius == 5, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 5)), - _NeonSizeButton(label: 'MAX', isSelected: localRadius == 6, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 6)), + NeonSizeButton(label: 'S', isSelected: localRadius == 3, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 3)), + NeonSizeButton(label: 'M', isSelected: localRadius == 4, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 4)), + NeonSizeButton(label: 'L', isSelected: localRadius == 5, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 5)), + NeonSizeButton(label: 'MAX', isSelected: localRadius == 6, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 6)), ], ), const SizedBox(height: 25), Divider(color: inkColor.withOpacity(0.3), thickness: 2.5), const SizedBox(height: 20), ], Text("TEMPO", style: getSharedTextStyle(themeType, TextStyle(fontSize: 14, fontWeight: FontWeight.w900, color: inkColor.withOpacity(0.6), letterSpacing: 1.5))), const SizedBox(height: 10), - _NeonTimeSwitch(isTimeMode: localTimeMode, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localTimeMode = !localTimeMode)), const SizedBox(height: 35), + NeonTimeSwitch(isTimeMode: localTimeMode, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localTimeMode = !localTimeMode)), const SizedBox(height: 35), Transform.rotate( angle: -0.02, @@ -829,11 +516,11 @@ class _HomeScreenState extends State with WidgetsBindingObserver { Wrap( spacing: 10, runSpacing: 10, alignment: WrapAlignment.center, children: [ - _NeonShapeButton(icon: Icons.diamond_outlined, label: 'Rombo', isSelected: localShape == ArenaShape.classic, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.classic)), - _NeonShapeButton(icon: Icons.add, label: 'Croce', isSelected: localShape == ArenaShape.cross, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.cross)), - _NeonShapeButton(icon: Icons.donut_large, label: 'Buco', isSelected: localShape == ArenaShape.donut, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.donut)), - _NeonShapeButton(icon: Icons.hourglass_bottom, label: 'Clessidra', isSelected: localShape == ArenaShape.hourglass, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.hourglass)), - _NeonShapeButton(icon: Icons.all_inclusive, label: 'Caos', isSelected: localShape == ArenaShape.chaos, theme: theme, themeType: themeType, isSpecial: true, isLocked: !isChaosUnlocked, onTap: () => setStateDialog(() => localShape = ArenaShape.chaos)), + NeonShapeButton(icon: Icons.diamond_outlined, label: 'Rombo', isSelected: localShape == ArenaShape.classic, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.classic)), + NeonShapeButton(icon: Icons.add, label: 'Croce', isSelected: localShape == ArenaShape.cross, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.cross)), + NeonShapeButton(icon: Icons.donut_large, label: 'Buco', isSelected: localShape == ArenaShape.donut, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.donut)), + NeonShapeButton(icon: Icons.hourglass_bottom, label: 'Clessidra', isSelected: localShape == ArenaShape.hourglass, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localShape = ArenaShape.hourglass)), + NeonShapeButton(icon: Icons.all_inclusive, label: 'Caos', isSelected: localShape == ArenaShape.chaos, theme: theme, themeType: themeType, isSpecial: true, isLocked: !isChaosUnlocked, onTap: () => setStateDialog(() => localShape = ArenaShape.chaos)), ], ), const SizedBox(height: 20), Divider(color: Colors.white.withOpacity(0.05), thickness: 2), const SizedBox(height: 20), @@ -842,17 +529,17 @@ class _HomeScreenState extends State with WidgetsBindingObserver { Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - _NeonSizeButton(label: 'S', isSelected: localRadius == 3, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 3)), - _NeonSizeButton(label: 'M', isSelected: localRadius == 4, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 4)), - _NeonSizeButton(label: 'L', isSelected: localRadius == 5, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 5)), - _NeonSizeButton(label: 'MAX', isSelected: localRadius == 6, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 6)), + NeonSizeButton(label: 'S', isSelected: localRadius == 3, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 3)), + NeonSizeButton(label: 'M', isSelected: localRadius == 4, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 4)), + NeonSizeButton(label: 'L', isSelected: localRadius == 5, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 5)), + NeonSizeButton(label: 'MAX', isSelected: localRadius == 6, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localRadius = 6)), ], ), const SizedBox(height: 20), Divider(color: Colors.white.withOpacity(0.05), thickness: 2), const SizedBox(height: 20), ], Text("TEMPO", style: getSharedTextStyle(themeType, TextStyle(fontSize: 12, fontWeight: FontWeight.w900, color: theme.text.withOpacity(0.5), letterSpacing: 1.5))), const SizedBox(height: 10), - _NeonTimeSwitch(isTimeMode: localTimeMode, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localTimeMode = !localTimeMode)), const SizedBox(height: 30), + NeonTimeSwitch(isTimeMode: localTimeMode, theme: theme, themeType: themeType, onTap: () => setStateDialog(() => localTimeMode = !localTimeMode)), const SizedBox(height: 30), SizedBox( width: double.infinity, height: 60, @@ -905,6 +592,7 @@ class _HomeScreenState extends State with WidgetsBindingObserver { 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'; + if (themeType == AppThemeType.arcade) bgImage = 'assets/images/arcade.jpg'; int wins = StorageService.instance.wins; int losses = StorageService.instance.losses; @@ -933,7 +621,7 @@ class _HomeScreenState extends State with WidgetsBindingObserver { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - // BLOCCO SINISTRO: AVATAR, NOME E AUDIO + // BLOCCO SINISTRO: AVATAR E NOME Expanded( // Permette di occupare lo spazio necessario senza spingere la destra child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -979,7 +667,7 @@ class _HomeScreenState extends State with WidgetsBindingObserver { ), ), - // BLOCCO DESTRO: STATISTICHE (SOPRA) E AUDIO (SOTTO) + // BLOCCO DESTRO: STATISTICHE E AUDIO Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ @@ -1199,8 +887,8 @@ class _HomeScreenState extends State with WidgetsBindingObserver { ), ), - // 4. Patina scura (Cyberpunk e Music) - if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music)) + // 4. Patina scura (Cyberpunk, Music e Arcade) + if (bgImage != null && (themeType == AppThemeType.cyberpunk || themeType == AppThemeType.music || themeType == AppThemeType.arcade)) Positioned.fill( child: Container( decoration: BoxDecoration( diff --git a/lib/widgets/custom_settings_button.dart b/lib/widgets/custom_settings_button.dart index b24af75..2574354 100644 --- a/lib/widgets/custom_settings_button.dart +++ b/lib/widgets/custom_settings_button.dart @@ -1,64 +1,74 @@ +// =========================================================================== +// FILE: lib/widgets/custom_settings_button.dart +// =========================================================================== + import 'package:flutter/material.dart'; -import '../theme/app_colors.dart'; +import '../core/app_colors.dart'; +import 'painters.dart'; // Importiamo i painter per i doodle e il font -// Widget per i pulsanti di selezione della forma dell'arena class NeonShapeButton extends StatelessWidget { - final IconData icon; - final String label; - final bool isSelected; - final VoidCallback onTap; - final ShapeBorder shape; // La forma geometrica del pulsante + final IconData icon; final String label; final bool isSelected; + final ThemeColors theme; final AppThemeType themeType; final VoidCallback onTap; + final bool isLocked; final bool isSpecial; - const NeonShapeButton({ - super.key, - required this.icon, - required this.label, - required this.isSelected, - required this.onTap, - this.shape = const RoundedRectangleBorder( // Forma di default - borderRadius: BorderRadius.all(Radius.circular(12.0))), - }); + const NeonShapeButton({super.key, required this.icon, required this.label, required this.isSelected, required this.theme, required this.themeType, required this.onTap, this.isLocked = false, this.isSpecial = false}); + + Color _getDoodleColor() { + switch (label) { + case 'Rombo': return Colors.lightBlue.shade200; + case 'Croce': return Colors.green.shade200; + case 'Buco': return Colors.pink.shade200; + case 'Clessidra': return Colors.purple.shade200; + case 'Caos': return Colors.grey.shade300; + default: return Colors.lightBlue.shade200; + } + } @override Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: AnimatedContainer( - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: ShapeDecoration( - shape: shape, - color: isSelected - ? AppColors.neonGreen.withOpacity(0.2) // Sfondo luminoso se selezionato - : AppColors.surface.withOpacity(0.5), // Sfondo più scuro se non selezionato - shadows: isSelected - ? [ // Bagliore intenso se selezionato - BoxShadow( - color: AppColors.neonGreen.withOpacity(0.6), - blurRadius: 12.0, - spreadRadius: 2.0, + if (themeType == AppThemeType.doodle) { + Color doodleColor = isLocked ? Colors.grey : _getDoodleColor(); + Color inkColor = const Color(0xFF111122); + double tilt = (label.length % 2 == 0) ? -0.05 : 0.04; + + return Transform.rotate( + angle: tilt, + child: GestureDetector( + onTap: isLocked ? null : onTap, + child: CustomPaint( + painter: DoodleBackgroundPainter(fillColor: isSelected ? doodleColor : Colors.white.withOpacity(0.8), strokeColor: inkColor, seed: label.length * 3), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(isLocked ? Icons.lock : icon, color: inkColor, size: 24), + const SizedBox(height: 2), + Text(isLocked ? "Liv. 10" : label, style: getSharedTextStyle(themeType, TextStyle(color: inkColor, fontSize: 11, fontWeight: FontWeight.w900, letterSpacing: 0.5))), + ], + ), ), - ] - : [], + ), + ), + ); + } + + Color mainColor = isSpecial && !isLocked ? Colors.purpleAccent : theme.playerBlue; + return GestureDetector( + onTap: isLocked ? null : onTap, + child: AnimatedContainer( + duration: const Duration(milliseconds: 250), curve: Curves.easeOutCubic, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), transform: Matrix4.translationValues(0, isSelected ? 2 : 0, 0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), border: Border.all(color: isLocked ? Colors.transparent : (isSelected ? mainColor : Colors.white.withOpacity(0.1)), width: isSelected ? 2 : 1), + gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isLocked ? [Colors.grey.withOpacity(0.1), Colors.black.withOpacity(0.2)] : isSelected ? [mainColor.withOpacity(0.3), mainColor.withOpacity(0.1)] : [theme.text.withOpacity(0.1), theme.text.withOpacity(0.02)]), + boxShadow: isLocked ? [] : isSelected ? [BoxShadow(color: mainColor.withOpacity(0.5), blurRadius: 15, spreadRadius: 1, offset: const Offset(0, 0))] : [BoxShadow(color: Colors.black.withOpacity(0.4), blurRadius: 6, offset: const Offset(2, 4)), BoxShadow(color: Colors.white.withOpacity(0.05), blurRadius: 2, offset: const Offset(-1, -1))], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ - Icon( - icon, - color: isSelected ? AppColors.neonGreen : AppColors.textSecondary, - size: 28, - ), - const SizedBox(height: 4), - Text( - label, - style: TextStyle( - color: isSelected ? AppColors.textPrimary : AppColors.textSecondary, - fontSize: 12, - fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, - ), - ), + Icon(isLocked ? Icons.lock : icon, color: isLocked ? Colors.grey.withOpacity(0.5) : (isSelected ? Colors.white : theme.text.withOpacity(0.6)), size: 24), + const SizedBox(height: 6), + Text(isLocked ? "Liv. 10" : label, style: getSharedTextStyle(themeType, TextStyle(color: isLocked ? Colors.grey.withOpacity(0.5) : (isSelected ? Colors.white : theme.text.withOpacity(0.6)), fontSize: 11, fontWeight: isSelected ? FontWeight.w900 : FontWeight.bold))), ], ), ), @@ -66,118 +76,242 @@ class NeonShapeButton extends StatelessWidget { } } -// Widget per i pulsanti di selezione della taglia dell'arena class NeonSizeButton extends StatelessWidget { - final String label; - final bool isSelected; - final VoidCallback onTap; - - const NeonSizeButton({ - super.key, - required this.label, - required this.isSelected, - required this.onTap, - }); + final String label; final bool isSelected; final ThemeColors theme; final AppThemeType themeType; final VoidCallback onTap; + const NeonSizeButton({super.key, required this.label, required this.isSelected, required this.theme, required this.themeType, required this.onTap}); @override Widget build(BuildContext context) { + if (themeType == AppThemeType.doodle) { + Color doodleColor = label == 'MAX' ? Colors.red.shade200 : Colors.cyan.shade100; Color inkColor = const Color(0xFF111122); double tilt = (label == 'M' || label == 'MAX') ? 0.05 : -0.04; + return Transform.rotate( + angle: tilt, + child: GestureDetector( + onTap: onTap, + child: CustomPaint(painter: DoodleBackgroundPainter(fillColor: isSelected ? doodleColor : Colors.white.withOpacity(0.8), strokeColor: inkColor, seed: label.codeUnitAt(0), isCircle: true), child: SizedBox(width: 50, height: 50, child: Center(child: Text(label, style: getSharedTextStyle(themeType, TextStyle(color: inkColor, fontSize: 18, fontWeight: FontWeight.w900)))))), + ), + ); + } return GestureDetector( onTap: onTap, child: AnimatedContainer( - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - width: 50, - height: 50, + duration: const Duration(milliseconds: 250), curve: Curves.easeOutCubic, width: 50, height: 50, transform: Matrix4.translationValues(0, isSelected ? 2 : 0, 0), decoration: BoxDecoration( - shape: BoxShape.circle, // Forma circolare - color: isSelected - ? AppColors.neonBlue.withOpacity(0.2) - : AppColors.surface.withOpacity(0.5), - border: Border.all( - color: isSelected ? AppColors.neonBlue : AppColors.surfaceLight, - width: 2.0, - ), - shadows: isSelected - ? [ - BoxShadow( - color: AppColors.neonBlue.withOpacity(0.6), - blurRadius: 10.0, - spreadRadius: 1.5, - ), - ] - : [], - ), - child: Center( - child: Text( - label, - style: TextStyle( - color: isSelected ? AppColors.textPrimary : AppColors.textSecondary, - fontSize: 16, - fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, - ), - ), + shape: BoxShape.circle, border: Border.all(color: isSelected ? theme.playerRed : Colors.white.withOpacity(0.1), width: isSelected ? 2 : 1), + gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isSelected ? [theme.playerRed.withOpacity(0.3), theme.playerRed.withOpacity(0.1)] : [theme.text.withOpacity(0.1), theme.text.withOpacity(0.02)]), + boxShadow: isSelected ? [BoxShadow(color: theme.playerRed.withOpacity(0.5), blurRadius: 15, spreadRadius: 1)] : [BoxShadow(color: Colors.black.withOpacity(0.4), blurRadius: 6, offset: const Offset(2, 4)), BoxShadow(color: Colors.white.withOpacity(0.05), blurRadius: 2, offset: const Offset(-1, -1))], ), + child: Center(child: Text(label, style: getSharedTextStyle(themeType, TextStyle(color: isSelected ? Colors.white : theme.text.withOpacity(0.6), fontSize: 14, fontWeight: isSelected ? FontWeight.w900 : FontWeight.bold)))), ), ); } } -// Widget per l'interruttore della modalità tempo (Clessidra) class NeonTimeSwitch extends StatelessWidget { - final bool isTimeMode; - final VoidCallback onTap; - - const NeonTimeSwitch({ - super.key, - required this.isTimeMode, - required this.onTap, - }); + final bool isTimeMode; final ThemeColors theme; final AppThemeType themeType; final VoidCallback onTap; + const NeonTimeSwitch({super.key, required this.isTimeMode, required this.theme, required this.themeType, required this.onTap}); @override Widget build(BuildContext context) { + if (themeType == AppThemeType.doodle) { + Color doodleColor = Colors.orange.shade200; Color inkColor = const Color(0xFF111122); + return Transform.rotate( + angle: -0.015, + child: GestureDetector( + onTap: onTap, + child: CustomPaint( + painter: DoodleBackgroundPainter(fillColor: isTimeMode ? doodleColor : Colors.white.withOpacity(0.8), strokeColor: inkColor, seed: 42), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), + child: Row( + mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(isTimeMode ? Icons.timer : Icons.timer_off, color: inkColor, size: 28), const SizedBox(width: 12), + Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [Text(isTimeMode ? 'A TEMPO' : 'RELAX', style: getSharedTextStyle(themeType, TextStyle(color: inkColor, fontWeight: FontWeight.w900, fontSize: 16, letterSpacing: 2.0))), Text(isTimeMode ? '15 sec a mossa' : 'Nessun limite', style: getSharedTextStyle(themeType, TextStyle(color: inkColor.withOpacity(0.8), fontSize: 13, fontWeight: FontWeight.bold)))]), + ], + ), + ), + ), + ), + ); + } return GestureDetector( onTap: onTap, child: AnimatedContainer( - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), + duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30.0), // Forma arrotondata per lo switch - color: isTimeMode - ? AppColors.neonGreen.withOpacity(0.2) - : AppColors.surface.withOpacity(0.5), - border: Border.all( - color: isTimeMode ? AppColors.neonGreen : AppColors.surfaceLight, - width: 2.0, - ), - shadows: isTimeMode - ? [ - BoxShadow( - color: AppColors.neonGreen.withOpacity(0.6), - blurRadius: 12.0, - spreadRadius: 2.0, - ), - ] - : [], + borderRadius: BorderRadius.circular(20), border: Border.all(color: isTimeMode ? Colors.amber : Colors.white.withOpacity(0.1), width: isTimeMode ? 2 : 1), + gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isTimeMode ? [Colors.amber.withOpacity(0.25), Colors.amber.withOpacity(0.05)] : [theme.text.withOpacity(0.1), theme.text.withOpacity(0.02)]), + boxShadow: isTimeMode ? [BoxShadow(color: Colors.amber.withOpacity(0.3), blurRadius: 15, spreadRadius: 2)] : [BoxShadow(color: Colors.black.withOpacity(0.4), blurRadius: 6, offset: const Offset(2, 4)), BoxShadow(color: Colors.white.withOpacity(0.05), blurRadius: 2, offset: const Offset(-1, -1))], ), child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.hourglass_empty, // Icona clessidra - color: isTimeMode ? AppColors.neonGreen : AppColors.textSecondary, - ), - const SizedBox(width: 8), - Text( - isTimeMode ? 'A TEMPO' : 'SENZA TEMPO', - style: TextStyle( - color: isTimeMode ? AppColors.textPrimary : AppColors.textSecondary, - fontWeight: isTimeMode ? FontWeight.bold : FontWeight.normal, + Icon(isTimeMode ? Icons.timer : Icons.timer_off, color: isTimeMode ? Colors.amber : theme.text.withOpacity(0.5), size: 28), const SizedBox(width: 12), + Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [Text(isTimeMode ? 'A TEMPO' : 'RELAX', style: getSharedTextStyle(themeType, TextStyle(color: isTimeMode ? Colors.white : theme.text.withOpacity(0.5), fontWeight: FontWeight.w900, fontSize: 14, letterSpacing: 1.5))), Text(isTimeMode ? '15 sec a mossa' : 'Nessun limite', style: getSharedTextStyle(themeType, TextStyle(color: isTimeMode ? Colors.amber.shade200 : theme.text.withOpacity(0.4), fontSize: 11, fontWeight: FontWeight.bold)))]), + ], + ), + ), + ); + } +} + +class NeonPrivacySwitch extends StatelessWidget { + final bool isPublic; + final ThemeColors theme; + final AppThemeType themeType; + final VoidCallback onTap; + + const NeonPrivacySwitch({super.key, required this.isPublic, required this.theme, required this.themeType, required this.onTap}); + + @override + Widget build(BuildContext context) { + if (themeType == AppThemeType.doodle) { + Color doodleColor = isPublic ? Colors.green.shade600 : Colors.red.shade600; + return Transform.rotate( + angle: 0.015, + child: GestureDetector( + onTap: onTap, + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + transform: Matrix4.translationValues(0, isPublic ? 3 : 0, 0), + decoration: BoxDecoration( + color: isPublic ? doodleColor : Colors.white, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(15), topRight: Radius.circular(8), + bottomLeft: Radius.circular(6), bottomRight: Radius.circular(15), ), + border: Border.all(color: isPublic ? theme.text : doodleColor.withOpacity(0.5), width: 2.5), + boxShadow: [BoxShadow(color: isPublic ? theme.text.withOpacity(0.8) : doodleColor.withOpacity(0.2), offset: const Offset(4, 5), blurRadius: 0)], + ), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(isPublic ? Icons.public : Icons.lock, color: isPublic ? Colors.white : doodleColor, size: 20), + const SizedBox(width: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text(isPublic ? 'PUBBLICA' : 'PRIVATA', style: getSharedTextStyle(themeType, TextStyle(color: isPublic ? Colors.white : doodleColor, fontWeight: FontWeight.w900, fontSize: 12, letterSpacing: 1.0))), + Text(isPublic ? 'In Bacheca' : 'Solo Codice', style: getSharedTextStyle(themeType, TextStyle(color: isPublic ? Colors.white : doodleColor.withOpacity(0.8), fontSize: 9, fontWeight: FontWeight.bold))), + ], + ), + ], + ), + ), + ), + ); + } + + return GestureDetector( + onTap: onTap, + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: isPublic + ? [Colors.greenAccent.withOpacity(0.25), Colors.greenAccent.withOpacity(0.05)] + : [theme.playerRed.withOpacity(0.25), theme.playerRed.withOpacity(0.05)], + ), + border: Border.all(color: isPublic ? Colors.greenAccent : theme.playerRed, width: isPublic ? 2 : 1), + boxShadow: isPublic + ? [BoxShadow(color: Colors.greenAccent.withOpacity(0.3), blurRadius: 15, spreadRadius: 2)] + : [BoxShadow(color: Colors.black.withOpacity(0.4), blurRadius: 6, offset: const Offset(2, 4))], + ), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(isPublic ? Icons.public : Icons.lock, color: isPublic ? Colors.greenAccent : theme.playerRed, size: 20), + const SizedBox(width: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text(isPublic ? 'PUBBLICA' : 'PRIVATA', style: getSharedTextStyle(themeType, TextStyle(color: isPublic ? Colors.white : theme.text.withOpacity(0.8), fontWeight: FontWeight.w900, fontSize: 11, letterSpacing: 1.5))), + Text(isPublic ? 'Tutti ti vedono' : 'Solo con Codice', style: getSharedTextStyle(themeType, TextStyle(color: isPublic ? Colors.greenAccent.shade200 : theme.playerRed.withOpacity(0.7), fontSize: 9, fontWeight: FontWeight.bold))), + ], ), ], ), ), ); } +} + +class NeonActionButton extends StatelessWidget { + final String label; + final Color color; + final VoidCallback onTap; + final ThemeColors theme; + final AppThemeType themeType; + + const NeonActionButton({super.key, required this.label, required this.color, required this.onTap, required this.theme, required this.themeType}); + + @override + Widget build(BuildContext context) { + if (themeType == AppThemeType.doodle) { + double tilt = (label == "UNISCITI" || label == "ANNULLA") ? -0.015 : 0.02; + return Transform.rotate( + angle: tilt, + child: GestureDetector( + onTap: onTap, + child: Container( + height: 50, + decoration: BoxDecoration( + color: color, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(20), + bottomLeft: Radius.circular(25), bottomRight: Radius.circular(10), + ), + border: Border.all(color: theme.text, width: 3.0), + boxShadow: [BoxShadow(color: theme.text.withOpacity(0.9), offset: const Offset(4, 4), blurRadius: 0)], + ), + child: Center( + child: FittedBox( + fit: BoxFit.scaleDown, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Text(label, style: getSharedTextStyle(themeType, TextStyle(fontSize: 20, fontWeight: FontWeight.w900, letterSpacing: 3.0, color: Colors.white))), + ), + ), + ), + ), + ), + ); + } + + return GestureDetector( + onTap: onTap, + child: Container( + height: 50, + decoration: BoxDecoration( + gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [color.withOpacity(0.9), color.withOpacity(0.6)]), + borderRadius: BorderRadius.circular(15), + border: Border.all(color: Colors.white.withOpacity(0.3), width: 1.5), + boxShadow: [ + BoxShadow(color: Colors.black.withOpacity(0.5), offset: const Offset(4, 8), blurRadius: 12), + BoxShadow(color: color.withOpacity(0.3), offset: const Offset(0, 0), blurRadius: 15, spreadRadius: 1), + ], + ), + child: Center( + child: FittedBox( + fit: BoxFit.scaleDown, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Text(label, style: getSharedTextStyle(themeType, const TextStyle(fontSize: 16, fontWeight: FontWeight.w900, letterSpacing: 2.0, color: Colors.white, shadows: [Shadow(color: Colors.black, blurRadius: 2, offset: Offset(1, 1))]))), + ), + ), + ), + ), + ); + } } \ No newline at end of file