diff --git a/.gitignore b/.gitignore index 5e59b862ba4..9e0d2d0dc5b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,10 @@ src/test/data/sandbox/ # MacOS custom attributes files created by Finder .DS_Store + +# VSC files +.classpath +.project +.settings +.vscode +/bin diff --git a/LICENSE b/LICENSE index 39b3478982c..1f0425b6b51 100644 --- a/LICENSE +++ b/LICENSE @@ -2,11 +2,11 @@ MIT License Copyright (c) 2016 Software Engineering Education - FOSS Resources -Permission is hereby granted, free of charge, to any person obtaining a copy +Permission is hereby granted, free of charge, to any client obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is +copies of the Software, and to permit clients to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all diff --git a/README.adoc b/README.adoc index e36efe534bb..b171861e723 100644 --- a/README.adoc +++ b/README.adoc @@ -1,11 +1,8 @@ -= Address Book (Level 3) += FitBiz ifdef::env-github,env-browser[:relfileprefix: docs/] -https://travis-ci.org/se-edu/addressbook-level3[image:https://travis-ci.org/se-edu/addressbook-level3.svg?branch=master[Build Status]] -https://ci.appveyor.com/project/damithc/addressbook-level3[image:https://ci.appveyor.com/api/projects/status/3boko2x2vr5cc3w2?svg=true[Build status]] -https://coveralls.io/github/se-edu/addressbook-level3?branch=master[image:https://coveralls.io/repos/github/se-edu/addressbook-level3/badge.svg?branch=master[Coverage Status]] -https://www.codacy.com/app/damith/addressbook-level3?utm_source=github.com&utm_medium=referral&utm_content=se-edu/addressbook-level3&utm_campaign=Badge_Grade[image:https://api.codacy.com/project/badge/Grade/fc0b7775cf7f4fdeaf08776f3d8e364a[Codacy Badge]] - +https://travis-ci.com/AY1920S2-CS2103T-F11-2/main[image:https://travis-ci.com/AY1920S2-CS2103T-F11-2/main.svg?branch=master[Build Status]] +https://coveralls.io/github/AY1920S2-CS2103T-F11-2/main[image:https://coveralls.io/repos/github/AY1920S2-CS2103T-F11-2/main/badge.svg?branch=master[Coverage Status]] ifdef::env-github[] image::docs/images/Ui.png[width="600"] @@ -15,20 +12,23 @@ ifndef::env-github[] image::images/Ui.png[width="600"] endif::[] -* This is a desktop Address Book application. It has a GUI but most of the user interactions happen using a CLI (Command Line Interface). -* It is a Java sample application intended for students learning Software Engineering while using Java as the main programming language. -* It is *written in OOP fashion*. It provides a *reasonably well-written* code example that is *significantly bigger* (around 6 KLoC)than what students usually write in beginner-level SE modules. +* The Fitness Business Management App you never knew you needed +* Tailored made for fitness coaches to manage their clients without the hassle of traditional pen and paper +* Here are some things you can do: +** Track your client's exercises and training schedules +** Display detailed graphs and charts of your client's training data +** Export a client's training data in `csv` format, allowing clients to easily store or view their own data on Excel == Site Map * <> * <> -* <> * <> * <> == Acknowledgements +* Adapted from the https://se-education.org/[AddressBook-Level3 project] created by SE-EDU initiative * Some parts of this sample application were inspired by the excellent http://code.makery.ch/library/javafx-8-tutorial/[Java FX tutorial] by _Marco Jakob_. * Libraries used: https://openjfx.io/[JavaFX], https://github.com/FasterXML/jackson[Jackson], https://github.com/junit-team/junit5[JUnit5] diff --git a/build.gradle b/build.gradle index 93029ef8262..997a26030fa 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,10 @@ mainClassName = 'seedu.address.Main' sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 +application { + applicationDefaultJvmArgs = ['-Dglass.gtk.uiScale=1.35'] +} + repositories { mavenCentral() maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } @@ -39,6 +43,8 @@ jacocoTestReport { test { useJUnitPlatform() + // uncomment this to enable printing to stdout in tests + // testLogging.showStandardStreams = true } dependencies { @@ -67,7 +73,7 @@ dependencies { } shadowJar { - archiveName = 'addressbook.jar' + archiveName = 'FitBiz.jar' destinationDir = file("${buildDir}/jar/") } @@ -77,8 +83,8 @@ task coverage(type: JacocoReport) { classDirectories.from files(sourceSets.main.output) executionData.from files(jacocoTestReport.executionData) afterEvaluate { - classDirectories.from files(classDirectories.files.collect { - fileTree(dir: it, exclude: ['**/*.jar']) + classDirectories = files(classDirectories.files.collect { + fileTree(dir: it, exclude: ['seedu/address/ui', 'seedu/address/model/util']) }) } reports { @@ -133,8 +139,8 @@ asciidoctor { idprefix: '', // for compatibility with GitHub preview idseparator: '-', 'site-root': "${sourceDir}", // must be the same as sourceDir, do not modify - 'site-name': 'AddressBook-Level3', - 'site-githuburl': 'https://github.com/se-edu/addressbook-level3', + 'site-name': 'FitBiz', + 'site-githuburl': 'https://github.com/AY1920S2-CS2103T-F11-2/main', 'site-seedu': true, // delete this line if your project is not a fork (not a SE-EDU project) ] diff --git a/docs/AboutUs.adoc b/docs/AboutUs.adoc index 458e6134f45..aeac5b1ce85 100644 --- a/docs/AboutUs.adoc +++ b/docs/AboutUs.adoc @@ -4,53 +4,48 @@ :imagesDir: images :stylesDir: stylesheets -AddressBook - Level 3 was developed by the https://se-edu.github.io/docs/Team.html[se-edu] team. + -_{The dummy content given below serves as a placeholder to be used by future forks of the project.}_ + -{empty} + +FitBiz is developed by 5 passionate software engineering students who aim to help fitness coaches manage their clients in a dynamic and innovative way. + We are a team based in the http://www.comp.nus.edu.sg[School of Computing, National University of Singapore]. == Project Team -=== John Doe -image::damithc.jpg[width="150", align="left"] -{empty}[http://www.comp.nus.edu.sg/~damithch[homepage]] [https://github.com/damithc[github]] [<>] +=== Choo Qi Le Aaron +image::aaroncql.png[width="150", align="left"] +{empty}[https://github.com/AaronCQL[github]] -Role: Project Advisor +Role: Team Leader + Developer ''' -=== John Roe -image::lejolly.jpg[width="150", align="left"] -{empty}[http://github.com/lejolly[github]] [<>] +=== Fong Yong Jie +image::yonggiee.png[width="150", align="left"] +{empty}[https://github.com/Yonggiee[github]] -Role: Team Lead + -Responsibilities: UI +Role: Developer ''' -=== Johnny Doe -image::yijinl.jpg[width="150", align="left"] -{empty}[http://github.com/yijinl[github]] [<>] +=== Li Zi Ying +image::ziyingli.png[width="150", align="left"] +{empty}[https://github.com/ziyingli[github]] -Role: Developer + -Responsibilities: Data +Role: Developer ''' -=== Johnny Roe -image::m133225.jpg[width="150", align="left"] -{empty}[http://github.com/m133225[github]] [<>] +=== Ng Ming Liang +image::dban1.png[width="150", align="left"] +{empty}[https://github.com/Dban1[github]] -Role: Developer + -Responsibilities: Dev Ops + Threading +Role: Developer ''' -=== Benson Meier -image::yl_coder.jpg[width="150", align="left"] -{empty}[http://github.com/yl-coder[github]] [<>] +=== Toh Ker Wei +image::tohkerwei.png[width="150", align="left"] +{empty}[https://github.com/tohkerwei[github]] -Role: Developer + -Responsibilities: UI +Role: Developer ''' diff --git a/docs/ContactUs.adoc b/docs/ContactUs.adoc index 81be279ef6d..5a8ed89c1ca 100644 --- a/docs/ContactUs.adoc +++ b/docs/ContactUs.adoc @@ -2,6 +2,6 @@ :site-section: ContactUs :stylesDir: stylesheets -* *Bug reports, Suggestions* : Post in our https://github.com/se-edu/addressbook-level3/issues[issue tracker] if you noticed bugs or have suggestions on how to improve. +* *Bug reports, Suggestions* : Post in our https://github.com/AY1920S2-CS2103T-F11-2/main/issues[issue tracker] if you noticed bugs or have suggestions on how to improve. * *Contributing* : We welcome pull requests. Follow the process described https://github.com/oss-generic/process[here] -* *Email us* : You can also reach us at `damith [at] comp.nus.edu.sg` +* *Email us* : You can also reach us at `e0310119[at]u.nus.edu.sg` diff --git a/docs/DevOps.adoc b/docs/DevOps.adoc index 2aa5a6bc0c1..37d762a8134 100644 --- a/docs/DevOps.adoc +++ b/docs/DevOps.adoc @@ -1,4 +1,4 @@ -= AddressBook Level 3 - Dev Ops += FitBiz Level 3 - Dev Ops :site-section: DeveloperGuide :toc: :toc-title: diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index 3d65905a853..be4bc1c2c3d 100644 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -1,4 +1,4 @@ -= AddressBook Level 3 - Developer Guide += FitBiz - Developer Guide :site-section: DeveloperGuide :toc: :toc-title: @@ -7,14 +7,15 @@ :imagesDir: images :stylesDir: stylesheets :xrefstyle: full +:experimental: ifdef::env-github[] :tip-caption: :bulb: :note-caption: :information_source: :warning-caption: :warning: endif::[] -:repoURL: https://github.com/se-edu/addressbook-level3/tree/master +:repoURL: https://github.com/AY1920S2-CS2103T-F11-2/main -By: `Team SE-EDU`      Since: `Jun 2016`      Licence: `MIT` +By: `AY1920S2-CS2103T-F11-2`   Since: `Feb 2020`      Licence: `MIT` == Setting up @@ -79,7 +80,7 @@ image::UiClassDiagram.png[] *API* : link:{repoURL}/src/main/java/seedu/address/ui/Ui.java[`Ui.java`] -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class. +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `ClientListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class. The `UI` component uses 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 link:{repoURL}/src/main/java/seedu/address/ui/MainWindow.java[`MainWindow`] is specified in link:{repoURL}/src/main/resources/view/MainWindow.fxml[`MainWindow.fxml`] @@ -100,7 +101,7 @@ link:{repoURL}/src/main/java/seedu/address/logic/Logic.java[`Logic.java`] . `Logic` uses the `AddressBookParser` class to parse the user command. . This results in a `Command` object which is executed by the `LogicManager`. -. The command execution can affect the `Model` (e.g. adding a person). +. The command execution can affect the `Model` (e.g. adding a client). . The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`. . In addition, the `CommandResult` object can also instruct the `Ui` to perform certain actions, such as displaying help to the user. @@ -123,11 +124,11 @@ The `Model`, * stores a `UserPref` object that represents the user's preferences. * stores the Address Book data. -* exposes an unmodifiable `ObservableList` 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. +* exposes an unmodifiable `ObservableList` 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. * does not depend on any of the other three components. [NOTE] -As a more OOP model, we can store a `Tag` list in `Address Book`, which `Person` can reference. This would allow `Address Book` to only require one `Tag` object per unique `Tag`, instead of each `Person` needing their own `Tag` object. An example of how such a model may look like is given below. + +As a more OOP model, we can store a `Tag` list in `Address Book`, which `Client` can reference. This would allow `Address Book` to only require one `Tag` object per unique `Tag`, instead of each `Client` needing their own `Tag` object. An example of how such a model may look like is given below. + + image:BetterModelClassDiagram.png[] @@ -153,94 +154,157 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa This section describes some noteworthy details on how certain features are implemented. -// tag::undoredo[] -=== [Proposed] Undo/Redo feature -==== Proposed Implementation +=== Command History --- Aaron Choo -The undo/redo mechanism is facilitated by `VersionedAddressBook`. -It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. -Additionally, it implements the following operations: +This feature allows users to save their previously entered commands and to retrieve them using the kbd:[Up] and kbd:[Down] arrow keys, similar to what most modern CLIs offer. -* `VersionedAddressBook#commit()` -- Saves the current address book state in its history. -* `VersionedAddressBook#undo()` -- Restores the previous address book state from its history. -* `VersionedAddressBook#redo()` -- Restores a previously undone address book state from its history. +==== Implementation -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively. +This command history mechanism is facilitated by the logic class `CommandHistory`, which controls both the model `CommandHistoryState` and the storage `CommandHistoryStorage`. The behaviour has been implemented to mimic most modern CLIs, namely: -Given below is an example usage scenario and how the undo/redo mechanism behaves at each step. +. The empty string, `""`, should not be stored in the history +. Commands that are similar to the most recently stored command in the history should not be stored (ie. duplicate commands will not be stored) +. All other user input, be it valid or invalid commands, should be stored +. Number of commands should only be stored up to a well-defined maximum number (100 in this case, for performance reasons discussed in the later section) +. Pressing the kbd:[Up] arrow key should browse backwards towards the least recently entered commands +. Pressing the kbd:[Down] arrow key should browse forwards towards the most recently entered commands +. The caret position should be at the end of the command string when browsing the history +. Persistent storage of the command history should be supported (ie. a user can quit the app and come back to the same history as his previous usage of the app) -Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state. +Since all user inputs, be it valid or invalid commands, should be stored, and since detection of the kbd:[Up] and kbd:[Down] arrow keys must occur in the `CommandBox` class found in the UI, we have decided to let `CommandBox` directly interact with `CommandHistory`. In other words, `CommandBox` will be responsible for calling `CommandHistory#addToHistory`, `CommandHistory#getNextCommand`, and `CommandHistory#getPreviousCommand`. A simplified class diagram of the classes involved in this feature is given below: -image::UndoRedoState0.png[] +image::CommandHistoryClassDiagram.png[] -Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state. +In the following sequence diagram, we trace the execution for when the user decides to enter the command `list-c` into FitBiz: -image::UndoRedoState1.png[] +image::CommandHistorySequenceDiagram.png[] -Step 3. The user executes `add n/David ...` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. +==== Design Considerations -image::UndoRedoState2.png[] +In designing the model `CommandHistoryState`, we had to decide on the underlying data structure to store the command history. We currently use an `ArrayList`, where each line of command is stored as an individual entry. Another alternative that we have considered is to store the commands in a `LinkedList`. -[NOTE] -If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`. +[options='header'] +|==================== +| Data Structure | Pros and Cons +| Array list | +*Pros*: Much easier to manipulate using indices -Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state. +*Cons*: Slower performance when list has the maximum number of commands stored and has to shift all indices back by 1 when removing the oldest command +| Linked list | +*Pros*: Fast removal of the oldest command -image::UndoRedoState3.png[] +*Cons*: Harder to implement as pointers have to be manipulated +|==================== -[NOTE] -If the `currentStatePointer` is at index 0, pointing to the initial address book state, then there are no previous address book states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo. +In the interest of saving developement time and better code readability, we decided to use an array list to store the commands. Since we have capped the maximum size of history to be 100, there is a need to remove the first item (or the zeroth index) from the list to free up space. Of course, doing a `remove(0)` on a 100-item array list will require that all 99 remaining items in the list be reassigned to new indices. However, we found out through extensive testing that this causes no observable nor significant lag when the maximum capacity of 100 items is reached and this happens. -The following sequence diagram shows how the undo operation works: +Moreover, the implementation of `CommandHistoryStorage#saveCommandHistory` will rewrite the whole data file in storage (as opposed to appending the file with the newly entered command). This decision was made to protect the integrity of the storage file, making sure that it always has the exact same data as what is stored in the `CommandHistory` model. As such, this rewriting of the file during the maximum capacity of the array list will be the bigger bottleneck in terms of performance, as opposed to the reassignment of indices. -image::UndoSequenceDiagram.png[] +As such, the choice of 100 as the maximum size of the command history is thus chosen. This number must be small enough to not cause the app to lag when the whole history is being written to storage, as well as be big enough to satisfy the user. Ultimately, we felt that 100 is a very generous estimate given that a user really only needs the past few commands at any point of time. -NOTE: The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. +=== Scheduling for a Client --- Ng Ming Liang +This feature allows for a user to assign a weekly schedule to a client. Timings are represented in the 24-hour format `HHmm`. Each client can have none or multiple schedules that do not have overlapping timings. Multiple clients are allowed to have overlapping timings with each other. -The `redo` command does the opposite -- it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state. +==== Implementation +This scheduling mechanism is facilitated by `ScheduleList`, which is a wrapper class for an `ArrayList` of `Schedule` objects. Each `Client` contains one `ScheduleList` attribute to keep track of all `Schedule` assigned to it. If there are no assigned `Schedule` for the `Client`, then the `ScheduleList` contains an empty `ArrayList` of `Schedule`. -[NOTE] -If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone address book states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo. +`Schedule` comprises three attributes: + +* `Day` + +* `StartTime` + +* `EndTime` + +`Day` wraps the enum `DayEnum.Weekday` and represents the day of the week the schedule takes place on. +`StartTime` and `EndTime` represent the start time and end time of the schedule in the "HHmm" format respectively. The relations between these classes are shown in the class diagram below. + +image::ScheduleClassDiagram.png[] -Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged. +These attributes are bounded by these characteristics: -image::UndoRedoState4.png[] +* Each `Client` can only contain unique `Schedule`, that is, there are no overlaps in timings between any two `Schedule` in the `ScheduleList`. This is ensured by `ScheduleCommandParser#checkIfOverlaps()` -Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. We designed it this way because it no longer makes sense to redo the `add n/David ...` command. This is the behavior that most modern desktop applications follow. +* Overlapping timings between the `Schedule` of different `Client` is allowed -image::UndoRedoState5.png[] +* The maximum timeframe between `StartTime` and `EndTime` is from `0000` to `2359` + +* `StartTime` cannot be later than `EndTime` + +* `Day` can only take up the 7 values of the week (MON/TUE/WED/THU/FRI/SAT/SUN) + +In the following sequence diagram, we trace the execution for when the user decides to enter the command `schedule 1 day/mon st/1100 et/1200` into FitBiz: + +image::ScheduleSequenceDiagram.png[] -The following activity diagram summarizes what happens when a user executes a new command: -image::CommitActivityDiagram.png[] ==== Design Considerations +In designing this feature, we had to consider the alternative ways in which we can choose to store the information of a schedule. One option of storing the relevant information (day, start, end times) for a schedule was simply to concatenate these values into a single String, for example, `"monday-1100-1200"`. However, we found that this did not exploit the desirable principles of Object-Oriented Programming. As respective sanity checks had to be done for the day +and timing, wrapping each of these properties into their wrapper classes allowed for better modularity and organisation of these attributes. For example, `Day#isValidDay` handles the validation of the input for day and `Time#isValidTimingFormat` handles the validation of time. + +Considerations also then had to be made for how to contain multiple `Schedule`. The current implementation uses the `ArrayList` data structure to hold multiple `Schedule`. Other considered alternative for `ScheduleList` was `HashSet`. +[options='header'] +|==================== +| Data Structure | Pros and Cons +| ArrayList | +*Pros*: Elements can be sorted and retrieved in ascending order + +*Cons*: Does not ensure that its elements are unique +| HashSet | +*Pros*: Does not allow duplicate values + +*Cons*: Does not return elements in order +|==================== + +As the nature of the schedule panel was to display a sorted collection of `Schedule`, we chose `ArrayList` as the underlying data structure. In addition, we also harnessed the capability of the `HashSet` to ensure no overlaps between `Schedule` within each `Client`, which is implemented by `ScheduleCommandParser#checkIfOverlaps`. -===== Aspect: How undo & redo executes +=== Command Autocompletion --- Aaron Choo -* **Alternative 1 (current choice):** Saves the entire address book. -** Pros: Easy to implement. -** Cons: May have performance issues in terms of memory usage. -* **Alternative 2:** Individual command knows how to undo/redo by itself. -** Pros: Will use less memory (e.g. for `delete`, just save the person being deleted). -** Cons: We must ensure that the implementation of each individual command are correct. +Similar to the previously mentioned "Command History" feature, this feature improves the user experience by allowing users to press the kbd:[Tab] key to autocomplete their partially entered commands. -===== Aspect: Data structure to support the undo/redo commands +==== Implementation -* **Alternative 1 (current choice):** Use a list to store the history of address book states. -** Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project. -** Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both `HistoryManager` and `VersionedAddressBook`. -* **Alternative 2:** Use `HistoryManager` for undo/redo -** Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase. -** Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as `HistoryManager` now needs to do two different things. -// end::undoredo[] +This feature is facilitated by the logic found in the `AutoComplete` class. Before we dive into the implementation, let us first define what _unambiguous_ and _ambiguous_ commands are. Unambiguous commands are those that can be uniquely identified by the sequence of letters that the user has entered. Ambiguous commands are those that cannot be identified by the said sequence of letters. For example, assume we only have 3 commands in our app, `add-c`, `add-e`, and `edit-c`. If the user enters `e` and presses kbd:[Tab], we say that this is an unambiguous command since clearly only `edit-c` can be the correct command. If instead, the user enters `a` and presses kbd:[Tab], we say that this is an ambiguous command, since both `add-c` and `add-e` are possible choices. Again, let us start by defining the behaviour (which also has been implemented to mimic most modern CLIs): -// tag::dataencryption[] -=== [Proposed] Data Encryption +. The caret position should be at the end of the line after any successful autocompletion of commands +. Any unambiguous commands should be completed upon pressing of the kbd:[Tab] key +. Any ambiguous commands should be completed up till the longest common prefix of all similar commands +** Using the ambiguous command example in the introduction above, when the user enters `a` and presses kbd:[Tab], the autocompletion should return `add-` to the user +. A list of all similar commands should be presented to the user should he try to autocomplete an ambiguous command -_{Explain here how the data encryption feature will be implemented}_ +A limitation of the current design is that we are only able to autocomplete _commands_, and not other fields/parameters like names and addresses that have been used by the user before. As such, since all commands defined in FitBiz do not have empty spaces in them, this allows us to easily determine when to disable this feature (ie. when the user has already completed the command and has moved on to entering the parameters). As such, the following code snippet is used in `AutoComplete#execute` to stop trying to autocomplete if white spaces has been detected: -// end::dataencryption[] +```java +if (currCommand.contains(WHITE_SPACE_STRING)) { + return; +} +``` + +Similarly, since this feature relies heavily on the UI `CommandBox`, we have decided to let `CommandBox` interact with `AutoComplete` directly. `AutoComplete` makes use of the `Trie` data structure which we will discuss in the next section. As such, the following simplified class diagram shows exactly which classes are responsible for this feature: + +image::CommandAutocompleteClassDiagram.png[] + +==== Design Considerations + +For the implementation of this feature, we have decided to use a Trie data structure. Since no such data structure exists natively in Java, we had to implement our own version of it. Of course, we have also considered other much simpler alternatives like simply storing all available commands in a `List`. A quick summary of the pros and cons is given here: + +[options='header'] +|==================== +| Data Structure | Pros and Cons +| Trie | +*Pros*: Searching is relatively inexpensive, and handles behaviour number 3 discussed above efficiently + +*Cons*: Harder initial development of this data structure +| List | +*Pros*: Fast initial development + +*Cons*: Searching is computationally expensive; does not scale well with the app as the list of commands grow +|==================== + +As such, the choice of implementing our own Trie data structure is obvious. Exchanging some initial development time for future scalability of our app will ensure that we, or future developers, do not end up wasting time refactoring what could have been done in the first place. Moreover, as mentioned, the Trie data structure is effective and computationally inexpensive in finding the longest common prefix of all ambiguous commands. The same cannot be said when using just a list. + +Also, since we have implemented our own Trie data structure, it would also allow more custom logic to be added later, and allow more creative freedom with respect to the features that future developers would want to add. === Logging @@ -257,11 +321,120 @@ We are using `java.util.logging` package for logging. The `LogsCenter` class is * `INFO` : Information showing the noteworthy actions by the App * `FINE` : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size +=== Exercise Feature --- Yong Jie + +The function of recording the clients' exercises is one of the main features of our application. This section provides its key implementation details. + +==== Implementation + +===== Exercise class + +We implemented the `Exercise` class to contain the details of the exercise. An example would be the use of `ExerciseWeight` class to represent the weight of the exercise. Below shows a UML class diagram which provides further understanding of `Exercise`. + +image::ExerciseClassDiagram.png[] + +===== Exercise Commands + +Currently, there are only 2 exercise commands. The `add-e` command adds an exercise to the client and the `delete-e` command deletes an exercise from a client. The commands follow a similar execution flow as other commands. + +For the `add-e` command, we had to pay particular attention to the index where new Exercise is added. This is such that the exercises for the client will be displayed in descending chronological order in the table after a `view-c` command. `TableView` provides sorting for dates. However, having `TableView` to do the sorting would result in mismatch of indexes of the exercises in the `UniqueExerciseList` and in the `TableView`. This would result in problems when using `delete-e` command as it deletes the exercise at the specified index. + +We will use an example of a `add-e` command to illustrate the program execution flow. Consider an instance where user inputs `add-e n/pushup d/12-12-2011 reps/20`. The `AddressBookParser` will create a `AddExerciseCommandParser`. By using `ParserUtil`, `AddExerciseCommandParser` will extract details like the reps of the exercise and pass the arguments to `AddExerciseCommand`. The sequence diagram below shows the execution flow when the AddExerciseCommand is executed. Details of exception thrown are omitted as this is a postive instance and for simplicity. + +image::AddExerciseCommandSequenceDiagram.png[] + +`AddExerciseCommand` checks if there is an client being viewed. For this instance, we will consider the positive case where indeed there is a client being viewed. `AddExerciseCommand` will retrieve the client being viewed from the `Model` so that details like the existing exercise list of the client can be obtained. The sequence diagram illustrates the execution flow of how the new exercise, `toAdd`, is added to the exercise list. + +image::AddExerciseCommandSequenceDiagramPart2.png[] + +The exercise list, `UniqueExerciseList`, will go through a loop and iterate through the exercises in the list. The date of each exercise will be compared with the date of the `toAdd` exercise. `toAdd` will then be added to the `UniqueExerciseList` at the index to keep the list sorted. + +==== Design Considerations + +This section explains the our design considerations and analysis for the storage of exercises. + +[options='header'] +|==================== +| Considerations | Pros and Cons +| Store exercises with client and all clients in one JSON file | +*Pros*: Much easier to link the exercises to the client during reading and storing + +*Cons*: Might have one large JSON file and potentially exceed the size limit of a JSON file +| Store all exercises into a separate JSON file | +*Pros*: Keep exercise data separate from client data + +*Cons*: Hard to link the exercises to the client during reading and storing + +| Store exercises with client but one JSON for each client | +*Pros*: Low chances of exceeding the size limit of a JSON file + +*Cons*: Might have too many JSON files for each client + +Tough to identify which JSON file is for which client +|==================== + +We decided to use the first approach of storing the exercises with the associated client and have all the clients data in one JSON file. By code wise, each `JsonAdaptedClient` will have a list of `JsonAdaptedExercise`. + +image::ClientExerciseStorageClassDiagram.png[] + +We want to keep the implementation reading and storing of data simple. The first approach is the most simple. When reading the data, it removes the need to associate the exercises to the client. A client might potentially have a large amount of exercises, resulting in the reading process to be extremely slow. + +Moreover, storing the exercise data from client data does not provide any performance benefits. Due to time constraints, we decided that the application should store all the data everytime it closes. This is regardless if the particular exercise or client data has been changed. Having to keep track of which data is edited and only overwrite those data would greatly increase the complexity of the application. Therefore, keeping exercises data separate from client data would be unnecessary and provide little additional functionality/benefits to the user. + +Lastly, we foresee that it is improbable for the data size of both clients and exercises to exceed the maximum size limit of a JSON file. With the target user in mind, it is unlikely that he will have an enormous amount of clients as he will have to cater time for each of them. Even though each client might have many exercises, the information of each exercise is relatively small. For now, collectively, the client and exercise data is unlikely to exceed the JSON size limit. We might consider to have multiple JSON files if the data size gets too big in future versions. + [[Implementation-Configuration]] === Configuration Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: `config.json`). +=== Personal Best --- Li Zi Ying + +This feature allows the users (ie. gym managers) to view the personal bests of exercises done by a client. This information is displayed in a table form, after the command `view-c INDEX` is called. + +==== Implementation + +The personal best feature is facilitated by the model `PersonalBest`, and the logic behind it is in `PersonalBestFinder`. The behaviour of this feature determines the personal best of each exercise done by the client based on these considerations: + +* If the `ExerciseWeight` attribute is recorded in the `Exercise`, then the `ExerciseWeight` is used as comparison +* If there is no `ExerciseWeight` recorded in the `Exercise`, then `ExerciseReps` will be used as comparison +* If neither of `ExerciseWeight` and `ExerciseReps` are recorded into the `Exercise`, then this particular exercise will not be put into the Exercise Personal Best table +** However, if the another `Exercise` of the same name is added in the future with `ExerciseWeight` and/or `ExerciseReps` specified, then the personal best of this exercise will still be calculated and shown in the Exercise Personal Best table + +When the user inputs `view-c`, `add-e` or `delete-c`, `PersonalBestFinder#generateAndSetPersonalBest` is called, taking the client currently in view as the parameter. `PersonalBestFinder#generateAndSetPersonalBest` then retrieves client's list of exercises using `Client#getExerciseList` and creates a new `HashMap`, where the `key` is `ExerciseName` and the `value` is `Exercise`. Then the personal bests of each exercise of the client in view are generated using the above considerations. Finally the list of personal bests is set using `PersonalBest#setPersonalBest`. + +A simplified class diagram of the classes involved in this feature is given below: + +image::PersonalBestClassDiagram.png[] + +In the following sequence diagram, we trace the execution for when the user decides to enter the command `view-c` into FitBiz: + +image::PersonalBestSequenceDiagram.png[] + +==== Design Considerations + +In designing this features, we had to decide on the placement of the `PersonalBest` class in the model to comply with the OOP standards. Currently, the `PersonalBest` model has a whole-part relationship with `Client`, with `Client` being the whole and `PersonalBest` being a part of `Client`. The alternative is to consider `PersonalBest` as a part of `Exercise` instead. + +[options='header'] +|==================== +| Considerations | Pros and Cons +| Put `PersonalBest` as a part of `Client` | +*Pros*: Logically makes more sense, as each client has to have a list of exercises to themselves, and thus `PersonalBest` of each of these exercises + +*Cons*: Might have significant conflicts as the `Client` model is changed to include one more attribute + +| Put `PersonalBest` as a part of `Exercise` | +*Pros*: Keep `Exercise` data and methods separate from `Client` data and methods + +*Cons*: Actually increases coupling as the logic was flawed + +|==================== + +We decided to use the first approach of placing `PersonalBest` as a part of `Client` instead of `Exercise`. There are multiple reasons for our choice as mentioned below. + +We want to maintain the OOP structure of the program. Logically, the personal best should belong to the client as the list of exercises belongs to the client. As the list of exercises is unique to every client, the personal best should also be so. + +Moreover, even though personal best is generated using the list of exercises in the client, it can be instantiated even without an exercise list. Therefore it does not require the exercise class to exist and does not have a whole-part relationship with exercise. Coupling will also be increased as the client will be relying on the exercise class to generate the personal best. Therefore, the final choice was to place the personal best under client, with every client having their own personal best attribute. + == Documentation Refer to the guide <>. @@ -279,51 +452,148 @@ Refer to the guide <>. *Target user profile*: -* has a need to manage a significant number of contacts +* has a need to manage a significant number of gym clients and their information (clients' details and exercises) * prefer desktop apps over other types * can type fast * prefers typing over mouse input * is reasonably comfortable using CLI apps +* wants to book facilities easily [v2.0] -*Value proposition*: manage contacts faster than a typical mouse/GUI driven app +*Value proposition*: Keep track of your gym training schedule and clients' exercises faster than a typical mouse/GUI driven app [appendix] == User Stories Priorities: High (must have) - `* * \*`, Medium (nice to have) - `* \*`, Low (unlikely to have) - `*` -[width="59%",cols="22%,<23%,<25%,<30%",options="header",] +[width="59%",cols="22%,<30%,<35%,<50%",options="header",] |======================================================================= |Priority |As a ... |I want to ... |So that I can... -|`* * *` |new user |see usage instructions |refer to instructions when I forget how to use the App +|`* * *` |coach for fitness competitors |record the cliental bests of my clients |monitor their progress +|`* * *` |coach for fitness competitors |record the exercise type and intensity my clients have done for the day |know if they are on track for their competitions +|`* * *` |coach for fitness competitors|record the date and time of my clients’ training sessions and keep track of which day they work out| +|`* * *` |coach with many fitness competitors |view my overall schedule for the day/week| +|`* * *` |coach that communicates with my clients |display visualisations(graphs/charts) |convey the client's training progress better +|`* * *` |coach |add new profiles to the app to keep track of new clients| +|`* * *` |coach |list all my clients| +|`* * *` |coach |edit a client’s details |change and update an existing client’s details +|`* * *` |coach |delete my client| +|`* * *` |coach |search my client by typing their name |find my client’s information easily +|`* * *` |coach |add, edit and delete new exercises that are not found in the application| +|`* * *`| coach |look for user help |get help on how to use the features +|`* *` |coach with many clients |be reminded of my daily schedule at the start of the day |track my appointments +|`* *` |forgetful coach with many clients |look at my records on clients |know what exercises they are weak in or require more assistance +|`* *` |coach with a tight schedule |display my open slots |plan for training more effectively +|`* *` |coach with many clients |set clientalised goals for my clients |plan a workout routine that is achievable +|`* *` |coach with many different clients |easily export the data of a client (to a CSV file) |backup and store that data in another format +|`* *` |coach |track my clients by using a tag |easily view the clients I want to +|`*` |coach with clients all over SG |find the nearest gym based on where my client stays| +|`*` |coach with a tight schedule |view a summary page to present to me just the important data, configurable by me| +|`*` |coach |track my total earnings from all my clients| +|`*` |coach that likes to vary my clients’ training |choose from a list of different exercises with the same purposes| +|`*` |coach for fitness competitors |view incoming competitions of my clients |be reminded to focus on them more +|`*` |coach who wants to visually track the progress of my clients |store photos to monitor the changes in my client’s physique| +|`*` |coach |check if the gym I am going to is closed| +|`*` |coach |use the timer in the application |seamlessly execute the time interval of the workout planned +|`*` |coach |book the facilities required by the workout| +|`*` |coach |see upcoming competitions or meet |plan for my clients to attend them +|`*` |coach for fitness competitors |record the food intake of my clients |know if they are following my diet plan for them +|`*` |coach |monitor my clients caloric intake |know he is meeting his dietary requirements +|`*` |coach |manage the payment fee/payment day of the clients |charge them accordingly +|======================================================================= -|`* * *` |user |add a new person | +_{More to be added}_ -|`* * *` |user |delete a person |remove entries that I no longer need +[appendix] +== Use Cases -|`* * *` |user |find a person by name |locate details of persons without having to go through the entire list +(For all use cases below, the *System* is the `FitBiz` and the *Actor* is the `user`, unless specified otherwise) -|`* *` |user |hide <> by default |minimize chance of someone else seeing them by accident +[discrete] +=== Use case 1: Add client -|`*` |user with many persons in the address book |sort persons by name |locate a person easily -|======================================================================= +*MSS* -_{More to be added}_ +1. User requests to add a client +2. FitBiz requests for details(eg. name) +3. User enters the details +4. FitBiz adds client to database ++ +Use case ends. -[appendix] -== Use Cases +*Extensions* -(For all use cases below, the *System* is the `AddressBook` and the *Actor* is the `user`, unless specified otherwise) +[none] +* 3a. The input format is invalid. ++ +[none] +** 3a1. FitBiz shows an error message +** 3a2. User enters the new details. ++ +Steps 3a1 to 3a2 are repeated until the data entered is correct. +Use case resumes from step 4 [discrete] -=== Use case: Delete person +=== Use case 2: View client *MSS* -1. User requests to list persons -2. AddressBook shows a list of persons -3. User requests to delete a specific person in the list -4. AddressBook deletes the person +1. User requests to view all the available information of client +2. FitBiz shows a list of clients +3. User requests to view a specific client in the list +4. FitBiz shows all available information of the client ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The list is empty. ++ +Use case ends. + +* 3a. The given name is invalid. ++ +[none] +** 3a1. FitBiz shows an error message. ++ +Use case resumes at step 2. + +[discrete] +=== Use case 3: Edit client + +*MSS* + +1. User requests to edit a client's cliental details +2. FitBiz shows a list of clients +3. User requests to edit a specific client in the list and inputs the attributes and values +4. FitBiz edits client's details ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The list is empty. ++ +Use case ends. + +* 3a. The input format is invalid. ++ +[none] +** 3a1. FitBiz shows an error message. ++ +Use case resumes at step 2. + +[discrete] +=== Use case 4: Delete client + +*MSS* + +1. User requests to delete a client +2. FitBiz shows a list of clients +3. User requests to delete a specific client in the list +4. FitBiz deletes the client + Use case ends. @@ -334,10 +604,194 @@ Use case ends. + Use case ends. -* 3a. The given index is invalid. +* 3a. The given format is invalid. + [none] -** 3a1. AddressBook shows an error message. +** 3a1. FitBiz shows an error message. ++ +Use case resumes at step 2. + +[discrete] +=== Use case 5: List clients + +*MSS* + +1. User requests to list all existing clients +2. FitBiz lists all existing clients ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The input format is invalid. ++ +[none] +** 2a1. FitBiz shows an error message. ++ +Use case resumes at step 1. + +[discrete] +=== Use case 6: Add exercise + +*MSS* + +1. User requests to add an exercise to a client +2. FitBiz shows a list of clients +3. User requests to add exercise to a specific client in the list +4. FitBiz add exercise to the client ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The list is empty. ++ +Use case ends. + +* 3a. The given name is invalid. ++ +[none] +** 3a1. FitBiz shows an error message. ++ +Use case resumes at step 2. + +[discrete] +=== Use case 7: Start timer + +*MSS* + +1. User requests to start a timer +2. FitBiz starts a timer for the specified duration ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The input format is invalid. ++ +[none] +** 2a1. FitBiz shows an error message. ++ +Use case resumes at step 1. + +[discrete] +=== Use case 8: Filter clients + +*MSS* + +1. User requests to filter clients based on an attribute +2. FitBiz filters clients based on specified attribute ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The input format is invalid. ++ +[none] +** 2a1. FitBiz shows an error message. ++ +Use case resumes at step 1. + +[discrete] +=== Use case 9: View cliental best + +*MSS* + +1. User requests to view a client's cliental best +2. FitBiz lists all clients +3. User requests to view the cliental best of a specific client on the list +3. FitBiz displays the cliental best ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The list is empty. ++ +Use case ends. + +* 3a. The input format is invalid. ++ +[none] +** 3a1. FitBiz shows an error message. ++ +Use case resumes at step 2. + +[discrete] +=== Use case 10: View schedule + +*MSS* + +1. User requests to view schedule for the day or the time specified +2. FitBiz shows the schedule ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The input format is invalid. ++ +[none] +** 2a1. FitBiz shows an error message. ++ +Use case resumes at step 1. + +[discrete] +=== Use case 11: Export data + +*MSS* + +1. User requests to export a client's training record to a CSV file +2. FitBiz shows a list of clients +3. User requests to export a specific client's training record in the list +4. FitBiz exports the client's training records ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The list is empty. ++ +Use case ends. + +* 3a. The given name is invalid. ++ +[none] +** 3a1. FitBiz shows an error message. ++ +Use case resumes at step 2. + +[discrete] +=== Use case 12: View visualisations + +*MSS* + +1. User requests to view graph visualisations of a client's progress +2. FitBiz shows a list of clients +3. User requests to view the training graph of a specific client in the list +4. Fitbiz shows the training graph of the client ++ +Use case ends. + +*Extensions* + +[none] +* 2a. The list is empty. ++ +Use case ends. + +* 3a. The given name is invalid. ++ +[none] +** 3a1. FitBiz shows an error message. + Use case resumes at step 2. @@ -347,8 +801,15 @@ _{More to be added}_ == Non Functional Requirements . Should work on any <> as long as it has Java `11` or above installed. -. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. +. Should be able to hold up to 1000 clients without a noticeable sluggishness in performance for typical usage. . A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. +. Should work without the need for Internet in the program. +. Should work reliably. +. Should be able to store data in a human-readable format. +. Should be for a single user. +. Should not use DBMS to store data. +. Should not exceed 100Mb in file size. + _{More to be added}_ @@ -359,7 +820,13 @@ _{More to be added}_ Windows, Linux, Unix, OS-X [[private-contact-detail]] Private contact detail:: -A contact detail that is not meant to be shared with others +A contact detail that is not meant to be shared with others. + +[[exercise]] Exercise:: +A workout activity done by a client that is to be recorded. + +[[cliental-best]] Cliental Best:: +The best/highest weight that the client has reached for an exercise. [appendix] == Product Survey @@ -402,15 +869,15 @@ These instructions only provide a starting point for testers to work on; testers _{ more test cases ... }_ -=== Deleting a person +=== Deleting a client -. Deleting a person while all persons are listed +. Deleting a client while all clients are listed -.. Prerequisites: List all persons using the `list` command. Multiple persons in the list. +.. Prerequisites: List all clients using the `list` command. Multiple clients in the list. .. Test case: `delete 1` + Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. .. Test case: `delete 0` + - Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. + Expected: No client is deleted. Error details shown in the status message. Status bar remains the same. .. Other incorrect delete commands to try: `delete`, `delete x` (where x is larger than the list size) _{give more}_ + Expected: Similar to previous. diff --git a/docs/Documentation.adoc b/docs/Documentation.adoc index ad90ac87bda..d067fe69e3c 100644 --- a/docs/Documentation.adoc +++ b/docs/Documentation.adoc @@ -1,4 +1,4 @@ -= AddressBook Level 3 - Documentation += FitBiz Level 3 - Documentation :site-section: DeveloperGuide :toc: :toc-title: diff --git a/docs/LearningOutcomes.adoc b/docs/LearningOutcomes.adoc index 436c1777617..82c59f49f04 100644 --- a/docs/LearningOutcomes.adoc +++ b/docs/LearningOutcomes.adoc @@ -33,7 +33,7 @@ What other user stories do you think AddressBook should support? Add those user === Exercise: Add a 'Rename tag' use case * Add a use case to the `DeveloperGuide.adoc` to cover the case of _renaming of an existing tag_. -e.g. rename the tag `friends` to `buddies` (i.e. all persons who had the `friends` tag will now have +e.g. rename the tag `friends` to `buddies` (i.e. all clients who had the `friends` tag will now have a `buddies` tag instead) Assume that AddressBook confirms the change with the user before carrying out the operation. @@ -108,12 +108,12 @@ image::PrintableInterface.png[width=400] String getPrintableString(Printable... printables) { ---- + -The above method can be used to get a printable string representing a bunch of person details. +The above method can be used to get a printable string representing a bunch of client details. For example, you should be able to call that method like this: + [source,java] ---- -// p is a Person object +// p is a Client object return getPrintableString(p.getPhone(), p.getEmail(), p.getAddress()); ---- diff --git a/docs/SettingUp.adoc b/docs/SettingUp.adoc index c0659782fab..9e7f90ebc14 100644 --- a/docs/SettingUp.adoc +++ b/docs/SettingUp.adoc @@ -1,4 +1,4 @@ -= AddressBook Level 3 - Setting Up += FitBiz Level 3 - Setting Up :site-section: DeveloperGuide :toc: :toc-title: @@ -72,7 +72,7 @@ Set up Travis to perform Continuous Integration (CI) for your fork. See <>). [NOTE] -Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork. +Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your cliental fork. Optionally, you can set up AppVeyor as a second CI (see <>). diff --git a/docs/Testing.adoc b/docs/Testing.adoc index 5767b92912c..2648a2d6e28 100644 --- a/docs/Testing.adoc +++ b/docs/Testing.adoc @@ -1,4 +1,4 @@ -= AddressBook Level 3 - Testing += FitBiz Level 3 - Testing :site-section: DeveloperGuide :toc: :toc-title: diff --git a/docs/UserGuide.adoc b/docs/UserGuide.adoc index 4e5d297a19f..7db8abf2b8f 100644 --- a/docs/UserGuide.adoc +++ b/docs/UserGuide.adoc @@ -1,4 +1,4 @@ -= AddressBook Level 3 - User Guide += FitBiz - User Guide :site-section: UserGuide :toc: :toc-title: @@ -12,166 +12,314 @@ ifdef::env-github[] :tip-caption: :bulb: :note-caption: :information_source: endif::[] -:repoURL: https://github.com/se-edu/addressbook-level3 +:repoURL: https://github.com/AY1920S2-CS2103T-F11-2/main -By: `Team SE-EDU` Since: `Jun 2016` Licence: `MIT` +By: `CS2103T-F11-2` Since: `Feb 2020` Licence: `MIT` -== Introduction +== Overview -AddressBook Level 3 (AB3) is for those who *prefer to use a desktop app for managing contacts*. More importantly, AB3 is *optimized for those who prefer to work with a Command Line Interface* (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps. Interested? Jump to the <> to get started. Enjoy! +=== About FitBiz + +FitBiz is a business management tool tailor made for fitness coaches to manage their clients. From managing your client's profile to planning your schedules, FitBiz will surely ease the pain and monotony of managing a small to medium client portfolio. + +This program is primarily a desktop application and optimised for those who prefer to work with a Command Line Interface (CLI). If you can type fast, and have clients to train and manage, FitBiz is definitely for you! + +=== About this User Guide + +This User Guide explains how to use the FitBiz CLI, as well as provides an understanding of the features and commands and some common use cases. + +In this guide, we cover: + +* Syntax of the commands available in FitBiz +* Common use cases for each command + +=== Miscellaneous Features + +As this is primarily a CLI based application, some features are included to make the user experience better. The following features are provided to simplify the use of FitBiz: + +* Command History: similar to most modern CLIs, users can press the kbd:[Up] and kbd:[Down] arrow key to cycle through their previously entered commands. This history is persisted in the storage, allowing users to quickly reference what they have entered in a previous usage of this app. +* Command Auto Completion: again, similar to most modern CLIs, users can press the kbd:[Tab] key to auto complete the commands that they have partially typed. If the partially typed letters begin a string that uniquely identifies a command, the complete command name appears. Otherwise, a list of all commands similar to the ambiguous letters will appear. == Quick Start -. Ensure you have Java `11` or above installed in your Computer. -. Download the latest `addressbook.jar` link:{repoURL}/releases[here]. -. Copy the file to the folder you want to use as the home folder for your Address Book. -. Double-click the file to start the app. The GUI should appear in a few seconds. +. Ensure you have Java 11 or above installed in your Computer +. Download the latest `FitBiz.jar` link:{repoURL}/releases[here] +. Copy the file to the folder you want to use as the home folder for your Fitness Manager +. Double-click the file to start the app. The GUI should appear in a few seconds +. Type the command in the command box and press kbd:[Enter] to execute it. e.g. typing `help` and pressing kbd:[Enter] will open the help window. +. Some example commands you can try: +* `list-c` : lists all clients +* `add-c n/John Doe g/Male p/98765432 e/johnd@example.com a/John street, block 123, #01-01 b/24-12-1997 h/170 cw/70 tw/75` +: adds a client named John Doe to FitBiz +* `exit` : exits the app +. Refer to <> below for details of each command + +== Commands + +This section introduces the syntax and the usages of the commands available in FitBiz. In explaining the syntax, we will adhere to the following format: + +* Words in `UPPER_SNAKE_CASE` are the parameters to be supplied by the user +** e.g. in `add-c n/NAME`, `NAME` is a parameter which can be used as `add-c n/John Doe` +* Items in square brackets are optional +** e.g. `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe` +* Items with `…` after them can be used multiple times including zero times +** e.g. `[t/TAG]…` can be used as (i.e. 0 times), `t/friend`, `t/friend t/family` etc. +* Parameters can be in any order +** e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable + +=== Add a new client profile: `add-c` + +Initialises and adds a new client profile. + +Format: `add-c n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [g/GENDER] [h/HEIGHT] [cw/CURRENT_WEIGHT] [tw/TARGET_WEIGHT] [r/REMARK] [s/SPORT]… [t/TAG]…` + +* `n/NAME` is case insensitive. e.g `hans` will match `Hans` +* The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +* Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` +* A client can have any number of tags (including 0) + +Examples: + +* `add-c n/Ming Liang p/98765432 e/johnd@example.com a/John street, block 123, #01-01` +** Adds a new client: Ming Liang with the above information +* `add-c n/Low Tah Kiow, John t/powerlifter e/betsycrowe@example.com a/some street p/1234567 t/strongman` +** Adds a new client: Low Tah Kiow, John with the above information + +=== Add a client's exercise: `add-e` + +Adds and records an exercise to the client currently being viewed. + +Format: `add-e n/EXERCISE_NAME d/DATE [ew/EXERCISE_WEIGHT] [reps/REPS] [sets/SETS]` + +* `add-e` can only be used when a client is in view (ie. `view-c` is called first) +* `DATE` must be of the form `DD-MM-YYYY` (ie. 02-07-2020 for 2nd July 2020) +* `n/EXERCISE_NAME` is case sensitive. e.g `squats` will not match `Squats` +* The order of words will matter. e.g `High Lunge` will not match `Lunge High` +* `[ew/EXERCISE_WEIGHT] [reps/REPS] [sets/SETS]` must be a positive whole integer (ie. 1, 2, 3, ...) + +Examples: + +* `view-c 1` ++ +`add-e n/Push Ups d/25-02-2020 reps/50` ++ +** Adds an exercise called "Push Ups" with "50 reps" on 25th February 2020 to the 1st client +* `view-c 3` ++ +`add-e n/Bench Press d/26-02-2020 ew/120 reps/10` ++ +** Adds an exercise called "Bench Press" of weight 120kg with "10 reps" on 26th February 2020 to the 3rd client + +=== Delete a client's exercise: `delete-e` + +Deletes an existing exercise at the specified index from the exercise list of the client currently being viewed. + +Format: `delete-e INDEX` + +* `delete-e` can only be used when a client is in view (ie. `view-c` is called first) +* `INDEX` refers to the index number shown in the displayed exercise list of the client currently being viewed +* `INDEX` must be a positive integer (ie. 1, 2, 3, ...) + +Examples: + +* `view-c 1` + -image::Ui.png[width="790"] +`delete-e 4` + -. Type the command in the command box and press kbd:[Enter] to execute it. + -e.g. typing *`help`* and pressing kbd:[Enter] will open the help window. -. Some example commands you can try: +** Deletes the 4th exercise from the exercise list of the 1st client -* *`list`* : lists all contacts -* **`add`**`n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : adds a contact named `John Doe` to the Address Book. -* **`delete`**`3` : deletes the 3rd contact shown in the current list -* *`exit`* : exits the app +=== Delete a client: `delete-c` -. Refer to <> for details of each command. +Deletes the client at the specified index from the program. -[[Features]] -== Features +Format: `delete-c INDEX` -==== -*Command Format* +* `INDEX` refers to the index number shown in the displayed client list +* `INDEX` must be a positive integer (ie. 1, 2, 3, ...) -* Words in `UPPER_CASE` are the parameters to be supplied by the user e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`. -* Items in square brackets are optional e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. -* Items with `…`​ after them can be used multiple times including zero times e.g. `[t/TAG]...` can be used as `{nbsp}` (i.e. 0 times), `t/friend`, `t/friend t/family` etc. -* Parameters can be in any order e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. -==== +Examples: -=== Viewing help : `help` +* `delete-c 4` +** Deletes the 4th client from the program -Format: `help` +=== Edit a client’s profile: `edit-c` -=== Adding a person: `add` +Edits the client’s cliental details by specifying the attribute and the new value. -Adds a person to the address book + -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` +Format: `edit-c INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [g/GENDER] [h/HEIGHT] [cw/CURRENT_WEIGHT] [tw/TARGET_WEIGHT] [r/REMARK] [s/SPORT]… [t/TAG]...` -[TIP] -A person can have any number of tags (including 0) +* `INDEX` refers to the index number shown in the displayed client list +* `INDEX` must be a positive integer (ie. 1, 2, 3, ...) +* At least one of the optional fields must be provided +* When editing tags, the existing tags of the client will be removed i.e adding of tags is not cumulative +* You can remove all the client’s tags by typing `t/` without specifying any tags after it Examples: -* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` -* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal` +* `edit-c 1 n/Ming Liang a/60 a/male` +** Edits the name of the 1st client to Ming Liang, age to 60, and gender to male. + +=== Export as CSV: `export` [Coming in v1.4] -=== Listing all persons : `list` +Exports a client’s training record to a CSV file. -Shows a list of all persons in the address book. + -Format: `list` +Format: `export INDEX` -=== Editing a person : `edit` +* `INDEX` refers to the index number shown in the displayed client list +* `INDEX` must be a positive integer (ie. 1, 2, 3, ...) -Edits an existing person in the address book. + -Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]...` +Example: -**** -* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index *must be a positive integer* 1, 2, 3, ... -* At least one of the optional fields must be provided. -* Existing values will be updated to the input values. -* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative. -* You can remove all the person's tags by typing `t/` without specifying any tags after it. -**** +* `export 6` +** Exports training records of the 6th client + +=== Filter clients based on attribute: `filter-c` [Coming in v1.4] + +Filters the client list by the specified keyword(s) that matches the name or any attributes the client has. + +Format: `filter-c KEYWORD [MORE_KEYWORDS]` + +* The search is case insensitive. e.g `push ups` will match `Push Ups` +* The order of the keywords does not matter (e.g. `Push Pull` will match `Pull Push`) +* Only full words will be matched e.g. `Push` will not match `Push Pull` +* Clients matching at least one keyword will be returned (i.e. `OR` search). e.g. `Hans Bo` will return `Hans Gruber, Bo Yang` Examples: -* `edit 1 p/91234567 e/johndoe@example.com` + -Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively. -* `edit 2 n/Betsy Crower t/` + -Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags. +* `filter-c Johnny` +** Returns a client list of `Johnny Tim` and `johnny` -=== Locating persons by name: `find` +=== Display visualisations of training progress: `graph` [Coming in v1.4] -Finds persons whose names contain any of the given keywords. + -Format: `find KEYWORD [MORE_KEYWORDS]` +Shows visualisations of a client’s exercise progress. -**** -* The search is case insensitive. e.g `hans` will match `Hans` -* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans` -* Only the name is searched. -* Only full words will be matched e.g. `Han` will not match `Hans` -* Persons matching at least one keyword will be returned (i.e. `OR` search). e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang` -**** +Format: `graph e/EXERCISE_NAME [s/START] [e/END]` + +* Generates a graphical representation of the client’s progress +* If `START` or `END` is not specified, it will default to the current month +* Date format of `[s/START]`, `[e/END]` is `DD-MM-YYYY` +* This command can only be used while viewing a client (ie. right after `view-c` is used) Examples: -* `find John` + -Returns `john` and `John Doe` -* `find Betsy Tim John` + -Returns any person having names `Betsy`, `Tim`, or `John` +* `graph e/Push Ups` +** Shows a graph of Ming Liang’s Push Ups progress over the current month -// tag::delete[] -=== Deleting a person : `delete` +=== View help: `help` -Deletes the specified person from the address book. + -Format: `delete INDEX` +Opens a window with the link to the User Guide. `Currently in v1.3` +Lists all available commands and a short description of what they do. Specify the command for more detailed explanation. `Coming in v1.4` -**** -* Deletes the person at the specified `INDEX`. -* The index refers to the index number shown in the displayed person list. -* The index *must be a positive integer* 1, 2, 3, ... -**** +Format: `help [c/COMMAND]` Examples: -* `list` + -`delete 2` + -Deletes the 2nd person in the address book. -* `find Betsy` + -`delete 1` + -Deletes the 1st person in the results of the `find` command. +* `help` +** Lists all commands +* `help add-c` +** Shows a detailed explanation of the `add-c` command + +=== List all clients: `list-c` -// end::delete[] -=== Clearing all entries : `clear` +Shows all clients currently entered in this program. -Clears all entries from the address book. + -Format: `clear` +* Note that this is the default view when you first launch FitBiz -=== Exiting the program : `exit` +Format: `list-c` -Exits the program. + -Format: `exit` +=== View a client profile: `view-c` -=== Saving the data +Shows all available information of the client at the specified index. This also displays all the exercises recorded for the client as well as their personal bests for said exercises. -Address book data are saved in the hard disk automatically after any command that changes the data. + -There is no need to save manually. +Format: `view-c INDEX` -// tag::dataencryption[] -=== Encrypting data files `[coming in v2.0]` +* `INDEX` refers to the index number shown in the displayed client list +* `INDEX` must be a positive integer (ie. 1, 2, 3, ...) + +Examples: + +* `view-c 3` +** Shows all information about the 3rd client +* `view-c 45` +** Shows all information about the 45th client + +=== Schedule trainings for a client: `schedule` + +Assigns weekly schedule timings to a client. The schedule will be displayed on the right panel of FitBiz, with the timings as well as the client's name. This command can assign multiple schedules to a client at once, by adding more arguments following the command. + +Format: `schedule INDEX day/DAY st/STARTTIME et/ENDTIME` + +* `INDEX` refers to the index number shown on the displayed client list +* `INDEX` must be a positive integer(ie. 1, 2, 3, ...) +* `INDEX` must be for an existing client index number +* `DAY` must be any one of the following values: +** MON +** TUE +** WED +** THU +** FRI +** SAT +** SUN +* `DAY` is not case-sensitive + +Examples: + +* `schedule 1 day/mon st/1100 et/1200` +** Adds to the 1st client a schedule for training from 11:00am to 12:00pm on Monday + + +=== View schedule for the day/week: `view-s` [Coming in v2.0] + +Shows the schedule for today or the time specified. + +Format: `view-s TYPE` + +* `TYPE` must be either `today`, `week` or `month` + +Examples: -_{explain how the user can enable/disable data encryption}_ -// end::dataencryption[] +* `view schedule today` +** Shows the schedule for today +* `view schedule week` +** Shows the schedule of the current week == FAQ *Q*: How do I transfer my data to another Computer? + -*A*: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous Address Book folder. +*A*: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous FitBiz folder. == Command Summary -* *Add* `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` + -e.g. `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague` -* *Clear* : `clear` -* *Delete* : `delete INDEX` + -e.g. `delete 3` -* *Edit* : `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]...` + -e.g. `edit 2 n/James Lee e/jameslee@example.com` -* *Find* : `find KEYWORD [MORE_KEYWORDS]` + -e.g. `find James Jake` -* *List* : `list` -* *Help* : `help` +=== General Commands + +[width="100%",cols="20%,<30%",options="header",] +|======================================================================= +|Command | Summary +|`export INDEX`| Exports client's training record to a CSV file. +|`help`| Shows all available commands and their description. +|`view-s TYPE`| Shows schedule for today or time specified. +|======================================================================= + +=== Client Commands + +[width="100%",cols="20%,<30%",options="header",] +|======================================================================= +|Command | Summary +|`add-c n/NAME p/PHONE_NUMBER e/EMAIL [t/TAG]…`| Adds a new client into FitBiz. +|`delete-c INDEX`| Deletes a client and its associated exercises. +|`edit-c INDEX [n/NAME] [p/PHONE] [e/EMAIL] [t/TAG]…​`| Edits an existing client. +|`filter-c KEYWORD [MORE_KEYWORDS]`| Filters a client based on specified keywords. +|`list-c`| Shows the list of clients in FitBiz. +|`view-c INDEX`| Shows detailed information of a client. +|`schedule INDEX [day/DAY] [st/STARTTIME] [et/ENDTIME]`| Assigns a schedule to a client. +|======================================================================= + +=== Exercise Commands + +[width="100%",cols="20%,<30%",options="header",] +|======================================================================= +|Command | Summary +|`add-e n/EXERCISE_NAME d/DATE ew/WEIGHT reps/REPS sets/SETS`| Adds a new exercise to a client. +|`delete-e INDEX`| Deletes an exercise in the exercise list of the client. +|`graph e/Push Ups`| Shows a graph of the exercise progress done by a client. +|======================================================================= diff --git a/docs/UsingTravis.adoc b/docs/UsingTravis.adoc index 887c0b09068..cd94166ae65 100644 --- a/docs/UsingTravis.adoc +++ b/docs/UsingTravis.adoc @@ -67,10 +67,10 @@ image:travis_build.png[Travis build] . Ensure that you have followed the steps above to set up Travis CI. . On GitHub, create a new user account and give this account collaborator and admin access to the repo. + - Using this account, generate a personal access token https://github.com/settings/tokens/new[here]. + Using this account, generate a cliental access token https://github.com/settings/tokens/new[here]. + [NOTE] -Personal access tokens are like passwords so make sure you keep them secret! If the personal access token is leaked, please delete it and generate a new one. +Cliental access tokens are like passwords so make sure you keep them secret! If the cliental access token is leaked, please delete it and generate a new one. + [NOTE] We use a new user account to generate the token for team projects to prevent team members from gaining access to other team members' repos. + @@ -79,7 +79,7 @@ If you are the only one with write access to the repo, you can use your own acco -- * Add a description for the token. (e.g. `Travis CI - deploy docs to gh-pages`) * Check the `public_repo` checkbox. -* Click `Generate Token` and copy your new personal access token. +* Click `Generate Token` and copy your new cliental access token. -- We will use this token to grant Travis access to the repo. + @@ -93,14 +93,14 @@ image:flick_repository_switch.png[Activate the switch] + -- * name: `GITHUB_TOKEN` -* value: personal access token copied in step 1 +* value: cliental access token copied in step 1 * Display value in build log: `OFF` -- image:travis_add_token.png[Travis add token] + [NOTE] *Make sure you set `Display value in build log` to `OFF`.* + -Otherwise, other people will be able to see the personal access token and thus have access this repo. + +Otherwise, other people will be able to see the cliental access token and thus have access this repo. + Similarly, make sure you *do not print `$GITHUB_TOKEN` to the logs* in Travis scripts as the logs are viewable by the public. . Now, whenever there's a new commit to master branch, Travis will push the latest documentation to gh-pages branch. diff --git a/docs/diagrams/AddExerciseCommandSequenceDiagram.puml b/docs/diagrams/AddExerciseCommandSequenceDiagram.puml new file mode 100644 index 00000000000..40df9f59d7e --- /dev/null +++ b/docs/diagrams/AddExerciseCommandSequenceDiagram.puml @@ -0,0 +1,47 @@ +@startuml AddExerciseCommandSequenceDiagram +!include style.puml + +box Logic LOGIC_COLOR_T1 + Participant ":AddExerciseCommand" as AddExerciseCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 + Participant ":Model" as model MODEL_COLOR + Participant "clientToEdit:Client" as client MODEL_COLOR + Participant "editedClient:Client" as client2 MODEL_COLOR +end box + +[-[LOGIC_COLOR]> AddExerciseCommand : execute(model) + +activate AddExerciseCommand LOGIC_COLOR +AddExerciseCommand -[LOGIC_COLOR]> model : hasClientInView() + +activate model MODEL_COLOR +model --[MODEL_COLOR]> AddExerciseCommand : True +deactivate model + +AddExerciseCommand -[LOGIC_COLOR]> model : getClientInView() +activate model MODEL_COLOR +AddExerciseCommand <[MODEL_COLOR]-- model : clientToEdit +deactivate model + +AddExerciseCommand -[LOGIC_COLOR]> client : getExerciseList() +activate client MODEL_COLOR +AddExerciseCommand <[MODEL_COLOR]-- client : exerciseList +deactivate client + +activate model MODEL_COLOR +ref over model, client + addToSort +end ref + +AddExerciseCommand -[LOGIC_COLOR]> client2 ** +activate client2 MODEL_COLOR + +client2 --[MODEL_COLOR]> AddExerciseCommand : editedClient +deactivate client2 + +[<[LOGIC_COLOR]-- AddExerciseCommand : CommandResult +deactivate AddExerciseCommand + +@enduml diff --git a/docs/diagrams/AddExerciseCommandSequenceDiagramPart2.puml b/docs/diagrams/AddExerciseCommandSequenceDiagramPart2.puml new file mode 100644 index 00000000000..b13f07eea71 --- /dev/null +++ b/docs/diagrams/AddExerciseCommandSequenceDiagramPart2.puml @@ -0,0 +1,50 @@ +@startuml AddExerciseCommandSequenceDiagramPart2 +!include style.puml + +box Model MODEL_COLOR_T1 + Participant ":UniqueExerciseList" as exerciseList MODEL_COLOR + Participant "curr:Exercise" as currExercise MODEL_COLOR + Participant "toAdd:Exercise" as toAddExercise MODEL_COLOR + Participant "curr:ExerciseDate" as currExerciseDate MODEL_COLOR + Participant "toAdd:ExerciseDate" as toAddExerciseDate MODEL_COLOR + Participant "curr:ExerciseDate" as currExerciseDate MODEL_COLOR + Participant "toAdd:ExerciseDate" as toAddExerciseDate MODEL_COLOR +end box + +group addToSort + [-> exerciseList: addToSorted(toAdd) + activate exerciseList MODEL_COLOR + + loop for all exercises in internalList + + exerciseList -[MODEL_COLOR]> currExercise :getExerciseDate() + activate currExercise MODEL_COLOR + + currExercise -[MODEL_COLOR]> currExerciseDate :getExerciseDate() + activate currExerciseDate MODEL_COLOR + + currExerciseDate --[MODEL_COLOR]> currExercise : exerciseDate for curr + deactivate currExerciseDate + + currExercise --[MODEL_COLOR]> exerciseList : exerciseDate for curr + deactivate currExercise + + exerciseList -[MODEL_COLOR]> toAddExercise : getExerciseDate() + activate toAddExercise MODEL_COLOR + + toAddExercise -[MODEL_COLOR]> toAddExerciseDate : getExerciseDate() + activate toAddExerciseDate MODEL_COLOR + + toAddExerciseDate --[MODEL_COLOR]> toAddExercise : exerciseDate for toAdd + deactivate toAddExerciseDate + + toAddExercise --[MODEL_COLOR]> exerciseList : exerciseDate for toAdd + deactivate toAddExercise + + end + + [<-- exerciseList: + deactivate exerciseList + +end +@enduml diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml index d1e2ae93675..d2ece116c74 100644 --- a/docs/diagrams/ArchitectureSequenceDiagram.puml +++ b/docs/diagrams/ArchitectureSequenceDiagram.puml @@ -13,7 +13,7 @@ activate ui UI_COLOR ui -[UI_COLOR]> logic : execute("delete 1") activate logic LOGIC_COLOR -logic -[LOGIC_COLOR]> model : deletePerson(p) +logic -[LOGIC_COLOR]> model : deleteClient(p) activate model MODEL_COLOR model -[MODEL_COLOR]-> logic diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml index 7790472da52..503df74808f 100644 --- a/docs/diagrams/BetterModelClassDiagram.puml +++ b/docs/diagrams/BetterModelClassDiagram.puml @@ -4,18 +4,18 @@ skinparam arrowThickness 1.1 skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR -AddressBook *-right-> "1" UniquePersonList +AddressBook *-right-> "1" UniqueClientList AddressBook *-right-> "1" UniqueTagList -UniqueTagList -[hidden]down- UniquePersonList -UniqueTagList -[hidden]down- UniquePersonList +UniqueTagList -[hidden]down- UniqueClientList +UniqueTagList -[hidden]down- UniqueClientList UniqueTagList *-right-> "*" Tag -UniquePersonList o-right-> Person +UniqueClientList o-right-> Client -Person o-up-> "*" Tag +Client o-up-> "*" Tag -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address +Client *--> Name +Client *--> Phone +Client *--> Email +Client *--> Address @enduml diff --git a/docs/diagrams/ClientExerciseStorageClassDiagram.puml b/docs/diagrams/ClientExerciseStorageClassDiagram.puml new file mode 100644 index 00000000000..94c573f365b --- /dev/null +++ b/docs/diagrams/ClientExerciseStorageClassDiagram.puml @@ -0,0 +1,10 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor STORAGE_COLOR +skinparam classBackgroundColor STORAGE_COLOR + +JsonSerializableFitBizStorage "1" *-right-> "*" JsonAdaptedClient +JsonAdaptedClient "1" *-right-> "*" JsonAdaptedExercise + +@enduml diff --git a/docs/diagrams/CommandAutocompleteClassDiagram.puml b/docs/diagrams/CommandAutocompleteClassDiagram.puml new file mode 100644 index 00000000000..eba66f2ed9c --- /dev/null +++ b/docs/diagrams/CommandAutocompleteClassDiagram.puml @@ -0,0 +1,13 @@ +@startuml +!include style.puml + +Package { + Class CommandBox UI_COLOR + Class AutoComplete LOGIC_COLOR + Class Trie MODEL_COLOR_T1 +} + +CommandBox "1" *-right-> AutoComplete +AutoComplete "1" *-right-> Trie + +@enduml diff --git a/docs/diagrams/CommandHistoryClassDiagram.puml b/docs/diagrams/CommandHistoryClassDiagram.puml new file mode 100644 index 00000000000..da623e430cc --- /dev/null +++ b/docs/diagrams/CommandHistoryClassDiagram.puml @@ -0,0 +1,15 @@ +@startuml +!include style.puml + +Package { + Class CommandBox UI_COLOR + Class CommandHistory LOGIC_COLOR + Class CommandHistoryStorage STORAGE_COLOR + Class CommandHistoryState MODEL_COLOR +} + +CommandBox "1" *--> CommandHistory +CommandHistory "1" *--> CommandHistoryStorage +CommandHistory "1" *--> CommandHistoryState + +@enduml diff --git a/docs/diagrams/CommandHistorySequenceDiagram.puml b/docs/diagrams/CommandHistorySequenceDiagram.puml new file mode 100644 index 00000000000..1411d9070d3 --- /dev/null +++ b/docs/diagrams/CommandHistorySequenceDiagram.puml @@ -0,0 +1,43 @@ +@startuml +!include style.puml + +Actor User as user USER_COLOR +Participant ":commandBox" as ui UI_COLOR +Participant ":commandHistory" as logic LOGIC_COLOR +Participant ":commandHistoryState" as model MODEL_COLOR +Participant ":commandHistoryStorage" as storage STORAGE_COLOR + +user -[USER_COLOR]> ui : "list-c" +activate ui UI_COLOR + +ui -[UI_COLOR]> logic : addToHistory("list-c") +activate logic LOGIC_COLOR + +logic -[LOGIC_COLOR]> model : add("list-c") +activate model MODEL_COLOR + +model -[MODEL_COLOR]-> logic +deactivate model + +logic -[LOGIC_COLOR]> model : getCurrentState() +activate model MODEL_COLOR + +model -[MODEL_COLOR]-> logic : ArrayList history +deactivate model + +logic -[LOGIC_COLOR]> storage : saveToStorage(history) +activate storage STORAGE_COLOR + +storage -[STORAGE_COLOR]> storage : Save to file +activate storage STORAGE_COLOR_T1 +deactivate storage + +storage --[STORAGE_COLOR]> logic +deactivate storage + +logic --[LOGIC_COLOR]> ui +deactivate logic + +ui--[UI_COLOR]> user +deactivate ui +@enduml diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml index 1dc2311b245..038ffb3f0ac 100644 --- a/docs/diagrams/DeleteSequenceDiagram.puml +++ b/docs/diagrams/DeleteSequenceDiagram.puml @@ -48,7 +48,7 @@ deactivate AddressBookParser LogicManager -> DeleteCommand : execute() activate DeleteCommand -DeleteCommand -> Model : deletePerson(1) +DeleteCommand -> Model : deleteClient(1) activate Model Model --> DeleteCommand diff --git a/docs/diagrams/ExerciseClassDiagram.puml b/docs/diagrams/ExerciseClassDiagram.puml new file mode 100644 index 00000000000..929a0b3d316 --- /dev/null +++ b/docs/diagrams/ExerciseClassDiagram.puml @@ -0,0 +1,15 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor MODEL_COLOR +skinparam classBackgroundColor MODEL_COLOR + +Client "1" *--> "1" UniqueExerciseList +UniqueExerciseList "1" *--> "*" Exercise + +Exercise "1" *--> "1" ExerciseName +Exercise "1" *--> "1" ExerciseReps +Exercise "1" *--> "1" ExerciseSets +Exercise "1" *--> "1" ExerciseDate +Exercise "1" *--> "1" ExerciseWeight +@enduml diff --git a/docs/diagrams/ExerciseStorageClassDiagram.puml b/docs/diagrams/ExerciseStorageClassDiagram.puml new file mode 100644 index 00000000000..93c1f4ddd93 --- /dev/null +++ b/docs/diagrams/ExerciseStorageClassDiagram.puml @@ -0,0 +1,24 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor STORAGE_COLOR +skinparam classBackgroundColor STORAGE_COLOR + +Interface Storage <> +Interface UserPrefsStorage <> +Interface AddressBookStorage <> + +Class StorageManager +Class JsonUserPrefsStorage +Class JsonAddressBookStorage + +StorageManager .left.|> Storage +StorageManager o-right-> UserPrefsStorage +StorageManager o--> AddressBookStorage + +JsonUserPrefsStorage .left.|> UserPrefsStorage +JsonAddressBookStorage .left.|> AddressBookStorage +JsonAddressBookStorage .down.> JsonSerializableAddressBookStorage +JsonSerializableAddressBookStorage .right.> JsonSerializableClient +JsonSerializableClient .right.> JsonAdaptedTag +@enduml diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index e85a00d4107..2d4fc491545 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -15,13 +15,13 @@ Class ModelManager Class UserPrefs Class ReadOnlyUserPrefs -Package Person { -Class Person +Package Client { +Class Client Class Address Class Email Class Name Class Phone -Class UniquePersonList +Class UniqueClientList } Package Tag { @@ -40,17 +40,17 @@ ModelManager o--> "1" AddressBook ModelManager o-left-> "1" UserPrefs UserPrefs .up.|> ReadOnlyUserPrefs -AddressBook *--> "1" UniquePersonList -UniquePersonList o--> "*" Person -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address -Person *--> "*" Tag +AddressBook *--> "1" UniqueClientList +UniqueClientList o--> "*" Client +Client *--> Name +Client *--> Phone +Client *--> Email +Client *--> Address +Client *--> "*" Tag Name -[hidden]right-> Phone Phone -[hidden]right-> Address Address -[hidden]right-> Email -ModelManager -->"1" Person : filtered list +ModelManager -->"1" Client : filtered list @enduml diff --git a/docs/diagrams/PersonalBestClassDiagram.puml b/docs/diagrams/PersonalBestClassDiagram.puml new file mode 100644 index 00000000000..cfdca46b817 --- /dev/null +++ b/docs/diagrams/PersonalBestClassDiagram.puml @@ -0,0 +1,18 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor MODEL_COLOR +skinparam classBackgroundColor MODEL_COLOR + +Client *-down-> "1" PersonalBest +Client *-up-> "1" UniqueExerciseList + +PersonalBestFinder -left-> PersonalBest : sets > +PersonalBestFinder -left-> "1" Client +PersonalBestFinder -left-> "1" UniqueExerciseList + +ViewCommand -up-> "1" PersonalBestFinder +AddExerciseCommand -up-> "1" PersonalBestFinder +DeleteExerciseCommand -left-> "1" PersonalBestFinder + +@enduml diff --git a/docs/diagrams/PersonalBestSequenceDiagram.puml b/docs/diagrams/PersonalBestSequenceDiagram.puml new file mode 100644 index 00000000000..fcc6f6e159b --- /dev/null +++ b/docs/diagrams/PersonalBestSequenceDiagram.puml @@ -0,0 +1,33 @@ +@startuml +!include style.puml + +Participant ":ViewCommand" as ui UI_COLOR +Participant ":PersonalBestFinder" as logic LOGIC_COLOR +Participant ":Client" as model MODEL_COLOR +Participant ":PersonalBest" as storage STORAGE_COLOR + +-[USER_COLOR]> ui : execute(model) +activate ui UI_COLOR + +ui -[UI_COLOR]> logic : generateAndSetPersonalBest(client) +activate logic LOGIC_COLOR + +logic -[LOGIC_COLOR]> model : getExerciseList() +activate model MODEL_COLOR + +model -[MODEL_COLOR]-> logic : exerciseList +deactivate model + +logic -[LOGIC_COLOR]> storage : setPersonalBest(values) +activate storage STORAGE_COLOR + +storage --[STORAGE_COLOR]> logic +deactivate storage + +logic --[LOGIC_COLOR]> ui +deactivate logic + +[<[LOGIC_COLOR]-- ui : CommandResult + +deactivate ui +@enduml diff --git a/docs/diagrams/ScheduleClassDiagram.puml b/docs/diagrams/ScheduleClassDiagram.puml new file mode 100644 index 00000000000..909d9429d2e --- /dev/null +++ b/docs/diagrams/ScheduleClassDiagram.puml @@ -0,0 +1,15 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor MODEL_COLOR +skinparam classBackgroundColor MODEL_COLOR + +ScheduleList *--> "*" Schedule + +Schedule *--> "1" Day +Schedule *--> "1" StartTime +Schedule *--> "1" EndTime + +StartTime --|> Time +EndTime --|> Time +@enduml diff --git a/docs/diagrams/ScheduleSequenceDiagram.puml b/docs/diagrams/ScheduleSequenceDiagram.puml new file mode 100644 index 00000000000..4f0609f1ffc --- /dev/null +++ b/docs/diagrams/ScheduleSequenceDiagram.puml @@ -0,0 +1,72 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":ScheduleCommandParser" as ScheduleCommandParser LOGIC_COLOR +participant "s:ScheduleCommand" as ScheduleCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute\n("schedule 1 day/mon st/1100 et/1200") +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand\n("schedule 1 day/mon st/1100 et/1200") +activate AddressBookParser + +create ScheduleCommandParser +AddressBookParser -> ScheduleCommandParser +activate ScheduleCommandParser + +ScheduleCommandParser --> AddressBookParser +deactivate ScheduleCommandParser + +AddressBookParser -> ScheduleCommandParser : parse("day/mon\nst/1100 et/1200") +activate ScheduleCommandParser + +create ScheduleCommand +ScheduleCommandParser -> ScheduleCommand +activate ScheduleCommand + +ScheduleCommand --> ScheduleCommandParser : s +deactivate ScheduleCommand + +ScheduleCommandParser --> AddressBookParser : s +deactivate ScheduleCommandParser + +AddressBookParser --> LogicManager : s +deactivate AddressBookParser + +LogicManager -> ScheduleCommand : execute() +activate ScheduleCommand + +ScheduleCommand -> Model : setClient() +activate Model + +Model --> ScheduleCommand: +deactivate Model + +ScheduleCommand -> Model: updateFilteredClientList() +activate Model + +Model --> ScheduleCommand +deactivate Model + +create CommandResult +ScheduleCommand -> CommandResult +activate CommandResult + +CommandResult --> ScheduleCommand +deactivate CommandResult + +ScheduleCommand --> LogicManager : result +deactivate ScheduleCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index 6adb2e156bf..93c1f4ddd93 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -19,6 +19,6 @@ StorageManager o--> AddressBookStorage JsonUserPrefsStorage .left.|> UserPrefsStorage JsonAddressBookStorage .left.|> AddressBookStorage JsonAddressBookStorage .down.> JsonSerializableAddressBookStorage -JsonSerializableAddressBookStorage .right.> JsonSerializablePerson -JsonSerializablePerson .right.> JsonAdaptedTag +JsonSerializableAddressBookStorage .right.> JsonSerializableClient +JsonSerializableClient .right.> JsonAdaptedTag @enduml diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml index 92746f9fcf7..711a76d5720 100644 --- a/docs/diagrams/UiClassDiagram.puml +++ b/docs/diagrams/UiClassDiagram.puml @@ -11,8 +11,8 @@ Class UiManager Class MainWindow Class HelpWindow Class ResultDisplay -Class PersonListPanel -Class PersonCard +Class ClientListPanel +Class ClientCard Class StatusBarFooter Class CommandBox } @@ -33,25 +33,25 @@ UiManager -down-> MainWindow MainWindow --> HelpWindow MainWindow *-down-> CommandBox MainWindow *-down-> ResultDisplay -MainWindow *-down-> PersonListPanel +MainWindow *-down-> ClientListPanel MainWindow *-down-> StatusBarFooter -PersonListPanel -down-> PersonCard +ClientListPanel -down-> ClientCard MainWindow -left-|> UiPart ResultDisplay --|> UiPart CommandBox --|> UiPart -PersonListPanel --|> UiPart -PersonCard --|> UiPart +ClientListPanel --|> UiPart +ClientCard --|> UiPart StatusBarFooter --|> UiPart HelpWindow -down-|> UiPart -PersonCard ..> Model +ClientCard ..> Model UiManager -right-> Logic MainWindow -left-> Logic -PersonListPanel -[hidden]left- HelpWindow +ClientListPanel -[hidden]left- HelpWindow HelpWindow -[hidden]left- CommandBox CommandBox -[hidden]left- ResultDisplay ResultDisplay -[hidden]left- StatusBarFooter diff --git a/docs/diagrams/tracing/LogicSequenceDiagram.puml b/docs/diagrams/tracing/LogicSequenceDiagram.puml index fdcbe1c0ccc..718f8a47d13 100644 --- a/docs/diagrams/tracing/LogicSequenceDiagram.puml +++ b/docs/diagrams/tracing/LogicSequenceDiagram.puml @@ -13,7 +13,7 @@ create ecp abp -> ecp abp -> ecp ++: parse(arguments) create ec -ecp -> ec ++: index, editPersonDescriptor +ecp -> ec ++: index, editClientDescriptor ec --> ecp -- ecp --> abp --: command abp --> logic --: command diff --git a/docs/draft/UserGuideDraft.md b/docs/draft/UserGuideDraft.md new file mode 100644 index 00000000000..dde43504daf --- /dev/null +++ b/docs/draft/UserGuideDraft.md @@ -0,0 +1,589 @@ + +# FitBiz User Guide + +- [1. Introduction](#1-introduction) +- [2. Quick Start](#2-quick-start) +- [3. Features](#3-features) + - [3.1. View help: `help`](#31-view-help-help) + - [3.2. Add a new client profile: `add client`](#32-add-a-new-client-profile-add-client) + - [3.3. View a client profile: `view client`](#33-view-a-client-profile-view-client) + - [3.4. Edit a client’s profile: `edit client`](#34-edit-a-clients-profile-edit-client) + - [3.5. Delete a client: `delete client`](#35-delete-a-client-delete-client) + - [3.6. List all clients: `list`](#36-list-all-clients-list) + - [3.7. Display a list of predefined exercises: `view exercise`](#37-display-a-list-of-predefined-exercises-view-exercise) + - [3.8. Add a new exercise: `add exercise template`](#38-add-a-new-exercise-add-exercise-template) + - [3.9. Start a timer: `time`](#39-start-a-timer-time) + - [3.10. Add a new routine template: `add routine template`](#310-add-a-new-routine-template-add-routine-template) + - [3.11. View the list of routine template: `view routine template`](#311-view-the-list-of-routine-template-view-routine-template) + - [3.12. Edit a routine template: `edit routine template`](#312-edit-a-routine-template-edit-routine-template) + - [3.13. Tag a client: `tag`](#313-tag-a-client-tag) + - [3.14. Sort clients based on attribute: `sort clients`](#314-sort-clients-based-on-attribute-sort-clients) + - [3.15. List routines: `list routines`](#315-list-routines-list-routines) + - [3.16. Check total earnings: `earnings`](#316-check-total-earnings-earnings) + - [3.18. Track payment date: `view payment`](#318-track-payment-date-view-payment) + - [3.19. View cliental best: `view pb`](#319-view-cliental-best-view-pb) + - [3.20. View schedule for the day/week: `view schedule`](#320-view-schedule-for-the-dayweek-view-schedule) + - [3.21. View client summary: `show summary`](#321-view-client-summary-show-summary) + - [3.22. Export as CSV: `export`](#322-export-as-csv-export) + - [3.23. Add a new food template: `add food template`](#323-add-a-new-food-template-add-food-template) + - [3.24. Edit an existing food template: `edit food template`](#324-edit-an-existing-food-template-edit-food-template) + - [3.25. Delete food item: `delete food template`](#325-delete-food-item-delete-food-template) + - [3.26. Display visualisations of training progress: `training graph`](#326-display-visualisations-of-training-progress-training-graph) + - [3.27. List all gyms: `list gyms`](#327-list-all-gyms-list-gyms) + - [3.28. Find out information about a gym: `view gym`](#328-find-out-information-about-a-gym-view-gym) + - [3.29. Make meal plans: `meal`](#329-make-meal-plans-meal) + - [3.28. Compares the daily and target caloric intake: `calories`](#328-compares-the-daily-and-target-caloric-intake-calories) + - [3.29. Show Competitors: `find competitor`](#329-show-competitors-find-competitor) + - [3.30. Find the nearest gyms: `find gym`](#330-find-the-nearest-gyms-find-gym) + - [3.31. Booking a facility: `book`](#331-booking-a-facility-book) + - [3.32. Add photos to client’s photo album: `add photo`](#332-add-photos-to-clients-photo-album-add-photo) + - [3.33. View client photo album: `view photo`](#333-view-client-photo-album-view-photo) + +## 1. Introduction + +FitBiz is for fitness coaches who are managing multiple clients and prefer to use a desktop app for managing their clients. More importantly, FitBiz is optimized for those who prefer to work with Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, FitBiz can get your client management and tracking tasks done faster than traditional GUI apps. Interested? Jump to the Section 2, “Quick Start” to get started. Enjoy! + +## 2. Quick Start + +1. Ensure you have Java 11 or above installed in your Computer. +2. Download the latest FitBiz.jar here. +3. Copy the file to the folder you want to use as the home folder for your Fitness Manager. +4. Double-click the file to start the app. The GUI should appear in a few seconds. +5. Type the command in the command box and press Enter to execute it. +e.g. typing help and pressing Enter will open the help window. +6. Some example commands you can try: + - `list` : lists all clients + - `add client n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : adds a contact named John Doe to the Address Book. + - `exit` : exits the app +7. Refer to Section 3, “Features” for details of each command. + +## 3. Features + +Format of commands: + +- Words in `UPPER_SNAKE_CASE` are the parameters to be supplied by the user e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe` +- Items in square brackets are optional e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe` +- Items with `…` after them can be used multiple times including zero times e.g. `[t/TAG]…` can be used as (i.e. 0 times), `t/friend`, `t/friend t/family` etc. +- Parameters can be in any order e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. + +### 3.1. View help: `help` + +Lists all available commands and a short description of what they do. Specify the command for more detailed explanation. + +Format: `help [c/COMMAND]` + +Examples: + +- `help` + - Lists all commands +- `help add client` + - Shows a detailed explanation of the `add client` command + +### 3.2. Add a new client profile: `add client` + +Initialises and adds a new client profile. + +Format: `add client n/NAME` + +- `n/NAME` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` + +Examples: + +- `add client n/Ming Liang` + - Adds a new client: Ming Liang +- `add client n/Low Tah Kiow, John` + - Adds a new client: Low Tah Kiow, John + +### 3.3. View a client profile: `view client` + +Shows all available information of the client. + +Format: `view client n/NAME` + +- `n/NAME` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` + +Examples: + +- `view client n/Ming Liang` + - Shows information about Ming Liang +- `view client n/Low Tah Kiow, John` + - Shows information about Low Tah Kiow, John + +### 3.4. Edit a client’s profile: `edit client` + +Updates the client’s cliental details by specifying the attribute and the new value. + +Format: `edit client n/NAME [a/ATTRIBUTE v/VALUE]...` + +- `n/NAME` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` +- `[a/ATTRIBUTE]` has to be a valid attribute for the client. +- `[v/VALUE]` has to be of matching type to the attribute of the client + +Examples: + +- `edit client n/Ming Liang a/age v/60 a/gender v/male` + - Sets Ming Liang’s age to 60 and gender to male. + +### 3.5. Delete a client: `delete client` + +Deletes a client from the program. + +Format: `delete n/NAME` + +- `n/NAME` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` + +Examples: + +- `delete n/Ming Liang` + - Removes Ming Liang’s profile. + +### 3.6. List all clients: `list` + +Shows all clients currently entered in this program. + +Format: `list` + +### 3.7. Display a list of predefined exercises: `view exercise` + +Displays a list of exercises available in the program. Specify the muscle group(s) to list only exercises that target that muscle group(s). + +Format: `view exercise [m/MUSCLE]...` + +Examples: + +- `view exercise` + - Shows a list of all exercises and their information stored in the program +- `view exercise m/abdomens m/chest` + - Shows all exercises that target the abdomens and chest + +### 3.8. Add a new exercise: `add exercise template` + +If the list of predefined exercises are not enough, you may choose to add a new exercise for future use. + +Format: `add exercise template e/EXERCISE_NAME t/TARGET_MUSCLE...` + +- There must be at least one `TARGET_MUSCLE` specified + +Examples: + +- `add exercise template e/Skipping Rope t/Quadriceps t/Calves` + - Adds a new exercise Skipping Rope which targets the Quadricepts and Calves muscle group + +### 3.9. Start a timer: `time` + +Starts a timer which will notify you when it ends. + +Format: `time [h/HOURS] [m/MINUTES] [s/SECONDS]` + +Examples: + +- `time m/4 s/40` + - Starts a timer for 4 minutes and 40 seconds + +### 3.10. Add a new routine template: `add routine template` + +Adds a new routine template with the specified name and exercise templates. + +Format: `add routine template n/NAME_OF_TEMPLATE e/[EXERCISE_TEMPLATES]...` + +- `n/NAME_OF_TEMPLATE` is case insensitive. e.g `back` will match `Back` +- The order of words will matter. e.g `Push Pull` will not match `Pull Push` +- Only exact match will be shown. e.g `Push` will not match `Push Pull` +- `e/EXERCISE_TEMPLATES` must exist in the predefined list of exercise templates + +Example: + +- `add routine template n/Push Pull e/Pull Up e/Bench Press` + - Adds a new routine template with called Push Pull with 2 exercises, Pull Up and Bench Press. + +### 3.11. View the list of routine template: `view routine template` + +Lists all routine templates. + +Format: `view routine template` + +### 3.12. Edit a routine template: `edit routine template` + +Edits a new routine template with the specified name and exercise templates. + +Format: `edit routine template n/NAME_OF_TEMPLATE [a/ATTRIBUTE v/VALUE]...` + +- `n/NAME_OF_TEMPLATE` is case insensitive. e.g `back` will match `Back` +- The order of words will matter. e.g `Push Pull` will not match `Pull Push` +- Only exact match will be shown. e.g `Push` will not match `Push Pull` +- `[a/ATTRIBUTE]` has to be a valid attribute for the routine template +- `[v/VALUE]` has to be of matching type to the attribute of the routine template + +Examples: + +- `edit routine template n/Push Pull a/NAME_OF_TEMPLATE v/Pull Push` + - Renames the routine template called Push Pull to Pull Push + +Example: + +- `add routine template n/Push Pull e/Pull Up e/Bench Press` + - Adds a new routine template with called Push Pull with 2 exercises, Pull Up and Bench Press + +### 3.13. Tag a client: `tag` + +Assigns a tag to a client for ease of grouping and searching. + +Format: `tag c/CLIENT t/TAG` + +Examples: + +- `tag c/Jeffreigh t/Professional` + - The client Jeffreigh is now tagged as "Professional". Future searches for the Professional tag will include Jeffreigh + +### 3.14. Sort clients based on attribute: `sort clients` + +Sorts clients by descending order based on the specified attribute. + +Format: `sort clients a/ATTRIBUTE` + +Examples: + +- `sort clients a/Height` + - returns a sorted list of all clients in descending order + +### 3.15. List routines: `list routines` + +Returns a list of all routines. + +Format: `list routines` + +Examples: + +- `list routines` + - returns a complete list of all routines. + +Sorts clients by descending order based on the specified attribute. + +Format: `sort clients a/ATTRIBUTE` + +Examples: + +- `sort clients a/Height` + - returns a sorted list of all clients in descending order + +### 3.16. Check total earnings: `earnings` + +Shows the total earnings or the specific earnings for a client. + +Format: `earnings [n/NAME] [t/TAG]` + +- If no name is given, total earnings from all clients will be shown +- If a name is given, only earnings from that client is shown +- `[n/NAME]` is case insensitive. e.g hans will match Hans +- The order of words will matter. e.g Hans Ong will not match Ong Hans +- Only exact match will be shown. e.g. Hans will not match Hans Ong + +Examples: + +- `earnings` + - Shows the complete list of clients and total earnings. +- `earnings n/Jane Doe` + - Shows the earnings from client Jane Doe only. + +### 3.18. Track payment date: `view payment` + +Shows the list of payment information. + +Format: `view payment d/DETAIL` + +- `d/DETAIL` can be `n/NAME`, `d/DATE` or `m/MONTH` +- `n/NAME`is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` +- `d/DATE` must be in the format `DD/MM/YYYY` +- `m/MONTH` must be spelt in full e.g. `january` + +Examples: + +- `view payment n/tom` + - Shows a payment details of clients name Tom +- `view payment d/12/12/2020` + - Shows all payment details on 12 December 2020 +- `view payment m/august` + - Shows all payment details in August + +### 3.19. View cliental best: `view pb` + +Displays the cliental best of all exercises of a client. + +Format: `view pb n/NAME` + +- `n/NAME` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` + +Example: + +- `view pb n/Raymond tan` + - Shows the best record done for all exercises done by Raymond Tan + +### 3.20. View schedule for the day/week: `view schedule` + +Shows the schedule for today or the time specified. + +Format: `view schedule t/TYPE` + +- `t/TYPE` can be `d/DATE`, `week` or `month` +- `d/DATE` must be of the format `DD/MM/YYYY` +- to view schedule for today, leave `t/TYPE` blank + +Examples: + +- `view schedule` + - Shows the schedule for today +- `view schedule t/week` + - Shows the schedule of the current week + +### 3.21. View client summary: `show summary` + +Shows all the trainings done by the client. + +Format: `view summary n/NAME` + +- `n/NAME` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` + +Example: + +- `view summary n/Timothy Lee` + - Shows all the training records of Timothy Lee + +### 3.22. Export as CSV: `export` + +Exports client's training record to a CSV file. + +Format: `export n/NAME` + +- `n/NAME` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` + +Example: + +- `export n/Lucy Liu` + - Exports training records of Lucy Liu as a CSV file + +### 3.23. Add a new food template: `add food template` + +Adds a new food template with the specified name and calories per serving. + +Format: `add food n/NAME_OF_FOOD c/CALORIES` + +- `n/NAME_OF_FOOD` is case insensitive. e.g `laksa` will match `Laksa` +- The order of words will matter. e.g `Nasi Lemak` will not match `Lemak Nasi` +- Only exact match will be shown. e.g `Nasi` will not match `Nasi Lemak` +- `c/CALORIES` is the calories per serving + +Example: + +- `add food template n/Chilli Crab c/100` + - Adds a new food template with food name Chilli Crab and 100 calories per serving. + +### 3.24. Edit an existing food template: `edit food template` + +Edits an existing food template. + +Format: `edit food template n/NAME_OF_FOOD [a/ATTRIBUTE v/VALUE]...` + +- `n/NAME_OF_FOOD` is case insensitive. e.g `laksa` will match `Laksa` +- The order of words will matter. e.g `Nasi Lemak` will not match `Lemak Nasi` +- Only exact match will be shown. e.g `Nasi` will not match `Nasi Lemak` +- `[a/ATTRIBUTE]` has to be a valid attribute for the food +- `[v/VALUE]` has to be of matching type to the attribute of the food + +Example: + +- `edit n/Chilli Crab a/CALORIES v/200` + - Edits the calories per serving for Chilli Crab to be 200g per serving. + +### 3.25. Delete food item: `delete food template` + +Deletes an existing food template. + +Format: `delete food template n/NAME_OF_FOOD` + +- `n/NAME_OF_FOOD` is case insensitive. e.g `laksa` will match `Laksa` +- The order of words will matter. e.g `Nasi Lemak` will not match `Lemak Nasi` +- Only exact match will be shown. e.g `Nasi` will not match `Nasi Lemak` +- `[a/ATTRIBUTE]` has to be a valid attribute for the food. + +Examples: + +- `delete food template n/Chilli Crab` + - Removes food template for Chilli Crab. + +### 3.26. Display visualisations of training progress: `training graph` + +Shows visualisations of client’s exercise progress. + +Format: `training graph n/NAME a/ATTRIBUTE [s/START] [e/END]` + +- Generates a graphical representation of the client’s progress +- Client is specified by `n/NAME` +- `a/ATTRIBUTE` include client’s weight, workout cliental best, fat percentage etc +- `[s/START]`, `[e/END]` are optional +- Date format of `[s/START]`, `[e/END]` is `DD/MM/YYYY` + +Examples: + +- `training graph n/Ming Liang a/weight` + - Shows a graph of Ming Liang’s weight losing progress since he first started to current date. + +### 3.27. List all gyms: `list gyms` + +Lists all available gyms in Singapore. + +Format: `list gyms` + +### 3.28. Find out information about a gym: `view gym` + +Finds and lists information about a gym, including opening and closing times, popularity etc. + +Format: `view gym g/GYM` + +- `g/GYM` is case insensitive. e.g `clementi gym` will match `Clementi Gym` +- The order of words will matter. e.g `Gym Clementi` will not match `Clementi Gym` +- Only exact match will be shown. e.g. `Jurong` will not match `Jurong East Gym`. + +Example: + +- `view gym g/Jurong East Fitness Club` + - Returns the address, opening and closing times and average occupancy. + +### 3.29. Make meal plans: `meal` + +Stores meal plans into the storage. + +Format: `meal [n/NAME] [l/] [f/FOOD] [c/CALORIES]` + +- Saves the meal into storage for reference and to assign to client. +- Multiple ingredients are separated by `[l/]`. +- Can have multiple `[l/]` for the breakdown of different ingredients in the food. +- `[c/CALORIES]` can be used to calculate client’s daily calories intake automatically. +- `[c/CALORIES]` must be a number. + +Examples: + +- `meal n/Chicken Breast with Brocolli l/f/Chicken breast c/165 calories 1/f/Brocolli c/34 calories` + - Stores meal plan chicken breast with broccoli with the breakdown of calories from chicken breast and broccoli. + +### 3.28. Compares the daily and target caloric intake: `calories` + +Calculates the difference between client’s current calorie intake and expected intake value + +Format: `calories [n/NAME]` + +- `[n/Name]` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` + +Examples: + +- `calories n/Ming Liang` + - Returns Ming Liang’s current calorie intake out of expected calorie intake. + +### 3.29. Show Competitors: `find competitor` + +Shows a list of clients who have the specified competition. + +Format: `find competitors [n/NAME]` + +- Shows a list of clients with the specified competition tagged to their profile. +- `n/[Name]` is case insensitive. e.g hometeamns will match HomeTeamNS +- The order of words will not matter. e.g `Fitness Ironman` will match `Ironman Fitness` +- Only full words will be matched. e.g. `Iron` will not match `Irons` +- Competition matching at least one keyword will be returned. e.g. `Ironman Powerlifting` will return `HomeTeamNS Fitness Ironman 2019, Sheffield 2020 Powerlifting` + +Examples: + +- `find competitors HomeTeamNS Fitness Ironman 2019` + - Shows a list of clients competing for HomeTeamNS Fitness Ironman 2019. +- `find competitors Sheffield 2020 Powerlifting` + - Shows a list of clients competing for Sheffield 2020 Powerlifting. + +### 3.30. Find the nearest gyms: `find gym` + +Finds the nearest gyms to a client according to their address. + +Format: `find gym [n/NAME]` + +- `n/NAME` is case insensitive. e.g `hans` will match `Hans` +- The order of words will matter. e.g `Hans Ong` will not match `Ong Hans` +- Only exact match will be shown. e.g. `Hans` will not match `Hans Ong` +- At most 5 gyms will be shown + +Examples: + +- `find gym n/Kee Ah Siow` + - Finds the nearest gyms to Kee Ah Siow + +### 3.31. Booking a facility: `book` + +Books a fitness facility from a in-built list of available facilities. + +Format: book `[f/FACILITY] [t/TIME] [d/DURATION]` + +- Books the facility specified in `[f/FACILITY]`. The facility needs to be found in the in-built list. Else, an error would occur +- `[f/FACILITY]`, `[t/TIME]`, `[d/DURATION]` must be provided +- Facilities have different operating hours and an error would occur if user book outside the operating hours +- Format for `[t/TIME]` is 24-hour clock +- Format for `[d/DURATION]` is in minutes and should be multiples of 30. Else, an error would occur + +Examples: + +- `book f/Farrer Park Field t/1400 d/60` + - Books Farrer Park Field from 2pm to 3pm +- `book f/Burghley Tennis Centre t/0900 d/120` + - Books Burghley Tennis Centre from 9am to 11am + +### 3.32. Add photos to client’s photo album: `add photo` + +Add photo to a client’s photo album to track physique progress. + +Format: `add photo n/NAME + +- `[n/NAME]` is case insensitive. e.g `hans` will match `Hans` +- If there are 2 people with the same name, enter the `INDEX` of the correct client +- After the client is identified, a file attachment window will appear +- Select the file you want from the file attachment window +- The timestamp of the photo added will be recorded + +Example: + +- `add photo tom` + - Adds photo tommy.png(chosen)to Tom’s photo album +- `add photo Betty` + - Adds photo betty.png(chosen) to Betty Koh’s photo album + +### 3.33. View client photo album: `view photo` + +Shows client's photo in an album format. + +Format: `view photo [n/NAME]` + +- Photos displayed in photo album are sorted by date(Newest to Oldest) +- The search is case insensitive. e.g `hans` will match `Hans` +- The order of the keywords will matter. e.g. `Hans Bo` will not match `Bo Hans` +- Only the name is searched. +- Only full words will be matched e.g. `Han` will not match `Hans` +- Clients matching at least one keyword will be returned (i.e. OR search). e.g. `Hans Bo` will return `Hans Gruber, Bo Yang` +- If there are 2 people identified, enter the `INDEX` of the correct client + +Examples: + +- `view photo Diana` + - Shows photo album of Diana diff --git a/docs/images/AddExerciseCommandSequenceDiagram.png b/docs/images/AddExerciseCommandSequenceDiagram.png new file mode 100644 index 00000000000..f5697e88839 Binary files /dev/null and b/docs/images/AddExerciseCommandSequenceDiagram.png differ diff --git a/docs/images/AddExerciseCommandSequenceDiagramPart2.png b/docs/images/AddExerciseCommandSequenceDiagramPart2.png new file mode 100644 index 00000000000..8183a1e518f Binary files /dev/null and b/docs/images/AddExerciseCommandSequenceDiagramPart2.png differ diff --git a/docs/images/ClientExerciseStorageClassDiagram.png b/docs/images/ClientExerciseStorageClassDiagram.png new file mode 100644 index 00000000000..2808fa0264f Binary files /dev/null and b/docs/images/ClientExerciseStorageClassDiagram.png differ diff --git a/docs/images/CommandAutocompleteClassDiagram.png b/docs/images/CommandAutocompleteClassDiagram.png new file mode 100644 index 00000000000..86428325b29 Binary files /dev/null and b/docs/images/CommandAutocompleteClassDiagram.png differ diff --git a/docs/images/CommandHistoryClassDiagram.png b/docs/images/CommandHistoryClassDiagram.png new file mode 100644 index 00000000000..9e4a8bd318b Binary files /dev/null and b/docs/images/CommandHistoryClassDiagram.png differ diff --git a/docs/images/CommandHistorySequenceDiagram.png b/docs/images/CommandHistorySequenceDiagram.png new file mode 100644 index 00000000000..2f7e09df0c2 Binary files /dev/null and b/docs/images/CommandHistorySequenceDiagram.png differ diff --git a/docs/images/ExerciseClassDiagram.png b/docs/images/ExerciseClassDiagram.png new file mode 100644 index 00000000000..9d144177ef9 Binary files /dev/null and b/docs/images/ExerciseClassDiagram.png differ diff --git a/docs/images/PersonalBestClassDiagram.png b/docs/images/PersonalBestClassDiagram.png new file mode 100644 index 00000000000..933d9e3d259 Binary files /dev/null and b/docs/images/PersonalBestClassDiagram.png differ diff --git a/docs/images/PersonalBestSequenceDiagram.png b/docs/images/PersonalBestSequenceDiagram.png new file mode 100644 index 00000000000..96988c65539 Binary files /dev/null and b/docs/images/PersonalBestSequenceDiagram.png differ diff --git a/docs/images/ScheduleClassDiagram.png b/docs/images/ScheduleClassDiagram.png new file mode 100644 index 00000000000..0807fdca137 Binary files /dev/null and b/docs/images/ScheduleClassDiagram.png differ diff --git a/docs/images/ScheduleSequenceDiagram.png b/docs/images/ScheduleSequenceDiagram.png new file mode 100644 index 00000000000..4c03d78ed44 Binary files /dev/null and b/docs/images/ScheduleSequenceDiagram.png differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png index 5bd77847aa2..c2f37720e59 100644 Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ diff --git a/docs/images/aaroncql.png b/docs/images/aaroncql.png new file mode 100644 index 00000000000..3ce89c8d4f9 Binary files /dev/null and b/docs/images/aaroncql.png differ diff --git a/docs/images/damithc.jpg b/docs/images/damithc.jpg deleted file mode 100644 index 12754388389..00000000000 Binary files a/docs/images/damithc.jpg and /dev/null differ diff --git a/docs/images/dban1.png b/docs/images/dban1.png new file mode 100644 index 00000000000..5a18d9ada58 Binary files /dev/null and b/docs/images/dban1.png differ diff --git a/docs/images/lejolly.jpg b/docs/images/lejolly.jpg deleted file mode 100644 index 2d1d94e0cf5..00000000000 Binary files a/docs/images/lejolly.jpg and /dev/null differ diff --git a/docs/images/m133225.jpg b/docs/images/m133225.jpg deleted file mode 100644 index fd14fb94593..00000000000 Binary files a/docs/images/m133225.jpg and /dev/null differ diff --git a/docs/images/tohkerwei.png b/docs/images/tohkerwei.png new file mode 100644 index 00000000000..48c252e81cc Binary files /dev/null and b/docs/images/tohkerwei.png differ diff --git a/docs/images/yijinl.jpg b/docs/images/yijinl.jpg deleted file mode 100644 index adbf62ad940..00000000000 Binary files a/docs/images/yijinl.jpg and /dev/null differ diff --git a/docs/images/yl_coder.jpg b/docs/images/yl_coder.jpg deleted file mode 100644 index 17b48a73227..00000000000 Binary files a/docs/images/yl_coder.jpg and /dev/null differ diff --git a/docs/images/yonggiee.png b/docs/images/yonggiee.png new file mode 100644 index 00000000000..4733d04e98f Binary files /dev/null and b/docs/images/yonggiee.png differ diff --git a/docs/images/ziyingli.png b/docs/images/ziyingli.png new file mode 100644 index 00000000000..581c6a5ebb0 Binary files /dev/null and b/docs/images/ziyingli.png differ diff --git a/docs/templates/LICENSE b/docs/templates/LICENSE index 2073b44dee6..58ea613b316 100644 --- a/docs/templates/LICENSE +++ b/docs/templates/LICENSE @@ -5,11 +5,11 @@ MIT License Copyright (C) 2012-2018 Dan Allen, Ryan Waldron and the Asciidoctor Project -Permission is hereby granted, free of charge, to any person obtaining a copy +Permission is hereby granted, free of charge, to any client obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is +copies of the Software, and to permit clients to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in diff --git a/docs/tutorials/AddRemark.adoc b/docs/tutorials/AddRemark.adoc index 51044c36494..1586cea06a3 100644 --- a/docs/tutorials/AddRemark.adoc +++ b/docs/tutorials/AddRemark.adoc @@ -41,7 +41,7 @@ package seedu.address.logic.commands; import seedu.address.model.Model; /** - * Changes the remark of an existing person in the address book. + * Changes the remark of an existing client in the address book. */ public class RemarkCommand extends Command { @@ -82,8 +82,8 @@ Following the convention in other commands, we add relevant messages as constant .RemarkCommand.java [source, java] ---- - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the remark of the person identified " - + "by the index number used in the last person listing. " + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the remark of the client identified " + + "by the index number used in the last client listing. " + "Existing remark will be overwritten by the input.\n" + "Parameters: INDEX (must be a positive integer) " + "r/ [REMARK]\n" @@ -120,8 +120,8 @@ public class RemarkCommand extends Command { private final String remark; /** - * @param index of the person in the filtered person list to edit the remark - * @param remark of the person to be updated to + * @param index of the client in the filtered client list to edit the remark + * @param remark of the client to be updated to */ public RemarkCommand(Index index, String remark) { requireAllNonNull(index, remark); @@ -245,13 +245,13 @@ If you are stuck, check out the sample link:https://github.com/nus-cs2103-AY1920 == Add `Remark` to the model Now that we have all the information that we need, let's lay the groundwork for some _persistent_ changes. -We achieve that by working with the `Person` model. -Each field in a Person is implemented as a separate class (e.g. a `Name` object represents the person's name). -That means we should add a `Remark` class so that we can use a `Remark` object to represent a remark given to a person. +We achieve that by working with the `Client` model. +Each field in a Client is implemented as a separate class (e.g. a `Name` object represents the client's name). +That means we should add a `Remark` class so that we can use a `Remark` object to represent a remark given to a client. === Add a new `Remark` class -Create a new `Remark` in `seedu.address.model.person`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code. +Create a new `Remark` in `seedu.address.model.client`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code. A copy-paste and search-replace later, you should have something like link:https://github.com/nus-cs2103-AY1920S1/addressbook-level3/commit/b7a47c50c8e5f0430d343a23d2863446b6ce9298#diff-af2f075d24dfcd333876f0fbce321f25[this]. Note how `Remark` has no constrains and thus does not require input validation. @@ -263,17 +263,17 @@ These should be relatively simple changes. == Add a placeholder element for remark to the UI -Without getting too deep into `fxml`, let's go on a 5 minute adventure to get some placeholder text to show up for each person. +Without getting too deep into `fxml`, let's go on a 5 minute adventure to get some placeholder text to show up for each client. Simply add [source, java] -.PersonCard.java +.ClientCard.java ``` @FXML private Label remark; ``` -to link:https://github.com/nus-cs2103-AY1920S1/addressbook-level3/commit/2758455583f0101ed918a318fc75679270843a0d#diff-0c6b6abcfac8c205e075294f25e851fe[`seedu.address.ui.PersonCard`]. +to link:https://github.com/nus-cs2103-AY1920S1/addressbook-level3/commit/2758455583f0101ed918a318fc75679270843a0d#diff-0c6b6abcfac8c205e075294f25e851fe[`seedu.address.ui.ClientCard`]. `@FXML` is an annotation that marks a private or protected field and makes it accessible to FXML. It might sound like Greek to you right now, don't worry -- we will get back to it later. @@ -282,34 +282,34 @@ Then insert ```