Files
EM2_ERP/em2rp/lib/views/widgets/notification_preferences_widget.dart

265 lines
8.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:em2rp/models/notification_preferences_model.dart';
import 'package:em2rp/providers/local_user_provider.dart';
import 'package:provider/provider.dart';
/// Widget pour afficher et modifier les préférences de notifications
class NotificationPreferencesWidget extends StatefulWidget {
const NotificationPreferencesWidget({super.key});
@override
State<NotificationPreferencesWidget> createState() => _NotificationPreferencesWidgetState();
}
class _NotificationPreferencesWidgetState extends State<NotificationPreferencesWidget> {
// État local pour feedback immédiat
NotificationPreferences? _localPrefs;
bool _isSaving = false;
@override
Widget build(BuildContext context) {
return Consumer<LocalUserProvider>(
builder: (context, userProvider, _) {
final user = userProvider.currentUser;
if (user == null) return const SizedBox.shrink();
// Utiliser les prefs locales si disponibles, sinon les prefs du user
final prefs = _localPrefs ?? user.notificationPreferences ?? NotificationPreferences.defaults();
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Titre section
Row(
children: [
Icon(Icons.notifications, color: Theme.of(context).primaryColor),
const SizedBox(width: 8),
Text(
'Préférences de notifications',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor,
),
),
if (_isSaving) ...[
const SizedBox(width: 8),
const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2),
),
],
],
),
const SizedBox(height: 8),
Text(
'Choisissez comment vous souhaitez être notifié',
style: TextStyle(
fontSize: 13,
color: Colors.grey.shade600,
),
),
const Divider(height: 24),
// Canaux de notification
Text(
'Canaux de notification',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.grey.shade700,
),
),
const SizedBox(height: 8),
_buildSwitchTile(
context,
title: 'Notifications in-app',
subtitle: 'Alertes dans l\'application',
value: prefs.inAppEnabled,
icon: Icons.app_settings_alt,
onChanged: (value) => _updatePrefs(
context,
prefs.copyWith(inAppEnabled: value),
),
),
_buildSwitchTile(
context,
title: 'Notifications email',
subtitle: 'Recevoir des emails',
value: prefs.emailEnabled,
icon: Icons.email,
onChanged: (value) => _updatePrefs(
context,
prefs.copyWith(emailEnabled: value),
),
),
_buildSwitchTile(
context,
title: 'Notifications push',
subtitle: 'Notifications navigateur',
value: prefs.pushEnabled,
icon: Icons.notifications_active,
onChanged: (value) => _updatePrefs(
context,
prefs.copyWith(pushEnabled: value),
),
),
const Divider(height: 24),
// Types de notifications
Text(
'Types de notifications',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.grey.shade700,
),
),
const SizedBox(height: 8),
_buildSwitchTile(
context,
title: 'Événements',
subtitle: 'Création, modification, assignations',
value: prefs.eventsNotifications,
icon: Icons.event,
onChanged: (value) => _updatePrefs(
context,
prefs.copyWith(eventsNotifications: value),
),
),
_buildSwitchTile(
context,
title: 'Maintenance',
subtitle: 'Rappels de maintenance',
value: prefs.maintenanceNotifications,
icon: Icons.build,
onChanged: (value) => _updatePrefs(
context,
prefs.copyWith(maintenanceNotifications: value),
),
),
_buildSwitchTile(
context,
title: 'Stock',
subtitle: 'Stock faible, quantités',
value: prefs.stockNotifications,
icon: Icons.inventory_2,
onChanged: (value) => _updatePrefs(
context,
prefs.copyWith(stockNotifications: value),
),
),
_buildSwitchTile(
context,
title: 'Équipement',
subtitle: 'Perdu, manquant, conflits',
value: prefs.equipmentNotifications,
icon: Icons.warning,
onChanged: (value) => _updatePrefs(
context,
prefs.copyWith(equipmentNotifications: value),
),
),
],
),
),
);
},
);
}
Widget _buildSwitchTile(
BuildContext context, {
required String title,
required String subtitle,
required bool value,
required IconData icon,
required ValueChanged<bool> onChanged,
}) {
return SwitchListTile(
secondary: Icon(icon, color: value ? Theme.of(context).primaryColor : Colors.grey),
title: Text(
title,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
subtitle: Text(
subtitle,
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
),
),
value: value,
onChanged: _isSaving ? null : onChanged, // Désactiver pendant sauvegarde
activeThumbColor: Theme.of(context).primaryColor,
inactiveThumbColor: Colors.grey.shade400, // Couleur visible quand OFF
inactiveTrackColor: Colors.grey.shade300, // Track visible quand OFF
contentPadding: EdgeInsets.zero,
dense: true,
);
}
Future<void> _updatePrefs(BuildContext context, NotificationPreferences newPrefs) async {
// Mise à jour locale immédiate pour feedback visuel
setState(() {
_localPrefs = newPrefs;
_isSaving = true;
});
final userProvider = context.read<LocalUserProvider>();
try {
await userProvider.updateNotificationPreferences(newPrefs);
if (mounted) {
setState(() {
_isSaving = false;
_localPrefs = null; // Revenir aux prefs du provider
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Préférences enregistrées'),
backgroundColor: Colors.green,
duration: Duration(seconds: 2),
),
);
}
} catch (e) {
if (mounted) {
setState(() {
_isSaving = false;
_localPrefs = null; // Rollback en cas d'erreur
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Erreur : $e'),
backgroundColor: Colors.red,
),
);
}
}
}
}