FoodManager and potentially even OptionalFood if the latter is allowed to be passed around outside of FoodList.

API: Ui.java
The UI component makes use of the following classes:
Ui: Responsible for communication between the other classes in the UI component and with the Logic component.UiHelper: Responsible for providing helper methods to the other classes in the UI component.UiInput: Responsible for reading in the user commands and checking if it is empty.UiOuput: Responsible for printing the outputs.UiMessage: Responsible for storing output messages in methods so that they can be retrieved and printed when necessary.The UiMessage class has dependencies with the following enumeration classes:
FitnessLevel: Descriptions of the five FitnessLevel are required in UiMessage#getAskForUserInfoMessage(String name) as shown in the code snippet below.Gender: Descriptions of the three Gender are required in UiMessage#getAskForUserInfoMessage(String name)as shown in the code snippet below.In summary, the UI component,
Logic component for command execution.Logic component.Data of the user’s diet is stored in the app’s memory via the model: a FoodList.
API: [FoodList.java] (https://github.com/AY2021S1-CS2113-T14-4/tp/blob/master/src/main/java/seedu/dietbook/list/FoodList.java)
FoodList provides the following functions:
Additionally, it is not dependent on the other components listed. Instead, it is dependent on a common Food class, which is used by serval components, including the storage, database, and calculator.
The above functions and the lack of dependency are met through the following means:
FoodList stores new information added via the creation and maintenance of a list of FoodEntry objects. These encapsulate the data being stored. In practice, the objects in the list are DatedFoodEntry objects, which additionally support the storage of the date and time.FoodListManager is used to perform logical operations on the list of FoodEntry objects. A FoodManager is also used as a fascade that obscures calculations and prevents modification of Food data stored.String that is meant to be supplied to the UI. In other data retrieval operations, such as those required by calculator, a list of Food objects is supplied as a means of data transfer between the components. Other lists of java data types such as LocalDateTime and Integer are also provided to the storage component.Overall, FoodList fulfils the role of being the app’s Model component by holding consumption data in the app’s memory. It is currently used as a singleton, but is not necessarily limited to such: e.g. a seperate FoodList for favorites/recurrent entries or entries that are flagged as unhealthy/healthy can be made and maintained by Logic.
There are a few common classes/packages that can be used multiple components. These are Food, StringFormatter, and MainLogger, located in the seedu.dietbook.food, seedu.dietbook.utils, and seedu.dietbook.logger packages respectively.
Food is a data class containing all the relevant nutritional information on a food: calories, carbohydrates, proteins, fats. Being common to multiple components/classes, it is a means of data transfer between classes while reducing direct coupling.
StringFormatter allows the formatting of strings in a manner similar to Python’s fstrings:
Strings can be formatted using the pattern ${map_key} and a corresponding key to value map.
MainLogger provides logging support to all classes.
This feature allows users to enter their personal information into the system so that they can be used for tracking diet progress and calorie recommendation calculation. This feature and its associated command words is only used during the initial setup of the application. Any subsequent editing of the user information can be done using the Edit user information feature.
Commands words used:
name: Saves the user’s name or nickname into the application.info: Saves the user’s age, gender, height, fitness level, original, current and target weight into the application.Main classes and methods used:
Manager: Stores a Person object.
Manager#setPerson(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, int newCurrentWeight, int newTargetWeight, FitnessLevel newFitnessLevel): Calls a method in Person class (listed below) to set the attribute values of the Person object.Person: Stores all user information provided.
Person#setAll(String newName, Gender newGender, int newAge, int newHeight, int newOriginalWeight, int newCurrentWeight, int newTargetWeight, FitnessLevel newFitnessLevel): Updates the attribute values of the Person object.Example usage scenario and how the feature work:
Summary: Only one instance of Person is ever instantiated. A default person is instantiated at the start with default attribute values and when the user enters their information for the first time during the set up, all the default values would be updated to the inputted values. Therefore, the command to enter the user information will result in a change in the attribute values and not the creation of a new Person object.
Step 1. When the user launches the application for the first time. A default Person object will be initialised by Manager and the user will be prompted to enter their name.
Object Diagram:

Step 2. The user inputs name Jack command to enter their name into DietBook. The name command calls Manager#setName(Jack), to store the name in Manager first. After which, user will be prompted to enter all other details.
Object Diagram:

Sequence Diagram:

Step 3. The user inputs a command like the following info g/M a/21 h/175 o/85 c/85 t/75 f/2 to enter all other personal information including age, gender, height, fitness level, original, current and target weight. The info command then calls Parse#executeProcessedInfo(info g/M a/21 h/175 o/85 c/85 t/75 f/2, manager) before calling Manager#setPerson(Jack, Gender.MALE, 21, 175, 85, 85, 75, FitnessLevel.LOW) which proceeds to call Person#setAll(Jack, Gender.MALE, 21, 175, 85, 85, 75, Fitness.LOW).
Object Diagram:

Sequence Diagram:

Aspect: Whether to enter name and other information separately or together
Aspect: Single or multiple usage of feature and command words
Aspect: Whether to use singleton pattern for Person class
Person
Person object by mistake and there might be negative consequence in creating multiple objects.However, there is minimal risk of creating multiple Person object by mistake and minimal negative consequence in creating multiple objects as long as the Manager refers the correct instance of Person.
Person
Person object.Aspect: Changing attribute values in Person object or creating new Person object
Person object
Person object
Person instance is kept and referred to.This feature allows users to edit their personal information after it has been entered into the system during the initial set up using the Enter user information feature. This feature was implemented to allow long term users to update their personal information like age, current weight, etc when necessary and also for careless users to edit their personal information if they have entered it wrongly.
Command word used:
editinfo: Edits the user information stored in the application.editinfo a/22: Edits the age of the user to 22editinfo a/22 c/80: Edits the age of the user to 22 and the current weight to 80.editinfo n/Jane g/F a/22 h/165 o/70 c/63 t/60 f/3: Edit the name, gender, age, height, original, current and target weight as well as the fitness level of the user to Jane, female, 22,165, 70, 63, 60 and You engage in moderate amount of exercise or have a job that requires moderate physical activity. respectively.Main classes and methods used:
Person: Stores all user information provided.
Person#setName(String newName): Updates the name the Person object.Person#setGender(Gender newGender): Updates the gender of the Person object.Person#setAge(int newAge): Updates the age of the Person object.Person#setHeight(int newHeight): Updates the height of the Person object.Person#setOriginalWeight(int newOriginalWeight): Updates the original of the Person object.Person#setCurrentWeight(int newCurrentWeight): Updates the current weight of the Person object.Person#setTargetWeight(int newTargetWeight): Updates the target weight of the Person object.Person#setFitnessLevel(FitnessLevel newFitnessLevel): Updates the fitness level of the Person objectExample usage scenario and how the feature work
Summary: The corresponding existing values in Person class would be updated to the inputted values, even if the new value given is the same as the existing value.
Step 1. Takes for example the user’s name, age, gender, height, fitness level, original, current and target weight are currently Jack, 21, male, 175,You engage in some form of light exercise or have a job that requires some physical activity. ,85, 85 and 75 respectively.
Object Diagram:

Step 2. When the user wishes to edit their age and current weight, they can enter a command like the following editinfo a/22 c/80. The editinfo command would call Parse#executeEditInfo(editinfo a/22 c/80, manager) before Person#setAge(22) and Person#setCurrentWeight(80) is called.
Object Diagram:

Sequence Diagram:

Aspect: Whether one or more changes to the personal information can be made using a single command or through the use of various commands
Aspect: Use of multiple or single setter method(s)
Person classPerson#setName(String newName): Updates the name the Person object.Person#setGender(Gender newGender): Updates the gender of the Person object.Person class
Head over to the Design Considerations Section in the Enter user information feature for more related design considerations.
This feature allows users to view their personal information stored in system. It was implemented to allow users to validate their personal information so that they can edit it if necessary using the Edit user information feature.
Command word used:
userinfo: Shows the user information stored in the application.Main classes and methods used:
Person: Stores all user information provided.
Person#toString(): Returns a string representation of all user information.Example usage scenario and how the feature work
Step 1. When the user wishes to view their personal information, they can enteruserinfo. The
userinfo command would call Person#toString().
Sequence Diagram:

This feature gives the user some flexibility, allowing them to make an entry without full knowledge of the nutritional information of the food that they are eating. Due to limitations in what can be estimated, there are only two main scenarios for missing fields: a missing total calorie count or some combination of missing nutritional values (carbohydrates, proteins, fat).
Main components involved:
Manager: Parses the user input and creates an AddCommand based on the details provided in the user input. It recognises that some combination of the optional inputs are missing and flags them to FoodList when calling the FoodList#addFood(...) method by using OptionalFood.EMPTY_VALUE = -1 as the input value.
FoodList: A food entry is created via the FoodList#addFood(...) method, which has some arguments set to OptionalFood.EMPTY_VALUE = -1. Hence, when a FoodEntry is instantiated, the FoodManager#createFood(String name, int calorie, int carbohydrate, int protein, int fat) recognises the flags in the arguments and creates an OptionalFood instead of Food, for which a reference is kept in FoodEntry. When a method requiring FoodEntry#getFood() is called, FoodManager is called via FoodManager#retrieveFood(Food food) to return a Food object with guesstimated nutritional values. This guesstimation process is done by the NutritionCalculator class.
There are essentially two phases to the usuage of FoodManager and its associated dependencies: the creation of a OptionalFood that has missing values and the retrieval of a guesstimated Food object when FoodEntry#getFood() needs to be called.
For brevity, the focus will be on the processes within FoodList.

Creation:
FoodList#addFood(int portionSize,String name, int calorie, int carbohydrate, int protein, int fat) (or its variant for backlogs: FoodList#addFoodAtDateTime(...)) is called by the Logic component to add a new entry with missing nutritional inputs. The missing inputs are encapsulated by OptionalFood.EMPTY_VALUE = -1 flags.FoodList#addFood(...) instantiates a new instance of DatedFoodEntry, passing on the arguments and flags to it instead. DatedFoodEntry uses FoodManager#createFood(String name, int calorie, int carbohydrate, int protein, int fat) to instantiate a Food object. Because there are missing values, FoodManager actually instantiates OptionalFood, a child class of Food instead. A reference to this OptionalFood object is stored in the DatedFoodEntry. The newly instantiated DatedFoodEntry is also stored in the list of FoodEntry objects in FoodList.
Retrieval:
FoodEntry#getFood() is only called within functions of FoodListManager. When a method such as FoodList#getPortionedFoods() is called, FoodListManager#convertListToPortionedFoods(List list) is subsequently called.FoodListManager#convertListToPortionedFoods(List list) calls ListFunctions#applyFunctionToList(List list, Function function), and passes FoodEntry#getFood() within the function argument.ListFunctions#applyFunctionToList(List list, Function function) executes the function containing FoodEntry#getFood() in its forEach stream.FoodEntry#getFood() calls the method FoodManager#retrieveFood(Food food), passing its Food object as an argument.FoodManager#retrieveFood(Food food) checks whether the Food object is an instance of OptionalFood. If it is an OptionalFood, then it is handled differently based on the missing information. Otherwise, the Food object is simply returned.OptionalFood is calculated using NutritionCalculator based on what is missing: if calorie is missing, then NutritionCalcular.calculateCalorieFromNutrients(int carbohydrate, int protein, int fat)is called, otherwise NutritionCalculator.calculateNutrientsFromCalorie(int calorie, int carbohydrate, int protein, int fat) is called instead to calculate the missing nutrient masses.Food object containing the estimates is created and returned by FoodManager#retrieveFood(Food food), leaving the original reference to the Food object in FoodEntry unmodified in any case.Only simple methods of estimating the missing information is used by NutritionCalculator. We can allow the user the weight the split of missing nutritional values differently (it is currently all weighed equally and split by calorie contribution). This ought to be performed by the Calculator component since that is its main role. However, due to the fascade pattern being used in this implementation, the difficulty to add this feature is increased: in order to maintain the status of FoodList being non-dependent on the other components, it is recommended that functions to split the nutrients be passed to FoodManager instead (i.e. use a functional paradigm).
Additionally, storage of the FoodList should support the storage and retrieval of such missing values. Currently, only the estimated versions of the Foods are stored, and information on its status as a Food that had missing values (an OptionalFood) is lost.
FoodManager to obscure the details and processes behind the handling of a Food object with missing values. It is noted that the OptionalFood class is obscured in this process, despite being a child class of the common class Food.
OptionalFood or check for the possibility of missing values within Food. This implementation limits the existence of instances of OptionalFood to within the FoodEntry class.FoodEntry and FoodManager had to be created and maintained due to the use of this design pattern. It also makes future work with other components that want to interact with FoodManager more difficult (see Future Work section).FoodManager could be exposed as a seperate set of API that should be invoked whenever an OptionalFood needs to be handled. FoodManager becomes an adapter that components such as FoodListManager or other classes use when there is the possibility of an OptionalFood object.
FoodManager since it is exposed and can vary independently. It is also easier to test.FoodManager and potentially even OptionalFood if the latter is allowed to be passed around outside of FoodList.The Save/Load feature is implemented by the saveload package.
At the base of the package, there is the Saver
and Loader class.
Note only the Saver and Loader class is flexible. They can be adapted to new situations without modifying
the code. The FoodSaveLoadManager and PersonSaveLoadManager are written specifically for this version. They
will have to be modified/replaced for future versions.
Stores data in a internal table with length and height specified. Handles the storage of its data by writing to a text file.
Specifies the length and height of the internal Saver table
Saver#save() saves the current data to the file in the folder with the given file nameSaver#add() Store String data in the x,y position in the tableLoads data from a text file and stores it in a internal table just like the saver
static method Loader.load(folder name , file name) : creates a Loader object with
a table storing the data found in the text file
Loader#get() retrives the data stored in the loaderBuilt on top of Saver and Loader class to implement save/load functionality
for list of food items the user has input into the dietbook. Contains a instance
of both Saver and Loader. It has its own folder to work with,
the user only has to specify the file name. To save the contents of a FoodList, call
FoodPortionDateSaveLoadManager#saveFoodList(FoodList foodlist, String fileName)
To load a file, call FoodPortionDateSaveLoadManager#load() first to load the contents of the file into
the FoodPortionDateSaveLoadManager and then call FoodPortionDateSaveLoadManager#saveFoodList() to
return the FoodList with those contents.
FoodPortionDateSaveLoadManager#saveFoodList() saves the contents of the FoodList objectFoodPortionDateSaveLoadManager#load() loads the file and store the contentsFoodPortionDateSaveLoadManager#saveFoodList() returns a FoodList with the contents of the ‘FoodPortionDateSaveLoadManager’Built on top of Saver and Loader class to implement save/load functionality for user information
Same as FoodPortionDateSaveLoadManager, it has its own folder to work with, the user only has to specify the file name
Unlike the FoodPortionDateSaveLoadManager, it stores the data inside itself and can be updated.
PersonSaveLoadManager#save() save the current state into the filePersonSaveLoadManager#load() loads the fileFoodPortionDateSaveLoadManager#save()
FoodPortionDateSaveLoadManager#load()
similiar diaghrams for PersonSaveLoadManager
DataBase stores a list of food items that can be found in NUS and can be accessed by user
The data is organized into a Canteen contains a number of Stores each of which contains a list of food items
It also offers a number of filtering and searching methods. The data base resource is a text file which
can be manually updated.
Stores a List of Canteen objects. Each Canteen object stores a List of Store object,
each Store object contains a List of Food objects. Currently has a number of filtering and searching
methods. These methods can easily be modified and new ones implemented depending on the needs of the application.
DataBase#init() reads from the data text resource and loads the contents into itselfDataBase#searchFoodByIndex() returns the Food with the provided indexDataBase#searchFoodByName() returns the first Food object that contains the string providedDataBase#searchAllFoodContainingName() returns a Stream<Food> that contains all Food containing the string providedAs of this version, there is no dev mode for an administrator or a user to add new items to the data base. This can be done manually by directly editing the data.txt resource.
The DataBase#init() method reads the data.txt file line by line
&%START and &%STOP the DataBase#init() method will read anything between these two indicators
initially the data base is in the _*canteen*_ state, the next line it reads will be the canteen name
when it moves from the canteen name line to the next line, it is in the _*store*_ state,
again the next line it reads will be the store name, when it moves from the store name line to the next line,
now it is in the _*food*_ state. In this state, input a line in the format {food name}|{calorie}|{carbohydrate}|{protein}|{fats},
this will add a food item. Any number of food lines can be written and the database will be in the _*food*_ state.
To go back up to the store state, write a line of &%UP. If a store name is given in the next line, the database
will again be in the _*food*_ state. To go back up to the canteen state write 2 consecutive lines of &%UP.
|data.txt line|explanation|before state|after state| |—————————————————–|———————————————————–|—————–|—————| |&%START| starts the reading | not reading | canteen | | canteen1 | set the current canteen name to canteen1 | canteen | store | | store 1 | sets the current store name to store1 | store | food | | food1 | adds a food with the data of food1 | food | food | | food2 | adds a food with the data of food2 | food | food | | &%UP | goes up to store | food | store | | store 2 | sets the current store name to store2 | store | food | | food 3 | adds a food with the data of food3 | food | food | | &%UP | goes up to store | food | store | | &%UP | goes up to canteen | store | canteen | |&%STOP | stops the reading | canteen | not reading |
DataBase#init()
DataBase#search()
NUS students living on campus who would like to track their diet.
DietBook is designed to track the food and different kinds of nutritional intake of the user. It can also provide the user with a daily calorie recommendation based on their personal information. As the application mainly targets _NUS students staying on campus, it has a database prepopulated with food items commonly found around NUS. This allows for such food items to be easily added to the list of food items consumed for tracking.
| Version | As a … | I want to … | So that I can … |
|---|---|---|---|
| v1.0 v2.0 | person with an ideal weight in mind | input my target weight and relevant information | get daily calorie intake recommendations |
| v1.0 | careless or long term user | be able to view my personal information | make changes when necessary |
| v2.0 | careless user | be able to edit my personal information | make changes if I input the wrong information |
| v2.0 | potential long term user | be able to edit my personal information | make changes to information like age, weight and fitness level as it can changes over time |
| v2.0 | user that wants to track weight changes | be able to view the weight I started off with, my current weight and the weight I desire | take note of my progress |
Java 11 is installed in the system.Given below are instructions to test the app manually.
name Tom and JerryTom and Jerry will be stored in the system and a message prompting the user to enter all other details will be displayed.name *1**1* will be stored in the system and a message prompting the user to enter all other details will be displayed.name Ja/cknameJacknameName Jackinfo g/M a/21 h/175 o/85 c/85 t/75 f/2info o/85 a/21 f/2 h/175 g/M c/85 t/75 (where parameters can be entered in any order)info g/Ma/21h/175 o/85 c/85 t/75 f/2 (where there are no spaces between the different parameters)Info o/85 a/21 F/2 h/175 g/M c/85 t/75 (where any letter of the command word or parameter tags are capitalised)infog/M a/21 h/175 o/85 c/85 t/75 f/2 info g/M a/21 h/175 o/85 c/85 t/75 f/2 z/9 (where extra parameters,parameter tags or words are present)info g//F a/21 h/175 o/85 c/85 t/75 f/2 (where / or any other special characters is used inappropriately)info g/f a/160 h/500 o/900 c/85 t/75.6 f/7(where age, height, weights, gender and fitness level are not within the valid ranges or not valid - refer to User Guide for more information)info a/21 (where any of the required parameters are missing)editinfo n/JaneJane.editinfo a/22 c/80 (where variable number of information is changed)22 while the current weight is updated to 80.editinfoRefer to Entering User Information Section under Instructions for manual testing for similar test cases that can be used for testing.
userinfouserinfo userinfoUserinfo