feat: Mise à jour des interfaces mobiles v3.2.3

- Amélioration des interfaces utilisateur sur mobile
- Optimisation de la responsivité des composants Flutter
- Mise à jour des widgets de chat et communication
- Amélioration des formulaires et tableaux
- Ajout de nouveaux composants pour l'administration
- Optimisation des thèmes et styles visuels

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-02 20:35:40 +02:00
parent 4153f73ace
commit f7baa7492c
106 changed files with 88501 additions and 88280 deletions

View File

@@ -9,6 +9,7 @@ import 'package:geosector_app/core/services/current_user_service.dart';
// Enum pour les types de tri
enum SortType { name, count, progress }
enum SortOrder { none, asc, desc }
class SectorDistributionCard extends StatefulWidget {
@@ -51,16 +52,20 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
}
Widget _buildSortButton(String label, SortType sortType) {
final isActive = _currentSortType == sortType && _currentSortOrder != SortOrder.none;
final isAsc = _currentSortType == sortType && _currentSortOrder == SortOrder.asc;
final isActive =
_currentSortType == sortType && _currentSortOrder != SortOrder.none;
final isAsc =
_currentSortType == sortType && _currentSortOrder == SortOrder.asc;
return InkWell(
onTap: () => _onSortPressed(sortType),
borderRadius: BorderRadius.circular(4),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: isActive ? Colors.blue.withOpacity(0.1) : Colors.grey.withOpacity(0.1),
color: isActive
? Colors.blue.withValues(alpha: 0.1)
: Colors.grey.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: isActive ? Colors.blue : Colors.grey[400]!,
@@ -73,7 +78,7 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
Text(
label,
style: TextStyle(
fontSize: 12,
fontSize: AppTheme.r(context, 12),
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
color: isActive ? Colors.blue : Colors.grey[700],
),
@@ -111,9 +116,9 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
children: [
Text(
widget.title,
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
fontSize: AppTheme.r(context, 16),
),
),
// Boutons de tri groupés
@@ -208,13 +213,13 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
// Préparer les données pour l'affichage - AFFICHER TOUS LES SECTEURS
List<Map<String, dynamic>> stats = [];
for (final sector in sectors) {
// Compter les passages par type pour ce secteur
Map<int, int> passagesByType = {};
int totalCount = 0;
int passagesNotType2 = 0;
// Compter tous les passages pour ce secteur
for (final passage in passages) {
if (passage.fkSector == sector.id) {
@@ -226,12 +231,11 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
}
}
}
// Calculer le pourcentage d'avancement
final int progressPercentage = totalCount > 0
? ((passagesNotType2 / totalCount) * 100).round()
: 0;
final int progressPercentage =
totalCount > 0 ? ((passagesNotType2 / totalCount) * 100).round() : 0;
stats.add({
'id': sector.id,
'name': sector.libelle,
@@ -240,8 +244,7 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
'progressPercentage': progressPercentage,
'color': sector.color.isEmpty
? 0xFF4B77BE
: int.tryParse(sector.color.replaceAll('#', '0xFF')) ??
0xFF4B77BE,
: int.tryParse(sector.color.replaceAll('#', '0xFF')) ?? 0xFF4B77BE,
});
}
@@ -274,7 +277,8 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
break;
case SortType.progress:
stats.sort((a, b) {
final result = (a['progressPercentage'] as int).compareTo(b['progressPercentage'] as int);
final result = (a['progressPercentage'] as int)
.compareTo(b['progressPercentage'] as int);
return _currentSortOrder == SortOrder.asc ? result : -result;
});
break;
@@ -293,14 +297,14 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
final Map<int, int> passagesByType = sectorData['passagesByType'] ?? {};
final int progressPercentage = sectorData['progressPercentage'] ?? 0;
final int sectorId = sectorData['id'] ?? 0;
// Calculer le ratio par rapport au maximum (éviter division par zéro)
final double widthRatio = maxCount > 0 ? count / maxCount : 0;
// Style différent pour les secteurs sans passages
final bool hasPassages = count > 0;
final textColor = hasPassages ? Colors.black87 : Colors.grey;
// Vérifier si l'utilisateur est admin
final bool isAdmin = CurrentUserService.instance.canAccessAdmin;
@@ -320,19 +324,21 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
// Sauvegarder le secteur sélectionné et l'index de la page carte dans Hive
final settingsBox = Hive.box(AppKeys.settingsBoxName);
settingsBox.put('selectedSectorId', sectorId);
settingsBox.put('selectedPageIndex', 4); // Index de la page carte
settingsBox.put(
'selectedPageIndex', 4); // Index de la page carte
// Naviguer vers le dashboard admin qui chargera la page carte
context.go('/admin');
},
child: Text(
name,
style: TextStyle(
fontSize: 14,
fontSize: AppTheme.r(context, 14),
color: textColor,
fontWeight: hasPassages ? FontWeight.w600 : FontWeight.w300,
fontWeight:
hasPassages ? FontWeight.w600 : FontWeight.w300,
decoration: TextDecoration.underline,
decorationColor: textColor.withOpacity(0.5),
decorationColor: textColor.withValues(alpha: 0.5),
),
overflow: TextOverflow.ellipsis,
),
@@ -340,20 +346,21 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
: Text(
name,
style: TextStyle(
fontSize: 14,
fontSize: AppTheme.r(context, 14),
color: textColor,
fontWeight: hasPassages ? FontWeight.w600 : FontWeight.w300,
fontWeight:
hasPassages ? FontWeight.w600 : FontWeight.w300,
),
overflow: TextOverflow.ellipsis,
),
),
Text(
hasPassages
? '$count passages ($progressPercentage% d\'avancement)'
hasPassages
? '$count passages ($progressPercentage% d\'avancement)'
: '0 passage',
style: TextStyle(
fontWeight: hasPassages ? FontWeight.bold : FontWeight.normal,
fontSize: 13,
fontSize: AppTheme.r(context, 13),
color: textColor,
),
),
@@ -373,7 +380,8 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
);
}
Widget _buildStackedBar(Map<int, int> passagesByType, int totalCount, int sectorId, String sectorName) {
Widget _buildStackedBar(Map<int, int> passagesByType, int totalCount,
int sectorId, String sectorName) {
if (totalCount == 0) {
// Barre vide pour les secteurs sans passages
return Container(
@@ -387,7 +395,7 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
// Ordre des types : 1, 3, 4, 5, 6, 7, 8, 9, puis 2 en dernier
final typeOrder = [1, 3, 4, 5, 6, 7, 8, 9, 2];
return Container(
height: 24,
decoration: BoxDecoration(
@@ -405,40 +413,45 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
children: typeOrder.map((typeId) {
final count = passagesByType[typeId] ?? 0;
if (count == 0) return const SizedBox.shrink();
final percentage = (count / totalCount) * 100;
final typeInfo = AppKeys.typesPassages[typeId];
final color = typeInfo != null
final color = typeInfo != null
? Color(typeInfo['couleur2'] as int)
: Colors.grey;
// Vérifier si l'utilisateur est admin pour les clics
final bool isAdmin = CurrentUserService.instance.canAccessAdmin;
return Expanded(
flex: count,
child: isAdmin
? InkWell(
onTap: () {
// Sauvegarder les filtres dans Hive pour la page historique
final settingsBox = Hive.box(AppKeys.settingsBoxName);
settingsBox.put('history_selectedSectorId', sectorId);
settingsBox.put('history_selectedSectorName', sectorName);
final settingsBox =
Hive.box(AppKeys.settingsBoxName);
settingsBox.put(
'history_selectedSectorId', sectorId);
settingsBox.put(
'history_selectedSectorName', sectorName);
settingsBox.put('history_selectedTypeId', typeId);
settingsBox.put('selectedPageIndex', 2); // Index de la page historique
settingsBox.put('selectedPageIndex',
2); // Index de la page historique
// Naviguer vers le dashboard admin qui chargera la page historique
context.go('/admin');
},
child: Container(
color: color,
child: Center(
child: percentage >= 5 // N'afficher le texte que si >= 5%
child: percentage >=
5 // N'afficher le texte que si >= 5%
? Text(
'$count (${percentage.toInt()}%)',
style: const TextStyle(
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontSize: AppTheme.r(context, 10),
fontWeight: FontWeight.bold,
shadows: [
Shadow(
@@ -456,12 +469,13 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
: Container(
color: color,
child: Center(
child: percentage >= 5 // N'afficher le texte que si >= 5%
child: percentage >=
5 // N'afficher le texte que si >= 5%
? Text(
'$count (${percentage.toInt()}%)',
style: const TextStyle(
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontSize: AppTheme.r(context, 10),
fontWeight: FontWeight.bold,
shadows: [
Shadow(
@@ -483,4 +497,4 @@ class _SectorDistributionCardState extends State<SectorDistributionCard> {
),
);
}
}
}