Skip to content
This repository has been archived by the owner on Mar 15, 2020. It is now read-only.

Latest commit

 

History

History
1164 lines (880 loc) · 53.8 KB

DeveloperGuide.adoc

File metadata and controls

1164 lines (880 loc) · 53.8 KB

NUStudy Developer Guide

By: AY1920S1-CS2103T-F11-4 Since: September 2019 Licence: MIT

NUStudy is an application for managing three kinds of informational material: lecture notes, quizzes and revision tasks. It helps users to prepare for exams and tests in university by facilitating their learning.

As a developer of NUStudy, this guide can help you understand the basic software architecture and design considerations for its implementation so that you can start contributing in no time.

For any queries, simply contact us.

ℹ️
In this document, monospaced texts may have different meanings. If the text is in PascalCase i.e. first letter of each word is capitalised, such as Logic, then the text is a class or interface name. If the text has a bracket such as execute("delete 1"). Otherwise, the monospaced texts are meant for highlighting or user commands depending on the context.

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

The architecture diagram below gives an overall view of NUStudy’s structure. Each component will be explained in more detail in the coming sections.

ArchitectureDiagram
Figure 1. Architecture Diagram

Main has two classes called Main and MainApp. It is responsible for initializing and shutting down the application, linking and cleaning up where necessary.

The commons package contains classes used by multiple other components, of which LogsCenter is important as it is used for logging. The rest of NUStudy consists of four primary components.

  • UI: The UI of NUStudy.

  • Logic: The command executor.

  • Model: Holds application data in memory.

  • Storage: Reads and writes data to disk.

Each of the four components defines its API in an interface with the same name as the component and exposes the API using a {Component Name}Manager class. For example, the Logic component (see the class diagram given below) defines its API in the Logic.java interface and exposes its functionality using the LogicManager.java class.

LogicClassDiagram
Figure 2. Class Diagram of the Logic Component

Inter-component interaction

The sequence diagram below shows how the components interact with each other for the scenario where the user issues the command deletenote 1.

ArchitectureSequenceDiagram
Figure 3. Component interactions for delete 1 command

2.2. UI

UiClassDiagram
Figure 4. Class diagram of the UI component
PanelPackageClassDiagram
Figure 5. Detailed class diagram for Panels package

API: Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, NoteListPanel, StatusBarFooter, etc. All these, including the MainWindow, inherit from the abstract UiPart class.

The UI component uses JavaFX. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml

This component

  • executes user commands using the Logic component.

  • listens for changes to Model data so that the UI can be updated with the modified data.

2.3. Logic

LogicClassDiagram
Figure 6. Class diagram of the Logic component

API: Logic.java

  1. Logic uses the AppDataParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a person).

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

  5. In addition, the CommandResult object can also instruct the Ui to perform certain actions, such as displaying help to the user.

Given below is the sequence diagram for interactions within the Logic component for the execute("delete 1") API call. The lifeline for DeleteCommandParser should end at the destroy marker × but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

DeleteSequenceDiagram
Figure 7. Interactions inside the Logic component for the deletenote 1 command

2.4. Model

ModelClassDiagram
Figure 8. Class diagram of the Model component

API: Model.java

The Model component is independent of the other three primary components of NUStudy. It stores application data – notes, questions and revision tasks – as well as a UserPrefs object representing the user’s preferences. It also exposes an unmodifiable ObservableList<Note> that is bound to the UI, so any data changes are immediately user-visible.

2.5. Storage

StorageClassDiagram
Figure 9. Class diagram of the Storage component

The Storage component reads and writes UserPrefs objects and NUStudy data in JSON format.

3. Implementation

This section describes some finer details on how certain features are implemented.

3.1. Image support for lecture notes

Usually, we do not learn best from just text; we rely on images that our minds can process more easily. As such, implementing images in lecture notes is a very important feature for NUStudy.

Although some lecture notes have multiple images, it is always possible to combine them using basic image editing software like the GNU Image Manipulation Program (GIMP) and Paint, so the implementation is limited to at most one image per note. Having a common format for notes facilitates their retrieval through the findnote command and aids a human user in remembering what the notes say.

3.1.1. Implementation

Instead of a custom class to represent an image, JavaFX’s scene.image.Image is used instead. This is out of necessity, since an ImageView is needed to display an image in the GUI and it requires an Image object, not just a String path to the image. No significant coupling is introduced by this choice because Image objects can exist without a GUI to display them.

The static method selectImage() in AppUtil opens up a dialog allowing the user to choose the necessary image. This is possible because FileChooser#showOpenDialog(), which shows the dialog, can be fed an argument of null instead of having to rely on a Window object, which is the domain of the UI module.

The aforementioned dialog returns null if it is closed without choosing a file (i.e. clicking the close button). We interpret this as "no change" rather than "no image", i.e. addnote and editnote proceed as if i/ was not provided. If the "no image" interpretation was used, the user who decides to edit a lecture note’s image but then decides not to would be surprised to see the image disappear without warning. Therefore the value i/none has to be explicitly provided in editnote to remove the image; EditNoteDescriptor has the field isImageRemoved to track this.

We also defer image selection until after the title has been checked against existing lecture notes, which saves time that would otherwise be wasted in navigating to the desired image. This is accomplished using three things:

  • the finalizeImage() method of the Note class, calling selectImage()

  • the needsImage field of Note, which allows a one-time execution of finalizeImage()

  • the isImageReplaced field of EditNoteDescriptor

