LoveBook, is a dating-focused application, revolving around providing online daters with a convenient and enjoyable tool to enhance their dating experiences. Featuring user preferences management, date organization, customizable filtering options and best match algorithms, LoveBook enhances the efficiency of your online dating journey.
ListView
:
https://stackoverflow.com/questions/20621752/javafx-make-listview-not-selectable-via-mouseRefer to the guide Setting up and getting started.
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
(consisting of
classes Main
and MainApp
) is
in charge of the app launch and shut down.
The bulk of the app's work is done by the following four components:
UI
: The UI of the App.Logic
: The command executor.Model
: Holds the data of the App in memory.Storage
: Reads data from, and writes data to, the hard disk.Commons
represents a collection of classes used by multiple other components.
How the architecture components interact with each other
This application attempts to separate the UI
, Logic
, Model
and Storage
components to reduce coupling between the
components.
This is done by using interfaces to define the API of each component and using classes to implement the functionality of
each component.
This allows the components to be easily added and replaced with other implementations without affecting the other
components.
For example, new features can be added to the Storage
component without affecting the other components.
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command delete 1
.
Each of the four main components (also shown in the diagram above),
interface
with the same name as the Component.{Component Name}Manager
class (which follows the corresponding
API interface
mentioned in the previous point.For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using
the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component
through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the
implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
Scroll back to Table of Contents
The API of this component is specified
in Ui.java
The UI consists of a MainWindow
that is made up of parts
e.g.CommandBox
, ResultDisplay
, DateListPanel
, StatusBarFooter
etc. All these, including the MainWindow
,
inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the
visible GUI.
The UI
component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that
are in the src/main/resources/view
folder. For example, the layout of
the MainWindow
is specified
in MainWindow.fxml
The UI
component,
Logic
component.Model
data so that the UI can be updated with the modified data.Logic
component, because the UI
relies on the Logic
to execute commands.Model
component, as it displays Date
object residing in the Model
.Scroll back to Table of Contents
**API
** : Logic.java
Here's a (partial) class diagram of the Logic
component:
The sequence diagram below illustrates the interactions within the Logic
component, taking execute("delete 1")
API
call as an example.
Note: 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.
How the Logic
component works:
Logic
is called upon to execute a command, it is passed to an LoveBookParser
object which in turn creates a
parser that matches the command (e.g., DeleteCommandParser
) and uses it to parse the command.Command
object (more precisely, an object of one of its subclasses e.g., DeleteCommand
) which
is executed by the LogicManager
.Model
when it is executed (e.g. to delete a date).CommandResult
object which is returned back from Logic
.Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
LoveBookParser
class creates an XYZCommandParser
(XYZ
is a
placeholder for the specific command name e.g., AddCommandParser
) which uses the other classes shown above to parse
the user command and create a XYZCommand
object (e.g., AddCommand
) which the LoveBookParser
returns back as
a Command
object.XYZCommandParser
classes (e.g., AddCommandParser
, DeleteCommandParser
, ...) inherit from the Parser
interface so that they can be treated similarly where possible e.g, during testing.Scroll back to Table of Contents
**API
** : Model.java
The Model
component,
Date
objects (which are contained in a UniqueDateList
object).Date
objects (e.g., results of a search query) as a separate filtered list which
is exposed to outsiders as an unmodifiable ObservableList<Date>
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.UserPrefs
object that represents the user’s preferences. This is exposed to the outside as
a ReadOnlyUserPrefs
objects.DatePrefs
object that represents the user’s preferences for dates. This is exposed to the outside as
a ReadOnlyDatePrefs
objects.Model
represents data entities of the domain, they
should make sense on their own without depending on other components)Scroll back to Table of Contents
**API
** : Storage.java
The Storage
component,
LoveBookStorage
, UserPrefsStorage
and DatePrefsStorage
, which means it can be treated as
either one of three (if the functionality of only one is needed).Model
component (because the Storage
component's job is to save/retrieve objects
that belong to the Model
)Scroll back to Table of Contents
Classes used by multiple components are in the seedu.LoveBook.commons
package.
Before diving into the implementation details, here's an overview of what changed from the AB-3 codebase.
Person
class has been renamed to Date
class, and most of the classes named Personxxx
have been renamed
accordingly.filter
, star
, bestMatch
(not exhaustive) have been added to the application.The following class diagram shows the new Date
class after the changes mentioned above.
Moving on to the implementation details, the following sections describe how and why the main features of the app work.
Scroll back to Table of Contents
CommandBox
class in the Ui
component to
the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates an AddCommandParser
object for add command
specific parsing.LoveBookParser
class also separates the command word from the user input and passes the arguments from the user
input to the AddCommandParser
object created above for parsing.AddCommandParser
carries out it's validation checks and creates new Date
, AddCommand
objects if the
validation checks pass.AddCommand
object is then passed back to the LogicManager
class for invocation of the execute
function
which adds the new Date
object created into the existing Model
component.The sequence diagram notation of the above steps is shown below.
The activity diagram notation of the above steps is shown below.
Aspect: Adding dates with same name
Alternative 1 (current choice): Don't allow dates with the same name to be added.
Alternative 2: Allow dates with the same name to be added.
Aspect: Allowing users to add dates without specifying all fields
Alternative 1 (current choice): Require users to specify all fields.
Alternative 2: Allow users to specify only some fields, and adding placeholder inputs to the remaining fields.
Aspect: Adding dates to existing date list
Alternative 1 (current choice): Sorts the list on every addition, maintaining a lexically sorted list.
Alternative 2: Adds the date to the end of the list.
Scroll back to Table of Contents
CommandBox
class in the Ui
component to
the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a ListCommand
object for list specific commands.
One thing to note here is that inputs like list 12
and list x
are accepted since they still contain list
.ListCommand
object is then passed back to the LogicManager
class for invocation of the execute
function
which sorts the list of dates in the Model
component and returns the sorted list to the Ui
component.The sequence diagram notation of the above steps is shown below.
Aspect: Ordering of dates
Alternative 1 (current choice): Sorts the list of dates by name.
Alternative 2: List the dates in the order they were added.
Scroll back to Table of Contents
CommandBox
class in the Ui
component to
the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a FilterCommandParser
object for filter command parsing.FilterCommandParser
carries out it's validation checks and creates a FilterCommand
object containing a
list of MetricContainsKeywordPredicate
objects if the checks pass.FilterCommand
object is then passed back to the LogicManager
class for invocation of the execute
function which
filters the list of dates in the Model
component and returns the filtered list to the Ui
component.The Activity diagram summarises what happens after the user enters a filter command.
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command filter name/John
.
Scroll back to Table of Contents
CommandBox
class in the Ui
component to
the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a SortCommandParser
object for sort command parsing.SortCommandParser
object carries out its validation checks and creates a SortCommand
object containing a
String prefix (eg. name/) and String sequence (increasing/decreasing) if all checks pass. One thing to note here is
that the sequence and prefix are case-sensitive.SortCommand
object is then passed back to the LogicManager
class for invocation of the execute
function which
sorts the list of dates based on a specified metric in the specified order in the Model
component and returns the sorted
list to the Ui
component.The Activity diagram summarises what happens after the user enters a sort command.
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command sort name/increasing
.
Scroll back to Table of Contents
CommandBox
class in the Ui
component to
the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a BlindDateCommand
object.
One thing to note here is that inputs like blindDate 12
and blindDate x
are accepted since they still contain list
.BlindDateCommand
object is then passed back to the LogicManager
class for invocation of the execute
function
which sorts the list of dates in the Model
component and returns the sorted list to the Ui
component.The Activity diagram summarises what happens after the user enters a blindDate command.
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command blindDate
.
Scroll back to Table of Contents
The best match feature is implemented using the BestMatchCommand
class. The BestMatchCommand
class iterates
through the list of Dates, and calls GetScore
to get the score of the date based on height, age, horoscope and
income.
CommandBox
class in the Ui
component to the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a BestMatchCommand
object.BestMatchCommand
object is then passed back to the LogicManager
class for invocation of the execute
function
which then picks the Date
with the highest score in the Model
component by calling the getScore
function for all Date
objects in the dateList
.Scoring Dates
Ranking of Scores
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command bestMatch
Scroll back to Table of Contents
CommandBox
class in the Ui
component to the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a SetPrefCommandParser
object for SetPrefCommand
specific parsing.LoveBookParser
class also separates the command word from the user input and passes the arguments from the user
input to the SetPrefCommandParser
object created above for parsing.SetPrefCommandParser
carries out it's validation checks and creates a new SetPrefCommand
object if the
validation checks pass.SetPrefCommand
object is then passed back to the LogicManager
class for invocation of the execute
function
which then updates the date preferences in the Model
component.The edit
feature is also implemented in a similar manner.
The Activity Diagram notation of the above steps is shown below.
The Sequence Diagram notation of the above steps is shown below.
Aspect: Allowing users to set their date preferences on launch
bestMatch
works
immediately from the start.Scroll back to Table of Contents
CommandBox
class in the Ui
component to the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a ShowPrefCommand
object.ShowPrefCommand
object is then passed back to the LogicManager
class for invocation of the execute
function
which then returns the preferences to the Ui
component.The Sequence Diagram notation of the above steps is shown below.
Scroll back to Table of Contents
CommandBox
class in the Ui
component to
the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a StarCommandParser
object for StarCommand specific parsing.LoveBookParser
class also separates the command word from the user input and passes the arguments from the user input to the StarCommandParser
object created above for parsing.StarCommandParser
carries out it's validation checks and creates a new StarCommand
object if the validation checks pass.StarCommand
object is then passed back to the LogicManager
class for invocation of the execute
function which then updates the isStarred field for the date object with the respective index.The Activity diagram summarises what happens after the user enters a star command.
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command star 1
Aspect: Choosing star to be an additional field for the add dates command
star INDEX
Scroll back to Table of Contents
CommandBox
class in the Ui
component to
the LogicManager
class in the Logic
component by invoking the execute
function.LogicManager
class then passes the user input to the LoveBookParser
class for parsing and validation.LoveBookParser
class then performs polymorphism and creates a UnstarCommandParser
object for UnstarCommand
specific parsing.LoveBookParser
class also separates the command word from the user input and passes the arguments from the user
input to the UnstarCommandParser
object created above for parsing.UnstarCommandParser
carries out it's validation checks and creates a new UnstarCommand
object if the
validation checks pass.UnstarCommand
object is then passed back to the LogicManager
class for invocation of the execute
function
which then updates the isStarred field for the date object with the respective index.The Activity diagram summarises what happens after the user enters a star command.
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command unstar 1
Scroll back to Table of Contents
Scroll back to Table of Contents
Target user profile:
Value proposition: LoveBook simplifies the process of storing information of dates and assessing compatibility between user and his/her dates by taking into account the user’s preferences, thereby enhancing the efficiency and effectiveness of finding the perfect match.
Scroll back to Table of Contents
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
* * | new user | be greeted with a welcome message when i launch the app | feel welcome |
* * | new user | be able to get help when i'm stuck | better navigate through the application |
* * * | dater | be able to key my preferred height in my preferences | get recommended a suitable date based on our height compatibility |
* * * | dater | be able to key in my preferred horoscope in my preferences | get recommended a suitable date based on our horoscope compatibility |
* * * | dater | be able to key in my preferred income in my preferences | get recommended a suitable date based on our income compatibility |
* * * | dater | be able to key in my preferred age in my preferences | get recommended a suitable date based on our age compatibility |
* * * | dater | be able to edit my entered preferences | change my preferences in the event I change my mind |
* * * | dater | be able to view my preferences | know what my preferences are in the event I forget |
* * * | dater | be able to pull up a list of my previous dates | keep track of who I have dated in the past |
* * * | dater | be able to delete dates from my list | limit my dating list to those who I am still interested in |
* * * | dater | to be able create a new date entry with his/her gender, name, income, height, horoscope and age | keep my list growing |
* * * | dater | to be able to edit the details of my date | keep my dates details up to date |
* * * | dater | to be able to be recommended a complete random date | have an exciting surprise date that day |
* * * | dater | to be able to filter my dates based on a particular metric | find dates that I am interested in amidst my long and ever growing list |
* * * | dater | to be able to be recommended the most compatible date for me | optimize my chance of finding my one true love |
* * * | dater | to be able to star dates | keep track of outstanding dates |
* * * | dater | to be able to unstar dates | keep focused on people who are still outstanding to me |
* * * | dater | to be able to sort my dates based on a particular metric | find dates that I am interested in amidst my long and ever growing list |
* * * | dater | to be able to find dates based on their name | locate a date easily |
* * | lazy user | to be able to clear all the dates in my list | start afresh with a new date list |
Scroll back to Table of Contents
(For all use cases below, the System is the LoveBook
and the Actor is the user
, unless specified otherwise)
Main Success Scenario (MSS):
User requests to list all dates.
LoveBook shows a list of dates.
Use case ends.
Extensions:
2a. The list is empty.
2a1. Use case ends.
Main Success Scenario (MSS):
User inputs command for adding date to LoveBook.
LoveBook validates the command.
LoveBook adds the new date to the LoveBook.
LoveBook displays a confirmation message.
Use case ends.
Extensions:
2a. The command is invalid (Fields do not exist, invalid format).
2a1. LoveBook displays an error message.
2a2. Use case ends.
Main Success Scenario (MSS):
Use case ends.
Extensions:
2a. No dates match the search query.
2a1. LoveBook displays an error message.
2a2. Use case ends.
Main Success Scenario (MSS):
Use case ends.
Extensions:
2a. The command is invalid (Fields do not exist, invalid format).
2a1. LoveBook shows an error message.
2a2. Use case ends.
2b. No fields to edit are given.
2b1. LoveBook displays an error message.
2b2. Use case ends.
2c. Edited field(s) are invalid.
2c1. LoveBook displays an error message.
2c2 Use case ends.
2d. Index provided is invalid.
2d1. LoveBook displays an error message.
2d2. Use case ends.
Main Success Scenario (MSS):
Use case ends.
Extensions:
2a. Index provided is invalid.
2a1. LoveBook displays an error message.
2a2. Use case ends.
Main Success Scenario (MSS):
Use case ends.
Extensions:
2a. The command is invalid (Preference does not exist, invalid format).
2a1. LoveBook displays an error message.
2a2. Use case ends.
2b. No Preferences to set are given.
2b1. LoveBook displays an error message.
2b2. Use case ends.
2c. Field(s) are invalid.
2c1. LoveBook displays an error message.
2c2. Use case ends.
2d. There are multiple values for a single field
Main Success Scenario (MSS):
Use case ends.
Extensions:
1a. No Preferences were previously set.
1a1. LoveBook displays the default preferences.
1a2. Use case ends.
Main Success Scenario (MSS):
Use case ends.
Extensions:
1a. The list is empty.
1a1. LoveBook displays an error message.
1a2. Use case ends.
Main Success Scenario (MSS):
Use case ends.
Extensions:
2a. The list is empty.
2a1. Use case ends.
2b. The command is invalid (Metrics do not exist, invalid format).
2b1.LoveBook displays an error message.
2b2. Use case ends.
2c. No metric to filter by are given.
2c1. LoveBook displays an error message.
2c2. Use case ends.
2d. Field(s) are invalid.
2d1. LoveBook displays an error message.
2d2. Use case ends.
Main Success Scenario (MSS):
Use case ends.
Extensions:
2a. The list is empty.
2a1. Use case ends.
2b. The command is invalid (Comparator does not exist, invalid format).
2b1. LoveBook displays an error message.
2b2. Use case ends.
2c. No comparator to sort is given.
2c1. LoveBook displays an error message.
2c2. Use case ends.
2d. Comparator is invalid.
2d1. LoveBook displays an error message.
2d2. Use case ends.
Main Success Scenario (MSS):
Use case ends.
Extensions:
1a. The list is empty.
1a1. LoveBook displays an error message.
1a2. Use case ends.
Scroll back to Table of Contents
Scroll back to Table of Contents
Term | Definition |
---|---|
Date | A person that the user is interested in and is currently seeing. |
Metric | A certain characteristic of a date. (e.g. Gender, Height) |
Command | Text that the user types into the application to perform an action. |
Parameter | A value that the user provides to the application when executing a command. (e.g. in gender/M M is a parameter) |
GUI | Graphical User Interface |
CLI | Command Line Interface |
Mainstream OS | Windows, Linux, Unix, OS-X |
Scroll back to Table of Contents
Given below are instructions to test the app manually. You are recommended to start with an empty LoveBook and follow the instructions sequentially in order for the example commands provided to be relevant. You can refer to the user guide for more details on the features.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
help
add name/Cleon age/22 gender/F height/176 horoscope/Taurus income/3000
Prerequisites: Have at least 1 date in the LoveBook.
edit 1 horoscope/Cancer name/John
Prerequisites: Have at least 1 date with name containing "John" in the LoveBook.
find John
Prerequisites: Have at least 2 dates (named "John" and "Cleon") in the LoveBook.
find John Cleon
list
filter age/22
Prerequisites: Have at least 1 date in the LoveBook. Best to have more than 5 dates.
blindDate
exit
command or click the 'X' button in the top right corner.Saving window preferences
Saving data
Date
in the database.data
folder is created under the current repository where the jar file is located.Scroll back to Table of Contents
Implementing LoveBook was not straightforward and often required us to brainstorm as a team to solve the challenges faced. Given below is a summary of the effort our team has put into developing LoveBook as well as challenges faced.
As we wanted to morph AB3 to fit into our idea of LoveBook, we had to refactor a large portion of the initial codebase and implement several new classes to get the basic minimum viable product of LoveBook. This included creating the Date class and its associated inner field classes. We also had to update how the application will store Dates and DatePrefs separately. In addition, many previous commands of AB3 had to be refactored or changed, and we added several new commands to LoveBook as well. Eventually, we were able to successfully implement both the Date and DatePref classes and all their associated commands.
One challenge we faced was implementing the bestMatch feature. Given the tight timeline of the team project, we decided to do a simple implementation of this feature that does not provide user with much flexibility. If given more time, we would like to develop this further by incorporating the use of artificial intelligence, as it is a relevant feature that will be used in the real world and brings value to our target users.
Our dedication to enhancing the aesthetics of LoveBook is highlighted by our attention to visual representation. We went beyond mere textual displays, incorporating visually engaging elements such as gender icons, horoscope symbols, and star command visual cues, all implemented using JavaFX. These features not only contribute to the overall visual appeal of the application but also serve a functional purpose in providing users with quick and intuitive insights into important date attributes. As our team was unfamiliar with JavaFX initially, it took us a great amount of time and effort to produce an eventual satisfactory and working UI that we were proud to adopt and incorporate into our application.
Scroll back to Table of Contents
Improve the command parser to be more robust. Some examples include:
Improve the income field to be more robust
Improve issues regarding sorting stability
Improve the filter feature to be more robust. Some examples include:
Improve the error message to be more comprehensive
Improve the message displayed when the user tries to perform an operation on an empty list
Improve the presets bar feature to be more comprehensive and clear
add
, edit
, delete
, setP
and showP
.clear
command, the button "clear" removes all text in the command box, making
it ambiguous. We plan to change this in a future iteration like a trash can icon.Improve the filter and sort command formats
Improve the best match feature to be more flexible
Income
, Age
, Height
and Horoscope