Skip to content

Commit

Permalink
Merge pull request #83 from jiakai-17/jiakai/implement-storage-tasks
Browse files Browse the repository at this point in the history
feat: Implement tasks storage
  • Loading branch information
m1oojv authored Oct 17, 2023
2 parents 2ba9bb7 + a3225f4 commit 6f8f906
Show file tree
Hide file tree
Showing 20 changed files with 648 additions and 7 deletions.
36 changes: 36 additions & 0 deletions src/main/java/seedu/address/model/AddressBook.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.person.Person;
import seedu.address.model.person.UniquePersonList;
import seedu.address.model.task.Task;
import seedu.address.model.task.UniqueTaskList;

/**
* Wraps all data at the address-book level
Expand All @@ -16,6 +18,7 @@
public class AddressBook implements ReadOnlyAddressBook {

private final UniquePersonList persons;
private final UniqueTaskList tasks;

/*
* The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
Expand All @@ -26,6 +29,7 @@ public class AddressBook implements ReadOnlyAddressBook {
*/
{
persons = new UniquePersonList();
tasks = new UniqueTaskList();
}

public AddressBook() {}
Expand All @@ -48,13 +52,22 @@ public void setPersons(List<Person> persons) {
this.persons.setPersons(persons);
}

/**
* Replaces the contents of the task list with {@code tasks}.
* {@code tasks} must not contain duplicate tasks.
*/
public void setTasks(List<Task> tasks) {
this.tasks.setTasks(tasks);
}

/**
* Resets the existing data of this {@code AddressBook} with {@code newData}.
*/
public void resetData(ReadOnlyAddressBook newData) {
requireNonNull(newData);

setPersons(newData.getPersonList());
setTasks(newData.getTaskList());
}

//// person-level operations
Expand Down Expand Up @@ -101,6 +114,24 @@ public void removeAllPerson() {
persons.removeAll();
}

//// task-level operations

/**
* Returns true if a task with the same identity as {@code task} exists in the address book.
*/
public boolean hasTask(Task task) {
requireNonNull(task);
return tasks.contains(task);
}

/**
* Adds a task to the address book.
* The task must not already exist in the address book.
*/
public void addTask(Task t) {
tasks.add(t);
}

//// util methods

@Override
Expand All @@ -115,6 +146,11 @@ public ObservableList<Person> getPersonList() {
return persons.asUnmodifiableObservableList();
}

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

