feat: Gestion des secteurs et migration v3.0.4+304
- Ajout système complet de gestion des secteurs avec contours géographiques - Import des contours départementaux depuis GeoJSON - API REST pour la gestion des secteurs (/api/sectors) - Service de géolocalisation pour déterminer les secteurs - Migration base de données avec tables x_departements_contours et sectors_adresses - Interface Flutter pour visualisation et gestion des secteurs - Ajout thème sombre dans l'application - Corrections diverses et optimisations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
242
app/lib/presentation/widgets/passage_form_modernized_example.dart
Executable file
242
app/lib/presentation/widgets/passage_form_modernized_example.dart
Executable file
@@ -0,0 +1,242 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geosector_app/presentation/widgets/custom_text_field.dart';
|
||||
import 'package:geosector_app/presentation/widgets/form_section.dart';
|
||||
|
||||
/// Exemple d'utilisation modernisée du formulaire de passage
|
||||
/// utilisant CustomTextField et FormSection adaptés
|
||||
class PassageFormModernizedExample extends StatefulWidget {
|
||||
final bool readOnly;
|
||||
|
||||
const PassageFormModernizedExample({
|
||||
super.key,
|
||||
this.readOnly = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PassageFormModernizedExample> createState() => _PassageFormModernizedExampleState();
|
||||
}
|
||||
|
||||
class _PassageFormModernizedExampleState extends State<PassageFormModernizedExample> {
|
||||
// Controllers pour l'exemple
|
||||
final _numeroController = TextEditingController();
|
||||
final _rueBisController = TextEditingController();
|
||||
final _rueController = TextEditingController();
|
||||
final _villeController = TextEditingController();
|
||||
final _dateController = TextEditingController();
|
||||
final _timeController = TextEditingController();
|
||||
final _nameController = TextEditingController();
|
||||
final _emailController = TextEditingController();
|
||||
final _phoneController = TextEditingController();
|
||||
final _montantController = TextEditingController();
|
||||
final _remarqueController = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_numeroController.dispose();
|
||||
_rueBisController.dispose();
|
||||
_rueController.dispose();
|
||||
_villeController.dispose();
|
||||
_dateController.dispose();
|
||||
_timeController.dispose();
|
||||
_nameController.dispose();
|
||||
_emailController.dispose();
|
||||
_phoneController.dispose();
|
||||
_montantController.dispose();
|
||||
_remarqueController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _selectDate() {
|
||||
// Logique de sélection de date
|
||||
}
|
||||
|
||||
void _selectTime() {
|
||||
// Logique de sélection d'heure
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Formulaire Modernisé')),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
// Section Date et Heure avec FormSection
|
||||
FormSection(
|
||||
title: 'Date et Heure de passage',
|
||||
icon: Icons.schedule,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _dateController,
|
||||
label: "Date",
|
||||
isRequired: true,
|
||||
readOnly: true,
|
||||
showLabel: false,
|
||||
hintText: "DD/MM/YYYY",
|
||||
suffixIcon: const Icon(Icons.calendar_today),
|
||||
onTap: widget.readOnly ? null : _selectDate,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _timeController,
|
||||
label: "Heure",
|
||||
isRequired: true,
|
||||
readOnly: true,
|
||||
showLabel: false,
|
||||
hintText: "HH:MM",
|
||||
suffixIcon: const Icon(Icons.access_time),
|
||||
onTap: widget.readOnly ? null : _selectTime,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Section Adresse
|
||||
FormSection(
|
||||
title: 'Adresse',
|
||||
icon: Icons.location_on,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: CustomTextField(
|
||||
controller: _numeroController,
|
||||
label: "Numéro",
|
||||
isRequired: true,
|
||||
showLabel: false,
|
||||
textAlign: TextAlign.right,
|
||||
keyboardType: TextInputType.number,
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: CustomTextField(
|
||||
controller: _rueBisController,
|
||||
label: "Bis/Ter",
|
||||
showLabel: false,
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
CustomTextField(
|
||||
controller: _rueController,
|
||||
label: "Rue",
|
||||
isRequired: true,
|
||||
showLabel: false,
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
CustomTextField(
|
||||
controller: _villeController,
|
||||
label: "Ville",
|
||||
isRequired: true,
|
||||
showLabel: false,
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Section Occupant
|
||||
FormSection(
|
||||
title: 'Occupant',
|
||||
icon: Icons.person,
|
||||
children: [
|
||||
CustomTextField(
|
||||
controller: _nameController,
|
||||
label: "Nom de l'occupant",
|
||||
isRequired: true,
|
||||
showLabel: false,
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _emailController,
|
||||
label: "Email",
|
||||
showLabel: false,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _phoneController,
|
||||
label: "Téléphone",
|
||||
showLabel: false,
|
||||
keyboardType: TextInputType.phone,
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Section Règlement (sans bordure)
|
||||
FormSection(
|
||||
title: '',
|
||||
showBorder: true,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextField(
|
||||
controller: _montantController,
|
||||
label: "Montant (€)",
|
||||
isRequired: true,
|
||||
showLabel: false,
|
||||
hintText: "0.00",
|
||||
textAlign: TextAlign.right,
|
||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Theme.of(context).colorScheme.outline),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Text("Dropdown de type de règlement"),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
CustomTextField(
|
||||
controller: _remarqueController,
|
||||
label: "Remarque",
|
||||
showLabel: false,
|
||||
hintText: "Commentaire sur le passage...",
|
||||
maxLines: 2,
|
||||
readOnly: widget.readOnly,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user