Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d839859
Add Gradle support
May 24, 2020
8090993
Level-1
Bicheng-G Aug 30, 2021
2cbd0da
Level-1 Version 2.0
Bicheng-G Aug 30, 2021
b072e1e
Level-2
Bicheng-G Aug 30, 2021
1bbcb6e
Level 3
Bicheng-G Sep 10, 2021
daa871d
Level 4
Bicheng-G Sep 11, 2021
656fd65
Level 4 small fixes
Bicheng-G Sep 19, 2021
38b9716
Add license info
damithc Oct 12, 2021
8469194
Mention se-education.org
damithc Oct 12, 2021
0dec650
Level-5 Handle Errors
Bicheng-G Oct 31, 2021
101d7d3
Level - 6 Delete && Changed Array type to Arraylist type
Bicheng-G Oct 31, 2021
ee4c8c9
Refactor Classes and Add Packages
Bicheng-G Oct 31, 2021
fd1ec16
Refactor and Packages
Bicheng-G Oct 31, 2021
6b939a4
A-MoreOOP && A-Packages
Bicheng-G Nov 3, 2021
0556d5c
Level-7 Save
Bicheng-G Nov 3, 2021
e6337b8
Level-7 Fixed Bug
Bicheng-G Nov 4, 2021
e8de287
small ui fixes
Bicheng-G Nov 4, 2021
060251f
Level - 7 bug fixes: Nullpointerexception when no file in the data di…
Bicheng-G Nov 4, 2021
12af3ec
Level-7 bug fixes
Bicheng-G Nov 4, 2021
9d2c2d4
Level-8 Dates and Times
Bicheng-G Nov 4, 2021
a93fdba
Level-8 Stretch goal: view task of given date
Bicheng-G Nov 5, 2021
9345368
Merge commit 'd8398594b7bc43da5eb865321c5a50cec4b3923d'
Bicheng-G Nov 5, 2021
fbe9ffd
Merge branch 'tweak-readme' of https://github.com/nus-tic2002-2021/duke
Bicheng-G Nov 5, 2021
4c49763
Merge branch 'add-details-to-readme' of https://github.com/nus-tic200…
Bicheng-G Nov 5, 2021
4f6567b
Level-9-Find tasks with matching keyword
Bicheng-G Nov 5, 2021
62af281
Added Individual Feature [C - Better Search]
Bicheng-G Nov 5, 2021
8591e02
Added Reset and Help command
Bicheng-G Nov 6, 2021
7d2f742
Level-10-GUI
Bicheng-G Nov 6, 2021
473ec97
GUI - UI Improvement
Bicheng-G Nov 6, 2021
4967c32
minor fix
Bicheng-G Nov 7, 2021
adc59b5
improved search method
Bicheng-G Nov 7, 2021
aa36d7c
A-JavaDoc
Bicheng-G Nov 7, 2021
104adf2
fixed-search
Bicheng-G Nov 7, 2021
68ff1ec
improve GUI ui
Bicheng-G Nov 7, 2021
1ccb21e
improve GUI ui
Bicheng-G Nov 7, 2021
cfac617
A-Coding Standard
Bicheng-G Nov 13, 2021
618f87e
A-CodeQuality
Bicheng-G Nov 13, 2021
d9a6e83
feat: integrated cheerpj
Bicheng-G Jul 6, 2025
b217061
chore: added doc folder
Bicheng-G Jul 6, 2025
7e8991a
chore: fix deployment
Bicheng-G Jul 6, 2025
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
434 changes: 434 additions & 0 deletions AutomatedTester.java

Large diffs are not rendered by default.

100 changes: 100 additions & 0 deletions CHEERPJ_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# CheerpJ Setup for Duke Task Manager

## Problem Solved
The original Duke application used JavaFX, which is not yet fully supported by CheerpJ. This has been converted to a Swing-based application that works perfectly with CheerpJ.

## What Was Changed
1. **Removed JavaFX Dependencies**: Removed JavaFX from build.gradle
2. **Converted to Swing**: Replaced JavaFX UI with Swing components
3. **Removed JavaFX Classes**: Deleted DialogBox.java and MainWindow.java
4. **Updated Main Application**: Created a new Main.java with Swing UI
5. **Fixed Launcher**: Updated Launcher.java to work with the new Main class

## Local Development
1. **Start HTTP Server**:
```bash
# Use Node.js http-server (supports Range headers)
npx http-server public -p 8002 --cors

# Note: Python's SimpleHTTPServer doesn't support Range headers!
```

2. **Open Browser**: Navigate to `http://localhost:8002`

3. **Test Commands**: Try these commands in the application:
- `help` - Show available commands
- `list` - List all tasks
- `todo buy milk` - Add a todo task
- `deadline submit report /by 31/12/2024 1800` - Add a deadline task
- `event meeting /at 15/12/2024 1400` - Add an event task
- `done 1` - Mark task 1 as done
- `delete 1` - Delete task 1
- `bye` - Exit the application

