2021-04-22 13:41:35 +00:00
|
|
|
import 'package:comunic/lists/forez_presences_set.dart';
|
|
|
|
import 'package:comunic/utils/date_utils.dart' as date_utils;
|
|
|
|
/// Forez presence calendar widget
|
|
|
|
///
|
|
|
|
/// This widget is used only by Forez groups
|
|
|
|
///
|
|
|
|
/// @author Pierre Hubert
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:table_calendar/table_calendar.dart';
|
|
|
|
|
|
|
|
enum CalendarDisplayMode { SINGLE_USER, MULTIPLE_USERS }
|
|
|
|
|
|
|
|
extension DateOnlyCompare on DateTime {
|
|
|
|
bool isSameDate(DateTime other) => date_utils.isSameDate(this, other);
|
|
|
|
}
|
|
|
|
|
|
|
|
class PresenceCalendarWidget extends StatefulWidget {
|
|
|
|
final PresenceSet presenceSet;
|
|
|
|
final void Function(DateTime) onDayClicked;
|
|
|
|
final CalendarDisplayMode mode;
|
|
|
|
final DateTime selectedDay;
|
|
|
|
|
|
|
|
const PresenceCalendarWidget({
|
|
|
|
Key key,
|
|
|
|
@required this.presenceSet,
|
|
|
|
this.onDayClicked,
|
|
|
|
this.mode = CalendarDisplayMode.SINGLE_USER,
|
|
|
|
this.selectedDay,
|
|
|
|
}) : assert(presenceSet != null),
|
|
|
|
assert(mode != null),
|
|
|
|
super(key: key);
|
|
|
|
|
|
|
|
@override
|
|
|
|
_PresenceCalendarWidgetState createState() => _PresenceCalendarWidgetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _PresenceCalendarWidgetState extends State<PresenceCalendarWidget> {
|
2021-05-29 13:40:47 +00:00
|
|
|
var selectedDay = DateTime.now();
|
2021-04-22 13:41:35 +00:00
|
|
|
|
2021-05-29 13:57:31 +00:00
|
|
|
@override
|
|
|
|
void didUpdateWidget(covariant PresenceCalendarWidget oldWidget) {
|
|
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
|
|
|
|
if (oldWidget.selectedDay != widget.selectedDay) {
|
|
|
|
selectedDay = widget.selectedDay;
|
|
|
|
setState(() {});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-22 13:41:35 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return TableCalendar(
|
2021-05-29 13:40:47 +00:00
|
|
|
firstDay: DateTime.utc(2020, 01, 01),
|
|
|
|
lastDay: DateTime.now().add(Duration(days: 365 * 2)),
|
|
|
|
selectedDayPredicate: (d) => d == selectedDay,
|
2021-04-22 13:41:35 +00:00
|
|
|
locale: "fr_FR",
|
|
|
|
weekendDays: [],
|
|
|
|
onHeaderTapped: _pickDate,
|
2021-05-29 13:48:51 +00:00
|
|
|
calendarBuilders: CalendarBuilders(
|
|
|
|
defaultBuilder: _dayBuilder,
|
|
|
|
todayBuilder: _dayBuilder,
|
|
|
|
selectedBuilder: _dayBuilder,
|
|
|
|
),
|
2021-04-22 13:41:35 +00:00
|
|
|
onDaySelected: _selectedDay,
|
|
|
|
availableCalendarFormats: const {CalendarFormat.month: "Mois"},
|
2021-05-29 13:40:47 +00:00
|
|
|
focusedDay: selectedDay,
|
2021-05-29 13:48:51 +00:00
|
|
|
onPageChanged: (s) {
|
|
|
|
setState(() {
|
|
|
|
selectedDay = s;
|
|
|
|
});
|
|
|
|
},
|
2021-04-22 13:41:35 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _pickDate(DateTime date) async {
|
|
|
|
final pickedDate = await showDatePicker(
|
|
|
|
context: context,
|
|
|
|
initialDate: date,
|
|
|
|
firstDate: DateTime.now().subtract(Duration(days: 20)),
|
|
|
|
lastDate: DateTime.now().add(Duration(days: 365 * 5)),
|
|
|
|
);
|
|
|
|
|
2021-05-29 13:40:47 +00:00
|
|
|
setState(() {
|
|
|
|
if (pickedDate != null) selectedDay = pickedDate;
|
|
|
|
});
|
2021-04-22 13:41:35 +00:00
|
|
|
}
|
|
|
|
|
2021-05-29 13:40:47 +00:00
|
|
|
Widget _dayBuilder(BuildContext context, DateTime date, DateTime focusedDay) {
|
2021-04-22 13:41:35 +00:00
|
|
|
if (widget.presenceSet.containsDate(date)) {
|
|
|
|
// Show the number of users who are present
|
|
|
|
if (widget.mode == CalendarDisplayMode.MULTIPLE_USERS)
|
|
|
|
return Stack(
|
|
|
|
children: [
|
|
|
|
CellWidget(
|
|
|
|
text: date.day.toString(),
|
|
|
|
color: Colors.green,
|
|
|
|
textColor: Colors.white,
|
|
|
|
circle: false,
|
|
|
|
selected: date.isSameDate(widget.selectedDay),
|
|
|
|
),
|
|
|
|
Positioned(
|
|
|
|
child: Material(
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.all(2.0),
|
|
|
|
child: Text(widget.presenceSet.countAtDate(date).toString()),
|
|
|
|
),
|
|
|
|
textStyle: TextStyle(color: Colors.white),
|
|
|
|
color: Colors.red,
|
|
|
|
),
|
|
|
|
bottom: 4,
|
|
|
|
right: 4,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
// Only show green circle
|
|
|
|
else
|
|
|
|
return CellWidget(
|
|
|
|
text: date.day.toString(),
|
|
|
|
color: Colors.green,
|
|
|
|
textColor: Colors.white,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return CellWidget(
|
|
|
|
text: date.day.toString(),
|
|
|
|
selected: date.isSameDate(widget.selectedDay),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-29 13:40:47 +00:00
|
|
|
void _selectedDay(DateTime selecteDay, DateTime focusedDay) {
|
|
|
|
if (widget.onDayClicked != null) widget.onDayClicked(selecteDay);
|
|
|
|
setState(() {});
|
2021-04-22 13:41:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class CellWidget extends StatelessWidget {
|
|
|
|
final String text;
|
|
|
|
final Color color;
|
|
|
|
final Color textColor;
|
|
|
|
final bool circle;
|
|
|
|
final bool selected;
|
|
|
|
|
|
|
|
const CellWidget({
|
|
|
|
Key key,
|
|
|
|
@required this.text,
|
|
|
|
this.color,
|
|
|
|
this.textColor,
|
|
|
|
this.circle = true,
|
|
|
|
this.selected,
|
|
|
|
}) : assert(text != null),
|
|
|
|
super(key: key);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return AnimatedContainer(
|
|
|
|
duration: const Duration(milliseconds: 250),
|
|
|
|
decoration: _buildCellDecoration(),
|
|
|
|
margin: const EdgeInsets.all(6.0),
|
|
|
|
alignment: Alignment.center,
|
|
|
|
child: Text(
|
|
|
|
text,
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
style: TextStyle(color: selected ?? false ? Colors.white : textColor),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Decoration _buildCellDecoration() => BoxDecoration(
|
|
|
|
shape: circle ? BoxShape.circle : BoxShape.rectangle,
|
|
|
|
color: selected ?? false ? Colors.deepPurple : color,
|
|
|
|
);
|
|
|
|
}
|