Skip to content

Commit

Permalink
feat: Add custom sort for EventController (#305)
Browse files Browse the repository at this point in the history
* feat: Add custom sort for EventController

* Make defaultEventSorter public and remove fallback of custom sorter to it
  • Loading branch information
dumazy authored Feb 22, 2024
1 parent ed7288e commit 90818ea
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 11 deletions.
25 changes: 19 additions & 6 deletions lib/src/event_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ class EventController<T extends Object?> extends ChangeNotifier {
/// [MonthView], [DayView] and [WeekView].
///
EventFilter<T>? eventFilter,
}) : _eventFilter = eventFilter;

/// This allows for custom sorting of events.
/// By default, events are sorted in a start time wise order.
EventSorter<T>? eventSorter,
}) : _eventFilter = eventFilter,
_calendarData = CalendarData(eventSorter: eventSorter);

//#region Private Fields
EventFilter<T>? _eventFilter;

/// Store all calendar event data
final CalendarData<T> _calendarData = CalendarData();
final CalendarData<T> _calendarData;

//#endregion

Expand Down Expand Up @@ -157,7 +162,15 @@ class EventController<T extends Object?> extends ChangeNotifier {
/// Exposes methods to manipulate stored data.
///
///
class CalendarData<T> {
class CalendarData<T extends Object?> {
/// Creates a new instance of [CalendarData].
CalendarData({
EventSorter<T>? eventSorter,
}) : _eventSorter = eventSorter;

//#region Private Fields
final EventSorter<T>? _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 = <CalendarEventData<T>>[];
Expand Down Expand Up @@ -203,12 +216,12 @@ class CalendarData<T> {
//#region Data Manipulation Methods
void addFullDayEvent(CalendarEventData<T> 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<T> event) {
_rangingEventList.addEventInSortedManner(event);
_rangingEventList.addEventInSortedManner(event, _eventSorter);
_eventList.add(event);
}

Expand All @@ -220,7 +233,7 @@ class CalendarData<T> {
date: [event],
});
} else {
_singleDayEvents[date]!.addEventInSortedManner(event);
_singleDayEvents[date]!.addEventInSortedManner(event, _eventSorter);
}

_eventList.add(event);
Expand Down
22 changes: 17 additions & 5 deletions lib/src/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,17 +165,19 @@ extension MinutesExtension on MinuteSlotSize {
}
}

extension MyList on List<CalendarEventData> {
extension MyList<T extends Object?> on List<CalendarEventData<T>> {
// Below function will add the new event in sorted manner(startTimeWise) in
// the existing list of CalendarEventData.

void addEventInSortedManner(CalendarEventData event) {
void addEventInSortedManner(
CalendarEventData<T> event, [
EventSorter<T>? 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 ?? defaultEventSorter).call(event, this[i]);
if (result <= 0) {
addIndex = i;
break;
}
Expand All @@ -189,6 +191,16 @@ extension MyList on List<CalendarEventData> {
}
}

/// Default [EventSorter] for [CalendarEventData]
/// It will sort the events based on their [CalendarEventData.startTime].
int defaultEventSorter<T extends Object?>(
CalendarEventData<T> a,
CalendarEventData<T> b,
) {
return (a.startTime?.getTotalMinutes ?? 0) -
(b.startTime?.getTotalMinutes ?? 0);
}

extension TimerOfDayExtension on TimeOfDay {
int get getTotalMinutes => hour * 60 + minute;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/src/typedefs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ typedef DateTapCallback = void Function(DateTime date);
typedef EventFilter<T extends Object?> = List<CalendarEventData<T>> Function(
DateTime date, List<CalendarEventData<T>> events);

/// Comparator for sorting events.
typedef EventSorter<T extends Object?> = int Function(
CalendarEventData<T> a, CalendarEventData<T> b);

typedef CustomHourLinePainter = CustomPainter Function(
Color lineColor,
double lineHeight,
Expand Down
115 changes: 115 additions & 0 deletions test/custom_sort_test.dart
Original file line number Diff line number Diff line change
@@ -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 = <CalendarEventData<bool>>[
first,
third,
fourth,
second,
];

late EventController<bool> 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<bool> a, CalendarEventData<bool> 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<bool> a, CalendarEventData<bool> 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);
});
});
});
}

0 comments on commit 90818ea

Please sign in to comment.