Files
unionflow-server-impl-quarkus/unionflow-mobile-apps/lib/features/navigation/presentation/pages/main_navigation.dart
2025-08-20 21:00:35 +00:00

406 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../../../shared/theme/app_theme.dart';
import '../../../../shared/widgets/coming_soon_page.dart';
import '../../../../shared/widgets/buttons/buttons.dart';
import '../../../dashboard/presentation/pages/enhanced_dashboard.dart';
import '../../../members/presentation/pages/members_list_page.dart';
import '../widgets/custom_bottom_nav_bar.dart';
class MainNavigation extends StatefulWidget {
const MainNavigation({super.key});
@override
State<MainNavigation> createState() => _MainNavigationState();
}
class _MainNavigationState extends State<MainNavigation>
with TickerProviderStateMixin {
int _currentIndex = 0;
late PageController _pageController;
late AnimationController _fabAnimationController;
late Animation<double> _fabAnimation;
@override
void initState() {
super.initState();
_pageController = PageController();
_fabAnimationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_fabAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _fabAnimationController,
curve: Curves.easeInOut,
));
_fabAnimationController.forward();
}
@override
void dispose() {
_pageController.dispose();
_fabAnimationController.dispose();
super.dispose();
}
final List<NavigationTab> _tabs = [
NavigationTab(
title: 'Tableau de bord',
icon: Icons.dashboard_outlined,
activeIcon: Icons.dashboard,
color: AppTheme.primaryColor,
),
NavigationTab(
title: 'Membres',
icon: Icons.people_outline,
activeIcon: Icons.people,
color: AppTheme.secondaryColor,
),
NavigationTab(
title: 'Cotisations',
icon: Icons.payment_outlined,
activeIcon: Icons.payment,
color: AppTheme.accentColor,
),
NavigationTab(
title: 'Événements',
icon: Icons.event_outlined,
activeIcon: Icons.event,
color: AppTheme.warningColor,
),
NavigationTab(
title: 'Plus',
icon: Icons.more_horiz_outlined,
activeIcon: Icons.menu,
color: AppTheme.infoColor,
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
onPageChanged: _onPageChanged,
children: [
EnhancedDashboard(
onNavigateToTab: _onTabTapped,
),
_buildMembresPage(),
_buildCotisationsPage(),
_buildEventsPage(),
_buildMorePage(),
],
),
bottomNavigationBar: CustomBottomNavBar(
currentIndex: _currentIndex,
tabs: _tabs,
onTap: _onTabTapped,
),
floatingActionButton: _buildFloatingActionButton(),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
);
}
Widget _buildFloatingActionButton() {
// Afficher le FAB seulement sur certains onglets
if (_currentIndex == 1 || _currentIndex == 2 || _currentIndex == 3) {
return ScaleTransition(
scale: _fabAnimation,
child: QuickButtons.fab(
onPressed: _onFabPressed,
icon: _getFabIcon(),
variant: FABVariant.gradient,
size: FABSize.regular,
tooltip: _getFabTooltip(),
),
);
}
return const SizedBox.shrink();
}
IconData _getFabIcon() {
switch (_currentIndex) {
case 1: // Membres
return Icons.person_add;
case 2: // Cotisations
return Icons.add_card;
case 3: // Événements
return Icons.add_circle_outline;
default:
return Icons.add;
}
}
String _getFabTooltip() {
switch (_currentIndex) {
case 1: // Membres
return 'Ajouter un membre';
case 2: // Cotisations
return 'Nouvelle cotisation';
case 3: // Événements
return 'Créer un événement';
default:
return 'Ajouter';
}
}
void _onPageChanged(int index) {
setState(() {
_currentIndex = index;
});
// Animation du FAB
if (index == 1 || index == 2 || index == 3) {
_fabAnimationController.forward();
} else {
_fabAnimationController.reverse();
}
// Vibration légère
HapticFeedback.selectionClick();
}
void _onTabTapped(int index) {
if (_currentIndex != index) {
setState(() {
_currentIndex = index;
});
_pageController.animateToPage(
index,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
}
void _onFabPressed() {
HapticFeedback.lightImpact();
String action;
switch (_currentIndex) {
case 1:
action = 'Ajouter un membre';
break;
case 2:
action = 'Nouvelle cotisation';
break;
case 3:
action = 'Créer un événement';
break;
default:
action = 'Action';
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('$action - En cours de développement'),
backgroundColor: _tabs[_currentIndex].color,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
action: SnackBarAction(
label: 'OK',
textColor: Colors.white,
onPressed: () {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
},
),
),
);
}
Widget _buildMembresPage() {
return MembersListPage();
}
Widget _buildCotisationsPage() {
return ComingSoonPage(
title: 'Module Cotisations',
description: 'Suivi et gestion des cotisations avec paiements automatiques',
icon: Icons.payment_rounded,
color: AppTheme.accentColor,
features: [
'Tableau de bord des cotisations',
'Relances automatiques par email/SMS',
'Paiements en ligne sécurisés',
'Génération de reçus automatique',
'Suivi des retards de paiement',
'Rapports financiers détaillés',
],
);
}
Widget _buildEventsPage() {
return ComingSoonPage(
title: 'Module Événements',
description: 'Organisation et gestion d\'événements avec calendrier intégré',
icon: Icons.event_rounded,
color: AppTheme.warningColor,
features: [
'Calendrier interactif des événements',
'Gestion des inscriptions en ligne',
'Envoi d\'invitations automatiques',
'Suivi de la participation',
'Gestion des lieux et ressources',
'Sondages et feedback post-événement',
],
);
}
Widget _buildMorePage() {
return Scaffold(
backgroundColor: AppTheme.backgroundLight,
appBar: AppBar(
title: const Text('Plus'),
backgroundColor: AppTheme.infoColor,
elevation: 0,
automaticallyImplyLeading: false,
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {},
),
],
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildMoreSection(
'Gestion',
[
_buildMoreItem(Icons.analytics, 'Rapports', 'Génération de rapports'),
_buildMoreItem(Icons.account_balance, 'Finances', 'Tableau de bord financier'),
_buildMoreItem(Icons.message, 'Communications', 'Messages et notifications'),
_buildMoreItem(Icons.folder, 'Documents', 'Gestion documentaire'),
],
),
const SizedBox(height: 24),
_buildMoreSection(
'Paramètres',
[
_buildMoreItem(Icons.person, 'Mon profil', 'Informations personnelles'),
_buildMoreItem(Icons.notifications, 'Notifications', 'Préférences de notification'),
_buildMoreItem(Icons.security, 'Sécurité', 'Mot de passe et sécurité'),
_buildMoreItem(Icons.language, 'Langue', 'Changer la langue'),
],
),
const SizedBox(height: 24),
_buildMoreSection(
'Support',
[
_buildMoreItem(Icons.help, 'Aide', 'Centre d\'aide et FAQ'),
_buildMoreItem(Icons.contact_support, 'Contact', 'Nous contacter'),
_buildMoreItem(Icons.info, 'À propos', 'Informations sur l\'application'),
_buildMoreItem(Icons.logout, 'Déconnexion', 'Se déconnecter', isDestructive: true),
],
),
],
),
);
}
Widget _buildMoreSection(String title, List<Widget> items) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 4, bottom: 12),
child: Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppTheme.textPrimary,
),
),
),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: items,
),
),
],
);
}
Widget _buildMoreItem(IconData icon, String title, String subtitle, {bool isDestructive = false}) {
return ListTile(
leading: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: (isDestructive ? AppTheme.errorColor : AppTheme.primaryColor).withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
),
child: Icon(
icon,
color: isDestructive ? AppTheme.errorColor : AppTheme.primaryColor,
size: 20,
),
),
title: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: isDestructive ? AppTheme.errorColor : AppTheme.textPrimary,
),
),
subtitle: Text(
subtitle,
style: const TextStyle(
fontSize: 14,
color: AppTheme.textSecondary,
),
),
trailing: Icon(
Icons.arrow_forward_ios,
size: 16,
color: AppTheme.textHint,
),
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('$title - En cours de développement'),
backgroundColor: isDestructive ? AppTheme.errorColor : AppTheme.primaryColor,
behavior: SnackBarBehavior.floating,
),
);
},
);
}
}
class NavigationTab {
final String title;
final IconData icon;
final IconData activeIcon;
final Color color;
NavigationTab({
required this.title,
required this.icon,
required this.activeIcon,
required this.color,
});
}