## Deployment to Production

### Vercel
```bash
# Option 1: Vercel CLI
cd public && vercel

# Option 2: Connect GitHub repo
# Build Command: (leave empty)
# Output Directory: public
```

### Netlify
```bash
# Option 1: Drag & drop the public folder to Netlify dashboard
# Option 2: Connect GitHub repo with settings:
# Build command: (leave empty)
# Publish directory: public
```

### GitHub Pages
```bash
# Move public contents to root
cp public/* .
git add .
git commit -m "Deploy CheerpJ Duke app"
git push
# Enable GitHub Pages in repository settings
```

## Production Considerations
- ✅ **Range Headers**: All major hosting platforms support HTTP Range headers (required by CheerpJ)
- ✅ **CDN Compatibility**: CheerpJ loads from their CDN which works with all platforms
- ✅ **Static Hosting**: Perfect for Vercel, Netlify, GitHub Pages
- ✅ **Performance**: JAR files are cached for optimal loading
- ✅ **Security**: Includes security headers configuration

## Technical Details
- **Framework**: Swing (fully compatible with CheerpJ)
- **CheerpJ Version**: 4.2 (from CDN)
- **Java Version**: Java 11 (configured in cheerpjInit)
- **UI Components**: JFrame, JTextArea, JTextField, JButton, JScrollPane

## Files Structure
```
public/
├── index.html # CheerpJ loader page
├── duke-V0.2.jar # Swing-based application JAR
├── _headers # Netlify headers configuration
└── vercel.json # Vercel configuration
```

## Why This Works
- CheerpJ has excellent support for Swing and AWT components
- Swing is more mature and stable in browser environments
- No dependencies on JavaFX runtime which has limited browser support
- All UI interactions work smoothly in the browser
- HTTP Range header support for efficient file loading

## Benefits
- ✅ Full compatibility with CheerpJ
- ✅ Works in all modern browsers
- ✅ No Java installation required on client
- ✅ Fast loading and responsive UI
- ✅ All Duke functionality preserved
- ✅ Easy deployment to any static hosting platform
- ✅ Production-ready with proper caching and security headers
81 changes: 81 additions & 0 deletions QuickTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import ui.WhatsAppStyleChatUI;
import java.lang.reflect.Method;

/**
* Quick test for specific issues found by automated tester
*/
public class QuickTest {

public static void main(String[] args) {
try {
WhatsAppStyleChatUI chatUI = new WhatsAppStyleChatUI();
Method preprocessMethod = WhatsAppStyleChatUI.class.getDeclaredMethod("preprocessInput", String.class);
preprocessMethod.setAccessible(true);

System.out.println("🔧 Testing Specific Fixes");
System.out.println("========================");

String[] problemCases = {
// Cases that were failing
"due project due friday",
"due task due tomorrow",
"due insurance claim due friday",
"due paper due monday",
"",
" ",
"appointment",
"meeting",
"deadline",
"appointment appointment appointment",
"call mom by morning",
"meeting tomorrow at 2pm",
"tell baby a joke",
"buy milk"
};

for (String testCase : problemCases) {
try {
String result = (String) preprocessMethod.invoke(chatUI, testCase);
System.out.printf("Input: \"%s\"\n", testCase);
System.out.printf("Output: \"%s\"\n", result);
System.out.printf("Valid: %s\n", isValidOutput(result));
System.out.println();
} catch (Exception e) {
System.out.printf("Input: \"%s\"\n", testCase);
System.out.printf("ERROR: %s\n", e.getMessage());
System.out.println();
}
}

} catch (Exception e) {
System.err.println("Test failed: " + e.getMessage());
e.printStackTrace();
}
}

private static boolean isValidOutput(String output) {
if (output == null || output.trim().isEmpty()) {
return false;
}

String[] parts = output.trim().split(" ", 2);
String cmdType = parts[0].toLowerCase();

switch (cmdType) {
case "event":
return parts.length > 1 && parts[1].contains("/at") &&
!parts[1].startsWith("/at") && !parts[1].endsWith("/at");
case "deadline":
return parts.length > 1 && parts[1].contains("/by") &&
!parts[1].startsWith("/by") && !parts[1].endsWith("/by");
case "todo":
return parts.length > 1 && !parts[1].trim().isEmpty();
case "help":
case "list":
case "search":
return true;
default:
return false;
}
}
}
85 changes: 67 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,73 @@
# Duke project template
# Duke

This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
A lightweight, fast and fun personal assistant chatbot built with Java 11. Duke helps you organise todos, deadlines and events through a conversational interface available in both the command line and a modern JavaFX GUI.

## Setting up in Intellij
## Table of Contents

