mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 05:03:44 +02:00
fix: compare only dates of availabilities for selected range
This commit is contained in:
parent
5931b4c29a
commit
e1dd2a3520
6 changed files with 184 additions and 65 deletions
|
@ -22,8 +22,6 @@ class AvailabilityService {
|
|||
Future<void> createAvailability({
|
||||
required AvailabilityModel availability,
|
||||
required DateTimeRange range,
|
||||
required TimeOfDay startTime,
|
||||
required TimeOfDay endTime,
|
||||
}) async {
|
||||
// apply the startTime and endTime to the availability model
|
||||
var updatedAvailability = availability.copyWith(
|
||||
|
@ -31,15 +29,15 @@ class AvailabilityService {
|
|||
range.start.year,
|
||||
range.start.month,
|
||||
range.start.day,
|
||||
startTime.hour,
|
||||
startTime.minute,
|
||||
availability.startDate.hour,
|
||||
availability.startDate.minute,
|
||||
),
|
||||
endDate: DateTime(
|
||||
range.start.year,
|
||||
range.start.month,
|
||||
range.start.day,
|
||||
endTime.hour,
|
||||
endTime.minute,
|
||||
availability.endDate.hour,
|
||||
availability.endDate.minute,
|
||||
),
|
||||
userId: userId,
|
||||
);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import "dart:collection";
|
||||
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_availability/src/service/availability_service.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/availability_view_model.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/availability_clear.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/availability_template_selection.dart";
|
||||
|
@ -49,19 +48,8 @@ class AvailabilitiesModificationScreen extends StatefulWidget {
|
|||
|
||||
class _AvailabilitiesModificationScreenState
|
||||
extends State<AvailabilitiesModificationScreen> {
|
||||
late AvailabilityModel _availability =
|
||||
widget.initialAvailabilities.getAvailabilities().firstOrNull ??
|
||||
AvailabilityModel(
|
||||
userId: "",
|
||||
startDate: widget.dateRange.start,
|
||||
endDate: widget.dateRange.end,
|
||||
breaks: [],
|
||||
);
|
||||
late List<AvailabilityTemplateModel> _selectedTemplates =
|
||||
widget.initialAvailabilities.getUniqueTemplates();
|
||||
bool _clearAvailability = false;
|
||||
TimeOfDay? _startTime;
|
||||
TimeOfDay? _endTime;
|
||||
late AvailabilityViewModel _availabilityViewModel =
|
||||
AvailabilityViewModel.fromModel(widget.initialAvailabilities);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -74,7 +62,7 @@ class _AvailabilitiesModificationScreenState
|
|||
// TODO(freek): the selected period might be longer than 1 month
|
||||
//so we need to get all the availabilites through a stream
|
||||
Future<void> onSave() async {
|
||||
if (_clearAvailability) {
|
||||
if (_availabilityViewModel.clearAvailability) {
|
||||
await service.clearAvailabilities(
|
||||
widget.initialAvailabilities.getAvailabilities(),
|
||||
);
|
||||
|
@ -88,10 +76,8 @@ class _AvailabilitiesModificationScreenState
|
|||
}
|
||||
|
||||
await service.createAvailability(
|
||||
availability: _availability,
|
||||
availability: _availabilityViewModel.toModel(),
|
||||
range: widget.dateRange,
|
||||
startTime: _startTime!,
|
||||
endTime: _endTime!,
|
||||
);
|
||||
widget.onExit();
|
||||
}
|
||||
|
@ -110,8 +96,7 @@ class _AvailabilitiesModificationScreenState
|
|||
}
|
||||
}
|
||||
|
||||
var canSave =
|
||||
_clearAvailability || (_startTime != null && _endTime != null);
|
||||
var canSave = _availabilityViewModel.canSave;
|
||||
var saveButton = options.primaryButtonBuilder(
|
||||
context,
|
||||
canSave ? onClickSave : null,
|
||||
|
@ -121,7 +106,9 @@ class _AvailabilitiesModificationScreenState
|
|||
// ignore: avoid_positional_boolean_parameters
|
||||
void onClearSection(bool isChecked) {
|
||||
setState(() {
|
||||
_clearAvailability = isChecked;
|
||||
_availabilityViewModel = _availabilityViewModel.copyWith(
|
||||
clearAvailability: isChecked,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -129,54 +116,56 @@ class _AvailabilitiesModificationScreenState
|
|||
var template = await widget.onTemplateSelection();
|
||||
if (template != null) {
|
||||
setState(() {
|
||||
_selectedTemplates = [template];
|
||||
_availability = _availability.copyWith(
|
||||
templateId: template.id,
|
||||
);
|
||||
_availabilityViewModel =
|
||||
_availabilityViewModel.copyWith(templates: [template]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void onTemplatesRemoved() {
|
||||
setState(() {
|
||||
_selectedTemplates = [];
|
||||
_availabilityViewModel = _availabilityViewModel.copyWith(
|
||||
templates: [],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void onStartChanged(TimeOfDay start) {
|
||||
setState(() {
|
||||
_startTime = start;
|
||||
_availabilityViewModel = _availabilityViewModel.copyWith(
|
||||
startTime: start,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void onEndChanged(TimeOfDay end) {
|
||||
setState(() {
|
||||
_endTime = end;
|
||||
_availabilityViewModel = _availabilityViewModel.copyWith(
|
||||
endTime: end,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void onBreaksChanged(List<BreakViewModel> breaks) {
|
||||
setState(() {
|
||||
_availability = _availability.copyWith(
|
||||
breaks: breaks.map((b) => b.toBreak()).toList(),
|
||||
_availabilityViewModel = _availabilityViewModel.copyWith(
|
||||
breaks: breaks,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return _AvailabilitiesModificationScreenLayout(
|
||||
dateRange: widget.dateRange,
|
||||
clearAvailability: _clearAvailability,
|
||||
clearAvailability: _availabilityViewModel.clearAvailability,
|
||||
onClearSection: onClearSection,
|
||||
selectedTemplates: _selectedTemplates,
|
||||
selectedTemplates: _availabilityViewModel.templates,
|
||||
onTemplateSelected: onTemplateSelected,
|
||||
onTemplatesRemoved: onTemplatesRemoved,
|
||||
startTime: _startTime,
|
||||
endTime: _endTime,
|
||||
startTime: _availabilityViewModel.startTime,
|
||||
endTime: _availabilityViewModel.endTime,
|
||||
onStartChanged: onStartChanged,
|
||||
onEndChanged: onEndChanged,
|
||||
breaks: _availability.breaks
|
||||
.map(BreakViewModel.fromAvailabilityBreakModel)
|
||||
.toList(),
|
||||
breaks: _availabilityViewModel.breaks,
|
||||
onBreaksChanged: onBreaksChanged,
|
||||
sidePadding: spacing.sidePadding,
|
||||
bottomButtonPadding: spacing.bottomButtonPadding,
|
||||
|
|
|
@ -51,21 +51,16 @@ class _AvailabilityOverviewState extends State<AvailabilityOverview> {
|
|||
|
||||
var availabilitySnapshot = useStream(availabilityStream);
|
||||
|
||||
var selectedAvailabilities = <AvailabilityWithTemplate>[];
|
||||
if (_selectedRange != null) {
|
||||
var availabilities = availabilitySnapshot.data
|
||||
?.where(
|
||||
(a) =>
|
||||
!a.availabilityModel.startDate
|
||||
.isBefore(_selectedRange!.start) &&
|
||||
!a.availabilityModel.endDate.isAfter(_selectedRange!.end),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (availabilities != null) {
|
||||
selectedAvailabilities = availabilities;
|
||||
}
|
||||
}
|
||||
var selectedAvailabilities = [
|
||||
if (_selectedRange != null) ...[
|
||||
...?availabilitySnapshot.data?.where(
|
||||
(item) => item.availabilityModel.isInRange(
|
||||
_selectedRange!.start,
|
||||
_selectedRange!.end,
|
||||
),
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
var availabilitiesAreSelected = selectedAvailabilities.isNotEmpty;
|
||||
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_availability/src/service/availability_service.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||
|
||||
///
|
||||
class AvailabilityViewModel {
|
||||
///
|
||||
const AvailabilityViewModel({
|
||||
this.templates = const [],
|
||||
this.breaks = const [],
|
||||
this.id,
|
||||
this.userId,
|
||||
this.startTime,
|
||||
this.endTime,
|
||||
this.clearAvailability = false,
|
||||
});
|
||||
|
||||
///
|
||||
factory AvailabilityViewModel.fromModel(
|
||||
List<AvailabilityWithTemplate> models,
|
||||
) {
|
||||
var model = models.firstOrNull?.availabilityModel;
|
||||
|
||||
var startTime =
|
||||
model != null ? TimeOfDay.fromDateTime(model.startDate) : null;
|
||||
var endTime = model != null ? TimeOfDay.fromDateTime(model.endDate) : null;
|
||||
return AvailabilityViewModel(
|
||||
templates: models.getUniqueTemplates(),
|
||||
breaks: model?.breaks
|
||||
.map(BreakViewModel.fromAvailabilityBreakModel)
|
||||
.toList() ??
|
||||
[],
|
||||
id: model?.id,
|
||||
userId: model?.userId,
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
final List<AvailabilityTemplateModel> templates;
|
||||
|
||||
///
|
||||
final bool clearAvailability;
|
||||
|
||||
///
|
||||
final TimeOfDay? startTime;
|
||||
|
||||
///
|
||||
final TimeOfDay? endTime;
|
||||
|
||||
///
|
||||
final String? id;
|
||||
|
||||
///
|
||||
final String? userId;
|
||||
|
||||
///
|
||||
final List<BreakViewModel> breaks;
|
||||
|
||||
/// Whether the availability is valid
|
||||
bool get isValid => breaks.every((element) => element.isValid);
|
||||
|
||||
/// Whether the save button should be enabled
|
||||
bool get canSave =>
|
||||
clearAvailability || (startTime != null && endTime != null);
|
||||
|
||||
/// create a AvailabilityModel from the current AvailabilityViewModel
|
||||
AvailabilityModel toModel() {
|
||||
var startDate = DateTime.now();
|
||||
var endDate = DateTime.now();
|
||||
return AvailabilityModel(
|
||||
id: id,
|
||||
userId: userId!,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
breaks: breaks.map((e) => e.toBreak()).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Copies the current properties into a new instance
|
||||
/// of [AvailabilityViewModel],
|
||||
AvailabilityViewModel copyWith({
|
||||
List<AvailabilityTemplateModel>? templates,
|
||||
TimeOfDay? startTime,
|
||||
TimeOfDay? endTime,
|
||||
String? id,
|
||||
String? userId,
|
||||
List<BreakViewModel>? breaks,
|
||||
bool? clearAvailability,
|
||||
}) =>
|
||||
AvailabilityViewModel(
|
||||
templates: templates ?? this.templates,
|
||||
startTime: startTime ?? this.startTime,
|
||||
endTime: endTime ?? this.endTime,
|
||||
id: id ?? this.id,
|
||||
userId: userId ?? this.userId,
|
||||
breaks: breaks ?? this.breaks,
|
||||
clearAvailability: clearAvailability ?? this.clearAvailability,
|
||||
);
|
||||
}
|
|
@ -289,12 +289,7 @@ List<CalendarDay> _generateCalendarDays(
|
|||
hasAvailability: false,
|
||||
),
|
||||
);
|
||||
var dayIsSelected = selectedRange != null &&
|
||||
!day.isBefore(selectedRange.start) &&
|
||||
!day.isAfter(selectedRange.end);
|
||||
specialDay = specialDay.copyWith(
|
||||
isSelected: dayIsSelected,
|
||||
);
|
||||
specialDay = checkIfDayIsSelected(selectedRange, day, specialDay);
|
||||
calendarDays.add(specialDay);
|
||||
}
|
||||
|
||||
|
@ -303,3 +298,21 @@ List<CalendarDay> _generateCalendarDays(
|
|||
|
||||
return calendarDays;
|
||||
}
|
||||
|
||||
/// Checks if the day is in the selected range
|
||||
/// Only the date part of the selected range is used
|
||||
CalendarDay checkIfDayIsSelected(
|
||||
DateTimeRange? selectedRange,
|
||||
DateTime day,
|
||||
CalendarDay specialDay,
|
||||
) {
|
||||
var dayIsSelected = false;
|
||||
if (selectedRange != null) {
|
||||
var startDate = DateUtils.dateOnly(selectedRange.start);
|
||||
var endDate = DateUtils.dateOnly(selectedRange.end);
|
||||
dayIsSelected = !day.isBefore(startDate) && !day.isAfter(endDate);
|
||||
}
|
||||
return specialDay.copyWith(
|
||||
isSelected: dayIsSelected,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,28 @@ class AvailabilityModel {
|
|||
endDate: endDate ?? this.endDate,
|
||||
breaks: breaks ?? this.breaks,
|
||||
);
|
||||
|
||||
/// returns true if the date of the availability overlaps with the given range
|
||||
/// This disregards the time of the date
|
||||
bool isInRange(DateTime start, DateTime end) {
|
||||
var startDate = DateTime(start.year, start.month, start.day);
|
||||
var endDate = DateTime(end.year, end.month, end.day);
|
||||
var availabilityStartDate = DateTime(
|
||||
this.startDate.year,
|
||||
this.startDate.month,
|
||||
this.startDate.day,
|
||||
);
|
||||
var availabilityEndDate = DateTime(
|
||||
this.endDate.year,
|
||||
this.endDate.month,
|
||||
this.endDate.day,
|
||||
);
|
||||
|
||||
return (startDate.isBefore(availabilityEndDate) ||
|
||||
startDate.isAtSameMomentAs(availabilityEndDate)) &&
|
||||
(endDate.isAfter(availabilityStartDate) ||
|
||||
endDate.isAtSameMomentAs(availabilityStartDate));
|
||||
}
|
||||
}
|
||||
|
||||
/// A model defining the structure of a break within an [AvailabilityModel]
|
||||
|
|
Loading…
Reference in a new issue