diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 296d262..5bdb560 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -2,8 +2,9 @@
-
+
+
\ No newline at end of file
diff --git a/FEATURES.md b/FEATURES.md
index 3cff608..0a498f5 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -5,13 +5,14 @@
- Persistence
## Section 2: Headlining Features
-
+- Task Queue
+- Themes
+- Menu bar
## Section 3: Power Ups
-
-
-## Section 3: Power Ups
-
+- Quotes & Notes
+- Progress Bar
+- Sort By Name & Description
## Section 4: Quality of Life
diff --git a/PA05_UML_Diagram.drawio.png b/PA05_UML_Diagram.drawio.png
new file mode 100644
index 0000000..d3e84bd
Binary files /dev/null and b/PA05_UML_Diagram.drawio.png differ
diff --git a/README.md b/README.md
index 91646fe..b14fec4 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,28 @@
-# 3500 PA05 Project Repo
+Java Journal!
+This bullet journal program allows you to write and save task and events for a week.
+You can save these to a file for later. This journa also supports adding a limit for how many
+tasks you can have in a day. This is a great way to keep track of your tasks and events for the week!
-[PA Write Up](https://markefontenot.notion.site/PA-05-8263d28a81a7473d8372c6579abd6481)
+GUI:
+
+- https://ibb.co/Qk6m2nH
+
+SOLID Principles:
+
+- Single Responsibility Principle: Each class is only responsible for a single job in the bullet
+ journal.
+- Open/Closed Principle: The controller class and its supporting model classes are open for
+ extension but closed for modification. This is because the Journal class can be extended to
+ add more functionality, but the classes do not need to be modified to add more functionality.
+- Liskov Substitution Principle: This application makes use of an abstract "Commitment" class.
+ This allows for the use of the "Commitment" class to be used in place of its subclasses.
+- Interface Segregation Principle: Interfaces and classes in this BuJo project contain only the methods
+ that they require to function.
+- Dependency Inversion Principle: The controller class is injected with the Week that it displays.
+ This allows for the controller to be independent of the Week class.
+
+Possible Extensions:
+
+- With my "initButton" method in the controller class, we could add a popup that allows a user to
+ enter a quote to be saves on the main screen. This popup would save its data to the Week class,
+ where it would be persisted.
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 27b9ec9..73b1af5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -47,13 +47,14 @@ javafx {
dependencies {
// Jackson
- implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.15.1'
-
+ implementation("com.fasterxml.jackson.core:jackson-databind:2.15.0")
+
// JavaFX
implementation('org.controlsfx:controlsfx:11.1.2')
// JUnit
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
+ testImplementation 'junit:junit:4.13.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
// TestFX
diff --git a/pa05_sketch_sections123.png b/pa05_sketch_sections123.png
new file mode 100644
index 0000000..083e687
Binary files /dev/null and b/pa05_sketch_sections123.png differ
diff --git a/src/main/java/cs3500/pa05/Driver.java b/src/main/java/cs3500/pa05/Driver.java
new file mode 100644
index 0000000..7250a25
--- /dev/null
+++ b/src/main/java/cs3500/pa05/Driver.java
@@ -0,0 +1,52 @@
+package cs3500.pa05;
+
+import cs3500.pa05.controller.BujoController;
+import cs3500.pa05.model.Week;
+import cs3500.pa05.view.BujoView;
+import javafx.application.Application;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+/**
+ * Represents a Java Bullet Journal game application
+ */
+public class Driver extends Application {
+
+ /**
+ * Starts the GUI for a game of Java Bullet Journal and initialized the module,
+ * view and controller
+ *
+ * @param stage the JavaFX stage to add elements to
+ */
+ @Override
+ public void start(Stage stage) {
+ stage.setTitle("Bullet Journal!");
+
+ // instantiate a simple welcome GUI view
+ Week week = new Week();
+ BujoController controller = new BujoController(week, stage);
+ BujoView view = new BujoView(controller);
+
+ try {
+ // load and place the view's scene onto the stage
+ Scene scene = view.load();
+ stage.setScene(scene);
+
+ controller.run();
+
+ // render the stage
+ stage.show();
+ } catch (IllegalStateException exc) {
+ System.err.println("Unable to load GUI.");
+ }
+ }
+
+ /**
+ * Entry point for a game of Java Bullet Journal
+ *
+ * @param args the command line arguments (unused)
+ */
+ public static void main(String[] args) {
+ launch();
+ }
+}
diff --git a/src/main/java/cs3500/pa05/controller/BujoController.java b/src/main/java/cs3500/pa05/controller/BujoController.java
new file mode 100644
index 0000000..b1e68fd
--- /dev/null
+++ b/src/main/java/cs3500/pa05/controller/BujoController.java
@@ -0,0 +1,388 @@
+package cs3500.pa05.controller;
+
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import cs3500.pa05.model.BujoFileWriter;
+import cs3500.pa05.model.Day;
+import cs3500.pa05.model.Event;
+import cs3500.pa05.model.Task;
+import cs3500.pa05.model.Time;
+import cs3500.pa05.model.Week;
+import cs3500.pa05.model.WeekJson;
+import cs3500.pa05.view.BujoView;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Scanner;
+import javafx.fxml.FXML;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.MenuButton;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.VBox;
+import javafx.stage.Popup;
+import javafx.stage.Stage;
+
+/**
+ * Represents a controller for a Java Bullet Journal
+ */
+public class BujoController {
+ private Week week;
+
+ private final Stage stage;
+
+ @FXML
+ private Button taskButton;
+
+ @FXML
+ private Button eventButton;
+
+ @FXML
+ private Button openButton;
+
+ @FXML
+ private Button saveButton;
+
+ @FXML
+ private TextField monthField;
+
+ @FXML
+ private TextField weekOfField;
+
+ @FXML
+ private MenuButton dayTaskBar;
+
+ @FXML
+ private TextField nameTextField;
+
+ @FXML
+ private TextField descriptionTextField;
+
+ @FXML
+ private VBox monday;
+
+ @FXML
+ private VBox tuesday;
+
+ @FXML
+ private VBox wednesday;
+
+ @FXML
+ private VBox thursday;
+
+ @FXML
+ private VBox friday;
+
+ @FXML
+ private VBox saturday;
+
+ @FXML
+ private VBox sunday;
+
+ @FXML
+ private TextField eventNameTextField;
+
+ @FXML
+ private TextField eventDescriptionTextField;
+
+ @FXML
+ private TextField eventStartTimeField;
+
+ @FXML
+ private TextField eventDurationField;
+
+ @FXML
+ private TextField eventDayField;
+
+ @FXML
+ private TextField taskDayField;
+
+ @FXML
+ private TextField commitEventField;
+
+ @FXML
+ private TextField commitTaskField;
+
+ private Popup warningPopup;
+
+ private String taskName;
+
+ private String taskDescription;
+
+ private String eventName;
+
+ private String eventDescription;
+
+ private String eventStartTime;
+
+ private String eventDuration;
+
+ private String taskDay;
+
+ private String eventDay;
+
+ private String openFilePath;
+
+ private String saveFilePath;
+
+ @FXML
+ private TextField savePath;
+
+ @FXML
+ private TextField loadPath;
+
+
+ /**
+ * Initializes a controller for a Java Bullet Journal.
+ *
+ * @param week the week to be displayed
+ * @param stage the stage to be displayed on
+ */
+ public BujoController(Week week, Stage stage) {
+ this.week = week;
+ this.stage = stage;
+ }
+
+ /**
+ * Initializes a game of Java Bullet Journal.
+ */
+ public void run() {
+
+ this.warningPopup = new Popup();
+ Scene warningScene = new BujoView(this).loadWarn();
+
+ warningPopup.getContent().add(warningScene.getRoot());
+ Button b = new Button("Done!");
+ b.setOnAction(e -> warningPopup.hide());
+
+ warningPopup.getContent().add(b);
+
+ this.commitEventField.setOnKeyTyped(event -> this.week.setMaxEvents(Integer.parseInt(
+ this.commitEventField.getText())));
+ this.commitTaskField.setOnKeyTyped(event -> this.week.setMaxTasks(Integer.parseInt(
+ this.commitTaskField.getText())));
+
+ Popup taskPopup = new Popup();
+ Scene taskScene = new BujoView(this).loadTask();
+ initPopupButton(this.taskButton, taskPopup, taskScene);
+
+ this.nameTextField.setOnKeyTyped(
+ event -> this.taskName = this.nameTextField.getText());
+ this.descriptionTextField.setOnKeyTyped(
+ event -> this.taskDescription = this.descriptionTextField.getText());
+ this.taskDayField.setOnKeyTyped(event -> this.taskDay = this.taskDayField.getText());
+
+ Popup eventPopup = new Popup();
+ Scene eventScene = new BujoView(this).loadEvent();
+ initPopupButton(this.eventButton, eventPopup, eventScene);
+ this.eventNameTextField.setOnKeyTyped(
+ event -> this.eventName = this.eventNameTextField.getText());
+ this.eventDescriptionTextField.setOnKeyTyped(
+ event -> this.eventDescription = this.eventDescriptionTextField.getText());
+ this.eventStartTimeField.setOnKeyTyped(
+ event -> this.eventStartTime = this.eventStartTimeField.getText());
+ this.eventDurationField.setOnKeyTyped(event -> this.eventDuration = this.eventDurationField
+ .getText());
+ this.eventDayField.setOnKeyTyped(event -> this.eventDay = this.eventDayField.getText());
+
+
+ Popup loadFilePopup = new Popup();
+ Scene openFileScene = new BujoView(this).loadOpen();
+ this.loadPath.setOnKeyTyped(event -> this.openFilePath = this.loadPath.getText());
+
+ initPopupButton(this.openButton, loadFilePopup, openFileScene);
+
+ Popup saveFilePopup = new Popup();
+ Scene saveFileScene = new BujoView(this).loadSave();
+ this.savePath.setOnKeyTyped(event -> this.saveFilePath = this.savePath.getText());
+
+ initPopupButton(this.saveButton, saveFilePopup, saveFileScene);
+
+ this.monthField.setText(this.week.getMonth());
+ this.monthField.setOnAction(event -> this.week.setMonth(this.monthField.getText()));
+
+ this.weekOfField.setText(this.week.getWeekOf());
+ this.weekOfField.setOnAction(event -> this.week.setMonth(this.monthField.getText()));
+
+
+ }
+
+ /**
+ * Loads a selected .bujo file into a Java Bullet Journal.
+ */
+ private void loadFile(String filename) {
+ StringBuilder file = new StringBuilder();
+ Scanner scanner = null;
+ try {
+ scanner = new Scanner(Path.of(filename));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ file.append(line);
+ }
+
+ scanner.close();
+
+ try {
+ JsonNode json = new ObjectMapper().readTree(file.toString());
+
+ WeekJson weekJson = new ObjectMapper().convertValue(json, WeekJson.class);
+
+ this.week = weekJson.toWeek();
+
+ this.commitEventField.setText(Integer.toString(this.week.getMaxEvents()));
+ this.commitTaskField.setText(Integer.toString(this.week.getMaxTasks()));
+
+ this.monthField.setText(this.week.getMonth());
+ this.weekOfField.setText(this.week.getWeekOf());
+
+ for (Day day : this.week.getDays()) {
+ populateDay(day);
+ }
+
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void populateDay(Day day) {
+ for (Event event : day.getEvents()) {
+ Label eventLabel = new Label(event.toString());
+ getVbox(day.getName()).getChildren().add(eventLabel);
+ }
+
+ for (Task task : day.getTasks()) {
+ Label taskLabel = new Label(task.toString());
+ taskLabel.setOnMouseClicked(event -> handleLabelClick(taskLabel, task));
+ getVbox(day.getName()).getChildren().add(taskLabel);
+ }
+ }
+
+ /**
+ * Saves a Java Bullet Journal to a .bujo file.
+ */
+ private void saveFile(String filename) {
+ BujoFileWriter.writeBujo(this.week, filename);
+ }
+
+ /**
+ * Adds a task to a Java Bullet Journal.
+ */
+ private void addTaskFromPopup() {
+ Day day = this.week.getDays()[Day.getDayIndex(this.taskDay)];
+
+ if (day.getTasks().size() >= this.week.getMaxTasks()) {
+ this.warningPopup.show(this.stage);
+ }
+
+ Task task = new Task(this.taskName, this.taskDescription, day.getName());
+ day.addTask(task);
+
+ Label taskLabel = new Label(task.toString());
+ taskLabel.setOnMouseClicked(event -> handleLabelClick(taskLabel, task));
+ getVbox(this.taskDay).getChildren().add(taskLabel);
+ }
+
+ /**
+ * Adds a task to a Java Bullet Journal.
+ */
+ private void addEventFromPopup() {
+
+ Day day = this.week.getDays()[Day.getDayIndex(this.eventDay)];
+
+ if (day.getEvents().size() >= this.week.getMaxEvents()) {
+ this.warningPopup.show(this.stage);
+ }
+
+ int hour = Integer.parseInt(this.eventStartTime.split(":")[0]);
+ int minute = Integer.parseInt(this.eventStartTime.split(":")[1]);
+
+ Event event =
+ new Event(this.eventName, this.eventDescription, day.getName(), new Time(hour, minute),
+ Integer.parseInt(this.eventDuration));
+ day.addEvent(event);
+
+ Label eventLabel = new Label(event.toString());
+ getVbox(this.eventDay).getChildren().add(eventLabel);
+ }
+
+ /**
+ * Handles clicking a task label in a Java Bullet Journal.
+ */
+ private void handleLabelClick(Label taskLabel, Task task) {
+ task.setComplete(!task.isComplete());
+ taskLabel.setText(task.toString());
+ }
+
+ /**
+ * Returns the correct VBox for a given string
+ *
+ * @param day the string representing the day
+ * @return the correct VBox
+ */
+ private VBox getVbox(String day) {
+ switch (day.toLowerCase()) {
+ case "monday":
+ return this.monday;
+ case "tuesday":
+ return this.tuesday;
+ case "wednesday":
+ return this.wednesday;
+ case "thursday":
+ return this.thursday;
+ case "friday":
+ return this.friday;
+ case "saturday":
+ return this.saturday;
+ case "sunday":
+ return this.sunday;
+ default:
+ throw new IllegalArgumentException("No such day");
+ }
+ }
+
+ /**
+ * Initializes the task button in a Java Bullet Journal.
+ */
+ private void initPopupButton(Button button, Popup popup, Scene s) {
+ button.setOnAction(event -> showPopup(popup));
+
+ popup.getContent().add(s.getRoot());
+
+ Button b = new Button("Done!");
+ b.setOnAction(e -> popup.hide());
+
+ popup.getContent().add(b);
+ popup.setOnHidden(e -> handleHiddenPopup(button));
+ }
+
+ /**
+ * Handles a hidden popup in a Java Bullet Journal.
+ */
+ private void handleHiddenPopup(Button button) {
+ if (button == this.taskButton) {
+ addTaskFromPopup();
+ }
+ if (button == this.eventButton) {
+ addEventFromPopup();
+ }
+ if (button == this.openButton) {
+ loadFile(this.openFilePath);
+ }
+ if (button == this.saveButton) {
+ saveFile(this.saveFilePath);
+ }
+ }
+
+ /**
+ * Shows a dialog for a task in a Java Bullet Journal.
+ */
+ private void showPopup(Popup popup) {
+ popup.show(this.stage);
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/BujoFileWriter.java b/src/main/java/cs3500/pa05/model/BujoFileWriter.java
new file mode 100644
index 0000000..94dea3f
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/BujoFileWriter.java
@@ -0,0 +1,68 @@
+package cs3500.pa05.model;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * A class that contains methods to write a Bullet Journal to a file.
+ */
+public class BujoFileWriter {
+ /**
+ * Writes a Bullet Journal to a file.
+ *
+ * @param week the week to write
+ * @param path the path to write to
+ */
+ public static void writeBujo(Week week, String path) {
+ try {
+ FileWriter myWriter = new FileWriter(path);
+ myWriter.write(weekToJson(week).toString());
+ myWriter.close();
+ } catch (IOException e) {
+ // write failed
+ }
+ }
+
+ /**
+ * Converts a week to a JsonNode.
+ *
+ * @param week the week to convert
+ * @return the JsonNode representing the week
+ */
+ public static JsonNode weekToJson(Week week) {
+ DayJson[] dayJsons = new DayJson[7];
+ Day[] days = week.getDays();
+ for (int i = 0; i < 7; i++) {
+ dayJsons[i] = dayToJson(days[i]);
+ }
+ WeekJson weekJson = new WeekJson(dayJsons, week.getMaxTasks(), week.getMaxEvents(),
+ week.getTheme().toString(), week.getMonth(), week.getWeekOf());
+ return JsonUtils.serializeRecord(weekJson);
+ }
+
+ /**
+ * Converts a day to a JsonNode.
+ *
+ * @param day the day to convert
+ * @return the JsonNode representing the day
+ */
+ public static DayJson dayToJson(Day day) {
+ TaskJson[] tasks = new TaskJson[day.getTasks().size()];
+ EventJson[] events = new EventJson[day.getEvents().size()];
+
+ for (Task task : day.getTasks()) {
+ tasks[day.getTasks().indexOf(task)] = new TaskJson(task.getName(), task.getDescription(),
+ task.getDay(), task.isComplete());
+ }
+
+ for (Event event : day.getEvents()) {
+ events[day.getEvents().indexOf(event)] = new EventJson(event.getName(),
+ event.getDescription(), event.getDay(),
+ new TimeJson(event.getStartTime().getHour(), event.getStartTime().getMinute()),
+ event.getDuration());
+ }
+
+ return new DayJson(day.getName(), tasks, events);
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/Commitment.java b/src/main/java/cs3500/pa05/model/Commitment.java
new file mode 100644
index 0000000..f2c279c
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/Commitment.java
@@ -0,0 +1,62 @@
+package cs3500.pa05.model;
+
+/**
+ * Represents a commitment in a day.
+ */
+public abstract class Commitment {
+
+ /**
+ * represents the name
+ */
+ public String name;
+
+ /**
+ * represents the description
+ */
+ public String description;
+
+ /**
+ * represents a day
+ */
+ public String day;
+
+ /**
+ * Constructs a commitment with the given name, description, and day.
+ *
+ * @param name the commitment's name
+ * @param description the commitment's description
+ * @param day the day of the commitment
+ */
+ public Commitment(String name, String description, String day) {
+ this.name = name;
+ this.description = description;
+ this.day = day;
+ }
+
+ /**
+ * Returns the name of this commitment.
+ *
+ * @return the name of this commitment
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the description of this commitment.
+ *
+ * @return the description of this commitment
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Returns the day of this commitment.
+ *
+ * @return the day of this commitment
+ */
+ public String getDay() {
+ return this.day;
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/Day.java b/src/main/java/cs3500/pa05/model/Day.java
new file mode 100644
index 0000000..13d5b00
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/Day.java
@@ -0,0 +1,89 @@
+package cs3500.pa05.model;
+
+import java.util.ArrayList;
+
+/**
+ * Represents a day in a week.
+ */
+public class Day {
+ private final String name;
+
+ private final ArrayList tasks;
+
+ private final ArrayList events;
+
+ /**
+ * Constructs a day with the given name.
+ *
+ * @param name the day's name
+ */
+ public Day(String name) {
+ this.name = name;
+ this.tasks = new ArrayList<>();
+ this.events = new ArrayList<>();
+ }
+
+ /**
+ * Returns the name of this day
+ *
+ * @return the name of this day
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns this day's tasks.
+ *
+ * @return this day's tasks
+ */
+ public ArrayList getTasks() {
+ return this.tasks;
+ }
+
+ /**
+ * Returns this day's events.
+ *
+ * @return this day's events
+ */
+ public ArrayList getEvents() {
+ return this.events;
+ }
+
+ /**
+ * Returns the index of this day given its name
+ *
+ * @param name of the day
+ * @return the index of this day given its name
+ */
+ public static int getDayIndex(String name) {
+ return switch (name.toLowerCase()) {
+ case "monday" -> 0;
+ case "tuesday" -> 1;
+ case "wednesday" -> 2;
+ case "thursday" -> 3;
+ case "friday" -> 4;
+ case "saturday" -> 5;
+ case "sunday" -> 6;
+ default -> throw new IllegalArgumentException("No such day");
+ };
+ }
+
+ /**
+ * Adds a task to this day
+ *
+ * @param task the task
+ */
+ public void addTask(Task task) {
+ this.tasks.add(task);
+ }
+
+ /**
+ * Adds an event to this day
+ *
+ * @param event the event
+ */
+ public void addEvent(Event event) {
+ this.events.add(event);
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/DayJson.java b/src/main/java/cs3500/pa05/model/DayJson.java
new file mode 100644
index 0000000..346bc9a
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/DayJson.java
@@ -0,0 +1,26 @@
+package cs3500.pa05.model;
+
+import cs3500.pa05.model.Event;
+import cs3500.pa05.model.Task;
+
+/**
+ * Represents a Json view of a day.
+ */
+public record DayJson(String name, TaskJson[] tasks, EventJson[] events) {
+
+ /**
+ * Returns the day represented by this Json
+ *
+ * @return the day represented by this Json
+ */
+ public Day toDay() {
+ Day day = new Day(this.name);
+ for (TaskJson task : this.tasks) {
+ day.addTask(task.toTask());
+ }
+ for (EventJson event : this.events) {
+ day.addEvent(event.toEvent());
+ }
+ return day;
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/Event.java b/src/main/java/cs3500/pa05/model/Event.java
new file mode 100644
index 0000000..eb0f548
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/Event.java
@@ -0,0 +1,60 @@
+package cs3500.pa05.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents in an event in a day.
+ */
+public class Event extends Commitment {
+
+ private final Time startTime;
+
+ // Duration in minutes
+ private final int duration;
+
+ /**
+ * Constructs an event with the given name, description, day, start time, and duration.
+ *
+ * @param name the event's name
+ * @param description the event's description
+ * @param day the day of the event
+ * @param startTime the start time of the event
+ * @param duration the duration of the event
+ */
+ public Event(@JsonProperty("name") String name, @JsonProperty("description") String description,
+ @JsonProperty("day") String day, @JsonProperty("start-time") Time startTime,
+ @JsonProperty("duration") int duration) {
+ super(name, description, day);
+ this.startTime = startTime;
+ this.duration = duration;
+ }
+
+ /**
+ * Returns a string representation of the data stored by this Event object.
+ *
+ * @return a string representation of the data stored by this Event object
+ */
+ @Override
+ public String toString() {
+ return this.getName() + "\n" + this.getDescription() + "\n" + this.startTime.toString() + "\n"
+ + this.duration;
+ }
+
+ /**
+ * getter method for this startTime
+ *
+ * @return a Time object representing the start time of this event
+ */
+ public Time getStartTime() {
+ return startTime;
+ }
+
+ /**
+ * Returns the duration of this Event
+ *
+ * @return the duration of this Event
+ */
+ public int getDuration() {
+ return duration;
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/EventJson.java b/src/main/java/cs3500/pa05/model/EventJson.java
new file mode 100644
index 0000000..5f65297
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/EventJson.java
@@ -0,0 +1,25 @@
+package cs3500.pa05.model;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents a Json view of an Event
+ *
+ * @param name the name of the event
+ * @param description the description of the event
+ * @param day the day of the event
+ * @param time the time of the event
+ * @param duration the duration of the event
+ */
+public record EventJson(
+ @JsonProperty("name") String name,
+ @JsonProperty("description") String description,
+ @JsonProperty("day") String day,
+ @JsonProperty("start-time") TimeJson time,
+ @JsonProperty("duration") int duration) {
+
+ public Event toEvent() {
+ return new Event(name, description, day, time.toTime(), duration);
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/JsonUtils.java b/src/main/java/cs3500/pa05/model/JsonUtils.java
new file mode 100644
index 0000000..2b6455c
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/JsonUtils.java
@@ -0,0 +1,26 @@
+package cs3500.pa05.model;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Simple utils class used to hold static methods that help with serializing and deserializing JSON.
+ */
+public class JsonUtils {
+ /**
+ * Converts a given record object to a JsonNode.
+ *
+ * @param record the record to convert
+ * @return the JsonNode representation of the given record
+ * @throws IllegalArgumentException if the record could not be converted correctly
+ */
+ public static JsonNode serializeRecord(Record record) throws IllegalArgumentException {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ return mapper.convertValue(record, JsonNode.class);
+ } catch (IllegalArgumentException e) {
+ System.out.println(e);
+ throw new IllegalArgumentException("Given record cannot be serialized");
+ }
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/Task.java b/src/main/java/cs3500/pa05/model/Task.java
new file mode 100644
index 0000000..e453b7a
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/Task.java
@@ -0,0 +1,51 @@
+package cs3500.pa05.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents a task in a day.
+ */
+public class Task extends Commitment {
+
+ private boolean complete = false;
+
+ /**
+ * Constructs a task with the given name, description, and day.
+ *
+ * @param name the task's name
+ * @param description the task's description
+ * @param day the day of the task
+ */
+ public Task(@JsonProperty("name") String name, @JsonProperty("description") String description,
+ @JsonProperty("day") String day) {
+ super(name, description, day);
+ }
+
+ /**
+ * Returns a string representation of the data stored by this Task object.
+ *
+ * @return a string representation of the data stored by this Task object
+ */
+ @Override
+ public String toString() {
+ return this.getName() + "\n" + this.getDescription() + (this.complete ? "[COMPLETE]}" : "");
+ }
+
+ /**
+ * Returns the value of this task's completed status.
+ *
+ * @return the value of this task's completed status
+ */
+ public boolean isComplete() {
+ return this.complete;
+ }
+
+ /**
+ * Sets the value of this Task object's complete field to the given value.
+ *
+ * @param complete weather this task is complete
+ */
+ public void setComplete(boolean complete) {
+ this.complete = complete;
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/TaskJson.java b/src/main/java/cs3500/pa05/model/TaskJson.java
new file mode 100644
index 0000000..785cfda
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/TaskJson.java
@@ -0,0 +1,22 @@
+package cs3500.pa05.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents a Json view of a Task
+ *
+ * @param name the name of the task
+ * @param description the description of the task
+ * @param day the day of the task
+ * @param complete whether the task is complete
+ */
+public record TaskJson(
+ @JsonProperty("name") String name,
+ @JsonProperty("description") String description,
+ @JsonProperty("day") String day,
+ @JsonProperty("complete") boolean complete) {
+
+ public Task toTask() {
+ return new Task(name, description, day);
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/Theme.java b/src/main/java/cs3500/pa05/model/Theme.java
new file mode 100644
index 0000000..c450e58
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/Theme.java
@@ -0,0 +1,39 @@
+package cs3500.pa05.model;
+
+
+/**
+ * Represents a theme of a BuJo
+ */
+public enum Theme {
+ DEFAULT,
+ DARK,
+ COLORFUL;
+
+ /**
+ * Returns the string representation of this theme.
+ *
+ * @return the string representation of this theme
+ */
+ public String toString() {
+ return switch (this) {
+ case DEFAULT -> "DEFAULT";
+ case DARK -> "DARK";
+ case COLORFUL -> "COLORFUL";
+ };
+ }
+
+ /**
+ * Returns the theme represented by the given string.
+ *
+ * @param s the string representation of the theme
+ * @return the theme represented by the given string
+ */
+ public static Theme fromString(String s) {
+ return switch (s) {
+ case "DEFAULT" -> DEFAULT;
+ case "DARK" -> DARK;
+ case "COLORFUL" -> COLORFUL;
+ default -> throw new IllegalArgumentException("Invalid theme");
+ };
+ }
+}
diff --git a/src/main/java/cs3500/pa05/model/Time.java b/src/main/java/cs3500/pa05/model/Time.java
new file mode 100644
index 0000000..838bdfa
--- /dev/null
+++ b/src/main/java/cs3500/pa05/model/Time.java
@@ -0,0 +1,55 @@
+package cs3500.pa05.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents a time in a day.
+ */
+public class Time implements Comparable