Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Feature Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Command summary
- Appendix: Planned Enhancements
Acknowledgements
We would like to thank:
- CS2103T AY22/23 Semester 2 teaching team for imparting valuable knowledge, skills and guidance
-
SE-edu AddressBook 3 which
QuickContacts
is built on - Open-source libraries used in
QuickContacts
: - Colors from Ayu
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml
files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
has two classes called Main
and MainApp
. It is responsible for,
- At app launch: Initializes the components in the correct sequence, and connects them up with each other.
- At shut down: Shuts down the components and invokes cleanup methods where necessary.
Commons
represents a collection of classes used by multiple other components.
The rest of the App consists of four components.
-
UI
: The UI of the App. -
Logic
: The command executor. -
Model
: Holds the data of the App in memory. -
Storage
: Reads data from, and writes data to, the hard disk.
Interaction between architecture components
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, MeetingListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the JavaFx UI framework. 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
The UI
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. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
object residing in theModel
.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
How the Logic
component works:
- When
Logic
is called upon to execute a command, it uses theQuickcContactsParser
class to parse the user command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,AddCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to add a person). - The result of the command execution is encapsulated as a
CommandResult
object which is returned back fromLogic
.
The Sequence Diagram below illustrates the interactions within the Logic
component for the execute("delete 1")
API call.
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
- When called upon to parse a user command, the
QuickContactsParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,AddCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,AddCommand
) which theQuickContactsParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,AddCommandParser
,DeleteCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores the address book data i.e., all
Person
objects (which are contained in aUniquePersonList
object) andMeeting
objects (which are contained in aUniqueMeetingList
object). - stores the currently ‘selected’
Person
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Person>
that can be ‘observed’ e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
The Person
model,
- consists of individual classes
Name
,Phone
,Email
,Address
andTag
which are used to store the respective information of aPerson
.
The Meeting
model,
- consists of individual classes
Title
,DateTime
,Person
,Location
andDescription
which are used to store the respective information of aMeeting
.
Storage component
API : Storage.java
The Storage
component,
- can save both address book data and user preference data in json format, and read them back into corresponding objects.
- inherits from both
QuickBookStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the seedu.quickcontacts.commons
package.
Feature Implementation
Create, Edit and Delete Operations for Person
and Meeting
This section describes some noteworthy details on how certain features related to Person
and Meeting
are
implemented. Person
and Meeting
have similar functionality and how they are implemented are similar. Without loss of
generality, the specifications below can be applied to both class of objects, unless specified otherwise.
In this section:
-
Object
is used to representPerson
andMeeting
- Correspondingly,
UniqueList
is used to representUniquePersonList
andUniqueMeetingList
- Correspondingly,
AddXYZCommand
is used to representAddCommand
andAddMeetingCommand
- Correspondingly,
EditXYZCommand
is used to representEditCommand
andEditMeetingCommand
- Correspondingly,
DeleteXYZCommand
is used to representDeleteCommand
andDeleteMeetingCommand
- Correspondingly,
AddParser
is used to representAddCommandParser
andAddMeetingCommandParser
- Correspondingly,
EditParser
is used to representEditCommandParser
andEditMeetingParser
- Correspondingly,
DeleteParser
is used to representDeleteCommandParser
andDeleteMeetingCommandParser
Depending on which object functionality you are exploring, simply substitute the general object (Object
or
UniqueList
) with the specific object.
We write in a general so that we cover breadth, and that we may adhere to DRY principle.
Adding
Description
The AddXYZCommand
handles the addition of Object
into QuickContacts. See the syntax for AddXYZCommand
here.
Implementation
When adding an Object
the control flow is as follows:
- The user queries the
UI
to add using theadd
oraddm
command. -
UI
calls theQuickContactsParser
throughLogicManager
to initiate anAddParser
object. -
QuickContactsParser
then passes the arguments to theAddParser
object. -
AddParser
initiates anAddXYZCommand
object. -
AddXYZCommand
object is passed all the way back toLogicManager
. -
LogicManager
callsexecute()
onAddXYZCommand
. -
AddXYZCommand
updates the model and returns aCommandResult
toLogicManager
. -
LogicManager
updates theUniqueList
.
Below is the Sequence Diagram as a concrete example for a Person
:
Exceptions
The AddMeetingCommand
throws a CommandException
if the object’s names is found in the address book (i.e.
no person in the address book has a matching name). The name must match exactly (case-sensitive) or else the
CommandException
will be thrown.
Editing
Description
The EditXYZCommand
is responsible for handling the editing of an Object
in QuickContacts. It allows users to modify the
details of a specific Object
. See the syntax for EditXYZCommand
here.
Implementation
When editing a meeting, the control flow is as follows:
- The user queries the UI to edit a
Object
using theedit
oreditm
command. - The UI calls the
QuickContactsParser
throughLogicManager
to initiate anEditParser
object. -
QuickContactsParser
then passes the arguments to theEditParser
object. -
EditParser
initiates anEditXYZCommand
object. -
EditXYZCommand
object is passed all the way back toLogicManager
. -
LogicManager
callsexecute()
on theEditXYZCommand
. -
EditXYZCommand
updates the model with the editedObject
details and returns aCommandResult
toLogicManager
. -
LogicManager
updates theUniqueList
with the new information by replacing the old with the new object.
Below is the Sequence Diagram as a concrete example for a Person
:
Exceptions
EditMeetingCommand
throws a CommandException
if any one of the Person
’s name is not found in QuickContacts. The
name must match exactly (case-sensitive).
Deleting
Description
The DeleteXYZCommand
handles the deletion of an Object
from QuickContacts. See the syntax for DeleteXYZCommand
here.
Implementation
When deleting an Object
, the control flow is as follows:
- The user queries the UI to delete using the
delete
ordelm
command. - The UI calls the
QuickContactsParser
through LogicManager to initiate aDeleteParser
object. -
QuickContactsParser
then passes the arguments to theDeleteParser
object. -
DeleteParser
initiates aDeleteXYZCommand
object. -
DeleteXYZCommand
object is passed all the way back toLogicManager
. -
LogicManager
callsexecute()
onDeleteXYZCommand
. -
DeleteXYZCommand
updates the model and returns aCommandResult
toLogicManager
. -
LogicManager
updates theUniquePersonList
by deleting thePerson
from it.
Below is the Sequence Diagram:
Exceptions
The DeleteXYZCommand
throws a CommandException if the specified index is not found in QuickContacts.
Finding Person
Description
The FindCommand
finds persons in the address book. See the syntax for FindCommand
here.
Implementation
When finding meetings, the control flow is as follows:
- The user queries the
UI
to find using afind
command. -
UI
calls theQuickContactsParser
throughLogicManager
to initiate aFindCommandParser
object. -
FindCommandParser
takes in a list of names and creates aFindCommand
object. -
FindCommand
is executed, and aNameContainsKeywordsPredicate
is passed to theupdateFilteredPersonList
method in theModel
component. -
LogicManager
creates aNameContainsKeywordsPredicate
, passing it to theupdateFilteredPersonList()
method in theModel
component. -
UI
displays the filtered meetings to the user.
Below is the Sequence Diagram:
Exceptions
The FindCommand
throws a CommandException
if no names are provided.
The names no need to match exactly (case-INsensitive) but the contacts are only filtered by one of the contact’s names,
as space is used as a delimiter.
Difference in Meetings
Implementation
For meetings, the usage and implementation is similar, but the FindMeetingCommand
will search for matching names in the
meetings list similar to FindMeeting
and returns meetings that satisfy the search criteria
(i.e. if the meeting has at least one contact that matches the input name).
However, findm
can be used without arguments to list all meetings. Thus, unlike find
, findm
will not throw exceptions
if not given
any arguments.
Exporting and importing of contacts
Description
Exporting generates a JSON for the contacts at the indices given.
For example, export p/1 p/2
generates a JSON for the first and second contacts.
Example JSON:
[ {
"name" : "Alice Pauline",
"phone" : "94351253",
"email" : "alice@example.com",
"address" : "123, Jurong West Ave 6, #08-111",
"tagged" : [ "friends" ]
}, {
"name" : "Benson Meier",
"phone" : "98765432",
"email" : "johnd@example.com",
"address" : "311, Clementi Ave 2, #02-25",
"tagged" : [ "owesMoney", "friends" ]
} ]
The JSON is generated using the Jackson library, through the use of the JsonUtil utility class. The JSON can be pasted in again proceeding the import command to import the information in the export command
Design Considerations
Alternative 1: Use some other format (eg. XML
or YAML
) for exporting
Could provide more readable and/or less text for copying.
Alternative 2 (current choice): Use existing JSON
format
Benefit: can directly copy-paste to and from the data files that already exist in the system.
Implementation
Here we only describe the ExportCommand
. Import is the same, besides step 5. where it instead calls add on the model to add the specified objects in JSON (similar to how storage loads the save file)
Control flow is as follows.
- The user queries the
UI
to export using a export command. -
UI
calls theQuickContactsParser
throughLogicManager
to initiate a `ExportCommandParser` object. -
ExportCommandParser
creates a `ExportCommand` object. -
ExportCommand
is returned toLogicManager
. -
LogicManager
executes `ExportCommand`. -
ExportCommand
queriesModelManager
for JSON string. -
ExportCommand
returns JSON string toLogicManager
andModelManager
. -
UI
outputs the JSON string.
Below is the Sequence Diagram:
Difference in Meetings
Implementation
Meetings has additional functionality of returning meetings between two dates. This is implemented through the use of a
isBetween
function implemented in the Meeting
class. The program will first gather all the meetings in the
corresponding indexes provided, then search for meetings between the start and end dates. If either date is empty, then
only the other date is considered.
Exceptions
Using the exported JSON, one can then import it using import VALID_JSON
.
Before importing, a check is done to make sure there are no duplicate values. This is done before the actual importing to ensure we do not have “half imports”.
Consider a situation where we have [Person2, Person3]
in the system. If we
import [Person1, Person2, Person3, Person4]
without considering duplicates first, Person1 will be imported
followed by the import of Person2 throwing a DuplicatePersonError, resulting in the command throwing a failure
message and Person4 not being imported but the system now has [Person1, Person2, Person3]
.
The JSON is parsed using the Jackson library. If the Jackson library is unable to parse the json, an error message
is thrown.
However, if the user wishes to “force import”, a f/
parameter is provided. This imports for each Person
if the
Person does not already exist, and ignores those that do.
This allows the previous situation to complete with [Person1, Person2, Person3, Person4]
in the system.
Autocompletion of Argument Prefixes
Autocompletion of command inputs is facilitated by the individual command parsers (XYZCommandParser
) which are
implementing the Parser
interface in the Logic
component. Each XYZCommandParser
implements how autocompletion
should work for that particular command by overriding Parser#getAutocompleteSuggestion
. This action is triggered when
the user presses TAB
when the command input starts with a valid command.
The CommandBox
UI component is actively listening for TAB
keystrokes by having a KeyPressedHandler
which will
trigger XYZCommandParser#getAutocompleteSuggestion
. A AutocompleteResult
would then be returned to the CommandBox
which contains the Prefix
to be appended to the current command input, or used to replace the last Prefix
in the
current command input.
Design Considerations
Alternative 1: Autocomplete by appending the next relevant Prefix
that is missing
- This will be easier to implement as all we need is to have a list of
Prefix
that is relevant for the command and cycle through and append those that are missing from the current command input. - Checking for missing
Prefix
from the command input can be achieved with the help ofArgumentTokenizer
. - Downside: some commands such as
edit
does not need all thePrefix
as user might just want to modify two attributes. Simply cycling through and appending missingPrefix
might require users to backspace some unnecessaryPrefix
.
Alternative 2 (current choice): Autocomplete by custom behaviour depending on the command
- This would require each
XYZCommandParser
to implement their own behaviour on how autocompletion should behave for that particular command. - Benefit: There is more flexibility in customising how to best cater autocompletion for each individual command to better the user experience.
Traversal of Commands
Traversal of commands is facilitated by CommandHistory
model in addition to KeyPressedHandler
in the CommandBox
UI component.
Internally, CommandHistory
utilises LinkedList
to store all the commands that have been executed by the user. Traversal of the list is facilitated by a static
pointer.
CommandBox
UI component is actively listening to the UP
and DOWN
keys which would be handled by the KeyPressedHandler
, which is responsible for traversing the command history using CommandHistory
.
The activity diagram below provides a visual representation of the flow of actions when the UP
and DOWN
keys are pressed.
DateTime parsing
Storing of dateTime
(date and/or time) of Meeting
is facilitated by DateTime
.
The dateTime
of a Meeting
requires users to input a date, but leaves the time of the meeting to be optional. Internally, DateTime
stores the date using LocalDate
and the time using LocalTime
. However, since the time is an optional field, the optionality of the time is implemented by wrapping LocalTime
with the Java Optional
class. This brings about various benefits and is further discussed below.
Moreover, DateTime
allows for various formats of parsing in a dateTime
value (22/02 3.30PM, 2202 1530, 22.02.2023 etc). This is facilitated by first having a list of formats for dates and times separately. Moreover, separators (.
, :
, /
etc) are maintained and inserted for each format dynamically. For example:
-
dd{SEP}MM{SEP}yyyy
specifies the format fordd/MM/yyyy
,dd.MM.yyyy
anddd-MM-yyyy
for separators/
,.
and-
respectively.
This way, formats are easily extensible and maintainable. The parsing of dateTime
inputs into LocalDate
and LocalTime
objects are facilitated by breaking up the input into 2 parts: date and time, before using LocalDate#parse
and LocalTime#parse
respectively.
Design Considerations
Aspect: How to encapsulate the time of a Meeting
which is optional
-
Alternative 1: Have the time set to
null
if user does not provide the time.- This would risk
NullPointerException
being thrown if the time is not provided but there are attempts of accessing the time. - As a result of the point above, there will be many instances of null checks, which would contribute to unnecessary code verbosity.
- This would risk
-
Alternative 2: Make use of
LocalTime.MAX
to represent that the time is not provided.- This alternative removes the risk of
NullPointerException
that comes with Alternative 1. - However, there would still be many instances of checks whether the time equals to
LocalTime.MAX
, which would contribute to unnecessary code verbosity.
- This alternative removes the risk of
-
Alternative 3 (current choice): Utilise Java
Optional
to wrap the time.- By doing so, there will not be any
NullPointerException
and enables us to make use of the provided methods (orElse
etc.) that helps to carry out the logic based on the presence of the time.
- By doing so, there will not be any
Sort Meeting commands (only in meetings)
Sorting
Description
The SortMeetingCommand
is a Java class that allows the user to sort meetings stored in a Model
object based on a specified attribute, such as title, date and time, location, or description. The sorting is done by creating a Comparator
for the specified attribute and passing it to the sortFilteredMeetingList
method in the Model
object. See the syntax here sort command.
Implementation
When sorting meetings, the control flow is as follows:
- The user issues a sort command with the desired attribute and optional reverse flag.
- The
UI
calls theQuickContactsParser
throughLogicManager
to initiate aSortMeetingCommandParser
object. - The
SortMeetingCommandParser
parses the command and creates aSortMeetingCommand
object. - The
SortMeetingCommand
is executed, and the correctComparator
for the specified attribute is applied to theModel
object’ssortFilteredMeetingList
method. -
LogicManager
returns aCommandResult
to theUI
with a success message indicating the attribute by which the meetings have been sorted.
Below is the Sequence Diagram:
Light Theme
The current theme is stored as a boolean inside GuiSettings, which is stored inside UserPrefs. Clicking the button toggles the boolean and removes the current stylesheet (eg. LightTheme.css/DarkTheme.css) and adds the opposite stylesheet to the scene.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
This sections describes the user requirements we intend to address with QuickContacts
.
Target User Profile
QuickContacts
is designed for users with busy schedules of meeting people.
- need to manage a large number of contacts and meetings
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition
QuickContacts
allows users to manage contacts and meetings faster than a typical mouse/GUI-driven application.
User stories
Priority levels:
- High (must have) -
* * *
- Medium (nice to have) -
* *
- Low (unlikely to have) -
*
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * * |
new user | see usage instructions | refer to instructions when I forget how to use the App |
* * * |
user | add a new person | |
* * * |
user | delete a person | remove entries that I no longer need |
* * * |
user | find a person by name | locate details of persons without having to go through the entire list |
* * |
user | hide private contact details | minimize chance of someone else seeing them by accident |
* |
user with many persons in the contact book | sort persons by name | locate a person easily |
* |
user | Find a person by tag | I can filter the contacts by tags |
* |
user | Sort by tag priority | I can find the most important contacts |
* |
user | Assign tag priority | |
* |
user | Retrieve deleted contacts | |
* |
user | Set a date for deletion of contacts | Remove the contacts automatically |
* |
user | Add a contact | Store my contact in app |
* |
user | Delete a contact | Remove unwanted contacts |
* |
user | Edit a contact | Change details of existing contacts |
* |
user | Assign tag to contact | Categorise my contacts |
* |
user | Use the help command | To see available commands |
* |
power user | Assign shortcuts to different actions | I can cut down on the time taken to type |
* |
User with many connections | Export my contacts | I can share my contacts easily |
* |
User with many connections | Copy the details of my contacts | I can share my contacts easily |
* |
User with many existing contacts | Import my contacts automatically | I don't have to spend too much time creating contacts one by one |
* |
User with many meetups with people | Sort meetings based on the date and time | I can prioritize my time well |
* |
Busy user with many meetups | Receive notifications about meetups with contacts | I won't be late for meetups |
* |
User with many meetups with people | Create a meeting | Schedule a meeting |
* |
User with many meetups with people | Edit a meeting | Change meeting details |
* |
User with many meetups with people | Delete a meeting | Remove cancelled or completed meetings |
* |
User with many meetups with people | View all meetings | See in a glance the meetings that I have |
* |
User with many meetups with people | View meeting details | Understand what my meeting is about |
* |
Users with meetings | Add a reminder to meeting | So I do not forget the meeting |
* |
Users with meetings | Edit reminder of meeting | Change how frequent my reminders are |
* |
Users with meetings | Delete a reminder | So I am not spammed with reminders |
* |
Users with many meetings | Tag meeting | Organize they types of meetings |
* |
User who are very familiar with the keyboard | Add custom keybinds | So that I am faster at organizing contacts |
* |
User with many meetings | See how many days left to a meeting | I don't forget to attend one |
* |
User in a hurry | Undo previous action up to 3 previous actions | I can be fast and a bit sloppy without worrying |
* |
User who use the app for a long time | Set a reminder to tag people | In future I can better organize people |
* |
User who forget what is in contacts | Ask if person/meeting still relevant | So that the contact remain relatively clean |
* |
User assign name to priority tag | Customise the tags | I can remember more easily who is ranked higher |
Use cases
For all use cases below, the system is QuickContacts
and the Actor is the user
, unless specified otherwise.
Use case: UC1 - Add a contact
MSS:
- User requests to add a contact.
-
QuickContacts
adds that contact. -
QuickContacts
shows new contact in list.Use case ends.
Extensions:
- 1a. Input for a required field is illegal.
- 1a1.
QuickContacts
prompts user with an error message. - Use case resumes at step 1.
- 1a1.
Use case: UC2 - Delete a contact
MSS:
- User requests to list contacts.
-
QuickContacts
shows a list of contacts. - User requests to delete a specific contact in the list.
-
QuickContacts
deletes the contact.Use case ends.
Extensions:
- 2a. The list is empty.
-
QuickContacts
returns an empty list. - Use case ends.
-
- 3a. Index for the contact to be deleted is invalid.
-
QuickContacts
prompts user with an error message. - Use case resumes from step 3.
-
Use case: UC3 - Find a contact
MSS:
- User requests searches contact by name.
-
QuickContacts
shows that person.Use case ends.
Extensions:
- 1a. Input for a required field is illegal.
- 1a1. Show error message.
- Use case continues at step 1.
Use case: UC4 - Edit an existing contact’s details
MSS:
- User requests to edit a contact.
-
QuickContacts
shows the contact with the updated details.Use case ends.
Extensions:
- 1a. Input for a field is illegal.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Contact cannot be found.
- 1b1. Show error message.
- Use case continues at step 1.
Use case: UC5 - User want to list all
MSS:
- User requests to list.
-
QuickContacts
shows all the person and meetings.Use case ends.
Extensions:
- 1a. list is empty.
- Use case ends.
Use case: UC6 - User wants to clear everything
MSS:
- User requests to
clear
. -
QuickContacts
deletes all contacts and meetings.Use case ends.
Use case: UC7 - User wants to exit
MSS:
- User requests to exit.
-
QuickContacts
closes.Use case ends.
Use case: UC8 - Add a meeting
MSS:
- User requests to add a meeting.
-
QuickContacts
adds that meeting. -
QuickContacts
shows new meeting in list.Use case ends.
Extensions:
- 1a. String in a field illegal.
- 1a1. Show error message.
- Use case resumes at step 1.
Use case: UC9 - Delete a meeting
MSS:
- User requests to list meetings.
-
QuickContacts
shows a list of meetings. - User requests to delete a specific meeting in the list.
-
QuickContacts
deletes the meeting.Use case ends.
Extensions:
- 2a. The list is empty.
- Use case ends.
- 3a. The given index is invalid.
- 3a1.
QuickContacts
shows an error message. - Use case resumes at step 2.
- 3a1.
Use case: UC10 - Edit a meeting
MSS:
- User requests to edit a meeting.
-
QuickContacts
shows the meeting with the updated details.Use case ends.
Extensions:
- 1a. String in a field illegal.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Meeting cannot be found.
- 1b1. Show error message.
- Use case continues at step 1.
Use case: UC11 - Sort by meeting attribute
MSS:
- User wants to sort by a meeting attribute.
-
QuickContacts
sorts the original list by order requested by user. -
QuickContacts
shows the sorted list.
Use case: UC12 - Export Contacts
MSS:
- User requests to export contacts.
-
QuickContacts
shows the exported contacts.Use case ends.
Extensions:
- 1a. String in a field illegal.
- 1a1. Show error message.
- Use case resumes at step 1.
- 1a. Person index not given.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Person index cannot be found.
- 1b1. Show error message.
- Use case continues at step 1.
Use case: UC13 - Import Contacts
MSS:
- User requests to import contacts.
-
QuickContacts
imports the meetings and updates the view.Use case ends.
Extensions:
- 1a. Contacts format malformed.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Contacts not provided.
- 1b1. Show error message.
- Use case continues at step 1.
- 1c. Duplicate contact without user indicating force import.
- 1c1. Show error message.
- Use case continues at step 1.
- 1d. User indicates force import.
- All contacts imported.
- Use case ends.
Use case: UC14 - Export Meetings
MSS:
- User requests to export meetings.
-
QuickContacts shows the exported meetings.
Use case ends.
Extensions:
- 1a. Meeting index not given.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Meeting index cannot be found.
- 1b1. Show error message.
- Use case continues at step 1.
Use case: UC15 - Import Meetings
MSS:
- User requests to import meetings.
-
QuickContacts imports the meetings and updates the view.
Use case ends.
Extensions:
- 1a. Meetings format malformed.
- 1a1. Show error message.
- Use case continues at step 1.
- 1b. Meetings not provided.
- 1b1. Show error message.
- Use case continues at step 1.
- 1c. Duplicate meeting without user indicating force import.
- 1c1. Show error message.
- Use case continues at step 1.
- 1d. User indicates force import.
- All meetings imported.
- Use case ends.
Use case: UC16 - Mark Meetings as Done
MSS:
- User marks meetings as done.
-
QuickContacts updates meetings and updates the view.
Use case ends.
Extensions:
- 1a. Meeting index not found.
- 1a1. Show error message.
- 1b. Meetings not provided.
- 1b1. Show error message.
Use case ends.
Use case: UC17 - View Pending Meetings
MSS:
- User requests to view pending meetings.
-
QuickContacts displays meetings that are not marked as done and are in the future.
Use case ends.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
- Can support 1000 meetings with same amount of lag as 10 meeting.
- Commands should be intuitive to not technical people.
- Should be clear that meeting and people are 2 separate things.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Meetings: Important dates with a duration and a place
- Find: Searches by name field, case-insensitive, match all matching words individually
- GUI: Graphic User Interface
- MSS: Main Success Scenario
- OS: Operating System
- Java: Programming Language by SUN Oracle
- CLI: Command Line Interface
- LinkedList: Data structure that consists of nodes that contain data and a reference to the next node
- JSON: Stands for JavaScript Object Notation and it is a file format used for storing and transmitting data in attribute-value pairs and arrays.
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
Deleting a contact
-
Deleting a contact while all contacts are being shown
-
Prerequisites: List all contacts using the
list
command. Multiple contacts in the list. -
Test case:
delete 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete 0
Expected: No contact is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete
,delete x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
Creating a meeting
-
Creating a meeting with a contact:
-
Prerequisites: Contact
Alex Yeo
exists in QuickContacts. -
Test case:
addm m/Lunch with Alex dt/2003 15:00 p/Alex Yeo
Expected: New meeting withAlex Yeo
on 20 March (of the current year) at 3PM is created, and it is displayed in the meetings list. -
Test case:
addm m/Lunch with Alex dt/2003 25:00 p/Alex Yeo l/The Deck des/Weekly catch-up
Expected: Meeting is not created since25:00
is an invalid time. Error details shown in the status message. Status bar remains the same.
-
-
Creating a meeting without a contact:
-
Test case:
addm m/Dinner at home dt/2003222
Expected: New meeting is created for200322
(20 March 2022). -
Test case:
addm m/Dinner at home
Expected: Meeting is not created as a date(and time) is required. Error details shown in the status message. Status bar remains the same.
-
Saving data
-
To simulate data file is not found:
-
Prerequisite:
QuickContacts
is currently not running and the data files have been generated. -
Rename the file
quickcontacts.json
in the same directory toquickcontacts.json.backup
. -
Launch
QuickContacts
.
Expected:
QuickContacts
launches normally and re-generates the sample default data. -
-
To simulate data file is corrupted:
-
Prerequisite:
QuickContacts
is currently not running and the data files have been generated. -
Open
quickcontacts.json
with a text editor, add a few random characters and save it. -
Launch
QuickContacts
.
Expected: A warning message will be displayed and
QuickContacts
will start from an empty data file. -
-
To simulate restoring data from a backup data file:
-
Prerequisite:
QuickContacts
is currently not running and the data files have been generated and you have the backup file ready. Assume that the backup file is namedquickcontacts.json.backup
. -
Delete
quickcontacts.json
from the directory that containsquickcontacts.jar
. -
Move
quickcontacts.json.backup
into the same directory asquickcontacts.jar
. -
Rename
quickcontacts.json.backup
toquickcontacts.json
. -
Launch
QuickContacts
.
Expected:
QuickContacts
will launch normally with the data restored from the backup. -
Command summary
Action | Format, Examples |
---|---|
Create a contact |
add n/CONTACT_NAME [p/CONTACT_PHONE_NUMBER] [e/CONTACT_EMAIL] [a/CONTACT_ADDRESS] [t/CONTACT_TAG]... e.g., add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague
|
Reset all data | clear |
Delete a contact |
delete INDEX e.g., delete 3
|
Edit a contact |
edit INDEX [n/CONTACT_NAME] [p/CONTACT_PHONE_NUMBER] [e/CONTACT_EMAIL] [a/CONTACT_ADDRESS] [t/CONTACT_TAG]... e.g., edit 2 n/James Lee e/jameslee@example.com
|
Find a contact |
find KEYWORD [MORE_KEYWORDS] e.g., find James Jake
|
List all contacts | list |
Help | help [COMMAND_WORD] |
Exit the app | exit |
Create a meeting | addm m/MEETING_TITLE dt/MEETING_DATE_TIME [p/MEETING_ATTENDEE]... [l/MEETING_LOCATION] [des/MEETING_DESCRIPTION] |
Edit a meeting | editm INDEX [m/MEETING_TITLE] [dt/MEETING_DATE_TIME] [p/MEETING_ATTENDEE]... [l/MEETING_LOCATION] [des/MEETING_DESCRIPTION] |
Find a meeting |
findm KEYWORD [MORE_KEYWORDS] e.g, findm James Jake
|
List all meetings | findm |
Mark meeting as done |
mark m/INDEX [m/MORE_INDEXES]... |
Mark meeting as not done |
unmark m/INDEX [m/MORE_INDEXES]... |
View pending Meetings | pending |
Delete a meeting |
delm INDEX e.g., delm 3
|
Export a contact |
export p/INDEX [p/MORE_INDEXES]... e.g., export p/1 p/2 p/3
|
Export a meeting |
exportm m/INDEX [m/MORE_INDEXES]... [start/MEETING_EXPORT_START_DATE] [end/MEETING_EXPORT_END_DATE] e.g., exportm m/1 m/2 m/3
|
Import a contact | import VALID_JSON |
Import a meeting | importm VALID_JSON |
Sort meetings |
sortm SORT_FIELD [r] e.g., sortm dt/
|
Appendix: Planned Enhancements
-
Currently, the UI shows a blank area when an attribute is undefined for contacts and meetings.
Proposed Fix: Have a placeholder
No ATTRIBUTE defined
for each undefined attribute. -
Currently, once we define an attribute for a contact, we are unable to remove it.
Proposed Fix: Add a new command “deleteattribute” for this purpose. For example,
deleteattribute p/1 e/
to remove email for a contact ordeleteattribute m/1 des/
to remove description for a meeting.