ImageSelectionSequenceDiagram
Figure 10. Sequence diagram for the execution of EditNoteCommandParser

The diagram above shows how EditNoteCommandParser creates an EditNoteCommand. It first creates an EditNoteDescriptor to hold details of what changes in the note, setting the new title (provided by the t/ argument) and content (c/) as necessary. If i/none is present, the EditNoteDescriptor is set to remove the image. If i/ is provided, it is set to replace the image. An EditNoteCommand containing the EditNoteDescriptor is finally returned for execution.

Images are only referenced, not embedded, in the JSON file holding application data. These references are Uniform Resource Identifiers (URIs) of system files, e.g. file:data/picture.png. Since NUStudy is meant to be portable, we cannot use absolute paths, since they would break when the images are moved or deleted. Instead we copy images into application data using finalizeImage(), which points references to these local copies.

3.1.2. Design considerations: where to place the image?

  • Alternative 1 (current choice): We show the images associated to each and every lecture note in the first column, together with the title and content.

    • Pros: This is easier to implement, for the code interfacing with FXML does not have to be written in places other than those directly pertaining to notes. It also makes the note "card" (object representing the note) self-contained.

    • Cons: Scrolling through lecture notes, all with images, takes time, but this downside is alleviated by the findnote command.

  • Alternative 2: We place one full note in the second column and only show a preview (the title and first words of the content) in the first column.

    • Pros: This behaviour is closer to notepad applications on mobile devices which show a list of notes. It saves space in the list and gives more prominence to a selected note, turning it into a flash card.

    • Cons: The second column, normally housing revision tasks, requires extra code to handle the display of full notes. This may include a separate NotePreview class, or Note may have a variable toggling between preview and full modes.

3.1.3. Design considerations: when to copy images into the local folder

  • Alternative 1 (current choice): We copy images when the command is executed, i.e. in Command#execute().

    • Pros: This effects a better separation of concerns – image selection is not execution of the command, while copying can be a side effect of command execution. Individual command effects can be fine-tuned.

    • Cons: Each command that copies images needs to have its own code implementing the copy. To reduce code duplication, that common code can be written as a method of the Note class requiring a Path object representing the destination folder for the copy.

  • Alternative 2: We copy images when the image is selected, i.e. in AppUtil#selectImage().

    • Pros: Compared to alternative 1, this takes less time between image selection and writing into application data, minimising the chance of exceptions due to changes in the file system (permissions, existence of the file at the specified path, etc.) being raised.

    • Cons: selectImage() has two only loosely related responsibilities in this alternative, which is a worse separation of concerns. It is impossible to take into account user preferences at the point of image selection, since it requires a Model object which is not available to AppUtil#selectImage().

3.2. Question management feature

3.2.1. Current implementation

The question management feature is facilitated by Model. The question-related commands extend Command with the question object if necessary. The commands update the Model which is implemented by ModelManager. This in turn updates AppData which stores all the questions internally as UniqueQuestionList. Local data will be updated in the end by LogicManager. The commands include:

  • AddQuestionCommand — Adds a new question to the app.

  • DeleteQuestionCommand — Deletes an existing question in the app.

  • ListQuestionCommand — Views the list of all questions available.

  • EditQuestionCommand — Edits an existing question in the app. (to be implemented)

  • FindQuestionCommand — Finds a question with a specified keyword. (to be implemented)

These operations are exposed in the Model interface as Model#addQuestion(Question question), Model#deleteQuestion(Question question), Model#getFilteredQuestionList() and Model#setQuestion(Question target, Question editedQuestion) respectively.

Given below is an example usage scenario and how the question mechanism behaves at each step.

Step 1. The user launches the application for the first time. The app will load all existing information from storage.

Step 2. The user executes addq q/QUESTION a/ANSWER s/SUBJECT d/DIFFICULTY command to add a new question to the app. The addq command calls Model#addQuestion(Question question), causing the AppData to be updated with the new question.

Step 3. The user executes deleteq 5 command to delete the 5th question in the app. The deleteq command calls Model#deleteQuestion(Question target) and Model#updateFilteredQuestionList(Predicate<Question> predicate), causing the AppData to be updated with the target question removed.

Step 4. The user executes editq 2 a/NEW_ANSWER command to edit the answer of the 2nd question in the app. The editq command calls Model#setQuestion(Question target, Question editedQuestion) and Model#updateFilteredQuestionList(Predicate<Question> predicate), causing the AppData to be updated with the original question being replaced by the edited question.

The following sequence diagram shows the interaction between classes when EditQuestionCommand#execute(model) is called:

EditQuestionCommandExecuteSequenceDiagram
Figure 11. Sequence diagram for execute(Model) of EditQuestionCommand

The following activity diagram summarizes what happens when a user executes a new addq command:

AddQuestionActivityDiagram
Figure 12. Activity diagram for addq command

Question is implemented as a concrete class with its relevant fields consist of QuestionBody, Answer, Subject, and Difficulty.

The following class diagram illustrates how Question class is designed:

QuestionClassDiagram
Figure 13. Class diagram for Question
Design considerations: How addq/deleteq/editq commands execute
  • Alternative 1 (current choice): Update the internal storage UniqueQuestionList in AppData first, then save the updated appData in local storage when the command finishes executing.

    • Pros: Easy to implement.

    • Cons: Need the extra step to ensure that the internal list is correctly maintained.

  • Alternative 2: Update the local storage directly when the command is executing.

    • Pros: No need to implement the internal list.

    • Cons: Will access local memory more frequently. May have performance issues in terms of memory usage.

