Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix homework dialog todoUntil hack. #1160

Merged
merged 2 commits into from
Nov 21, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 74 additions & 45 deletions app/lib/homework/homework_dialog/homework_dialog_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -338,12 +338,7 @@ class SavingFailed extends HomeworkDialogBlocPresentationEvent {
List<Object?> get props => [error, stackTrace];
}

/// Since [HomeworkDto] can't have a null value for [todoUntil] we need to use
/// a magic number to know if the user changed the due date and submission time
/// or not.
final _kNoDateSelectedDateTime = DateTime(1337, 13, 37, 13, 37, 13, 37);
HomeworkDto _kNoDataChangedHomework = HomeworkDto.create(courseID: '')
.copyWith(todoUntil: _kNoDateSelectedDateTime);
HomeworkDto _kNoDataChangedHomework = HomeworkDto.create(courseID: '');

class EmptyTitleException extends Equatable implements Exception {
const EmptyTitleException();
Expand All @@ -366,6 +361,39 @@ class NoDueDateSelectedException extends Equatable implements Exception {
List<Object?> get props => [];
}

/// State of due date and submission time in the homework dialog.
///
/// We use an extra class instead of _HomeworkDto as _HomeworkDto.todoUntil
/// can't represent all due date and submission time states. For example
/// _HomeworkDto.todoUntil can't be set to null.
class _DateSelection extends Equatable {
final Date? dueDate;
final Time? submissionTime;

static const noSelection = _DateSelection(
dueDate: null,
submissionTime: null,
);

const _DateSelection({
this.dueDate,
this.submissionTime,
});

_DateSelection copyWith({
Date? dueDate,
Time? submissionTime,
}) {
return _DateSelection(
dueDate: dueDate ?? this.dueDate,
submissionTime: submissionTime ?? this.submissionTime,
);
}

@override
List<Object?> get props => [dueDate, submissionTime];
}

class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
with
BlocPresentationMixin<HomeworkDialogState,
Expand All @@ -379,6 +407,9 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
late final IList<CloudFile> _initialAttachments;
late final bool isEditing;

_DateSelection _initialDateSelection = _DateSelection.noSelection;
_DateSelection _dateSelection = _DateSelection.noSelection;

bool finishedInitializing = false;

bool showTitleEmptyError = false;
Expand Down Expand Up @@ -431,6 +462,14 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
// value might be `true` in the _initialHomework.
_initialHomework = _initialHomework!.copyWith(sendNotification: false);
_homework = _initialHomework!;
_initialDateSelection = _DateSelection(
dueDate: _homework.todoUntil.toDate(),
submissionTime: _homework.todoUntil.toTime(),
);
_dateSelection = _DateSelection(
dueDate: _homework.todoUntil.toDate(),
submissionTime: _homework.todoUntil.toTime(),
);
_cloudFiles = _initialAttachments;
finishedInitializing = true;

Expand All @@ -448,7 +487,7 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
showNoCourseChosenError = true;
hasInputErrors = true;
}
if (_homework.todoUntil.year == _kNoDateSelectedDateTime.year) {
if (_dateSelection.dueDate == null) {
showNoDueDateChosenError = true;
hasInputErrors = true;
}
Expand All @@ -461,11 +500,11 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
final userInput = UserInput(
title: _homework.title,
todoUntil: DateTime(
_homework.todoUntil.year,
_homework.todoUntil.month,
_homework.todoUntil.day,
_homework.withSubmissions ? _homework.todoUntil.hour : 0,
_homework.withSubmissions ? _homework.todoUntil.minute : 0,
_dateSelection.dueDate!.year,
_dateSelection.dueDate!.month,
_dateSelection.dueDate!.day,
_dateSelection.submissionTime?.hour ?? 0,
_dateSelection.submissionTime?.minute ?? 0,
),
description: _homework.description,
withSubmission: _homework.withSubmissions,
Expand Down Expand Up @@ -546,14 +585,7 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
);
on<DueDateChanged>(
(event, emit) {
_homework = _homework.copyWith(
// copyWith because we need to keep the magic "not changed" value for
// the submission time (hour, minute, second, etc.).
todoUntil: _homework.todoUntil.copyWith(
year: event.newDueDate.year,
month: event.newDueDate.month,
day: event.newDueDate.day,
));
_dateSelection = _dateSelection.copyWith(dueDate: event.newDueDate);
if (showNoDueDateChosenError) {
showNoDueDateChosenError = false;
}
Expand All @@ -572,7 +604,7 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
emit(_getNewState());

// Manual date was already set, we don't want to overwrite it.
if (_homework.todoUntil.year != _kNoDateSelectedDateTime.year) {
if (_dateSelection.dueDate != null) {
return;
}
final nextLesson =
Expand All @@ -592,19 +624,17 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
);
on<SubmissionsChanged>(
(event, emit) {
_homework = _homework.copyWith(
withSubmissions: event.newSubmissionsOptions.enabled,
// copyWith because we need to keep the magic "not changed" value for
// the due date (year, month, day attributes).
todoUntil: _homework.todoUntil.copyWith(
hour: event.newSubmissionsOptions.submissionTime?.hour ?? 23,
minute: event.newSubmissionsOptions.submissionTime?.minute ?? 59,
// Remove magic number used to indicate that submission time has not
// been changed.
millisecond: 0,
microsecond: 0,
),
);
final enabled = event.newSubmissionsOptions.enabled;
_homework = _homework.copyWith(withSubmissions: enabled);

if (enabled) {
_dateSelection = _dateSelection.copyWith(
submissionTime: event.newSubmissionsOptions.submissionTime ??
Time(hour: 23, minute: 59));
} else {
_dateSelection = _dateSelection.copyWith(submissionTime: null);
}

emit(_getNewState());
},
);
Expand Down Expand Up @@ -649,15 +679,14 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
final didHomeworkChange = isEditing
? _initialHomework != _homework
: _homework != _kNoDataChangedHomework;

final didDueDateChange = _dateSelection != _initialDateSelection;
final didFilesChange = _initialAttachments != _cloudFiles;
final didLocalFilesChange = _localFiles.isNotEmpty;
final didDataChange =
didHomeworkChange || didFilesChange || didLocalFilesChange;

final hasChangedTodoDate =
_homework.todoUntil.year != _kNoDataChangedHomework.todoUntil.year;
final hasUserEditedSubmissionTime =
_homework.todoUntil.millisecond != _kNoDateSelectedDateTime.millisecond;
final didDataChange = didHomeworkChange ||
didDueDateChange ||
didFilesChange ||
didLocalFilesChange;

return Ready(
title: (
Expand All @@ -676,16 +705,16 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
: null,
),
dueDate: (
hasChangedTodoDate ? Date.fromDateTime(_homework.todoUntil) : null,
_dateSelection.dueDate,
error: showNoDueDateChosenError
? const NoDueDateSelectedException()
: null,
),
submissions: _homework.withSubmissions
? SubmissionsEnabled(
deadline: hasUserEditedSubmissionTime
? _homework.todoUntil.toTime()
: Time(hour: 23, minute: 59))
deadline:
_dateSelection.submissionTime ?? Time(hour: 23, minute: 59),
)
: SubmissionsDisabled(isChangeable: !_homework.private),
description: _homework.description,
attachments: IList([
Expand Down
Loading