PROJECT: SplitWiser


Overview

For our Software Engineering module, we were tasked to morph a base Address Book 3 (AB3) application into a product we envisioned for a specific target audience.

Our team decided to work on SplitWiser, a desktop Java applet to simplify expense tracking and bill-splitting amongst friends in group activities.

Ui
Figure 1. Screenshots of SplitWiser app

SplitWiser allows users to manage their contacts and activities centrally, and is primarily designed for fast typists in mind. The app employs a familiar command-line interface (CLI) for input reminiscent of terminal shells, and provides feedback to the user via a Graphical User Interface (GUI) designed with JavaFX.

My primary responsibility was to design and implement all GUI-related commands, with the requisite GUI components and styles. This role is particularly crucial, since the GUI bridges the gap between the inner workings of the app and what is seen by the end-user. As a cohesive and responsive GUI is critical to the the user experience (UX) of the app, my work heavily builds upon the GUI provided by AB3.

The following sections detail my contributions in greater depth, alongside the documentation I have written for my enhancements.

Summary of contributions

Major enhancements

  • Reworked List command (PR #112): Added the ability to view a list of contacts or activities.

    • What it does: The list command was reworked to allow the user to specify either the list of tracked contacts or activities for the app to display.

    • Justification: This feature supports the centralised management of both contacts and activities, as the lists show a high-level overview of each entry. This allows users to use the view command in tandem to display full details of an entry, and enables certain contextual commands (find and delete) to behave differently depending on which list the user is currently viewing.

    • Highlights: The list command can be used from any context. However, its implementation was challenging due to the high level of coordination between multiple components of the app (UI, Model and Logic), since all these components must share a consistent view of the current context.

    • Credits: to fellow team member Lee Liak Ghee for implementing our initial design for a Context class to represent the active state of the app.

  • View command (PRs #124, #205): Added the ability to view details of a particular contact or activity.

    • What it does: The view command allows the user to bring up the details panel for a specified entry (activity or contact) in the currently viewed list.

    • Justification: Due to the limited size of the list entries, the full information of each contact or activity is only displayed in the respective details panel. This reduces visual clutter in the list view and provides additional freedom to customise each details panel separately. It also enables many contextual commands (expense, invite, disinvite, settle, edit and delete), which function based on the currently viewed entry. This eliminates the need to manually input the entry each command operates on, reducing the amount of typing and thus improving the UX.

    • Highlights: The details panel displayed by the view command also provides the user with these additional features:

      • Contact details panel: shows the activity history of the contact and the aggregate amount owed for each

      • Activity details panel: shows the total expenditure in an activity

      • Activity details panel: greys out soft-deleted expenses and settlements

      • Activity details panel: shows required transfers to clear all debt within the activity

Minor enhancements

  • GUI redesign (PRs #86, #124): Redesigned the entire GUI to align with our v2.0 vision of the app.

    • What it does: The GUI was redesigned around a single-panel interface with a light theme, shared by different UI components. New UI classes were introduced as required and the stylesheets were re-organised.

    • Justification: This enhancement improves the cohesiveness of the GUI across different operating systems (OS), and ensures it is responsive to user commands.

    • Highlights: Ensuring the GUI appears visually similar across different OSes was technically challenging, due to the poor documentation of the JavaFX CSS and FXML standard. This enhancement required a significant amount of manual user testing on different OSes.

  • Improved status bar (PR #206): Reworked the status bar to be more useful to users.

    • What it does: Upon initial app launch, the status bar will display the file path to the data file. After that, the status bar will instead describe the current application context.

    • Justification: By displaying the current context, this improves the UX by minimising the chance a user enters a command that is not defined for the current context.

Other contributions

  • Project management:

    • Set up the automated kanban board for the project

    • Add Git pre-commit and pre-push hooks to automate workflow and minimise build failures on Travis: #87

    • Managed the three releases v1.2, v1.3 and v1.3.1 (interim version for mock PE) on GitHub

  • Documentation:

    • Designed and iterated the mockups for the v2.0 version of SplitWiser for the User Guide and Developer Guide (DG): #41, #42

    • Updated UML diagrams in the DG: #116, #209

  • Community:

    • Major feature PRs reviewed: #53, #90, #98, #129, #137, #162, #191

    • Bug fixes for InternalState during app initialisation (PR #117) and integration of invite command (PR #143)

Code contribution

  • My code contribution and relevant statistics may be viewed at Reposense

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.

Limitations

Application window size

For improved compatibility across different operating systems, the application window size is locked and not resizable by the user.

Floating-point rounding

Amounts smaller than $0.01 are not displayed to full precision. Instead, SplitWiser indicates that the amount is <$0.01.

Viewing help : help

Brings up the help dialog.

Format: help

List all contacts or activities : list

Switches the current view to list either all contacts or activities.

The following screenshot displays the appearance of the list of contacts and activities respectively.

ListComparison
  • Argument values supplied with parameters are ignored for this command.

Format: list c/ for contacts OR list a/ for activities

View a contact or activity : view

Switches the current view to show details of a contact or activity based on their display index in the current/last viewed list.

The following screenshot displays the details panel for a contact and activity respectively.

ViewComparison

Format: view a/ACTIVITY_ID OR view c/CONTACT_ID

Examples:

  • view a/1
    Views the details of the first activity, if the activity list was last displaying one or more activities

  • view c/2
    Views the details of the second contact, if the contact list was last displaying at least two contacts

Assign an activity as a sub-activity: assign (v2.0 only)

Assigns a specified activity by display index as a sub-activity of the currently viewed activity. If no activity is currently being viewed, or the specified index does not correspond to an activity in the list of activities, no change is made.

Multiple activities can be assigned at once.

Format: assign a/ACTIVITY_ID …​

Examples:

  • assign 3 5 If viewing an activity with title 'Family trip', assigns the activities with display indices 3 and 5 as sub-activities of 'Family trip', if the list of activities contain at least five activities.

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.

UI component

UiClassDiagram
Figure 2. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow class that comprises parts from two categories:

  • Common parts that are displayed regardless of the current application context, e.g. CommandBox, ResultDisplay,StatusBarFooter etc.

  • Contextual parts that are only displayed in the respective application context, e.g. ActivityListPanel, PersonDetailsPanel.

All of these UI classes, including MainWindow itself, inherit from the abstract UiPart class. The common UI classes are shown above MainWindow in the above class diagram, whereas the contextual UI classes are shown below MainWindow.

All UI classes are built upon the JavaFX GUI framework. The structure of each UI part X is defined in a matching X.fxml file in the folder src/main/resources/view. For example, the layout of the MainWindow is specified in MainWindow.fxml.

To create a visually cohesive and pleasant GUI, custom CSS styling rules were also employed to style each UI part individually. These stylesheets may be found as .css files in the folder src/main/resources/view`.

The UI component,

  • Executes user commands using the Logic component.

  • Listens for some changes to Model data so that relevant UI parts may be re-rendered with the modified data.

  • Parses the returned CommandResult to perform appropriate additional actions, such as exiting the application or switching the contextual part being displayed.

GUI commands: List and View features

Introduction

To reduce the amount of typing required of the user, it was decided that the app would support contextual commands that operate differently based on the data the user was currently viewing.

The List and View commands (collectively, GUI commands) were thus introduced to enable the user to switch between different views (panels) of the app, of which there are four:

  • Contact list (PersonListPanel) - displays brief information (e.g. name, mobile number) of every tracked contact

  • Activity list (ActivityListPanel) - displays brief information (e.g. title) of every tracked activity

  • Contact details (PersonDetailsPanel) - displays full details of a specific contact, including that contact’s activity history

  • Activity details (ActivityDetailsPanel) - displays full details of a specific activity, including all expenses, settlements and required transfers

These mechanism of GUI commands is facilitated by a combination of three classes, MainWindow, Model and Context.

Context class

Context is an immutable utility class introduced to describe the nature of the current view of the app. It stores state information about the current ContextType and an optional Object of interest, and is essential for the UI, Model and Logic components to maintain a consistent

A Context may be instantiated in one of three ways:

  • invoking the factory method newListContactContext or newListContactContext, which creates a new Context of type LIST_ACTIVITY or LIST_CONTACT respectively

  • invoking the constructor with an Activity, which creates a new Context of type VIEW_ACTIVITY with that activity

  • invoking the constructor with a Person, which creates a new Context of type VIEW_CONTACT with that contact

ContextClassDiagram
Figure 3. Class diagram of Context class and ContextType enum

The Context class exposes relevant getter methods Context#getType, Context#getActivity and Context#getContact. This enables contextual commands and the UI to retrieve the Activity or Person of interest, thus supporting contextual behaviour of the UI and other commands.

During the execution of any command that changes the active view of the app, a new Context is created, with the relevant Activity or Person, if any. The command then updates the Model with the method Model#setContext.

The updated Context of the Model is then wrapped as part of the CommandResult and returned to the MainWindow, which prompts the UI to perform additional actions.

UI context switching

After executing a command successfully, the MainWindow receives a CommandResult, which it uses to determine if any additional actions need to be performed.

If the CommandResult contains a Context, then MainWindow switches the currently displayed panel out for the appropriate panel specified by the ContextType. The following activity diagram encapsulates the additional actions that may be performed as a result of MainWindow parsing the CommandResult.

ContextSwitchActivityDiagram
Figure 4. Activity diagram for UI after successful command execution

List feature

During execution, the List command creates the specified Context (either of type LIST_ACTIVITY or LIST_CONTACT). It then updates the Model with the new Context, alongside the FilteredList of Activity or Person respectively.

As MainWindow observes both FilteredList, JavaFX will automatically re-render the contained card entries when the respective list undergoes structural changes. The updated Context is then returned to MainWindow via the CommandResult, where it switches to displaying the specified list.

Given below is an example usage scenario of a user intending to view the list of activities.

Step 1. The user launches SplitWiser for the first time, which defaults to displaying the list of contacts.

Step 2. The user executes list a/ to prompt the app to display the full list of activities.

The following sequence diagram demonstrates the role of the Logic and Model components in the execution of GUI commands. The role of the UI component is detailed in UI context switching.

ListSequenceDiagram
Figure 5. Sequence diagram for listing all activities
The lifeline for ListCommand and ListCommandParser should end at the destroy marker (X), but due to a limitation of PlantUML, the lifeline reaches the end of the diagram.

View feature

The View feature is intended to be used in tandem with the List feature, and displays the full details of the entry at a specified display index of the specified list. Note however, this takes into account the filter applied on the specified list, e.g. from the Find feature.

During execution of the View command, a new Context is created, along with the Person or Activity to be viewed, obtained from the Model. The rest of the execution follows that of the List command.

Given below is an example usage scenario of a user intending to view the second activity.

Step 1. The user launches SplitWiser for the first time, which defaults to displaying the list of contacts.

Step 2. The user executes list a/ to prompt the app to display the full list of activities.

Step 3. The user executes view a/2 to view the full details of the second activity, which succeeds if the list contains two or more activities.

Design considerations

Aspect: representing the current context state
  • Alternative 1 (current choice): Creating an immutable Context class as a state container to store the appropriate information.

    • Pros: Lightweight; context state can be easily passed between components that require access, as it is encapsulated entirely within Context.

    • Cons: Harder to implement.

  • Alternative 2: Storing the Context state in a designated central component, e.g. the ModelManager, and exposing relevant methods to other components.

    • Pros: Trivial to implement.

    • Cons: Tightly couples all components that require access to the context state to the central component, complicating testing.