416 lines
12 KiB
Dart
416 lines
12 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/membres_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 AnimationController _fabAnimationController;
|
|
late Animation<double> _fabAnimation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
_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() {
|
|
_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: IndexedStack(
|
|
index: _currentIndex,
|
|
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 _onTabTapped(int index) {
|
|
if (_currentIndex != 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 _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 const MembresListPage();
|
|
}
|
|
|
|
Widget _buildCotisationsPage() {
|
|
return const 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 const 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 Container(
|
|
color: AppTheme.backgroundLight,
|
|
child: Column(
|
|
children: [
|
|
// Header personnalisé au lieu d'AppBar
|
|
Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
|
decoration: const BoxDecoration(
|
|
color: AppTheme.infoColor,
|
|
borderRadius: BorderRadius.only(
|
|
bottomLeft: Radius.circular(20),
|
|
bottomRight: Radius.circular(20),
|
|
),
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
const Text(
|
|
'Plus',
|
|
style: TextStyle(
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
IconButton(
|
|
icon: const Icon(Icons.settings, color: Colors.white),
|
|
onPressed: () {},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
// Contenu scrollable
|
|
Expanded(
|
|
child: 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,
|
|
});
|
|
} |