- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD) * DEV: Clés TEST Pierre (mode test) * REC: Clés TEST Client (mode test) * PROD: Clés LIVE Client (mode live) - Ajout de la gestion des bases de données immeubles/bâtiments * Configuration buildings_database pour DEV/REC/PROD * Service BuildingService pour enrichissement des adresses - Optimisations pages et améliorations ergonomie - Mises à jour des dépendances Composer - Nettoyage des fichiers obsolètes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
184 lines
6.6 KiB
Dart
Executable File
184 lines
6.6 KiB
Dart
Executable File
import 'package:flutter/material.dart';
|
|
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
|
|
|
/// Widget pour afficher une ligne du tableau d'amicales
|
|
/// Affiche les colonnes id, name, codePostal, libRegion et une colonne Actions (conditionnelle)
|
|
/// La colonne Actions contient des boutons Edit et Delete selon les permissions
|
|
/// Pour un admin d'amicale (rôle 2), seule la ligne est cliquable sans colonne Actions
|
|
class AmicaleRowWidget extends StatelessWidget {
|
|
final AmicaleModel amicale;
|
|
final Function(AmicaleModel)? onTap;
|
|
final Function(AmicaleModel)? onEdit;
|
|
final Function(AmicaleModel)? onDelete;
|
|
final bool isHeader;
|
|
final bool isAlternate;
|
|
final bool showActionsColumn;
|
|
|
|
const AmicaleRowWidget({
|
|
super.key,
|
|
required this.amicale,
|
|
this.onTap,
|
|
this.onEdit,
|
|
this.onDelete,
|
|
this.isHeader = false,
|
|
this.isAlternate = false,
|
|
this.showActionsColumn = true,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
|
|
// Définir les styles en fonction du type de ligne (en-tête ou données)
|
|
final textStyle = isHeader
|
|
? theme.textTheme.titleSmall?.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
color: theme.colorScheme.primary,
|
|
)
|
|
: theme.textTheme.bodyMedium;
|
|
|
|
// Couleur de fond en fonction du type de ligne
|
|
final backgroundColor = isHeader ? theme.colorScheme.primary.withOpacity(0.1) : (isAlternate ? theme.colorScheme.surface : theme.colorScheme.surface);
|
|
|
|
return InkWell(
|
|
onTap: isHeader || onTap == null ? null : () => onTap!(amicale),
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: backgroundColor,
|
|
border: Border(
|
|
bottom: BorderSide(
|
|
color: theme.dividerColor.withOpacity(0.3),
|
|
width: 1,
|
|
),
|
|
),
|
|
),
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 12.0),
|
|
child: Row(
|
|
children: [
|
|
// Colonne ID
|
|
Expanded(
|
|
flex: 1,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
child: Text(
|
|
isHeader ? 'ID' : amicale.id.toString(),
|
|
style: textStyle,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
),
|
|
|
|
// Colonne Nom
|
|
Expanded(
|
|
flex: 4,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
child: Text(
|
|
isHeader ? 'Nom' : amicale.name,
|
|
style: textStyle,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
),
|
|
|
|
// Colonne Code Postal
|
|
Expanded(
|
|
flex: 2,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
child: Text(
|
|
isHeader ? 'Code Postal' : amicale.codePostal,
|
|
style: textStyle,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
),
|
|
|
|
// Colonne Ville
|
|
Expanded(
|
|
flex: 2,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
child: Text(
|
|
isHeader ? 'Ville' : amicale.ville,
|
|
style: textStyle,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
),
|
|
|
|
// Colonne Région
|
|
Expanded(
|
|
flex: 3,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
child: Text(
|
|
isHeader ? 'Région' : (amicale.libRegion ?? ''),
|
|
style: textStyle,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
),
|
|
|
|
// Colonne Actions (conditionnelle)
|
|
if (showActionsColumn && (isHeader || onEdit != null || onDelete != null))
|
|
Expanded(
|
|
flex: 2,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
child: isHeader
|
|
? Text(
|
|
'Actions',
|
|
style: textStyle,
|
|
overflow: TextOverflow.ellipsis,
|
|
)
|
|
: Row(
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
children: [
|
|
// Bouton Edit
|
|
if (onEdit != null)
|
|
IconButton(
|
|
icon: Icon(
|
|
Icons.edit,
|
|
color: theme.colorScheme.primary,
|
|
size: 20,
|
|
),
|
|
tooltip: 'Modifier',
|
|
onPressed: () => onEdit!(amicale),
|
|
constraints: const BoxConstraints(
|
|
minWidth: 36,
|
|
minHeight: 36,
|
|
),
|
|
padding: EdgeInsets.zero,
|
|
visualDensity: VisualDensity.compact,
|
|
),
|
|
// Bouton Delete
|
|
if (onDelete != null)
|
|
IconButton(
|
|
icon: Icon(
|
|
Icons.delete,
|
|
color: theme.colorScheme.error,
|
|
size: 20,
|
|
),
|
|
tooltip: 'Supprimer',
|
|
onPressed: () => onDelete!(amicale),
|
|
constraints: const BoxConstraints(
|
|
minWidth: 36,
|
|
minHeight: 36,
|
|
),
|
|
padding: EdgeInsets.zero,
|
|
visualDensity: VisualDensity.compact,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|