Skip to content

Commit 8fa6b0d

Browse files
committed
Add GUI for chatbot
1 parent 5143718 commit 8fa6b0d

File tree

14 files changed

+316
-51
lines changed

14 files changed

+316
-51
lines changed

build.gradle

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ repositories {
1414
}
1515

1616
dependencies {
17+
String javaFxVersion = '17.0.7'
18+
19+
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
20+
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
21+
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
22+
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win'
23+
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac'
24+
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux'
25+
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win'
26+
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac'
27+
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux'
28+
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
29+
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
30+
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
31+
1732
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.10.0'
1833
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.10.0'
1934
}

data/duke.txt

27 Bytes
Binary file not shown.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package monday;
2+
3+
import java.io.IOException;
4+
import java.util.Collections;
5+
6+
import javafx.collections.FXCollections;
7+
import javafx.collections.ObservableList;
8+
import javafx.fxml.FXML;
9+
import javafx.fxml.FXMLLoader;
10+
import javafx.geometry.Pos;
11+
import javafx.scene.Node;
12+
import javafx.scene.control.Label;
13+
import javafx.scene.image.Image;
14+
import javafx.scene.image.ImageView;
15+
import javafx.scene.layout.HBox;
16+
17+
18+
/**
19+
* An example of a custom control using FXML.
20+
* This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label
21+
* containing text from the speaker.
22+
*/
23+
public class DialogBox extends HBox {
24+
@FXML
25+
private Label dialog;
26+
@FXML
27+
private ImageView displayPicture;
28+
29+
private DialogBox(String text, Image img) {
30+
try {
31+
FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml"));
32+
fxmlLoader.setController(this);
33+
fxmlLoader.setRoot(this);
34+
fxmlLoader.load();
35+
} catch (IOException e) {
36+
e.printStackTrace();
37+
}
38+
39+
dialog.setText(text);
40+
displayPicture.setImage(img);
41+
}
42+
43+
/**
44+
* Flips the dialog box such that the ImageView is on the left and text on the right.
45+
*/
46+
private void flip() {
47+
ObservableList<Node> tmp = FXCollections.observableArrayList(this.getChildren());
48+
Collections.reverse(tmp);
49+
getChildren().setAll(tmp);
50+
setAlignment(Pos.TOP_LEFT);
51+
}
52+
53+
public static DialogBox getUserDialog(String text, Image img) {
54+
return new DialogBox(text, img);
55+
}
56+
57+
public static DialogBox getDukeDialog(String text, Image img) {
58+
var db = new DialogBox(text, img);
59+
db.flip();
60+
return db;
61+
}
62+
}

src/main/java/monday/Launcher.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package monday;
2+
3+
import javafx.application.Application;
4+
5+
/**
6+
* A launcher class to workaround classpath issues.
7+
*/
8+
public class Launcher {
9+
public static void main(String[] args) {
10+
Application.launch(Main.class, args);
11+
}
12+
}

