Fix recap screens layout (desktop/mobile) and widget styles
- Restore horizontal 2:1 layout for desktop readonly cards - Implement adaptive height for mobile readonly cards - Fix spacing and margins on mobile recap screens - Update field styles to use beige background - Adjust ChildCardWidget width for mobile editing - Fix compilation errors and duplicate methods Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -94,19 +94,34 @@ class _ChildCardWidgetState extends State<ChildCardWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final config = DisplayConfig.fromContext(context, mode: widget.mode);
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final scaleFactor = config.isMobile ? 0.9 : 1.1; // Réduire légèrement sur mobile
|
||||
|
||||
// Si mode Readonly Desktop : Layout spécial "Vintage" horizontal
|
||||
if (config.isReadonly && !config.isMobile) {
|
||||
return _buildReadonlyDesktopCard(context, config, screenSize);
|
||||
}
|
||||
|
||||
// Si mode Readonly Mobile : Layout spécial "Vintage" vertical (1:2)
|
||||
if (config.isReadonly && config.isMobile) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width * 0.05),
|
||||
child: _buildReadonlyMobileCard(context, config),
|
||||
);
|
||||
}
|
||||
|
||||
final File? currentChildImage = widget.childData.imageFile;
|
||||
// Utiliser la couleur de la carte de childData pour l'ombre si besoin, ou directement pour le fond
|
||||
// ... (reste du code existant pour mobile/editable)
|
||||
final Color baseCardColorForShadow = widget.childData.cardColor == CardColorVertical.lavender
|
||||
? Colors.purple.shade200
|
||||
: (widget.childData.cardColor == CardColorVertical.pink ? Colors.pink.shade200 : Colors.grey.shade200); // Placeholder pour autres couleurs
|
||||
: (widget.childData.cardColor == CardColorVertical.pink ? Colors.pink.shade200 : Colors.grey.shade200);
|
||||
final Color initialPhotoShadow = baseCardColorForShadow.withAlpha(90);
|
||||
final Color hoverPhotoShadow = baseCardColorForShadow.withAlpha(130);
|
||||
|
||||
return Container(
|
||||
width: 345.0 * scaleFactor,
|
||||
height: config.isMobile ? null : 600.0 * scaleFactor, // Hauteur augmentée pour éviter l'overflow
|
||||
width: config.isMobile ? double.infinity : screenSize.width * 0.6,
|
||||
// On retire la hauteur fixe pour laisser le contenu définir la taille, comme les autres cartes
|
||||
// height: config.isMobile ? null : 600.0 * scaleFactor,
|
||||
padding: EdgeInsets.all(22.0 * scaleFactor),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(image: AssetImage(widget.childData.cardColor.path), fit: BoxFit.fill),
|
||||
@@ -117,6 +132,7 @@ class _ChildCardWidgetState extends State<ChildCardWidget> {
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// ... (contenu existant)
|
||||
HoverReliefWidget(
|
||||
onPressed: config.isReadonly ? null : widget.onPickImage,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
@@ -135,7 +151,7 @@ class _ChildCardWidgetState extends State<ChildCardWidget> {
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10.0 * scaleFactor), // Réduit de 12 à 10
|
||||
SizedBox(height: 10.0 * scaleFactor),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@@ -156,7 +172,7 @@ class _ChildCardWidgetState extends State<ChildCardWidget> {
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8.0 * scaleFactor), // Réduit de 9 à 8
|
||||
SizedBox(height: 8.0 * scaleFactor),
|
||||
_buildField(
|
||||
config: config,
|
||||
scaleFactor: scaleFactor,
|
||||
@@ -165,7 +181,7 @@ class _ChildCardWidgetState extends State<ChildCardWidget> {
|
||||
hint: 'Facultatif si à naître',
|
||||
isRequired: !widget.childData.isUnbornChild,
|
||||
),
|
||||
SizedBox(height: 5.0 * scaleFactor), // Réduit de 6 à 5
|
||||
SizedBox(height: 5.0 * scaleFactor),
|
||||
_buildField(
|
||||
config: config,
|
||||
scaleFactor: scaleFactor,
|
||||
@@ -173,18 +189,18 @@ class _ChildCardWidgetState extends State<ChildCardWidget> {
|
||||
controller: _lastNameController,
|
||||
hint: 'Nom de l\'enfant',
|
||||
),
|
||||
SizedBox(height: 8.0 * scaleFactor), // Réduit de 9 à 8
|
||||
SizedBox(height: 8.0 * scaleFactor),
|
||||
_buildField(
|
||||
config: config,
|
||||
scaleFactor: scaleFactor,
|
||||
label: widget.childData.isUnbornChild ? 'Date prévisionnelle de naissance' : 'Date de naissance',
|
||||
controller: _dobController,
|
||||
hint: 'JJ/MM/AAAA',
|
||||
readOnly: true, // Toujours readonly pour le TextField (date picker)
|
||||
readOnly: true,
|
||||
onTap: config.isReadonly ? null : widget.onDateSelect,
|
||||
suffixIcon: Icons.calendar_today,
|
||||
),
|
||||
SizedBox(height: 10.0 * scaleFactor), // Réduit de 11 à 10
|
||||
SizedBox(height: 10.0 * scaleFactor),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -195,7 +211,7 @@ class _ChildCardWidgetState extends State<ChildCardWidget> {
|
||||
checkboxSize: config.isMobile ? 20.0 : 22.0 * scaleFactor,
|
||||
fontSize: config.isMobile ? 13.0 : 16.0,
|
||||
),
|
||||
SizedBox(height: 5.0 * scaleFactor), // Réduit de 6 à 5
|
||||
SizedBox(height: 5.0 * scaleFactor),
|
||||
AppCustomCheckbox(
|
||||
label: 'Naissance multiple',
|
||||
value: widget.childData.multipleBirth,
|
||||
@@ -236,6 +252,310 @@ class _ChildCardWidgetState extends State<ChildCardWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Layout SPÉCIAL Readonly Desktop (Ancien Design Horizontal)
|
||||
Widget _buildReadonlyDesktopCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
// Convertir la couleur verticale (pour mobile) en couleur horizontale (pour desktop/récap)
|
||||
// On mappe les couleurs verticales vers horizontales
|
||||
String horizontalCardAsset = CardColorHorizontal.lavender.path; // Par défaut
|
||||
|
||||
// Mapping manuel simple
|
||||
if (widget.childData.cardColor.path.contains('lavender')) horizontalCardAsset = CardColorHorizontal.lavender.path;
|
||||
else if (widget.childData.cardColor.path.contains('blue')) horizontalCardAsset = CardColorHorizontal.blue.path;
|
||||
else if (widget.childData.cardColor.path.contains('green')) horizontalCardAsset = CardColorHorizontal.green.path;
|
||||
else if (widget.childData.cardColor.path.contains('lime')) horizontalCardAsset = CardColorHorizontal.lime.path;
|
||||
else if (widget.childData.cardColor.path.contains('peach')) horizontalCardAsset = CardColorHorizontal.peach.path;
|
||||
else if (widget.childData.cardColor.path.contains('pink')) horizontalCardAsset = CardColorHorizontal.pink.path;
|
||||
else if (widget.childData.cardColor.path.contains('red')) horizontalCardAsset = CardColorHorizontal.red.path;
|
||||
|
||||
final File? currentChildImage = widget.childData.imageFile;
|
||||
final cardWidth = screenSize.width / 2.0;
|
||||
|
||||
return SizedBox(
|
||||
width: cardWidth,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 2.0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 25.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(horizontalCardAsset),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Titre + Edit Button
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Enfant ${widget.childIndex + 1}' + (widget.childData.isUnbornChild ? ' (à naître)' : ''),
|
||||
style: GoogleFonts.merienda(fontSize: 28, fontWeight: FontWeight.w600),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 28),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Contenu principal : Photo + Champs
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
// PHOTO (1/3)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
child: currentChildImage != null
|
||||
? (kIsWeb
|
||||
? Image.network(currentChildImage.path, fit: BoxFit.cover)
|
||||
: Image.file(currentChildImage, fit: BoxFit.cover))
|
||||
: Image.asset('assets/images/photo.png', fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 32),
|
||||
|
||||
// CHAMPS (2/3)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_buildReadonlyField('Prénom :', _firstNameController.text),
|
||||
const SizedBox(height: 12),
|
||||
_buildReadonlyField('Nom :', _lastNameController.text),
|
||||
const SizedBox(height: 12),
|
||||
_buildReadonlyField(
|
||||
widget.childData.isUnbornChild ? 'Date prévisionnelle :' : 'Date de naissance :',
|
||||
_dobController.text
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Consentements
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
AppCustomCheckbox(
|
||||
label: 'Consentement photo',
|
||||
value: widget.childData.photoConsent,
|
||||
onChanged: (v) {}, // Readonly
|
||||
checkboxSize: 22.0,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
const SizedBox(width: 32),
|
||||
AppCustomCheckbox(
|
||||
label: 'Naissance multiple',
|
||||
value: widget.childData.multipleBirth,
|
||||
onChanged: (v) {}, // Readonly
|
||||
checkboxSize: 22.0,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Carte en mode readonly MOBILE avec hauteur adaptative
|
||||
Widget _buildReadonlyMobileCard(BuildContext context, DisplayConfig config) {
|
||||
final File? currentChildImage = widget.childData.imageFile;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
// Pas de height fixe
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 24.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(widget.childData.cardColor.path), // Image verticale
|
||||
fit: BoxFit.fill, // Fill pour s'adapter
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min, // S'adapte au contenu
|
||||
children: [
|
||||
// Titre + Edit Button
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Enfant ${widget.childIndex + 1}' + (widget.childData.isUnbornChild ? ' (à naître)' : ''),
|
||||
style: GoogleFonts.merienda(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
const SizedBox(width: 28),
|
||||
],
|
||||
),
|
||||
|
||||
// Contenu aligné en haut
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
// Photo
|
||||
SizedBox(
|
||||
height: 150,
|
||||
width: 150,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: currentChildImage != null
|
||||
? (kIsWeb
|
||||
? Image.network(currentChildImage.path, fit: BoxFit.cover)
|
||||
: Image.file(currentChildImage, fit: BoxFit.cover))
|
||||
: Image.asset('assets/images/photo.png', fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Champs
|
||||
_buildReadonlyField('Prénom :', _firstNameController.text),
|
||||
const SizedBox(height: 8),
|
||||
_buildReadonlyField('Nom :', _lastNameController.text),
|
||||
const SizedBox(height: 8),
|
||||
_buildReadonlyField(
|
||||
widget.childData.isUnbornChild ? 'Date prévisionnelle :' : 'Date de naissance :',
|
||||
_dobController.text
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Consentements
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
AppCustomCheckbox(
|
||||
label: 'Consentement photo',
|
||||
value: widget.childData.photoConsent,
|
||||
onChanged: (v) {},
|
||||
checkboxSize: 20.0,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
AppCustomCheckbox(
|
||||
label: 'Naissance multiple',
|
||||
value: widget.childData.multipleBirth,
|
||||
onChanged: (v) {},
|
||||
checkboxSize: 20.0,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
if (widget.onEdit != null)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 24),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Helper pour champ Readonly style "Beige"
|
||||
Widget _buildReadonlyField(String label, String value) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: GoogleFonts.merienda(fontSize: 22.0, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 50.0,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 12.0),
|
||||
decoration: BoxDecoration(
|
||||
image: const DecorationImage(
|
||||
image: AssetImage('assets/images/bg_beige.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
value.isNotEmpty ? value : '-',
|
||||
style: GoogleFonts.merienda(fontSize: 18.0),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildField({
|
||||
required DisplayConfig config,
|
||||
required double scaleFactor,
|
||||
|
||||
@@ -78,7 +78,7 @@ class FormFieldWrapper extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
|
||||
// Valeur
|
||||
// Valeur avec fond beige
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
@@ -86,20 +86,17 @@ class FormFieldWrapper extends StatelessWidget {
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF5F5F5),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: const Color(0xFFE0E0E0),
|
||||
width: 1,
|
||||
image: const DecorationImage(
|
||||
image: AssetImage('assets/images/bg_beige.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
value.isEmpty ? '-' : value,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: config.isMobile ? 14 : 16,
|
||||
color: value.isEmpty
|
||||
? const Color(0xFFBDBDBD)
|
||||
: const Color(0xFF2C2C2C),
|
||||
color: const Color(0xFF2C2C2C),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -48,6 +48,8 @@ class PersonalInfoFormScreen extends StatefulWidget {
|
||||
final bool showSameAddressCheckbox; // Afficher "Même adresse que parent 1"
|
||||
final bool? initialSameAddress;
|
||||
final PersonalInfoData? referenceAddressData; // Pour pré-remplir si "même adresse"
|
||||
final bool embedContentOnly; // Si true, affiche seulement la carte (sans scaffold/fond/titre)
|
||||
final VoidCallback? onEdit; // Callback pour le bouton d'édition (si affiché)
|
||||
|
||||
const PersonalInfoFormScreen({
|
||||
super.key,
|
||||
@@ -63,6 +65,8 @@ class PersonalInfoFormScreen extends StatefulWidget {
|
||||
this.showSameAddressCheckbox = false,
|
||||
this.initialSameAddress,
|
||||
this.referenceAddressData,
|
||||
this.embedContentOnly = false,
|
||||
this.onEdit,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -150,6 +154,10 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final config = DisplayConfig.fromContext(context, mode: widget.mode);
|
||||
|
||||
if (widget.embedContentOnly) {
|
||||
return _buildCard(context, config, screenSize);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
@@ -180,37 +188,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: config.isMobile ? 16 : 30),
|
||||
Container(
|
||||
width: config.isMobile ? screenSize.width * 0.9 : screenSize.width * 0.6,
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: config.isMobile ? 20 : 50,
|
||||
horizontal: config.isMobile ? 24 : 50,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
config.isMobile
|
||||
? _getVerticalCardAsset()
|
||||
: widget.cardColor.path
|
||||
),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Toggles "Ajouter Parent 2" et "Même Adresse" (uniquement en mode éditable)
|
||||
if (config.isEditable && widget.showSecondPersonToggle)
|
||||
_buildToggles(context, config),
|
||||
|
||||
// Champs du formulaire
|
||||
_buildFormFields(context, config),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildCard(context, config, screenSize),
|
||||
|
||||
// Boutons mobile sous la carte (dans le scroll)
|
||||
if (config.isMobile) ...[
|
||||
@@ -297,6 +275,198 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
// En mode readonly desktop avec embedContentOnly, utiliser le layout ancien (AspectRatio 2:1)
|
||||
if (config.isReadonly && !config.isMobile && widget.embedContentOnly) {
|
||||
return _buildReadonlyDesktopCard(context, config, screenSize);
|
||||
}
|
||||
|
||||
// En mode readonly mobile avec embedContentOnly, forcer le ratio 1:2 (Vertical)
|
||||
if (config.isReadonly && config.isMobile && widget.embedContentOnly) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width * 0.05), // Marge 5%
|
||||
child: _buildMobileReadonlyCard(context, config, screenSize),
|
||||
);
|
||||
}
|
||||
|
||||
// Mode normal (éditable ou mobile non-récap)
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Container(
|
||||
width: config.isMobile ? screenSize.width * 0.9 : screenSize.width * 0.6,
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: config.isMobile ? 20 : (config.isReadonly ? 30 : 50),
|
||||
horizontal: config.isMobile ? 24 : 50,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
config.isMobile
|
||||
? _getVerticalCardAsset()
|
||||
: widget.cardColor.path
|
||||
),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.embedContentOnly) ...[
|
||||
Text(
|
||||
// Titre raccourci sur mobile en mode readonly pour laisser place au bouton edit
|
||||
(config.isMobile && config.isReadonly && widget.title.contains('Parent Principal'))
|
||||
? 'Parent Principal'
|
||||
: widget.title,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: config.isMobile ? 18 : 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
|
||||
if (config.isEditable && widget.showSecondPersonToggle)
|
||||
_buildToggles(context, config),
|
||||
|
||||
_buildFormFields(context, config),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (config.isReadonly && widget.onEdit != null)
|
||||
Positioned(
|
||||
top: 10,
|
||||
right: 10,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 28),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Carte en mode readonly MOBILE avec hauteur adaptative
|
||||
Widget _buildMobileReadonlyCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
// Pas de height fixe, s'adapte au contenu
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 24.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(_getVerticalCardAsset()),
|
||||
fit: BoxFit.fill, // Fill pour que l'image s'étire selon la hauteur du contenu
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min, // Important : prend le min de place
|
||||
children: [
|
||||
// Titre + Edit Button
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
(widget.title.contains('Parent Principal') ? 'Parent Principal' : (widget.title.contains('Deuxième Parent') ? 'Deuxième Parent' : widget.title)),
|
||||
style: GoogleFonts.merienda(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
const SizedBox(width: 28),
|
||||
],
|
||||
),
|
||||
|
||||
// Contenu aligné en haut (plus d'Expanded ici car parent non contraint)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: _buildFormFields(context, config),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
if (widget.onEdit != null)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 24),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Carte en mode readonly desktop avec AspectRatio 2:1 (format de l'ancien récapitulatif)
|
||||
Widget _buildReadonlyDesktopCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
// Largeur de la carte : 50% de l'écran (comme l'ancien système)
|
||||
final cardWidth = screenSize.width / 2.0;
|
||||
|
||||
return SizedBox(
|
||||
width: cardWidth,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 2.0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 25.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(widget.cardColor.path),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Titre centré
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 55), // Espace très augmenté pour pousser les champs vers le bas
|
||||
// Champs du formulaire
|
||||
_buildFormFields(context, config),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Bouton d'édition à droite
|
||||
if (widget.onEdit != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 28),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Construit les toggles (Parent 2 / Même adresse)
|
||||
Widget _buildToggles(BuildContext context, DisplayConfig config) {
|
||||
if (config.isMobile) {
|
||||
@@ -305,10 +475,10 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
children: [
|
||||
_buildSecondPersonToggle(context, config),
|
||||
if (widget.showSameAddressCheckbox) ...[
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 5), // Réduit de 12 à 5
|
||||
_buildSameAddressToggle(context, config),
|
||||
],
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: 10), // Réduit de 24 à 10
|
||||
],
|
||||
);
|
||||
} else {
|
||||
@@ -392,7 +562,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
value: _sameAddress,
|
||||
onChanged: _fieldsEnabled ? (value) {
|
||||
setState(() {
|
||||
_sameAddress = value ?? false;
|
||||
_sameAddress = value;
|
||||
_updateAddressFields();
|
||||
});
|
||||
} : null,
|
||||
@@ -414,6 +584,14 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
|
||||
/// Layout DESKTOP : champs côte à côte (horizontal)
|
||||
Widget _buildDesktopFields(BuildContext context, DisplayConfig config) {
|
||||
// En mode readonly, utiliser l'ancien layout du récapitulatif
|
||||
if (config.isReadonly) {
|
||||
return _buildReadonlyDesktopFields(context);
|
||||
}
|
||||
|
||||
// Mode éditable : layout normal
|
||||
final double verticalSpacing = 32.0;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
// Nom et Prénom
|
||||
@@ -440,7 +618,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(height: verticalSpacing),
|
||||
|
||||
// Téléphone et Email
|
||||
Row(
|
||||
@@ -468,7 +646,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(height: verticalSpacing),
|
||||
|
||||
// Adresse
|
||||
_buildField(
|
||||
@@ -478,7 +656,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
hint: 'Numéro et nom de votre rue',
|
||||
enabled: _fieldsEnabled && !_sameAddress,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(height: verticalSpacing),
|
||||
|
||||
// Code Postal et Ville
|
||||
Row(
|
||||
@@ -511,8 +689,154 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Layout DESKTOP en mode READONLY : réplique l'ancien design du récapitulatif
|
||||
Widget _buildReadonlyDesktopFields(BuildContext context) {
|
||||
const double verticalSpacing = 20.0; // Réduit pour compacter le bas
|
||||
const double labelFontSize = 22.0;
|
||||
const double valueFontSize = 18.0; // Taille du texte dans les champs
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
// Ligne 1 : Nom + Prénom
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildDisplayFieldValue(
|
||||
context,
|
||||
'Nom :',
|
||||
_lastNameController.text,
|
||||
labelFontSize: labelFontSize,
|
||||
valueFontSize: valueFontSize,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(
|
||||
child: _buildDisplayFieldValue(
|
||||
context,
|
||||
'Prénom :',
|
||||
_firstNameController.text,
|
||||
labelFontSize: labelFontSize,
|
||||
valueFontSize: valueFontSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
|
||||
// Ligne 2 : Téléphone + Email
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildDisplayFieldValue(
|
||||
context,
|
||||
'Téléphone :',
|
||||
_phoneController.text,
|
||||
labelFontSize: labelFontSize,
|
||||
valueFontSize: valueFontSize,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(
|
||||
child: _buildDisplayFieldValue(
|
||||
context,
|
||||
'Email :',
|
||||
_emailController.text,
|
||||
multiLine: true,
|
||||
labelFontSize: labelFontSize,
|
||||
valueFontSize: valueFontSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: verticalSpacing),
|
||||
|
||||
// Ligne 3 : Adresse complète (adresse + CP + ville)
|
||||
_buildDisplayFieldValue(
|
||||
context,
|
||||
'Adresse :',
|
||||
"${_addressController.text}\n${_postalCodeController.text} ${_cityController.text}".trim(),
|
||||
multiLine: true,
|
||||
fieldHeight: 80,
|
||||
labelFontSize: labelFontSize,
|
||||
valueFontSize: valueFontSize,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Helper pour afficher un champ en lecture seule avec le style de l'ancien récap
|
||||
Widget _buildDisplayFieldValue(
|
||||
BuildContext context,
|
||||
String label,
|
||||
String value, {
|
||||
bool multiLine = false,
|
||||
double fieldHeight = 50.0,
|
||||
double labelFontSize = 18.0,
|
||||
double valueFontSize = 18.0, // Taille du texte dans le champ
|
||||
}) {
|
||||
const FontWeight labelFontWeight = FontWeight.w600;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: labelFontSize,
|
||||
fontWeight: labelFontWeight,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: multiLine ? null : fieldHeight,
|
||||
constraints: multiLine ? const BoxConstraints(minHeight: 50.0) : null,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 12.0),
|
||||
decoration: BoxDecoration(
|
||||
image: const DecorationImage(
|
||||
image: AssetImage('assets/images/bg_beige.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
value.isNotEmpty ? value : '-',
|
||||
style: GoogleFonts.merienda(fontSize: valueFontSize),
|
||||
maxLines: multiLine ? null : 1,
|
||||
overflow: multiLine ? TextOverflow.visible : TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Layout MOBILE : tous les champs empilés verticalement
|
||||
Widget _buildMobileFields(BuildContext context, DisplayConfig config) {
|
||||
// Mode Readonly Mobile : Layout compact et groupé
|
||||
if (config.isReadonly) {
|
||||
// NOTE: FormFieldWrapper ajoute déjà un padding vertical (8px mobile),
|
||||
// donc on n'ajoute pas de SizedBox supplémentaire ici pour éviter un double espacement.
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
_buildField(config: config, label: 'Nom', controller: _lastNameController),
|
||||
_buildField(config: config, label: 'Prénom', controller: _firstNameController),
|
||||
_buildField(config: config, label: 'Téléphone', controller: _phoneController),
|
||||
_buildField(config: config, label: 'Email', controller: _emailController),
|
||||
// Adresse complète en un seul bloc multiligne
|
||||
FormFieldWrapper(
|
||||
config: config,
|
||||
label: 'Adresse',
|
||||
value: "${_addressController.text}\n${_postalCodeController.text} ${_cityController.text}".trim(),
|
||||
maxLines: 3,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Mode Editable Mobile : Layout standard avec champs séparés
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
|
||||
@@ -23,6 +23,9 @@ class PresentationFormScreen extends StatefulWidget {
|
||||
final String previousRoute;
|
||||
final Function(String text, bool cguAccepted) onSubmit;
|
||||
|
||||
final bool embedContentOnly;
|
||||
final VoidCallback? onEdit;
|
||||
|
||||
const PresentationFormScreen({
|
||||
super.key,
|
||||
this.mode = DisplayMode.editable,
|
||||
@@ -34,6 +37,8 @@ class PresentationFormScreen extends StatefulWidget {
|
||||
required this.initialCguAccepted,
|
||||
required this.previousRoute,
|
||||
required this.onSubmit,
|
||||
this.embedContentOnly = false,
|
||||
this.onEdit,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -75,6 +80,10 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final config = DisplayConfig.fromContext(context, mode: widget.mode);
|
||||
|
||||
if (widget.embedContentOnly) {
|
||||
return _buildCard(context, config, screenSize);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
@@ -154,7 +163,7 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
|
||||
const SizedBox(height: 16),
|
||||
// Carte qui prend tout l'espace restant
|
||||
Expanded(
|
||||
child: _buildMobileCard(context, config, screenSize),
|
||||
child: _buildCard(context, config, screenSize),
|
||||
),
|
||||
// Boutons en bas
|
||||
const SizedBox(height: 20),
|
||||
@@ -188,13 +197,228 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
_buildDesktopCard(context, config, screenSize),
|
||||
_buildCard(context, config, screenSize),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Wrapper pour la carte (Mobile ou Desktop)
|
||||
Widget _buildCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
// Si mode Readonly Desktop : Layout spécial "Vintage" horizontal (2:1)
|
||||
if (config.isReadonly && !config.isMobile && widget.embedContentOnly) {
|
||||
return _buildReadonlyDesktopCard(context, config, screenSize);
|
||||
}
|
||||
|
||||
// Si mode Readonly Mobile : Layout spécial "Vintage" vertical (1:2)
|
||||
if (config.isReadonly && config.isMobile && widget.embedContentOnly) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width * 0.05),
|
||||
child: _buildMobileReadonlyCard(context, config, screenSize),
|
||||
);
|
||||
}
|
||||
|
||||
final Widget cardContent = config.isMobile
|
||||
? _buildMobileCard(context, config, screenSize)
|
||||
: _buildDesktopCard(context, config, screenSize);
|
||||
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
if (widget.embedContentOnly)
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: config.isMobile ? 18 : 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
cardContent,
|
||||
],
|
||||
)
|
||||
else
|
||||
cardContent,
|
||||
|
||||
if (config.isReadonly && widget.onEdit != null)
|
||||
Positioned(
|
||||
top: widget.embedContentOnly ? 50 : 10,
|
||||
right: 10,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Carte en mode readonly MOBILE avec hauteur adaptative
|
||||
Widget _buildMobileReadonlyCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
// Pas de height fixe, s'adapte au contenu
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 24.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(_getVerticalCardAsset()),
|
||||
fit: BoxFit.fill, // Fill pour que l'image s'étire selon la hauteur du contenu
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min, // S'adapte au contenu
|
||||
children: [
|
||||
// Titre + Edit Button
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
const SizedBox(width: 28),
|
||||
],
|
||||
),
|
||||
|
||||
// Contenu aligné en haut (Texte scrollable + Checkbox)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
// Champ texte scrollable
|
||||
// On utilise ConstrainedBox pour limiter la hauteur max
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 300), // Max height pour éviter une carte infinie
|
||||
child: CustomDecoratedTextField(
|
||||
controller: _textController,
|
||||
hintText: widget.textFieldHint,
|
||||
fieldHeight: null, // Flexible
|
||||
maxLines: 100,
|
||||
expandDynamically: true, // Scrollable
|
||||
fontSize: 14.0,
|
||||
readOnly: config.isReadonly,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Checkbox
|
||||
Transform.scale(
|
||||
scale: 0.85,
|
||||
child: AppCustomCheckbox(
|
||||
label: 'J\'accepte les CGU et la\nPolitique de confidentialité',
|
||||
value: _cguAccepted,
|
||||
onChanged: (v) {},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
if (widget.onEdit != null)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 24),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Carte en mode readonly desktop avec AspectRatio 2:1 (format de l'ancien récapitulatif)
|
||||
Widget _buildReadonlyDesktopCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
// Largeur de la carte : 50% de l'écran
|
||||
final cardWidth = screenSize.width / 2.0;
|
||||
|
||||
return SizedBox(
|
||||
width: cardWidth,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 2.0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 25.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(widget.cardColor.path),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Titre + Edit Button
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: GoogleFonts.merienda(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black87),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 28),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Texte de motivation
|
||||
Expanded(
|
||||
child: CustomDecoratedTextField(
|
||||
controller: _textController,
|
||||
hintText: '',
|
||||
fieldHeight: double.infinity, // Remplit l'espace disponible
|
||||
maxLines: 10,
|
||||
expandDynamically: false, // Fixe pour le readonly
|
||||
fontSize: 18.0,
|
||||
readOnly: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// CGU
|
||||
AppCustomCheckbox(
|
||||
label: 'J\'accepte les Conditions Générales\nd\'Utilisation et la Politique de confidentialité',
|
||||
value: _cguAccepted,
|
||||
onChanged: (v) {}, // Readonly
|
||||
checkboxSize: 22.0,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Carte DESKTOP : Format horizontal 2:1
|
||||
Widget _buildDesktopCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
final cardWidth = screenSize.width * 0.6;
|
||||
@@ -223,13 +447,14 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
|
||||
maxLines: 10,
|
||||
expandDynamically: true,
|
||||
fontSize: 18.0,
|
||||
readOnly: config.isReadonly,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
AppCustomCheckbox(
|
||||
label: 'J\'accepte les Conditions Générales\nd\'Utilisation et la Politique de confidentialité',
|
||||
value: _cguAccepted,
|
||||
onChanged: (value) => setState(() => _cguAccepted = value ?? false),
|
||||
onChanged: config.isReadonly ? (v) {} : (value) => setState(() => _cguAccepted = value ?? false),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -239,6 +464,26 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
|
||||
|
||||
/// Carte MOBILE : Prend tout l'espace disponible
|
||||
Widget _buildMobileCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
// Le contenu du champ texte
|
||||
Widget textFieldContent = LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
// En mode embed (récap), constraints.maxHeight peut être infini, donc on fixe une hauteur par défaut
|
||||
// En mode standalone, on utilise la hauteur disponible
|
||||
double height = constraints.maxHeight;
|
||||
if (height.isInfinite) height = 200.0;
|
||||
|
||||
return CustomDecoratedTextField(
|
||||
controller: _textController,
|
||||
hintText: widget.textFieldHint,
|
||||
fieldHeight: height,
|
||||
maxLines: 100,
|
||||
expandDynamically: false,
|
||||
fontSize: 14.0,
|
||||
readOnly: config.isReadonly,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width * 0.05),
|
||||
child: Container(
|
||||
@@ -251,21 +496,14 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
|
||||
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
// Champ de texte qui prend l'espace disponible et scrollable
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return CustomDecoratedTextField(
|
||||
controller: _textController,
|
||||
hintText: widget.textFieldHint,
|
||||
fieldHeight: constraints.maxHeight,
|
||||
maxLines: 100, // Grande valeur pour permettre le scroll
|
||||
expandDynamically: false,
|
||||
fontSize: 14.0,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
// Champ de texte
|
||||
if (widget.embedContentOnly)
|
||||
// En mode récapitulatif, on donne une hauteur fixe pour éviter l'erreur d'Expanded
|
||||
SizedBox(height: 200, child: textFieldContent)
|
||||
else
|
||||
// En mode écran complet, on prend tout l'espace restant
|
||||
Expanded(child: textFieldContent),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
// Checkbox en bas
|
||||
Transform.scale(
|
||||
@@ -273,7 +511,7 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
|
||||
child: AppCustomCheckbox(
|
||||
label: 'J\'accepte les CGU et la\nPolitique de confidentialité',
|
||||
value: _cguAccepted,
|
||||
onChanged: (value) => setState(() => _cguAccepted = value ?? false),
|
||||
onChanged: config.isReadonly ? (v) {} : (value) => setState(() => _cguAccepted = value ?? false),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'dart:io';
|
||||
import '../models/card_assets.dart';
|
||||
import '../config/display_config.dart';
|
||||
import 'custom_app_text_field.dart';
|
||||
import 'form_field_wrapper.dart';
|
||||
import 'app_custom_checkbox.dart';
|
||||
import 'hover_relief_widget.dart';
|
||||
import 'custom_navigation_button.dart';
|
||||
@@ -48,6 +49,8 @@ class ProfessionalInfoFormScreen extends StatefulWidget {
|
||||
final String previousRoute;
|
||||
final Function(ProfessionalInfoData) onSubmit;
|
||||
final Future<void> Function()? onPickPhoto;
|
||||
final bool embedContentOnly;
|
||||
final VoidCallback? onEdit;
|
||||
|
||||
const ProfessionalInfoFormScreen({
|
||||
super.key,
|
||||
@@ -59,6 +62,8 @@ class ProfessionalInfoFormScreen extends StatefulWidget {
|
||||
required this.previousRoute,
|
||||
required this.onSubmit,
|
||||
this.onPickPhoto,
|
||||
this.embedContentOnly = false,
|
||||
this.onEdit,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -170,6 +175,10 @@ class _ProfessionalInfoFormScreenState extends State<ProfessionalInfoFormScreen>
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final config = DisplayConfig.fromContext(context, mode: widget.mode);
|
||||
|
||||
if (widget.embedContentOnly) {
|
||||
return _buildCard(context, config, screenSize);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
@@ -200,29 +209,8 @@ class _ProfessionalInfoFormScreenState extends State<ProfessionalInfoFormScreen>
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: config.isMobile ? 16 : 30),
|
||||
Container(
|
||||
width: config.isMobile ? screenSize.width * 0.9 : screenSize.width * 0.6,
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: config.isMobile ? 20 : 50,
|
||||
horizontal: config.isMobile ? 24 : 50,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
config.isMobile
|
||||
? _getVerticalCardAsset()
|
||||
: widget.cardColor.path
|
||||
),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: config.isMobile
|
||||
? _buildMobileFields(context, config)
|
||||
: _buildDesktopFields(context, config),
|
||||
),
|
||||
),
|
||||
_buildCard(context, config, screenSize),
|
||||
|
||||
// Boutons mobile sous la carte
|
||||
if (config.isMobile) ...[
|
||||
const SizedBox(height: 20),
|
||||
@@ -271,8 +259,308 @@ class _ProfessionalInfoFormScreenState extends State<ProfessionalInfoFormScreen>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
// Si mode Readonly Desktop : Layout spécial "Vintage" horizontal
|
||||
if (config.isReadonly && !config.isMobile && widget.embedContentOnly) {
|
||||
return _buildReadonlyDesktopCard(context, config, screenSize);
|
||||
}
|
||||
|
||||
// Si mode Readonly Mobile : Layout spécial "Vintage" vertical
|
||||
if (config.isReadonly && config.isMobile && widget.embedContentOnly) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: screenSize.width * 0.05),
|
||||
child: _buildMobileReadonlyCard(context, config, screenSize),
|
||||
);
|
||||
}
|
||||
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Container(
|
||||
width: config.isMobile ? screenSize.width * 0.9 : screenSize.width * 0.6,
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: config.isMobile ? 20 : (config.isReadonly ? 30 : 50),
|
||||
horizontal: config.isMobile ? 24 : 50,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
config.isMobile
|
||||
? _getVerticalCardAsset()
|
||||
: widget.cardColor.path
|
||||
),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.embedContentOnly) ...[
|
||||
Text(
|
||||
widget.title,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: config.isMobile ? 18 : 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
config.isMobile
|
||||
? _buildMobileFields(context, config)
|
||||
: _buildDesktopFields(context, config),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (config.isReadonly && widget.onEdit != null)
|
||||
Positioned(
|
||||
top: 10,
|
||||
right: 10,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Carte en mode readonly MOBILE avec hauteur adaptative
|
||||
Widget _buildMobileReadonlyCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
// Pas de height fixe
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 24.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(_getVerticalCardAsset()),
|
||||
fit: BoxFit.fill, // Fill pour s'adapter
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Titre + Edit Button
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
const SizedBox(width: 28),
|
||||
],
|
||||
),
|
||||
|
||||
// Contenu aligné en haut
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: _buildMobileFields(context, config),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
if (widget.onEdit != null)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 24),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Carte en mode readonly desktop avec AspectRatio 2:1
|
||||
Widget _buildReadonlyDesktopCard(BuildContext context, DisplayConfig config, Size screenSize) {
|
||||
final cardWidth = screenSize.width / 2.0;
|
||||
|
||||
return SizedBox(
|
||||
width: cardWidth,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 2.0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 25.0),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(widget.cardColor.path),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Titre + Edit Button
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: GoogleFonts.merienda(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black87),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black54, size: 28),
|
||||
onPressed: widget.onEdit,
|
||||
tooltip: 'Modifier',
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Contenu
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
// PHOTO (1/3)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
child: _photoFile != null
|
||||
? Image.file(_photoFile!, fit: BoxFit.cover)
|
||||
: (_photoPathFramework != null && _photoPathFramework!.startsWith('assets/')
|
||||
? Image.asset(_photoPathFramework!, fit: BoxFit.contain)
|
||||
: Image.asset('assets/images/photo.png', fit: BoxFit.contain)),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
AppCustomCheckbox(
|
||||
label: 'J\'accepte l\'utilisation\nde ma photo.',
|
||||
value: _photoConsent,
|
||||
onChanged: (v) {}, // Readonly
|
||||
checkboxSize: 22.0,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 32),
|
||||
|
||||
// CHAMPS (2/3) - Layout optimisé compact
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Ligne 1 : Ville + Pays
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: _buildReadonlyField('Ville de naissance', _birthCityController.text)),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(child: _buildReadonlyField('Pays de naissance', _birthCountryController.text)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Ligne 2 : Date + NIR (NIR prend plus de place si possible ou 50/50)
|
||||
Row(
|
||||
children: [
|
||||
Expanded(flex: 2, child: _buildReadonlyField('Date de naissance', _dateOfBirthController.text)),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(flex: 3, child: _buildReadonlyField('NIR', _nirController.text)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Ligne 3 : Agrément + Capacité
|
||||
Row(
|
||||
children: [
|
||||
Expanded(flex: 3, child: _buildReadonlyField('N° Agrément', _agrementController.text)),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(flex: 2, child: _buildReadonlyField('Capacité', _capacityController.text)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Helper pour champ Readonly style "Beige"
|
||||
Widget _buildReadonlyField(String label, String value) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: GoogleFonts.merienda(fontSize: 18.0, fontWeight: FontWeight.w600),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 45.0, // Hauteur réduite pour compacter
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10.0),
|
||||
decoration: BoxDecoration(
|
||||
image: const DecorationImage(
|
||||
image: AssetImage('assets/images/bg_beige.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
value.isNotEmpty ? value : '-',
|
||||
style: GoogleFonts.merienda(fontSize: 16.0),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Layout DESKTOP : Photo à gauche, champs à droite
|
||||
Widget _buildDesktopFields(BuildContext context, DisplayConfig config) {
|
||||
final double verticalSpacing = config.isReadonly ? 16.0 : 32.0;
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -296,7 +584,7 @@ class _ProfessionalInfoFormScreenState extends State<ProfessionalInfoFormScreen>
|
||||
hint: 'Votre ville de naissance',
|
||||
validator: (v) => v!.isEmpty ? 'Ville requise' : null,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(height: verticalSpacing),
|
||||
_buildField(
|
||||
config: config,
|
||||
label: 'Pays de naissance',
|
||||
@@ -304,7 +592,7 @@ class _ProfessionalInfoFormScreenState extends State<ProfessionalInfoFormScreen>
|
||||
hint: 'Votre pays de naissance',
|
||||
validator: (v) => v!.isEmpty ? 'Pays requis' : null,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(height: verticalSpacing),
|
||||
_buildField(
|
||||
config: config,
|
||||
label: 'Date de naissance',
|
||||
@@ -320,7 +608,7 @@ class _ProfessionalInfoFormScreenState extends State<ProfessionalInfoFormScreen>
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(height: verticalSpacing),
|
||||
_buildField(
|
||||
config: config,
|
||||
label: 'N° Sécurité Sociale (NIR)',
|
||||
@@ -334,7 +622,7 @@ class _ProfessionalInfoFormScreenState extends State<ProfessionalInfoFormScreen>
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(height: verticalSpacing),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@@ -509,20 +797,28 @@ class _ProfessionalInfoFormScreenState extends State<ProfessionalInfoFormScreen>
|
||||
IconData? suffixIcon,
|
||||
String? Function(String?)? validator,
|
||||
}) {
|
||||
return CustomAppTextField(
|
||||
controller: controller,
|
||||
labelText: label,
|
||||
hintText: hint ?? label,
|
||||
fieldWidth: double.infinity,
|
||||
fieldHeight: config.isMobile ? 45.0 : 53.0,
|
||||
labelFontSize: config.isMobile ? 15.0 : 22.0,
|
||||
inputFontSize: config.isMobile ? 14.0 : 20.0,
|
||||
keyboardType: keyboardType ?? TextInputType.text,
|
||||
readOnly: readOnly,
|
||||
onTap: onTap,
|
||||
suffixIcon: suffixIcon,
|
||||
validator: validator,
|
||||
);
|
||||
if (config.isReadonly) {
|
||||
return FormFieldWrapper(
|
||||
config: config,
|
||||
label: label,
|
||||
value: controller.text,
|
||||
);
|
||||
} else {
|
||||
return CustomAppTextField(
|
||||
controller: controller,
|
||||
labelText: label,
|
||||
hintText: hint ?? label,
|
||||
fieldWidth: double.infinity,
|
||||
fieldHeight: config.isMobile ? 45.0 : 53.0,
|
||||
labelFontSize: config.isMobile ? 15.0 : 22.0,
|
||||
inputFontSize: config.isMobile ? 14.0 : 20.0,
|
||||
keyboardType: keyboardType ?? TextInputType.text,
|
||||
readOnly: readOnly,
|
||||
onTap: onTap,
|
||||
suffixIcon: suffixIcon,
|
||||
validator: validator,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Boutons mobile
|
||||
|
||||
@@ -230,11 +230,12 @@ Widget buildDisplayFieldValue(
|
||||
height: multiLine ? null : fieldHeight,
|
||||
constraints: multiLine ? const BoxConstraints(minHeight: 50.0) : null,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 12.0),
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/input_field_bg.png'),
|
||||
decoration: BoxDecoration(
|
||||
image: const DecorationImage(
|
||||
image: AssetImage('assets/images/bg_beige.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
value.isNotEmpty ? value : '-',
|
||||
|
||||
Reference in New Issue
Block a user