Design considerations: Data structure to support the question commands
  • Alternative 1 (current choice): Use a UniqueQuestionList to store questions in AppData.

    • Pros: Cater to the question model specifically. Question list operations are encapsulated in one class.

    • Cons: Logic is duplicated as other models also implement similar list structure.

  • Alternative 2: Use Java list to store the questions.

    • Pros: Do not need to maintain a separate list class.

    • Cons: Violates Single Responsibility Principle and Separation of Concerns as the model needs to maintain various list operations.

3.3. Quiz mode for revision

3.3.1. Implementation

The quiz mode feature is facilitated by Model. The quiz-related commands extend Command with specific question object. The commands update the Model which is implemented by ModelManager. This in turn updates AppData which stores filtered specific questions internally as QuizQuestionList. Local data will be updated in the end by LogicManager. The commands include:

  • QuizModeCommand — Enters the quiz mode with questions selected by user.

  • QuizCheckAnswer — Checks the correctness of answer entered by user.

  • QuizShowAnswerCommand — Shows the answer for current question.

  • QuizSkipQuestion — Skips the current question.

  • QuitQuizModeCommand — Quits the quiz mode.

These operations are exposed in the Model interface as Model#getQuizQuestions(int numOfQuestions, Subject subject Difficulty difficulty), Model#setQuizQuestionList(ObservableList<Question> quizQuestionList), Model#showQuizAnswer(), Model#getFilteredQuizQuestionList(), Model#checkQuizAnswer(Answer answer), Model#removeOneQuizQuestion() and Model#clearQuizQuestionList() respectively.

Given below is an example usage scenario and how the question mechanism behaves at each step.

Step 1. The user launches the application for the first time. The app will load all existing information from storage.

Step 2. The user executes quiz n/NUMBER OF QUESTIONS d/DIFFICULTY s/SUBJECT command to enter quiz mode of the app. The quiz command calls Model#getQuizQuestions(int numOfQuestions, Subject subject Difficulty difficulty) and Model#setQuizQuestionList(ObservableList<Question> quizQuestionList), causing the AppData to be updated with a list of specific question selected by user for quiz.

Step 3. The user types answer to answer the question. It calls Model#checkQuizAnswer(Answer answer) and Model#addQuizResult(QuizResult quizResult), causing the AppData to be updated with the result of the answer.

The following graph explains how QuizResult class is designed:

QuizResultClassDiagram
Figure 14. QuizResultClassDiagram

Step 4. The user executes show command to show the answer of current quiz question in the app. The show command calls Model#showQuizAnswer(), causing the AppData to display the answer on the Ui.

Step 5. The user executes skip command to skip the current quiz question in the app. The skip command calls Model#removeOneQuizQuestion(), causing the AppData to display the next quiz question on the Ui.

Step 6. The user executes quit command to exit from the quiz mode. The quit command calls Model#clearQuizQuestionList(), causing the AppData to clear all quiz question list and return to normal mode.

The following sequence diagram shows how the quiz operation works:

QuizModeSequenceDiagram
Figure 15. QuizModeSequenceDiagram

The following activity diagram summarizes what happens when a user executes a new command for quiz:

400
Figure 16. QuizModeActivityDiagram

3.3.2. Design Considerations

Aspect: How to store the quiz results
  • Alternative 1 (current choice): Update the internal storage QuizResultList in AppData first, then save the updated appData in local storage when the command finishes executing.

    • Pros: It is easier to implement.

    • Cons: It needs the extra step to ensure that the internal list is correctly maintained.

  • Alternative 2: Update the local storage directly when the command is executing.

    • Pros: There is no need to implement the internal list.

    • Cons: The access to local memory is more frequent and it may have performance issues in terms of memory usage.

Aspect: What data structure is used to support the quiz commands
  • Alternative 1 (current choice): Use QuizQuestionList and QuizResultList to store data in AppData.

    • Pros: It is targeted to the quiz model specifically. Quiz question and result list operations are encapsulated in one class.

    • Cons: Logic is duplicated as other models also implement similar list structure.

  • Alternative 2: Use Java list to store the quiz questions and results.

    • Pros: There is no need to maintain a separate list class.

    • Cons: It violates Single Responsibility Principle and Separation of Concerns as the model needs to maintain various list operations.

3.4. Statistics feature

3.4.1. Implementation

The statistics feature gathers data stored from quizzes done in NUStudy to analyse and return an output. The different commands supported by the statistics feature are used to filter the type of statistics the user wants. These commands include:

  • GetQnsCommand — Gets all questions answered correctly/incorrectly.

  • GetReportCommand — Returns a report of the specified question.

  • GetStatisticsCommand — Returns a pie chart containing a break down of the questions by its results.

  • GetOverviewCommand — Gets an overview of the types of questions that have been attempted overall.

Given below is an example usage scenario and how the statistics mechanism behaves at each step.

Step 1. The user launches the application. The app will attempt to read past data from any quizzes done and store it internally to a quizResults list.

Step 2. The user enters stats s/CS2103T to get the statistics of all quiz questions done for CS2103T. A GetStatisticsCommand will be created. When it is executed from the MainWindow, it returns a new CommandResult with command type: STATS.

The following class diagram shows how the GetStatisticsCommand and CommandResult classes are related.

StatisticsClassDiagram
Figure 17. Class diagram for GetStatisticsCommand

