feat(ui): RefreshIndicator + AlwaysScrollable + dark mode sur 14 pages

RefreshIndicator ajouté (dispatche les events BLoC appropriés) :
- adhesion_detail, adhesions_page, demande_aide_detail, demandes_aide_page
- event_detail, organization_detail, org_selector, org_types
- user_management_detail, reports (TabBarView), logs (Dashboard tab)
- profile (onglet Perso), backup (3 onglets), notifications

Fixes associés :
- AlwaysScrollableScrollPhysics sur tous les scroll widgets
  (permet pull-to-refresh même si contenu < écran)
- Empty states des listes : wrappés dans SingleChildScrollView pour refresh
- Dark mode adaptatif sur textes/surfaces/borders hardcodés
- backup_page : bouton retour ajouté dans le header gradient
- org_types : chevron/star/border adaptatifs
- reports : couleurs placeholders graphique + chevrons
This commit is contained in:
dahoud
2026-04-15 20:13:50 +00:00
parent f78892e5f6
commit 55f84da49a
14 changed files with 1565 additions and 1538 deletions

View File

@@ -2,7 +2,10 @@
library event_detail_page;
import 'package:flutter/material.dart';
import '../../../../shared/design_system/tokens/module_colors.dart';
import '../../../../shared/design_system/tokens/color_tokens.dart';
import '../../../../shared/design_system/tokens/app_colors.dart';
import '../../../../shared/design_system/components/uf_app_bar.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../core/di/injection.dart';
import '../../bloc/evenements_bloc.dart';
@@ -51,10 +54,9 @@ class _EventDetailPageState extends State<EventDetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Détails de l\'événement'),
backgroundColor: AppColors.primaryGreen,
foregroundColor: Colors.white,
appBar: UFAppBar(
title: "Détails de l'événement",
moduleGradient: ModuleColors.evenementsGradient,
actions: [
IconButton(
icon: const Icon(Icons.edit),
@@ -62,10 +64,16 @@ class _EventDetailPageState extends State<EventDetailPage> {
),
],
),
body: BlocBuilder<EvenementsBloc, EvenementsState>(
builder: (context, state) {
return SingleChildScrollView(
child: Column(
body: SafeArea(
top: false,
child: BlocBuilder<EvenementsBloc, EvenementsState>(
builder: (context, state) {
return RefreshIndicator(
color: ModuleColors.evenements,
onRefresh: _loadInscriptionStatus,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(),
@@ -76,8 +84,10 @@ class _EventDetailPageState extends State<EventDetailPage> {
const SizedBox(height: 80), // Espace pour le bouton flottant
],
),
);
), // SingleChildScrollView
); // RefreshIndicator
},
),
),
floatingActionButton: _buildInscriptionButton(context),
);
@@ -87,12 +97,9 @@ class _EventDetailPageState extends State<EventDetailPage> {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.primaryGreen,
AppColors.primaryGreen.withOpacity(0.8),
],
colors: ModuleColors.evenementsGradient,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
@@ -191,7 +198,7 @@ class _EventDetailPageState extends State<EventDetailPage> {
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Icon(icon, color: AppColors.primaryGreen, size: 20),
Icon(icon, color: ModuleColors.evenements, size: 20),
const SizedBox(width: 12),
Expanded(
child: Column(
@@ -201,7 +208,7 @@ class _EventDetailPageState extends State<EventDetailPage> {
label,
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 2),
@@ -261,7 +268,7 @@ class _EventDetailPageState extends State<EventDetailPage> {
const SizedBox(height: 8),
Row(
children: [
const Icon(Icons.location_on, color: AppColors.primaryGreen),
const Icon(Icons.location_on, color: ModuleColors.evenements),
const SizedBox(width: 8),
Expanded(
child: Text(
@@ -296,7 +303,7 @@ class _EventDetailPageState extends State<EventDetailPage> {
'${widget.evenement.participantsActuels} inscrits',
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
@@ -305,7 +312,7 @@ class _EventDetailPageState extends State<EventDetailPage> {
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[100],
color: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
),
child: const Row(
@@ -335,14 +342,14 @@ class _EventDetailPageState extends State<EventDetailPage> {
if (!isComplet) {
return FloatingActionButton.extended(
onPressed: () => _showInscriptionDialog(context, isInscrit),
backgroundColor: AppColors.primaryGreen,
backgroundColor: ModuleColors.evenements,
icon: const Icon(Icons.check),
label: const Text('S\'inscrire'),
);
} else {
return const FloatingActionButton.extended(
onPressed: null,
backgroundColor: Colors.grey,
backgroundColor: AppColors.textTertiary,
icon: Icon(Icons.block),
label: Text('Complet'),
);
@@ -425,17 +432,17 @@ class _EventDetailPageState extends State<EventDetailPage> {
Color _getStatutColor(StatutEvenement statut) {
switch (statut) {
case StatutEvenement.planifie:
return AppColors.info;
return ColorTokens.info;
case StatutEvenement.confirme:
return AppColors.success;
return ColorTokens.success;
case StatutEvenement.enCours:
return AppColors.warning;
return ColorTokens.warningLight;
case StatutEvenement.termine:
return AppColors.textSecondaryLight;
return ColorTokens.textSecondary;
case StatutEvenement.annule:
return AppColors.error;
return ColorTokens.error;
case StatutEvenement.reporte:
return AppColors.brandGreen;
return ColorTokens.warning;
}
}
}