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.
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
anddelete
) 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
anddelete
), 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:
-
Documentation:
-
Community:
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.
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.
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.
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
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.-
The behaviour of the
MainWindow
part is further detailed in GUI commands: List and View features.
-
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
ornewListContactContext
, which creates a newContext
of typeLIST_ACTIVITY
orLIST_CONTACT
respectively -
invoking the constructor with an
Activity
, which creates a newContext
of typeVIEW_ACTIVITY
with that activity -
invoking the constructor with a
Person
, which creates a newContext
of typeVIEW_CONTACT
with that contact
Context
class and ContextType
enumThe 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
.
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.
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. theModelManager
, 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.
-