Refactoring
This commit is contained in:
@@ -0,0 +1,407 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../core/widgets/unified_card.dart';
|
||||
import '../../../../core/theme/app_colors.dart';
|
||||
import '../../../../core/theme/app_text_styles.dart';
|
||||
import '../../../../core/utils/date_formatter.dart';
|
||||
import '../../../../core/utils/currency_formatter.dart';
|
||||
import '../../domain/entities/demande_aide.dart';
|
||||
|
||||
/// Widget de carte pour afficher une demande d'aide
|
||||
///
|
||||
/// Cette carte affiche les informations essentielles d'une demande d'aide
|
||||
/// avec un design cohérent et des interactions tactiles.
|
||||
class DemandeAideCard extends StatelessWidget {
|
||||
final DemandeAide demande;
|
||||
final bool isSelected;
|
||||
final bool isSelectionMode;
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onLongPress;
|
||||
final ValueChanged<bool>? onSelectionChanged;
|
||||
|
||||
const DemandeAideCard({
|
||||
super.key,
|
||||
required this.demande,
|
||||
this.isSelected = false,
|
||||
this.isSelectionMode = false,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.onSelectionChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return UnifiedCard(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: isSelected
|
||||
? Border.all(color: AppColors.primary, width: 2)
|
||||
: null,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeader(),
|
||||
const SizedBox(height: 12),
|
||||
_buildContent(),
|
||||
const SizedBox(height: 12),
|
||||
_buildFooter(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader() {
|
||||
return Row(
|
||||
children: [
|
||||
if (isSelectionMode) ...[
|
||||
Checkbox(
|
||||
value: isSelected,
|
||||
onChanged: onSelectionChanged,
|
||||
activeColor: AppColors.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
demande.titre,
|
||||
style: AppTextStyles.titleMedium.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_buildStatutChip(),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.person,
|
||||
size: 16,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
child: Text(
|
||||
demande.nomDemandeur,
|
||||
style: AppTextStyles.bodySmall.copyWith(
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
demande.numeroReference,
|
||||
style: AppTextStyles.bodySmall.copyWith(
|
||||
color: AppColors.textSecondary,
|
||||
fontFamily: 'monospace',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (demande.estUrgente) ...[
|
||||
const SizedBox(width: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.error.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.priority_high,
|
||||
size: 16,
|
||||
color: AppColors.error,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'URGENT',
|
||||
style: AppTextStyles.labelSmall.copyWith(
|
||||
color: AppColors.error,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildContent() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
demande.description,
|
||||
style: AppTextStyles.bodyMedium,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
_buildTypeAideChip(),
|
||||
const SizedBox(width: 8),
|
||||
_buildPrioriteChip(),
|
||||
const Spacer(),
|
||||
if (demande.montantDemande != null)
|
||||
Text(
|
||||
CurrencyFormatter.formatCFA(demande.montantDemande!),
|
||||
style: AppTextStyles.titleSmall.copyWith(
|
||||
color: AppColors.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFooter() {
|
||||
return Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.access_time,
|
||||
size: 16,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'Créée ${DateFormatter.formatRelative(demande.dateCreation)}',
|
||||
style: AppTextStyles.bodySmall.copyWith(
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
if (demande.dateModification != demande.dateCreation) ...[
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'• Modifiée ${DateFormatter.formatRelative(demande.dateModification)}',
|
||||
style: AppTextStyles.bodySmall.copyWith(
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
const Spacer(),
|
||||
_buildProgressIndicator(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatutChip() {
|
||||
final color = _getStatutColor(demande.statut);
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
demande.statut.libelle,
|
||||
style: AppTextStyles.labelSmall.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTypeAideChip() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.surface,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColors.outline),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
_getTypeAideIcon(demande.typeAide),
|
||||
size: 14,
|
||||
color: AppColors.primary,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
demande.typeAide.libelle,
|
||||
style: AppTextStyles.labelSmall.copyWith(
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPrioriteChip() {
|
||||
final color = _getPrioriteColor(demande.priorite);
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
_getPrioriteIcon(demande.priorite),
|
||||
size: 14,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
demande.priorite.libelle,
|
||||
style: AppTextStyles.labelSmall.copyWith(
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProgressIndicator() {
|
||||
final progress = demande.pourcentageAvancement;
|
||||
final color = _getProgressColor(progress);
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 60,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.outline,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
child: FractionallySizedBox(
|
||||
alignment: Alignment.centerLeft,
|
||||
widthFactor: progress / 100,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'${progress.toInt()}%',
|
||||
style: AppTextStyles.labelSmall.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Color _getStatutColor(StatutAide statut) {
|
||||
switch (statut) {
|
||||
case StatutAide.brouillon:
|
||||
return AppColors.textSecondary;
|
||||
case StatutAide.soumise:
|
||||
return AppColors.warning;
|
||||
case StatutAide.enEvaluation:
|
||||
return AppColors.info;
|
||||
case StatutAide.approuvee:
|
||||
return AppColors.success;
|
||||
case StatutAide.rejetee:
|
||||
return AppColors.error;
|
||||
case StatutAide.enCours:
|
||||
return AppColors.primary;
|
||||
case StatutAide.terminee:
|
||||
return AppColors.success;
|
||||
case StatutAide.versee:
|
||||
return AppColors.success;
|
||||
case StatutAide.livree:
|
||||
return AppColors.success;
|
||||
case StatutAide.annulee:
|
||||
return AppColors.error;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getPrioriteColor(PrioriteAide priorite) {
|
||||
switch (priorite) {
|
||||
case PrioriteAide.basse:
|
||||
return AppColors.success;
|
||||
case PrioriteAide.normale:
|
||||
return AppColors.info;
|
||||
case PrioriteAide.haute:
|
||||
return AppColors.warning;
|
||||
case PrioriteAide.critique:
|
||||
return AppColors.error;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getProgressColor(double progress) {
|
||||
if (progress < 25) return AppColors.error;
|
||||
if (progress < 50) return AppColors.warning;
|
||||
if (progress < 75) return AppColors.info;
|
||||
return AppColors.success;
|
||||
}
|
||||
|
||||
IconData _getTypeAideIcon(TypeAide typeAide) {
|
||||
switch (typeAide) {
|
||||
case TypeAide.aideFinanciereUrgente:
|
||||
return Icons.attach_money;
|
||||
case TypeAide.aideFinanciereMedicale:
|
||||
return Icons.medical_services;
|
||||
case TypeAide.aideFinanciereEducation:
|
||||
return Icons.school;
|
||||
case TypeAide.aideMaterielleVetements:
|
||||
return Icons.checkroom;
|
||||
case TypeAide.aideMaterielleNourriture:
|
||||
return Icons.restaurant;
|
||||
case TypeAide.aideProfessionnelleFormation:
|
||||
return Icons.work;
|
||||
case TypeAide.aideSocialeAccompagnement:
|
||||
return Icons.support;
|
||||
case TypeAide.autre:
|
||||
return Icons.help;
|
||||
}
|
||||
}
|
||||
|
||||
IconData _getPrioriteIcon(PrioriteAide priorite) {
|
||||
switch (priorite) {
|
||||
case PrioriteAide.basse:
|
||||
return Icons.keyboard_arrow_down;
|
||||
case PrioriteAide.normale:
|
||||
return Icons.remove;
|
||||
case PrioriteAide.haute:
|
||||
return Icons.keyboard_arrow_up;
|
||||
case PrioriteAide.critique:
|
||||
return Icons.priority_high;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user