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

[Seng Zhen Hong] iP #468

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
55f9f9f
docs/README.md: Tweak document template
Jan 7, 2024
f837ddb
Add Gradle support
May 24, 2020
a6f7324
Bump gradle and lib version
Eclipse-Dominator Aug 5, 2023
b2a586c
Initial implementation of CharmBot with greeting and exit
Jan 31, 2024
943d23f
Enhance Charmbot to echo user commands and exit on bye
Jan 31, 2024
0744083
Add text storage and display functionality to CharmBot
Jan 31, 2024
3788eb8
Added mark and unmark functionality to Charmbot
IamZhenHong Feb 5, 2024
0e044fd
Added Todos,Events,Deadlines tracking for CharmBot
IamZhenHong Feb 5, 2024
b8eff85
Added Automated Test UI Testing
IamZhenHong Feb 5, 2024
b9b266d
Added exceptions to handle input errors
IamZhenHong Feb 5, 2024
ac52d32
Added error handling functionality to CharmBot
IamZhenHong Feb 6, 2024
a229714
Added support for deleting tasks from list
IamZhenHong Feb 6, 2024
be64ce0
Enabling saving and loading data with hard disk
IamZhenHong Feb 7, 2024
7fa2323
Merge branch 'branch-Level-7df into main
IamZhenHong Feb 7, 2024
0855b3d
Added date and time to task objects
IamZhenHong Feb 8, 2024
1eec1b6
Made the code more OOP
IamZhenHong Feb 13, 2024
0e069f1
Divided classes into packages
IamZhenHong Feb 13, 2024
458a7bc
Merge branch 'add-gradle-support'
IamZhenHong Feb 14, 2024
a850dc8
Set up gradle
IamZhenHong Feb 14, 2024
d062dc1
Added JUnit test for Ui and Task
IamZhenHong Feb 14, 2024
7db053c
Package app as jar file
IamZhenHong Feb 14, 2024
48a711e
Added JavaDoc commments
IamZhenHong Feb 14, 2024
27951d6
Added find function
IamZhenHong Feb 14, 2024
ae1320a
Added checkstyle
IamZhenHong Feb 15, 2024
7d94a89
Added GUI
IamZhenHong Feb 22, 2024
0d04ccd
Add assertion to ensure non-empty array in parseCommand method
IamZhenHong Feb 22, 2024
57fc714
Merge pull request #2 from IamZhenHong/branch-A-Assertions
IamZhenHong Feb 22, 2024
f827e1c
Improved code quality
IamZhenHong Feb 22, 2024
a5202ae
Merge pull request #3 from IamZhenHong/branch-A-CodeQuality
IamZhenHong Feb 22, 2024
cef5727
Improved GUI
IamZhenHong Feb 23, 2024
5576363
Merge pull request #4 from IamZhenHong/GUI
IamZhenHong Feb 23, 2024
e1e239e
Update README.md
IamZhenHong Feb 23, 2024
940e034
Update README.md
IamZhenHong Feb 23, 2024
ada747a
Update README.md
IamZhenHong Feb 23, 2024
a584e66
Added Ui.png
IamZhenHong Feb 25, 2024
130a9ea
Merge branch 'master' of github.com:IamZhenHong/ip
IamZhenHong Feb 25, 2024
c71765f
Update README.md
IamZhenHong Feb 25, 2024
981ea66
Added welcome message
IamZhenHong Feb 25, 2024
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
2 changes: 2 additions & 0 deletions duke.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
D | 0 | a | 1100
D | 0 | a | 1100
Binary file added src/main/java/DeadlineTask.class
Binary file not shown.
Binary file added src/main/java/Duke.class
Binary file not shown.
281 changes: 277 additions & 4 deletions src/main/java/Duke.java
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good naming of functions and variables and all in all LGTM but just some minor nits

Original file line number Diff line number Diff line change
@@ -1,10 +1,283 @@
import java.io.File;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can consider ordering imports in lexical order

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

class DukeException extends Exception {
public DukeException(String message) {
super(message);
}
}

