2026-03-14 00:00:01 +01:00
// ===========================================================================
2026-03-15 03:00:01 +01:00
// FILE: lib/ui/home/dialog.dart
2026-03-14 00:00:01 +01:00
// ===========================================================================
import ' package:flutter/material.dart ' ;
import ' package:provider/provider.dart ' ;
import ' package:shared_preferences/shared_preferences.dart ' ;
import ' package:cloud_firestore/cloud_firestore.dart ' ;
import ' package:firebase_auth/firebase_auth.dart ' ;
2026-03-15 03:00:01 +01:00
import ' ../../core/theme_manager.dart ' ;
import ' ../../core/app_colors.dart ' ;
import ' ../../l10n/app_localizations.dart ' ;
import ' ../../widgets/painters.dart ' ;
import ' ../../widgets/cyber_border.dart ' ;
2026-03-14 00:00:01 +01:00
// ===========================================================================
// 1. DIALOGO MISSIONI (QUESTS)
// ===========================================================================
class QuestsDialog extends StatelessWidget {
const QuestsDialog ( { super . key } ) ;
@ override
Widget build ( BuildContext context ) {
final themeManager = context . watch < ThemeManager > ( ) ;
final theme = themeManager . currentColors ;
final themeType = themeManager . currentThemeType ;
final loc = AppLocalizations . of ( context ) ! ;
return FutureBuilder < SharedPreferences > (
future: SharedPreferences . getInstance ( ) ,
builder: ( context , snapshot ) {
if ( ! snapshot . hasData ) return const SizedBox ( ) ;
final prefs = snapshot . data ! ;
return Dialog (
backgroundColor: Colors . transparent ,
insetPadding: const EdgeInsets . all ( 20 ) ,
child: Container (
padding: const EdgeInsets . all ( 25.0 ) ,
decoration: BoxDecoration (
gradient: LinearGradient ( begin: Alignment . topLeft , end: Alignment . bottomRight , colors: [ theme . background . withOpacity ( 0.95 ) , theme . background . withOpacity ( 0.8 ) ] ) ,
borderRadius: BorderRadius . circular ( 25 ) ,
border: Border . all ( color: theme . playerBlue . withOpacity ( 0.5 ) , width: 2 ) ,
boxShadow: [ BoxShadow ( color: theme . playerBlue . withOpacity ( 0.2 ) , blurRadius: 20 , spreadRadius: 5 ) ]
) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
Icon ( Icons . assignment_turned_in , size: 50 , color: theme . playerBlue ) ,
const SizedBox ( height: 10 ) ,
Text ( loc . questsTitle , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 22 , fontWeight: FontWeight . w900 , color: theme . text , letterSpacing: 1.5 ) ) ) ,
const SizedBox ( height: 25 ) ,
. . . List . generate ( 3 , ( index ) {
int i = index + 1 ;
int type = prefs . getInt ( ' q ${ i } _type ' ) ? ? 0 ;
int prog = prefs . getInt ( ' q ${ i } _prog ' ) ? ? 0 ;
int target = prefs . getInt ( ' q ${ i } _target ' ) ? ? 1 ;
String title = " " ;
IconData icon = Icons . star ;
if ( type = = 0 ) { title = " Vinci partite Online " ; icon = Icons . public ; }
else if ( type = = 1 ) { title = " Vinci contro la CPU " ; icon = Icons . smart_toy ; }
else { title = " Gioca in Arene Speciali " ; icon = Icons . extension ; }
bool completed = prog > = target ;
double percent = ( prog / target ) . clamp ( 0.0 , 1.0 ) ;
return Container (
margin: const EdgeInsets . only ( bottom: 15 ) ,
padding: const EdgeInsets . all ( 12 ) ,
decoration: BoxDecoration (
color: completed ? Colors . green . withOpacity ( 0.1 ) : theme . text . withOpacity ( 0.05 ) ,
borderRadius: BorderRadius . circular ( 15 ) ,
border: Border . all ( color: completed ? Colors . green : theme . gridLine . withOpacity ( 0.3 ) ) ,
) ,
child: Row (
children: [
Icon ( icon , color: completed ? Colors . green : theme . text . withOpacity ( 0.6 ) , size: 30 ) ,
const SizedBox ( width: 15 ) ,
Expanded (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Text ( title , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 14 , fontWeight: FontWeight . bold , color: completed ? Colors . green : theme . text ) ) ) ,
const SizedBox ( height: 6 ) ,
ClipRRect (
borderRadius: BorderRadius . circular ( 10 ) ,
child: LinearProgressIndicator ( value: percent , backgroundColor: theme . gridLine . withOpacity ( 0.2 ) , color: completed ? Colors . green : theme . playerBlue , minHeight: 8 ) ,
)
] ,
) ,
) ,
const SizedBox ( width: 10 ) ,
Text ( " $ prog / $ target " , style: getSharedTextStyle ( themeType , TextStyle ( fontWeight: FontWeight . bold , color: theme . text . withOpacity ( 0.6 ) ) ) ) ,
] ,
) ,
) ;
} ) ,
const SizedBox ( height: 15 ) ,
SizedBox (
width: double . infinity , height: 50 ,
child: ElevatedButton (
style: ElevatedButton . styleFrom ( backgroundColor: theme . playerBlue , foregroundColor: Colors . white , shape: RoundedRectangleBorder ( borderRadius: BorderRadius . circular ( 15 ) ) ) ,
onPressed: ( ) = > Navigator . pop ( context ) ,
child: const Text ( " CHIUDI " , style: TextStyle ( fontSize: 16 , fontWeight: FontWeight . w900 , letterSpacing: 2 ) ) ,
) ,
)
] ,
) ,
) ,
) ;
}
) ;
}
}
// ===========================================================================
// 2. DIALOGO CLASSIFICA (LEADERBOARD)
// ===========================================================================
class LeaderboardDialog extends StatelessWidget {
const LeaderboardDialog ( { super . key } ) ;
@ override
Widget build ( BuildContext context ) {
final themeManager = context . watch < ThemeManager > ( ) ;
final theme = themeManager . currentColors ;
final themeType = themeManager . currentThemeType ;
final loc = AppLocalizations . of ( context ) ! ;
Widget content = Container (
padding: const EdgeInsets . all ( 20.0 ) ,
decoration: BoxDecoration (
gradient: LinearGradient ( begin: Alignment . topLeft , end: Alignment . bottomRight , colors: [ theme . background . withOpacity ( 0.95 ) , theme . background . withOpacity ( 0.8 ) ] ) ,
borderRadius: BorderRadius . circular ( 25 ) ,
border: Border . all ( color: Colors . amber . withOpacity ( 0.8 ) , width: 2 ) ,
boxShadow: [ BoxShadow ( color: Colors . amber . withOpacity ( 0.2 ) , blurRadius: 20 , spreadRadius: 5 ) ]
) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
const Icon ( Icons . emoji_events , size: 50 , color: Colors . amber ) ,
const SizedBox ( height: 10 ) ,
Text ( loc . leaderboardTitle , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 20 , fontWeight: FontWeight . w900 , color: theme . text , letterSpacing: 1.5 ) ) ) ,
const SizedBox ( height: 20 ) ,
SizedBox (
height: 350 ,
child: StreamBuilder < QuerySnapshot > (
stream: FirebaseFirestore . instance . collection ( ' leaderboard ' ) . orderBy ( ' xp ' , descending: true ) . limit ( 50 ) . snapshots ( ) ,
builder: ( context , snapshot ) {
if ( snapshot . connectionState = = ConnectionState . waiting ) {
return Center ( child: CircularProgressIndicator ( color: theme . playerBlue ) ) ;
}
if ( ! snapshot . hasData | | snapshot . data ! . docs . isEmpty ) {
return Center ( child: Text ( " Ancora nessun campione... " , style: TextStyle ( color: theme . text . withOpacity ( 0.5 ) ) ) ) ;
}
2026-03-15 03:00:01 +01:00
// 1. ESTRAIAMO TUTTI I DOCUMENTI
final rawDocs = snapshot . data ! . docs ;
// 2. APPLICHIAMO IL FILTRO PER NASCONDERE "PAOLO"
final filteredDocs = rawDocs . where ( ( doc ) {
var data = doc . data ( ) as Map < String , dynamic > ;
String name = ( data [ ' name ' ] ? ? ' ' ) . toString ( ) . toUpperCase ( ) ;
return name ! = ' PAOLO ' ;
} ) . toList ( ) ;
// 3. SE DOPO IL FILTRO NON C'E' NESSUNO
if ( filteredDocs . isEmpty ) {
return Center ( child: Text ( " Ancora nessun campione... " , style: TextStyle ( color: theme . text . withOpacity ( 0.5 ) ) ) ) ;
}
2026-03-14 00:00:01 +01:00
return ListView . builder (
physics: const BouncingScrollPhysics ( ) ,
2026-03-15 03:00:01 +01:00
itemCount: filteredDocs . length ,
2026-03-14 00:00:01 +01:00
itemBuilder: ( context , index ) {
2026-03-15 03:00:01 +01:00
var doc = filteredDocs [ index ] ;
var data = doc . data ( ) as Map < String , dynamic > ;
2026-03-14 00:00:01 +01:00
String ? myUid = FirebaseAuth . instance . currentUser ? . uid ;
2026-03-15 03:00:01 +01:00
bool isMe = doc . id = = myUid ;
2026-03-14 00:00:01 +01:00
return Container (
margin: const EdgeInsets . only ( bottom: 8 ) ,
padding: const EdgeInsets . symmetric ( horizontal: 12 , vertical: 10 ) ,
decoration: BoxDecoration (
color: isMe ? theme . playerBlue . withOpacity ( 0.2 ) : theme . text . withOpacity ( 0.05 ) ,
borderRadius: BorderRadius . circular ( 10 ) ,
border: isMe ? Border . all ( color: theme . playerBlue , width: 1.5 ) : null
) ,
child: Row (
children: [
Text ( " # ${ index + 1 } " , style: getSharedTextStyle ( themeType , TextStyle ( fontWeight: FontWeight . w900 , color: index = = 0 ? Colors . amber : ( index = = 1 ? Colors . grey . shade400 : ( index = = 2 ? Colors . brown . shade300 : theme . text . withOpacity ( 0.5 ) ) ) ) ) ) ,
const SizedBox ( width: 15 ) ,
Expanded ( child: Text ( data [ ' name ' ] ? ? ' Unknown ' , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 16 , fontWeight: isMe ? FontWeight . w900 : FontWeight . bold , color: theme . text ) ) ) ) ,
Column (
crossAxisAlignment: CrossAxisAlignment . end ,
children: [
Text ( " Lv. ${ data [ ' level ' ] ? ? 1 } " , style: TextStyle ( color: theme . playerRed , fontWeight: FontWeight . bold , fontSize: 12 ) ) ,
Text ( " ${ data [ ' xp ' ] ? ? 0 } XP " , style: TextStyle ( color: theme . text . withOpacity ( 0.6 ) , fontSize: 10 ) ) ,
] ,
)
] ,
) ,
) ;
}
) ;
}
) ,
) ,
const SizedBox ( height: 15 ) ,
SizedBox (
width: double . infinity , height: 50 ,
child: ElevatedButton (
style: ElevatedButton . styleFrom ( backgroundColor: Colors . amber . shade700 , foregroundColor: Colors . black , shape: RoundedRectangleBorder ( borderRadius: BorderRadius . circular ( 15 ) ) ) ,
onPressed: ( ) = > Navigator . pop ( context ) ,
child: const Text ( " CHIUDI " , style: TextStyle ( fontSize: 16 , fontWeight: FontWeight . w900 , letterSpacing: 2 ) ) ,
) ,
)
] ,
) ,
) ;
if ( themeType = = AppThemeType . cyberpunk | | themeType = = AppThemeType . music ) {
content = AnimatedCyberBorder ( child: content ) ;
}
return Dialog ( backgroundColor: Colors . transparent , insetPadding: const EdgeInsets . all ( 20 ) , child: content ) ;
}
}
// ===========================================================================
// 3. DIALOGO TUTORIAL
// ===========================================================================
class TutorialDialog extends StatelessWidget {
const TutorialDialog ( { super . key } ) ;
@ override
Widget build ( BuildContext context ) {
final themeManager = context . watch < ThemeManager > ( ) ;
final theme = themeManager . currentColors ;
final themeType = themeManager . currentThemeType ;
Color inkColor = const Color ( 0xFF111122 ) ;
2026-03-15 03:00:01 +01:00
// ETICHETTE DINAMICHE PER I POTENZIAMENTI
String goldLabel = " ORO: " ;
String bombLabel = " BOMBA: " ;
String swapLabel = " SCAMBIO: " ;
String jokerLabel = " JOLLY: " ;
String iceLabel = " GHIACCIO: " ;
String multiplierLabel = " x2: " ;
String blockLabel = " BUCO NERO: " ;
if ( themeType = = AppThemeType . grimorio ) {
goldLabel = " CORONA: " ;
bombLabel = " STREGA: " ;
jokerLabel = " GIULLARE: " ;
swapLabel = " TORNADO: " ;
multiplierLabel = " FULMINE: " ;
blockLabel = " METEORITE: " ;
} else if ( themeType = = AppThemeType . music ) {
goldLabel = " DISCO D'ORO: " ;
bombLabel = " MUTO: " ;
jokerLabel = " DJ: " ;
swapLabel = " MIXER: " ;
iceLabel = " NOTA: " ;
multiplierLabel = " AVANTI VELOCE: " ;
blockLabel = " PAUSA: " ;
} else if ( themeType = = AppThemeType . arcade ) {
goldLabel = " GETTONE: " ;
bombLabel = " FANTASMA: " ;
jokerLabel = " GAMEPAD: " ;
swapLabel = " SHUFFLE: " ;
blockLabel = " POWER OFF: " ;
} else if ( themeType = = AppThemeType . cyberpunk ) {
goldLabel = " CHIP: " ;
bombLabel = " VIRUS: " ;
jokerLabel = " BOT: " ;
swapLabel = " NETWORK: " ;
blockLabel = " FIREWALL: " ;
} else if ( themeType = = AppThemeType . wood ) {
goldLabel = " GEMMA: " ;
bombLabel = " FUOCO: " ;
jokerLabel = " CHIAVE: " ;
blockLabel = " DIVIETO: " ;
} else if ( themeType = = AppThemeType . doodle ) {
bombLabel = " VIRUS: " ;
}
2026-03-14 00:00:01 +01:00
Widget dialogContent = themeType = = AppThemeType . doodle
? Transform . rotate (
angle: - 0.01 ,
child: CustomPaint (
painter: DoodleBackgroundPainter ( fillColor: Colors . yellow . shade50 , strokeColor: inkColor , seed: 400 ) ,
child: Padding (
padding: const EdgeInsets . all ( 25.0 ) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Center ( child: Text ( " COME GIOCARE " , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 28 , fontWeight: FontWeight . w900 , color: inkColor , letterSpacing: 2 ) ) ) ) ,
const SizedBox ( height: 20 ) ,
TutorialStep ( icon: Icons . line_axis , text: " Chiudi i 4 lati di un quadrato per conquistare 1 punto e avere una mossa extra! " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 15 ) ,
TutorialStep ( icon: Icons . lens_blur , text: " Ma presta attenzione! Ogni quadrato nasconde un'insidia o un regalo! " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 15 ) ,
const Divider ( color: Colors . black26 , thickness: 2 ) ,
const SizedBox ( height: 10 ) ,
Center ( child: Text ( " GLOSSARIO ARENA " , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 18 , fontWeight: FontWeight . w900 , color: inkColor ) ) ) ) ,
const SizedBox ( height: 10 ) ,
TutorialStep ( icon: ThemeIcons . gold ( themeType ) , iconColor: Colors . amber . shade700 , text: " $ goldLabel Chiudilo per ottenere +2 Punti. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 10 ) ,
TutorialStep ( icon: ThemeIcons . bomb ( themeType ) , iconColor: Colors . deepPurple , text: " $ bombLabel Non chiuderlo! Perderai -1 Punto. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 10 ) ,
2026-03-15 03:00:01 +01:00
TutorialStep ( icon: ThemeIcons . swap ( themeType ) , iconColor: Colors . purpleAccent , text: " $ swapLabel Inverte istantaneamente i punteggi dei giocatori. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
2026-03-14 00:00:01 +01:00
const SizedBox ( height: 10 ) ,
TutorialStep ( icon: ThemeIcons . joker ( themeType ) , iconColor: Colors . green . shade600 , text: " $ jokerLabel Scegli dove nasconderlo a inizio partita. Se lo chiudi tu +2, se lo chiude l'avversario -1! " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 10 ) ,
2026-03-15 03:00:01 +01:00
TutorialStep ( icon: ThemeIcons . ice ( themeType ) , iconColor: Colors . cyanAccent , text: " $ iceLabel Devi cliccarlo due volte per poterlo rompere e chiudere. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
2026-03-14 00:00:01 +01:00
const SizedBox ( height: 10 ) ,
2026-03-15 03:00:01 +01:00
TutorialStep ( icon: ThemeIcons . multiplier ( themeType ) , iconColor: Colors . yellowAccent , text: " $ multiplierLabel Non dà punti, ma raddoppia il punteggio della prossima casella che chiudi! " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
2026-03-14 00:00:01 +01:00
const SizedBox ( height: 10 ) ,
2026-03-15 03:00:01 +01:00
TutorialStep ( icon: ThemeIcons . block ( themeType ) , iconColor: Colors . grey , text: " $ blockLabel Questa casella non esiste. Se la chiudi perdi il turno. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
2026-03-14 00:00:01 +01:00
const SizedBox ( height: 25 ) ,
Center (
child: GestureDetector (
onTap: ( ) = > Navigator . pop ( context ) ,
child: CustomPaint (
painter: DoodleBackgroundPainter ( fillColor: Colors . red . shade200 , strokeColor: inkColor , seed: 401 ) ,
child: Container (
height: 50 , width: 150 , alignment: Alignment . center ,
child: Text ( " HO CAPITO! " , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 18 , fontWeight: FontWeight . w900 , color: inkColor ) ) ) ,
) ,
) ,
) ,
)
] ,
) ,
) ,
) ,
)
: Container (
padding: const EdgeInsets . all ( 25.0 ) ,
decoration: BoxDecoration (
gradient: LinearGradient ( begin: Alignment . topLeft , end: Alignment . bottomRight , colors: [ theme . background . withOpacity ( 0.95 ) , theme . background . withOpacity ( 0.8 ) ] ) ,
borderRadius: BorderRadius . circular ( 25 ) ,
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 | | themeType = = AppThemeType . music ? [ ] : [ BoxShadow ( color: Colors . black . withOpacity ( 0.5 ) , blurRadius: 20 , offset: const Offset ( 4 , 10 ) ) ] ,
) ,
child: SingleChildScrollView (
physics: const BouncingScrollPhysics ( ) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Center ( child: Text ( " COME GIOCARE " , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 24 , fontWeight: FontWeight . w900 , color: theme . text , letterSpacing: 2 ) ) ) ) ,
const SizedBox ( height: 20 ) ,
TutorialStep ( icon: Icons . grid_4x4 , text: " Chiudi i 4 lati di un quadrato per conquistare 1 punto e avere una mossa extra! " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 15 ) ,
TutorialStep ( icon: Icons . lens_blur , text: " Ma presta attenzione! Ogni quadrato nasconde un'insidia o un regalo! " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 15 ) ,
const Divider ( color: Colors . white24 , thickness: 1.5 ) ,
const SizedBox ( height: 10 ) ,
Center ( child: Text ( " GLOSSARIO ARENA " , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 16 , fontWeight: FontWeight . w900 , color: theme . text . withOpacity ( 0.7 ) , letterSpacing: 1.5 ) ) ) ) ,
const SizedBox ( height: 15 ) ,
TutorialStep ( icon: ThemeIcons . gold ( themeType ) , iconColor: Colors . amber , text: " $ goldLabel Chiudilo per ottenere +2 Punti. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 10 ) ,
TutorialStep ( icon: ThemeIcons . bomb ( themeType ) , iconColor: themeType = = AppThemeType . cyberpunk | | themeType = = AppThemeType . arcade ? Colors . greenAccent : Colors . deepPurple , text: " $ bombLabel Non chiuderlo! Perderai -1 Punto. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 10 ) ,
2026-03-15 03:00:01 +01:00
TutorialStep ( icon: ThemeIcons . swap ( themeType ) , iconColor: Colors . purpleAccent , text: " $ swapLabel Inverte istantaneamente i punteggi dei giocatori. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
2026-03-14 00:00:01 +01:00
const SizedBox ( height: 10 ) ,
TutorialStep ( icon: ThemeIcons . joker ( themeType ) , iconColor: theme . playerBlue , text: " $ jokerLabel Scegli dove nasconderlo a inizio partita. Se lo chiudi tu +2, se lo chiude l'avversario -1! " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
const SizedBox ( height: 10 ) ,
2026-03-15 03:00:01 +01:00
TutorialStep ( icon: ThemeIcons . ice ( themeType ) , iconColor: Colors . cyanAccent , text: " $ iceLabel Devi cliccarlo due volte per poterlo rompere e chiudere. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
2026-03-14 00:00:01 +01:00
const SizedBox ( height: 10 ) ,
2026-03-15 03:00:01 +01:00
TutorialStep ( icon: ThemeIcons . multiplier ( themeType ) , iconColor: Colors . yellowAccent , text: " $ multiplierLabel Non dà punti, ma raddoppia il punteggio della prossima casella che chiudi! " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
2026-03-14 00:00:01 +01:00
const SizedBox ( height: 10 ) ,
2026-03-15 03:00:01 +01:00
TutorialStep ( icon: ThemeIcons . block ( themeType ) , iconColor: Colors . grey , text: " $ blockLabel Questa casella non esiste. Se la chiudi perdi il turno. " , themeType: themeType , inkColor: inkColor , theme: theme ) ,
2026-03-14 00:00:01 +01:00
const SizedBox ( height: 30 ) ,
SizedBox (
width: double . infinity , height: 50 ,
child: ElevatedButton (
style: ElevatedButton . styleFrom ( backgroundColor: theme . playerBlue , foregroundColor: Colors . white , shape: RoundedRectangleBorder ( borderRadius: BorderRadius . circular ( 15 ) ) ) ,
onPressed: ( ) = > Navigator . pop ( context ) ,
child: const Text ( " CHIUDI " , style: TextStyle ( fontSize: 16 , fontWeight: FontWeight . w900 , letterSpacing: 2 ) ) ,
) ,
)
] ,
) ,
) ,
) ;
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 ) ;
}
}
class TutorialStep extends StatelessWidget {
final IconData icon ;
final Color ? iconColor ;
final String text ;
final AppThemeType themeType ;
final Color inkColor ;
final ThemeColors theme ;
const TutorialStep ( { super . key , required this . icon , this . iconColor , required this . text , required this . themeType , required this . inkColor , required this . theme } ) ;
@ override
Widget build ( BuildContext context ) {
return Row (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Icon ( icon , color: iconColor ? ? ( themeType = = AppThemeType . doodle ? inkColor : theme . playerBlue ) , size: 28 ) ,
const SizedBox ( width: 15 ) ,
Expanded (
child: Text ( text , style: getSharedTextStyle ( themeType , TextStyle ( fontSize: 14 , color: themeType = = AppThemeType . doodle ? inkColor : theme . text . withOpacity ( 0.8 ) , height: 1.3 ) ) ) ,
) ,
] ,
) ;
}
}