diff --git a/em2rp/lib/views/calendar_page.dart b/em2rp/lib/views/calendar_page.dart index fd61ba8..53f7353 100644 --- a/em2rp/lib/views/calendar_page.dart +++ b/em2rp/lib/views/calendar_page.dart @@ -601,80 +601,92 @@ class _CalendarPageState extends State { constraints: BoxConstraints( maxHeight: isMobile ? 240 : 280, ), - child: ListView.separated( + child: ListView.builder( shrinkWrap: true, itemCount: _searchResults.length, physics: const ClampingScrollPhysics(), - separatorBuilder: (context, index) => - const SizedBox(height: 8), + // ✅ prototypeItem : les résultats ont une hauteur variable + // selon la présence du champ adresse (~56px sans, ~70px avec). + // prototypeItem à 72px (cas avec adresse + padding) pour + // que Flutter estime correctement la hauteur scrollable. + // ListView.separated ne supporte pas itemExtent/prototypeItem, + // d'où la conversion en ListView.builder avec séparateur intégré. + prototypeItem: const SizedBox(height: 72), itemBuilder: (context, index) { final event = _searchResults[index]; final isSelected = _selectedEvent?.id == event.id; + final isLast = index == _searchResults.length - 1; - return Material( - color: isSelected - ? AppColors.rouge.withOpacity(0.08) - : Colors.white, - borderRadius: BorderRadius.circular(12), - child: InkWell( - borderRadius: BorderRadius.circular(12), - onTap: () => _onSearchResultSelected(event), - child: Padding( - padding: const EdgeInsets.all(12), - child: Row( - children: [ - Container( - width: 10, - height: 10, - decoration: BoxDecoration( - color: _getStatusColor(event.status), - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - event.name, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontWeight: FontWeight.w600, - ), + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Material( + color: isSelected + ? AppColors.rouge.withOpacity(0.08) + : Colors.white, + borderRadius: BorderRadius.circular(12), + child: InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () => _onSearchResultSelected(event), + child: Padding( + padding: const EdgeInsets.all(12), + child: Row( + children: [ + Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: _getStatusColor(event.status), + shape: BoxShape.circle, ), - const SizedBox(height: 4), - Text( - _formatSearchResultDate( - event.startDateTime), - style: TextStyle( - color: Colors.grey.shade700, - fontSize: 12, - ), - ), - if (event.address.isNotEmpty) ...[ - const SizedBox(height: 2), - Text( - event.address, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: Colors.grey.shade600, - fontSize: 12, + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + event.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.w600, + ), ), - ), - ], - ], - ), + const SizedBox(height: 4), + Text( + _formatSearchResultDate( + event.startDateTime), + style: TextStyle( + color: Colors.grey.shade700, + fontSize: 12, + ), + ), + if (event.address.isNotEmpty) ...[ + const SizedBox(height: 2), + Text( + event.address, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 12, + ), + ), + ], + ], + ), + ), + const SizedBox(width: 8), + const Icon(Icons.chevron_right, + color: Colors.grey), + ], ), - const SizedBox(width: 8), - const Icon(Icons.chevron_right, - color: Colors.grey), - ], + ), ), ), - ), + if (!isLast) const SizedBox(height: 8), + ], ); }, ), diff --git a/em2rp/lib/views/equipment_management_page.dart b/em2rp/lib/views/equipment_management_page.dart index a1cb416..a4de267 100644 --- a/em2rp/lib/views/equipment_management_page.dart +++ b/em2rp/lib/views/equipment_management_page.dart @@ -501,9 +501,11 @@ class _EquipmentManagementPageState extends State return ListView.builder( controller: _scrollController, itemCount: itemCount, - // ✅ Ajouter une estimation de la hauteur pour améliorer le scroll - // Note : À ajuster selon la hauteur réelle de vos cartes - // itemExtent: 140, // Décommentez si toutes les cartes ont la même hauteur + // ✅ prototypeItem utilisé car les cartes ont des hauteurs variables : + // - Les équipements standards (ListTile + margin) font ~88px + // - Les consommables/câbles affichent _buildQuantityDisplay en plus (~30px) + // - prototypeItem permet à Flutter d'optimiser le scroll sans couper les items + prototypeItem: const SizedBox(height: 88), // ✅ Augmenter le cache pour un scroll plus fluide cacheExtent: 500, // Précharger 500px en plus itemBuilder: (context, index) {