Skip to content

Commit

Permalink
Merge pull request #93 from AY2122S1-CS2103T-F13-2/add-recurring-tasks
Browse files Browse the repository at this point in the history
Add recurring tasks
  • Loading branch information
CraveToCode authored Oct 21, 2021
2 parents a6c28c7 + c053d51 commit f6c76a2
Show file tree
Hide file tree
Showing 27 changed files with 491 additions and 56 deletions.
14 changes: 9 additions & 5 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ NurseyBook is a **desktop app made for nurses in nursing homes to aid them in ma
* **`clear`** : Deletes all contacts.

* **`exit`** : Exits the app.


1. Refer to the [Features](#features) below for details of each command.

Expand Down Expand Up @@ -88,7 +88,7 @@ Examples:
* `addElderly en/John a/77 g/M r/420 t/diabetes`
* `addElderly en/John a/77 g/M r/420 t/diabetes nn/Timothy rs/Son`


### Edit an elderly's details: `editElderly`

Edit the details of a specific elderly.
Expand Down Expand Up @@ -175,10 +175,14 @@ Format: `viewTasks`

Adds a task to the task list.

Format: `addTask [en/ELDERLY_NAME]... desc/DESCRIPTION date/DATE time/TIME`
:bulb: **Tip:**
You can add a recurring task to the list! <br>
There are a few recurring options available namely: `DAY`, `WEEK` and `MONTH` (4 weeks later from the previous date). Tasks that have passed their original date will have their date automatically changed to the new date based on the recurrence type of the task.

Format: `addTask [en/ELDERLY_NAME]... desc/DESCRIPTION date/DATE time/TIME [recur/RECURRENCE_TYPE]`

Example:
`addTask en/John desc/check insulin level date/2021-09-25 time/19:22`
`addTask en/John desc/check insulin level date/2021-09-25 time/19:22 recur/week`

### Delete task: `deleteTask`

Expand Down Expand Up @@ -209,7 +213,7 @@ Examples:

### View reminders: `remind`

Shows the list of upcoming tasks (that are coming up in the next three days), such as the required
Shows the list of upcoming tasks (that are coming up in the next three days), such as the required
medical needs for those under the user's care.

Format: `remind`
Expand Down
21 changes: 13 additions & 8 deletions src/main/java/seedu/address/logic/commands/AddTaskCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_DATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_DESC;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_RECURRING;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_TIME;

import seedu.address.logic.commands.CommandResult.ListDisplayChange;
Expand All @@ -19,13 +20,18 @@ public class AddTaskCommand extends Command {

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a task to the address book. "
+ "Parameters: "
+ "[" + PREFIX_NAME + "NAME]...\n"
+ "Example: " + COMMAND_WORD
+ " " + PREFIX_NAME + "Khong Guan "
+ " " + PREFIX_NAME + "Swee Choon"
+ " " + PREFIX_TASK_DESC + "Scheduled 3rd Pfizer shot"
+ " " + PREFIX_TASK_DATE + "2021-10-10"
+ " " + PREFIX_TASK_TIME + "14:30";
+ "[" + PREFIX_NAME + "NAME]..."
+ PREFIX_TASK_DESC + "DESCRIPTION "
+ PREFIX_TASK_DATE + "DATE "
+ PREFIX_TASK_TIME + "TIME "
+ "[" + PREFIX_TASK_RECURRING + "RECURRENCE_TYPE]\n"
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_NAME + "Khong Guan "
+ PREFIX_NAME + "Swee Choon "
+ PREFIX_TASK_DESC + "Weekly Taiji "
+ PREFIX_TASK_DATE + "2021-10-10 "
+ PREFIX_TASK_TIME + "14:30 "
+ PREFIX_TASK_RECURRING + "week";

public static final String MESSAGE_SUCCESS = "New task added: %1$s";

Expand All @@ -42,7 +48,6 @@ public AddTaskCommand(Task t) {
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);

model.addTask(toAdd);
return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd), ListDisplayChange.TASK);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import seedu.address.logic.commands.CommandResult.ListDisplayChange;
import seedu.address.model.Model;

/**
* Lists all tasks in the address book to the user.
*/
public class ViewTasksCommand extends Command {
public static final String COMMAND_WORD = "viewTasks";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_DATE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_DESC;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_RECURRING;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TASK_TIME;

import java.util.Set;
Expand All @@ -14,6 +15,8 @@
import seedu.address.model.person.Name;
import seedu.address.model.task.DateTime;
import seedu.address.model.task.Description;
import seedu.address.model.task.Recurrence;
import seedu.address.model.task.Recurrence.RecurrenceType;
import seedu.address.model.task.Task;

/**
Expand All @@ -28,7 +31,8 @@ public class AddTaskCommandParser implements Parser<AddTaskCommand> {
*/
public AddTaskCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_TASK_DESC, PREFIX_TASK_DATE, PREFIX_TASK_TIME);
ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_TASK_DESC, PREFIX_TASK_DATE, PREFIX_TASK_TIME,
PREFIX_TASK_RECURRING);

