PROJECT: The Real App


Overview

The Real App is an enhanced desktop address book designed primarily for real estate agents. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.

Summary of contributions

  • Major enhancement: Transform the model to allow for client contact and property information to be stored, modified and accessed.

    • What it does: allows The Real App to treat each entry as a customer to process and store the relevant information.

    • Justification: This feature forms the underlying model of The Real App and allows the user to use The Real App to store customer and real estate information.

    • Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required extensive changes to many existing components, such as logic, model, storage and ui .

  • Minor enhancement:

    • Modify add command to allow user to add entries into the revamped contact book.

    • Modify edit command to allow user to edit entries in the revamped contact book.

    • Transform existing find command into search command to allow user to search and retrieve information.

    • Integrate new search command with the archive feature.

    • Modify UI to display all the information of customers and properties.

  • Code contributed: [Project Code Dashboard]

  • Other contributions:

    • Project management:

      • Set up the organisation Github and the team repo.

      • Set up Travis-CI and Coverall.

      • Set up auto-publishing of documentation.

    • Documentation:

      • Update product name in README.adoc and modified Ui.png: #1

      • Update AboutUs.adoc and add photo for tanlongbin #12

      • Update User Guide: #78 #87 #154

      • Update Developer Guide: #92 #157

    • Community:

      • PRs reviewed (with non-trivial review comments): #64, #68

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

Starting the app

  1. Double-click the file to start the app. The GUI should appear in a few seconds.

    UiExplained
  2. Type the command in the command box and press Enter to execute it.
    E.g. typing help and pressing Enter will open the help window.

  3. The outcome of the command will be displayed in the result display box.
    E.g. after successfully executing the help command, the following message will appear:
    Opened help window.
    Displaying main person list!

  4. The pin list shows the contacts who has been pinned. It can be resized by clicking and dragging the borders of the box.

  5. The main contact list shows the active list of contacts. It can also be resized by clicking and dragging the borders of the box. You can toggle between the contact list view and the archive list view using commands list and archivelist.

  6. The browser window will display the property’s location on Google Maps™ when an appropriate contact is selected. You can go to [GoogleMaps] for more details of the Google Maps™ display.

Adding a contact : add

Adds a contact to the contact book, with 4 variants of customer types. Adds the associated property information for sellers and landlords.

KEYWORD List: c/CUSTOMER_TYPE, n/NAME, p/PHONE_NUMBER, e/EMAIL, r/REMARK, a/ADDRESS, rp/RENTAL_PRICE_OF_PROPERTY, sp/SELLING_PRICE_OF_PROPERTY, t/TAG

Accepted customer types: seller, buyer, landlord, tenant
NAME, PHONE, EMAIL & REMARK are compulsory for all customers.
ADDRESS & SELLING_PRICE of property are compulsory for sellers.
ADDRESS & RENTAL_PRICE of property are compulsory for landlords.

A property can have any number of TAG (including 0).
  • Seller:
    Format: add c/seller n/NAME p/PHONE_NUMBER e/EMAIL r/REMARKS a/ADDRESS sp/SELLING_PRICE_OF_PROPERTY [t/TAG]…​
    Example: add c/seller n/James Tan p/97652456 e/jamestan@example.com r/need to sell by April 2018 a/Blk 345 Clementi Ave 5, #04-04, S120345 sp/500000 t/MRT t/newlyRenovated

  • Buyer:
    Format: add c/buyer n/NAME p/PHONE_NUMBER e/EMAIL r/REMARKS
    Example: add c/buyer n/James Ho p/87657252 e/jamesho@example.com r/looking for 3-room apartment

  • Landlord:
    Format: add c/landlord n/NAME p/PHONE_NUMBER e/EMAIL r/REMARKS a/ADDRESS rp/RENTAL_PRICE_OF_PROPERTY [t/TAG]…​
    Example: add c/landlord n/Hans Tan p/90826522 e/hanstan@example.com r/family friend a/Blk 345 Woodlands Street 32, #04-04, S730345 rp/1500 t/MRT t/newlyRenovated

  • Tenant:
    Format: add c/tenant n/NAME p/PHONE_NUMBER e/EMAIL r/REMARKS
    Example: add c/tenant n/Bo Yang p/86541526 e/boyang@example.com r/looking for 4-room apartment