public class Duke {
private static final String FILE_PATH = "duke.txt";
private static ArrayList<Task> tasks;
public Duke() {
tasks = loadTasksFromFile();
}

public static void main(String[] args) {
Duke duke = new Duke();
String logo = " ____ _ \n"
+ "| _ \\ _ _| | _____ \n"
+ "| | | | | | | |/ / _ \\\n"
+ "| |_| | |_| | < __/\n"
+ "|____/ \\__,_|_|\\_\\___|\n";
+ "| _ \\ _ _| | _____ \n"
+ "| | | | | | | |/ / _ \\\n"
+ "| |_| | |_| | < __/\n"
+ "|____/ \\__,_|_|\\_\\___|\n";
System.out.println("Hello from\n" + logo);
System.out.println("____________________________________________________________");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can consider making linebreaks into a constant variable which can make code cleaner

System.out.println("Hello! I'm CharmBot ");
System.out.println("What can I do for you?");
System.out.println("____________________________________________________________");

Scanner scanner = new Scanner(System.in);
String command = scanner.nextLine();
// Initialize tasks list here

while (!command.equals("bye")) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can consider breaking down this function into smaller functions to make it more readable for others, might be a little too long currently. Can break down into like two functions like run and commands

System.out.println("____________________________________________________________");
try {
if (command.equals("list")) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code seems to be too long for me. Try to divide each commands into different functions.

if (tasks.isEmpty()) {
System.out.println("You have no tasks in your list.");
} else {
System.out.println("Here are the tasks in your list:");
for (int i = 0; i < tasks.size(); i++) {
System.out.println((i + 1) + "." + tasks.get(i));
}
}
} else if (command.startsWith("mark")) {
int taskIndex = Integer.parseInt(command.split(" ")[1]) - 1;
if (taskIndex < 0 || taskIndex >= tasks.size()) {
throw new DukeException("Invalid task index.");
}
tasks.get(taskIndex).markAsDone();
System.out.println("Nice! I've marked this task as done:");
System.out.println(tasks.get(taskIndex));
} else if (command.startsWith("unmark")) {
int taskIndex = Integer.parseInt(command.split(" ")[1]) - 1;
if (taskIndex < 0 || taskIndex >= tasks.size()) {
throw new DukeException("Invalid task index.");
}
tasks.get(taskIndex).markAsNotDone();
System.out.println("OK, I've marked this task as not done yet:");
System.out.println(tasks.get(taskIndex));
} else if (command.startsWith("delete")) {
int taskIndex = Integer.parseInt(command.split(" ")[1]) - 1;
if (taskIndex < 0 || taskIndex >= tasks.size()) {
throw new DukeException("Invalid task index.");
}
Task deletedTask = tasks.remove(taskIndex);
System.out.println("Noted. I've removed this task:");
System.out.println(" " + deletedTask);
System.out.println("Now you have " + tasks.size() + " tasks in the list.");
} else {
if (command.startsWith("todo")) {
String description = command.substring(5).trim();
if (description.isEmpty()) {
throw new DukeException("The description of a todo cannot be empty.");
}
tasks.add(new ToDoTask(description));
System.out.println("Got it. I've added this task:");
System.out.println(tasks.get(tasks.size() - 1));
System.out.println("Now you have " + tasks.size() + " tasks in the list.");
} else if (command.startsWith("deadline ")) {
String[] parts = command.substring(9).split("/by");
if (parts.length != 2 || parts[0].trim().isEmpty() || parts[1].trim().isEmpty()) {
throw new DukeException("Invalid command format. Please use 'deadline <description> /by <time in hhmm format>'. For example, 'deadline Finish project /by 1800'.");
}
String description = parts[0].trim();
String by = parts[1].trim();
LocalTime byTime = LocalTime.parse(by, DateTimeFormatter.ofPattern("HHmm"));
tasks.add(new DeadlineTask(description, byTime));
System.out.println("Got it. I've added this task:");
System.out.println(tasks.get(tasks.size() - 1));
System.out.println("Now you have " + tasks.size() + " tasks in the list.");
} else if (command.startsWith("event ")) {
String[] parts = command.substring(6).split("/from");
if (parts.length != 2 || parts[0].trim().isEmpty() || parts[1].trim().isEmpty()) {
throw new DukeException("Invalid command format. Please use 'event <description> /from <start time> /to <end time>'.");
}
String description = parts[0].trim();
String[] eventParts = parts[1].split("/to");
if (eventParts.length != 2 || eventParts[0].trim().isEmpty() || eventParts[1].trim().isEmpty()) {
throw new DukeException("Invalid command format. Please use 'event <description> /from <start time> /to <end time>'.");
}
String from = eventParts[0].trim();
String to = eventParts[1].trim();
LocalTime startTime = LocalTime.parse(from, DateTimeFormatter.ofPattern("HHmm"));
LocalTime endTime = LocalTime.parse(to, DateTimeFormatter.ofPattern("HHmm"));
tasks.add(new EventTask(description, startTime, endTime));
System.out.println("Got it. I've added this task:");
System.out.println(tasks.get(tasks.size() - 1));
System.out.println("Now you have " + tasks.size() + " tasks in the list.");
} else {
throw new DukeException("I'm sorry, but I don't know what that means :-(");
}
}
} catch (NumberFormatException e) {
System.out.println("Invalid command format. Please provide a valid task index.");
} catch (DukeException e) {
System.out.println("____________________________________________________________");
System.out.println("OOPS!!! " + e.getMessage());
System.out.println("____________________________________________________________");
}
System.out.println("____________________________________________________________");
command = scanner.nextLine();
}
duke.saveTasksToFile(tasks);

