By: CoderLifeInsights
Since: March 2020
Licence: MIT
- 1. Introduction
- 2. Setting up
- 3. Design
- 4. Implementation
- 5. Documentation
- 6. Testing
- 7. Dev Ops
- Appendix A: Product Scope
- Appendix B: User Stories
- Appendix C: Use Cases
- C.1. Use case: Add person
- C.2. Use case: Find a person by name
- C.3. Use case: Add group
- C.4. Use case: Delete Group
- C.5. Use case: Edit Group
- C.6. Use case: List Group
- C.7. Use case: Export data
- C.8. Use case: Import data
- C.9. Use case: Suggest person
- C.10. Use case: Suggest place
- C.11. Use case: Suggest activity
- C.12. Use case: View time
- C.13. Use case: Add an event with a person
- C.14. Use case: Add an event with a group
- C.15. Use case: View the places or activities visited with a group
- Appendix D: Non Functional Requirements
- Appendix E: Glossary
- Appendix F: Instructions for Manual Testing
- F.1. Launch and Shutdown
- F.2. Deleting a person
- F.3. Finding a person
- F.4. Suggest a person
- F.5. Suggest a place
- F.6. Suggest an activity
- F.7. Import CoderLifeInsights data
- F.8. Export CoderLifeInsights data
- F.9. Adding an event
- F.10. Add a Group
- F.11. Delete a Group
- F.12. Edit a Group
- F.13. List all Groups
- F.14. Exiting the program
- Appendix G: Effort
1. Introduction
[written by: Raivat Bhupesh Shah]
CoderLifeInsights is a desktop application that provides you insights and suggestions to your social life as a programmer using a CLI (Command Line Interface).
Managing social life as a programmer can be difficult since you spend most of the in front of the screen, probably coding. And thus, it is easy to lose track of people who you spend time with or need to spend time with. CoderLifeInsights helps you track and gain insights on your social life off the screen.
CoderLifeInsights is a Command Line Interface (CLI) application that also has a Graphical User Interface (GUI). Thus, the users are expected to use CoderLifeInsights mainly through CLI, but the GUI is used to give the user a glimpse of their data, show insights and error messages whenever applicable.
We’re delighted that you’re interested in the development of CoderLifeInsights and reading this guide is a great first step to get upto speed with the codebase and how it is organised. This guide also serves as reference for all current developers when needed.
2. Setting up
Refer to the guide here.
3. Design
3.1. Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component. The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
The .puml files used to create diagrams in this document can be found in the diagrams folder.
Refer to the Using PlantUML guide to learn how to create and edit diagrams.
|
-
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 method where necessary.
Commons
represents a collection of classes used by multiple other components.
The following class plays an important role at the architecture level:
-
LogsCenter
: Used by many classes to write log messages to the App’s log file.
The rest of the App consists of four components.
Each of the four components
-
Defines its API in an
interface
with the same name as the Component. -
Exposes its functionality using a
{Component Name}Manager
class.
For example, the Logic
component (see the class diagram given below) defines it’s API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
delete 1
commandThe sections below give more details of each component.
3.2. UI component
API : Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, StatusBarFooter
etc.
The ResultDisplay
, in turn, is made up of further component parts, such as AllEventPanel
.
All these components, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses 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.
3.3. Logic component
API :
Logic.java
-
Logic
uses theAddressBookParser
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.
delete 1
Command
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
3.4. Model component
[section modified by: Raivat Bhupesh Shah]
API : Model.java
The Model
,
-
stores a
UserPref
object that represents the user’s preferences. -
stores the CoderLifeInsights data.
-
exposes an unmodifiable
ObservableList<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. -
Also exposes an unmodifiable
ObservableList<Group>
and `ObservableList<Event> for the same reason as above. -
does not depend on any of the other three components.
As a more OOP model, we can store a Tag list in Address Book , which Person can reference.
This would allow Address Book to only require one Tag object per unique Tag , instead of each Person needing their own Tag object.
An example of how such a model may look like is given below. |
+
3.5. Storage component
[section modified by: Raivat Bhupesh Shah]
API : Storage.java
The Storage
component,
-
can save
UserPref
objects in json format and read it back. -
can save the CoderLifeInsights data in json format and read it back.
3.6. Common classes
Classes used by multiple components are in the seedu.address.commons
package.
4. Implementation
This section describes some noteworthy details on how certain features are implemented.
4.1. Import feature
[written by: Cheng Lit Yaw]
4.1.1. Implementation
The import feature allows users to import data from a comma-separated values (CSV) file. It allows users to bulk import their contacts, groups and events from a previously exported data from CoderLifeInsights application.
Given below is the sequence diagram to illustrate how the import operation interacts with the command import l/life.csv g/group.csv e/event.csv
:
-
User enters
import l/life.csv g/group.csv e/event.csv
. -
All 3 files would then be parsed by
ImportCommandParser
to check if the files exist with the path specified. -
On successful check,
ImportCommand
would be created and callsImportFile#importCsv
,ImportFile#importGroupCsv
and `ImportFile#importEventCsv`to check if the CSV file headers are valid. -
ImportCommand
would then callModel#importCsvToAddressBook
,Model#importCsvGroupsToAddressBook
andModel#importCsvEventsToAddressBook
to check if the persons, groups and events are duplicates of the current CoderLifeInsights. -
If the imported data are not duplicates, it will then create a valid list of persons, groups and events to be added to CoderLifeInsights.
-
CoderLifeInsights will then populate the 3 lists to the current data.
Given below is an activity diagram to summarise the steps above.
4.1.2. Csv file format and constraints
In order for data to be imported into CoderLifeInsights, the CSV file provided must be in the exact format.
For life.csv
:
Headers required:
-
name
-
phone
-
email
-
address
-
tagged
-
time
-
places
-
activities
Cell Formatting
-
No leading and trailing spaces in a cell.
-
To specify a comma within a cell, the value of the cell should be inside double quotes. Eg:
-
"Friends, Family"
-
"High School, Colleague"
-
4.1.3. Design Considerations
Aspect | Alternative 1 (current choice) | Alternative 2 |
---|---|---|
How import executes |
Imports the entire Csv file, converts all the rows into a list of Pros: Cons: |
Imports the Csv file, converts all the rows into a list of Pros: Cons: |
The first alternative was chosen as performance of the application is prioritised over ease of implementation. There would be risk of the application stop responding if the second alternative was chosen.
4.2. Export feature
[written by: Cheng Lit Yaw]
4.2.1. Implementation
The export feature allows users to export their current data into a comma-separated value file with file name specified.
Given below is a sequence diagram to illustrate how the export operation interacts with the command export l/life.csv g/group.csv e/event.csv
:
-
User enters
export l/life.csv g/group.csv e/event.csv
-
All 3 files would then be parsed by
ExportCommandParser
to check if the files specified exist within the specified file path. -
This is necessary to avoid existing files being overwritten.
-
If files do not exist,
ExportCommand
would then be created and callsExportFile#exportCsv
,ExportFile#exportGroupCsv
andExportFile#exportEventCsv
. -
Life, groups and events data would then be exported
life.csv
,group.csv
andevent.csv
respectively.
Given below is an activity diagram to summarise the steps above.
4.3. Suggestion Feature
[written by: Cheng Lit Yaw]
4.3.1. Implementation
The suggestion feature allows users to get a person to hangout with, a place to hangout or an activity to do.
Given below is an sequence diagram illustrating how the suggestion operation works with the command suggest person
.
-
User enters
suggest person
. -
SuggestCommandParser
would then check if keyword entered corresponds toperson
,place
oractivity
. -
Upon valid keyword entered,
SuggestCommand
would callModel#suggestPerson
to return a suggested person. -
ObservableList of filteredPersons would be iterated to get suggested person based on least time spent and reverse lexicographical order of name as a tie breaker.
Model
would self-invoke the methodModel#updateFilteredPersonList
to update filteredPersonList. -
filteredPersonList would then be updated to reflect on the GUI as a suggestion.
A similar approach would apply to place
and activity
where instead of Model#suggestPerson
, it would be
Model#suggestPlace
or Model#suggestActivity
where an ObservableList of filteredEvents would be iterated to get
suggested place or activity based on the least frequency of the place visited or activity done.
If there are multiple place visited or activity done has the same frequency, a tie breaker would be introduced where a random place/activity would be suggested among the same frequencies.
Given below is an activity diagram to summarise the steps above.
4.4. Add Group Feature
[written by: Raivat Bhupesh Shah]
4.4.1. Implementation
The Add Group feature is implemented to allow users to track social activities with a group of people
(instead of just one person). A Group
represents a social group containing
1 or more Person
. To avoid dependencies, a Group
class stores the index of a Person
instead of the Person
object
itself. A Group
can be created with or without Person
as member(s), but must have a Name
.
This feature creates a new Group
instance, which is then stored in an instance of UniqueGroupList
,
which in turn is stored in the AddressBook
. These classes are part of the model
component.
The feature is supported by the AddGroupCommand
class, which extends the abstract
class Command
and AddGroupCommandParser
, which implements the Parser
interface. These classes are part of the
logic
component.
The following class diagram showcases the relationship between the main classes that support this command and key attributes and methods:
Here below is an example usage scenario and how the add_group
feature works at each step:
-
User enters
add_group n/group_name
oradd_group n/group_name m/index …
into the app. -
The request is handled by the
LogicManager#execute(String)
, which then calls and passes the input to theAddressBookParser#parseCommand(String)
method. -
AddressBookParser
detects the command wordadd_group
in the input string and creates anAddGroupCommandParser
to parse inputs according to the format specified forAddGroupCommand
. -
AddGroupCommandParser
parses the input and also performs input validation to check for correct types (eg alphanumeric characters forName
andInteger
for memberIDs) using theAddGroupCommandParser#parse(String)
method. -
AddressBookParser#parse(String)
calls the constructor ofGroup
and creates a newGroup
instance with the inputs from the user. It creates a newAddGroupCommand
and passes the newly createdGroup
to it. -
AddressBookParser
returns the newCommand
object to theAddressBookParser
, which in turn returns it toLogicManager
. -
LogicManager
calls theAddGroupCommand#execute(model)
method -
The
AddGroupCommand#execute(model)
method obtains a copy of theFilteredPersonList
fromModel
using theModel#getFilteredList()
method. Using the list, the method verifies if the member indexes in theGroup
instance exist in thePerson
list. -
the
AddGroupCommand
adds the group to the app by calling theModel#addGroup(Group)
method. -
As a last step, the
AddGroupCommand
creates aCommandResult
withSuccessMessage
andViewType
and returns it toLogicManager
.
The process is shown in the following sequence diagram:
4.4.2. Design Considerations
Aspect: How the add_group
command executes
-
Alternative 1 (current choice): Separate parsing from code execution
-
Pros: Clear distinction between class responsibilities.
-
Cons: More code, may increase coupling as objects are passed around between the classes.
-
-
Alternative 2: Parse and Execute in the same class
-
Pros: Less code, less variables/object to pass between classes.
-
Cons: No separate classes so maybe harder to trace bugs. It maybe harder to understand for future developers, as the design would be different to the
add_person
command (adapted from AddressBookLevel 3).
-
Aspect: How to store the group
instances
-
Alternative 1 (current choice): Store in a separate
UniqueGroupList
-
Pros: Separate List is easier to manage and edit. Thus, this option is also advantageous as there is an
edit_group
command as well. -
Cons: Another list to be stored in AddressBook, which might lead to more memory usage. Since the target user is may keep the app running in the background, this can be disadvantageous.
-
-
Alternative 2: Store inside Person Objects, which are stored in
UniquePersonList
-
Pros: No need of a separate list, one list to store all essential data. This might be better from a memory standpoint.
-
Cons: Harder to maintain group instances inside person as there will be multiple copies and for most users, the number of groups of people will be less than the number of people. This alternative would also make the Person class depend upon the Group class, which can be error-prone.
-
4.5. Delete Group Feature
[written by: Raivat Bhupesh Shah]
4.5.1. Implementation
The Delete Group feature allows the user to delete a previously Group
. This feature is implemented using the
DeleteGroupCommand
, which extends the abstract class Command
and the DeleteGroupCommandParser
, which implements
the Parser
interface.The feature is also supported by UniqueGroupList
,
which stores the Group
instances. The relationship between classes is similar to the one seen in diagram x.x and hence
is omitted for conciseness.
Here below is an example workflow, which is shown using an activity diagram:
The above workflow is achieved due to the interlinked classes. Their behaviour during an execution of the DeleteGroup feature is shown using the following Sequence Diagram.
4.5.2. Design Considerations
Aspect: how the delete group feature executes
-
Alternative 1 (current choice) : Separate
DeleteGroupCommand
andDeleteGroup
classes to support the feature.
Pros: clear class responsibility, easier to trace bugs. Since this follows the design of most other commands, intuitive to understand for new developers
Cons: increases the amount of code, which might introduce more errors. -
Alternative 2: The
DeleteGroupCommand
class parses the inputted index
Pros: Since only one argument to parse, this eliminates the need for another class. Less code. Cons: Can cause confusion among developers regarding the class responsibility.
4.6. List Group Feature
[written by: Raivat Bhupesh Shah]
The list group feature allows users to view all the Group
instances currently stored in CoderLifeInsights.
4.6.1. Implementation
This feature is mainly supported by the ListGroupCommand
, which extends the abstract class Command
.
Here below is a sequence diagram showcasing how the command works.
The following is an example usage scenario and how the list group mechanism behaves at each step.
-
User enters
list_groups
into the command prompt -
The
LogicManager
callsAddressBookParser#parseCommand()
with the arguments supplied by the user -
The method
AddressBookParser#parseCommand()
checks if the input is valid and if yes, creates aListGroupCommand
. -
The
ListGroupCommand
calls theupdateFilteredGroupList
method ofModel
to update the GUI. -
The
ListGroupCommand
returns theCommandResult
to AddressBookParser -
The
AddressBookParser
returns theCommandResult
toLogicManager
.
The following activity diagram summarises the workflow for the list group feature.
4.7. Edit Group Feature
[written by: Raivat Bhupesh Shah]
The Edit Group Feature allows the user to edit an existing Group
in the app.
4.7.1. Implementation
The Edit Group Feature is facilitated by the EditGroupCommand
, which extends the abstract class Command
, and
the EditGroupCommandParser
, which implements the Parser
interface. Both of these classes are part of the Logic
component. Additionally, a private and static EditGroupDescriptor
class is present in EditGroupCommand
as a container
class to encapsulate attributes to be edited for a Group
.
he following operations are implemented and used for accomplishing this feature:
-
EditGroupCommandParser#parser(String args)
- Parses the input to obtain the arguments and returns anEditGroupCommand
instance with the arguments. -
EditGroupCommandParser#arePrefixesPresent(ArgumentMultimap argumentMultiMap, Prefix… prefixes)
- checks if the member indexes are supplied by the user. -
EditGroupCommand#EditGroupCommand(Index index, EditGroupDescriptor editGroupDescriptor)
- Creates a newEditGroupCommand
instance with the supplied index and editGroupDescriptor. -
EditGroupCommand#createEditedGroup(Group groupToEdit, EditGroupDescriptor editGroupDescriptor)
- Modifies the givengroupToEdit
with the details given ineditGroupDescriptor
.
The following is an example usage scenario and how the edit group mechanism behaves at each step:
-
User types
edit_group index n/new_name
oredit_group index m/index …
into the app. -
The request is handled by
LogicManager#execute(String)
, which then calls and passes the input to theAddressBookParser#parseCommand(String)
method. -
AddressBookParser
detects the command wordedit_group
in the input string and creates a newEditGroupCommandParser
to parse inputs according to the format specified forEditGroupCommand
. -
Input is parsed using the
EditGroupCommandParser#parse(String)
method, which also performs input validation. The method creates aEditGroupDescriptor
using the parsed inputs by calling the static constructor insideEditGroupCommand
. -
The
EditGroupCommandParser
creates a newEditGroupCommand
instance with the givenindex
and newly createdEditGroupDescriptor
object and returns it toAddressBookParser
, which in turn returns it toLogicManager
. -
LogicManager
calls theEditGroupCommand#execute(model)
method. -
EditGroupCommand
obtains a copy of theFilteredPersonList
by calling theModel#getFilteredPersonList()
method. This is used to check if the member indexes supplied by the user exist in the app and that there are no duplicate person indexes in the command. -
EditGroupCommand
edits the group at given index by calling its own private static methodEditGroupCommand#createEditGroup(Group, EditGroupDescriptor)
. -
EditGroupCommand
obtains a copy of theFilteredGroupList
by calling theModel#getFilteredGroupList()
method. This is used to check if the edited group already exits in the app. -
As a last step,
EditGroupCommand
creates aCommandResult
withSuccessMessage
andViewType
and returns it toLogicManager
.
The above process is shown in the following sequence diagram:
The following activity diagram summarises the general workflow for the Edit Group Feature
4.7.2. Design Considerations
Aspect: What and how to edit
-
Alternative 1 (current choice): Only edit parameters that are supplied. For the parameters that are supplied, overwrite the existing entry.
-
Pros: The single edit group feature can achieve both addition and deletion of members as well as renaming of the group. Better maintainability of code.
-
Cons: Overwriting all existing entries might affect usability as the user will have to re-enter the current member indexes if they want to add to member indexes rather than delete.
-
-
Alternative 2: Only edit parameters that are supplied. For the parameters that are supplied, add to the existing entries instead of overwriting.
-
Pros: The user will not have to re-enter member indexes if they choose to retain members inside a group.
-
Cons: Will require implementing a separate command to then delete member indexes from a group. This can also confuse the user if there are too many commands.
-
-
Alternative 3: Edit all parameters. Overwrite all existing entries.
-
Pros: Simplest to implement in terms of code. Will require less code than alternative 1 and 2.
-
Cons: Cumbersome for the user as they have to enter an attribute value even if they don’t want to change it.
-
4.8. Add Event Feature
[written by: Ernest Lian Qi Quan]
The add event feature allows users to add an event to a saved contact or group in CoderLifeInsights specified using the member m/
tag or the group g/
tag.
4.8.1. Implementation
Command: add_event ACTIVITY m/INDEX time/TIME place/PLACE
or add_event ACTIVITY g/INDEX time/TIME place/PLACE
Remarks:
-
TIME is the variable used to store the time the user has spent with a saved contact or group.
-
TIME parameter must contain at least 2 digits. For example: A time of 1 hour and 30 minutes will be input as
130
. -
An event added must have time of at least 1 minute. e.g. time/01
-
PLACE and ACTIVITY are case-sensitive
Example usage: add_event date night m/1 time/230 place/Gardens by the Bay
The command above will add the following to the Person whose index is 1
on the filtered or unfiltered list:
-
Activity
date night
into the Person’s activityList. -
Place
Gardens by the Bay
into the Person’s placeList. -
Time
230
which equals 2 hours and 30 minutes, will be added to the Person’s time.
It will also create an Event with the following attributes:
-
Activity:
date night
-
Place:
Gardens by the Bay
-
Time:
2h 30m
The sequence diagram below showcases how the command works with a valid input:
Depicted below is the class diagram of the Event class, displaying how the UniqueEventList and Event classes are associated to the AddressBook class:
The Event created is stored in an UniqueEventList, which is saved to the Json file as well. The Events saved are used to generate output for features.
The following class diagram shows how the Time, PlaceList and ActivityList are associated with a Person object. The Person class only displays relevant information to the Time, PlaceList and ActivityList classes:
The Time, ActivityList and PlaceList classes were implemented similar to a Person’s Name or Address. A Person’s Time is displayed on the GUI as well for users to know how much time they have spent with that Person.
The reason behind this implementation was to ensure that information added from the AddEventCommand would be saved through changes to Persons or Groups in CoderLifeInsights.
The pertinent information would then be used in following features which require these data to generate output.
A Group object also has the same implementation of Time, PlaceList and ActivityList and its class diagram is similar to the diagram above, with the Person class being substituted by the Group class.
These information are also saved for the Group object when an Event is added to a Group object.
The following activity diagram depicts the following scenario:
-
User enters
add_event date night m/1 time/230 place/Gardens by the Bay
into the command prompt. -
The
LogicManager
callsAddressBookParser#parseCommand()
. -
The method
AddressBookParser#parseCommand()
creates aAddEventCommandParser
and calls theAddEventCommandParser#parse()
method. -
AddEventCommandParser#parse()
checks if input is valid. -
AddEventCommandParser#parse()
then creates a new instance of anEvent
. -
AddEventCommandParser#parse()
then creates a new instance ofAddEventCommand
, with the createdEvent
as it’s parameter. -
AddEventCommand
calls theAddEventCommand#execute()
method. -
AddEventCommand#execute()
retrieves the filtered list with the call tomodel#getFilteredPersonList()
. -
AddEventCommand#execute()
then retrieves the Person object to be edited with the call tomodel#getFilteredPersonList()#get()
. -
AddEventCommand#execute()
then computes the new Time by retrieving the Person’s current Time with the call toperson#getTime()
,then adding it to the input Time. -
AddEventCommand#execute()
then creates a new ActivityList by retrieving the Person’s ActivityList with the call toperson#getActivityList2()
, followed byActivityList#addActivity()
, which returns a new ActivityList with the new activity added. -
AddEventCommand#execute()
then creates a new PlaceList by retrieving the Person’s PlaceList with the call toperson#getPlaceList2()
, followed byPlaceList#addPlace()
, which returns a new PlaceList with the new place added. -
AddEventCommand#execute()
then creates a new Person object with all the same attributes except for the Time, PlaceList, and ActivityList which is replaced by the new Time computed, the new PlaceList and the new ActivityList with the call to the Person constructor. -
AddEventCommand#execute()
then replaces the existing Person object with the new Person object with the call tomodel#setPerson()
. -
AddEventCommand#execute()
then updates the filtered list with the call tomodel#updateFilteredPersonList()
. -
AddEventCommand#execute()
then updates the UniqueEventList with the call tomodel#addEvent()
, which adds the createdEvent
to the UniqueEventList. -
AddEventCommand
returns theCommandResult
toAddressBookParser
. -
AddressBookParser
returns theCommandResult
toLogicManager
.
4.8.2. Justification
The Add Event feature and the relevant classes were added and implemented to add and store Events and relevant data that are used to generate output for other features such as insights.
4.9. Insights feature
[written by: Mah Cai Jun, Terence]
The Insights feature displays various insights about the persons, groups and events stored in Coder Life Insights.
It is activated by the command word view
.
4.9.1. Implementation
There are 4 key steps, as labelled in the diagram above, that are essential to how the Insights feature
and view
functionality are implemented. Rather than updating the model with incoming information, this
command is concerned with retrieving updated information from the model, and displaying the right information
by switching between the various possible view panels on the GUI.
To ensure that up-to-date information is retrieved, the Model contains ObservableLists
which allow
listeners to be updated whenever the list contents are updated.
In Step 1, the ViewCommand
object updates the relevant ObservableList
in the ModelManager
with the user’s desired information. It checks the appropriate view panel for displaying the desired
information, represented as a ViewType
Enum within the returned CommandResult
. In Step 2,
the MainWindow
retrieves the appropriate ViewType
from the CommandResult
, thus knowing which
view panel to use. In Step 3, it retrieves the appropriate ObservableList
from the Model, previously
updated by the ViewCommand
. In Step 4, it displays, on the view panel determined in Step 2, the
information retrieved from Step 3.
The class diagram below depicts the key relationships between the important features.
The main GUI controller, MainWindow
, composes the Logic component, which in turn composes
the Model component. This allows MainWindow
to access the ObservableLists
in the Model.
4.10. [Proposed] Undo/Redo feature
4.10.1. Proposed Implementation
The undo/redo mechanism is facilitated by VersionedAddressBook
.
It extends AddressBook
with an undo/redo history, stored internally as an addressBookStateList
and
currentStatePointer
.
Additionally, it implements the following operations:
-
VersionedAddressBook#commit()
— Saves the current CoderLifeInsights state in its history. -
VersionedAddressBook#undo()
— Restores the previous CoderLifeInsights state from its history. -
VersionedAddressBook#redo()
— Restores a previously undone CoderLifeInsights state from its history.
These operations are exposed in the Model
interface as Model#commitAddressBook()
, Model#undoAddressBook()
and Model#redoAddressBook()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time.
The VersionedAddressBook
will be initialized with the initial CoderLifeInsights state, and the currentStatePointer
pointing to that single CoderLifeInsights state.
Step 2. The user executes delete 5
command to delete the 5th person in the CoderLifeInsights.
The delete
command calls Model#commitAddressBook()
, causing the modified state of the CoderLifeInsights after the delete 5
command executes to be saved in the addressBookStateList
, and the currentStatePointer
is shifted to the newly inserted address book state.
Step 3. The user executes add n/David …
to add a new person.
The add
command also calls Model#commitAddressBook()
, causing another modified CoderLifeInsights state to be saved into the addressBookStateList
.
If a command fails its execution, it will not call Model#commitAddressBook() , so the CoderLifeInsights state will not be saved into the addressBookStateList .
|
Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the undo
command.
The undo
command will call Model#undoAddressBook()
, which will shift the currentStatePointer
once to the left, pointing it to the previous CoderLifeInsights state, and restores the CoderLifeInsights to that state.
If the currentStatePointer is at index 0, pointing to the initial CoderLifeInsights state, then there are no previous CoderLifeInsights states to restore.
The undo command uses Model#canUndoAddressBook() to check if this is the case.
If so, it will return an error to the user rather than attempting to perform the undo.
|
The following sequence diagram shows how the undo operation works:
The lifeline for UndoCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
The redo
command does the opposite — it calls Model#redoAddressBook()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and restores the CoderLifeInsights to that state.
If the currentStatePointer is at index addressBookStateList.size() - 1 , pointing to the latest CoderLifeInsights state, then there are no undone CoderLifeInsights states to restore.
The redo command uses Model#canRedoAddressBook() to check if this is the case.
If so, it will return an error to the user rather than attempting to perform the redo.
|
Step 5. The user then decides to execute the command list
.
Commands that do not modify the CoderLifeInsights, such as list
, will usually not call Model#commitAddressBook()
, Model#undoAddressBook()
or Model#redoAddressBook()
.
Thus, the addressBookStateList
remains unchanged.
Step 6. The user executes clear
, which calls Model#commitAddressBook()
.
Since the currentStatePointer
is not pointing at the end of the addressBookStateList
, all CoderLifeInsights states after the currentStatePointer
will be purged.
We designed it this way because it no longer makes sense to redo the add n/David …
command.
This is the behavior that most modern desktop applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
4.10.2. Design Considerations
Aspect: How undo & redo executes
-
Alternative 1 (current choice): Saves the entire CoderLifeInsights.
-
Pros: Easy to implement.
-
Cons: May have performance issues in terms of memory usage.
-
-
Alternative 2: Individual command knows how to undo/redo by itself.
-
Pros: Will use less memory (e.g. for
delete
, just save the person being deleted). -
Cons: We must ensure that the implementation of each individual command are correct.
-
Aspect: Data structure to support the undo/redo commands
-
Alternative 1 (current choice): Use a list to store the history of CoderLifeInsights states.
-
Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project.
-
Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both
HistoryManager
andVersionedAddressBook
.
-
-
Alternative 2: Use
HistoryManager
for undo/redo-
Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.
-
Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as
HistoryManager
now needs to do two different things.
-
4.11. Logging
We are using java.util.logging
package for logging.
The LogsCenter
class is used to manage the logging levels and logging destinations.
-
The logging level can be controlled using the
logLevel
setting in the configuration file (See Section 4.12, “Configuration”) -
The
Logger
for a class can be obtained usingLogsCenter.getLogger(Class)
which will log messages according to the specified logging level -
Currently log messages are output through:
Console
and to a.log
file.
Logging Levels
-
SEVERE
: Critical problem detected which may possibly cause the termination of the application -
WARNING
: Can continue, but with caution -
INFO
: Information showing the noteworthy actions by the App -
FINE
: Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size
4.12. Configuration
Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json
).
5. Documentation
We use asciidoc for writing documentation.
We chose asciidoc over Markdown because asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting. |
5.1. Editing Documentation
See UsingGradle.adoc to learn how to render .adoc
files locally to preview the end result of your edits.
Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc
files in real-time.
5.2. Editing Diagrams
See UsingPlantUml.adoc to find out how to create and update the UML diagrams in the developer guide.
5.3. Publishing Documentation
See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.
5.3.1. Converting Documentation to PDF format
We use Google Chrome for converting documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.
Here are the steps to convert the project documentation files to PDF format.
-
Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the
docs/
directory to HTML format. -
Go to your generated HTML files in the
build/docs
folder, right click on them and selectOpen with
→Google Chrome
. -
Within Chrome, click on the
Print
option in Chrome’s menu. -
Set the destination to
Save as PDF
, then clickSave
to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.
5.4. Site-wide Documentation Settings
The build.gradle
file specifies some project-specific asciidoc attributes which affects how all documentation files within this project are rendered.
Attributes left unset in the build.gradle file will use their default value, if any.
|
Attribute name | Description | Default value |
---|---|---|
|
The name of the website. If set, the name will be displayed near the top of the page. |
not set |
|
URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar. |
not set |
|
Define this attribute if the project is an official SE-EDU project. This will render the SE-EDU navigation bar at the top of the page, and add some SE-EDU-specific navigation items. |
not set |
5.5. Per-file Documentation Settings
Each .adoc
file may also specify some file-specific asciidoc attributes which affects how the file is rendered.
Asciidoctor’s built-in attributes may be specified and used as well.
Attributes left unset in .adoc files will use their default value, if any.
|
Attribute name | Description | Default value |
---|---|---|
|
Site section that the document belongs to.
This will cause the associated item in the navigation bar to be highlighted.
One of: * Official SE-EDU projects only |
not set |
|
Set this attribute to remove the site navigation bar. |
not set |
5.6. Site Template
The files in docs/stylesheets
are the CSS stylesheets of the site.
You can modify them to change some properties of the site’s design.
The files in docs/templates
controls the rendering of .adoc
files into HTML5. These template files are written in a mixture of Ruby and Slim.
Modifying the template files in |
6. Testing
6.1. Running Tests
There are two ways to run tests.
Method 1: Using IntelliJ JUnit test runner
-
To run all tests, right-click on the
src/test/java
folder and chooseRun 'All Tests'
-
To run a subset of tests, you can right-click on a test package, test class, or a test and choose
Run 'ABC'
Method 2: Using Gradle
-
Open a console and run the command
gradlew clean test
(Mac/Linux:./gradlew clean test
)
See UsingGradle.adoc for more info on how to run tests using Gradle. |
6.2. Types of tests
We have three types of tests:
-
Unit tests targeting the lowest level methods/classes.
e.g.seedu.address.commons.StringUtilTest
-
Integration tests that are checking the integration of multiple code units (those code units are assumed to be working).
e.g.seedu.address.storage.StorageManagerTest
-
Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
e.g.seedu.address.logic.LogicManagerTest
6.3. Troubleshooting Testing
Problem: Keyboard and mouse movements are not simulated on macOS Mojave, resulting in GUI Tests failure.
-
Reason: From macOS Mojave onwards, applications without
Accessibility
permission cannot simulate certain keyboard and mouse movements. -
Solution: Open
System Preferences
, clickSecurity and Privacy
→Privacy
→Accessibility
, and check the box besideIntellij IDEA
.
Accessibility
permission is granted to IntelliJ IDEA
7. Dev Ops
7.1. Build Automation
See UsingGradle.adoc to learn how to use Gradle for build automation.
7.2. Continuous Integration
We use Travis CI and AppVeyor to perform Continuous Integration on our projects. See UsingTravis.adoc and UsingAppVeyor.adoc for more details.
We also use Codeacy to automate code quality reviews. See Getting Started with Codacy for more details.
7.3. Continuous Deployment
[written by: Raivat Bhupesh Shah]
We maintain a site for this project here. To ensure that each PR complies with our site requirements for auto-deploy, we use Netlify for Continuous Deployment. Read this guide to get upto speed with Netlify CD.
7.4. Coverage Reporting
We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.
7.5. Documentation Previews
When a pull request has changes to asciidoc files, you can use Netlify to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged. See UsingNetlify.adoc for more details.
7.6. Making a Release
Here are the steps to create a new release.
-
Update the version number in
MainApp.java
. -
Generate a JAR file using Gradle.
-
Tag the repo with the version number. e.g.
v0.1
-
Create a new release using GitHub and upload the JAR file you created.
7.7. Pull Requests
Branch protection was applied to the master branch of the repository to protect from rogue merges. A mandatory review is required before a pull request can be merged into the master branch.
7.8. Managing Dependencies
A project often depends on third-party libraries. For example, Address Book depends on the Jackson library for JSON parsing. Managing these dependencies can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives:
-
Include those libraries in the repo (this bloats the repo size)
-
Require developers to download those libraries manually (this creates extra work for developers)
Appendix A: Product Scope
[written by: Raivat Bhupesh Shah]
Target user profile:
-
prefers command-line apps over GUI-intensive apps
-
can type fast
-
prefers typing over mouse input
-
is reasonably comfortable using CLI apps
-
has a need to manage and maintain their social life
-
wants to analyse data from their social life
Value proposition: provides insights of the user’s social life and encourages social interactions
Appendix B: User Stories
[written by: Raivat Bhupesh Shah]
Priorities: 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 by default |
minimize chance of someone else seeing them by accident. |
|
user with many persons in the CoderLifeInsights |
sort persons by name |
locate a person easily. |
|
user |
add time spent with a person |
track and analyse how much time has been spent with that person or the social group they belong to. |
|
user |
places I have been with a person |
track and analyse the different places the user has been with along the person. |
|
user |
add activity done with a person |
track and analyse types of activities done with that person or the social group they belong to. |
|
user |
import csv contacts |
build upon my existing contacts directory and not start from scratch. |
|
user |
export csv contacts |
take backup of my progress. |
|
user |
create a new social group |
track a cluster of people together, e.g. secondary school friends, JC friends, family, university friends etc. |
|
user |
assign persons to different groups |
track people I know from multiple places (Eg workplace and school both). |
|
user |
edit group |
change the name of a social circle. Add or remove people. |
|
user |
delete group |
remove social circles that are no longer needed. |
|
user |
list all groups |
get a glimpse of all social circles. |
|
user |
list specific group places |
know which places the group has been to. |
|
user |
list specific group activities |
know which activites the group has been doing. |
|
user |
list specific group time spent |
know how much time has been spent with this group. |
|
user |
randomly select person |
get a person to hangout with. |
|
user |
get suggestions on a person based time spent |
know who to hangout with. |
|
user |
get suggestions on an activity based on my activities done |
to know which activity to do. |
|
user |
get suggestions on a place based on my places visited |
know which place to go to. |
|
user |
get insights on places I have been to. |
get a glimpse of all the places I have been to. |
|
user |
get insights on time spent with all groups |
know time spent distribution within a group. |
|
user |
get insights on all activities done. |
know which activities I have done and their frequency. |
|
user |
get insights on time spent with individuals |
know the spread of time with all individuals. |
|
user |
get the last 5 events that happened |
get a glimpse of what I did the last 5 events. |
Appendix C: Use Cases
(For all use cases below, the System is the CoderLifeInsights
and the Actor is the user
, unless specified otherwise)
Use case: Delete person
[written by: Cheng Lit Yaw]
MSS
-
User requests to list persons
-
CoderLifeInsights shows a list of persons
-
User requests to delete a specific person in the list
-
CoderLifeInsights deletes the person
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. Specific person selected to be deleted not in list.
Use case resumes at step 2.
C.1. Use case: Add person
MSS
-
User requests to add person
-
CoderLifeInsights adds the person and displays their details
Use case ends.
Extensions
-
1a. No details of the person provided as arguments.
-
1a1. CoderLifeInsights shows an error message.
Use case resumes at step 2.
-
C.2. Use case: Find a person by name
[written by: Cheng Lit Yaw]
MSS
-
User requests to search a person with specified keyword
-
CoderLifeInsights displays a list of people matching the keyword specified
Use case ends.
Extensions
-
1a. No details of the person provided as arguments.
-
1a1. CoderLifeInsights shows an error message.
Use case resumes at step 2.
-
C.3. Use case: Add group
[written by: Raivat Bhupesh Shah]
MSS
-
User requests to add group
-
CoderLifeInsights adds the group and displays its details
Use case ends.
Extensions
-
1a. Group name not provided
-
1a1. CoderLifeInsights shows an error message.
Step 1 continues until name is provided
Use case resumes at step 2.
-
-
1b. Member indexes provided are invalid (don’t exist in the app)
-
1b1. CoderLifeInsights shows an error message.
Step 1 continues until valid member indexes are supplied or no indexes are supplied (member indexes are optional)
Use case resumes at step 2.
-
C.4. Use case: Delete Group
[written by: Raivat Bhupesh Shah]
Preconditions: group to be deleted exists in the app
MSS
-
User requests to delete group with specified index
-
CodeLifeInsights deletes the group and displays its details
Use case ends.
C.5. Use case: Edit Group
[written by: Raivat Bhupesh Shah]
Preconditions: group to be deleted exists in the app
MSS
-
User requests to edit group with specified index
-
CodeLifeInsights deletes the group and displays its details
Use case ends.
Extensions
-
1a. No values to edit are provided
-
1a1. CoderLifeInsights shows an error message telling the user a group can’t be edited with no new info.
Step 1 continues until at least one new value is provided.
Use case resumes at step 2
-
-
1b. If member indexes are provided, they are invalid (don’t exist in the app)
-
1b1. CoderLifeInsights shows an error message telling the user that one or more member indexes are invalid.
Step 1 continues until all member indexes provided are correct or no new member indexes are provided at all.
Use case resumes at step 2
-
C.6. Use case: List Group
[written by: Raivat Bhupesh Shah]
MSS
-
User requests to list all groups
-
CoderLifeInsights displays all the groups in a list format with their indexes, time spent, member indexes, and event ids.
Use case ends.
C.7. Use case: Export data
[written by: Cheng Lit Yaw]
MSS
-
User requests to export life, group and event data to specified CSV file path.
-
CoderLifeInsights exports data to specified CSV files.
Use case ends.
Extensions
-
1a. No file path specified.
-
1a1. CoderLifeInsights shows an error message.
Use case resumes at step 2.
-
C.8. Use case: Import data
[written by: Cheng Lit Yaw]
MSS
-
User requests to import life, group and event data from specified CSV file path.
-
CoderLifeInsights imports data from specified CSV files.
Use case ends
Extensions * 1a. No file path specified. ** 1a1. CoderLifeInsights shows an error message.
+ Use case resumes at step 2.
C.9. Use case: Suggest person
[written by: Cheng Lit Yaw]
MSS
-
User requests for suggestion of person.
-
CoderLifeInsights suggests a person to hangout with.
Use case ends
Extensions
* 1a.
No person available in CoderLifeInsights to suggest
Use case ends.
C.10. Use case: Suggest place
[written by: Cheng Lit Yaw]
MSS
-
User requests for suggestion of place.
-
CoderLifeInsights suggests a place to visit.
Use case ends
Extensions
* 1a.
No place available in CoderLifeInsights to suggest
Use case ends.
C.11. Use case: Suggest activity
[written by: Cheng Lit Yaw]
MSS
-
User requests for suggestion of activity.
-
CoderLifeInsights suggests an activity to do.
Use case ends
Extensions
* 1a.
No activity available in CoderLifeInsights to suggest
Use case ends.
C.12. Use case: View time
[written by: Cheng Lit Yaw]
MSS
1. User requests to view time comparison between individuals and groups.
2. CoderLifeInsights displays pie chart of Individual time spent vs Group time spent.
Use case ends
Extensions
-
1a. No event data for group or individual available for comparison.
Use case ends
C.13. Use case: Add an event with a person
[written by: Ernest Lian Qi Quan]
MSS
-
User wants to add an Event with the following details to the first person displayed on the Person List on CoderLifeInsights:
Activity:swimming
Place:pool
Time:1 hour and 30 minutes
-
User enters correct command with valid input and prefixes
-
Event is created and added to the Person
Use case ends
Extensions
-
2a. User enters incorrect command
-
2a1. Invalid command error is displayed
-
2a2. User re-enters valid command with valid input
Use case resumes at 3.
-
-
2b. User enters correct command but invalid input
-
2b1. Invalid command error is displayed
-
2b2. User re-enters valid and correct command with valid input
Use case resumes at 3.
-
-
2c. Person index specified is out of bounds
-
2c1. Invalid person index error message is displayed
-
2c2. User re-enters command with correct and valid person index
Use case resumes at 3.
-
C.14. Use case: Add an event with a group
[written by: Ernest Lian Qi Quan]
MSS
-
User wants to add an Event with the following details to the first group displayed on the Group List on CoderLifeInsights:
Activity:dancing
Place:dance studio
Time:1 hour and 30 minutes
-
User enters correct command with valid input and prefixes
-
Event is created and added to the Group
Use case ends
Extensions
-
2a. User enters incorrect command
-
2a1. Invalid command error is displayed
-
2a2. User re-enters valid command with valid input
Use case resumes at 3.
-
-
2b. User enters correct command but invalid input
-
2b1. Invalid command error is displayed
-
2b2. User re-enters valid and correct command with valid input
Use case resumes at 3.
-
-
2c. Group index specified is out of bounds
-
2c1. Invalid group index error message is displayed
-
2c2. User re-enters command with correct and valid group index
Use case resumes at 3.
-
C.15. Use case: View the places or activities visited with a group
[written by: Ernest Lian Qi Quan]
MSS
-
User wants to view insights on the places or activities been to or carried out with a group.
-
User enters view group command
-
CoderLifeInsights displays the requested information in table form for the user.
Use case ends
Extensions
-
2a. User enters valid command with invalid group index
-
2a1. Invalid group index error message is displayed
-
2a2. User re-enters command with a valid group index
Use case resumes at 3.
-
Appendix D: 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.
-
Should be easy to log info onto the application.
-
Should not require user to install
-
Features implemented should be testable using automated and manual testing.
-
Should work for a single user only.
-
Should be able to run with or without internet connection.
Appendix E: Glossary
- Mainstream OS
-
Windows, Linux, Unix, macOS
- Private contact detail
-
A contact detail that is not meant to be shared with others
- CoderLifeInsights
-
An application.
- Event
-
An event is an event that the user took part in, either with another individual or group. An event has an activity (what the user engaged in), a place, time spent and the person/group.
- Time
-
Time represents the time spent in an event. It is represented by number of hours (0 or greater) and number of minutes (between 0 and 59 inclusive).
Appendix F: Instructions for Manual Testing
Given below are instructions to test the app manually.
These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. |
F.1. 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.
-
F.2. Deleting a person
-
Deleting a person while all persons are listed
-
Prerequisites: List all persons using the
list
command. Multiple persons 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 person 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) {give more}
Expected: Similar to previous.
-
F.3. Finding a person
[written by: Cheng Lit Yaw]
-
Finding a person with keywords
-
Prerequisites: Have person data containing keyword available for search.
-
Test case:
find betty
Expected: Details of betty shown in GUI. -
Test case:
find jjjjjjjj
Expected: No detail of jjjjjjjj shown in GUI. 0 persons listed! shown in status message. Nothing displayed in Person column. -
Other incorrect find commands to try:
find
,find ukloiuj
Expected: Similar to previous.
-
F.4. Suggest a person
[written by: Cheng Lit Yaw]
-
Suggest a person to hangout with
-
Prerequisites: Have person data with event added for suggestion.
-
Test case:
suggest person
Expected: Details of person with the least time spent shown in People column
-
-
Suggest person with no events added.
-
Prerequisites: Have person data with no events added.
-
Test case:
suggest person
Expected: The last People alphabetically in CoderlifeInsights shown in People column.
-
-
Suggest person with no person data.
-
Prerequisites: Have no person data in CoderLifeInsights
-
Test case:
suggest person
Expected: Nothing shown in People column. Person suggestion provided shown in status message.
-
F.5. Suggest a place
[written by: Cheng Lit Yaw]
-
Suggest a place to visit
-
Prerequisites: Have events added for suggestion.
-
Test case:
suggest place
Expected: Details of place with the least frequency visited shown in Insights column
-
-
Suggest place with no events added.
-
Prerequisites: Have data with no events added.
-
Test case:
suggest place
Expected: Nothing shown in Insights column. Place suggestion provided shown in status message.
-
F.6. Suggest an activity
[written by: Cheng Lit Yaw]
-
Suggest an activity to do.
-
Prerequisites: Have events added for suggestion.
-
Test case:
suggest activity
Expected: Details of activity with the least frequency visited shown in Insights column
-
-
Suggest activity with no events added.
-
Prerequisites: Have data with no events added.
-
Test case:
suggest activity
Expected: Nothing shown in Insights column. Activity suggestion provided shown in status message.
-
F.7. Import CoderLifeInsights data
[written by: Cheng Lit Yaw]
-
Import life, group and event data.
-
Prerequisites: CSV files containing named
life.csv
,group.csv
andevent.csv
data available in specified path. No duplicates of person, group and events available in CoderLifeInsights. -
Test case:
import l/life.csv g/group.csv e/event.csv
Expected: People column populated with person data.
Insights column populated with time data.
Groups column populated with group data.
Files imported: life.csv groups.csv events.csv shown in status message.
-
-
Import life, group and event data with non-existent file.
-
Prerequisites: CSV files of provided path does not exist.
-
Test case: `import l/test.csv g/grouptest.csv e/eventtest.csv Expected: CoderLifeInsights will return error message showing that path provided does not exist.
-
F.8. Export CoderLifeInsights data
[written by: Cheng Lit Yaw]
-
Export life, group and event data.
-
Prerequisites: CSV files of provided file name must not exist.
-
Test case:
export l/life.csv g/group.csv e/event.csv
Expected: All valid life, group and event data will be exported to the respective CSV files.
-
-
Export life, group and event data with CSV files that exist in path provided.
-
Prerequisites: CSV files of provided file name must exist.
-
Test case:
export l/life.csv g/group.csv e/event.csv
Expected: CoderLifeInsights will return error message showing that files already exist. Another naming convention is required.
-
F.9. Adding an event
[written by: Ernest Lian Qi Quan]
-
Add an event to a person or group saved in CoderLifeInsights
-
Prerequisites: Have a person or group saved in CoderLifeInsights
-
Test case 1 (adding an event to a person):
add_event anything place/anywhere time/30 m/1
Expected: New event successfully added: Event: anything place: anywhere for 0h 30m -
Test case 2 (adding an event to a group):
add_event anything place/anywhere time/30 g/1
Expected: New event successfully added: Event: anything place: anywhere for 0h 30m
-
-
Adding an event to a person or group not saved in CoderLifeInsights
-
Prerequisites: Choose an index that is greater than the number of persons and groups saved in CoderLifeInsights, for example, 100 for the sample test data
-
Test case 1(adding an event to a person):
add_event anything place/anywhere time/30 m/100
Expected: The person index provided is invalid -
Test case 2 (adding an event to a group):
add_event anything place/anywhere time/30 g/100
Expected: The group index provided is invalid
-
-
Adding an event to a person or group with time spent of 0 hours and 0 minutes:
-
Prerequisites: Have a person or group saved in CoderLifeInsights
-
Test case 1 (adding an event to a person):
add_event anything place/anywhere time/00 m/1
+ Expected: Time parameter has to be greater than 0 minutes -
Test case 2 (adding an event to a group):
add_event anything place/anywhere time/00 g/1
Expected: Time parameter has to be greater than 0 minutes
-
-
Adding an event with required fields missing:
-
Prerequisites: Have a person or group saved in CoderLifeInsights
-
Testcase 1:
add_event place/anywhere time/30 m/1
-
Testcase 2:
add_event anything place/ time/30 m/1
-
Testcase 3:
add_event anything time/30 m/1
-
Testcase 4:
add_event anything place/anywhere time/ m/1
-
Testcase 5:
add_event anything place/anywhere m/1
-
Testcase 6:
add_event anything place/anywhere time/30
-
Testcase 7:
add_event
Expected: Invalid command format!
add_event: Creates an event with a group or an individual that adds an activity, place and time to the subject.
Parameters: ACTIVITY place/PLACE m/INDEX time/TIME
OR
Parameters: ACTIVITY place/PLACE g/INDEX time/TIME
Example: add_event Dancing place/SCAPE m/1 time/300
-
-
Adding an event with an invalid person or group index
-
Prerequisites: Have a person or group saved in CoderLifeInsights
-
Testcase 1:
add_event anything place/anywhere time/30 m/
-
Testcase 2:
add_event anything place/anywhere time/30 m/s
-
Testcase 3:
add_event anything place/anywhere time/30 m/1 s
Expected: Index is not a non-zero unsigned integer.
-
-
Adding an event with an invalid time
-
Prerequisites: Have a person or group saved in CoderLifeInsights
-
Testcase 1:
add_event anything place/anywhere time/0 m/s
-
Testcase 2:
add_event anything place/anywhere time/30s m/s
-
Testcase 3:
add_event anything place/anywhere time/test m/s
Expected: Time parameter needs to be unsigned integers of at least 2 digits.
For example: [5 minutes = 05]; [1 hour = 100]; [10 hours and 30 minutes = 1030]
-
-
Adding an event to both group and member at the same time
-
Prerequisites: None
-
Testcase 1:
add_event anything place/anywhere time/30s m/1 g/1
Expected: Invalid command format!
add_event: Creates an event with a group or an individual that adds an activity, place and time to the subject.
Parameters: ACTIVITY place/PLACE m/INDEX time/TIME
OR
Parameters: ACTIVITY place/PLACE g/INDEX time/TIME
Example: add_event Dancing place/SCAPE m/1 time/300
-
F.10. Add a Group
[written by: Raivat Bhupesh Shah]
-
Adding an empty group
-
Prerequisites: None
-
Test case:
add_group n/empty_group_name
Expected: New group added to CoderLifeInsights, new group displayed in groups panel and success message displayed to the user.
-
-
Adding a group with members (Persons)
-
Prerequisites: Member indexes must exist in the app. Hence, add as many members you want as `Person' before.
-
For example, add a Person using the command
add_person n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]
-
Note down the person indexes for persons whom you want as members of the new group
-
-
Test case:
add_group n/new_group_name m/1 m/2 …
Expected: New group added to CoderLifeInsights, new group displayed in groups panel and success message displayed to the user.
-
F.11. Delete a Group
[written by: Raivat Bhupesh Shah]
-
Deleting an existing group
-
Prerequisites: the group to be removed must exist in CoderLifeInsights.
-
If for example the app contains no groups, add a group using
add_group n/delete_demo
. It should have index 1.
-
-
Test case:
delete_group 1
Expected: Group deleted from the app and success message shown to the user.
-
-
Deleting a non-existent group
-
Prerequisites: the group to be deleted (referenced by the index) must not exist in CoderLifeInsights. To be safe, use the index that is 1 more than the largest index of the current groups. You can find the largest index using
list_groups
and observing the last group entry. If the app has 99 groups, choose 100 as the index of the group to be deleted. -
Test case:
delete group 100
Expected: Group not deleted as there is no group at given index. Error message shown to user saying Group Index specified is invalid.
-
F.12. Edit a Group
[written by: Raivat Bhupesh Shah]
-
Editing all fields possible of an existing group
-
Prerequisites: the group to be edited must exist in CoderLifeInsights. Follow
8.9
to create a group in the app if one doesn’t exit already. Note down the index of the group either when it is created or using the group list on the right in the GUI. The new members to be included in the group must also exist in the app. -
Test case: If you want to edit the group with index 1 and change member list to only have person with index 1, enter
edit_group 1 n/new_name m/1
. Expected: Group at index 1 is changed. Name isnew_name
whereasmembers
now only has1
(instead of the indexes that existed earlier).
-
-
Editing the name of an existing group
-
Prerequisites: the group to be edited must exist in CoderLifeInsights.
-
Test case:
edit_group 1 n/another_name
. Expected: The name of group at index 1 is changed ofanother_name
. Success message displayed to the user. The member list of the group at index 1 remains unchanged.
-
-
Editing the member indexes of an existing group
-
Prerequisites: the new member indexes must exist in CoderLifeInsights.
-
Test case:
edit_group 1 m/1 ..
. Expected: The member list of the group at index 1 is changed to the new member indexes supplied. The name of the group at index 1 remains unchanged. Success message is displayed to the user.
-
-
Editing a non-existent group
-
Prerequisites: the group at specified index must not exist in CoderLifeInsights. Pick an index that is larger than the current largest index of groups in the app. If 99 is the largest index, choose 100.
-
Test case:
edit_group 100
. Expected: Error message saying group index is invalid is displayed to the user.
-
F.13. List all Groups
[written by: Raivat Bhupesh Shah]
-
List all groups
-
Prerequisites: None.
-
Test Case:
list_groups
Expected: the group panel will show all the groups currently in the app. If there are no groups, it will be blank. A success message will be shown to the user.
-
F.14. Exiting the program
[written by: Cheng Lit Yaw]
-
Exit the program
-
Test Case:
exit
Expected: Exits the program.
-
Appendix G: Effort
To develop and implement the features we have for CoderLifeInsights was difficult and time consuming. For a project of this size, effective communication was required amongst the team members and the situation was made worse due to quarantine measures of the COVID-19. As a result, conflicts arose in the group but was quickly resolved for the better of the project. All of us dealt with the situation professionally and was determined to complete and deliver CoderLifeInsights as a working application.
Some difficulties that we face during implementation of CoderLifeInsights:
-
Multiple entity implementation:
-
Designing
Event
andGroup
class was challenging as we had to consider the data being stored in each class that would be independent of the existingPerson
class. A great deal architecture analysis was done to avoid dependency between classes. At the same time, we enhanced thePerson
class to store additional information according to our user’s needs.
-
-
JSON Implementation
-
We have to learn about the JSON packages that were available and apply it to not only existing
Person
class but alsoEvent
in the form ofUniqueEventList
andGroup
class similar toPerson
. This also required an in-depth understanding of Java data structures andOptional
class. -
With this implementation, we were able to develop the
import
andexport
features to enable the user to transfer data from one computer to another. This is crucial to our user as programmers would work between multiple computers and would want to keep a backup and keep their data in sync across computers.
-
-
Redesigning UI of AB3
-
Considering our lack of knowledge in UI designs and JavaFX, we had to learn to implement the PanelLists as well as the Pie Chart class to display meaningful information to our users. In total we had more than 3 PanelLists and all of which had to interact with each of the features implemented. The flow of the application in between each command was also well thought out and seamless.
-
We further enhanced the UI from AB3 from a single column application to a resizable multiple column application. In order for the application columns to fit the desired window size of the user, each column size was carefully measured and well thought out to fit our user’s need as a programmer. The colors were carefully selected to brighten up the user’s mood after a long day of work. As it is a social application, bright color scheme would be ideal.
-
After going through this project, we not only learnt good Software Engineering practices but also communication skills between team members that was crucial to the success of CoderLifeInsights. As we have invested a significant amount of time towards this project, we aim to continue developing the application during the summer holidays to further enhance the features of the project.
A cluster of 0 or more other people with a commonality as identified by the user (eg same JC, same OG, etc). An empty `Group`is allowed since it is assumed that the user themselves is a member of the social group (which is why they would want to track it.)