When multiple parameters of the same type are entered, only the last one will be added. e.g. add …​ p/97642542 p/87654321 …​, only 87654321 will be saved to the contact.

Screenshots for 1st example:

  • Enter add c/seller n/James Tan p/97652456 e/jamestan@example.com r/need to sell by April 2018 a/Blk 345 Clementi Ave 5, #04-04, S120345 sp/500000 t/MRT t/newlyRenovated:

add screenshot 1
  • Client James Tan is successfully added, the contact list is updated and the newly added contact is selected:

add screenshot 2

Displaying a sorted list of contacts by specified category : sort [coming in v2.0]

Shows a list of all contacts in the contact book, sorted according to a specified category.
Format: sort CATEGORY [CATEGORY_RESTRICTOR] ORDER

CATEGORY List: n, sp, rp
CATEGORY_RESTRICTOR List: <NAME, >NAME, <SELLING_PRICE, >SELLING_PRICE, <RENTAL_PRICE, >RENTAL_PRICE
ORDER List: ascending, decreasing

  • Sort methods:

    • Sort by contact name n greater or smaller than specified name in ascending/decreasing alphabetical order

    • Sort by selling price of property sp greater or smaller than specified selling price in ascending/decreasing order

    • Sort by rental price of property rp greater or smaller than specified rental price in ascending/decreasing order

Example: sort sp <540000 ascending
Displays the contact list sorted by price less than $540,000 in ascending order.

Example: sort n ascending
Displays the contact list sorted by name in ascending alphabetical order.

Searching for contact(s) by keyword(s) : search

Search for contact(s) whose information contains any of the keyword(s).
e.g. search by name, search by address, search by tags etc.
Format: search KEYWORD [KEYWORD]…​

KEYWORD List: CUSTOMER_TYPE, NAME, PHONE_NUMBER, EMAIL, REMARK, ADDRESS, t/TAG

  • The search is case insensitive. e.g hans will match Hans

  • The order of the keywords does not matter. e.g. Hans Bo will match Bo Hans

  • Keywords will be searched for match in any of the abovementioned information categories. e.g. adam will match customers named Adam and/or customers with property on Adam Road.

  • Keywords of different information category can be combined in the same search command. e.g. search adam clementi 98752432.

  • Only full words will be matched e.g. Han will not match Hans

  • Contacts matching at least one keyword will be returned (i.e. OR search). e.g. Hans Bo will return Hans Gruber, Bo Yang

Examples:

  • search James
    Returns James Tan and James Ho

  • search James Tan Yang
    Returns any contact with information matching James, Tan, or Yang

  • search Woodlands Landlord
    Returns any contact with information matching Woodlands or Landlord

Screenshots for 1st example:

  • Enter search James:

search screenshot 1
  • The search is executed successfully and the contact list is updated to show James Tan and James Ho.

search screenshot 2

Editing a contact : edit