System.out.println("____________________________________________________________");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe consider connecting this three println statements using +.

System.out.println("Bye. Hope to see you again soon!");
System.out.println("____________________________________________________________");
}


private ArrayList<Task> loadTasksFromFile() {
ArrayList<Task> tasks = new ArrayList<>();
try {
File file = new File(FILE_PATH);
if (!file.exists()) {
file.createNewFile();
} else {
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
Task task = parseTaskFromString(line);
tasks.add(task);
}
scanner.close();
}
} catch (IOException e) {
System.out.println("Error loading tasks from file: " + e.getMessage());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can consider making this into your own exception class and include the additional error messages as part of the new exception

}
return tasks;
}

private Task parseTaskFromString(String line) {
String[] parts = line.split("\\|");
String type = parts[0].trim();
boolean isDone = parts[1].trim().equals("1"); // Assuming "1" represents task is done
String description = parts[2].trim();

switch (type) {
case "D":
String by = parts[3].trim();
LocalTime byTime = LocalTime.parse(by, DateTimeFormatter.ofPattern("HHmm"));
return new DeadlineTask(description, byTime);
case "E":
String from = parts[3].trim();
String to = parts[4].trim();
LocalTime startTime = LocalTime.parse(from, DateTimeFormatter.ofPattern("HHmm"));
LocalTime endTime = LocalTime.parse(to, DateTimeFormatter.ofPattern("HHmm"));
return new EventTask(description, startTime, endTime);
default:
return new ToDoTask(description);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider the case when the file is corrupted

}
}




private void saveTasksToFile(ArrayList<Task> tasks) {
try (PrintWriter writer = new PrintWriter(FILE_PATH)) {
for (Task task : tasks) {
writer.println(task.toFileString());
}
} catch (IOException e) {
System.out.println("Error saving tasks to file: " + e.getMessage());
}
}
}

// Task, ToDoTask, DeadlineTask, EventTask classes remain unchanged

class Task {
protected String description;
protected boolean isDone;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice boolean naming👍


public Task(String description) {
this.description = description;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why you added this. infront in task and not in Duke class? Can consider having a constant reference standard.

this.isDone = false;
}

public void markAsDone() {
this.isDone = true;
}

public void markAsNotDone() {
this.isDone = false;
}

public String toFileString() {
return "[" + (isDone ? "X" : " ") + "] " + description;
}


@Override
public String toString() {
return "[" + (isDone ? "X" : " ") + "] " + description;
}
}



class ToDoTask extends Task {
public ToDoTask(String description) {
super(description);
}

@Override
public String toFileString() {
return "T | " + (isDone ? "1" : "0") + " | " + description;
}

@Override
public String toString() {
return "[T][" + (isDone ? "X" : " ") + "] " + description;
}
}

class DeadlineTask extends Task {

private LocalTime deadline;

public DeadlineTask(String description, LocalTime by) {
super(description);
this.deadline = by;
}

@Override
public String toFileString() {
return "D | " + (isDone ? "1" : "0") + " | " + description + " | " + deadline.format(DateTimeFormatter.ofPattern("HHmm"));
}

@Override
public String toString() {
return "[D][" + (isDone ? "X" : " ") + "] " + description + " (by: " +deadline + ")";
}
}

class EventTask extends Task {
private LocalTime startTime;
private LocalTime endTime;

public EventTask(String description, LocalTime startTime, LocalTime endTime) {
super(description);
this.startTime = startTime;
this.endTime = endTime;
}

@Override
public String toFileString() {
return "E | " + (isDone ? "1" : "0") + " | " + description + " | " + startTime.format(DateTimeFormatter.ofPattern("HHmm")) + " | " + endTime.format(DateTimeFormatter.ofPattern("HHmm"));
}

@Override
public String toString() {
return "[E][" + (isDone ? "X" : " ") + "] " + description + " (from: " + startTime.format(DateTimeFormatter.ofPattern("HH:mm")) + " to: " + endTime.format(DateTimeFormatter.ofPattern("HH:mm")) + ")";
}
}
Binary file added src/main/java/DukeException.class
Binary file not shown.
Binary file added src/main/java/EventTask.class
Binary file not shown.
Binary file added src/main/java/Task.class
Binary file not shown.
Binary file added src/main/java/ToDoTask.class
Binary file not shown.
Empty file added src/main/java/duke.txt
Empty file.
21 changes: 0 additions & 21 deletions text-ui-test/runtest.bat

This file was deleted.

Empty file modified text-ui-test/runtest.sh
100644 → 100755
Empty file.