Step 3. After CommandResult is returned to MainWindow, it will call a showStats method to create a pie chart. It will then show a statistics panel, hiding all notes, tasks and questions.

The following sequence diagram shows how the UI handles the GetStatisticsCommand:

StatisticsSequenceDiagram
Figure 18. UI sequence diagram for GetStatisticsCommand

Step 4. The user now wants to stop viewing statistics and decides to view all notes, tasks and questions again using the listnote command. The statistics panel will now be hidden.

The following activity diagram summarizes what happens when a user executes the statistics command:

StatisticsActivityDiagram
Figure 19. Statistics activity diagram

3.4.2. Design Considerations

Aspect: Where statistics are shown
  • Alternative 1 (current choice): Hide all other panels and only show statistics.

    • Pros: Less scrolling will be needed and more information can be shown in one panel.

    • Cons: More methods are needed to deal with hiding and showing the different panels leading to more room for errors.

  • Alternative 2: Allocate a spot in the main window with the notes, tasks and questions for statistics to be displayed.

    • Pros: It is easy to implement.

    • Cons: The number of notes, tasks and questions that can be seen without scrolling will be decreased. The charts will be small and condensed making it difficult to see the data at first glance.

Aspect: How statistics are represented
  • Alternative 1 (current choice): Use a pie chart.

    • Pros: It is easy to read at a glance.

    • Cons: Pie chart slices may get too small to see if there are too little correct/incorrect questions done.

  • Alternative 2: Use a grouped bar chart.

    • Pros: The questions done are sorted by subjects, thus it is more informative.

    • Cons: As the number of subjects increases, the bars get thinner making it more difficult to see the data. This is also more difficult to implement.

3.5. Revision task management

Revision task management involves addition, deletion, editing, searching and many other operations on tasks. This section explains how task management features are implemented.

3.5.1. Implementation

Revision task management is facilitated by Model. Commands related to task manipulation extend Command class. The commands update the Model interface which is implemented by ModelManager class. The ModelManager then updates AppData which stores all the revision tasks in an internal data structure TaskList. TaskList is essentially an ObservableList of Task. Local data will be updated in the end by LogicManager.

The revision task management commands include:

  • AddTaskForNoteCommand — Adds a new task for revising note to the app.

  • AddTaskForQuestionCommand — Adds a new task for revising question to the app.

  • ClearTaskCommand — Clears all tasks in the app.

  • DeleteTaskCommand — Deletes a task from the app.

  • DoneTaskCommand — Marks a task as done.

  • EditTaskCommand — Edits fields of a task.

  • FindTaskCommand — Searches for a task with given information.

  • ListAllTaskCommand — Displays all tasks to the user.

  • ListDoneTaskTaskCommand — Displays tasks that have been done to the user.

  • ListNotDoneTaskCommand — Displays tasks that have not been done to the user.

  • ListOverdueTaskCommand — Displays tasks that have passed the scheduled time to the user.

These operations are exposed in the Model interface as Model#addTask(Task task), Model#hasTask(Task task), Model#clearTaskList(), Model#deleteTask(Task target), Model#markTaskAsDone(Task taskDone), Model#setTask(Task target, Task editedTask), Model#updateFilteredTaskList(Predicate<Task> predicate) and Model#getFilteredTaskList() respectively.

Taking AddTaskForNoteCommand as an example, the following process illustrates the mechanism of adding a revision task for note to the task list (adding a revision task for question has a similar command but different parameters).

Step 1. The user enters command rn t/UML diagram dt/01/01/2019 tm/1200 for adding a task for note. The command is parsed by AddTaskForNoteCommandParser. AddTaskForNoteParser then creates an AddTaskForNoteCommand. The high-level logic of parsing and creating the command is similar to the process of deleting a note from the note list as illustrated by the sequence diagram for deleting a note. However, the execution stage of AddTaskForNoteCommand differs from that of deleting a note.

Step 2. The Logic Manager calls Command#execute(Model) which essentially calls AddTaskForNoteCommand#execute(Model) because of polymorphism.

Step 3. AddTaskForNoteCommand calls its own private method hasValidNote(Model) which checks if the Note with Title "UML diagram" exists in Model. If not, a CommandException will be thrown and execute(Model) stops because non-existing note title is not allowed to be the heading of any tasks.

Step 4. AddTaskForNoteCommand calls Model#hasTask(Task) to check whether the Model has a task identical to the one the user is adding. If there is an existing identical task, a CommandException will be thrown and execute(Model) stops to avoid duplicate tasks.

Step 5. AddTaskForNoteCommand calls Model#addTask(Task) to add the new task to the Model. Model calls AppData#addTask(Task) to add the task to AppData which keeps track of all data of the app. AppData then calls TaskList#add(Task) to add the task to TaskList, which is the underlying data structure storing tasks.

Step 6. A CommandResult is created and returned to the LogicManager to inform the user of successful addition of a new task to the revision plan.

The following sequence diagram illustrates the interaction between classes when calling AddTaskForNoteCommand#execute(Model).

AddTaskForNoteCommandExecuteSequenceDiagram
Figure 20. Sequence diagram for execute(Model) of AddTaskForNoteCommand

Zooming in to Step 3, when calling hasValidNoteForTask(Model), AddTaskForNoteCommand creates a new Note with a Title "UML diagram" and a Content "dummy entry". The entry of Content is not important because AddTaskForNoteCommand only records the Title of a Note and the existence of a Note is checked against its Title only (if the title is in the note list, then the note exists in the list). The detailed process is illustrated by the sequence diagram below.