Edits an existing contact and/or associated property (if any) in the contact book, with 4 variants of customer types.

  • Edits the contact at the specified INDEX. The index refers to the index number shown in the displayed contact list. The index must be a positive integer 1, 2, 3, …​

  • At least one of the optional fields must be provided.

  • Existing values will be updated to the input values.

  • When editing tags, the existing tags of the property will be removed i.e adding of tags is not cumulative.

  • You can remove all the property’s tags by typing t/ without specifying any tags after it.

  • Seller:
    Format: edit INDEX_SELLER [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [r/REMARKS] [a/ADDRESS] [sp/SELLING_PRICE_OF_PROPERTY] [t/TAG]…​
    Example: edit 2 n/James Li e/jamesli@example.com sp/450000 t/

    • Edits the name and email address of the 2nd contact to be James Li and jamesli@example.com respectively. Edits selling price of the associated property to be 450000 and clears all existing tags.

  • Buyer:
    Format: edit INDEX_BUYER [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [r/REMARKS]
    Example: edit 2 n/James Han e/jameshan@example.com r/looking for houses in Woodlands

    • Edits the name, email address and remarks of the 2nd contact to be James Tan, jamestan@example.com and looking for houses in Woodlands respectively.

  • Landlord:
    Format: edit INDEX_LANDLORD [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [r/REMARKS] [a/ADDRESS] [rp/RENTAL_PRICE_OF_PROPERTY] [t/TAG]…​
    Example: edit 2 n/Jim Lee p/87654321 rp/1700 t/MRT t/Park

    • Edits the name and phone number of the 2nd contact to be Jim Lee and 87654321 respectively. Edits rental price of the associated property to be 1700, clears all existing tags and adds new tags MRT and Park.

  • Tenant:
    Format: edit INDEX_TENANT [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [r/REMARKS]
    Example: edit 2 n/James p/87654322

    • Edits the name and phone number of the 2nd contact to be James and 87654322 respectively.

The customer type of the contact cannot be changed and only information type relevant to the customer type can be modified.

When multiple parameters of the same type are entered, only the last one will be edited. e.g. edit …​ p/97642542 p/12345678 …​, only 12345678 will be saved to the contact.

Screenshots for 1st example:

  • Enter list:

archive screenshot 1
  • Main contact list is displayed:

edit screenshot 1
  • Make sure that the contact at index 2 is a seller, otherwise choose the correct index corresponding to a seller.
    Enter edit 2 n/James Li e/jamesli@example.com sp/450000 t/:

edit screenshot 2
  • Contact at index 2 is now edited to James Li and the information are updated accordingly. The contact is also selected upon successful execution of the edit command:

edit screenshot 3

Searching for archived contact(s) : archivesearch

Searches the archive and finds contact(s) whose information contains any of the keyword(s).
Format: archivesearch KEYWORD [KEYWORD]…​

  • Archive list must be displayed prior to this.

  • KEYWORD List: CUSTOMER_TYPE, NAME, PHONE_NUMBER, EMAIL, REMARK, ADDRESS, t/TAG

Example:

  • archivesearch James Seller
    Returns any contact with information fields matching keywords James and/or Seller

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Model component

ModelClassDiagram
Figure 1. Structure of the Model Component

API : Model.java

The Model,

  • stores a UserPref object that represents the user’s preferences.

  • stores the Address Book, Archive Book and Pin Book data as 3 separate instances of the AddressBook class.

  • 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.

  • 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 Property can reference. This would allow Address Book to only require one Tag object per unique Tag, instead of each Property needing their own Tag object. An example of how such a model may look like is given below.

ModelClassBetterOopDiagram

Transformation of AddressBook4 to The Real App

Current Implementation

To allow The Real App to store client contact and property information, the model of AB4 must be modified. The Person class has been modified to only contain the following 4 information:

  • Name — Encapsulates the name of a client in the model.

  • Phone — Encapsulates the phone of a client in the model.

  • Email — Encapsulates the email of a client in the model.

  • Remark — Encapsulates the remark associated with a client in the model.

The Person class has also been extended to the following 4 sub-classes to encapsulate the customer type and related information:

  • Buyer — Represents a client who is a buyer in the model.

  • Seller — Represents a client who is a seller in the model, contains additional property information.

  • Tenant — Represents a client who is a tenant in the model.

  • Landlord — Represents a client who is a landlord in the model, contains additional property information.

The abstraction of the property information is done through a Property class. The Property class encapsulates property information through the following 3 classes:

  • Address — Encapsulates the address of a property in the model.

  • Price — Encapsulates the price of a property in the model.

  • Tag — Encapsulates short keywords associated with a property in the model.

There are 2 ways through which client information can be added into the model. One is through user input in the add command, the other is through reading the storage json files at launch.

Given below is an example scenario of how client information can be added into the model via the 2 ways described above.

From storage

Step 1. The user launches the application.

Step 2. MainApp will find the addressbook, archivebook and pinbook json files in the data folder and get them as JsonAddressBookStorage objects.

Step 3. The JsonAddressBookStorage objects are used to initialise StorageManager.

Step 4. The MainApp calls initModelManager method which will eventually return a ModelManager object.

Step 5. To build the model, the StorageManager will build three AddressBook objects which are collections of all the Person objects stored in the addressbook, archivebook and pinbook json files.

Step 6. The three AddressBook objects are used to initialise the ModelManager, which creates the model.

The following sequence diagram summarizes how the model is created from json files when a user launches The Real App:

LaunchSequenceDiagram

Through add command

Step 1. The user launches the application.

Step 2. The user enters the add command with the correct parameters into the Command Box.
e.g. add c/seller n/James Tan p/97652456 e/jamestan@example.com r/need to sell by April 2018 a/Blk 345 Clementi Ave 5, #04-04, S120345 sp/500000 t/MRT t/newlyRenovated

Step 3. The LogicManager handles the user input and creates an AddCommand object.

Step 4. The AddCommand object is executed by the LogicManager.

Step 5. The ModelManager updates the model to add the contact into the AddressBook.

The following sequence diagram summarizes how a contact is added to the AddressBook using the add command:

AddSequenceDiagram

Other Improvements

To allow for modification and retrieval of information, the edit and search commands have been expanded to fit the new model.

Edit command

Edit command has been improved to handle the different types of contacts safely. Object type checking is done during the execution of the command to ensure that only the correct information associated with the customer type is edited. This also ensures that the returned object is the same class as the original object being edited.

Search command

The original find command in AB4 has been renamed to search command to better reflect its new functionality. search command can now search through multiple information fields to look for matches to the input keywords. This allows users to quickly retrieve contacts using whatever limited information they may have at hand.

Design Considerations

Aspect: Abstraction of different customer types
  • Alternative 1 (current choice): The four customer types are abstracted as sub-classes which extends the Person class

    • Pros: Allows for subclass polymorphism.

    • Cons: Legacy code from AB4 is not optimised for runtime polymorphism.

  • Alternative 2: Encapsulate customer type information in Person class using a CustomerType class.

    • Pros: Easy to implement.

    • Cons: Requires rigorous checking of customer type to ensure each contact is handled appropriately.

  • Alternative 3: Refactor Person class into an abstract class and extend the 4 subclasses from it

    • Pros: Prevents the initialisation of a Person object, which is not required in our application.

    • Cons: Much of the legacy code of AB4 has strong dependence on the instantiation of the Person objects.

Adding a client

  1. Adding a client to the app.

    1. Prerequisite: The app must be launched and the client does not already exist in the database.

    2. Test case: add c/seller n/James Tan p/97652456 e/jamestan@example.com r/need to sell by April 2018 a/Blk 345 Clementi Ave 5, #04-04, S120345 sp/500000 t/MRT t/newlyRenovated
      Expected: A new contact appears at the end of the contact list with all the relevant information added. Address location of the added contact is displayed on the Google Maps™ window panel(if applicable).

    3. Test case: add c/buyer n/James Ho e/jamesho@example.com r/looking for 3-room apartment
      Expected: Contact cannot be added as there are missing parameters. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect add commands to try: add c/seller p/86567123, add c/buyer n/James Ho. Expected: Similar to previous.

Edit a contact

  1. Editing an existing contact in the app.

    1. Prerequisite: The app must be launched and there are contacts currently in the database.

    2. Test case: edit x n/James Han e/jameshan@example.com r/looking for houses in Woodlands (where x is the index of a buyer contact)
      Expected: The buyer contact as index x will be edited with new name James Han, new email jameshan@example.com and new remark looking for houses in Woodlands. Other information remains the same.

    3. Test case: edit x n/James Li e/jamesli@example.com sp/450000 t/ (where x is the index of a contact who is not a seller)
      Expected: Contact cannot be edited as there are parameters that are not applicable to this customer type. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect edit commands to try: edit n/James, edit 1. Expected: Invalid command format.

Edit a contact

  1. Searching for a contact in the app.

    1. Prerequisite: The app must be launched and there are contacts currently in the database.

    2. Test case: search James
      Expected: The contact list will be updated to display all contacts with information matching the keyword james.

    3. Test case: search &$%$ Expected: No contacts listed as &$%$ does not match any of the valid information field in a contact.

    4. Other incorrect search commands to try: `search `. Expected: Invalid command format.

Archiving a person

  1. Archiving a person while all persons are listed

    1. Prerequisites: List all persons using the list command. Multiple persons in the list.

    2. Test case: archive 2
      Expected: 2nd contact in the list is selected. Details of the archived contact shown in the status message. Timestamp in the status bar is updated.

    3. Test case: archive 0
      Expected: No person is archived. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect archive commands to try: archive, archive one, archive x (where x is larger than the list size), archive n (where n is a name of an existing contact), archive .
      Expected: Similar to previous.

  2. Archiving a person from a search command result

    1. Prerequisites: Enter list. Search for persons using the search command. Persons that match the search are displayed in the list.

    2. Test case: archive 1
      Expected: 1st contact in the list is archived. Details of the archived contact shown in the status message. Timestamp in the status bar is updated.

    3. Test case: archive 0
      Expected: No person is archived. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect archive commands to try: archive, archive one, archive x (where x is larger than the list size), archive n (where n is a name of an existing contact), archive .
      Expected: Similar to previous.

Selecting an archived person

  1. Selecting a person while all archived persons are listed

    1. Prerequisites: List all archived persons using the archivelist command. Multiple persons in the list.

    2. Test case: archiveselect 2
      Expected: 2nd contact in the list is selected. Address location of the selected contact is displayed on the Google Maps™ browser window panel (if applicable).

    3. Test case: archiveselect 0
      Expected: No person is selected. Error details shown in the status message.

    4. Other incorrect archiveselect commands to try: archiveselect, archiveselect one, archiveselect x (where x is larger than the list size), archiveselect n (where n is a name of an existing archived contact), archiveselect .
      Expected: Similar to previous.

  2. Selecting a person from an archivesearch command result

    1. Prerequisites: Enter archivelist. Search for archived persons using the archivesearch command. Persons that match the search are displayed in the list.

    2. Test case: archiveselect 1
      Expected: 1st contact in the list is selected. Address location of the selected contact is displayed on the Google Maps™ browser window panel (if applicable).

    3. Test case: archiveselect 0
      Expected: No person is selected. Error details shown in the status message.

    4. Other incorrect archiveselect commands to try: archiveselect, archiveselect one, archiveselect x (where x is larger than the list size), archiveselect n (where n is a name of an existing archived contact), archiveselect .
      Expected: Similar to previous.

Unarchiving a person

  1. Unrchiving a person while all archived persons are listed

    1. Prerequisites: List all archived persons using the archivelist command. Multiple persons in the list.

    2. Test case: unarchive 2
      Expected: 2nd contact in the list is unarchived. Details of the unarchived contact shown in the status message. Timestamp in the status bar is updated.

    3. Test case: unarchive 0
      Expected: No person is unarchived. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect unarchive commands to try: unarchive, unarchive x (where x is larger than the list size), unarchive n (where n is a name of an existing contact), unarchive .
      Expected: Similar to previous.

  2. Unarchiving a person from an archivesearch command result

    1. Prerequisites: Enter archivelist. Search for archived persons using the archivesearch command. Persons that match the search are displayed in the list.

    2. Test case: unarchive 1
      Expected: 1st contact in the list is unarchived. Details of the unarchived contact shown in the status message. Timestamp in the status bar is updated.

    3. Test case: unarchive 0
      Expected: No person is unarchived. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect unarchive commands to try: unarchive, unarchive x (where x is larger than the list size), unarchive n (where n is a name of an existing contact), unarchive .
      Expected: Similar to previous.

PROJECT: PowerPointLabs


{Optionally, you may include other projects in your portfolio.}