src/main/java/monday/Main.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package monday;
2+
3+
import java.io.IOException;
4+
5+
import javafx.application.Application;
6+
import javafx.fxml.FXMLLoader;
7+
import javafx.scene.Scene;
8+
import javafx.scene.layout.AnchorPane;
9+
import javafx.stage.Stage;
10+
11+
12+
/**
13+
* A GUI for Duke using FXML.
14+
*/
15+
public class Main extends Application {
16+
17+
private Monday monday = new Monday();
18+
19+
@Override
20+
public void start(Stage stage) {
21+
try {
22+
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
23+
AnchorPane ap = fxmlLoader.load();
24+
Scene scene = new Scene(ap);
25+
stage.setScene(scene);
26+
fxmlLoader.<MainWindow>getController().setMonday(monday);
27+
stage.show();
28+
} catch (IOException e) {
29+
e.printStackTrace();
30+
}
31+
}
32+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package monday;
2+
3+
import javafx.fxml.FXML;
4+
import javafx.scene.control.Button;
5+
import javafx.scene.control.ScrollPane;
6+
import javafx.scene.control.TextField;
7+
import javafx.scene.image.Image;
8+
import javafx.scene.layout.AnchorPane;
9+
import javafx.scene.layout.VBox;
10+
/**
11+
* Controller for MainWindow. Provides the layout for the other controls.
12+
*/
13+
public class MainWindow extends AnchorPane {
14+
@FXML
15+
private ScrollPane scrollPane;
16+
@FXML
17+
private VBox dialogContainer;
18+
@FXML
19+
private TextField userInput;
20+
@FXML
21+
private Button sendButton;
22+
23+
private Monday monday;
24+
25+
private Image userImage = new Image(this.getClass().getResourceAsStream("/images/bai.png"));
26+
private Image mondayImage = new Image(this.getClass().getResourceAsStream("/images/fa.png"));
27+
28+
@FXML
29+
public void initialize() {
30+
scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
31+
}
32+
33+
public void setMonday(Monday d) {
34+
monday = d;
35+
}
36+
37+
/**
38+
* Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to
39+
* the dialog container. Clears the user input after processing.
40+
*/
41+
@FXML
42+
private void handleUserInput() {
43+
String input = userInput.getText();
44+
String response = monday.getResponse(input);
45+
dialogContainer.getChildren().addAll(
46+
DialogBox.getUserDialog(input, userImage),
47+
DialogBox.getDukeDialog(response, mondayImage)
48+
);
49+
userInput.clear();
50+
}
51+
}

src/main/java/monday/Monday.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,28 @@
1212
* delete, keep track of the tasks they have.
1313
*/
1414
public class Monday {
15+
16+
private final TaskList taskList = new TaskList("./data/duke.txt");
17+
1518
/**
1619
* Starts the Monday application.
1720
* Initializes necessary components, greets the user, handles user input, and handles errors.
18-
*
19-
* @param filepath the filepath to store the tasks
2021
*/
21-
private static void startMonday(String filepath) {
22+
private void startMonday() {
2223
Scanner scanner = new Scanner(System.in);
23-
TaskList taskList = new TaskList(filepath);
2424
boolean isRunning = true;
2525

2626
Ui.printSeparator();
27-
Ui.greet();
27+
System.out.println(Ui.greet());
2828
Ui.printSeparator();
2929
while (isRunning) {
3030
String userInput = scanner.nextLine();
31+
if (userInput.equals("bye")) {
32+
isRunning = false;
33+
}
3134
Ui.printSeparator();
3235
try {
33-
isRunning = Parser.mondayParser(userInput, taskList);
36+
System.out.println(Parser.mondayParser(userInput, taskList));
3437
} catch (MondayExceptions e) {
3538
System.out.println(e);
3639
} catch (NumberFormatException e) {
@@ -45,12 +48,21 @@ private static void startMonday(String filepath) {
4548
scanner.close();
4649
}
4750

51+
public String getResponse(String input) {
52+
try {
53+
return Parser.mondayParser(input, taskList);
54+
} catch (MondayExceptions e) {
55+
return e.toString();
56+
}
57+
}
58+
4859
/**
4960
* Entry point to Monday.
5061
*
5162
* @param args Command line arguments
5263
*/
5364
public static void main(String[] args) {
54-
startMonday("./data/duke.txt");
65+
Monday monday = new Monday();
66+
monday.startMonday();
5567
}
5668
}

src/main/java/monday/monday/parser/Parser.java

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,20 @@ private enum Command {
2424
DEADLINE,
2525
EVENT,
2626
DELETE,
27-
FIND
27+
FIND,
28+
HI
2829
}
2930

3031
/**
3132
* Parses the user input and performs the corresponding action.
3233
*
3334
* @param userInput the user input to be parsed
3435
* @param taskList the TaskList object to perform actions on
35-
* @return true if the application should continue running, false otherwise
36+
* @return response from chatbot
3637
* @throws MondayExceptions if there are errors related to the Monday application
3738
* @throws IllegalArgumentException if the user input is in the wrong format
3839
*/
39-
public static boolean mondayParser(String userInput, TaskList taskList) throws MondayExceptions {
40+
public static String mondayParser(String userInput, TaskList taskList) throws MondayExceptions {
4041
String[] input = userInput.split(" ", 2);
4142
String command = input[0];
4243
String content = input.length > 1 ? input[1] : null;
@@ -45,20 +46,19 @@ public static boolean mondayParser(String userInput, TaskList taskList) throws M
4546

4647

4748
switch (commandEnum) {
49+
case HI:
50+
return Ui.greet();
4851
case BYE:
49-
Ui.exit();
50-
return false;
52+
return Ui.exit();
5153
case LIST:
52-
taskList.displayList();
53-
break;
54+
return taskList.displayList();
5455
case MARK: {
5556
if (content == null) {
5657
throw new MondayExceptions("Mark requires a index to mark the task as completed.");
5758
}
5859
int index = Integer.parseInt(content);
5960

60-
taskList.mark(index);
61-
break;
61+
return taskList.mark(index);
6262
}
6363
case UNMARK: {
6464
if (content == null) {
@@ -67,17 +67,15 @@ public static boolean mondayParser(String userInput, TaskList taskList) throws M
6767

6868
int index = Integer.parseInt(content);
6969

70-
taskList.unMark(index);
71-
break;
70+
return taskList.unMark(index);
7271
}
7372
case TODO:
7473
if (content == null) {
7574
throw new MondayExceptions("The description of a todo cannot be empty.\n"
7675
+ "Usage: todo (task)");
7776
}
7877

79-
taskList.addToTask(new ToDo(content));
80-
break;
78+
return taskList.addToTask(new ToDo(content));
8179
case DEADLINE:
8280
try {
8381
if (content == null) {
@@ -89,12 +87,11 @@ public static boolean mondayParser(String userInput, TaskList taskList) throws M
8987
String description = taskDetails[0];
9088
String date = taskDetails[1];
9189

92-
taskList.addToTask(new Deadline(description.trim(), date.trim()));
90+
return taskList.addToTask(new Deadline(description.trim(), date.trim()));
9391
} catch (ArrayIndexOutOfBoundsException e) {
9492
throw new IllegalArgumentException("Invalid Format. "
9593
+ "Usage: deadline (task) /by (time)");
9694
}
97-
break;
9895
case EVENT:
9996
try {
10097
if (content == null) {
@@ -108,22 +105,20 @@ public static boolean mondayParser(String userInput, TaskList taskList) throws M
108105
String start = taskTiming[0];
109106
String end = taskTiming[1];
110107

111-
taskList.addToTask(new Event(description.trim(),
108+
return taskList.addToTask(new Event(description.trim(),
112109
start.trim(),
113110
end.trim()));
114111
} catch (ArrayIndexOutOfBoundsException e) {
115112
throw new IllegalArgumentException("Invalid Format. "
116113
+ "Usage: event (task) /from (start time) /to (end time)");
117114
}
118-
break;
119115
case DELETE:
120116
if (content == null) {
121117
throw new MondayExceptions("Delete requires a index to delete the task");
122118
}
123119
int index = Integer.parseInt(content);
124120

125-
taskList.delete(index);
126-
break;
121+
return taskList.delete(index);
127122
case FIND:
128123
if (content == null) {
129124
throw new MondayExceptions("Find requires a keyword to find the tasks");
@@ -136,12 +131,10 @@ public static boolean mondayParser(String userInput, TaskList taskList) throws M
136131
+ "Usage: find (keyword), there should only be one keyword.");
137132
}
138133

139-
taskList.find(keywordDetails[0]);
140-
break;
134+
return taskList.find(keywordDetails[0]);
141135
default:
142136
throw new MondayExceptions("Sorry, I do not understand what that means.\n"
143137
+ "Please provide a valid input/command. e.g todo read book");
144138
}
145-
return true;
146139
}
147140
}

0 commit comments

Comments
 (0)