Vue mobile add event OK

This commit is contained in:
2025-06-01 15:04:59 +02:00
parent 004d442e67
commit 9a9c932262
4 changed files with 1071 additions and 899 deletions

View File

@ -10,7 +10,7 @@ import 'package:em2rp/views/widgets/calendar_widgets/event_details.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:em2rp/views/widgets/calendar_widgets/month_view.dart';
import 'package:em2rp/views/widgets/calendar_widgets/week_view.dart';
import 'package:em2rp/views/pages/event_add_page.dart';
import 'package:em2rp/views/event_add_page.dart';
import 'package:em2rp/views/widgets/calendar_widgets/mobile_calendar_view.dart';
import 'package:em2rp/utils/colors.dart';
@ -40,23 +40,43 @@ class _CalendarPageState extends State<CalendarPage> {
final events = eventProvider.events;
if (events.isNotEmpty) {
final now = DateTime.now();
events.sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
int closestIdx = 0;
Duration minDiff = (events[0].startDateTime.difference(now)).abs();
for (int i = 1; i < events.length; i++) {
final diff = (events[i].startDateTime.difference(now)).abs();
if (diff < minDiff) {
minDiff = diff;
closestIdx = i;
// Pour mobile : sélectionner le premier événement du jour ou le prochain événement à venir
final todayEvents = events
.where((e) =>
e.startDateTime.year == now.year &&
e.startDateTime.month == now.month &&
e.startDateTime.day == now.day)
.toList()
..sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
EventModel? selected;
DateTime? selectedDay;
int selectedEventIndex = 0;
if (todayEvents.isNotEmpty) {
selected = todayEvents[0];
selectedDay = DateTime(now.year, now.month, now.day);
} else {
// Chercher le prochain événement à venir
final futureEvents = events
.where((e) => e.startDateTime.isAfter(now))
.toList()
..sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
if (futureEvents.isNotEmpty) {
selected = futureEvents[0];
selectedDay = DateTime(selected.startDateTime.year,
selected.startDateTime.month, selected.startDateTime.day);
} else {
// Aucun événement à venir, prendre le plus proche dans le passé
events.sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
selected = events.last;
selectedDay = DateTime(selected.startDateTime.year,
selected.startDateTime.month, selected.startDateTime.day);
}
}
final closestEvent = events[closestIdx];
setState(() {
_selectedDay = DateTime(closestEvent.startDateTime.year,
closestEvent.startDateTime.month, closestEvent.startDateTime.day);
_focusedDay = _selectedDay!;
_selectedDay = selectedDay;
_focusedDay = selectedDay!;
_selectedEventIndex = 0;
_selectedEvent = closestEvent;
_selectedEvent = selected;
});
}
});
@ -188,111 +208,221 @@ class _CalendarPageState extends State<CalendarPage> {
? eventsForSelectedDay[_selectedEventIndex]
: null;
return Stack(
children: [
// Calendrier + détails en dessous
AnimatedPositioned(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
top: _calendarCollapsed ? -600 : 0, // cache le calendrier en haut
left: 0,
right: 0,
height: _calendarCollapsed ? 0 : null,
child: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
_buildMonthHeader(context),
if (!_calendarCollapsed)
MobileCalendarView(
focusedDay: _focusedDay,
selectedDay: _selectedDay,
events: eventProvider.events,
onDaySelected: (day) {
final eventsForDay = eventProvider.events
.where((e) =>
e.startDateTime.year == day.year &&
e.startDateTime.month == day.month &&
e.startDateTime.day == day.day)
.toList()
..sort((a, b) =>
a.startDateTime.compareTo(b.startDateTime));
setState(() {
_selectedDay = day;
_calendarCollapsed = false;
_selectedEventIndex = 0;
_selectedEvent =
eventsForDay.isNotEmpty ? eventsForDay[0] : null;
});
},
),
Expanded(
child: hasEvents
? EventDetails(
event: eventsForSelectedDay[_selectedEventIndex],
selectedDate: _selectedDay,
events: eventsForSelectedDay.cast<EventModel>(),
onSelectEvent: (event, date) {
final idx = eventsForSelectedDay
.indexWhere((e) => e.id == event.id);
setState(() {
_selectedEventIndex = idx >= 0 ? idx : 0;
_selectedEvent = event;
});
},
)
: Center(
child:
Text('Aucun événement ne démarre à cette date')),
),
],
),
),
),
// Vue détail (prend tout l'espace quand calendrier caché)
if (_calendarCollapsed && _selectedDay != null)
// GESTURE DETECTOR pour swipe vertical (plier/déplier) et horizontal (mois)
return GestureDetector(
onVerticalDragEnd: (details) {
if (details.primaryVelocity != null) {
if (details.primaryVelocity! < -200) {
// Swipe vers le haut : plier
setState(() {
_calendarCollapsed = true;
});
} else if (details.primaryVelocity! > 200) {
// Swipe vers le bas : déplier
setState(() {
_calendarCollapsed = false;
});
}
}
},
onHorizontalDragEnd: (details) {
if (details.primaryVelocity != null) {
if (details.primaryVelocity! < -200) {
// Swipe gauche : mois suivant
setState(() {
_focusedDay =
DateTime(_focusedDay.year, _focusedDay.month + 1, 1);
});
} else if (details.primaryVelocity! > 200) {
// Swipe droite : mois précédent
setState(() {
_focusedDay =
DateTime(_focusedDay.year, _focusedDay.month - 1, 1);
});
}
}
},
child: Stack(
children: [
// Calendrier + détails en dessous
AnimatedPositioned(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
top: _calendarCollapsed ? 0 : 600,
top: _calendarCollapsed ? -600 : 0, // cache le calendrier en haut
left: 0,
right: 0,
bottom: 0,
height: _calendarCollapsed ? 0 : null,
child: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
_buildMonthHeader(context),
Expanded(
child: Stack(
children: [
if (currentEvent != null)
EventDetails(
event: currentEvent,
selectedDate: _selectedDay,
events: eventsForSelectedDay.cast<EventModel>(),
onSelectEvent: (event, date) {
final idx = eventsForSelectedDay
.indexWhere((e) => e.id == event.id);
setState(() {
_selectedEventIndex = idx >= 0 ? idx : 0;
_selectedEvent = event;
});
},
),
if (!hasEvents)
Center(
child:
Text('Aucun événement ne démarre à cette date'),
),
],
if (!_calendarCollapsed)
// Ajout d'un GestureDetector pour swipe horizontal sur le calendrier
GestureDetector(
onHorizontalDragEnd: (details) {
if (details.primaryVelocity != null) {
if (details.primaryVelocity! < -200) {
// Swipe gauche : mois suivant
setState(() {
_focusedDay = DateTime(
_focusedDay.year, _focusedDay.month + 1, 1);
});
} else if (details.primaryVelocity! > 200) {
// Swipe droite : mois précédent
setState(() {
_focusedDay = DateTime(
_focusedDay.year, _focusedDay.month - 1, 1);
});
}
}
},
child: MobileCalendarView(
focusedDay: _focusedDay,
selectedDay: _selectedDay,
events: eventProvider.events,
onDaySelected: (day) {
final eventsForDay = eventProvider.events
.where((e) =>
e.startDateTime.year == day.year &&
e.startDateTime.month == day.month &&
e.startDateTime.day == day.day)
.toList()
..sort((a, b) =>
a.startDateTime.compareTo(b.startDateTime));
setState(() {
_selectedDay = day;
_calendarCollapsed = false;
_selectedEventIndex = 0;
_selectedEvent = eventsForDay.isNotEmpty
? eventsForDay[0]
: null;
});
},
),
),
Expanded(
child: hasEvents
// Ajout d'un GestureDetector pour swipe horizontal sur le détail événement
? GestureDetector(
onHorizontalDragEnd: (details) {
if (details.primaryVelocity != null) {
if (details.primaryVelocity! < -200) {
// Swipe gauche : événement suivant
if (_selectedEventIndex <
eventsForSelectedDay.length - 1) {
setState(() {
_selectedEventIndex++;
_selectedEvent = eventsForSelectedDay[
_selectedEventIndex];
});
}
} else if (details.primaryVelocity! > 200) {
// Swipe droite : événement précédent
if (_selectedEventIndex > 0) {
setState(() {
_selectedEventIndex--;
_selectedEvent = eventsForSelectedDay[
_selectedEventIndex];
});
}
}
}
},
child: EventDetails(
event: eventsForSelectedDay[_selectedEventIndex],
selectedDate: _selectedDay,
events: eventsForSelectedDay.cast<EventModel>(),
onSelectEvent: (event, date) {
final idx = eventsForSelectedDay
.indexWhere((e) => e.id == event.id);
setState(() {
_selectedEventIndex = idx >= 0 ? idx : 0;
_selectedEvent = event;
});
},
),
)
: Center(
child: Text(
'Aucun événement ne démarre à cette date')),
),
],
),
),
),
],
// Vue détail (prend tout l'espace quand calendrier caché)
if (_calendarCollapsed && _selectedDay != null)
AnimatedPositioned(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
top: _calendarCollapsed ? 0 : 600,
left: 0,
right: 0,
bottom: 0,
child: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
_buildMonthHeader(context),
Expanded(
child: Stack(
children: [
if (currentEvent != null)
// Ajout d'un GestureDetector pour swipe horizontal sur le détail événement
GestureDetector(
onHorizontalDragEnd: (details) {
if (details.primaryVelocity != null) {
if (details.primaryVelocity! < -200) {
// Swipe gauche : événement suivant
if (_selectedEventIndex <
eventsForSelectedDay.length - 1) {
setState(() {
_selectedEventIndex++;
_selectedEvent = eventsForSelectedDay[
_selectedEventIndex];
});
}
} else if (details.primaryVelocity! > 200) {
// Swipe droite : événement précédent
if (_selectedEventIndex > 0) {
setState(() {
_selectedEventIndex--;
_selectedEvent = eventsForSelectedDay[
_selectedEventIndex];
});
}
}
}
},
child: EventDetails(
event: currentEvent,
selectedDate: _selectedDay,
events: eventsForSelectedDay.cast<EventModel>(),
onSelectEvent: (event, date) {
final idx = eventsForSelectedDay
.indexWhere((e) => e.id == event.id);
setState(() {
_selectedEventIndex = idx >= 0 ? idx : 0;
_selectedEvent = event;
});
},
),
),
if (!hasEvents)
Center(
child: Text(
'Aucun événement ne démarre à cette date'),
),
],
),
),
],
),
),
),
],
),
);
}