Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acda4244a9 | ||
|
|
14efccc711 | ||
|
|
916d83755f | ||
|
|
a442766096 | ||
|
|
8bd1694f70 | ||
|
|
4042d5823e |
+34
@@ -0,0 +1,34 @@
|
||||
name: Flutter Code Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev, feature/*, hotfix]
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
|
||||
jobs:
|
||||
flutter-check:
|
||||
name: Analyse & Test Flutter
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: ⬇️ Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: 💡 Set up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: '3.19.0' # ou celle que tu utilises
|
||||
channel: stable
|
||||
|
||||
- name: 📦 Install dependencies
|
||||
run: flutter pub get
|
||||
|
||||
- name: 🔍 Dart Analyzer
|
||||
run: flutter analyze
|
||||
|
||||
# - name: 🧪 Run tests (if present)
|
||||
# run: flutter test || echo "No tests found"
|
||||
|
||||
- name: 🧱 Build (Flutter Web)
|
||||
run: flutter build web --release
|
||||
@@ -0,0 +1,74 @@
|
||||
# 🚀 Guide de contribution – Projet P'titsPas (Flutter)
|
||||
|
||||
Bienvenue ! Ce guide explique comment collaborer efficacement sur ce projet Flutter.
|
||||
|
||||
---
|
||||
|
||||
## 📌 Branches Git
|
||||
|
||||
Le projet suit une stratégie de branches simple et efficace :
|
||||
|
||||
| Branche | Rôle |
|
||||
|---------------|---------------------------------------------|
|
||||
| `main` | Production (version stable déployée) |
|
||||
| `develop` | Intégration (version en cours de test) |
|
||||
| `feature/XXX` | Développement d’une nouvelle fonctionnalité |
|
||||
| `fix/XXX` | Correction de bug |
|
||||
| `hotfix/XXX` | Patch urgent sur `main` |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Cycle de développement
|
||||
|
||||
1. **Crée une branche à partir de `develop`**
|
||||
```bash
|
||||
git checkout develop
|
||||
git pull origin develop
|
||||
git checkout -b feature/FRONT-XXX-nom-fonctionnalite
|
||||
|
||||
2. Travaille localement + commit régulièrement
|
||||
|
||||
Commits clairs et concis :
|
||||
Nom de la branche: Fonctionnalité push
|
||||
|
||||
```bash
|
||||
git commit -m "FRONT-021: ajout du widget zone enfants"
|
||||
```
|
||||
|
||||
3. Pousse ta branche
|
||||
|
||||
Exemple
|
||||
```bash
|
||||
git push origin feature/FRONT-XXX-nom
|
||||
|
||||
|
||||
4. Ouvre une Pull Request vers develop
|
||||
|
||||
Ps : **La PR vers develop est faite lorsque une fonctionnalité du ticket à été fait et testé ou lorsque tous le ticket est finis**
|
||||
- Titre : [FRONT-021] Widget zone enfants
|
||||
|
||||
- Description : ce que tu as fait, ce qu’il reste à tester
|
||||
- Lie le ticket associé (ex: Fixes #21)
|
||||
|
||||
5. Relecture & Merge
|
||||
- Au moins 1 review nécessaire
|
||||
- Pas de commit direct sur develop ou main
|
||||
|
||||
6. Une fois merge, supprime la branche distante:
|
||||
|
||||
PS: **La branche est supprimé que lorsque tout le ticket a été consommé**
|
||||
```bash
|
||||
git push origin --delete feature/FRONT-XXX-nom
|
||||
```
|
||||
|
||||
🧼 Règles de bonne conduite
|
||||
|
||||
- Une PR = une seule fonctionnalité ou correction
|
||||
|
||||
- Code commenté si logique complexe
|
||||
|
||||
- Garder les noms de variables/dossiers clairs et en anglais
|
||||
|
||||
- Pas de code mort ou non utilisé
|
||||
|
||||
- Tester les commandes du workflow(dans le .github) afin d'être sur de ne pas avoir des erreur dans le code et pour etre sur de passer les tests du Workflow
|
||||
@@ -14,3 +14,56 @@ A few resources to get you started if this is your first Flutter project:
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
|
||||
### Workflow Git
|
||||
|
||||
Le projet suit un **Git Flow simplifié** avec 3 branches principales :
|
||||
|
||||
- `main` : version stable et déployée en production
|
||||
- `develop` : version intégrée et testée avant passage en production
|
||||
- `feature/*`, `fix/*`, `hotfix/*` : branches spécifiques au développement
|
||||
|
||||
**Cycle standard :**
|
||||
```bash
|
||||
# Création d’une feature
|
||||
git checkout develop
|
||||
git checkout -b feature/FRONT-021-zone-enfants
|
||||
|
||||
# Développement
|
||||
git add .
|
||||
git commit -m "FRONT-021: Widget zone enfants"
|
||||
git push origin feature/FRONT-021-zone-enfants
|
||||
|
||||
# Pull Request => vers develop
|
||||
# Merge → suppression de la branche
|
||||
Voir CONTRIBUTING.md pour les conventions détaillées.
|
||||
```
|
||||
### Structure du projet Flutter
|
||||
|
||||
Le projet suit une architecture modulaire MVC simplifiée compatible avec Provider (ou Riverpod léger).
|
||||
|
||||
```plaintext
|
||||
lib/
|
||||
├── main.dart # Point d’entrée
|
||||
├── routes/ # go_router ou auto_route
|
||||
├── models/ # Classes de données (User, Parent, Enfant, etc.)
|
||||
├── services/ # Requêtes HTTP, AuthService, StorageService
|
||||
├── utils/ # Helpers, validateurs, formatteurs
|
||||
├── widgets/ # Composants UI réutilisables
|
||||
├── screens/ # Pages par grande fonctionnalité
|
||||
│ ├── auth/ # Connexion, inscription, mot de passe oublié
|
||||
│ ├── registration/ # Création parent / assistante maternelle
|
||||
│ ├── dashboard/ # Tableau de bord parent / AM / gestionnaire
|
||||
│ ├── profile/ # Gestion des infos utilisateur
|
||||
│ └── children/ # Fiches enfants
|
||||
```
|
||||
|
||||
### Architecture choisie
|
||||
🟩 Type : MVC Modulaire avec Provider (ou Riverpod léger)
|
||||
|
||||
Avantages :
|
||||
|
||||
- Simple à prendre en main
|
||||
- Rapide à structurer
|
||||
- Permet la séparation des features
|
||||
- Adaptée à un projet Flutter Web PWA
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
flutter.sdk=C:\\Users\\marti\\dev\\flutter
|
||||
flutter.sdk=C:\\Users\\myhan\\flutter
|
||||
sdk.dir=C:\\Users\\myhan\\AppData\\Local\\Android\\Sdk
|
||||
@@ -0,0 +1,96 @@
|
||||
import 'dart:io';
|
||||
|
||||
class ChildminderId {
|
||||
String firstName;
|
||||
String lastName;
|
||||
String address;
|
||||
String postalCode;
|
||||
String city;
|
||||
String phone;
|
||||
String email;
|
||||
String password;
|
||||
File? profilePicture;
|
||||
bool photoConsent;
|
||||
|
||||
ChildminderId({
|
||||
this.firstName = '',
|
||||
this.lastName = '',
|
||||
this.address = '',
|
||||
this.postalCode = '',
|
||||
this.city = '',
|
||||
this.phone = '',
|
||||
this.email = '',
|
||||
this.password = '',
|
||||
this.profilePicture,
|
||||
this.photoConsent = false,
|
||||
});
|
||||
}
|
||||
|
||||
class ChildminderProfessional {
|
||||
String dateOfBirth;
|
||||
String birthCity;
|
||||
String birthCountry;
|
||||
String socialSecurityNumber; // NIR
|
||||
String agreementNumber;
|
||||
int maxChildren;
|
||||
|
||||
ChildminderProfessional({
|
||||
this.dateOfBirth = '',
|
||||
this.birthCity = '',
|
||||
this.birthCountry = '',
|
||||
this.socialSecurityNumber = '',
|
||||
this.agreementNumber = '',
|
||||
this.maxChildren = 1,
|
||||
});
|
||||
}
|
||||
|
||||
class ChildminderRegistrationData {
|
||||
ChildminderId identity;
|
||||
ChildminderProfessional professional;
|
||||
String presentationMessage;
|
||||
bool cguAccepted;
|
||||
bool isPhotoRequired;
|
||||
|
||||
ChildminderRegistrationData({
|
||||
ChildminderId? identityData,
|
||||
ChildminderProfessional? professionalData,
|
||||
this.presentationMessage = '',
|
||||
this.cguAccepted = false,
|
||||
this.isPhotoRequired = false,
|
||||
}) : identity = identityData ?? ChildminderId(),
|
||||
professional = professionalData ?? ChildminderProfessional();
|
||||
|
||||
void updateIdentity(ChildminderId data) {
|
||||
identity = data;
|
||||
}
|
||||
|
||||
void updateProfessional(ChildminderProfessional data) {
|
||||
professional = data;
|
||||
}
|
||||
|
||||
void updatePresentation(String message) {
|
||||
presentationMessage = message;
|
||||
}
|
||||
|
||||
void acceptCGU() {
|
||||
cguAccepted = true;
|
||||
}
|
||||
|
||||
bool get isComplete {
|
||||
return identity.firstName.isNotEmpty &&
|
||||
identity.lastName.isNotEmpty &&
|
||||
identity.address.isNotEmpty &&
|
||||
identity.postalCode.isNotEmpty &&
|
||||
identity.city.isNotEmpty &&
|
||||
identity.phone.isNotEmpty &&
|
||||
identity.email.isNotEmpty &&
|
||||
identity.password.isNotEmpty &&
|
||||
professional.dateOfBirth.isNotEmpty &&
|
||||
professional.birthCity.isNotEmpty &&
|
||||
professional.birthCountry.isNotEmpty &&
|
||||
professional.socialSecurityNumber.isNotEmpty &&
|
||||
professional.agreementNumber.isNotEmpty &&
|
||||
cguAccepted &&
|
||||
(!isPhotoRequired || (identity.profilePicture != null && identity.photoConsent));
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:p_tits_pas/screens/auth/am/am_register_step1_sceen.dart';
|
||||
import '../screens/auth/login_screen.dart';
|
||||
import '../screens/auth/register_choice_screen.dart';
|
||||
import '../screens/auth/parent_register_step1_screen.dart';
|
||||
import '../screens/auth/parent_register_step2_screen.dart';
|
||||
import '../screens/auth/parent_register_step3_screen.dart';
|
||||
import '../screens/auth/parent_register_step4_screen.dart';
|
||||
import '../screens/auth/parent_register_step5_screen.dart';
|
||||
import '../screens/auth/parent/parent_register_step1_screen.dart';
|
||||
import '../screens/auth/parent/parent_register_step2_screen.dart';
|
||||
import '../screens/auth/parent/parent_register_step3_screen.dart';
|
||||
import '../screens/auth/parent/parent_register_step4_screen.dart';
|
||||
import '../screens/auth/parent/parent_register_step5_screen.dart';
|
||||
import '../screens/home/home_screen.dart';
|
||||
import '../models/user_registration_data.dart';
|
||||
import '../models/parent_user_registration_data.dart';
|
||||
|
||||
class AppRouter {
|
||||
static const String login = '/login';
|
||||
@@ -18,6 +19,8 @@ class AppRouter {
|
||||
static const String parentRegisterStep3 = '/parent-register/step3';
|
||||
static const String parentRegisterStep4 = '/parent-register/step4';
|
||||
static const String parentRegisterStep5 = '/parent-register/step5';
|
||||
|
||||
static const String amRegisterStep1 = '/am-register/step1';
|
||||
static const String home = '/home';
|
||||
|
||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||
@@ -74,6 +77,10 @@ class AppRouter {
|
||||
}
|
||||
slideTransition = true;
|
||||
break;
|
||||
case amRegisterStep1:
|
||||
screen = const AmRegisterStep1Screen();
|
||||
slideTransition = true;
|
||||
break;
|
||||
case home:
|
||||
screen = const HomeScreen();
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/models/am_user_registration_data.dart';
|
||||
import 'package:p_tits_pas/models/card_assets.dart';
|
||||
import 'package:p_tits_pas/utils/data_generator.dart';
|
||||
import 'package:p_tits_pas/widgets/FormFieldConfig.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
|
||||
class AmRegisterStep1Screen extends StatefulWidget {
|
||||
const AmRegisterStep1Screen({super.key});
|
||||
@override
|
||||
State <AmRegisterStep1Screen> createState() => _AmRegisterStep1ScreenState();
|
||||
}
|
||||
|
||||
class _AmRegisterStep1ScreenState extends State<AmRegisterStep1Screen> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late ChildminderRegistrationData _registrationData;
|
||||
|
||||
final _lastNameController = TextEditingController();
|
||||
final _firstNameController = TextEditingController();
|
||||
final _phoneController = TextEditingController();
|
||||
final _emailController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
final _confirmPasswordController = TextEditingController();
|
||||
final _addressController = TextEditingController();
|
||||
final _postalCodeController = TextEditingController();
|
||||
final _cityController = TextEditingController();
|
||||
|
||||
// File? _selectedImage;
|
||||
// bool _photoConsent = false;
|
||||
// final ImagePicker _picker = ImagePicker();
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_registrationData = ChildminderRegistrationData();
|
||||
_generateAndFillData();
|
||||
}
|
||||
|
||||
void _generateAndFillData() {
|
||||
final String genFirstName = DataGenerator.firstName();
|
||||
final String genLastName = DataGenerator.lastName();
|
||||
|
||||
_addressController.text = DataGenerator.address();
|
||||
_postalCodeController.text = DataGenerator.postalCode();
|
||||
_cityController.text = DataGenerator.city();
|
||||
_firstNameController.text = genFirstName;
|
||||
_lastNameController.text = genLastName;
|
||||
_phoneController.text = DataGenerator.phone();
|
||||
_emailController.text = DataGenerator.email(genFirstName, genLastName);
|
||||
_passwordController.text = DataGenerator.password();
|
||||
_confirmPasswordController.text = _passwordController.text;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_lastNameController.dispose();
|
||||
_firstNameController.dispose();
|
||||
_phoneController.dispose();
|
||||
_emailController.dispose();
|
||||
_passwordController.dispose();
|
||||
_confirmPasswordController.dispose();
|
||||
_addressController.dispose();
|
||||
_postalCodeController.dispose();
|
||||
_cityController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
List<List<ModularFormField>> get formFields => [
|
||||
[
|
||||
ModularFormField(
|
||||
label: 'Nom',
|
||||
hint: 'Votre nom de famille',
|
||||
controller: _lastNameController,
|
||||
isRequired: true,
|
||||
flex: 12,
|
||||
),
|
||||
ModularFormField(
|
||||
label: 'Prénom',
|
||||
hint: 'Votre prénom',
|
||||
controller: _firstNameController,
|
||||
isRequired: true,
|
||||
flex: 12,
|
||||
),
|
||||
],
|
||||
[
|
||||
ModularFormField(
|
||||
label: 'Téléphone',
|
||||
hint: 'Votre numéro de téléphone',
|
||||
controller: _phoneController,
|
||||
keyboardType: TextInputType.phone,
|
||||
flex: 12,
|
||||
),
|
||||
ModularFormField(
|
||||
label: 'Email',
|
||||
hint: 'Votre adresse email',
|
||||
controller: _emailController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
flex: 12,
|
||||
),
|
||||
],
|
||||
[
|
||||
ModularFormField(
|
||||
label: 'Mot de passe',
|
||||
hint: 'Votre mot de passe',
|
||||
controller: _passwordController,
|
||||
isPassword: true,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) return 'Mot de passe requis';
|
||||
if (value.length < 6) return '6 caractères minimum';
|
||||
return null;
|
||||
},
|
||||
isRequired: true,
|
||||
flex: 12,
|
||||
),
|
||||
ModularFormField(
|
||||
label: 'Confirmer le mot de passe',
|
||||
hint: 'Confirmez votre mot de passe',
|
||||
controller: _confirmPasswordController,
|
||||
isPassword: true,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) return 'Mot de passe requis';
|
||||
if (value != _passwordController.text) return 'Les mots de passe ne correspondent pas';
|
||||
return null;
|
||||
},
|
||||
isRequired: true,
|
||||
flex: 12,
|
||||
),
|
||||
],
|
||||
[
|
||||
ModularFormField(
|
||||
label: 'Adresse (N° et Rue)',
|
||||
hint: 'Numéro et nom de votre rue',
|
||||
controller: _addressController,
|
||||
isRequired: true,
|
||||
),
|
||||
],
|
||||
[
|
||||
ModularFormField(
|
||||
label: 'Code postal',
|
||||
hint: 'Votre code postal',
|
||||
controller: _postalCodeController,
|
||||
keyboardType: TextInputType.number,
|
||||
isRequired: true,
|
||||
flex: 1,
|
||||
),
|
||||
ModularFormField(
|
||||
label: 'Ville',
|
||||
hint: 'Votre ville',
|
||||
controller: _cityController,
|
||||
flex: 4,
|
||||
isRequired: true,
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
void _handleSubmit() {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
_registrationData.updateIdentity(
|
||||
ChildminderId(
|
||||
firstName: _firstNameController.text,
|
||||
lastName: _lastNameController.text,
|
||||
address: _addressController.text,
|
||||
postalCode: _postalCodeController.text,
|
||||
city: _cityController.text,
|
||||
phone: _phoneController.text,
|
||||
email: _emailController.text,
|
||||
password: _passwordController.text,
|
||||
),
|
||||
);
|
||||
Navigator.pushNamed(context, '/am-register/step2',
|
||||
arguments: _registrationData);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Image.asset(
|
||||
'assets/images/paper2.png',
|
||||
fit: BoxFit.cover,
|
||||
repeat: ImageRepeat.repeat,
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Étape 1/4',
|
||||
style: GoogleFonts.merienda(fontSize: 16, color: Colors.black54),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'Informations de l\'assistante maternelle',
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Container(
|
||||
width: screenSize.width * 0.6,
|
||||
padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 50),
|
||||
constraints: const BoxConstraints(minHeight: 570),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(CardColorHorizontal.lavender.path),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: ModularForm(
|
||||
formKey: _formKey,
|
||||
fieldGroups: formFields,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: screenSize.height / 2 - 20,
|
||||
left: 40,
|
||||
child: IconButton(
|
||||
icon: Transform(
|
||||
alignment: Alignment.center,
|
||||
transform: Matrix4.rotationY(math.pi),
|
||||
child: Image.asset('assets/images/chevron_right.png', height: 40),
|
||||
),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
tooltip: 'Retour',
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: screenSize.height / 2 - 20,
|
||||
right: 40,
|
||||
child: IconButton(
|
||||
icon: Image.asset('assets/images/chevron_right.png', height: 40),
|
||||
onPressed: _handleSubmit,
|
||||
tooltip: 'Suivant',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'dart:math' as math; // Pour la rotation du chevron
|
||||
import '../../models/user_registration_data.dart'; // Import du modèle de données
|
||||
import '../../utils/data_generator.dart'; // Import du générateur de données
|
||||
import '../../widgets/custom_app_text_field.dart'; // Import du widget CustomAppTextField
|
||||
import '../../models/card_assets.dart'; // Import des enums de cartes
|
||||
import '../../../models/parent_user_registration_data.dart'; // Import du modèle de données
|
||||
import '../../../utils/data_generator.dart'; // Import du générateur de données
|
||||
import '../../../widgets/custom_app_text_field.dart'; // Import du widget CustomAppTextField
|
||||
import '../../../models/card_assets.dart'; // Import des enums de cartes
|
||||
|
||||
class ParentRegisterStep1Screen extends StatefulWidget {
|
||||
const ParentRegisterStep1Screen({super.key});
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'dart:math' as math; // Pour la rotation du chevron
|
||||
import '../../models/user_registration_data.dart'; // Import du modèle
|
||||
import '../../utils/data_generator.dart'; // Import du générateur
|
||||
import '../../widgets/custom_app_text_field.dart'; // Import du widget
|
||||
import '../../models/card_assets.dart'; // Import des enums de cartes
|
||||
import '../../../models/parent_user_registration_data.dart'; // Import du modèle
|
||||
import '../../../utils/data_generator.dart'; // Import du générateur
|
||||
import '../../../widgets/custom_app_text_field.dart'; // Import du widget
|
||||
import '../../../models/card_assets.dart'; // Import des enums de cartes
|
||||
|
||||
class ParentRegisterStep2Screen extends StatefulWidget {
|
||||
final UserRegistrationData registrationData; // Accepte les données de l'étape 1
|
||||
+6
-6
@@ -2,16 +2,16 @@ import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'dart:math' as math; // Pour la rotation du chevron
|
||||
import 'package:flutter/gestures.dart'; // Pour PointerDeviceKind
|
||||
import '../../widgets/hover_relief_widget.dart'; // Import du nouveau widget
|
||||
import '../../../widgets/hover_relief_widget.dart'; // Import du nouveau widget
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
// import 'package:image_cropper/image_cropper.dart'; // Supprimé
|
||||
import 'dart:io' show File, Platform; // Ajout de Platform
|
||||
import 'package:flutter/foundation.dart' show kIsWeb; // Import pour kIsWeb
|
||||
import '../../widgets/custom_app_text_field.dart'; // Import du nouveau widget TextField
|
||||
import '../../widgets/app_custom_checkbox.dart'; // Import du nouveau widget Checkbox
|
||||
import '../../models/user_registration_data.dart'; // Import du modèle de données
|
||||
import '../../utils/data_generator.dart'; // Import du générateur
|
||||
import '../../models/card_assets.dart'; // Import des enums de cartes
|
||||
import '../../../widgets/custom_app_text_field.dart'; // Import du nouveau widget TextField
|
||||
import '../../../widgets/app_custom_checkbox.dart'; // Import du nouveau widget Checkbox
|
||||
import '../../../models/parent_user_registration_data.dart'; // Import du modèle de données
|
||||
import '../../../utils/data_generator.dart'; // Import du générateur
|
||||
import '../../../models/card_assets.dart'; // Import des enums de cartes
|
||||
|
||||
// La classe _ChildFormData est supprimée car on utilise ChildData du modèle
|
||||
|
||||
+3
-3
@@ -4,9 +4,9 @@ import 'package:p_tits_pas/widgets/custom_decorated_text_field.dart'; // Import
|
||||
import 'dart:math' as math; // Pour la rotation du chevron
|
||||
import 'package:p_tits_pas/widgets/app_custom_checkbox.dart'; // Import de la checkbox personnalisée
|
||||
// import 'package:p_tits_pas/models/placeholder_registration_data.dart'; // Remplacé
|
||||
import '../../models/user_registration_data.dart'; // Import du vrai modèle
|
||||
import '../../utils/data_generator.dart'; // Import du générateur
|
||||
import '../../models/card_assets.dart'; // Import des enums de cartes
|
||||
import '../../../models/parent_user_registration_data.dart'; // Import du vrai modèle
|
||||
import '../../../utils/data_generator.dart'; // Import du générateur
|
||||
import '../../../models/card_assets.dart'; // Import des enums de cartes
|
||||
|
||||
class ParentRegisterStep4Screen extends StatefulWidget {
|
||||
final UserRegistrationData registrationData; // Accepte les données
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../models/user_registration_data.dart'; // Utilisation du vrai modèle
|
||||
import '../../widgets/image_button.dart'; // Import du ImageButton
|
||||
import '../../models/card_assets.dart'; // Import des enums de cartes
|
||||
import '../../../models/parent_user_registration_data.dart'; // Utilisation du vrai modèle
|
||||
import '../../../widgets/image_button.dart'; // Import du ImageButton
|
||||
import '../../../models/card_assets.dart'; // Import des enums de cartes
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import '../../widgets/custom_decorated_text_field.dart'; // Import du CustomDecoratedTextField
|
||||
import '../../../widgets/custom_decorated_text_field.dart'; // Import du CustomDecoratedTextField
|
||||
|
||||
// Nouvelle méthode helper pour afficher un champ de type "lecture seule" stylisé
|
||||
Widget _buildDisplayFieldValue(BuildContext context, String label, String value, {bool multiLine = false, double fieldHeight = 50.0, double labelFontSize = 18.0}) {
|
||||
@@ -100,6 +100,8 @@ class RegisterChoiceScreen extends StatelessWidget {
|
||||
onPressed: () {
|
||||
// TODO: Naviguer vers l'écran d'inscription assmat
|
||||
print('Choix: Assistante Maternelle');
|
||||
Navigator.pushNamed(context, '/am-register/step1');
|
||||
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:p_tits_pas/widgets/custom_app_text_field.dart';
|
||||
|
||||
class ModularFormField {
|
||||
final String label;
|
||||
final String hint;
|
||||
final TextEditingController controller;
|
||||
final TextInputType? keyboardType;
|
||||
final bool isPassword;
|
||||
final String? Function(String?)? validator;
|
||||
final bool isRequired;
|
||||
final int flex;
|
||||
|
||||
ModularFormField({
|
||||
required this.label,
|
||||
required this.hint,
|
||||
required this.controller,
|
||||
this.keyboardType,
|
||||
this.isPassword = false,
|
||||
this.validator,
|
||||
this.isRequired = false,
|
||||
this.flex = 1,
|
||||
});
|
||||
}
|
||||
|
||||
class ModularForm extends StatelessWidget {
|
||||
final List<List<ModularFormField>> fieldGroups;
|
||||
final GlobalKey<FormState> formKey;
|
||||
final double? width;
|
||||
final EdgeInsets padding;
|
||||
final String? title;
|
||||
final VoidCallback? onSubmit;
|
||||
final String submitLabel;
|
||||
|
||||
const ModularForm({
|
||||
super.key,
|
||||
required this.fieldGroups,
|
||||
required this.formKey,
|
||||
this.width,
|
||||
this.padding = const EdgeInsets.all(20),
|
||||
this.title,
|
||||
this.onSubmit,
|
||||
this.submitLabel = "Suivant",
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: width ?? MediaQuery.of(context).size.width * 0.6,
|
||||
padding: padding,
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (title != null) ...[
|
||||
Text(
|
||||
title!,
|
||||
style: GoogleFonts.merienda(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
...fieldGroups.map((group) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: group.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
final field = entry.value;
|
||||
|
||||
return [
|
||||
Expanded(
|
||||
flex: field.flex,
|
||||
child: CustomAppTextField(
|
||||
controller: field.controller,
|
||||
labelText: field.label,
|
||||
hintText: field.hint,
|
||||
obscureText: field.isPassword,
|
||||
keyboardType: field.keyboardType ?? TextInputType.text,
|
||||
validator: field.validator,
|
||||
style: CustomAppTextFieldStyle.beige,
|
||||
fieldWidth: double.infinity, // CORRECTION PRINCIPALE
|
||||
),
|
||||
),
|
||||
// Ajouter un espaceur entre les champs (sauf pour le dernier)
|
||||
if (index < group.length - 1)
|
||||
const Expanded(
|
||||
flex: 1,
|
||||
child: SizedBox(), // Espacement de 4% comme dans l'original
|
||||
),
|
||||
];
|
||||
}).expand((element) => element).toList(),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
if (onSubmit != null)
|
||||
Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: onSubmit,
|
||||
child: Text(submitLabel),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user