if (!arePrefixesPresent(argMultimap, PREFIX_TASK_DESC, PREFIX_TASK_DATE, PREFIX_TASK_TIME)
|| !argMultimap.getPreamble().isEmpty()) {
Expand All @@ -40,8 +44,10 @@ public AddTaskCommand parse(String args) throws ParseException {
DateTime dateTime = ParserUtil.parseDateTime(
argMultimap.getValue(PREFIX_TASK_DATE).get(),
argMultimap.getValue(PREFIX_TASK_TIME).get());
Recurrence recurrence = ParserUtil.parseRecurrence(
argMultimap.getValue(PREFIX_TASK_RECURRING).orElse(RecurrenceType.NONE.name()));

Task task = new Task(description, dateTime, relatedNames);
Task task = new Task(description, dateTime, relatedNames, recurrence);

return new AddTaskCommand(task);
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/seedu/address/logic/parser/CliSyntax.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ public class CliSyntax {
public static final Prefix PREFIX_TASK_DESC = new Prefix("desc/");
public static final Prefix PREFIX_TASK_DATE = new Prefix("date/");
public static final Prefix PREFIX_TASK_TIME = new Prefix("time/");
public static final Prefix PREFIX_TASK_RECURRING = new Prefix("recur/");

}
20 changes: 18 additions & 2 deletions src/main/java/seedu/address/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import seedu.address.model.tag.Tag;
import seedu.address.model.task.DateTime;
import seedu.address.model.task.Description;
import seedu.address.model.task.Recurrence;

/**
* Contains utility methods used for parsing strings in the various *Parser classes.
Expand Down Expand Up @@ -232,10 +233,10 @@ public static Description parseDesc(String description) throws ParseException {
}

/**
* Parses a {@code String description} into an {@code Description}.
* Parses a {@code String date} and {@code String time} into an {@code DateTime}.
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the given {@code description} is invalid.
* @throws ParseException if the given {@code date} and {@code time} is invalid.
*/
public static DateTime parseDateTime(String date, String time) throws ParseException {
requireAllNonNull(date, time);
Expand All @@ -249,4 +250,19 @@ public static DateTime parseDateTime(String date, String time) throws ParseExcep
}
return new DateTime(trimmedDate, trimmedTime);
}

/**
* Parses a {@code String recurrenceType} into an {@code Recurrence}.
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the given {@code recurrenceType} is invalid.
*/
public static Recurrence parseRecurrence(String recurrenceType) throws ParseException {
requireNonNull(recurrenceType);
String trimmedRecurrenceType = recurrenceType.trim().toUpperCase();
if (!Recurrence.isValidRecurrence(trimmedRecurrenceType)) {
throw new ParseException(Recurrence.MESSAGE_CONSTRAINTS);
}
return new Recurrence(trimmedRecurrenceType);
}
}
1 change: 1 addition & 0 deletions src/main/java/seedu/address/model/AddressBook.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ public ObservableList<Elderly> getElderlyList() {

@Override
public ObservableList<Task> getTaskList() {
tasks.changeDateOfPastRecurringTasks();
return tasks.asUnmodifiableObservableList();
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/seedu/address/model/task/DateTime.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ public DateTime(String date, String time) {
}
}

/**
* Constructs an {@code DateTime}.
*
* @param date A valid date.
* @param time A valid time.
*/
public DateTime(LocalDate date, LocalTime time) {
this.date = date;
this.time = time;
}

/**
* Returns true if a given string is a valid date.
*/
Expand Down
76 changes: 76 additions & 0 deletions src/main/java/seedu/address/model/task/Recurrence.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package seedu.address.model.task;

import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;

import java.util.Objects;

/**
* Represents if a task is a recurring task in NurseyBook.
* Guarantees: immutable; is valid as declared in {@link #isValidRecurrence(String)}
*/
public class Recurrence {
public static final String MESSAGE_CONSTRAINTS = "Recurrence can only be of type day, week or month and "
+ "is case-insensitive. It cannot be null.";

/**
* The first character of the Description must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
public static final String VALIDATION_REGEX = "\\bNONE|DAY|WEEK|MONTH\\b";

private boolean isRecurring;

private RecurrenceType recurrenceType;

public enum RecurrenceType {
NONE, DAY, WEEK, MONTH
}

/**
* Constructs an {@code Recurrence}.
*
* @param recurrenceTypeStr A valid recurrence type.
*/
public Recurrence(String recurrenceTypeStr) {
requireNonNull(recurrenceTypeStr);
recurrenceTypeStr = recurrenceTypeStr.toUpperCase();
checkArgument(isValidRecurrence(recurrenceTypeStr), MESSAGE_CONSTRAINTS);
this.isRecurring = !recurrenceTypeStr.equals(RecurrenceType.NONE.name());
this.recurrenceType = RecurrenceType.valueOf(recurrenceTypeStr);
}

/**
* Returns true if a given string is a valid recurrence type.
*/
public static boolean isValidRecurrence(String test) {
return test.matches(VALIDATION_REGEX);
}

public boolean isRecurring() {
return isRecurring;
}

public RecurrenceType getRecurrenceType() {
return recurrenceType;
}

@Override
public String toString() {
return recurrenceType.name();
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof Recurrence // instanceof handles nulls
&& isRecurring == ((Recurrence) other).isRecurring) // both booleans are the same
&& recurrenceType.equals(((Recurrence) other).recurrenceType); // state check
}

@Override
public int hashCode() {
return Objects.hash(isRecurring, recurrenceType);
}

}
4 changes: 2 additions & 2 deletions src/main/java/seedu/address/model/task/Status.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ public class Status {
public static final String MESSAGE_CONSTRAINTS = "Status can take either 'true' or 'false' as its values and"
+ "is case-insensitive. It cannot be null.";

/*
/**
* The first character of the Description must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
public static final String VALIDATION_REGEX = "^(?i)(true|false)$";

/*
/**
* If a task is completed/done, isDone will be true. Else, it will be false.
*/
public final boolean isDone;
Expand Down
Loading

0 comments on commit f6c76a2

Please sign in to comment.