265 lines
8.5 KiB
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,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|