From 4b0adc042cf0993ce1f9d26ebd42bbc4bb80ab15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9=20Dumazy?= Date: Mon, 15 Jan 2024 10:13:03 +0100 Subject: [PATCH] feat: Add custom sort for EventController --- lib/src/event_controller.dart | 25 ++++++-- lib/src/extensions.dart | 22 +++++-- lib/src/typedefs.dart | 4 ++ test/custom_sort_test.dart | 115 ++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 11 deletions(-) create mode 100644 test/custom_sort_test.dart diff --git a/lib/src/event_controller.dart b/lib/src/event_controller.dart index 8ac88bb4..4a58e370 100644 --- a/lib/src/event_controller.dart +++ b/lib/src/event_controller.dart @@ -24,13 +24,18 @@ class EventController extends ChangeNotifier { /// [MonthView], [DayView] and [WeekView]. /// EventFilter? eventFilter, - }) : _eventFilter = eventFilter; + + /// This allows for custom sorting of events. + /// By default, events are sorted in a start time wise order. + EventSorter? eventSorter, + }) : _eventFilter = eventFilter, + _calendarData = CalendarData(eventSorter: eventSorter); //#region Private Fields EventFilter? _eventFilter; /// Store all calendar event data - final CalendarData _calendarData = CalendarData(); + final CalendarData _calendarData; //#endregion @@ -157,7 +162,15 @@ class EventController extends ChangeNotifier { /// Exposes methods to manipulate stored data. /// /// -class CalendarData { +class CalendarData { + /// Creates a new instance of [CalendarData]. + CalendarData({ + EventSorter? eventSorter, + }) : _eventSorter = eventSorter; + + //#region Private Fields + EventSorter? _eventSorter; + /// Stores all the events in a list(all the items in below 3 list will be /// available in this list as global itemList of all events). final _eventList = >[]; @@ -203,12 +216,12 @@ class CalendarData { //#region Data Manipulation Methods void addFullDayEvent(CalendarEventData event) { // TODO: add separate logic for adding full day event and ranging event. - _fullDayEventList.addEventInSortedManner(event); + _fullDayEventList.addEventInSortedManner(event, _eventSorter); _eventList.add(event); } void addRangingEvent(CalendarEventData event) { - _rangingEventList.addEventInSortedManner(event); + _rangingEventList.addEventInSortedManner(event, _eventSorter); _eventList.add(event); } @@ -220,7 +233,7 @@ class CalendarData { date: [event], }); } else { - _singleDayEvents[date]!.addEventInSortedManner(event); + _singleDayEvents[date]!.addEventInSortedManner(event, _eventSorter); } _eventList.add(event); diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index b26c67da..c46ec14a 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -165,17 +165,24 @@ extension MinutesExtension on MinuteSlotSize { } } -extension MyList on List { +extension MyList on List> { // Below function will add the new event in sorted manner(startTimeWise) in // the existing list of CalendarEventData. - void addEventInSortedManner(CalendarEventData event) { + void addEventInSortedManner( + CalendarEventData event, [ + EventSorter? sorter, + ]) { var addIndex = -1; for (var i = 0; i < this.length; i++) { - if ((event.startTime?.getTotalMinutes ?? 0) - - (this[i].startTime?.getTotalMinutes ?? 0) <= - 0) { + var result = sorter?.call(event, this[i]) ?? 0; + + /// If result is 0 then use the default startTimeWiseCompare + if (result == 0) { + result = _startTimeWiseCompare(event, this[i]); + } + if (result <= 0) { addIndex = i; break; } @@ -189,6 +196,11 @@ extension MyList on List { } } +int _startTimeWiseCompare(CalendarEventData a, CalendarEventData b) { + return (a.startTime?.getTotalMinutes ?? 0) - + (b.startTime?.getTotalMinutes ?? 0); +} + extension TimerOfDayExtension on TimeOfDay { int get getTotalMinutes => hour * 60 + minute; } diff --git a/lib/src/typedefs.dart b/lib/src/typedefs.dart index f517c492..317f0dc1 100644 --- a/lib/src/typedefs.dart +++ b/lib/src/typedefs.dart @@ -72,6 +72,10 @@ typedef DateTapCallback = void Function(DateTime date); typedef EventFilter = List> Function( DateTime date, List> events); +/// Comparator for sorting events. +typedef EventSorter = int Function( + CalendarEventData a, CalendarEventData b); + typedef CustomHourLinePainter = CustomPainter Function( Color lineColor, double lineHeight, diff --git a/test/custom_sort_test.dart b/test/custom_sort_test.dart new file mode 100644 index 00000000..0829b0b3 --- /dev/null +++ b/test/custom_sort_test.dart @@ -0,0 +1,115 @@ +import 'package:calendar_view/calendar_view.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('Custom sort', () { + final date = DateTime(2024, 01, 01); + const oneHour = Duration(hours: 1); + + /// The bool value indicates if the event is "important" or "regular". + + final first = CalendarEventData( + title: 'Regular event - first', + event: false, + date: date, + startTime: date.add(oneHour), + endTime: date.add(oneHour * 2), + ); + + final second = CalendarEventData( + title: 'Important event - second', + event: true, + date: date, + startTime: date.add(oneHour * 2), + endTime: date.add(oneHour * 3), + ); + + final third = CalendarEventData( + title: 'Important event - third', + event: true, + date: date, + startTime: date.add(oneHour * 3), + endTime: date.add(oneHour * 4), + ); + + final fourth = CalendarEventData( + title: 'Regular event - fourth', + event: false, + date: date, + startTime: date.add(oneHour * 4), + endTime: date.add(oneHour * 5), + ); + + /// Events are in random order + final events = >[ + first, + third, + fourth, + second, + ]; + + late EventController controller; + + test('Should return events in startTimeWise order', () { + controller = EventController(); + controller.addAll(events); + + final eventsOnDay = controller.getEventsOnDay(date); + + expect(eventsOnDay[0], first); + expect(eventsOnDay[1], second); + expect(eventsOnDay[2], third); + expect(eventsOnDay[3], fourth); + }); + + group('with custom sorter', () { + test('Should return events in custom order', () { + final sorter = (CalendarEventData a, CalendarEventData b) { + if (a.event == true && b.event == false) { + return -1; + } else if (a.event == false && b.event == true) { + return 1; + } + return 0; + }; + + controller = EventController( + eventSorter: sorter, + ); + controller.addAll(events); + + final eventsOnDay = controller.getEventsOnDay(date); + + expect(eventsOnDay[0], second); + expect(eventsOnDay[1], third); + expect(eventsOnDay[2], first); + expect(eventsOnDay[3], fourth); + }); + + test('Should fallback to default sorter if custom sorter returns 0', () { + /// Sorter that will only sort the fourth event + final sorter = (CalendarEventData a, CalendarEventData b) { + if (a.title == 'Regular event - fourth') { + return -1; + } + if (b.title == 'Regular event - fourth') { + return 1; + } + return 0; + }; + + controller = EventController( + eventSorter: sorter, + ); + controller.addAll(events); + + final eventsOnDay = controller.getEventsOnDay(date); + + expect(eventsOnDay[0], fourth); + expect(eventsOnDay[1], first); + expect(eventsOnDay[2], second); + expect(eventsOnDay[3], third); + }); + }); + }); +}