HasValidNoteSequenceDiagram
Figure 21. Sequence diagram for checking existence of a Note in the model when AddTaskForNoteCommand calls its own hasValidNoteForTask(Model)

The following activity diagram summarizes the whole process of adding a task for note.

AddTaskForNoteActivityDiagram
Figure 22. Activity diagram for adding a task for note

3.5.2. Design considerations

Aspect: Design of Task
  • Alternative 1 (current implementation): We implement Task as a concrete class with two subclasses to support task for notes and questions respectively.

    • Pros: It supports different behaviours of task for Note and task for Question by polymorphism. The concrete Task class will also allow adding of general tasks in v2.0.

    • Cons: We need to implement two different AddTask commands to support addition of the two different types of tasks. Hence we need to write more pieces of code.

The class diagram below illustrates how Task class is designed:

TaskClassDiagram
Figure 23. Design of Task class
  • Alternative 2: We design Task as an interface to be implemented by two different classes.

    • Pros: This approach is better in data hiding. The client classes know less information about internal properties of Task.

    • Cons: We need to implement all methods in the interface and hence more code snippets are needed. Both implementing classes have to include the field in common such as isDone, which results in duplicate code snippets.

  • Alternative 3: We wrap everything in one concrete Task class to support both lecture notes and questions.

    • Pros: We need to write less code.

    • Cons: It violates the principle of Separation of Concern, making it hard to maintain or extend in the future if more types of tasks are needed.

Aspect: Design of command for adding a task
  • Alternative 1 (current implementation): We implement the command as two independent classes, namely AddTaskForNoteCommand and AddTaskForQuestionCommand to support adding TaskForNote and TaskForQuestion respectively.

    • Pros: The two types of commands, although similar in logic, receive different parameters and interact with different classes (one interacting with TaskForNote while another one interacting with TaskForQuestion). Therefore, it is better to separate the concerns by implementing the commands as two separate classes. If TaskForNote and TaskForQuestion classes deviate more significantly in the future in terms of their behaviour, this approach makes it easier to maintain the adding commands.

    • Cons: We need to write more code. There might be some duplicate code snippets involving the logic shared by both commands. We also need to implement different parsers for the two commands, which involes some extra work.

  • Alternative 2: We implement only one class of adding command to support both TaskForNote and TaskForQuestion.

    • Pros: We can write less code as there would be fewer duplicate code snippets and we do not need to implement separate command parsers.

    • Cons: This approach leads to lower level of abstraction as all concerns of Task, regardless of TaskForNote or TaskForQuestion, are wrapped into the same class. It could be difficult to maintain if the behaviors of TaskForNote and TaskForQuestion get more complex and diverse.

3.6. Logging

We use java.util.logging for logging. The LogsCenter class is used to manage the logging levels and destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (see Section 3.7, “Configuration”).

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class), which will log messages according to the specified logging level.

  • Log messages are written to the console and to a .log file.

Logging levels

  • SEVERE: Indicates a critical (potentially fatal) problem with NUStudy.

  • WARNING: After this incident NUStudy may continue, but with caution.

  • INFO: Informational reports about actions taken by NUStudy.

  • FINE: Strictly only useful for debugging purposes, records all data processed by NUStudy.

3.7. Configuration

The user preferences file location and logging level can be set through the configuration file, by default config.json.

4. Documentation

Refer to the guide here.

5. Testing

Refer to the guide here.

6. DevOps

Refer to the guide here.

Appendix A: Product Scope

Target user profile:

  • has a need to manage a significant number of notes

  • has a need to test contents of notes

  • prefers desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

Value proposition: Revise more efficiently with spaced repetition and active recall compared to a typical note-taking app

Appendix B: User Stories

Priorities:

  • High (must have) – * * *

  • Medium (nice to have) – * *

  • Low (will be implemented in v2.0) – *

Priority As a/an…​ I want to…​ So that I can…​ Author

* * *

student

share and receive lecture content from others

my friends can share in the common knowledge, and my family can understand what I am studying

Jeremy

* * *

student

annotate my lecture notes

I can go beyond the curriculum

Jeremy

*

module coordinator

brief my subordinates about study materials

the tutors/lecturers under my charge are teaching what they are supposed to teach

Jeremy

*

tutor

discuss the key points to remember from a tutorial

my students get as much out of their tutorials as possible

Jeremy

* *

quizmaster

quiz contestants about their knowledge using the app

the contestants can have as much fun as possible

Jeremy

* * *

student

set a revision plan and add tasks to my plan

I can be more organised in my revision and will not lose my focus

Shui Yao

* * *

student

remove a revision task

I can remove accidentally added revision task or remove a revision task should there be a change of plan

Shui Yao

* * *

student

edit the revision task

I can modify the details of a particular revision task in case I messed up some information

Shui Yao

* *

student

mark a task as done

I can update the status of my revision plan and have greater motivation to move on

Shui Yao

* * *

student

view my revision plan

be more clear on the big picture of my revision and check whatever is left to do when I forget

Shui Yao

* *

student

view unfinished tasks

I can have a easy overview of what I need to to next

Shui Yao

* *

student

view overdue tasks

I can re-schedule my revision and be more careful with the workload in my next planning

Shui Yao

*

student

get notified when a revision task is about to start

I can finish up whatever stuff at hand and get ready for revision

Shui Yao

*

student

disable notification

I will not be bothered in some important events

