feat: mise à jour de la version à 1.1.18 et amélioration de la page calendrier avec ajout de la fonctionnalité de rafraîchissement des événements
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:em2rp/providers/local_user_provider.dart';
|
||||
import 'package:em2rp/providers/event_provider.dart';
|
||||
import 'package:em2rp/utils/performance_monitor.dart';
|
||||
@@ -24,13 +26,22 @@ class CalendarPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CalendarPageState extends State<CalendarPage> {
|
||||
static const double _minDetailsPaneFraction = 0.25;
|
||||
static const double _maxDetailsPaneFraction = 0.5;
|
||||
static const double _desktopResizeHandleWidth = 12;
|
||||
static const double _minCalendarPaneWidth = 480;
|
||||
static const double _minDetailsPaneWidth = 320;
|
||||
|
||||
CalendarFormat _calendarFormat = CalendarFormat.month;
|
||||
DateTime _focusedDay = DateTime.now();
|
||||
DateTime? _selectedDay;
|
||||
EventModel? _selectedEvent;
|
||||
bool _calendarCollapsed = false;
|
||||
int _selectedEventIndex = 0;
|
||||
String? _selectedUserId; // Filtre par utilisateur (null = tous les événements)
|
||||
String?
|
||||
_selectedUserId; // Filtre par utilisateur (null = tous les événements)
|
||||
bool _isRefreshing = false;
|
||||
double _detailsPaneFraction = 0.35;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -46,13 +57,15 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
Future<void> _loadCurrentMonthEvents() async {
|
||||
PerformanceMonitor.start('CalendarPage.loadCurrentMonthEvents');
|
||||
|
||||
final localAuthProvider = Provider.of<LocalUserProvider>(context, listen: false);
|
||||
final localAuthProvider =
|
||||
Provider.of<LocalUserProvider>(context, listen: false);
|
||||
final eventProvider = Provider.of<EventProvider>(context, listen: false);
|
||||
final userId = localAuthProvider.uid;
|
||||
final canViewAllEvents = localAuthProvider.hasPermission('view_all_events');
|
||||
|
||||
if (userId != null) {
|
||||
print('[CalendarPage] Loading events for ${_focusedDay.year}-${_focusedDay.month}');
|
||||
print(
|
||||
'[CalendarPage] Loading events for ${_focusedDay.year}-${_focusedDay.month}');
|
||||
|
||||
await eventProvider.loadMonthEvents(
|
||||
userId,
|
||||
@@ -79,6 +92,19 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
PerformanceMonitor.end('CalendarPage.loadCurrentMonthEvents');
|
||||
}
|
||||
|
||||
/// Vide le cache et recharge les événements du mois courant
|
||||
Future<void> _refreshEvents() async {
|
||||
if (_isRefreshing) return;
|
||||
setState(() => _isRefreshing = true);
|
||||
try {
|
||||
final eventProvider = Provider.of<EventProvider>(context, listen: false);
|
||||
eventProvider.clearAllCache();
|
||||
await _loadCurrentMonthEvents();
|
||||
} finally {
|
||||
if (mounted) setState(() => _isRefreshing = false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Charge les événements de manière asynchrone et sélectionne l'événement approprié
|
||||
/// DEPRECATED: Utiliser _loadCurrentMonthEvents à la place
|
||||
Future<void> _loadEventsAsync() async {
|
||||
@@ -107,9 +133,10 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
final todayEvents = events.where((e) {
|
||||
final start = e.startDateTime;
|
||||
return start.year == now.year &&
|
||||
start.month == now.month &&
|
||||
start.day == now.day;
|
||||
}).toList()..sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
|
||||
start.month == now.month &&
|
||||
start.day == now.day;
|
||||
}).toList()
|
||||
..sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
|
||||
|
||||
EventModel? selected;
|
||||
DateTime? selectedDay;
|
||||
@@ -121,7 +148,8 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
// Chercher le prochain événement à venir
|
||||
final futureEvents = events
|
||||
.where((e) => e.startDateTime.isAfter(now))
|
||||
.toList()..sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
|
||||
.toList()
|
||||
..sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
|
||||
|
||||
if (futureEvents.isNotEmpty) {
|
||||
selected = futureEvents[0];
|
||||
@@ -186,21 +214,98 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
});
|
||||
}
|
||||
|
||||
double _clampDetailsPaneFraction(double fraction, double totalWidth) {
|
||||
if (totalWidth <= 0) {
|
||||
return fraction.clamp(_minDetailsPaneFraction, _maxDetailsPaneFraction);
|
||||
}
|
||||
|
||||
final minFractionFromPixels = _minDetailsPaneWidth / totalWidth;
|
||||
final maxFractionFromPixels =
|
||||
(totalWidth - _desktopResizeHandleWidth - _minCalendarPaneWidth) /
|
||||
totalWidth;
|
||||
|
||||
final minFraction =
|
||||
math.max(_minDetailsPaneFraction, minFractionFromPixels);
|
||||
final maxFraction =
|
||||
math.min(_maxDetailsPaneFraction, maxFractionFromPixels);
|
||||
|
||||
if (maxFraction < minFraction) {
|
||||
return fraction.clamp(_minDetailsPaneFraction, _maxDetailsPaneFraction);
|
||||
}
|
||||
|
||||
return fraction.clamp(minFraction, maxFraction);
|
||||
}
|
||||
|
||||
Widget _buildDesktopDetailsPane(List<EventModel> filteredEvents) {
|
||||
if (_selectedEvent != null) {
|
||||
return EventDetails(
|
||||
event: _selectedEvent!,
|
||||
selectedDate: _selectedDay,
|
||||
events: filteredEvents,
|
||||
onSelectEvent: (event, date) {
|
||||
setState(() {
|
||||
_selectedEvent = event;
|
||||
_selectedDay = date;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: _selectedDay != null
|
||||
? const Text('Aucun événement ne démarre à cette date')
|
||||
: const Text('Sélectionnez un événement pour voir les détails'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDesktopResizeHandle(double totalWidth) {
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.resizeLeftRight,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onHorizontalDragUpdate: (details) {
|
||||
setState(() {
|
||||
_detailsPaneFraction = _clampDetailsPaneFraction(
|
||||
_detailsPaneFraction - (details.delta.dx / totalWidth),
|
||||
totalWidth,
|
||||
);
|
||||
});
|
||||
},
|
||||
child: SizedBox(
|
||||
width: _desktopResizeHandleWidth,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 4,
|
||||
margin: const EdgeInsets.symmetric(vertical: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final eventProvider = Provider.of<EventProvider>(context);
|
||||
final localUserProvider = Provider.of<LocalUserProvider>(context);
|
||||
final canCreateEvents = localUserProvider.hasPermission('create_events');
|
||||
final canViewAllUserEvents = localUserProvider.hasPermission('view_all_user_events');
|
||||
final canViewAllUserEvents =
|
||||
localUserProvider.hasPermission('view_all_user_events');
|
||||
final isMobile = MediaQuery.of(context).size.width < 600;
|
||||
|
||||
// Appliquer le filtre utilisateur si actif
|
||||
final filteredEvents = _getFilteredEvents(eventProvider.events);
|
||||
|
||||
// Debug logs
|
||||
print('[CalendarPage.build] Total events: ${eventProvider.events.length}, Filtered: ${filteredEvents.length}');
|
||||
print(
|
||||
'[CalendarPage.build] Total events: ${eventProvider.events.length}, Filtered: ${filteredEvents.length}');
|
||||
if (eventProvider.events.isNotEmpty) {
|
||||
print('[CalendarPage.build] First event: ${eventProvider.events.first.name} at ${eventProvider.events.first.startDateTime}');
|
||||
print(
|
||||
'[CalendarPage.build] First event: ${eventProvider.events.first.name} at ${eventProvider.events.first.startDateTime}');
|
||||
}
|
||||
|
||||
if (eventProvider.isLoading) {
|
||||
@@ -214,6 +319,26 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: "Calendrier",
|
||||
actions: [
|
||||
if (_isRefreshing)
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh, color: Colors.white),
|
||||
tooltip: 'Mettre à jour les événements',
|
||||
onPressed: _refreshEvents,
|
||||
),
|
||||
],
|
||||
),
|
||||
drawer: const MainDrawer(currentPage: '/calendar'),
|
||||
body: Column(
|
||||
@@ -247,7 +372,9 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
),
|
||||
// Corps du calendrier
|
||||
Expanded(
|
||||
child: isMobile ? _buildMobileLayout(filteredEvents) : _buildDesktopLayout(filteredEvents),
|
||||
child: isMobile
|
||||
? _buildMobileLayout(filteredEvents)
|
||||
: _buildDesktopLayout(filteredEvents),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -271,36 +398,30 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
}
|
||||
|
||||
Widget _buildDesktopLayout(List<EventModel> filteredEvents) {
|
||||
return Row(
|
||||
children: [
|
||||
// Calendrier (65% de la largeur)
|
||||
Expanded(
|
||||
flex: 65,
|
||||
child: _buildCalendar(filteredEvents),
|
||||
),
|
||||
// Détails de l'événement (35% de la largeur)
|
||||
Expanded(
|
||||
flex: 35,
|
||||
child: _selectedEvent != null
|
||||
? EventDetails(
|
||||
event: _selectedEvent!,
|
||||
selectedDate: _selectedDay,
|
||||
events: filteredEvents,
|
||||
onSelectEvent: (event, date) {
|
||||
setState(() {
|
||||
_selectedEvent = event;
|
||||
_selectedDay = date;
|
||||
});
|
||||
},
|
||||
)
|
||||
: Center(
|
||||
child: _selectedDay != null
|
||||
? Text('Aucun événement ne démarre à cette date')
|
||||
: const Text(
|
||||
'Sélectionnez un événement pour voir les détails'),
|
||||
),
|
||||
),
|
||||
],
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final totalWidth = constraints.maxWidth;
|
||||
final detailsPaneFraction =
|
||||
_clampDetailsPaneFraction(_detailsPaneFraction, totalWidth);
|
||||
final detailsWidth = totalWidth * detailsPaneFraction;
|
||||
final calendarWidth =
|
||||
totalWidth - _desktopResizeHandleWidth - detailsWidth;
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: calendarWidth,
|
||||
child: _buildCalendar(filteredEvents),
|
||||
),
|
||||
_buildDesktopResizeHandle(totalWidth),
|
||||
SizedBox(
|
||||
width: detailsWidth,
|
||||
child: _buildDesktopDetailsPane(filteredEvents),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -341,19 +462,23 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
if (details.primaryVelocity != null) {
|
||||
if (details.primaryVelocity! < -200) {
|
||||
// Swipe gauche : mois suivant
|
||||
final newMonth = DateTime(_focusedDay.year, _focusedDay.month + 1, 1);
|
||||
final newMonth =
|
||||
DateTime(_focusedDay.year, _focusedDay.month + 1, 1);
|
||||
setState(() {
|
||||
_focusedDay = newMonth;
|
||||
});
|
||||
print('[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
print(
|
||||
'[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
_loadCurrentMonthEvents();
|
||||
} else if (details.primaryVelocity! > 200) {
|
||||
// Swipe droite : mois précédent
|
||||
final newMonth = DateTime(_focusedDay.year, _focusedDay.month - 1, 1);
|
||||
final newMonth =
|
||||
DateTime(_focusedDay.year, _focusedDay.month - 1, 1);
|
||||
setState(() {
|
||||
_focusedDay = newMonth;
|
||||
});
|
||||
print('[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
print(
|
||||
'[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
_loadCurrentMonthEvents();
|
||||
}
|
||||
}
|
||||
@@ -385,7 +510,8 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
setState(() {
|
||||
_focusedDay = newMonth;
|
||||
});
|
||||
print('[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
print(
|
||||
'[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
_loadCurrentMonthEvents();
|
||||
} else if (details.primaryVelocity! > 200) {
|
||||
// Swipe droite : mois précédent
|
||||
@@ -394,7 +520,8 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
setState(() {
|
||||
_focusedDay = newMonth;
|
||||
});
|
||||
print('[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
print(
|
||||
'[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
_loadCurrentMonthEvents();
|
||||
}
|
||||
}
|
||||
@@ -557,11 +684,13 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
icon: const Icon(Icons.chevron_left,
|
||||
color: AppColors.rouge, size: 28),
|
||||
onPressed: () {
|
||||
final newMonth = DateTime(_focusedDay.year, _focusedDay.month - 1, 1);
|
||||
final newMonth =
|
||||
DateTime(_focusedDay.year, _focusedDay.month - 1, 1);
|
||||
setState(() {
|
||||
_focusedDay = newMonth;
|
||||
});
|
||||
print('[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
print(
|
||||
'[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
_loadCurrentMonthEvents();
|
||||
},
|
||||
),
|
||||
@@ -600,11 +729,13 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
icon: const Icon(Icons.chevron_right,
|
||||
color: AppColors.rouge, size: 28),
|
||||
onPressed: () {
|
||||
final newMonth = DateTime(_focusedDay.year, _focusedDay.month + 1, 1);
|
||||
final newMonth =
|
||||
DateTime(_focusedDay.year, _focusedDay.month + 1, 1);
|
||||
setState(() {
|
||||
_focusedDay = newMonth;
|
||||
});
|
||||
print('[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
print(
|
||||
'[CalendarPage] Month changed to ${newMonth.year}-${newMonth.month}');
|
||||
_loadCurrentMonthEvents();
|
||||
},
|
||||
),
|
||||
@@ -721,7 +852,7 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
onPageChanged: (focusedDay) {
|
||||
// Détecter si on a changé de mois
|
||||
final monthChanged = focusedDay.year != _focusedDay.year ||
|
||||
focusedDay.month != _focusedDay.month;
|
||||
focusedDay.month != _focusedDay.month;
|
||||
|
||||
setState(() {
|
||||
_focusedDay = focusedDay;
|
||||
@@ -729,7 +860,8 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
|
||||
// Charger les événements du nouveau mois si nécessaire
|
||||
if (monthChanged) {
|
||||
print('[CalendarPage] Month changed to ${focusedDay.year}-${focusedDay.month}');
|
||||
print(
|
||||
'[CalendarPage] Month changed to ${focusedDay.year}-${focusedDay.month}');
|
||||
_loadCurrentMonthEvents();
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user