feat: Début des évolutions interfaces mobiles v3.2.4

- Préparation de la nouvelle branche pour les évolutions
- Mise à jour de la version vers 3.2.4
- Intégration des modifications en cours

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-04 16:49:29 +02:00
parent 2187dccfeb
commit 2786252307
86 changed files with 3434 additions and 180898 deletions

View File

@@ -40,15 +40,10 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
// État du tri actuel
PassageSortType _currentSort = PassageSortType.dateDesc;
// État des filtres
String selectedSector = 'Tous';
String selectedPeriod = 'Tous';
String selectedType = 'Tous';
String selectedPaymentMethod = 'Tous';
DateTimeRange? selectedDateRange;
// IDs pour les filtres
// État des filtres (uniquement pour synchronisation)
int? selectedSectorId;
String selectedPeriod = 'Toutes';
DateTimeRange? selectedDateRange;
// Repository pour les secteurs
late SectorRepository _sectorRepository;
@@ -130,20 +125,11 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
try {
// Charger le secteur présélectionné
final int? preselectedSectorId = _settingsBox.get('history_selectedSectorId');
final String? preselectedSectorName = _settingsBox.get('history_selectedSectorName');
final int? preselectedTypeId = _settingsBox.get('history_selectedTypeId');
final String? preselectedPeriod = _settingsBox.get('history_selectedPeriod');
final int? preselectedPaymentId = _settingsBox.get('history_selectedPaymentId');
if (preselectedSectorId != null && preselectedSectorName != null) {
if (preselectedSectorId != null) {
selectedSectorId = preselectedSectorId;
selectedSector = preselectedSectorName;
debugPrint('Secteur présélectionné: $preselectedSectorName (ID: $preselectedSectorId)');
}
if (preselectedTypeId != null) {
selectedType = preselectedTypeId.toString();
debugPrint('Type de passage présélectionné: $preselectedTypeId');
debugPrint('Secteur présélectionné: ID $preselectedSectorId');
}
if (preselectedPeriod != null) {
@@ -152,11 +138,6 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
debugPrint('Période présélectionnée: $preselectedPeriod');
}
if (preselectedPaymentId != null) {
selectedPaymentMethod = preselectedPaymentId.toString();
debugPrint('Mode de règlement présélectionné: $preselectedPaymentId');
}
// Nettoyer les valeurs après utilisation
_settingsBox.delete('history_selectedSectorId');
_settingsBox.delete('history_selectedSectorName');
@@ -173,26 +154,11 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
try {
if (selectedSectorId != null) {
_settingsBox.put('history_selectedSectorId', selectedSectorId);
_settingsBox.put('history_selectedSectorName', selectedSector);
}
if (selectedType != 'Tous') {
final typeId = int.tryParse(selectedType);
if (typeId != null) {
_settingsBox.put('history_selectedTypeId', typeId);
}
}
if (selectedPeriod != 'Tous') {
if (selectedPeriod != 'Toutes') {
_settingsBox.put('history_selectedPeriod', selectedPeriod);
}
if (selectedPaymentMethod != 'Tous') {
final paymentId = int.tryParse(selectedPaymentMethod);
if (paymentId != null) {
_settingsBox.put('history_selectedPaymentId', paymentId);
}
}
} catch (e) {
debugPrint('Erreur lors de la sauvegarde des préférences: $e');
}
@@ -201,7 +167,6 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
// Mettre à jour le filtre par secteur
void _updateSectorFilter(String sectorName, int? sectorId) {
setState(() {
selectedSector = sectorName;
selectedSectorId = sectorId;
});
_saveFilterPreferences();
@@ -328,21 +293,6 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
return false;
}
// Filtrer par type
if (selectedType != 'Tous') {
final typeId = int.tryParse(selectedType);
if (typeId != null && passage['type'] != typeId) {
return false;
}
}
// Filtrer par mode de règlement
if (selectedPaymentMethod != 'Tous') {
final paymentId = int.tryParse(selectedPaymentMethod);
if (paymentId != null && passage['payment'] != paymentId) {
return false;
}
}
// Filtrer par période/date
if (selectedDateRange != null && passage['date'] is DateTime) {
@@ -654,210 +604,9 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
);
}
// Construction des filtres
Widget _buildFilters(BuildContext context) {
final theme = Theme.of(context);
final size = MediaQuery.of(context).size;
final isDesktop = size.width > 900;
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
color: Colors.white.withValues(alpha: 0.95),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Filtres',
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: theme.colorScheme.primary,
),
),
const SizedBox(height: 16),
if (isDesktop)
Row(
children: [
// Filtre par secteur (si plusieurs secteurs)
if (_userSectors.length > 1)
Expanded(
child: _buildSectorFilter(theme),
),
if (_userSectors.length > 1)
const SizedBox(width: 16),
// Filtre par période
Expanded(
child: _buildPeriodFilter(theme),
),
],
)
else
Column(
children: [
// Filtre par secteur (si plusieurs secteurs)
if (_userSectors.length > 1) ...[
_buildSectorFilter(theme),
const SizedBox(height: 16),
],
// Filtre par période
_buildPeriodFilter(theme),
],
),
],
),
),
);
}
// Les filtres sont maintenant gérés directement dans le PassagesListWidget
// Construction du filtre par secteur
Widget _buildSectorFilter(ThemeData theme) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Secteur',
style: theme.textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12.0),
decoration: BoxDecoration(
border: Border.all(color: theme.colorScheme.outline),
borderRadius: BorderRadius.circular(8.0),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: selectedSector,
isExpanded: true,
icon: const Icon(Icons.arrow_drop_down),
items: [
const DropdownMenuItem<String>(
value: 'Tous',
child: Text('Tous les secteurs'),
),
..._userSectors.map((sector) {
final String libelle = sector.libelle.isNotEmpty
? sector.libelle
: 'Secteur ${sector.id}';
return DropdownMenuItem<String>(
value: libelle,
child: Text(
libelle,
overflow: TextOverflow.ellipsis,
),
);
}),
],
onChanged: (String? value) {
if (value != null) {
if (value == 'Tous') {
_updateSectorFilter('Tous', null);
} else {
try {
final sector = _userSectors.firstWhere(
(s) => s.libelle == value,
);
_updateSectorFilter(value, sector.id);
} catch (e) {
debugPrint('Erreur lors de la sélection du secteur: $e');
_updateSectorFilter('Tous', null);
}
}
}
},
),
),
),
],
);
}
// Construction du filtre par période
Widget _buildPeriodFilter(ThemeData theme) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Période',
style: theme.textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12.0),
decoration: BoxDecoration(
border: Border.all(color: theme.colorScheme.outline),
borderRadius: BorderRadius.circular(8.0),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: selectedPeriod,
isExpanded: true,
icon: const Icon(Icons.arrow_drop_down),
items: const [
DropdownMenuItem<String>(
value: 'Tous',
child: Text('Toutes les périodes'),
),
DropdownMenuItem<String>(
value: 'Derniers 15 jours',
child: Text('Derniers 15 jours'),
),
DropdownMenuItem<String>(
value: 'Dernière semaine',
child: Text('Dernière semaine'),
),
DropdownMenuItem<String>(
value: 'Dernier mois',
child: Text('Dernier mois'),
),
],
onChanged: (String? value) {
if (value != null) {
_updatePeriodFilter(value);
}
},
),
),
),
// Afficher la plage de dates sélectionnée si elle existe
if (selectedDateRange != null && selectedPeriod != 'Tous')
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
children: [
Icon(
Icons.date_range,
size: 16,
color: theme.colorScheme.primary,
),
const SizedBox(width: 8),
Text(
'Du ${selectedDateRange!.start.day}/${selectedDateRange!.start.month}/${selectedDateRange!.start.year} au ${selectedDateRange!.end.day}/${selectedDateRange!.end.month}/${selectedDateRange!.end.year}',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
);
}
// Méthodes de filtre retirées car maintenant gérées dans le widget
@override
Widget build(BuildContext context) {
@@ -869,18 +618,7 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Filtres avec bouton de rafraîchissement
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Filtres (secteur et période) avec bouton rafraîchir
if (!_isLoading && (_userSectors.length > 1 || selectedPeriod != 'Tous'))
_buildFilters(context),
],
),
),
// Les filtres sont maintenant intégrés dans le PassagesListWidget
// Affichage du chargement ou des erreurs
if (_isLoading)
@@ -944,14 +682,31 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
}
}
// Appliquer les filtres
passagesMap = _getFilteredPassages(passagesMap);
// Appliquer le tri sélectionné
passagesMap = _sortPassages(passagesMap);
return PassagesListWidget(
showAddButton: true, // Activer le bouton de création
// Données
passages: passagesMap,
// Activation des filtres
showFilters: true,
showSearch: true,
showTypeFilter: true,
showPaymentFilter: true,
showSectorFilter: true,
showUserFilter: false, // Pas de filtre membre pour la page user
showPeriodFilter: true,
// Données pour les filtres
sectors: _userSectors,
members: null, // Pas de filtre membre pour la page user
// Valeurs initiales
initialSectorId: selectedSectorId,
initialPeriod: selectedPeriod,
dateRange: selectedDateRange,
// Filtre par utilisateur courant
filterByUserId: currentUserId,
// Bouton d'ajout
showAddButton: true,
onAddPassage: () async {
// Ouvrir le dialogue de création de passage
await showDialog(
@@ -1041,17 +796,17 @@ class _UserHistoryPageState extends State<UserHistoryPage> {
),
],
),
passages: passagesMap,
showFilters: true,
showSearch: true,
// Actions
showActions: true,
initialSearchQuery: '',
initialTypeFilter: selectedType,
initialPaymentFilter: selectedPaymentMethod,
excludePassageTypes: const [],
filterByUserId: null, // Déjà filtré en amont
key: const ValueKey('user_passages_list'),
onPassageSelected: null,
// Callback pour synchroniser les filtres
onFiltersChanged: (filters) {
setState(() {
selectedSectorId = filters['sectorId'];
selectedPeriod = filters['period'] ?? 'Toutes';
selectedDateRange = filters['dateRange'];
});
},
onDetailsView: (passage) {
debugPrint('Affichage des détails: ${passage['id']}');
_showPassageDetails(passage);