2026-03-15 15:00:01 +01:00
// ===========================================================================
// FILE: lib/ui/multiplayer/lobby_widgets.dart
// ===========================================================================
import ' package:flutter/material.dart ' ;
import ' dart:math ' as math ;
import ' package:google_fonts/google_fonts.dart ' ;
import ' ../../core/theme_manager.dart ' ;
import ' ../../core/app_colors.dart ' ;
TextStyle getLobbyTextStyle ( 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 ) ) ;
} else if ( themeType = = AppThemeType . music ) {
return GoogleFonts . audiowide ( textStyle: baseStyle . copyWith ( letterSpacing: 1.5 ) ) ;
}
return baseStyle ;
}
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 ( {
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 . blue . shade700 ;
case ' Croce ' : return Colors . teal . shade700 ;
case ' Buco ' : return Colors . pink . shade600 ;
case ' Clessidra ' : return Colors . deepPurple . shade600 ;
case ' Caos ' : return Colors . blueGrey . shade800 ;
default : return Colors . blue . shade700 ;
}
}
@ override
Widget build ( BuildContext context ) {
if ( themeType = = AppThemeType . doodle ) {
Color doodleColor = isLocked ? Colors . grey : _getDoodleColor ( ) ;
double tilt = ( label . length % 2 = = 0 ) ? - 0.03 : 0.04 ;
return Transform . rotate (
angle: tilt ,
child: GestureDetector (
onTap: isLocked ? null : onTap ,
child: AnimatedContainer (
duration: const Duration ( milliseconds: 200 ) ,
padding: const EdgeInsets . symmetric ( horizontal: 6 , vertical: 6 ) ,
transform: Matrix4 . translationValues ( 0 , isSelected ? 3 : 0 , 0 ) ,
decoration: BoxDecoration (
color: isSelected ? doodleColor : Colors . white ,
borderRadius: const BorderRadius . only (
topLeft: Radius . circular ( 15 ) , topRight: Radius . circular ( 8 ) ,
bottomLeft: Radius . circular ( 6 ) , bottomRight: Radius . circular ( 18 ) ,
) ,
border: Border . all ( color: isSelected ? theme . text : doodleColor . withOpacity ( 0.5 ) , width: isSelected ? 2.5 : 1.5 ) ,
boxShadow: isSelected
? [ BoxShadow ( color: theme . text . withOpacity ( 0.8 ) , offset: const Offset ( 3 , 4 ) , blurRadius: 0 ) ]
: [ BoxShadow ( color: doodleColor . withOpacity ( 0.2 ) , offset: const Offset ( 2 , 2 ) , blurRadius: 0 ) ] ,
) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
Icon ( isLocked ? Icons . lock : icon , color: isSelected ? Colors . white : doodleColor , size: 20 ) ,
const SizedBox ( height: 2 ) ,
2026-03-15 17:00:01 +01:00
FittedBox ( fit: BoxFit . scaleDown , child: Text ( isLocked ? " Liv. 7 " : label , style: getLobbyTextStyle ( themeType , TextStyle ( color: isSelected ? Colors . white : doodleColor , fontSize: 9 , fontWeight: FontWeight . w900 , letterSpacing: 0.2 ) ) ) ) ,
2026-03-15 15:00:01 +01:00
] ,
) ,
) ,
) ,
) ;
}
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: 8 , vertical: 8 ) ,
transform: Matrix4 . translationValues ( 0 , isSelected ? 2 : 0 , 0 ) ,
decoration: BoxDecoration (
borderRadius: BorderRadius . circular ( 12 ) ,
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 ) ] ,
) ,
border: Border . all (
color: isLocked ? Colors . transparent : ( isSelected ? mainColor : Colors . white . withOpacity ( 0.1 ) ) ,
width: isSelected ? 2 : 1 ,
) ,
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: 20 ) ,
const SizedBox ( height: 4 ) ,
2026-03-15 17:00:01 +01:00
FittedBox ( fit: BoxFit . scaleDown , child: Text ( isLocked ? " Liv. 7 " : label , style: getLobbyTextStyle ( themeType , TextStyle ( color: isLocked ? Colors . grey . withOpacity ( 0.5 ) : ( isSelected ? Colors . white : theme . text . withOpacity ( 0.6 ) ) , fontSize: 9 , fontWeight: isSelected ? FontWeight . w900 : FontWeight . bold ) ) ) ) ,
2026-03-15 15:00:01 +01:00
] ,
) ,
) ,
) ;
}
}
class NeonSizeButton extends StatelessWidget {
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 . shade700 : Colors . blueGrey . shade600 ;
double tilt = ( label = = ' M ' | | label = = ' MAX ' ) ? 0.05 : - 0.04 ;
return Transform . rotate (
angle: tilt ,
child: GestureDetector (
onTap: onTap ,
child: AnimatedContainer (
duration: const Duration ( milliseconds: 200 ) ,
width: 42 , height: 40 ,
transform: Matrix4 . translationValues ( 0 , isSelected ? 3 : 0 , 0 ) ,
decoration: BoxDecoration (
color: isSelected ? doodleColor : Colors . white ,
borderRadius: const BorderRadius . all ( Radius . elliptical ( 25 , 20 ) ) ,
border: Border . all ( color: isSelected ? theme . text : doodleColor . withOpacity ( 0.5 ) , width: 2 ) ,
boxShadow: isSelected
? [ BoxShadow ( color: theme . text . withOpacity ( 0.8 ) , offset: const Offset ( 3 , 4 ) , blurRadius: 0 ) ]
: [ BoxShadow ( color: doodleColor . withOpacity ( 0.2 ) , offset: const Offset ( 2 , 2 ) , blurRadius: 0 ) ] ,
) ,
child: Center (
child: FittedBox ( fit: BoxFit . scaleDown , child: Text ( label , style: getLobbyTextStyle ( themeType , TextStyle ( color: isSelected ? Colors . white : doodleColor , fontSize: 13 , fontWeight: FontWeight . w900 ) ) ) ) ,
) ,
) ,
) ,
) ;
}
return GestureDetector (
onTap: onTap ,
child: AnimatedContainer (
duration: const Duration ( milliseconds: 250 ) ,
curve: Curves . easeOutCubic ,
width: 42 , height: 42 ,
transform: Matrix4 . translationValues ( 0 , isSelected ? 2 : 0 , 0 ) ,
decoration: BoxDecoration (
shape: BoxShape . circle ,
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 ) ] ,
) ,
border: Border . all ( color: isSelected ? theme . playerRed : Colors . white . withOpacity ( 0.1 ) , width: isSelected ? 2 : 1 ) ,
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: FittedBox ( fit: BoxFit . scaleDown , child: Text ( label , style: getLobbyTextStyle ( themeType , TextStyle ( color: isSelected ? Colors . white : theme . text . withOpacity ( 0.6 ) , fontSize: 12 , 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 . shade700 ;
return Transform . rotate (
angle: - 0.015 ,
child: GestureDetector (
onTap: onTap ,
child: AnimatedContainer (
duration: const Duration ( milliseconds: 200 ) ,
padding: const EdgeInsets . symmetric ( horizontal: 10 , vertical: 8 ) ,
transform: Matrix4 . translationValues ( 0 , isTimeMode ? 3 : 0 , 0 ) ,
decoration: BoxDecoration (
color: isTimeMode ? doodleColor : Colors . white ,
borderRadius: const BorderRadius . only (
topLeft: Radius . circular ( 8 ) , topRight: Radius . circular ( 15 ) ,
bottomLeft: Radius . circular ( 15 ) , bottomRight: Radius . circular ( 6 ) ,
) ,
border: Border . all ( color: isTimeMode ? theme . text : doodleColor . withOpacity ( 0.5 ) , width: 2.5 ) ,
boxShadow: isTimeMode
? [ BoxShadow ( color: theme . text . withOpacity ( 0.8 ) , offset: const Offset ( 4 , 5 ) , blurRadius: 0 ) ]
: [ BoxShadow ( color: doodleColor . withOpacity ( 0.2 ) , offset: const Offset ( 2 , 2 ) , blurRadius: 0 ) ] ,
) ,
child: Row (
mainAxisSize: MainAxisSize . max ,
mainAxisAlignment: MainAxisAlignment . center ,
children: [
Icon ( isTimeMode ? Icons . timer : Icons . timer_off , color: isTimeMode ? Colors . white : doodleColor , size: 20 ) ,
const SizedBox ( width: 8 ) ,
Flexible (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( isTimeMode ? ' A TEMPO ' : ' RELAX ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: isTimeMode ? Colors . white : doodleColor , fontWeight: FontWeight . w900 , fontSize: 12 , letterSpacing: 1.0 ) ) ) ) ,
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( isTimeMode ? ' 15s a mossa ' : ' Senza limiti ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: isTimeMode ? 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: 10 , vertical: 8 ) ,
decoration: BoxDecoration (
borderRadius: BorderRadius . circular ( 15 ) ,
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 ) ] ,
) ,
border: Border . all ( color: isTimeMode ? Colors . amber : Colors . white . withOpacity ( 0.1 ) , width: isTimeMode ? 2 : 1 ) ,
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: 20 ) ,
const SizedBox ( width: 8 ) ,
Flexible (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( isTimeMode ? ' A TEMPO ' : ' RELAX ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: isTimeMode ? Colors . white : theme . text . withOpacity ( 0.5 ) , fontWeight: FontWeight . w900 , fontSize: 11 , letterSpacing: 1.5 ) ) ) ) ,
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( isTimeMode ? ' 15s a mossa ' : ' Senza limiti ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: isTimeMode ? Colors . amber . shade200 : theme . text . withOpacity ( 0.4 ) , fontSize: 9 , 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: 10 , 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 ) ,
Flexible (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( isPublic ? ' STANZA PUBBLICA ' : ' STANZA PRIVATA ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: isPublic ? Colors . white : doodleColor , fontWeight: FontWeight . w900 , fontSize: 10 , letterSpacing: 1.0 ) ) ) ) ,
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( isPublic ? ' In bacheca ' : ' Invita con codice ' , style: getLobbyTextStyle ( 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: 10 , 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 ) ,
Flexible (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( isPublic ? ' STANZA PUBBLICA ' : ' STANZA PRIVATA ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: isPublic ? Colors . white : theme . text . withOpacity ( 0.8 ) , fontWeight: FontWeight . w900 , fontSize: 10 , letterSpacing: 1.0 ) ) ) ) ,
2026-03-15 17:00:01 +01:00
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( isPublic ? ' Tutti ti vedono ' : ' Solo con Codice ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: isPublic ? Colors . greenAccent . shade200 : theme . playerRed . withOpacity ( 0.7 ) , fontSize: 9 , fontWeight: FontWeight . bold ) ) ) ) ,
2026-03-15 15:00:01 +01:00
] ,
) ,
) ,
] ,
) ,
) ,
) ;
}
}
class NeonInviteFavoriteButton extends StatelessWidget {
final ThemeColors theme ;
final AppThemeType themeType ;
final VoidCallback onTap ;
const NeonInviteFavoriteButton ( { super . key , required this . theme , required this . themeType , required this . onTap } ) ;
@ override
Widget build ( BuildContext context ) {
if ( themeType = = AppThemeType . doodle ) {
Color doodleColor = Colors . pink . shade600 ;
return Transform . rotate (
angle: - 0.015 ,
child: GestureDetector (
onTap: onTap ,
child: AnimatedContainer (
duration: const Duration ( milliseconds: 200 ) ,
padding: const EdgeInsets . symmetric ( horizontal: 10 , vertical: 8 ) ,
decoration: BoxDecoration (
color: Colors . white ,
borderRadius: const BorderRadius . only (
topLeft: Radius . circular ( 8 ) , topRight: Radius . circular ( 15 ) ,
bottomLeft: Radius . circular ( 15 ) , bottomRight: Radius . circular ( 6 ) ,
) ,
border: Border . all ( color: doodleColor . withOpacity ( 0.5 ) , width: 2.5 ) ,
boxShadow: [ BoxShadow ( color: doodleColor . withOpacity ( 0.2 ) , offset: const Offset ( 4 , 5 ) , blurRadius: 0 ) ] ,
) ,
child: Row (
mainAxisSize: MainAxisSize . max ,
mainAxisAlignment: MainAxisAlignment . center ,
children: [
Icon ( Icons . favorite , color: doodleColor , size: 20 ) ,
const SizedBox ( width: 8 ) ,
Flexible (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( ' PREFERITI ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: doodleColor , fontWeight: FontWeight . w900 , fontSize: 12 , letterSpacing: 1.0 ) ) ) ) ,
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( ' Invita amico ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: 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: 10 , vertical: 8 ) ,
decoration: BoxDecoration (
borderRadius: BorderRadius . circular ( 15 ) ,
gradient: LinearGradient (
begin: Alignment . topLeft ,
end: Alignment . bottomRight ,
colors: [ Colors . pinkAccent . withOpacity ( 0.25 ) , Colors . pinkAccent . withOpacity ( 0.05 ) ] ,
) ,
border: Border . all ( color: Colors . pinkAccent , width: 1.5 ) ,
boxShadow: [ BoxShadow ( color: Colors . pinkAccent . withOpacity ( 0.3 ) , blurRadius: 15 , spreadRadius: 2 ) ] ,
) ,
child: Row (
mainAxisSize: MainAxisSize . max ,
mainAxisAlignment: MainAxisAlignment . center ,
children: [
const Icon ( Icons . favorite , color: Colors . pinkAccent , size: 20 ) ,
const SizedBox ( width: 8 ) ,
Flexible (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( ' PREFERITI ' , style: getLobbyTextStyle ( themeType , const TextStyle ( color: Colors . white , fontWeight: FontWeight . w900 , fontSize: 11 , letterSpacing: 1.5 ) ) ) ) ,
FittedBox ( fit: BoxFit . scaleDown , alignment: Alignment . centerLeft , child: Text ( ' Invita amico ' , style: getLobbyTextStyle ( themeType , TextStyle ( color: Colors . pinkAccent . shade200 , 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: getLobbyTextStyle ( themeType , const 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: getLobbyTextStyle ( 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 ) ) ] ) ) ) ,
) ,
) ,
) ,
) ,
) ;
}
}