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({ const BreakViewModel({
this.startTime, this.startTime,
this.endTime, this.endTime,
this.duration, this.submittedDuration,
}); });
/// Create a [BreakViewModel] from a [AvailabilityBreakModel] /// Create a [BreakViewModel] from a [AvailabilityBreakModel]
@ -17,7 +17,7 @@ class BreakViewModel {
BreakViewModel( BreakViewModel(
startTime: TimeOfDay.fromDateTime(data.startTime), startTime: TimeOfDay.fromDateTime(data.startTime),
endTime: TimeOfDay.fromDateTime(data.endTime), endTime: TimeOfDay.fromDateTime(data.endTime),
duration: data.duration, submittedDuration: data.submittedDuration,
); );
/// The start time for this break /// The start time for this break
@ -26,20 +26,18 @@ class BreakViewModel {
/// The end time for this break /// The end time for this break
final TimeOfDay? endTime; 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 /// This is allowed to diverge from the difference between [startTime] and
/// [endTime] to indicate that the break is somewhere between [startTime] and /// [endTime] to indicate that the break is somewhere between [startTime] and
/// [endTime] /// [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 /// If the duration is null, return the difference between the start and end
/// time in minutes /// time in minutes
int get durationInMinutes => Duration get duration => submittedDuration ?? toBreak().duration;
duration?.inMinutes ??
((endTime!.hour * 60 + endTime!.minute) -
(startTime!.hour * 60 + startTime!.minute));
/// Returns true if the break is valid /// Returns true if the break is valid
/// The start is before the end and the duration is equal or lower than the /// 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)) { if (startDateTime.isAfter(endDateTime)) {
return false; return false;
} }
if (duration == null) { if (submittedDuration == null) {
return true; return true;
} }
var actualDuration = endDateTime.difference(startDateTime); var actualDuration = endDateTime.difference(startDateTime);
return duration! <= actualDuration; return submittedDuration! <= actualDuration;
} }
/// Whether the save/next button should be enabled /// Whether the save/next button should be enabled
@ -66,21 +64,22 @@ class BreakViewModel {
/// Convert to [AvailabilityBreakModel] for saving /// Convert to [AvailabilityBreakModel] for saving
AvailabilityBreakModel toBreak() => AvailabilityBreakModel( AvailabilityBreakModel toBreak() => AvailabilityBreakModel(
startTime: DateTime(0, 0, 0, startTime!.hour, startTime!.minute), startTime:
endTime: DateTime(0, 0, 0, endTime!.hour, endTime!.minute), DateTime(0, 0, 0, startTime?.hour ?? 0, startTime?.minute ?? 0),
duration: duration, endTime: DateTime(0, 0, 0, endTime?.hour ?? 0, endTime?.minute ?? 0),
submittedDuration: submittedDuration,
); );
/// Create a copy with new values /// Create a copy with new values
BreakViewModel copyWith({ BreakViewModel copyWith({
TimeOfDay? startTime, TimeOfDay? startTime,
TimeOfDay? endTime, TimeOfDay? endTime,
Duration? duration, Duration? submittedDuration,
}) => }) =>
BreakViewModel( BreakViewModel(
startTime: startTime ?? this.startTime, startTime: startTime ?? this.startTime,
endTime: endTime ?? this.endTime, endTime: endTime ?? this.endTime,
duration: duration ?? this.duration, submittedDuration: submittedDuration ?? this.submittedDuration,
); );
/// compareto method to order two breaks based on their start time /// compareto method to order two breaks based on their start time
@ -92,4 +91,11 @@ class BreakViewModel {
other.startTime!.minute; other.startTime!.minute;
return difference; 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 Duration? initialValue;
/// ///
final void Function(Duration) onDurationChanged; final void Function(Duration?) onDurationChanged;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -79,6 +79,8 @@ class DurationInputField extends StatelessWidget {
var duration = int.tryParse(value); var duration = int.tryParse(value);
if (duration != null) { if (duration != null) {
onDurationChanged(Duration(minutes: duration)); onDurationChanged(Duration(minutes: duration));
} else {
onDurationChanged(null);
} }
} }

View file

@ -146,7 +146,7 @@ class BreakDisplay extends StatelessWidget {
breakModel.endTime!, breakModel.endTime!,
); );
var breakDuration = breakModel.durationInMinutes; var breakDuration = breakModel.duration.inMinutes;
return InkWell( return InkWell(
onTap: onClick, onTap: onClick,
@ -246,9 +246,14 @@ class _AvailabilityBreakSelectionDialogState
var translations = options.translations; var translations = options.translations;
var spacing = options.spacing; var spacing = options.spacing;
void onUpdateDuration(Duration duration) { void onUpdateDuration(Duration? duration) {
setState(() { 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( Expanded(
flex: 2, flex: 2,
child: DurationInputField( child: DurationInputField(
initialValue: _breakViewModel.duration, initialValue: _breakViewModel.submittedDuration,
onDurationChanged: onUpdateDuration, onDurationChanged: onUpdateDuration,
), ),
), ),

View file

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

View file

@ -331,7 +331,8 @@ class DayTemplateData implements TemplateData {
AvailabilityBreakModel( AvailabilityBreakModel(
startTime: date.mergeTime(templateBreak.startTime), startTime: date.mergeTime(templateBreak.startTime),
endTime: date.mergeTime(templateBreak.endTime), 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( AvailabilityBreakModel(
startTime: asTime(startHour), startTime: asTime(startHour),
endTime: asTime(startHour + 1), endTime: asTime(startHour + 1),
duration: const Duration(minutes: 30), submittedDuration: const Duration(minutes: 30),
); );
DayTemplateData createTemplate(int startHour) => DayTemplateData( DayTemplateData createTemplate(int startHour) => DayTemplateData(