mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 05:03:44 +02:00
feat(flutter_availability_data_interface): add implementation for apply method on availability templates
This commit is contained in:
parent
a8af7fd6ac
commit
6748a2440c
2 changed files with 220 additions and 6 deletions
|
@ -23,6 +23,8 @@ class AvailabilityTemplateModel {
|
|||
this.id,
|
||||
});
|
||||
|
||||
/// Automatically parses [templateData] based on the dynamic data map and
|
||||
/// template type.
|
||||
factory AvailabilityTemplateModel.fromType({
|
||||
required String userId,
|
||||
required String name,
|
||||
|
@ -63,7 +65,12 @@ class AvailabilityTemplateModel {
|
|||
/// The specific data for this template
|
||||
final TemplateData templateData;
|
||||
|
||||
/// returns the [templateData] in its serialized form
|
||||
Map<String, dynamic> get rawTemplateData => templateData.toMap();
|
||||
|
||||
/// applies the template to a range of dates
|
||||
List<AvailabilityModel> apply(DateTime start, DateTime end) =>
|
||||
templateData.apply(userId: userId, start: start, end: end);
|
||||
}
|
||||
|
||||
/// Used as the key for defining week-based templates
|
||||
|
@ -114,6 +121,7 @@ abstract interface class TemplateData {
|
|||
/// Applies the current template to all days found between [start] and [end],
|
||||
/// inclusive
|
||||
List<AvailabilityModel> apply({
|
||||
required String userId,
|
||||
required DateTime start,
|
||||
required DateTime end,
|
||||
});
|
||||
|
@ -147,7 +155,7 @@ class WeekTemplateData implements TemplateData {
|
|||
if (thursday != null) WeekDay.thursday: thursday,
|
||||
if (friday != null) WeekDay.friday: friday,
|
||||
if (saturday != null) WeekDay.saturday: saturday,
|
||||
if (sunday != null) WeekDay.monday: sunday,
|
||||
if (sunday != null) WeekDay.sunday: sunday,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -188,11 +196,21 @@ class WeekTemplateData implements TemplateData {
|
|||
|
||||
@override
|
||||
List<AvailabilityModel> apply({
|
||||
required String userId,
|
||||
required DateTime start,
|
||||
required DateTime end,
|
||||
}) {
|
||||
// TODO(Joey): Implement the apply method
|
||||
throw UnimplementedError();
|
||||
var dates = _getDatesBetween(start, end);
|
||||
|
||||
return [
|
||||
for (var date in dates)
|
||||
if (data.containsKey(WeekDay.fromDateTime(date)))
|
||||
...data[WeekDay.fromDateTime(date)]!.apply(
|
||||
start: date,
|
||||
end: date,
|
||||
userId: userId,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,15 +263,34 @@ class DayTemplateData implements TemplateData {
|
|||
|
||||
@override
|
||||
List<AvailabilityModel> apply({
|
||||
required String userId,
|
||||
required DateTime start,
|
||||
required DateTime end,
|
||||
}) {
|
||||
// TODO(Joey): Implement the apply method
|
||||
throw UnimplementedError();
|
||||
var dates = _getDatesBetween(start, end);
|
||||
|
||||
return [
|
||||
for (var date in dates) ...[
|
||||
AvailabilityModel(
|
||||
userId: userId,
|
||||
startDate: date.mergeTime(startTime),
|
||||
endDate: date.mergeTime(endTime),
|
||||
breaks: [
|
||||
for (var templateBreak in breaks) ...[
|
||||
AvailabilityBreakModel(
|
||||
startTime: date.mergeTime(templateBreak.startTime),
|
||||
endTime: date.mergeTime(templateBreak.endTime),
|
||||
duration: templateBreak.isTight ? null : templateBreak.duration,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toMap() => {
|
||||
Map<String, dynamic> toMap() => {
|
||||
"startTime": startTime.toIso8601String(),
|
||||
"endTime": endTime.toIso8601String(),
|
||||
"breaks": [
|
||||
|
@ -263,3 +300,17 @@ class DayTemplateData implements TemplateData {
|
|||
],
|
||||
};
|
||||
}
|
||||
|
||||
List<DateTime> _getDatesBetween(DateTime startDate, DateTime endDate) {
|
||||
var diff = endDate.difference(startDate).inDays;
|
||||
return [
|
||||
for (var i = 0; i <= diff; i++) ...[
|
||||
DateTime(startDate.year, startDate.month, startDate.day + i),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
extension _MergeTime on DateTime {
|
||||
DateTime mergeTime(DateTime time) =>
|
||||
DateTime(year, month, day, time.hour, time.minute);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,126 @@ import "package:flutter_test/flutter_test.dart";
|
|||
|
||||
void main() {
|
||||
group("AvailabilityTemplate", () {
|
||||
group("Apply", () {
|
||||
test("applying a week template should generate correct availability", () {
|
||||
DateTime asTime(int hours, [int minutes = 0]) =>
|
||||
DateTime(1, 1, 1, hours, minutes);
|
||||
|
||||
AvailabilityBreakModel createBreak(int startHour) =>
|
||||
AvailabilityBreakModel(
|
||||
startTime: asTime(startHour),
|
||||
endTime: asTime(startHour + 1),
|
||||
duration: const Duration(minutes: 30),
|
||||
);
|
||||
|
||||
DayTemplateData createTemplate(int startHour) => DayTemplateData(
|
||||
startTime: asTime(startHour),
|
||||
endTime: asTime(startHour + 7),
|
||||
breaks: [createBreak(startHour + 3)],
|
||||
);
|
||||
|
||||
var monday = createTemplate(1);
|
||||
var tuesday = createTemplate(2);
|
||||
var wednesday = createTemplate(3);
|
||||
var thursday = createTemplate(4);
|
||||
var friday = createTemplate(5);
|
||||
var saturday = createTemplate(6);
|
||||
var sunday = createTemplate(7);
|
||||
|
||||
var sut = AvailabilityTemplateModel(
|
||||
userId: "",
|
||||
name: "",
|
||||
color: 0,
|
||||
templateType: AvailabilityTemplateType.week,
|
||||
templateData: WeekTemplateData.forDays(
|
||||
monday: monday,
|
||||
tuesday: tuesday,
|
||||
wednesday: wednesday,
|
||||
thursday: thursday,
|
||||
friday: friday,
|
||||
saturday: saturday,
|
||||
sunday: sunday,
|
||||
),
|
||||
);
|
||||
|
||||
var startOfRangeToApply = DateTime(1999, 1, 1);
|
||||
var endOfRangeToApply = DateTime(2024, 12, 31);
|
||||
|
||||
var availabilities = sut.apply(startOfRangeToApply, endOfRangeToApply);
|
||||
|
||||
AvailabilityModel findAvailabilityByDate(DateTime date) =>
|
||||
availabilities
|
||||
.where((value) => value.startDate.date == date.date)
|
||||
.first;
|
||||
|
||||
var firstDay = startOfRangeToApply;
|
||||
expect(findAvailabilityByDate(firstDay), isA<AvailabilityModel>());
|
||||
|
||||
var lastDay = endOfRangeToApply;
|
||||
expect(findAvailabilityByDate(lastDay), isA<AvailabilityModel>());
|
||||
|
||||
var leapDayMillenial = DateTime(2000, 2, 29);
|
||||
expect(
|
||||
findAvailabilityByDate(leapDayMillenial).matchesTemplate(tuesday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var savingsTimeSwitch = DateTime(2020, 10, 25);
|
||||
expect(
|
||||
findAvailabilityByDate(savingsTimeSwitch).matchesTemplate(sunday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var dayAfterSavingsTime = DateTime(2020, 10, 26);
|
||||
expect(
|
||||
findAvailabilityByDate(dayAfterSavingsTime).matchesTemplate(monday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var aMondayInJuly = DateTime(2024, 7, 8);
|
||||
expect(
|
||||
findAvailabilityByDate(aMondayInJuly).matchesTemplate(monday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var aTuesdayInJuly = DateTime(2024, 7, 9);
|
||||
expect(
|
||||
findAvailabilityByDate(aTuesdayInJuly).matchesTemplate(tuesday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var aWednesdayInJuly = DateTime(2024, 7, 10);
|
||||
expect(
|
||||
findAvailabilityByDate(aWednesdayInJuly).matchesTemplate(wednesday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var aThursdayInJuly = DateTime(2024, 7, 11);
|
||||
expect(
|
||||
findAvailabilityByDate(aThursdayInJuly).matchesTemplate(thursday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var aFridayInJuly = DateTime(2024, 7, 12);
|
||||
expect(
|
||||
findAvailabilityByDate(aFridayInJuly).matchesTemplate(friday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var aSaturdayInJuly = DateTime(2024, 7, 13);
|
||||
expect(
|
||||
findAvailabilityByDate(aSaturdayInJuly).matchesTemplate(saturday),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
var aSundayInJuly = DateTime(2024, 7, 14);
|
||||
expect(
|
||||
findAvailabilityByDate(aSundayInJuly).matchesTemplate(sunday),
|
||||
isTrue,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group("Serialization", () {
|
||||
test("week template should serialize and deserialize correctly", () {
|
||||
var baseDate = DateTime(1994, 10, 18, 10, 0);
|
||||
|
@ -62,3 +182,46 @@ void main() {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
extension on AvailabilityModel {
|
||||
bool matchesTemplate(DayTemplateData template) {
|
||||
var startDateMatches = template.startTime.timeMatches(startDate);
|
||||
var endDateMatches = template.endTime.timeMatches(endDate);
|
||||
var breaksMatch = template.breaks.matches(breaks);
|
||||
|
||||
return startDateMatches && endDateMatches && breaksMatch;
|
||||
}
|
||||
}
|
||||
|
||||
extension on List<AvailabilityBreakModel> {
|
||||
bool matches(List<AvailabilityBreakModel> other) {
|
||||
if (other.length != length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var otherBreak in other) {
|
||||
if (!any((e) => e.matches(otherBreak))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
extension on AvailabilityBreakModel {
|
||||
bool matches(AvailabilityBreakModel other) {
|
||||
var startTimeMatches = other.startTime.timeMatches(startTime);
|
||||
var endTimeMatches = other.endTime.timeMatches(endTime);
|
||||
var durationMatches = other.duration == duration;
|
||||
|
||||
return startTimeMatches && endTimeMatches && durationMatches;
|
||||
}
|
||||
}
|
||||
|
||||
extension on DateTime {
|
||||
DateTime get date => DateTime(year, month, day);
|
||||
|
||||
bool timeMatches(DateTime other) =>
|
||||
other.hour == hour && other.minute == minute;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue