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.
|
Refer to the guide here.
The architecture diagram below gives an overall view of NUStudy’s structure. Each component will be explained in more detail in the coming sections.
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.
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.
The sequence diagram below shows how the components interact with each other for the scenario where the user
issues the command deletenote 1
.
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.
API: Logic.java
-
Logic
uses theAppDataParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding a person). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
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.
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.
API: Storage.java
The Storage
component reads and writes UserPrefs
objects and NUStudy data in JSON format.
This section describes some finer details on how certain features are implemented.
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.
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 theNote
class, callingselectImage()
-
the
needsImage
field ofNote
, which allows a one-time execution offinalizeImage()
-
the
isImageReplaced
field ofEditNoteDescriptor
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.
-
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, orNote
may have a variable toggling between preview and full modes.
-
-
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 aPath
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 aModel
object which is not available toAppUtil#selectImage()
.
-
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:
The following activity diagram summarizes what happens when a user executes a new 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:
-
Alternative 1 (current choice): Update the internal storage
UniqueQuestionList
inAppData
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.
-
-
Alternative 1 (current choice): Use a
UniqueQuestionList
to store questions inAppData
.-
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.
-
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:
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:
The following activity diagram summarizes what happens when a user executes a new command for quiz:
-
Alternative 1 (current choice): Update the internal storage
QuizResultList
inAppData
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.
-
-
Alternative 1 (current choice): Use
QuizQuestionList
andQuizResultList
to store data inAppData
.-
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.
-
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.
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
:
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:
-
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.
-
-
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.
-
Revision task management involves addition, deletion, editing, searching and many other operations on tasks. This section explains how task management features are implemented.
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)
.
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.
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.
-
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 forQuestion
by polymorphism. The concreteTask
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:
-
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.
-
-
Alternative 1 (current implementation): We implement the command as two independent classes, namely
AddTaskForNoteCommand
andAddTaskForQuestionCommand
to support addingTaskForNote
andTaskForQuestion
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 withTaskForQuestion
). Therefore, it is better to separate the concerns by implementing the commands as two separate classes. IfTaskForNote
andTaskForQuestion
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
andTaskForQuestion
.-
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 ofTaskForNote
orTaskForQuestion
, are wrapped into the same class. It could be difficult to maintain if the behaviors ofTaskForNote
andTaskForQuestion
get more complex and diverse.
-
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 usingLogsCenter.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.
Refer to the guide here.
Refer to the guide here.
Refer to the guide here.
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
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 |
(For all use cases below, the system is NUStudy
and the actor is the student
)
MSS
-
Student gives the command to add a lecture note –
addnote t/TITLE c/CONTENT
-
Application shows a lecture note with the given title and contents to the user
-
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
MSS
-
Student gives the command to delete a lecture note –
deletenote INDEX
-
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
Preconditions: lecture note list is not empty
MSS
-
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
-
NUStudy adds the task to revision plan
-
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
MSS
-
Student requests to list revision plan
-
NUStudy lists the revision plan
-
Student specifies the index of the task in the revision plan list
-
NUStudy removes the task from the revision plan
-
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
MSS
-
Student clears the revision plan
-
NUStudy clears the revision plan
-
NUStudy informs the Student that the revision plan is successfully cleared
Use case ends.
MSS
-
Student gives the command to get the statistics for a difficulty and some subjects
stats [d/DIFFICULTY] [s/SUBJECT1] [s/SUBJECT2]…
-
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
MSS
-
Student gives the command to get report of a question
report INDEX
-
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
MSS
-
Student keys in add question and specifies the relevant fields -
add q/QUESTION a/ANSWER s/SUBJECT d/DIFFICULTY
-
Application adds the question with its fields.
-
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
MSS
-
User requests to view a list of questions from another command (eg.
findq
,difficulty
,subject
). -
Application shows the list of questions retrieved from this command.
-
User enters the delete command with the index of the question to be deleted.
-
Application removes the question from the question bank.
-
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
MSS
-
Student changes the difficulty level of a question - edit
-dif id/INDEX d/DIFFICULTY
-
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
MSS
-
Student gives the command to enter the test mode
quiz [n/NUMBER_OF_QUESTIONS] [d/DIFFICULTY] [s/SUBJECT]
-
Application shows a question with difficulty and subject indicated
-
Application waits for the student to key in the answer
-
Student enters the answer
-
Application displays whether the input answer is correct or wrong
-
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
-
Images must be copied into the application data, residing in a dedicated folder, rather than merely linking to somewhere on the filesystem
-
Export format of lecture notes and flash cards must be human-readable text
-
Images must be referenced by pathnames with respect to the image folder
-
Charts returned by statistics feature must be simple enough that it is universally understood
A few ways of manually testing NUStudy are listed below. Of course, any tester should explore more than just these.
-
Initial launch
-
Download the JAR file and copy into an empty folder.
-
Open the jar file. The GUI with some initial application data should be visible.
-
-
Saving window preferences
-
Change the position and size of the window and close it.
-
Re-launch NUStudy. It should look just like when it was closed.
-
-
Adding a lecture note with an image
-
Type
addnote t/t c/c i/
in the command line. An image dialog should be brought up. -
Select any image. It should appear in the lecture note panel, as a new lecture note with title "t" and content "c".
-
-
Modifying an image
-
After adding one lecture note with an image, type
editnote i i/
wherei
is its index. -
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.
-
-
Local copy of images
-
Close the application and move the JAR file and its associated application data to another location.
-
Relaunch the application. Images should display as before.
-
-
Silent ignoring of broken images
-
Once lecture notes with images have been added, close NUStudy and delete all images in its data folder.
-
Relaunch the application. The app should not throw an exception, merely not display any images.
-
Add back the images to the lecture notes using
editnote
. This operation should succeed.
-
-
Adding a question with all necessary fields
-
Type
addq q/MVC design pattern refers to ( ). a/Model View Controller s/CS2103T d/Medium
in the command line. -
The application will show the success of adding the question if all fields are present and valid.
-
-
Editing a question
-
Type
editq 1 d/Hard
to change the difficulty of the question at index 1 to hard. -
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.
-
-
Finding a question
-
Type
findq java python
in the command line. -
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.
-
-
Deleting a question
-
Type
listq
in the command line to view a list of all questions. -
Type
deleteq 2
in the command line to delete the second question from the list. -
The application will display the success of deletion of this question and its relevant fields. The question will be removed from the list.
-
ℹ️
|
Ensure the application has at least one question to do the quiz. |
-
Entering the quiz mode
-
Type
quiz n/1 d/easy s/cs2040
in the command line. -
If the application has the questions which fit the requirement, it will enter the quiz mode and display the quiz questions.
-
-
Answering the question
-
Type your answer in the command line after entering the quiz mode.
-
The result of your answer will be displayed under the command box.
-
-
Showing the answer of the question
-
Type
show
in the command line when the application is in the quiz mode. -
The correct answer of the current quiz question will be displayed under the command box.
-
-
Skipping current question
-
Type
skip
in the command line when the application is in the quiz mode. -
The current question will be skipped and the next question will be displayed if there are still available questions.
-
-
Quiting from the quiz mode
-
Type
quit
in the command line when the application is in the quiz mode. -
The application will exit from the quiz mode and return to the original mode.
-
ℹ️
|
Ensure that there are some questions in the app and some of them have been answered in quiz mode. |
-
Getting statistics
-
Type
stats
. -
The application will display "Here are the statistics:". All notes, tasks and questions will be hidden, a panel containing a pie chart will appear.
-
-
Getting questions
-
Type
question -c
. -
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.
-
-
Getting report
-
Type
report 1
. -
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.
-
-
Getting overview
-
Type
overview
. -
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.
-
-
Before adding task
-
Add some notes to the app to be used for tasks.
-
Add notes by typing
addnote t/a c/a
, followed byaddnote t/b c/b
.
-
-
Adding a task for revising a note to the revision list
-
Type
rn t/a dt/01/11/2019 tm/0900
. -
The app will display message for successful addition of the task if there is a note with title "a" in the note list.
-
-
Adding a task for revising a question to the revision list
-
Type
rq i/1 dt/12/09/2019 tm/1200
. -
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.
-
-
Editing a task
-
Type
redit 1 h/b
. -
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.
-
-
Marking a task as done
-
Type
rdone 1
-
The first task will be marked as done.
-
-
Searching for a task
-
Type
rfind tm/0900
. -
All task at 9am will be shown (if existing).
-
-
Listing all tasks
-
Type
rlist
. -
All tasks will be shown.
-
-
Showing finished tasks
-
Type
finished
. -
All finished (done) tasks will be shown.
-
Similar operations can be done for unfinished tasks and overdue tasks with command
unfinished
,overdue
respectively.
-
-
Deleting a task
-
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) -
Type
rdelete 2
-
The second task in the current list view will be successfully deleted (if existing).
-
-
Clearing all tasks
-
Type
rclear
. -
All tasks will be cleared.
-
Type
rlist
and you can see no task is left in the list.
-