Nouvelle architecture centralisée pour tous les formulaires : **Configuration centrale (display_config.dart):** - DisplayMode enum (editable/readonly) - LayoutType enum (mobile/desktop) - DisplayConfig class pour configuration complète - LayoutHelper avec utilitaires (détection, spacing, etc.) - Breakpoint: 600px (mobile < 600px reste toujours vertical) **Widgets génériques (form_field_wrapper.dart):** - FormFieldWrapper: champ auto-adaptatif (TextField ou Text readonly) - FormFieldRow: ligne responsive (horizontal desktop, vertical mobile) **Structure de page (base_form_screen.dart):** - BaseFormScreen: layout complet avec carte, boutons, navigation - Gestion auto des assets carte (horizontal/vertical selon layout) **Avantages:** ✅ Code unique pour editable + readonly + mobile + desktop ✅ Logique centralisée (aucune duplication) ✅ Héritage automatique via DisplayConfig propagé ✅ API simple et cohérente Prochaine étape: Migration des widgets existants Référence: #78 Co-authored-by: Cursor <cursoragent@cursor.com>
107 lines
2.7 KiB
Dart
107 lines
2.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
/// Mode d'affichage d'un formulaire
|
|
enum DisplayMode {
|
|
/// Mode éditable (formulaire d'inscription)
|
|
editable,
|
|
|
|
/// Mode lecture seule (récapitulatif)
|
|
readonly,
|
|
}
|
|
|
|
/// Configuration d'affichage pour les widgets de formulaire
|
|
class DisplayConfig {
|
|
/// Mode d'affichage (editable/readonly)
|
|
final DisplayMode mode;
|
|
|
|
/// Type de layout détecté (mobile/desktop)
|
|
final LayoutType layoutType;
|
|
|
|
const DisplayConfig({
|
|
required this.mode,
|
|
required this.layoutType,
|
|
});
|
|
|
|
/// Crée une config à partir du contexte
|
|
factory DisplayConfig.fromContext(
|
|
BuildContext context, {
|
|
required DisplayMode mode,
|
|
}) {
|
|
return DisplayConfig(
|
|
mode: mode,
|
|
layoutType: LayoutHelper.getLayoutType(context),
|
|
);
|
|
}
|
|
|
|
/// Est en mode éditable
|
|
bool get isEditable => mode == DisplayMode.editable;
|
|
|
|
/// Est en mode lecture seule
|
|
bool get isReadonly => mode == DisplayMode.readonly;
|
|
|
|
/// Est en layout mobile
|
|
bool get isMobile => layoutType == LayoutType.mobile;
|
|
|
|
/// Est en layout desktop
|
|
bool get isDesktop => layoutType == LayoutType.desktop;
|
|
|
|
/// Layout vertical (mobile)
|
|
bool get isVerticalLayout => isMobile;
|
|
|
|
/// Layout horizontal (desktop)
|
|
bool get isHorizontalLayout => isDesktop;
|
|
}
|
|
|
|
/// Type de layout
|
|
enum LayoutType {
|
|
/// Mobile (< 600px) - toujours vertical
|
|
mobile,
|
|
|
|
/// Desktop/Tablette (≥ 600px) - horizontal
|
|
desktop,
|
|
}
|
|
|
|
/// Utilitaires pour la détection de layout
|
|
class LayoutHelper {
|
|
/// Seuil de largeur pour mobile/desktop (en pixels)
|
|
static const double mobileBreakpoint = 600.0;
|
|
|
|
/// Détermine le type de layout selon la largeur d'écran
|
|
static LayoutType getLayoutType(BuildContext context) {
|
|
final width = MediaQuery.of(context).size.width;
|
|
return width < mobileBreakpoint
|
|
? LayoutType.mobile
|
|
: LayoutType.desktop;
|
|
}
|
|
|
|
/// Vérifie si on est sur mobile
|
|
static bool isMobile(BuildContext context) {
|
|
return getLayoutType(context) == LayoutType.mobile;
|
|
}
|
|
|
|
/// Vérifie si on est sur desktop
|
|
static bool isDesktop(BuildContext context) {
|
|
return getLayoutType(context) == LayoutType.desktop;
|
|
}
|
|
|
|
/// Retourne un espacement adapté au layout
|
|
static double getSpacing(BuildContext context, {
|
|
double mobileSpacing = 12.0,
|
|
double desktopSpacing = 20.0,
|
|
}) {
|
|
return isMobile(context) ? mobileSpacing : desktopSpacing;
|
|
}
|
|
|
|
/// Retourne une largeur max adaptée au layout
|
|
static double getMaxWidth(BuildContext context, {
|
|
double? mobileMaxWidth,
|
|
double? desktopMaxWidth,
|
|
}) {
|
|
if (isMobile(context)) {
|
|
return mobileMaxWidth ?? double.infinity;
|
|
} else {
|
|
return desktopMaxWidth ?? 1200.0;
|
|
}
|
|
}
|
|
}
|