diff --git a/data/flashcards/flashcard.txt b/data/flashcards/flashcard.txt index e95f8a7c6e..e0e9e10c3e 100644 --- a/data/flashcards/flashcard.txt +++ b/data/flashcards/flashcard.txt @@ -1,8 +1,2 @@ -d | a | - | - | - -dfdf | dfdf | - | - | - -dfdf | asdfdf | - | - | - -ddf | dfdf | - | - | - -hello | bye | - | - | - -hello | bye | - | - | - -end program | hello | - | - | - -hello | world | - | - | - +ddd | dfdf | - | - | - +ddff | a | - | - | - diff --git a/docs/UserGuide.md b/docs/UserGuide.md index abd9fbe891..946cb4f9bf 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -2,18 +2,25 @@ ## Introduction -{Give a product intro} +TaskLinker is a CLI-tool for helping students memorize flashcards and track +their flashcard and generell academic progress in the courses they are taking. ## Quick Start -{Give steps to get started quickly} - 1. Ensure that you have Java 11 or above installed. -1. Down the latest version of `Duke` from [here](http://link.to/duke). +1. Down the latest jar from [the latest release on GitHub] + (https://github.com/AY2324S1-CS2113-F11-3/tp/releases). +1. Run the jar via `java -jar duke.jar` + +## General explanation of flashcards + +## Features -## Features +### Listing all flashcards: `list flashcards` -{Give detailed description of each feature} +Prints out a list of all flashcards. + +Format: `list flashcards` ### Adding a todo: `todo` Adds a new item to the list of todo items. @@ -21,14 +28,57 @@ Adds a new item to the list of todo items. Format: `todo n/TODO_NAME d/DEADLINE` * The `DEADLINE` can be in a natural language format. -* The `TODO_NAME` cannot contain punctuation. +* The `TODO_NAME` cannot contain punctuation. -Example of usage: +Example of usage: `todo n/Write the rest of the User Guide d/next week` `todo n/Refactor the User Guide to remove passive voice d/13/04/2020` +### Creating a new flashcard: `create flashcard` + +Starts the process of adding a new flashcard. + +After entering this command, you are prompted to first input the front page +text (once you have typed it out, submit it by pressing ) and then the +back page text (once you have typed it out, submit it by pressing ) of +your new flashcard. + +After you've done this, a success message will be printed out. This +indicates that a new flashcard has been successfully created and saved. + +Format: `create flashcard` + +### Reviewing your flashcards: `review flashcards` + +Starts the process of reviewing flashcard. + +After entering this command, you are prompted to select your exact review +mode from 3 choices: + +- `random mode`: Randomly selects flashcards to review +- `spaced repetition mode`: Which flashcards are shown depends on how well + you previously knew them. Flashcards which you couldn't remember well are + shown more often, while flashcards which you remembered well are shown + less often. +- `review by tag mode`: Randomly selects flashcards with a certain tag to review + +Input `a` to choose `random mode`, input `b` to choose `spaced repetition +mode` and input `c` to choose `review by tag mode`. + +Once you've selected a review mode, the actual review begins: the front page +of a flashcard is shown to you. You should now try and think of the answer +(the text on the back page of the flashcard); and once you're ready, press + to compare it to the actual back page. + +Now, the process repeats and the next flashcard is shown to you. + +If you want to quit the review process, simply input `q` or `quit` instead +of pressing to reveal the back page. + +Format: `create flashcard` + ## FAQ **Q**: How do I transfer my data to another computer? @@ -37,6 +87,6 @@ Example of usage: ## Command Summary -{Give a 'cheat sheet' of commands here} - -* Add todo `todo n/TODO_NAME d/DEADLINE` +* List all flashcards: `list flashcards` +* Create a new flashcard: `create flashcard` +* Review your flashcards: `review flashcards` diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java index 2640517379..bdb913c923 100644 --- a/src/main/java/seedu/duke/Duke.java +++ b/src/main/java/seedu/duke/Duke.java @@ -28,13 +28,34 @@ private void run() { if (fc.isResponsible(input)) { fc.processInput(input); - } else if (cm.isResponsible(input)) { cm.processInput(input); + } else if (input.startsWith("help")) { + printHelp(); } else { System.out.println(" Invalid command! Please try again."); } } } -} \ No newline at end of file + + private void printHelp() { + System.out.println(" If you need help, please consult our " + + "user guide at https://ay2324s1-cs2113-f11-3.github" + + ".io/tp/UserGuide.html"); + System.out.println(); + System.out.println(" Here is a quick overview over all available " + + "commands: "); + + String[] commandFormats = new String[] { + "list flashcards", + "create flashcard", + "review flashcards", + "help", + }; + + for (String commandFormat : commandFormats) { + System.out.println(" - " + commandFormat); + } + } +} diff --git a/src/main/java/seedu/duke/calendar/CalendarManager.java b/src/main/java/seedu/duke/calendar/CalendarManager.java index 34eaa21ad1..6e1a7db435 100644 --- a/src/main/java/seedu/duke/calendar/CalendarManager.java +++ b/src/main/java/seedu/duke/calendar/CalendarManager.java @@ -4,8 +4,6 @@ import seedu.duke.calendar.command.EventCommand; import seedu.duke.calendar.command.UnknownCommand; -import seedu.duke.calendar.Event; -import seedu.duke.flashcard.FlashcardStorage; import java.io.FileNotFoundException; import java.util.ArrayList; diff --git a/src/main/java/seedu/duke/flashcard/Flashcard.java b/src/main/java/seedu/duke/flashcard/Flashcard.java index 45c72a5666..ed620d2a8d 100644 --- a/src/main/java/seedu/duke/flashcard/Flashcard.java +++ b/src/main/java/seedu/duke/flashcard/Flashcard.java @@ -8,22 +8,35 @@ import java.util.ArrayList; public class Flashcard { + private static int globalMaxId = 1; private String frontText; private String backText; - private ArrayList tags; private ArrayList reviews; private LocalDateTime lastReviewOn; - - + private int id; public Flashcard(String frontText, String backText) { this.frontText = frontText; this.backText = backText; - tags = new ArrayList<>(); reviews = new ArrayList<>(); lastReviewOn = null; + + globalMaxId += 1; + id = globalMaxId; + } + + public static void calculateAndUpdateGlobalMaxId(FlashcardList flashcardList) { + int currentMax = 1; + + for (Flashcard flashcard : flashcardList.getFlashcards()){ + if (flashcard.getId() > currentMax) { + currentMax = flashcard.getId(); + } + } + + globalMaxId = currentMax + 1; } public void setLastReviewOn(LocalDateTime lastReviewOn) { @@ -34,6 +47,10 @@ public String getFrontText() { return frontText; } + public int getId() { + return id; + } + public String getBackText() { return backText; } @@ -41,7 +58,11 @@ public String getBackText() { public String toString() { return "front text: " + frontText + System.lineSeparator() + "back text: " + backText + System.lineSeparator() - + "tags: " + tags.toString() + System.lineSeparator() - + "next review due on: " + lastReviewOn + System.lineSeparator(); + + "next review due on: " + lastReviewOn + System.lineSeparator() + + "id: " + id + System.lineSeparator(); + } + + public void addReview(FlashcardReview flashcardReview) { + reviews.add(flashcardReview); } } diff --git a/src/main/java/seedu/duke/flashcard/FlashcardCommandParser.java b/src/main/java/seedu/duke/flashcard/FlashcardCommandParser.java index 3714be31e7..e9a7b6f39c 100644 --- a/src/main/java/seedu/duke/flashcard/FlashcardCommandParser.java +++ b/src/main/java/seedu/duke/flashcard/FlashcardCommandParser.java @@ -6,6 +6,8 @@ import seedu.duke.flashcard.command.CreateFlashcardCommand; import seedu.duke.flashcard.command.ListFlashcardsCommand; import seedu.duke.flashcard.command.StartReviewCommand; +import seedu.duke.flashcard.command.DeleteAllFlashcardsCommand; +import seedu.duke.flashcard.command.DeleteFlashcardCommand; import seedu.duke.flashcard.command.UnknownCommand; public class FlashcardCommandParser { @@ -17,7 +19,11 @@ public FlashcardCommand parseInput(String input) { } else if (input.startsWith("list flashcards")) { return new ListFlashcardsCommand(); } else if (input.startsWith("review flashcards")) { - return new StartReviewCommand(); + return new StartReviewCommand(input); + } else if (input.startsWith("delete all flashcards")) { + return new DeleteAllFlashcardsCommand(); + } else if (input.startsWith("delete flashcard")) { + return new DeleteFlashcardCommand(input); } return new UnknownCommand(); diff --git a/src/main/java/seedu/duke/flashcard/FlashcardComponent.java b/src/main/java/seedu/duke/flashcard/FlashcardComponent.java index 60d0e5d86f..004dddbfbd 100644 --- a/src/main/java/seedu/duke/flashcard/FlashcardComponent.java +++ b/src/main/java/seedu/duke/flashcard/FlashcardComponent.java @@ -12,7 +12,6 @@ public class FlashcardComponent { private FlashcardCommandParser parser; private FlashcardList flashcardList; private FlashcardUi ui; - private FlashcardStorage storage; @@ -32,6 +31,7 @@ public FlashcardComponent() { } //@@author wendelinwemhoener + Flashcard.calculateAndUpdateGlobalMaxId(flashcardList); ui = new FlashcardUi(flashcardList); } diff --git a/src/main/java/seedu/duke/flashcard/FlashcardList.java b/src/main/java/seedu/duke/flashcard/FlashcardList.java index cce69c2d36..b4d909c91c 100644 --- a/src/main/java/seedu/duke/flashcard/FlashcardList.java +++ b/src/main/java/seedu/duke/flashcard/FlashcardList.java @@ -21,7 +21,33 @@ public int getSize(){ } + //@@author wendelinwemhoener public void add(Flashcard flashcard) { flashcards.add(flashcard); } + + public void deleteAllFlashcards() { + flashcards.clear(); + } + + public boolean isEmpty() { + return flashcards.isEmpty(); + } + + public boolean deleteFlashcardById(int flashcardId) { + int indexToDeleteAt = -1; + + for (int i = 0; i < flashcards.size(); i++) { + if (flashcards.get(i).getId() == flashcardId) { + indexToDeleteAt = i; + } + } + + if (indexToDeleteAt == -1) { + return false; + } else { + flashcards.remove(indexToDeleteAt); + return true; + } + } } diff --git a/src/main/java/seedu/duke/flashcard/FlashcardStorage.java b/src/main/java/seedu/duke/flashcard/FlashcardStorage.java index 780b80ba79..d74154c3cd 100644 --- a/src/main/java/seedu/duke/flashcard/FlashcardStorage.java +++ b/src/main/java/seedu/duke/flashcard/FlashcardStorage.java @@ -6,6 +6,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Scanner; +import java.util.logging.Level; +import java.util.logging.Logger; /** * storage for flashcards @@ -14,10 +16,12 @@ public class FlashcardStorage { // simply implemented for save & load first + private static Logger flashlogger; // for logging protected String path; public FlashcardStorage(String path){ this.path = path; + flashlogger = Logger.getLogger("flash"); } @@ -34,7 +38,9 @@ public boolean isStorageAvailable(){ */ private Flashcard loadFlashcard(String[] tokens){ - assert tokens.length == 5: "Token length should be 5"; + assert tokens.length == 5 : "Token length should be 5"; + + //flashlogger.log(Level.INFO, "token length is", tokens.length); String frontText = tokens[0].trim(); String backText = tokens[1].trim(); @@ -45,6 +51,8 @@ private Flashcard loadFlashcard(String[] tokens){ Flashcard flashcard = new Flashcard(frontText, backText); + //flashlogger.log(Level.INFO, "added flashcard"); + for(String tag:tags){ if (tag.trim().equals("-")) { break; @@ -76,6 +84,9 @@ private Flashcard loadFlashcard(String[] tokens){ * @throws FileNotFoundException */ public FlashcardList loadFlashcards() throws FileNotFoundException{ + + flashlogger.log(Level.INFO, "loading flashcard"); + FlashcardList flashcardList = new FlashcardList(new ArrayList<>()); File f = new File (this.path); Scanner s = new Scanner(f); @@ -105,7 +116,8 @@ public void saveFlashcards(ArrayList flashcardList) { } fw.close(); } catch (IOException e){ - System.out.println("Failed to save."); + //System.out.println("Failed to save."); + flashlogger.log(Level.WARNING, "problem: failed to save"); } } diff --git a/src/main/java/seedu/duke/flashcard/command/DeleteAllFlashcardsCommand.java b/src/main/java/seedu/duke/flashcard/command/DeleteAllFlashcardsCommand.java new file mode 100644 index 0000000000..4fb4de3383 --- /dev/null +++ b/src/main/java/seedu/duke/flashcard/command/DeleteAllFlashcardsCommand.java @@ -0,0 +1,14 @@ +package seedu.duke.flashcard.command; + +import seedu.duke.flashcard.FlashcardList; + +import java.util.Scanner; + +public class DeleteAllFlashcardsCommand extends FlashcardCommand { + public void execute(Scanner scanner, FlashcardList flashcardList) { + flashcardList.deleteAllFlashcards(); + + System.out.println(" All your flashcards have been successfully " + + "deleted ."); + } +} diff --git a/src/main/java/seedu/duke/flashcard/command/DeleteFlashcardCommand.java b/src/main/java/seedu/duke/flashcard/command/DeleteFlashcardCommand.java new file mode 100644 index 0000000000..6d12b96cb1 --- /dev/null +++ b/src/main/java/seedu/duke/flashcard/command/DeleteFlashcardCommand.java @@ -0,0 +1,60 @@ +package seedu.duke.flashcard.command; + +import seedu.duke.flashcard.FlashcardList; + +import java.util.Scanner; + +public class DeleteFlashcardCommand extends DualFlashcardCommand { + private String input = null; + + public DeleteFlashcardCommand(String input) { + this.input = input; + beginnerCommandLength = 2; + expertCommandLength = 3; + syntaxString = "delete flashcard FLASHCARD_ID"; + } + + protected void executeBeginnerMode(Scanner scanner, + FlashcardList flashcardList) { + System.out.println(" Enter id of the flashcard you want to delete:" + + " "); + + String input = scanner.nextLine(); + int flashcardId; + + try { + flashcardId = Integer.parseInt(input); + } catch (NumberFormatException e) { + System.out.println(" Invalid input! Id must be an integer"); + return; + } + + deleteFlashcardById(flashcardId, flashcardList); + } + + protected void executeExpertMode(Scanner scanner, + FlashcardList flashcardList) { + String[] commandParts = input.split(" "); + + try { + int flashcardId = Integer.parseInt(commandParts[2]); + deleteFlashcardById(flashcardId, flashcardList); + } catch (NumberFormatException e) { + System.out.println(" Invalid id! Id must be an integer"); + } + } + + private void deleteFlashcardById(int flashcardId, FlashcardList flashcardList) { + boolean deletionWasSuccessful = + flashcardList.deleteFlashcardById(flashcardId); + + if (deletionWasSuccessful) { + System.out.println(" Flashcard with id " + flashcardId + " has been " + + "successfully deleted."); + } else { + System.out.println(" Couldn't find a flashcard with id " + flashcardId); + System.out.println(" No deletion has been performed. Please " + + "try again with a valid id."); + } + } +} diff --git a/src/main/java/seedu/duke/flashcard/command/DualFlashcardCommand.java b/src/main/java/seedu/duke/flashcard/command/DualFlashcardCommand.java new file mode 100644 index 0000000000..8d2bb119bd --- /dev/null +++ b/src/main/java/seedu/duke/flashcard/command/DualFlashcardCommand.java @@ -0,0 +1,29 @@ +package seedu.duke.flashcard.command; + +import seedu.duke.flashcard.FlashcardList; + +import java.util.Scanner; + +public abstract class DualFlashcardCommand extends FlashcardCommand { + protected int beginnerCommandLength; + protected int expertCommandLength; + protected String input; + protected String syntaxString; + + protected abstract void executeBeginnerMode(Scanner scanner, FlashcardList flashcardList); + + protected abstract void executeExpertMode(Scanner scanner, + FlashcardList flashcardList); + + public void execute(Scanner scanner, FlashcardList flashcardList) { + String[] commandParts = input.split(" "); + if (commandParts.length == beginnerCommandLength) { + executeBeginnerMode(scanner, flashcardList); + } else if (commandParts.length == expertCommandLength) { + executeExpertMode(scanner, flashcardList); + } else { + System.out.println(" Invalid syntax! The syntax is '" + syntaxString + "'"); + System.out.println(" Please try again."); + } + } +} diff --git a/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java b/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java index d70eba6cac..aa4f35117b 100644 --- a/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java +++ b/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java @@ -9,6 +9,11 @@ public class ListFlashcardsCommand extends FlashcardCommand { public void execute(Scanner scanner, FlashcardList flashcardList) { + if (flashcardList.isEmpty()) { + System.out.println(" You dont't have any flashcards yet! "); + return; + } + System.out.println(" Here is a list of all your flashcards: "); System.out.println(); diff --git a/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java b/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java index a024fe9848..3bea59c6aa 100644 --- a/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java +++ b/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java @@ -12,10 +12,17 @@ import java.util.Arrays; import java.util.Scanner; -public class StartReviewCommand extends FlashcardCommand { +public class StartReviewCommand extends DualFlashcardCommand { private final ArrayList choices = new ArrayList<>(Arrays.asList( "a", "b", "c")); + public StartReviewCommand(String input) { + this.input = input; + beginnerCommandLength = 2; + expertCommandLength = 3; + syntaxString = "review flashcards REVIEW_MODE"; + } + private String getUserChoiceReviewMode(Scanner scanner) { System.out.println(" How do you want to review your flashcards?"); System.out.println(" a) random mode"); @@ -25,17 +32,47 @@ private String getUserChoiceReviewMode(Scanner scanner) { return scanner.nextLine(); } - public void execute(Scanner scanner, FlashcardList flashcardList) { + protected void executeBeginnerMode(Scanner scanner, + FlashcardList flashcardList) { String choice = getUserChoiceReviewMode(scanner); - while (!choices.contains(choice)) { + while (!choices.contains(choice.toLowerCase())) { System.out.println(" Invalid choice! Your choice must be a, b " + "or c! Please try again."); choice = getUserChoiceReviewMode(scanner); } - ReviewMode reviewMode = createReviewMode(choice, flashcardList); + startReview(scanner, flashcardList, choice); + } + + protected void executeExpertMode(Scanner scanner, + FlashcardList flashcardList) { + String[] commandParts = input.split(" "); + + try { + String choice = commandParts[2].toLowerCase(); + + if (!choices.contains(choice)) { + System.out.println(" Invalid choice! Your choice must be a, b " + + "or c! Please try again."); + return; + } + + startReview(scanner, flashcardList, choice); + } catch (IndexOutOfBoundsException e) { + System.out.println(" Invalid syntax! The syntax is 'review " + + "flashcards REVIEW_MODE'"); + System.out.println(" Please try again."); + } + + + } + + private void startReview(Scanner scanner, + FlashcardList flashcardList, + String choice) { + ReviewMode reviewMode = createReviewMode(choice.toLowerCase(), flashcardList); if (reviewMode instanceof RandomReviewMode) { reviewMode.startReviewSession(scanner); diff --git a/src/main/java/seedu/duke/flashcard/review/ReviewDifficulty.java b/src/main/java/seedu/duke/flashcard/review/ReviewDifficulty.java index 36eaa54bbb..ded27fb269 100644 --- a/src/main/java/seedu/duke/flashcard/review/ReviewDifficulty.java +++ b/src/main/java/seedu/duke/flashcard/review/ReviewDifficulty.java @@ -4,7 +4,6 @@ public enum ReviewDifficulty { EASY, - GOOD, - HARD, - AGAIN + MODERATE, + HARD } diff --git a/src/main/java/seedu/duke/flashcard/review/ReviewMode.java b/src/main/java/seedu/duke/flashcard/review/ReviewMode.java index f1cd8ba482..85647c0ae2 100644 --- a/src/main/java/seedu/duke/flashcard/review/ReviewMode.java +++ b/src/main/java/seedu/duke/flashcard/review/ReviewMode.java @@ -6,6 +6,8 @@ import seedu.duke.flashcard.FlashcardList; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Scanner; public abstract class ReviewMode { @@ -28,7 +30,7 @@ public void startReviewSession(Scanner scanner) { printFlashcardFrontTextPrompt(flashcardToReview); String input = scanner.nextLine(); - boolean shouldTerminate = input.equals("quit") || input.equals("q"); + boolean shouldTerminate = input.startsWith("quit") || input.equals("q"); if (shouldTerminate) { break; } @@ -36,6 +38,8 @@ public void startReviewSession(Scanner scanner) { System.out.println(" The actual back text is: " + flashcardToReview.getBackText()); System.out.println(); + letUserRateReviewDifficulty(scanner, flashcardToReview); + flashcardToReview.setLastReviewOn(LocalDateTime.now()); } @@ -55,4 +59,40 @@ protected void printFlashcardFrontTextPrompt(Flashcard flashcardToReview) { "compare it, or enter 'q'/'quit' to end this " + "review session]"); } + + protected void letUserRateReviewDifficulty(Scanner scanner, + Flashcard flashcard) { + System.out.println(" How hard was it to remeber the back page of " + + "this flashcard?"); + System.out.println(" Press if it was easy, if it was " + + "moderately challenging or if it was quite hard."); + + final ArrayList choices = new ArrayList<>(Arrays.asList( + "e", "m", "h")); + String choice = scanner.nextLine(); + + while (!choices.contains(choice)) { + System.out.println(" Invalid choice! Your choice must be e, m " + + "or h! Please try again."); + + choice = scanner.nextLine(); + } + + ReviewDifficulty reviewDifficulty; + switch (choice.toLowerCase()) { + case "e": + reviewDifficulty = ReviewDifficulty.EASY; + break; + case "m": + reviewDifficulty = ReviewDifficulty.MODERATE; + break; + default: + reviewDifficulty = ReviewDifficulty.HARD; + break; + } + + FlashcardReview flashcardReview = + new FlashcardReview(LocalDateTime.now(), reviewDifficulty); + flashcard.addReview(flashcardReview); + } } diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/duke/DukeTest.java index 3f9f8bf927..2748e0373c 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/duke/DukeTest.java @@ -7,8 +7,6 @@ import seedu.duke.flashcard.FlashcardComponent; import seedu.duke.flashcard.FlashcardStorage; -import java.util.ArrayList; - class DukeTest { @Test public void sampleTest() { diff --git a/text-ui-test/ACTUAL.TXT b/text-ui-test/ACTUAL.TXT index 3cba380ccf..3631e57a32 100644 --- a/text-ui-test/ACTUAL.TXT +++ b/text-ui-test/ACTUAL.TXT @@ -1,2 +1,7 @@ -Do you choose flashcard or calendar? -Enter your command: + Failed to create directory +Failed to find files +Making New file for Flashcards + Failed to create directory +Failed to find files +Making new file for Events + Invalid command! Please try again.