@Override
public boolean equals(Object other) {
if (other == this) {
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/seedu/address/model/ReadOnlyAddressBook.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import javafx.collections.ObservableList;
import seedu.address.model.person.Person;
import seedu.address.model.task.Task;

/**
* Unmodifiable view of an address book
Expand All @@ -14,4 +15,10 @@ public interface ReadOnlyAddressBook {
*/
ObservableList<Person> getPersonList();

/**
* Returns an unmodifiable view of the tasks list.
* This list will not contain any duplicate tasks.
*/
ObservableList<Task> getTaskList();

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ public void removeAll() {
internalList.clear();
}

/**
* Replaces the contents of this list with another {@code UniquePersonList}.
* @param replacement the {@code UniquePersonList} to replace this list with.
*/
public void setPersons(UniquePersonList replacement) {
requireNonNull(replacement);
internalList.setAll(replacement.internalList);
Expand Down
153 changes: 153 additions & 0 deletions src/main/java/seedu/address/model/task/UniqueTaskList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package seedu.address.model.task;

import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;

import java.util.Iterator;
import java.util.List;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import seedu.address.model.task.exceptions.DuplicateTaskException;
import seedu.address.model.task.exceptions.TaskNotFoundException;

/**
* A list of tasks that enforces uniqueness between its elements and does not allow nulls.
* A task is considered unique by comparing using {@code Task#isSameTask(Task)}. As such, adding and updating
* of tasks uses Task#isSameTask(Task) for equality to ensure that the task being added or updated is
* unique in terms of identity in the UniqueTaskList. However, the removal of a task uses Task#equals(Object)
* to ensure that the task with exactly the same fields will be removed.
* Supports a minimal set of list operations.
*
* @see Task#isSameTask(Task)
*/
public class UniqueTaskList implements Iterable<Task> {

private final ObservableList<Task> internalList = FXCollections.observableArrayList();
private final ObservableList<Task> internalUnmodifiableList =
FXCollections.unmodifiableObservableList(internalList);

/**
* Returns true if the list contains an equivalent task as the given argument.
*/
public boolean contains(Task toCheck) {
requireNonNull(toCheck);
return internalList.stream().anyMatch(toCheck::isSameTask);
}

/**
* Adds a task to the list.
* The task must not already exist in the list.
*/
public void add(Task toAdd) {
requireNonNull(toAdd);
if (contains(toAdd)) {
throw new DuplicateTaskException();
}
internalList.add(toAdd);
}

/**
* Replaces the task {@code target} in the list with {@code editedTask}.
* {@code target} must exist in the list.
* The task identity of {@code editedTask} must not be the same as another existing task in the list.
*/
public void setTask(Task target, Task editedTask) {
requireAllNonNull(target, editedTask);

int index = internalList.indexOf(target);
if (index == -1) {
throw new TaskNotFoundException();
}

if (!target.isSameTask(editedTask) && contains(editedTask)) {
throw new DuplicateTaskException();
}

internalList.set(index, editedTask);
}

/**
* Removes the equivalent task from the list.
* The task must exist in the list.
*/
public void remove(Task toRemove) {
requireNonNull(toRemove);
if (!internalList.remove(toRemove)) {
throw new TaskNotFoundException();
}
}

/**
* Replaces the contents of this list with another {@code UniqueTaskList}.
* @param replacement the {@code UniqueTaskList} to replace this list with.
*/
public void setTasks(UniqueTaskList replacement) {
requireNonNull(replacement);
internalList.setAll(replacement.internalList);
}

/**
* Replaces the contents of this list with {@code tasks}.
* {@code tasks} must not contain duplicate tasks.
*/
public void setTasks(List<Task> tasks) {
requireAllNonNull(tasks);
if (!tasksAreUnique(tasks)) {
throw new DuplicateTaskException();
}

internalList.setAll(tasks);
}

/**
* Returns the backing list as an unmodifiable {@code ObservableList}.
*/
public ObservableList<Task> asUnmodifiableObservableList() {
return internalUnmodifiableList;
}

@Override
public Iterator<Task> iterator() {
return internalList.iterator();
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof UniqueTaskList)) {
return false;
}

UniqueTaskList otherUniqueTaskList = (UniqueTaskList) other;
return internalList.equals(otherUniqueTaskList.internalList);
}

@Override
public int hashCode() {
return internalList.hashCode();
}

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

/**
* Returns true if {@code tasks} contains only unique tasks.
*/
private boolean tasksAreUnique(List<Task> tasks) {
for (int i = 0; i < tasks.size() - 1; i++) {
for (int j = i + 1; j < tasks.size(); j++) {
if (tasks.get(i).isSameTask(tasks.get(j))) {
return false;
}
}
}
return true;
}
}
62 changes: 62 additions & 0 deletions src/main/java/seedu/address/storage/JsonAdaptedTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package seedu.address.storage;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.task.Note;
import seedu.address.model.task.Task;
import seedu.address.model.task.Title;

/**
* Jackson-friendly version of {@link Task}.
*/
class JsonAdaptedTask {

public static final String MISSING_FIELD_MESSAGE_FORMAT = "Task's %s field is missing!";

private final String title;
private final String note;

/**
* Constructs a {@code JsonAdaptedTask} with the given task details.
*/
@JsonCreator
public JsonAdaptedTask(@JsonProperty("title") String title, @JsonProperty("note") String note) {
this.title = title;
this.note = note;
}

/**
* Converts a given {@code Task} into this class for Jackson use.
*/
public JsonAdaptedTask(Task source) {
title = source.getTitle().value;
note = source.getNote().value;
}

/**
* Converts this Jackson-friendly adapted task object into the model's {@code Task} object.
*
* @throws IllegalValueException if there were any data constraints violated in the adapted task.
*/
public Task toModelType() throws IllegalValueException {
if (title == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Title.class.getSimpleName()));
}
if (!Title.isValidTitle(title)) {
throw new IllegalValueException(Title.MESSAGE_CONSTRAINTS);
}
final Title modelTitle = new Title(title);

if (note == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Note.class.getSimpleName()));
}
if (!Note.isValidNote(note)) {
throw new IllegalValueException(Note.MESSAGE_CONSTRAINTS);
}
final Note modelNote = new Note(note);

return new Task(modelTitle, modelNote);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import seedu.address.model.AddressBook;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.person.Person;
import seedu.address.model.task.Task;

/**
* An Immutable AddressBook that is serializable to JSON format.
Expand All @@ -20,15 +21,19 @@
class JsonSerializableAddressBook {

public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
public static final String MESSAGE_DUPLICATE_TASK = "Tasks list contains duplicate task(s).";

private final List<JsonAdaptedPerson> persons = new ArrayList<>();
private final List<JsonAdaptedTask> tasks = new ArrayList<>();

/**
* Constructs a {@code JsonSerializableAddressBook} with the given persons.
* Constructs a {@code JsonSerializableAddressBook} with the given persons and tasks.
*/
@JsonCreator
public JsonSerializableAddressBook(@JsonProperty("persons") List<JsonAdaptedPerson> persons) {
public JsonSerializableAddressBook(@JsonProperty("persons") List<JsonAdaptedPerson> persons,
@JsonProperty("tasks") List<JsonAdaptedTask> tasks) {
this.persons.addAll(persons);
this.tasks.addAll(tasks);
}

/**
Expand All @@ -38,6 +43,7 @@ public JsonSerializableAddressBook(@JsonProperty("persons") List<JsonAdaptedPers
*/
public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
tasks.addAll(source.getTaskList().stream().map(JsonAdaptedTask::new).collect(Collectors.toList()));
}

/**
Expand All @@ -54,6 +60,15 @@ public AddressBook toModelType() throws IllegalValueException {
}
addressBook.addPerson(person);
}

for (JsonAdaptedTask jsonAdaptedTask : tasks) {
Task task = jsonAdaptedTask.toModelType();
if (addressBook.hasTask(task)) {
throw new IllegalValueException(MESSAGE_DUPLICATE_TASK);
}
addressBook.addTask(task);
}

return addressBook;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"phone": "948asdf2424",
"email": "[email protected]",
"address": "4th street"
} ]
} ],
"tasks": []
}
Loading

0 comments on commit 6f8f906

Please sign in to comment.