Initialisation du projet geosector complet (web + flutter)
This commit is contained in:
687
flutt/lib/presentation/widgets/responsive_navigation.dart
Normal file
687
flutt/lib/presentation/widgets/responsive_navigation.dart
Normal file
@@ -0,0 +1,687 @@
|
||||
import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
import 'package:geosector_app/core/repositories/user_repository.dart';
|
||||
import 'package:geosector_app/presentation/widgets/help_dialog.dart';
|
||||
import 'package:geosector_app/presentation/widgets/profile_dialog.dart';
|
||||
|
||||
/// Widget qui fournit une navigation responsive pour l'application.
|
||||
/// Affiche une sidebar en mode desktop et une bottomBar en mode mobile.
|
||||
class ResponsiveNavigation extends StatefulWidget {
|
||||
/// Le contenu principal à afficher
|
||||
final Widget body;
|
||||
|
||||
/// Le titre de la page
|
||||
final String title;
|
||||
|
||||
/// L'index de la page sélectionnée
|
||||
final int selectedIndex;
|
||||
|
||||
/// Callback appelé lorsqu'un élément de navigation est sélectionné
|
||||
final Function(int) onDestinationSelected;
|
||||
|
||||
/// Liste des destinations de navigation
|
||||
final List<NavigationDestination> destinations;
|
||||
|
||||
/// Actions supplémentaires à afficher dans l'AppBar
|
||||
final List<Widget>? additionalActions;
|
||||
|
||||
/// Indique si le bouton "Nouveau passage" doit être affiché
|
||||
final bool showNewPassageButton;
|
||||
|
||||
/// Callback appelé lorsque le bouton "Nouveau passage" est pressé
|
||||
final VoidCallback? onNewPassagePressed;
|
||||
|
||||
/// Clé de la boîte Hive pour sauvegarder les paramètres
|
||||
final String settingsBoxKey;
|
||||
|
||||
/// Clé pour sauvegarder l'état de la sidebar
|
||||
final String sidebarStateKey;
|
||||
|
||||
/// Widgets à afficher en bas de la sidebar
|
||||
final List<Widget>? sidebarBottomItems;
|
||||
|
||||
/// Indique si l'utilisateur est un administrateur
|
||||
final bool isAdmin;
|
||||
|
||||
/// Indique si l'AppBar doit être affiché
|
||||
final bool showAppBar;
|
||||
|
||||
const ResponsiveNavigation({
|
||||
Key? key,
|
||||
required this.body,
|
||||
required this.title,
|
||||
required this.selectedIndex,
|
||||
required this.onDestinationSelected,
|
||||
required this.destinations,
|
||||
this.additionalActions,
|
||||
this.showNewPassageButton = true,
|
||||
this.onNewPassagePressed,
|
||||
this.settingsBoxKey = AppKeys.settingsBoxName,
|
||||
this.sidebarStateKey = 'isSidebarMinimized',
|
||||
this.sidebarBottomItems,
|
||||
this.isAdmin = false,
|
||||
this.showAppBar = true,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ResponsiveNavigation> createState() => _ResponsiveNavigationState();
|
||||
}
|
||||
|
||||
class _ResponsiveNavigationState extends State<ResponsiveNavigation> {
|
||||
/// État de la barre latérale (minimisée ou non)
|
||||
bool _isSidebarMinimized = false;
|
||||
|
||||
/// Référence à la boîte Hive pour les paramètres
|
||||
late Box _settingsBox;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_initSettings();
|
||||
}
|
||||
|
||||
/// Initialiser la boîte de paramètres et charger les préférences
|
||||
Future<void> _initSettings() async {
|
||||
try {
|
||||
// Ouvrir la boîte de paramètres si elle n'est pas déjà ouverte
|
||||
if (!Hive.isBoxOpen(widget.settingsBoxKey)) {
|
||||
_settingsBox = await Hive.openBox(widget.settingsBoxKey);
|
||||
} else {
|
||||
_settingsBox = Hive.box(widget.settingsBoxKey);
|
||||
}
|
||||
|
||||
// Charger l'état de la barre latérale
|
||||
final sidebarState = _settingsBox.get(widget.sidebarStateKey);
|
||||
if (sidebarState != null && sidebarState is bool) {
|
||||
setState(() {
|
||||
_isSidebarMinimized = sidebarState;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors du chargement des paramètres: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Sauvegarder l'état de la barre latérale
|
||||
void _saveSettings() {
|
||||
try {
|
||||
// Sauvegarder l'état de la barre latérale
|
||||
_settingsBox.put(widget.sidebarStateKey, _isSidebarMinimized);
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la sauvegarde des paramètres: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final size = MediaQuery.of(context).size;
|
||||
final isDesktop = size.width > 900;
|
||||
|
||||
return Scaffold(
|
||||
appBar: widget.showAppBar
|
||||
? AppBar(
|
||||
title: Text(widget.title),
|
||||
actions: _buildAppBarActions(context),
|
||||
)
|
||||
: null,
|
||||
body: isDesktop ? _buildDesktopLayout() : _buildMobileLayout(),
|
||||
bottomNavigationBar: (isDesktop) ? null : _buildBottomNavigationBar(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction du layout pour les écrans de bureau (web)
|
||||
Widget _buildDesktopLayout() {
|
||||
// Utiliser une couleur de fond différente selon le type d'utilisateur
|
||||
final backgroundColor = widget.isAdmin
|
||||
? const Color(0xFFFFEBEE) // Fond rouge clair pour l'interface admin
|
||||
: const Color(
|
||||
0xFFE8F5E9); // Fond vert clair pour l'interface utilisateur
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
_buildSidebar(),
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: backgroundColor,
|
||||
child: widget.body,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction du layout pour les écrans mobiles
|
||||
Widget _buildMobileLayout() {
|
||||
// Utiliser une couleur de fond différente selon le type d'utilisateur
|
||||
final backgroundColor = widget.isAdmin
|
||||
? const Color(0xFFFFEBEE) // Fond rouge clair pour l'interface admin
|
||||
: const Color(
|
||||
0xFFE8F5E9); // Fond vert clair pour l'interface utilisateur
|
||||
|
||||
return Container(
|
||||
color: backgroundColor,
|
||||
child: widget.body,
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction des actions de l'AppBar
|
||||
List<Widget> _buildAppBarActions(BuildContext context) {
|
||||
List<Widget> actions = [];
|
||||
|
||||
// Ajouter les actions supplémentaires si elles existent
|
||||
if (widget.additionalActions != null &&
|
||||
widget.additionalActions!.isNotEmpty) {
|
||||
actions.addAll(widget.additionalActions!);
|
||||
} else if (widget.showNewPassageButton && widget.selectedIndex == 0) {
|
||||
// Ajouter le bouton "Nouveau passage" en haut à droite pour la page d'accueil
|
||||
actions.add(
|
||||
TextButton.icon(
|
||||
icon: const Icon(Icons.add_location_alt, color: Colors.white),
|
||||
label: const Text('Nouveau passage',
|
||||
style: TextStyle(color: Colors.white)),
|
||||
onPressed: widget.onNewPassagePressed ??
|
||||
() {
|
||||
// Fonction par défaut si onNewPassagePressed n'est pas fourni
|
||||
_showPassageForm(context);
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).colorScheme.secondary,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
),
|
||||
),
|
||||
);
|
||||
actions.add(const SizedBox(width: 16)); // Espacement à droite
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
/// Construction de la barre de navigation inférieure pour mobile
|
||||
Widget _buildBottomNavigationBar() {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return NavigationBar(
|
||||
selectedIndex: widget.selectedIndex,
|
||||
onDestinationSelected: widget.onDestinationSelected,
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
elevation: 8,
|
||||
destinations: widget.destinations,
|
||||
);
|
||||
}
|
||||
|
||||
/// Obtenir le nom complet de l'utilisateur (prénom + nom)
|
||||
String _getFullUserName(BuildContext context) {
|
||||
// Utiliser l'instance globale définie dans app.dart
|
||||
final user = userRepository.currentUser;
|
||||
|
||||
if (user == null) return 'Utilisateur';
|
||||
|
||||
String fullName = '';
|
||||
|
||||
// Ajouter le prénom si disponible
|
||||
if (user.firstName != null && user.firstName!.isNotEmpty) {
|
||||
fullName += user.firstName!;
|
||||
}
|
||||
|
||||
// Ajouter le nom
|
||||
if (user.name != null && user.name!.isNotEmpty) {
|
||||
// Ajouter un espace si le prénom est déjà présent
|
||||
if (fullName.isNotEmpty) {
|
||||
fullName += ' ';
|
||||
}
|
||||
fullName += user.name!;
|
||||
}
|
||||
|
||||
// Si aucun nom n'a été trouvé, utiliser 'Utilisateur' par défaut
|
||||
return fullName.isEmpty ? 'Utilisateur' : fullName;
|
||||
}
|
||||
|
||||
/// Obtenir les initiales du prénom et du nom de l'utilisateur
|
||||
String _getUserInitials(BuildContext context) {
|
||||
// Utiliser l'instance globale définie dans app.dart
|
||||
final user = userRepository.currentUser;
|
||||
|
||||
if (user == null) return 'U';
|
||||
|
||||
String initials = '';
|
||||
|
||||
// Ajouter l'initiale du prénom si disponible
|
||||
if (user.firstName != null && user.firstName!.isNotEmpty) {
|
||||
initials += user.firstName!.substring(0, 1).toUpperCase();
|
||||
}
|
||||
|
||||
// Ajouter l'initiale du nom
|
||||
if (user.name != null && user.name!.isNotEmpty) {
|
||||
initials += user.name!.substring(0, 1).toUpperCase();
|
||||
}
|
||||
|
||||
// Si aucune initiale n'a été trouvée, utiliser 'U' par défaut
|
||||
return initials.isEmpty ? 'U' : initials;
|
||||
}
|
||||
|
||||
/// Afficher le sectName entre parenthèses s'il existe
|
||||
Widget _buildSectNameText(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
// Utiliser l'instance globale définie dans app.dart
|
||||
final user = userRepository.currentUser;
|
||||
|
||||
// Si l'utilisateur n'a pas de sectName ou s'il est vide, retourner un widget vide
|
||||
if (user == null || user.sectName == null || user.sectName!.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
// Sinon, afficher le sectName entre parenthèses
|
||||
return Text(
|
||||
'(${user.sectName})',
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction de la barre latérale pour la version web
|
||||
Widget _buildSidebar() {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Card(
|
||||
margin: EdgeInsets.zero,
|
||||
elevation: 4,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.zero,
|
||||
),
|
||||
child: Container(
|
||||
width: _isSidebarMinimized ? 70 : 250,
|
||||
color: theme.colorScheme.surface,
|
||||
child: Column(
|
||||
children: [
|
||||
// Bouton pour minimiser/maximiser la barre latérale
|
||||
Align(
|
||||
alignment: _isSidebarMinimized
|
||||
? Alignment.center
|
||||
: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(top: 8, right: _isSidebarMinimized ? 0 : 8),
|
||||
child: IconButton(
|
||||
icon: Icon(_isSidebarMinimized
|
||||
? Icons.chevron_right
|
||||
: Icons.chevron_left),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isSidebarMinimized = !_isSidebarMinimized;
|
||||
_saveSettings(); // Sauvegarder l'état de la barre latérale
|
||||
});
|
||||
},
|
||||
tooltip: _isSidebarMinimized ? 'Développer' : 'Réduire',
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (!_isSidebarMinimized)
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
child: Text(
|
||||
_getUserInitials(context),
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
color: theme.colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (!_isSidebarMinimized) ...[
|
||||
Text(
|
||||
_getFullUserName(context),
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
// Afficher le sectName entre parenthèses s'il existe
|
||||
_buildSectNameText(context),
|
||||
Text(
|
||||
userRepository.currentUser?.email ?? '',
|
||||
style: theme.textTheme.bodySmall,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
] else
|
||||
const SizedBox(height: 8),
|
||||
const Divider(),
|
||||
|
||||
// Éléments de navigation
|
||||
for (int i = 0; i < widget.destinations.length; i++)
|
||||
_buildNavItem(
|
||||
i, widget.destinations[i].label, widget.destinations[i].icon),
|
||||
|
||||
const Spacer(),
|
||||
const Divider(),
|
||||
|
||||
// Éléments du bas de la sidebar
|
||||
if (widget.sidebarBottomItems != null && !_isSidebarMinimized)
|
||||
...widget.sidebarBottomItems!,
|
||||
|
||||
// Éléments par défaut du bas de la sidebar
|
||||
if (!_isSidebarMinimized)
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Text(
|
||||
'Paramètres',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
color: theme.colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
_SettingsItem(
|
||||
icon: Icons.person,
|
||||
title: 'Mon compte',
|
||||
subtitle: null,
|
||||
isSidebarMinimized: _isSidebarMinimized,
|
||||
onTap: () {
|
||||
// Afficher la boîte de dialogue de profil avec l'ID de l'utilisateur actuel
|
||||
// Utiliser l'instance globale définie dans app.dart
|
||||
final user = userRepository.currentUser;
|
||||
if (user != null && user.id != null) {
|
||||
// Convertir l'ID en chaîne de caractères si nécessaire
|
||||
ProfileDialog.show(context, user.id!.toString());
|
||||
} else {
|
||||
// Afficher un message d'erreur si l'utilisateur n'est pas trouvé
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: const Text('Erreur: Utilisateur non trouvé'),
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (widget.isAdmin && userRepository.currentUser?.role == 2)
|
||||
_SettingsItem(
|
||||
icon: Icons.people,
|
||||
title: 'Amicale & membres',
|
||||
isSidebarMinimized: _isSidebarMinimized,
|
||||
onTap: () {
|
||||
// Navigation vers le tableau de bord admin avec sélection de l'onglet "Amicale et membres"
|
||||
context.go('/admin');
|
||||
|
||||
// Sélectionner l'onglet "Amicale et membres" (index 5)
|
||||
// Nous devons sauvegarder cet index dans les paramètres pour que le tableau de bord
|
||||
// puisse le récupérer et sélectionner le bon onglet
|
||||
final settingsBox = Hive.box(AppKeys.settingsBoxName);
|
||||
settingsBox.put('adminSelectedPageIndex', 5);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_SettingsItem(
|
||||
icon: Icons.help_outline,
|
||||
title: 'Aide',
|
||||
isSidebarMinimized: _isSidebarMinimized,
|
||||
onTap: () {
|
||||
// Afficher la boîte de dialogue d'aide avec le titre de la page courante
|
||||
HelpDialog.show(context, widget.title);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction d'un élément de navigation pour la barre latérale
|
||||
Widget _buildNavItem(int index, String title, Widget icon) {
|
||||
final theme = Theme.of(context);
|
||||
final isSelected = widget.selectedIndex == index;
|
||||
final IconData? iconData = (icon is Icon) ? (icon as Icon).icon : null;
|
||||
|
||||
// Remplacer certains titres si l'interface est de type "user"
|
||||
String displayTitle = title;
|
||||
if (!widget.isAdmin) {
|
||||
if (title == "Accueil") {
|
||||
displayTitle = "Tableau de bord";
|
||||
} else if (title == "Stats") {
|
||||
displayTitle = "Statistiques";
|
||||
}
|
||||
}
|
||||
|
||||
if (_isSidebarMinimized) {
|
||||
// Version minimisée - afficher uniquement l'icône
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Tooltip(
|
||||
message: displayTitle,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
widget.onDestinationSelected(index);
|
||||
},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? theme.colorScheme.primary.withOpacity(0.1)
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: iconData != null
|
||||
? Icon(
|
||||
iconData,
|
||||
color: isSelected
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurface.withOpacity(0.6),
|
||||
size: 24,
|
||||
)
|
||||
: icon,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Version normale avec texte et icône
|
||||
return ListTile(
|
||||
leading: iconData != null
|
||||
? Icon(
|
||||
iconData,
|
||||
color: isSelected
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurface.withOpacity(0.6),
|
||||
)
|
||||
: icon,
|
||||
title: Text(
|
||||
displayTitle,
|
||||
style: TextStyle(
|
||||
color: isSelected
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurface,
|
||||
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
tileColor:
|
||||
isSelected ? theme.colorScheme.primary.withOpacity(0.1) : null,
|
||||
onTap: () {
|
||||
widget.onDestinationSelected(index);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Affiche le formulaire de passage
|
||||
void _showPassageForm(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(
|
||||
'Nouveau passage',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Adresse',
|
||||
prefixIcon: const Icon(Icons.location_on),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
DropdownButtonFormField<int>(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Type de passage',
|
||||
prefixIcon: const Icon(Icons.category),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
items: const [
|
||||
DropdownMenuItem(
|
||||
value: 1,
|
||||
child: Text('Effectué'),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 2,
|
||||
child: Text('À finaliser'),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 3,
|
||||
child: Text('Refusé'),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 4,
|
||||
child: Text('Don'),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 5,
|
||||
child: Text('Lot'),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: 6,
|
||||
child: Text('Maison vide'),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Commentaire',
|
||||
prefixIcon: const Icon(Icons.comment),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
maxLines: 3,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
'Annuler',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// Enregistrer le passage
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: const Text('Passage enregistré avec succès'),
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
),
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
foregroundColor: theme.colorScheme.onPrimary,
|
||||
),
|
||||
child: const Text('Enregistrer'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Widget pour les éléments de paramètres
|
||||
class _SettingsItem extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
final Widget? trailing;
|
||||
final VoidCallback onTap;
|
||||
final bool isSidebarMinimized;
|
||||
|
||||
const _SettingsItem({
|
||||
required this.icon,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.trailing,
|
||||
required this.onTap,
|
||||
required this.isSidebarMinimized,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
if (isSidebarMinimized) {
|
||||
// Version minimisée - afficher uniquement l'icône
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Tooltip(
|
||||
message: title,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: theme.colorScheme.primary,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Version normale avec texte et icône
|
||||
return ListTile(
|
||||
leading: Icon(
|
||||
icon,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
title: Text(title),
|
||||
subtitle: subtitle != null ? Text(subtitle!) : null,
|
||||
trailing: trailing,
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user