Shui Yao

* * *

student

change the difficulty level of questions

I can customize the difficulty level of the questions as I progress along the time

Xueting

* * *

student

find all the questions at a particular difficulty level

I can see how well I understand the subject content

Xueting

*

student

set a mix of different difficulty levels at exam mode

I can better simulate the real-time exams conditions

Xueting

* *

student

get a statistics of the number of questions I have attempted at a difficulty level

I can see how often I have practiced for this subject

Xueting

* *

student

get statistics of the accuracy level of the specific difficulty

I can visualise how well I have practiced for this subject

Xueting

*

student

get statistics of the change of difficulty levels I have made to a question

I can understand my improvement in understanding the content

Xueting

* * *

student

see how well I am able to answer questions for different subjects

focus more on subjects that I need to improve on

Irene

* * *

student

check my past responses to different questions

compare with my current response and improve on it if necessary/check if I am making the same mistakes twice

Irene

* *

student

have a graphical report of my progress

get an overview of my progress with a glimpse

Irene

* *

student

get an overview to see the number of questions I have done for the different subjects/difficulties

I can see which subjects/difficulties I need to attempt more questions of

Irene

*

student

check the questions that I have attempted for a specific time period

I can skip questions that I have already done during that time period

Irene

*

student

mark and store the questions I have made mistakes on

I can get a better understanding of which part I need to put more time to study

Dongjun

* * *

student

take a series questions as a mock test before exam

I can refresh my memory on different modules before exam

Dongjun

* *

student

find specific questions according to the keywords

I can filter the questions I want for different purposes

Dongjun

* * *

student

change the difficulty of my test

I can be better prepared for actual exam

Dongjun

* *

student

view all questions and answers stored

I can refer them as revision guide according to different subjects

Dongjun

Appendix C: Use Cases

(For all use cases below, the system is NUStudy and the actor is the student)

Use case: Create lecture note (Jeremy)

MSS

  1. Student gives the command to add a lecture note – addnote t/TITLE c/CONTENT

  2. Application shows a lecture note with the given title and contents to the user

  3. Application also updates the lecture note list with the new note

Use case ends

Extensions

  • 1a. Student also gives i/ in the command

    • 1a1. Application brings up a file selection dialog

    • 1a2. Student selects the image they wish to include in the lecture note

    • 1a3. Application accepts the image

  • Use case resumes from step 2

  • 1a2a. The selected file is not an image (.png, .jpg, .gif)

    • 1a2a1. Application displays message about the supported file formats

    • 1a2a2. Student selects a file again

    • Repeat 1a2a1, 1a2a2 until a supported file format is selected

  • Use case resumes from step 1a3

Use case: Delete lecture note (Jeremy)

MSS

  1. Student gives the command to delete a lecture note – deletenote INDEX

  2. Application deletes the note from the note list

Use case ends

Extensions

  • 1a. Student gives an out-of-range or non-numeric index

    • 1a1. Application displays message showing in-range indices

    • 1a2. Student re-enters the command

    • Repeat 1a1 and 1a2 until a valid index is provided

  • Use case resumes from step 2

Use case: Add a revision task for note to revision plan (Shui Yao)

Preconditions: lecture note list is not empty

MSS

  1. Student keys in revision task command and specifies the title of the note he/she wants to add to revision plan, with starting date and starting time

  2. NUStudy adds the task to revision plan

  3. NUStudy informs the Student about successful addition of the task

Use case ends

Extensions

  • 1a. NUStudy detects missing entry for note title

    • 1a1. NUStudy requests for input of note title

    • 1a2. Student enters correct input

    • Steps 1a1 - 1a2 are repeated until the input is valid

  • Use case resumes from Step 2

  • 1b. NUStudy detects a note title entry that is non-existent in the note list

    • 1b1. NUStudy requests for a valid input of note title (a note that exists in the note list)

    • 1b2. Student enters valid note title

    • Steps 1b1 - 1b2 are repeated until the input is valid

  • Use case resumes from Step 2

  • 1c. NUStudy detects missing starting date or time

    • 1c1. NUStudy requests for correct input with starting date and time

    • 1c2. Student enters correct input following the format

    • Steps 1c1 - 1c2 are repeated until getting a correct input with valid starting date and time

  • Use case resumes from Step 2

  • 1d. NUStudy detects invalid date or time

    • 1d1. NUStudy requests for valid date and time

    • 1d2. Student enters correct input with valid date and time

    • Steps 1d1 - 1d2 are repeated until getting a correct input with valid date and time

  • Use case resumes from Step 2

Use case: Delete a task from revision plan (Shui Yao)

MSS

  1. Student requests to list revision plan

  2. NUStudy lists the revision plan

  3. Student specifies the index of the task in the revision plan list

  4. NUStudy removes the task from the revision plan

  5. NUStudy informs the Student about the successful removal of the task

Use case ends

Extensions

  • 1a. NUStudy detects that the revision plan has no tasks

    • 1a1. NUStudy informs the Student that the revision plan is empty

  • Use case ends

  • 3a. NUStudy detects an index that is not in the revision plan

    • 3a1. NUStudy requests for correct input with valid index

    • 3a2. Student enters correct input with valid index

    • Steps 3a1 - 3a2 are repeated until getting a valid index

  • Use case resumes from Step 2

Use case: Clear the revision plan (Shui Yao)

MSS

  1. Student clears the revision plan

  2. NUStudy clears the revision plan

  3. NUStudy informs the Student that the revision plan is successfully cleared