Prerequisites: JDK 11, update Intellij to the most recent version.
- [Duke](#duke)
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Quick Start](#quick-start)
- [Usage](#usage)
- [Contributing](#contributing)
- [License](#license)
- [Acknowledgements](#acknowledgements)

1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first)
1. Open the project into Intellij as follows:
1. Click `Open`.
1. Select the project directory, and click `OK`.
1. If there are any further prompts, accept the defaults.
1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).<br>
In the same dialog, set the **Project language level** field to the `SDK default` option.
3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
## Features

- [x] Add **Todo**, **Deadline** and **Event** tasks
- [x] Mark tasks as done or delete them
- [x] Edit existing tasks in-place
- [x] Natural-language date parsing (e.g.&nbsp;"next Friday 5&nbsp;pm")
- [x] Persistent storage — your data is saved between sessions
- [x] Powerful keyword and date search
- [x] Smart auto-complete and contextual help
- [x] WhatsApp-style modern GUI
- [x] Extensive unit and integration test-suite

## Quick Start

1. Ensure you have **Java&nbsp;11** installed.
2. Clone this repository:

```bash
git clone https://github.com/<your-username>/duke.git
cd duke
```
Hello from
____ _
| _ \ _ _| | _____
| | | | | | | |/ / _ \
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|
3. Build and run Duke using Gradle:

```bash
./gradlew run
```
4. Type `help` in the Duke prompt to see the full list of available commands.

## Usage

| Command | Example | Description |
|---------|---------|-------------|
| `todo TASK_DESCRIPTION` | `todo read book` | Adds a todo task |
| `deadline TASK_DESCRIPTION /by DATE` | `deadline submit report /by 2025-03-15` | Adds a deadline task |
| `event TASK_DESCRIPTION /at DATE` | `event project meeting /at 2025-03-10 14:00` | Adds an event task |
| `list` | | Lists all tasks |
| `done INDEX` | `done 2` | Marks the given task as completed |
| `delete INDEX` | `delete 3` | Deletes the given task |
| `find KEYWORD` | `find book` | Finds tasks containing the keyword |

Run `help` inside Duke for the complete command reference and advanced usage examples.

## Contributing

We welcome pull requests and issues!

1. Fork the repository and create your branch from **`master`**.
2. Follow the [Conventional Commits](https://www.conventionalcommits.org/) style.
3. Ensure the tests pass via `./gradlew test` before submitting.
4. Create a pull request using the provided template.

## License

Duke is released under the [MIT License](LICENSE).

## Acknowledgements

This project is based on the excellent teaching materials from [se-education](https://se-education.org/) and is maintained by our open-source contributors.
97 changes: 97 additions & 0 deletions TestCoreFunction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import ui.WhatsAppStyleChatUI;
import java.lang.reflect.Method;

/**
* Test class to verify core functionality of natural language processing
*/
public class TestCoreFunction {

public static void main(String[] args) {
try {
// Create an instance to test preprocessing
WhatsAppStyleChatUI chatUI = new WhatsAppStyleChatUI();

// Use reflection to access the private preprocessInput method
Method preprocessMethod = WhatsAppStyleChatUI.class.getDeclaredMethod("preprocessInput", String.class);
preprocessMethod.setAccessible(true);

System.out.println("🧪 Testing Core Natural Language Processing");
System.out.println("===========================================\n");

// Test cases
String[] testInputs = {
// Event tests
"meeting tomorrow at 2pm",
"event meeting tomorrow at 2pm",
"add meeting tomorrow at 2pm",
"appointment with doctor on friday 3pm",
"lunch with client next monday at 12pm",

// Deadline tests
"deadline project by friday",
"submit report by tomorrow 5pm",
"finish homework by next week",
"project due next friday",

// Todo tests
"add buy milk",
"todo tell baby a joke",
"create shopping list",
"buy groceries",
"call mom",

// Direct commands (should pass through)
"list",
"help",
"done 1",
"delete 2"
};

for (String input : testInputs) {
try {
String result = (String) preprocessMethod.invoke(chatUI, input);
System.out.printf("Input: \"%s\"\n", input);
System.out.printf("Output: \"%s\"\n", result);
System.out.println("Status: " + (isValidCommand(result) ? "✅ VALID" : "❌ INVALID"));
System.out.println();
} catch (Exception e) {
System.out.printf("Input: \"%s\"\n", input);
System.out.printf("Error: %s\n", e.getMessage());
System.out.println("Status: ❌ ERROR");
System.out.println();
}
}

} catch (Exception e) {
System.err.println("Failed to test: " + e.getMessage());
e.printStackTrace();
}
}

private static boolean isValidCommand(String command) {
String cmd = command.toLowerCase().trim();

// Check for valid todo format
if (cmd.startsWith("todo ") && cmd.length() > 5) {
return true;
}

// Check for valid event format
if (cmd.startsWith("event ") && cmd.contains(" /at ")) {
return true;
}

// Check for valid deadline format
if (cmd.startsWith("deadline ") && cmd.contains(" /by ")) {
return true;
}

// Check for direct commands
if (cmd.equals("list") || cmd.equals("help") || cmd.startsWith("done ") ||
cmd.startsWith("delete ") || cmd.startsWith("search ")) {
return true;
}

return false;
}
}
Loading