Developer Guide
Developer Guide
- Acknowledgements
- Design
- Implementation
- Appendix: Requirements
- Product Scope
- Non-Functional Requirements
- Glossary
- Instructions for manual testing
- Launch and Shutdown
- View user profile
- Update user profile
- Adding a meal
- List meals or foods in database meals added
- Deleting a meal
- Filtering foods based on calories
- Find nutrition of a food
- Add a exercise
- Track calorie intake
- See examples of meal or exercise
- See list of available commands
- Exiting the application
- Saving data
- Dealing with missing/corrupted data files
Acknowledgements
- Command, Parser and UI java files are adapted from one of our group member’s Duke Project
- The source for the nutritional data is from the following links, Western, Nasi Padang, Taiwanese, and Mala.
Design
Architecture
Main Components of LifeTracker
LifeTracker
is where users will access the application from. It is responsible for:
- At app launch: Initialise the Databases and UI classes
- At app closure: Saves all updated data to databases
The rest of the Application consists of three components:
UI
: Reponsible for I/O between user and applicationCommand
: Handles execution of user inputsStorage
: Stores information of the user and meals eaten
UI Component
API: ui.java
The UI is made up of five classes, GeneralUi
, CalorieUi
, ExampleUi
, ExerciseUi
and WeightUi
, and together,
they improve on the accessibility of the application.
The UI
component,
- Displays what are the possible inputs at any one time
- Allows the user to check that a value added is correct
- Informs the user whenever there is an invalid input
Command Component
API: commands.java
How the Command
component works:
- When a user first enters something into the CLI, the
CommandParser
subclass from theParser
class is used to parse the user command. - Based on the results of the parsing, a specific command object is created (e.g.
AddMealCommand
) which inherits from the abstractCommand
and itsexecute
method. - Every command uses the
execute
method differently according to its needs. (For example,AddMealCommand
would require saving of meals to a single database, whileTrackCalorieCommand
would require reading from various databases for the desired result) - The command can also communicate with the various storage components when it is executed, such as saving and loading of user, meals, foods, exercise data.
- In addition, the command also communicates with the UI Component to display the results of the execution of the command back to the user.
- In the case of command execution failures, an Exception Object (more precisely, an object of one of its subclasses, e.g. LifeTrackerException) is thrown.
Storage Component
API: storage.java
The Storage
is the base class which all Storage
components inherit from. There are currently four storages:
FoodStorage
: For parsing and storing all of the foods supported by LifeTrackerUserStorage
: For storing the user’s profileMealStorage
: For storing the meals that the user ateExerciseStorage
: For storing the exercises that the user did
Interfaces
To ensure that each Storage
component only implements methods for writing and reading when needed, we created two interfaces
FileReadable
: Hasload()
method forStorage
component to be able to read from a databaseFileWritable
: Haswrite()
method forStorage
component to be able to write to a database
For example, FoodStorage
is not meant to be edited by user, hence it does not implement FileWritable
Implementation
This section describes some noteworthy details on how certain features are implemented.
Add meal feature
Implementation
The proposed mechanism for adding a meal is facilitated by AddMealCommand
. It extends Command
and overrides the
execute
method in the Command
class.
In this command, there are 2 ways for the user to add a meal to storage.
- Using a one-line command in their CLI in the format
add [DATE] /on [MEAL_TYPE] /type [FOOD_INDEX] /foods
- Typing
add
into the CLI and following the printed prompts to enter the date in the specified format, type of meal and specific food.
Step 1. As seen from the sequence diagram above, when the AddMealCommand is executed via the execute
method in
LifeTracker, the user’s input is first parsed to determine how he/she wants to input it. Either method sets the food,
date and meal type features necessary to create a new meal.
Step 2. The constructor for the Meal
class is called which instantiates a new instance of Meal using the
parameters provided.
Step 3. mealStorage
saves the meal to the database and then ui
prints out the confirmation of the meal added.
Design considerations
Aspect: How to add meals
- Alternative 1 (current choice): Use a one-line command for the CLI.
- Pros: Faster to input for experienced users.
- Cons: Format might be difficult for new users.
- Alternative 2 (current choice): Follow printed prompts for data.
- Pros: Usage would be easier for new users.
- Cons: Slower to input for experienced users.
Therefore, our group chose to implement both ways.
List feature
Implementation
The proposed mechanism for listing stored foods, meals and exercises is facilitated by ListCommand
. It extends Command
and overrides the execute
method in the Command
class.
Step 1: The user will input either list foods
, list meals
, list exercises
based on which information the user wants to retrieve.
Step 2: Based the input, ListCommand
will call either printAllFoods
, printAllMeals
, or printAllExercises
method of the ui
object.
Step 3: The ui
will retrieve the relevant information from the storage and print out their details.
Design Considerations
Aspect: How to list all the foods in the database, and the meals and the exercises of the user
- Alternative 1 (current choice): List information based on input command.
- Pros: More concise, no unnecessary information.
- Cons: Slightly slower to input command.
- Alternative 2: List all meals, exercises, and foods at once.
- Pros: Slightly faster to input command.
- Cons: Lots of unnecessary information would be displayed.
Delete feature
Implementation
In order to delete a meal or exercise from their meal history, a user has to type either delete /meal [MEAL_INDEX]
or delete /exercise [EXERCISE_INDEX]
into the CLI. Users can see
which meal or exercise they want to delete by viewing the respective csv files or using the list command.
In the above implementation, DeleteMealCommand parses the user input to obtain the index to delete and proceeds to delete it via the method from mealStorage() and prints out the deleted meal to the user.
Design considerations
Aspect: How to delete meals
- Alternative 1 (current choice): Delete items from list based on index.
- Pros: Does not needlessly delete wanted items.
- Cons: Need to get the index from
list
command first.
- Alternative 2: Clears all data.
- Pros: Faster input, no need for
list
command to retrieve index. - Cons: Deletes data that user might want to keep.
- Pros: Faster input, no need for
View feature
Implementation
The proposed view mechanism is facilitated by ViewUserCommand
. It extends Command
and overrides the
execute
method in the Command
class.
It stores the user’s data internally as user
and the meals consumed by the user as meals
. It also
initializes the UI for calories as calorieUI
.
Given below is an example usage scenario and how the view feature behaves at each step.
Step 1. The user launches the application and calls the view /[fieldname]
command. The ViewUserCommand
will be
initialized with the current user and meal storage state. user
and meals
will point to the user storage
and meal state respectively.
The method parseCommand()
is then called to check and ensure that the /[fieldname]
provided is valid information that can be viewed as well as the number of arguments provided is correct.
Step 2. Based on the /[fieldname]
that the user provided the different getter methods will be called in the entity
User
to return the appropriate information. In this case, the user has input the command view /weight
which will
call the getter method getWeight()
in the entity User
to return the current weight of the user and initializes the
variable weight
with that value.
If the user’s weight is equal to 0.0 then the method printFieldNotStored()
in GeneralUi
will be called to notify the
user that that specific information has not been stored yet. Otherwise, the method printWeight()
will be called to
print out the weight of the user.
For name, weight, height, age and gender there will a check done to see whether the field has information stored in it. If the fields are empty the user will be alerted and asked to update it.
Design considerations
Aspect: How to view user data
- Alternative 1 (current choice): Use a one-line for the CLI
- Pros: Faster to input for experienced users.
- Cons: Format might be difficult for new users.
- Alternative 2 : Follow printed prompts for data.
- Pros: Usage would be easier for new users.
- Cons: Slower to input for experienced users.
Update feature
Implementation
The proposed update mechanism is facilitated by UpdateUserCommand
. It extends Command
and overrides the execute
method in the Command
class.
It stores the user’s data internally as user
and the meals consumed by the user as meals
. It also
initializes the UI for calories as calorieUI
.
Given below is an example usage scenario and how the view feature behaves at each step.
It stores the user’s data internally as user
.
Step 1. The user launches the application and calls the update /[fieldname] [newInfo]
command. The UpdateUserCommand
class will be
initialized with the current user storage state. user
will point to the user storage.
The method parseCommand()
is then called to check and ensure that the /[fieldname]
provided is valid information that can be updated as well as the number of arguments provided is correct.
Step 2. Based on the /[fieldname]
that the user provided the different setter methods will be called in the entity
User
to update the appropriate information. In this case, the user has input the command update /weight [newInfo]
which will
call the setter method setWeight()
in the entity User
to return the set the current weight of the user to the newly
updated one.
The caloric limit is then recalculated with the calling of calculateCaloricNeeds()
static method in User
based on the new information provided and the caloric limit in user
is then updated with setCaloricLimit
.
The new weight difference between the current weight and target weight is also shown with the calling of the static
method displayNewWeightDifference()
.
The method updateUser()
in userStorage is then called to update the user’s detail in the storage.
For updates made to weight, height, age and gender, there will be a call to the static method calculateCaloricNeeds()
in the class User. This is done to ensure that with every new change, the caloric limit is recalculated. This recalculated
caloric limit is will then be the new limit and the method setCaloricLimit()
is called to update the user’s daily caloric
limit to the new one.
For updates made to weight and targetWeight, there will be a call to the static method displayNewWeightDifference()
and
displayNewTargetWeightDifference()
respectively to show the new difference between target weight and current weight of the user.
At the end of every update, the userStorage will be updated accordingly.
Design considerations
Aspect: How to update user data
- Alternative 1 (current choice): Use a one-line for the CLI
- Pros: Faster to input for experienced users.
- Cons: Format might be difficult for new users.
- Alternative 2 : Follow printed prompts for data.
- Pros: Usage would be easier for new users.
- Cons: Slower to input for experienced users.
Nutrition feature
Implementation
The proposed update mechanism is facilitated by NutritionCommand
. It extends Command
and overrides the execute
method in the Command
class.
Step 1: The user inputs nutrition
into the command line.
Step 2: The user will then be prompted to enter what food they would like to see the nutrition for.
Step 3: A list of type food
will then be created called filteredFoods
, populated by foods from foodStorage
that contains the user’s input.
Step 4: The list will then be displayed to the user, who can pick which food by its index.
Step 5: The nutritional information for that food will then be displayed.
Design considerations
Aspect: How to view nutritional information for foods
- Alternative 1 (current choice): Follow prompts for information.
- Pros: User can get accurate information about the food.
- Cons: Slower input.
- Alternative 2: Use a one line command for the CLI.
- Pros: Faster input.
- Cons: User might input food that’s not in the database and therefore there is no nutritional information available.
Filter feature
Implementation
This proposed mechanism for allowing the user to search for meals with a filter, facilitated by FilterCaloriesCommand
. It extends Command
and overrides the execute
method in the Command
class.
Step 1. The user calls the filter
command, specifying a particular calorie range through a upper and lower bound.
Step 2. FilterCaloriesCommand
will parse the lower and upper bound from the input.
Step 3. FilterCaloriesCommand
will then retrieve the meals that fit within that range from FoodStorage
.
Step 4. FilterCaloiresCommand
will then print out the meals that has been filtered based on the lower and upper bound.
Design considerations
Aspect: How to find foods from the database based on calories
- Alternative 1 (current choice): Use a one-line for the CLI
- Pros: Faster to input for experienced users.
- Cons: Format might be difficult for new users.
- Alternative 2 : Follow printed prompts for data.
- Pros: Usage would be easier for new users.
- Cons: Slower to input for experienced users.
Exercise feature
Implementation
The proposed update mechanism is facilitated by AddExerciseCommand
. It extends Command
and overrides the execute
method in the Command
class.
Design considerations
Aspect: How to add exercises
- Alternative 1 (current choice): Use a one-line command for the CLI.
- Pros: Faster to input for experienced users.
- Cons: Format might be difficult for new users.
- Alternative 2 (current choice): Follow printed prompts for data.
- Pros: Usage would be easier for new users.
- Cons: Slower to input for experienced users.
Track feature
Implementation
The mechanism for tracking net calorie intake is facilitated by TrackCalorieCommand
. It extends Command
and overrides the execute
method in the Command
class.
Step 1: The user will either input track all
to view all history or track /start [DATE] /end [DATE]
to filter the results based on dates
Step 2a: Based the input, TrackCalorieCommand
will either parse the start date from user input or set the start date to the earliest meal or exercise added by calling getStartingDate
.
Step 2b: Based the input, TrackCalorieCommand
will either parse the end date from user input or set the end date to the latest meal or exercise added by calling getEndingDate
.
Step 3: TrackCalorieCommand
will retrieve the meals and exercises filtered from the starting date by calling getMealByDate
and getExerciseByDate
respectively.
Step 4: TrackCalorieCommand
will iterate through the filtered meals and exercises day by day and print out the net calorie intake for each day.
Design considerations
Aspect: How to track the calories of the user
- Alternative 1 (current choice): Use a one-line command for the CLI.
- Pros: Faster to input for experienced users.
- Cons: Format might be difficult for new users.
- Alternative 2 (current choice): Follow printed prompts for data.
- Pros: Usage would be easier for new users.
- Cons: Slower to input for experienced users.
Examples feature
Implementation
The proposed mechanism for displaying examples of exercises and meals is facilitated by ExamplesCommand
. It extends Command
and overrides
the execute
method in the Command
class.
Step 1. The user calls the examples
command, specifying whether they wish for meal
or exercise
to be displayed.
Step 2. ExamplesCommand
will parse the user input.
Step 3. ExamplesCommand
will retrieve either the examples of meal
or examples of exercise
based on the user input, from the ExampleData
database.
Step 4. The examples of meal
or exercise
will then be printed out and displayed for the user.
Design considerations
Aspect: How to list examples of exercises and meals
- Alternative 1 (current choice): List examples based on input command.
- Pros: More concise, no unnecessary information.
- Cons: Slightly slower to input command.
- Alternative 2: List all examples.
- Pros: Slightly faster to input command.
- Cons: Lots of unnecessary information would be displayed.
Appendix: Requirements
Product scope
Target user profile
- Is an NUS student
- Looking to lose/maintain their weight
- Looking to make healthier choices in terms of food
- Can type fast
- Prefers typing to mouse interactions
- Is reasonably comfortable using CLI apps
Value proposition
For individuals trying to lose weight, managing their daily caloric intake is crucial. However, many may find it hard to track and manage their calories. LifeTracker allows users to easily automate the tracking of their calories and keep a record of their daily caloric intake.
LifeTracker can also keep track of the exercises that users have done and factor it in to their daily calories lost. This allows the user to keep track of their net calorie gain on a daily basis.
User Stories
Version
As a ...
I want to ...
So that I can ...
v1.0
new user
see usage instructions
refer to them when I forget how to use the application
v1.0
user
calculate my caloric needs based on my height and weight
lead a healthy lifestyle within my caloric needs
v1.0
user
add a meal
keep track of the food I have eaten on a particular day
v1.0
user
delete a meal
remove a meal if I entered it in wrongly
v1.0
user
view my previous meals
track the calories of each meal
v1.0
user
key in my weight on a daily basis
keep track of my weight loss/gain
v1.0
user
see the amount of calories left I have in the day
not exceed my daily caloric limit
v2.0
user
search for a type of food and view its nutritional contents
make a more informed choice about what to eat
v2.0
user
search for meals within a specific calorie range
decide which meal to consume
v2.0
user
enter the type and duration of exercise I have completed
keep better track of my physical activies
v2.1
user
be inspired to work out
stay in shape
v2.1
user
search based on a filter
have results that better suit my needs
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
installed. - This app is meant for a single user and will not be able to accurately keep track of the meals, personal information and caloric requirements for different people.
- This app is targeted at users who would prefer typing over other input types. Ideally they would have an above-average typing speed and therefore prefer CLI over other interfaces.
Glossary
- glossary item - Definition
Instructions for manual testing
Given below are instructions on how to test the application by yourself manually. You can use these instructions as a starting point for your testing.
Launch and Shutdown
- Initial launch
- Download the jar file from the release page and copy the file into an empty folder
- Open a cmd terminal and redirect or cd into the folder the jar file was downloaded into.
- Type “java -jar tp.jar” and press enter to run the file.
- Shutdown
- Type
bye
into the command line and press enter to exit the application.
- Type
View user profile
Test case: view /weight
Expected: Weight information will be shown.
Test case: view /null
Expected: “Oops! Invalid field name /null for command view” message will be shown as /null fieldName does not exist.
Update user profile
Test case: update /weight 60
Expected: Amount of weight needed to lose to hit target weight message as well as user settings successfully updated message will be shown
Test case: update /null 60
Expected: “Oops! Invalid field name /null for command view” message will be shown as /null fieldName does not exist.
Test case: update /weight 800
Expected: “800 kg is an impossible value for /weight please enter a valid one!” message is shown as a weight of 800 kg is impossible to attain.
Test case: update /weight abc
Expected: “abc is not of valid format for /weight please try again!” message as weight only accepts numerical values.
Adding a meal
Test case: add /on 3/3/2023 /type Lunch /foods Spaghetti, Alfredo (Small)
Expected: Spaghetti and Alfredo are added to the list. Details of the food such as calories are shown in the status message.
Test case: add
Expected: Application will then ask for date of meal, type of meal, and food, and will then display the foods in the database containing the food that was added. Food is then added to the list and details of the food such as calories are shown in the status message.
Test case: add /on dummy /type dummy /foods dummy
Expected: No food is added. Error details are shown in the status message, such as “dummy is not a valid date”, “Invalid meal type” or “no food found with dummy”.
List meals or foods in database meals added
Test case: list meals
Expected: A list of meals eaten today would be displayed.
Test case: list foods
Expected: A list of all foods in the databse would be displayed.
Test case: list dummy
Expected: An error message would be displayed.
Deleting a meal
Prerequisite: List all meals eaten using the list command. At least 1 meal in the list.
Test case: delete 1
Expected: First meal is deleted from the list. Details of the deleted meal are shown in the status message.
Test case: delete 0
Expected: No meal is deleted. Error details shown in the status message.
Other incorrect delete commands to try: delete, delete x, (where x is larger than the list size)
Expected: Similar to previous.
Filter foods based on calories
Test case: filter 400 600
Expected: A list of all meals within that range will be displayed
Test case: filter 400 300
Expected: An error message will be displayed
Find nutrition of a food
Prerequisite: Food needs to exist in the database.
Test case: nutrition
Expected: Prompt will ask you to enter the food you would like to see the nutrition for. A menu displaying all foods which contain the food entered will appear, which you can then enter the index to see the specific food.
Add a exericse
Test case: exercise /type running /description 5km /calories 500 /on 5/5/2023
Expected: An exercise of running for 5km that burnt 500 calories on 5/5/2023 is added.
Test case: exercise /type dummy /description dummy /calories dummy /on dummy
Expected: No exercise is added, error message will be displayed.
Track calorie intake
Test case: track /start 5/5/2023 /end 6/5/2023
Expected: Calories consumed, calories burnt and net calories for 5/5/2023 and 6/5/2023 would be displayed in the status message.
Test case: track /start dummy /end dummy
Expected: Error message will be dislayed.
See examples of meal or exercise
Test case: examples exercise
Expected: Examples of different types of exercise will be displayed
Test case: examples weight
Expected: An error message will be displayed
See list of available commands
Test case: help
Expected: List of available commands for this application will be displayed.
Exiting the application
Test case: bye
Expected: Application exits.
Saving data
Meal data, user data and exercise data will be saved in ./data/mealData.csv, ./data/userData.csv, ./data/exerciseData.csv respectively.
Dealing with missing/corrupted data files
Delete the ./data/mealData.csv, ./data/userData.csv, ./data/exerciseData.csv files for corrupted data and restart the programme.