Use case ends.

Use case: Get statistics for subjects (Irene)

MSS

  1. Student gives the command to get the statistics for a difficulty and some subjects stats [d/DIFFICULTY] [s/SUBJECT1] [s/SUBJECT2]…​

  2. Application returns a pie chart with number of questions answered correctly and incorrectly

Use case ends

Extensions

  • 1a. Student provides an invalid difficulty or invalid subjects

    • 1a1. Application will inform students that there are no statistics for that difficulty/subjects

    • 1a2. Student will re-enter the command

    • Repeat 1a1 and 1a2 until valid difficulty/subjects is/are provided

  • Use case resumes from step 2

Use case: Get report of individual questions (Irene)

MSS

  1. Student gives the command to get report of a question report INDEX

  2. Application returns past attempts of the question and statistics of how well the question has been answered

Use case ends

Extensions

  • 1a. Student gives an out-of-range index

    • 1a1. Application displays a message indicating that the index is invalid

    • 1a2. Student re-enters the command

    • Repeat 1a1 and 1a2 until a valid index is provided

  • Use case resumes from step 2

  • 1b. Student does not provide an index

    • 1b1. Application displays a message indicating that the command format is invalid

    • 1b2. Student re-enters the command

    • Repeat 1b1 and 1b2 until a valid index is provided

  • Use case resumes from step 2

Use case: Add a question to question bank in NUStudy (Xueting)

MSS

  1. Student keys in add question and specifies the relevant fields - add q/QUESTION a/ANSWER s/SUBJECT d/DIFFICULTY

  2. Application adds the question with its fields.

  3. Application informs the user about the success addition of question.

Use case ends

Extensions

  • 1a. Student does not specify the difficulty level

    • 1a1. Application shows an error message to require difficulty level input

    • 1a2. Student inputs the difficulty level

    • Repeat 1a1 and 1a2 until a difficulty level is provided

  • Use case resumes from step 2

Use case: Delete a question (Xueting)

MSS

  1. User requests to view a list of questions from another command (eg. findq, difficulty, subject).

  2. Application shows the list of questions retrieved from this command.

  3. User enters the delete command with the index of the question to be deleted.

  4. Application removes the question from the question bank.

  5. Application informs the user about the success of deletion.

Use case ends

Extensions

  • 1a. There is no question listed from the previous command.

    • 1a1. Application informs the user that the index is invalid since the question list is empty.

  • Use case ends

  • 1b. Student inputs invalid index for a question (either negative or out of range).

    • 1b1. Application shows an error message to inform the user that the index is invalid.

    • 1b2. Student re-enter the command by providing a valid index.

    • Repeat 1b1 and 1b2 until valid index is provided

  • Use case resumes at step 2

Use case: Edit difficulty level of a specific question (Xueting)

MSS

  1. Student changes the difficulty level of a question - edit -dif id/INDEX d/DIFFICULTY

  2. Application shows and stores the question with the updated difficulty level

Use case ends

Extensions

  • 1a. Student does not provide the updated difficulty level

    • 1a1. Application shows an error message to require difficulty level update

    • 1a2. Student inputs the new difficulty level

    • Repeat 1a1 and 1a2 until a difficulty level is provided

  • Use case resumes at step 2

  • 1b. Student provides the same difficulty level as the previous one

    • 1b1. Application shows a warning message indicating that the difficulty level is not updated and ask whether the user would like to proceed

    • 1b2. Student chooses either to proceed with the original difficulty level or re-edit the difficulty level

  • Use case resumes at step 2

  • 1c. Student inputs an invalid (out of range or non-numeric) questions index

    • 1c1. Application displays the range of valid question indices

    • 1c2. Student re-enters the question index

    • Repeat 1c1 and 1c2 until a valid index is provided

  • Use case resumes at step 1

Use case: Take a quiz (Dongjun)

MSS

  1. Student gives the command to enter the test mode quiz [n/NUMBER_OF_QUESTIONS] [d/DIFFICULTY] [s/SUBJECT]

  2. Application shows a question with difficulty and subject indicated

  3. Application waits for the student to key in the answer

  4. Student enters the answer

  5. Application displays whether the input answer is correct or wrong

  6. Repeat 2 - 5 until all questions are answered

Use case ends

Extensions

  • 1a. Student inputs the invalid quiz command

    • 1a1. Application returns the correct format for quiz command

    • 1a2. Students enter the correct quiz command

  • Use case resumes from step 1

  • 3a. Student chooses to skip current questions by giving skip

    • Application skips this question and display the next question

  • Use case resumes from step 2

  • 3b. Student chooses to get the answer for current question by giving show

    • 3b1. Application displays the answer

  • Use case resumes from step 2

  • a. At any time, Student chooses to exit from the quiz

    • a1. Student gives the command quit

    • a2. Application exits from the quiz mode

  • Use case ends

Appendix D: Non-functional requirements

  1. Images must be copied into the application data, residing in a dedicated folder, rather than merely linking to somewhere on the filesystem

  2. Export format of lecture notes and flash cards must be human-readable text

  3. Images must be referenced by pathnames with respect to the image folder

  4. Charts returned by statistics feature must be simple enough that it is universally understood

Appendix E: Glossary

Lecture note

An object stored in the application model that includes a title, text content and optionally an image. It is not quizzable.

Appendix F: Manual testing

A few ways of manually testing NUStudy are listed below. Of course, any tester should explore more than just these.

