Bonsoir à tous,
On va mettre ça sur le compte de la chaleur…mais je n’arrive pas à faire ce que je veux, et surtout, je ne comprends pas la mécanique.
En fait, je souhaite faire un setState d’un widget à partir d’un autre widget.
Pour expliquer ma situation, j’ai un premier widget AdministrationScreen qui retourne un Scaffold, ce dernier contenant avec un body (widget AdminWinTypesTab) et un Floating Action Button.
Le Floating Action Button ouvre une modal bottom dont le contenu est le widget ModalBottomContent.
Ce dernier contient une colonne avec le titre et un autre widget, AdminWinTypesColumn.
Ce que je souhaite faire, c’est un setState de ma liste (widget AdminWinTypesTab) une fois que je valide et que la fonction qui modifie mes données est exécutée.
Je vous mets le code ci-dessous, en espérant qu’il ne soit pas trop indigeste.
import 'package:flutter/material.dart';
import '../datas/datas.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test Refresh State',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const AdministrationScreen(),
);
}
}
class AdministrationScreen extends StatefulWidget {
const AdministrationScreen({super.key});
@override
State<AdministrationScreen> createState() => _AdministrationScreenState();
}
class _AdministrationScreenState extends State<AdministrationScreen>
with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: const Text('Test'),
),
body: const AdminWinTypesTab(),
floatingActionButton: FloatingActionButton(
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height / 1.75,
child: const Scaffold(
body: SingleChildScrollView(
child: SizedBox(
child: Padding(
padding: EdgeInsets.all(20.0),
child: ModalBottomSheetContent(
add: true,
),
),
),
),
),
);
},
);
},
backgroundColor: Colors.green,
child: const Icon(
Icons.add,
),
),
);
}
}
class ModalBottomSheetContent extends StatefulWidget {
final bool add;
final String? winType;
const ModalBottomSheetContent({
super.key,
required this.add,
this.winType,
});
@override
State<ModalBottomSheetContent> createState() =>
_ModalBottomSheetContentState();
}
class _ModalBottomSheetContentState extends State<ModalBottomSheetContent> {
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'${widget.add ? 'Ajouter' : 'Modifier'} dans les types de gain',
style: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(
height: 10,
),
AdminWinTypesColumn(add: widget.add, winType: widget.winType),
],
);
}
}
class AdminWinTypesColumn extends StatefulWidget {
final bool add;
final String? winType;
const AdminWinTypesColumn({
super.key,
required this.add,
this.winType,
});
@override
State<AdminWinTypesColumn> createState() => _AdminWinTypesColumnState();
}
class _AdminWinTypesColumnState extends State<AdminWinTypesColumn> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _nameController = TextEditingController();
int? indexToModify;
void _submit(bool add, int? indexToModify, String? winTypeToModify) async {
if (_formKey.currentState!.validate()) {
String action;
if (add) {
action = 'add';
} else {
action = 'modify';
}
modifyWinType(winTypeToModify!, action, indexToModify);
if (context.mounted) {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(action),
backgroundColor: Colors.green,
),
);
}
}
setState(() {});
}
@override
void initState() {
// Récupération des informations si modification
if (!widget.add) {
_nameController.text = widget.winType!;
indexToModify = winTypes.indexOf(widget.winType!);
}
super.initState();
}
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Column(
children: [
Form(
key: _formKey,
child: Column(
children: [
Row(
children: [
const SizedBox(
width: 100,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Type de gain',
),
Text(
'(au singulier) :',
),
],
),
),
Flexible(
child: TextFormField(
controller: _nameController,
validator: (value) {
if (value == null || value.trim().isEmpty) {
return 'Entre le nom';
}
if (value == widget.winType) {
return 'Le nom est inchangé';
}
return null;
},
),
),
],
),
],
),
),
const SizedBox(height: 30),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
textStyle: const TextStyle(color: Colors.white),
),
child: const Text('Annuler'),
),
ElevatedButton(
onPressed: () {
int? indexTomodify = widget.add ? null : indexToModify;
String? winTypeToModify = _nameController.text.trim();
_submit(widget.add, indexTomodify, winTypeToModify);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
textStyle: const TextStyle(color: Colors.black),
),
child: const Text('Valider'),
),
],
),
],
),
);
}
}
class AdminWinTypesTab extends StatefulWidget {
const AdminWinTypesTab({
super.key,
});
@override
State<AdminWinTypesTab> createState() => _AdminWinTypesTabState();
}
class _AdminWinTypesTabState extends State<AdminWinTypesTab> {
Future<void> modifyWinTypesAndRefresh(
String winType, String action, int indexToModify) async {
Color? snackBarColor;
String? snackBarMessage;
await modifyWinType(winType, action, indexToModify);
if (action == 'delete') {
snackBarColor = Colors.red;
snackBarMessage = 'Type de gain "$winType" supprimé';
}
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
snackBarMessage!,
),
backgroundColor: snackBarColor,
),
);
}
setState(() {});
}
void refreshWinTypesTab() {
setState(() {});
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<String>?>(
future: getWinTypes(),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data != null) {
List<String> fetchedWinTypes = snapshot.data!;
return ListView.builder(
itemCount: fetchedWinTypes.length,
itemBuilder: (context, index) {
String winType = fetchedWinTypes[index];
return ListTile(
tileColor: index.isOdd ? null : Colors.grey.shade300,
title: Text(
winType,
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return SizedBox(
height:
MediaQuery.of(context).size.height / 1.75,
child: Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: ModalBottomSheetContent(
add: false,
winType: winType,
),
),
),
),
);
},
);
},
icon: const Icon(Icons.edit, color: Colors.green)),
IconButton(
onPressed: () async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Column(
children: [
const Icon(
Icons.dangerous,
color: Colors.red,
),
Text(
'Supprimer le type de gain "$winType" ?',
style: const TextStyle(
color: Colors.red,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'Annuler',
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
TextButton(
onPressed: () {
modifyWinTypesAndRefresh(
winType, 'delete', index);
Navigator.of(context).pop();
},
child: const Text(
'Supprimer',
style: TextStyle(
color: Colors.red,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
],
);
},
);
},
icon: const Icon(
Icons.delete_forever,
color: Colors.red,
),
),
],
),
);
},
);
} else if (snapshot.hasError) {
return Center(child: Text('Erreur: ${snapshot.error}'));
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
}
Merci beaucoup pour votre aide.
Fabien