From e15e12c7e79154c57898b282dcab92ed536febdb Mon Sep 17 00:00:00 2001 From: Yugam2508 Date: Sun, 1 Mar 2026 10:25:40 +0800 Subject: [PATCH] Add JavaFX GUI interface (Level-10) --- build.gradle | 8 +- data/jarvis.txt | 5 -- src/main/java/jarvis/Jarvis.java | 96 ++++++++++++++++++++++++ src/main/java/jarvis/Launcher.java | 12 +++ src/main/java/jarvis/Main.java | 116 +++++++++++++++++++++++++++++ 5 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 src/main/java/jarvis/Launcher.java create mode 100644 src/main/java/jarvis/Main.java diff --git a/build.gradle b/build.gradle index 946779d808..202626bd7e 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'application' id 'com.github.johnrengelman.shadow' version '7.1.2' + id 'org.openjfx.javafxplugin' version '0.1.0' } repositories { @@ -18,7 +19,7 @@ test { } application { - mainClass.set("jarvis.Jarvis") + mainClass.set("jarvis.Launcher") } shadowJar { @@ -27,6 +28,11 @@ shadowJar { archiveVersion = "" } +javafx { + version = "21.0.1" + modules = ['javafx.controls', 'javafx.fxml'] +} + java { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 diff --git a/data/jarvis.txt b/data/jarvis.txt index 7d34a7aa0a..e69de29bb2 100644 --- a/data/jarvis.txt +++ b/data/jarvis.txt @@ -1,5 +0,0 @@ -D | 0 | finish homework | Sunday -T | 0 | task -T | 0 | read book -T | 0 | return book -T | 0 | eat apple diff --git a/src/main/java/jarvis/Jarvis.java b/src/main/java/jarvis/Jarvis.java index 28f9159601..c826f8971d 100644 --- a/src/main/java/jarvis/Jarvis.java +++ b/src/main/java/jarvis/Jarvis.java @@ -150,6 +150,102 @@ public void run() { ui.showExit(); } + /** + * Generates a response for the given user input. + * + * @param input The user's input command. + * @return The response from Jarvis. + */ + public String getResponse(String input) { + CommandType command = Parser.parseCommand(input); + StringBuilder response = new StringBuilder(); + + try { + switch (command) { + case BYE: + return "Bye. Hope to see you again soon!"; + case LIST: + if (tasks.size() == 0) { + return "No tasks in your list yet!"; + } + response.append("Here are the tasks in your list:\n"); + for (int i = 0; i < tasks.size(); i++) { + response.append((i + 1)).append(".").append(tasks.get(i)).append("\n"); + } + return response.toString(); + case MARK: + int markIndex = Parser.parseIndex(input); + tasks.get(markIndex).markAsDone(); + storage.save(tasks.getAllTasks()); + return "Nice! I've marked this task as done:\n " + tasks.get(markIndex); + case UNMARK: + int unmarkIndex = Parser.parseIndex(input); + tasks.get(unmarkIndex).markAsNotDone(); + storage.save(tasks.getAllTasks()); + return "OK, I've marked this task as not done yet:\n " + tasks.get(unmarkIndex); + case DELETE: + int delIndex = Parser.parseIndex(input); + Task deleted = tasks.deleteTask(delIndex); + storage.save(tasks.getAllTasks()); + return "Noted. I've removed this task:\n " + deleted + + "\nNow you have " + tasks.size() + " tasks in the list."; + case TODO: + if (input.trim().equals("todo")) { + throw new JarvisException("OOPS!!! Empty todo."); + } + Task todo = new Todo(input.substring(5).trim()); + tasks.addTask(todo); + storage.save(tasks.getAllTasks()); + return "Got it. I've added this task:\n " + todo + + "\nNow you have " + tasks.size() + " tasks in the list."; + case DEADLINE: + if (input.trim().equals("deadline")) { + throw new JarvisException("OOPS!!! Empty deadline."); + } + String[] dParts = input.substring(9).split(" /by "); + Task deadline = new Deadline(dParts[0].trim(), dParts[1].trim()); + tasks.addTask(deadline); + storage.save(tasks.getAllTasks()); + return "Got it. I've added this task:\n " + deadline + + "\nNow you have " + tasks.size() + " tasks in the list."; + case EVENT: + if (input.trim().equals("event")) { + throw new JarvisException("OOPS!!! Empty event."); + } + String[] eParts = input.substring(6).split(" /from "); + String[] tParts = eParts[1].split(" /to "); + Task event = new Event(eParts[0].trim(), tParts[0].trim(), tParts[1].trim()); + tasks.addTask(event); + storage.save(tasks.getAllTasks()); + return "Got it. I've added this task:\n " + event + + "\nNow you have " + tasks.size() + " tasks in the list."; + case FIND: + String[] fParts = input.split(" ", 2); + if (fParts.length < 2 || fParts[1].trim().isEmpty()) { + return "The search keyword cannot be empty."; + } + String keyword = fParts[1].trim(); + ArrayList foundTasks = tasks.findTasks(keyword); + if (foundTasks.isEmpty()) { + return "No matching tasks found."; + } + response.append("Here are the matching tasks in your list:\n"); + for (int i = 0; i < foundTasks.size(); i++) { + response.append((i + 1)).append(".").append(foundTasks.get(i)).append("\n"); + } + return response.toString(); + case CHEER: + return getRandomQuote(); + default: + throw new JarvisException("OOPS!!! I'm sorry, but I don't know what that means :-("); + } + } catch (JarvisException e) { + return e.getMessage(); + } catch (Exception e) { + return "OOPS!!! Something went wrong: " + e.getMessage(); + } + } + /** * Retrieves a random motivational quote from the cheer.txt file. * diff --git a/src/main/java/jarvis/Launcher.java b/src/main/java/jarvis/Launcher.java new file mode 100644 index 0000000000..c00963bd31 --- /dev/null +++ b/src/main/java/jarvis/Launcher.java @@ -0,0 +1,12 @@ +package jarvis; + +import javafx.application.Application; + +/** + * A launcher class to workaround classpath issues. + */ +public class Launcher { + public static void main(String[] args) { + Application.launch(Main.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/jarvis/Main.java b/src/main/java/jarvis/Main.java new file mode 100644 index 0000000000..822167b5d6 --- /dev/null +++ b/src/main/java/jarvis/Main.java @@ -0,0 +1,116 @@ +package jarvis; + +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +/** + * Main JavaFX application class for Jarvis. + */ +public class Main extends Application { + + private Jarvis jarvis = new Jarvis("./data/jarvis.txt"); + private ScrollPane scrollPane; + private VBox dialogContainer; + private TextField userInput; + private Button sendButton; + private Scene scene; + + @Override + public void start(Stage stage) { + scrollPane = new ScrollPane(); + dialogContainer = new VBox(); + dialogContainer.setSpacing(10); + scrollPane.setContent(dialogContainer); + + userInput = new TextField(); + sendButton = new Button("Send"); + + AnchorPane mainLayout = new AnchorPane(); + mainLayout.getChildren().addAll(scrollPane, userInput, sendButton); + + scene = new Scene(mainLayout); + + stage.setScene(scene); + stage.setTitle("Jarvis"); + stage.setMinHeight(600); + stage.setMinWidth(400); + + mainLayout.setPrefSize(400, 600); + scrollPane.setPrefSize(385, 535); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS); + scrollPane.setVvalue(1.0); + scrollPane.setFitToWidth(true); + + dialogContainer.setPrefHeight(Region.USE_COMPUTED_SIZE); + + userInput.setPrefWidth(325); + sendButton.setPrefWidth(55); + + AnchorPane.setTopAnchor(scrollPane, 1.0); + AnchorPane.setBottomAnchor(sendButton, 1.0); + AnchorPane.setRightAnchor(sendButton, 1.0); + AnchorPane.setLeftAnchor(userInput, 1.0); + AnchorPane.setBottomAnchor(userInput, 1.0); + + Label welcomeLabel = new Label("Hello! I'm Jarvis\nWhat can I do for you?"); + dialogContainer.getChildren().add(welcomeLabel); + + sendButton.setOnMouseClicked((event) -> { + handleUserInput(); + }); + + userInput.setOnAction((event) -> { + handleUserInput(); + }); + + dialogContainer.heightProperty().addListener((observable) -> scrollPane.setVvalue(1.0)); + + stage.show(); + } + + /** + * Handles user input and displays response. + */ + private void handleUserInput() { + String input = userInput.getText(); + if (input.trim().isEmpty()) { + return; + } + + Label userLabel = new Label("You: " + input); + dialogContainer.getChildren().add(userLabel); + + String response = getResponse(input); + Label jarvisLabel = new Label("Jarvis: " + response); + dialogContainer.getChildren().add(jarvisLabel); + + userInput.clear(); + + if (input.trim().equalsIgnoreCase("bye")) { + javafx.application.Platform.exit(); + } + } + + /** + * Gets response from Jarvis based on user input. + * + * @param input The user's input command. + * @return The response from Jarvis. + */ + private String getResponse(String input) { + try { + return jarvis.getResponse(input); + } catch (Exception e) { + return "Error: " + e.getMessage(); + } + } +} \ No newline at end of file