F.1. Opening and closing

  1. Initial launch

    1. Download the JAR file and copy into an empty folder.

    2. Open the jar file. The GUI with some initial application data should be visible.

  2. Saving window preferences

    1. Change the position and size of the window and close it.

    2. Re-launch NUStudy. It should look just like when it was closed.

F.2. Image support

  1. Adding a lecture note with an image

    1. Type addnote t/t c/c i/ in the command line. An image dialog should be brought up.

    2. Select any image. It should appear in the lecture note panel, as a new lecture note with title "t" and content "c".

  2. Modifying an image

    1. After adding one lecture note with an image, type editnote i i/ where i is its index.

    2. The same image dialog should be brought up; select a different image. This image should appear in place of the old image, if any, even if the filename is the same.

  3. Local copy of images

    1. Close the application and move the JAR file and its associated application data to another location.

    2. Relaunch the application. Images should display as before.

  4. Silent ignoring of broken images

    1. Once lecture notes with images have been added, close NUStudy and delete all images in its data folder.

    2. Relaunch the application. The app should not throw an exception, merely not display any images.

    3. Add back the images to the lecture notes using editnote. This operation should succeed.

F.3. Question management

  1. Adding a question with all necessary fields

    1. Type addq q/MVC design pattern refers to ( ). a/Model View Controller s/CS2103T d/Medium in the command line.

    2. The application will show the success of adding the question if all fields are present and valid.

  2. Editing a question

    1. Type editq 1 d/Hard to change the difficulty of the question at index 1 to hard.

    2. The application will show the success of updating the question’s difficulty and display all the fields. The question at index 1 will have a new difficulty of Hard.

  3. Finding a question

    1. Type findq java python in the command line.

    2. The application will return a list of questions which contain the keyword "java" or "python" in either its question body or answer. If no question contains these keywords, the application will return an empty list.

  4. Deleting a question

    1. Type listq in the command line to view a list of all questions.

    2. Type deleteq 2 in the command line to delete the second question from the list.

    3. The application will display the success of deletion of this question and its relevant fields. The question will be removed from the list.

F.4. Quiz mode

ℹ️
Ensure the application has at least one question to do the quiz.
  1. Entering the quiz mode

    1. Type quiz n/1 d/easy s/cs2040 in the command line.

    2. If the application has the questions which fit the requirement, it will enter the quiz mode and display the quiz questions.

  2. Answering the question

    1. Type your answer in the command line after entering the quiz mode.

    2. The result of your answer will be displayed under the command box.

  3. Showing the answer of the question

    1. Type show in the command line when the application is in the quiz mode.

    2. The correct answer of the current quiz question will be displayed under the command box.

  4. Skipping current question

    1. Type skip in the command line when the application is in the quiz mode.

    2. The current question will be skipped and the next question will be displayed if there are still available questions.

  5. Quiting from the quiz mode

    1. Type quit in the command line when the application is in the quiz mode.

    2. The application will exit from the quiz mode and return to the original mode.

F.5. Getting statistics

ℹ️
Ensure that there are some questions in the app and some of them have been answered in quiz mode.
  1. Getting statistics

    1. Type stats.

    2. The application will display "Here are the statistics:". All notes, tasks and questions will be hidden, a panel containing a pie chart will appear.

  2. Getting questions

    1. Type question -c.

    2. The application will display "Here are the correct questions:". All notes, tasks and questions will be hidden, a panel containing a pie chart and a list of all correct quiz results will appear.

  3. Getting report

    1. Type report 1.

    2. The application will display "Here is a report of question 1:". All notes, tasks and questions will be hidden, a panel containing a pie chart and all quiz results for question 1 will appear.

  4. Getting overview

    1. Type overview.

    2. The application will display "Here is an overview of the questions:". All notes, tasks and questions will be hidden, a panel containing a stack bar chart will appear.

F.6. Revision task management

  1. Before adding task

    1. Add some notes to the app to be used for tasks.

    2. Add notes by typing addnote t/a c/a, followed by addnote t/b c/b.

  2. Adding a task for revising a note to the revision list

    1. Type rn t/a dt/01/11/2019 tm/0900.

    2. The app will display message for successful addition of the task if there is a note with title "a" in the note list.

  3. Adding a task for revising a question to the revision list

    1. Type rq i/1 dt/12/09/2019 tm/1200.

    2. The app will display message for successful addition of the task if there is a question with index 1 in the question list. If the question list is empty, an error message will be shown.

  4. Editing a task

    1. Type redit 1 h/b.

    2. The heading of the first task will be changed to b if both the first task and a note with title "b" exist in the note list.

  5. Marking a task as done

    1. Type rdone 1

    2. The first task will be marked as done.

  6. Searching for a task

    1. Type rfind tm/0900.

    2. All task at 9am will be shown (if existing).

  7. Listing all tasks

    1. Type rlist.

    2. All tasks will be shown.

  8. Showing finished tasks

    1. Type finished.

    2. All finished (done) tasks will be shown.

    3. Similar operations can be done for unfinished tasks and overdue tasks with command unfinished, overdue respectively.

  9. Deleting a task

    1. Type rlist to display all tasks for better demo effect. (If there are more than one tasks in the current list view, you can skip this step)

    2. Type rdelete 2

    3. The second task in the current list view will be successfully deleted (if existing).

  10. Clearing all tasks

    1. Type rclear.

    2. All tasks will be cleared.

    3. Type rlist and you can see no task is left in the list.