2026-03-15 02:00:01 +01:00
// ===========================================================================
// FILE: lib/widgets/custom_settings_button.dart
// ===========================================================================
2026-02-27 23:35:54 +01:00
import ' package:flutter/material.dart ' ;
2026-03-15 02:00:01 +01:00
import ' ../core/app_colors.dart ' ;
import ' painters.dart ' ; // Importiamo i painter per i doodle e il font
2026-02-27 23:35:54 +01:00
class NeonShapeButton extends StatelessWidget {
2026-03-15 02:00:01 +01:00
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 . 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 ;
}
}
2026-02-27 23:35:54 +01:00
@ override
Widget build ( BuildContext context ) {
2026-03-15 02:00:01 +01:00
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 ;
2026-02-27 23:35:54 +01:00
return GestureDetector (
2026-03-15 02:00:01 +01:00
onTap: isLocked ? null : onTap ,
2026-02-27 23:35:54 +01:00
child: AnimatedContainer (
2026-03-15 02:00:01 +01:00
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 ) ) ] ,
2026-02-27 23:35:54 +01:00
) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
2026-03-15 02:00:01 +01:00
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 ) ) ) ,
2026-02-27 23:35:54 +01:00
] ,
) ,
) ,
) ;
}
}
class NeonSizeButton extends StatelessWidget {
2026-03-15 02:00:01 +01:00
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 } ) ;
2026-02-27 23:35:54 +01:00
@ override
Widget build ( BuildContext context ) {
2026-03-15 02:00:01 +01:00
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 ) ) ) ) ) ) ,
) ,
) ;
}
2026-02-27 23:35:54 +01:00
return GestureDetector (
onTap: onTap ,
child: AnimatedContainer (
2026-03-15 02:00:01 +01:00
duration: const Duration ( milliseconds: 250 ) , curve: Curves . easeOutCubic , width: 50 , height: 50 , transform: Matrix4 . translationValues ( 0 , isSelected ? 2 : 0 , 0 ) ,
2026-02-27 23:35:54 +01:00
decoration: BoxDecoration (
2026-03-15 02:00:01 +01:00
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 ) ) ] ,
2026-02-27 23:35:54 +01:00
) ,
2026-03-15 02:00:01 +01:00
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 ( { 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 ) ) ) ] ) ,
] ,
) ,
2026-02-27 23:35:54 +01:00
) ,
) ,
) ,
2026-03-15 02:00:01 +01:00
) ;
}
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 ) ) ) ] ) ,
] ,
) ,
2026-02-27 23:35:54 +01:00
) ,
) ;
}
}
2026-03-15 02:00:01 +01:00
class NeonPrivacySwitch extends StatelessWidget {
final bool isPublic ;
final ThemeColors theme ;
final AppThemeType themeType ;
2026-02-27 23:35:54 +01:00
final VoidCallback onTap ;
2026-03-15 02:00:01 +01:00
const NeonPrivacySwitch ( { super . key , required this . isPublic , required this . theme , required this . themeType , required this . onTap } ) ;
2026-02-27 23:35:54 +01:00
@ override
Widget build ( BuildContext context ) {
2026-03-15 02:00:01 +01:00
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 ) ) ) ,
] ,
) ,
] ,
) ,
) ,
) ,
) ;
}
2026-02-27 23:35:54 +01:00
return GestureDetector (
onTap: onTap ,
child: AnimatedContainer (
duration: const Duration ( milliseconds: 300 ) ,
curve: Curves . easeInOut ,
2026-03-15 02:00:01 +01:00
padding: const EdgeInsets . symmetric ( horizontal: 16 , vertical: 8 ) ,
2026-02-27 23:35:54 +01:00
decoration: BoxDecoration (
2026-03-15 02:00:01 +01:00
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 ) ] ,
2026-02-27 23:35:54 +01:00
) ,
2026-03-15 02:00:01 +01:00
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 ) ) ] ,
2026-02-27 23:35:54 +01:00
) ,
child: Row (
2026-03-15 02:00:01 +01:00
mainAxisSize: MainAxisSize . max ,
mainAxisAlignment: MainAxisAlignment . center ,
2026-02-27 23:35:54 +01:00
children: [
2026-03-15 02:00:01 +01:00
Icon ( isPublic ? Icons . public : Icons . lock , color: isPublic ? Colors . greenAccent : theme . playerRed , size: 20 ) ,
2026-02-27 23:35:54 +01:00
const SizedBox ( width: 8 ) ,
2026-03-15 02:00:01 +01:00
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 ) ,
2026-02-27 23:35:54 +01:00
) ,
2026-03-15 02:00:01 +01:00
border: Border . all ( color: theme . text , width: 3.0 ) ,
boxShadow: [ BoxShadow ( color: theme . text . withOpacity ( 0.9 ) , offset: const Offset ( 4 , 4 ) , blurRadius: 0 ) ] ,
2026-02-27 23:35:54 +01:00
) ,
2026-03-15 02:00:01 +01:00
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 ) ,
2026-02-27 23:35:54 +01:00
] ,
) ,
2026-03-15 02:00:01 +01:00
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 ) ) ] ) ) ) ,
) ,
) ,
) ,
2026-02-27 23:35:54 +01:00
) ,
) ;
}
}