fix: allow clearing the duration from the pause dialog

This commit is contained in:
Freek van de Ven 2024-07-19 10:48:20 +02:00 committed by FlutterJoey
parent 020d7a71f8
commit 134f827f3a
6 changed files with 51 additions and 36 deletions

View file

@ -7,7 +7,7 @@ class BreakViewModel {
const BreakViewModel({
this.startTime,
this.endTime,
this.duration,
this.submittedDuration,
});
/// Create a [BreakViewModel] from a [AvailabilityBreakModel]
@ -17,7 +17,7 @@ class BreakViewModel {
BreakViewModel(
startTime: TimeOfDay.fromDateTime(data.startTime),
endTime: TimeOfDay.fromDateTime(data.endTime),
duration: data.duration,
submittedDuration: data.submittedDuration,
);
/// The start time for this break
@ -26,20 +26,18 @@ class BreakViewModel {
/// The end time for this break
final TimeOfDay? endTime;
/// The full duration of the actual break.
/// The full duration of the actual break. This is filled in by the users and
/// stays null if the user has not filled it in.
///
/// This is allowed to diverge from the difference between [startTime] and
/// [endTime] to indicate that the break is somewhere between [startTime] and
/// [endTime]
final Duration? duration;
final Duration? submittedDuration;
/// Get the duration in minutes
/// Get the duration of the break
/// If the duration is null, return the difference between the start and end
/// time in minutes
int get durationInMinutes =>
duration?.inMinutes ??
((endTime!.hour * 60 + endTime!.minute) -
(startTime!.hour * 60 + startTime!.minute));
Duration get duration => submittedDuration ?? toBreak().duration;
/// Returns true if the break is valid
/// The start is before the end and the duration is equal or lower than the
@ -54,11 +52,11 @@ class BreakViewModel {
if (startDateTime.isAfter(endDateTime)) {
return false;
}
if (duration == null) {
if (submittedDuration == null) {
return true;
}
var actualDuration = endDateTime.difference(startDateTime);
return duration! <= actualDuration;
return submittedDuration! <= actualDuration;
}
/// Whether the save/next button should be enabled
@ -66,21 +64,22 @@ class BreakViewModel {
/// Convert to [AvailabilityBreakModel] for saving
AvailabilityBreakModel toBreak() => AvailabilityBreakModel(
startTime: DateTime(0, 0, 0, startTime!.hour, startTime!.minute),
endTime: DateTime(0, 0, 0, endTime!.hour, endTime!.minute),
duration: duration,
startTime:
DateTime(0, 0, 0, startTime?.hour ?? 0, startTime?.minute ?? 0),
endTime: DateTime(0, 0, 0, endTime?.hour ?? 0, endTime?.minute ?? 0),
submittedDuration: submittedDuration,
);
/// Create a copy with new values
BreakViewModel copyWith({
TimeOfDay? startTime,
TimeOfDay? endTime,
Duration? duration,
Duration? submittedDuration,
}) =>
BreakViewModel(
startTime: startTime ?? this.startTime,
endTime: endTime ?? this.endTime,
duration: duration ?? this.duration,
submittedDuration: submittedDuration ?? this.submittedDuration,
);
/// compareto method to order two breaks based on their start time
@ -92,4 +91,11 @@ class BreakViewModel {
other.startTime!.minute;
return difference;
}
/// Clear the duration of the break
BreakViewModel clearDuration() => BreakViewModel(
startTime: startTime,
endTime: endTime,
submittedDuration: null,
);
}

View file

@ -67,7 +67,7 @@ class DurationInputField extends StatelessWidget {
final Duration? initialValue;
///
final void Function(Duration) onDurationChanged;
final void Function(Duration?) onDurationChanged;
@override
Widget build(BuildContext context) {
@ -79,6 +79,8 @@ class DurationInputField extends StatelessWidget {
var duration = int.tryParse(value);
if (duration != null) {
onDurationChanged(Duration(minutes: duration));
} else {
onDurationChanged(null);
}
}

View file

@ -146,7 +146,7 @@ class BreakDisplay extends StatelessWidget {
breakModel.endTime!,
);
var breakDuration = breakModel.durationInMinutes;
var breakDuration = breakModel.duration.inMinutes;
return InkWell(
onTap: onClick,
@ -246,9 +246,14 @@ class _AvailabilityBreakSelectionDialogState
var translations = options.translations;
var spacing = options.spacing;
void onUpdateDuration(Duration duration) {
void onUpdateDuration(Duration? duration) {
setState(() {
_breakViewModel = _breakViewModel.copyWith(duration: duration);
if (duration != null) {
_breakViewModel =
_breakViewModel.copyWith(submittedDuration: duration);
} else {
_breakViewModel = _breakViewModel.clearDuration();
}
});
}
@ -317,7 +322,7 @@ class _AvailabilityBreakSelectionDialogState
Expanded(
flex: 2,
child: DurationInputField(
initialValue: _breakViewModel.duration,
initialValue: _breakViewModel.submittedDuration,
onDurationChanged: onUpdateDuration,
),
),

View file

@ -60,8 +60,8 @@ class AvailabilityBreakModel {
const AvailabilityBreakModel({
required this.startTime,
required this.endTime,
Duration? duration,
}) : _duration = duration;
this.submittedDuration,
});
/// Parses a break from a map.
///
@ -74,7 +74,7 @@ class AvailabilityBreakModel {
DateTime.fromMillisecondsSinceEpoch((map["startTime"] ?? 0) as int),
endTime:
DateTime.fromMillisecondsSinceEpoch((map["endTime"] ?? 0) as int),
duration: map["duration"] != null
submittedDuration: map["duration"] != null
? Duration(minutes: map["duration"] as int)
: null,
);
@ -83,35 +83,36 @@ class AvailabilityBreakModel {
///
/// If duration is not the same as the difference between [startTime] and
/// [endTime], the [startTime] is considered the start of the period of which
/// a break of [_duration] can be held.
/// a break of [submittedDuration] can be held.
final DateTime startTime;
/// The end time for this break
///
/// If duration is not the same as the difference between [startTime] and
/// [endTime], the [endTime] is considered the end of the period of which
/// a break of [_duration] can be held.
/// a break of [submittedDuration] can be held.
final DateTime endTime;
/// The full duration of the actual break.
/// The full duration of the actual break. This is filled in by the users and
/// stays null if the user has not filled it in.
///
/// This is allowed to diverge from the difference between [startTime] and
/// [endTime] to indicate that the break is somewhere between [startTime] and
/// [endTime]
final Duration? _duration;
final Duration? submittedDuration;
/// Results in the set duration, or the difference between [startTime] and
/// [endTime] if no duration is set.
Duration get duration => _duration ?? period;
Duration get duration => submittedDuration ?? period;
/// The period in which the break will take place.
///
/// Will be the same as [duration] if the initial [_duration] is null
/// Will be the same as [duration] if the initial [submittedDuration] is null
Duration get period => endTime.difference(startTime);
/// Whether the duration of the break matches the difference between
/// [startTime] and [endTime]
bool get isTight => _duration == null || _duration == period;
bool get isTight => submittedDuration == null || submittedDuration == period;
/// Copies the current properties into a new instance of
/// [AvailabilityBreakModel], except for the properties provided
@ -119,12 +120,12 @@ class AvailabilityBreakModel {
AvailabilityBreakModel copyWith({
DateTime? startTime,
DateTime? endTime,
Duration? duration,
Duration? submittedDuration,
}) =>
AvailabilityBreakModel(
startTime: startTime ?? this.startTime,
endTime: endTime ?? this.endTime,
duration: duration ?? _duration,
submittedDuration: submittedDuration ?? this.submittedDuration,
);
/// Returns a map variant of this object.
@ -135,6 +136,6 @@ class AvailabilityBreakModel {
Map<String, dynamic> toMap() => <String, dynamic>{
"startTime": startTime.millisecondsSinceEpoch,
"endTime": endTime.millisecondsSinceEpoch,
"duration": _duration?.inMinutes,
"duration": submittedDuration?.inMinutes,
};
}

View file

@ -331,7 +331,8 @@ class DayTemplateData implements TemplateData {
AvailabilityBreakModel(
startTime: date.mergeTime(templateBreak.startTime),
endTime: date.mergeTime(templateBreak.endTime),
duration: templateBreak.isTight ? null : templateBreak.duration,
submittedDuration:
templateBreak.isTight ? null : templateBreak.duration,
),
],
],

View file

@ -12,7 +12,7 @@ void main() {
AvailabilityBreakModel(
startTime: asTime(startHour),
endTime: asTime(startHour + 1),
duration: const Duration(minutes: 30),
submittedDuration: const Duration(minutes: 30),
);
DayTemplateData createTemplate(int startHour) => DayTemplateData(