diff --git a/README.md b/README.md
index 13f5c77403f..db7735bc27e 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,12 @@
-[](https://github.com/se-edu/addressbook-level3/actions)
+[](https://github.com/AY2223S2-CS2103T-T13-4/tp/actions/)
+[](https://codecov.io/gh/AY2223S2-CS2103T-T13-4/tp)

-* This is **a sample project for Software Engineering (SE) students**.
+* This is **a desktop application for managing bookmarks**.
Example usages:
- * as a starting point of a course project (as opposed to writing everything from scratch)
- * as a case study
-* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details.
- * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big.
- * It comes with a **reasonable level of user and developer documentation**.
-* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...).
-* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**.
-* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info.
+ * To keep track of a book your are currently reading.
+ * To keep track of books you have finished reading.
+ * To keep track of books you wish to start reading.
+* For the detailed documentation of this project, see the **[MyLib Product Website](https://ay2223s2-cs2103t-t13-4.github.io/tp/)**.
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
diff --git a/build.gradle b/build.gradle
index 108397716bd..c44a144a944 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ plugins {
id 'jacoco'
}
-mainClassName = 'seedu.address.Main'
+mainClassName = 'seedu.library.Main'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
@@ -20,6 +20,9 @@ checkstyle {
toolVersion = '10.2'
}
+run {
+ enableAssertions = true;
+}
test {
useJUnitPlatform()
finalizedBy jacocoTestReport
@@ -66,7 +69,7 @@ dependencies {
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'MyLib.jar'
}
defaultTasks 'clean', 'test'
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..a867c0dc68e 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -9,51 +9,51 @@ You can reach us at the email `seer[at]comp.nus.edu.sg`
## Project team
-### John Doe
+### Teo Rayon
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/NoyaRoeT)]
+[[portfolio](team/noyaroet.md)]
-* Role: Project Advisor
+* Role: Developer
+* Responsibilities: Backend & Features
-### Jane Doe
+### Zenith Yap
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/zenithyap)]
+[[portfolio](team/zenithyap.md)]
-* Role: Team Lead
+* Role: Developer
* Responsibilities: UI
-### Johnny Doe
+### Wong Jia Jun
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/Wong-Jia-Jun)]
+[[portfolio](team/wong-jia-jun.md)]
* Role: Developer
-* Responsibilities: Data
-
-### Jean Doe
+* Responsibilities: UI
+### Wong Yong Xiang
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/wongyx)]
+[[portfolio](team/wongyx.md)]
* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Responsibilities: TBC
-### James Doe
+### Zhou Yuxin
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/zhoyx)]
+[[portfolio](team/zhoyx.md)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities: Backend work
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 46eae8ee565..f650f75b10b 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -6,39 +6,81 @@ title: Developer Guide
{:toc}
--------------------------------------------------------------------------------------------------------------------
+
-## **Acknowledgements**
+
+
+## **Software Overview**
+
+* MyLib is a desktop application originally built to serve as a single platform for organising and tracking all the online webnovels and comics that you may be reading. However, it is more than capable of doing so for any other reading material you might be interested in, such as blogs, articles, research papers and basically anything you can read. MyLib is optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). This means that most of MyLib’s features are meant to be accessed through typed commands rather than mouse clicks.
+
+--------------------------------------------------------------------------------------------------------------------
+
+## **Intended Audience**
+
+This guide is intended primarily for developers who want to work on the MyLib code base at https://github.com/AY2223S2-CS2103T-T13-4/tp.
+
+--------------------------------------------------------------------------------------------------------------------
+
+
+## **Using the Guide**
+
+This guide contains certain visuals to aid in conveying information more effectively
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+| Symbol | GMFD syntax | Meaning |
+|:---------------------:|:----------------------:|:-------------------------------------------:|
+| :bulb: | `:bulb:` | Useful advice that devleopers can use |
+| :information_source: | `:information_source:` | Supplementary information for the developer |
--------------------------------------------------------------------------------------------------------------------
-## **Setting up, getting started**
-Refer to the guide [_Setting up and getting started_](SettingUp.md).
+## **About Us**
+Please refer to the [About Us](AboutUs.md) page for information about the developers.
--------------------------------------------------------------------------------------------------------------------
+## **Acknowledgements**
+
+* This project is based on the [AddressBook Level 3 (AB3)](https://se-education.org/addressbook-level3/) project created by the [SE-EDU initiative](https://se-education.org/).
+* Libraries used: [JavaFX](https://openjfx.io/), [JUnit5](https://github.com/junit-team/junit5)
+
+--------------------------------------------------------------------------------------------------------------------
+## **About MyLib**
+This Developer Guide provides in-depth documentation on how MyLib is designed and implemented. It covers the architecture of MyLib, detailed specifications on smaller pieces of the design, and an outline of all parts of the software and how they will work.
+
+You can use this guide to maintain and evolve MyLib.
+
+
+
## **Design**
+This section gives you a high-level overview of how the application is structured and what the key components of MyLib are.
+
+
:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/se-edu/addressbook-level3/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
+
### Architecture
-
+
+
The ***Architecture Diagram*** given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
+
**Main components of the architecture**
-**`Main`** has two classes called [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for,
-* At app launch: Initializes the components in the correct sequence, and connects them up with each other.
-* At shut down: Shuts down the components and invokes cleanup methods where necessary.
+**`Main`** has two classes called [`Main`](https://github.com/AY2223S2-CS2103T-T13-4/tp/blob/master/src/main/java/seedu/library/Main.java) and [`MainApp`](https://github.com/AY2223S2-CS2103T-T13-4/tp/blob/master/src/main/java/seedu/library/MainApp.java). It is responsible for:
+* Initializing the components in the correct sequence
+* Connecting components with each other during app launch
+* Shutting down the components
+* Invoking cleanup methods where necessary when app shuts down
[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components.
@@ -60,135 +102,401 @@ Each of the four main components (also shown in the diagram above),
* defines its *API* in an `interface` with the same name as the Component.
* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point.
+
For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
+
### UI component
-The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java)
+The UI component handles the user-interface portion of the application.
+The **API** of this component is specified in [`Ui.java`](https://github.com/AY2223S2-CS2103T-T13-4/tp/blob/master/src/main/java/seedu/library/ui/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 which captures the commonalities between classes that represent parts of the visible GUI.
+The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `BookmarkListPanel`, `StatusBarFooter`, `ZoomView` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
-The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml)
+The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/AY2223S2-CS2103T-T13-4/tp/blob/master/src/main/java/seedu/library/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2223S2-CS2103T-T13-4/tp/blob/master/src/main/resources/view/MainWindow.fxml)
The `UI` component,
* executes user commands using the `Logic` component.
* listens for changes to `Model` data so that the UI can be updated with the modified data.
* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands.
-* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`.
+* depends on some classes in the `Model` component, as it displays `Bookmark` object residing in the `Model`.
+
### Logic component
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+The Logic Component handles the execution of commands
+**API** : [`Logic.java`](https://github.com/AY2223S2-CS2103T-T13-4/tp/blob/master/src/main/java/seedu/library/logic/Logic.java)
Here's a (partial) class diagram of the `Logic` component:
How the `Logic` component works:
-1. When `Logic` is called upon to execute a command, it uses the `AddressBookParser` class to parse the user command.
+1. When `Logic` is called upon to execute a command, it uses the `LibraryParser` class to parse the user command.
1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddCommand`) which is executed by the `LogicManager`.
-1. The command can communicate with the `Model` when it is executed (e.g. to add a person).
+1. The command can communicate with the `Model` when it is executed (e.g. to add a bookmark).
1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
+
The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API call.
-
+
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
-* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object.
+* When called upon to parse a user command, the `LibraryParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `LibraryParser` returns back as a `Command` object.
* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
+
### Model component
-**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
+
+The Model component holds the data of the app in memory.
+**API** : [`Model.java`](https://github.com/AY2223S2-CS2103T-T13-4/tp/blob/master/src/main/java/seedu/library/model/Model.java)
The `Model` component,
-
-* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
-* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as 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.
+* stores the Library data i.e., all `Bookmark` objects (which are contained in a `UniqueBookmarkList` object).
+* stores the currently 'selected' `Bookmark` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as 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.
* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components)
+
-
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `Library`, which `Bookmark` references. This allows `Library` to only require one `Tag` object per unique tag, instead of each `Bookmark` needing their own `Tag` objects.
-
+
### Storage component
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
+The Storage Component reads data from, and writes data to, the hard disk.
+**API** : [`Storage.java`](https://github.com/AY2223S2-CS2103T-T13-4/tp/blob/master/src/main/java/seedu/library/storage/Storage.java)
-
+
The `Storage` component,
-* can save both address book data and user preference data in json format, and read them back into corresponding objects.
-* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
+* can save both Library data and user preference data in json format, and read them back into corresponding objects.
+* inherits from both `LibraryStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
### Common classes
-Classes used by multiple components are in the `seedu.addressbook.commons` package.
+Classes used by multiple components are in the `seedu.library.commons` package.
--------------------------------------------------------------------------------------------------------------------
+
## **Implementation**
This section describes some noteworthy details on how certain features are implemented.
+### Add Feature
+
+#### Implementation
+
+The `add` command creates a new bookmark in the library. This allows users to keep easily keep track of their readings.
+
+A bookmark in MyLib contains:
+* Title - the title of the content that is being tracked by this bookmark
+* Author - the author of the content that is being tracked by this bookmark
+* Progress - consists of volume, chapter and page, and is used to track your progress with the content being tracked by this bookmark.
+* Genre - the genre your content falls under.
+* Rating - to indicate how much you enjoyed the content being tracked by this bookmark.
+* Tags - a custom labels attached to a bookmark for custom categorization purposes.
+* URL - to hold the URL of the website that the content being tracked by this bookmark is hosted at.
+
+For a bookmark in MyLib, everything except for title and genre is optional.
+
+Steps involved and interactions between components when a valid add bookmark command is received
+1. Upon receiving a valid `add` command from the UI component, the `execute()` command for the `LogicManager` is called with the command inputs.
+2. `LibraryParser` parses the input to determine the command type, in this case it is a `add` command, thus an `AddCommandParser` is created.
+3. The `AddCommandParser` then parses the input and constructs a new `Bookmark` with the input fields based on their tags.
+4. The newBookmark is then used to create an `AddCommand` to be returned to the `LogicManager`.
+5. `execute()` method of `AddCommand` is then called by the `LogicManager`
+ 1. This adds the newBookmark to the library
+ 2. And returns a `CommandResult` object to the `LogidManager`.
+
+
+The following sequence diagram shows the interaction between the objects when a user executes the Add command.
+
+
+
+
+
+### GoTo Feature
+
+#### Implementation
+
+The `Bookmark` class will have an attribute `url` of type `URL` which represents site which the bookmark is hyperlinked to.
+The `GoToCommand` will then open the site in the default browser of the user. Before the `GoToCommand` object is created.
+
+* The `GoToCommandParser` will checks if the command is of the correct format and argument index is valid
+* Then the `GoToCommand` will execute these steps in order
+ 1. Get the current bookmarklist displayed
+ 2. Get bookmark of specified index from the bookmarklist and get its `url`
+ 3. Open the url in the default browser.
+
+The following Activity diagram depicts what happens when the `GoToCommand` is executed.
+
+
+
+
+The following sequence diagram shows the interaction between the objects when a user executes the GoTo command.
+
+
+
+#### Design Considerations:
+
+**Aspect: What data type to use?:**
+
+Currently, the url value is a `String` object that is parsed into Url object in `Bookmark` class and
+is then created into a URI object when `GoToCommand` is executed
+
+The benefits of using `String` is that it is easy to saved and retrieve from Json Storage File.
+
+* **Alternative 1 (current choice):** url stored as string and URI object to open site only created in `GoToCommand`.
+ * Pros: Easy to implement, easier storage
+ * Cons: May have security due to parsing or encoding errors
+
+* **Alternative 2:** url stored as a URI object in Bookmark
+ * Pros: Will use be safer as errors are caught before object is created
+ * Cons: Difficulty in implementing as harder to parse for user input due to format of URI
+
+
+### View Feature
+
+#### Implementation
+
+The `ViewCommand` allows user to view the bookmark's labelled details in the right panel/ Zoomview panel on the bottom right of GUI.
+
+The user can use the `view` command followed by a postive index/integer. The value of this index corresponds to the
+index beside the bookmark the user wishes to view in the bookmarkList panel of the GUI. Therefore its value has to lie
+between the 1 and the length of current displayed bookmarklist inclusive.
+
+
:information_source: **Note:** This `view` command can only be executed
+if a bookmark exists in the bookmarkList Panel
+
+
+#### Design considerations:
+
+**Aspect: How to pick bookmark to view?:**
+
+* **Alternative 1(current choice):** Pick by index given to bookmark when `bookmarkCard` object is created.
+ * Pros: Simple to implement and intuitive for user to pick desired bookmark based on the order in bookmarklist
+ * Cons: An extra field to be stored which might be unnecessary.
+* **Alternative 2:** Pick based on the title of the bookmark.
+ * Pros: No need extra overhead or space required to store an extra field
+ * Cons: Some titles may have similar titles so user may have to type out entire title which may be quite long or
+ have some sort of combination of Title and author to identify the unique bookmark.
+
+
+
+### Find Feature
+
+#### Implementation
+
+The `FindCommand` allows user to find an existing bookmark by searching for a specific `Title`, `Genre`, `Tag`, and/or
+`Author`.
+
+User can use the `find` command followed by optional prefixes of the field they want to search by and the word they
+want to search for. The prefixes are `n/` for `Title`, `g/` for `Genre`, `t/` for `Tag`, and `a/` for `Author`.
+An example of a user input would be: `find g/ Fantasy`. User inputs are parsed in `FindCommandParser` which will
+split the input based on the prefixes.
+
+Some limitations of the user input includes:
+1. There must be at least 1 prefix provided
+ * User cannot use `find` without specifying a field that they want to search for
+2. The `genre` and `tag` provided must be valid
+ * User can only search for `genre` and `tags` that already exist in the list of `Genre` and `Tag`
+ * Searching for invalid `genre`/`tag` would give an error message informing the user that the `genre`/`tag` does not
+ exist
+
+#### Design considerations:
+
+**Aspect: Which fields of bookmark can `find` searched for?:**
+
+Currently, `find` allows user to search by `title`, `genre`, `tag` and `author`.
+
+The main reason is that it is intuitive to use these fields to identify one bookmark from another.
+
+A considered field to be included in `find` is the `progress` field. However, it seems counter-intuitive to search a
+bookmark by the `progress` field as it is not common for people to remember how far they have read a book, so users are
+unlikely to search for a bookmark using `progress`.
+
+
+### Tags Feature
+
+#### Implementation
+The `ListTagsCommand` lists all tags in the tag list. The `AddTagCommand` allows you to add tags to the tag list.
+The `DeleteTagCommand` allows you to delete tags from the tag list.
+
+For listing the tags, you can use the `tags` command. For adding a tag to the tag list,
+you can use the `addtag` command followed by the tag prefix, `t/`. An example of a user input
+would be `addtag t/MaleProtagonist`. For deleting a tag from the tag list, you can use the
+`dtag` command followed by the name of the tag name. An example of user input would be
+`dtag MaleProtagnoist`.
+
+Some limitations of the user inputs include:
+1. For deleting tags, only one tag name can be specified
+ * You cannot delete more than one tag name in a single command
+
+#### Design considerations:
+
+**Aspect: How to store the tag list?:**
+The tag list is stored as a JSON file which will be saved to the user's local device.
+
+The main reason for this is due to the need for the user's tag list to be saved even after the user exist
+the application. When the user starts the application in the future, the tag list must be how the user left it.
+
+
+### Rating Field
+#### Implementation
+The `Rating` field of a bookmark allows user to rate books in the Library. This is stored as the attribute `Rating`
+in the `Bookmark` class.
+
+`Rating` is an optional field to be added to a bookmark. It was represented as an integer as that allows it to be
+easily displayed as stars on the user interface and thus easy to understand for the user. When no `Rating` is provided,
+no star logos would be displayed. The sort command also sorts the bookmarks based on the rating provided.
+
+#### Design considerations:
+
+**Aspect: How should `Rating` be stored?**
+The `Rating` field is represented by integer values from 0 to 5. This allows for a simple and intuitive way to rate
+books in the `Library`.
+
+- **Alternative 1(current choice):** Representing it as an integer from 0 to 5 inclusive.
+ - Pros: Simple to keep track of and store, easily map rating to star icons in UI.
+ - Cons: Might not be granular enough to represent all possible values.
+- **Alternative 2:** Representing it a decimal value from 0 to 5.
+ - Pros: Higher level of granularity.
+ - Cons: Difficult to represent with visual symbols in the UI to accurately reflect difference in ratings.
+
+**Aspect: How should `Rating` be displayed to users?**
+- Alternative 1: Represented as a number for example "Rating: 4".
+ - Pros: Easy to implement in the UI.
+ - Cons: Lots of textual information already present in the UI, adding more text makes it less visually appealing.
+- Alternative 2(current choice): Representing it with 5-star icons in the BookmarkList Panel.
+ - Pros: User can view ratings of books without having to click on the Bookmark Card.
+ - Cons: Harder to implement in the UI.
+
+
+### Progress Field
+
+#### Implementation
+
+The `Progress` field of a `Bookmark` is used to track the latest read portion of the associated book. This could be many
+things including the latest read volume of a series, or the chapter or page of a single book. It is mainly for a user to
+remember where he last left off when they revisit the book.
+
+Currently, `Progress` contains 3 public attributes: `volume`, `chapter` and `page`, all of which are implemented as
+separate `String` objects. While these attributes can be empty, at least one of them must not be empty.
+
:information_source: **Note:** For a case where all 3 attributes are empty
+, this should be reflected by a `Bookmark` with `Progress = null`.
+
+
+The valid range of values for the 3 attributes are as follows:
+1. Each of the 3 attributes can only be `~` or an unsigned integer in the form of a `String`
+ * `~` represents an empty value.
+ * If it is an unsigned integer, it may not start with `0`.
+2. At least one of the 3 attributes must be an unsigned integer
+ * They cannot all be `~`. i.e. Cannot have an empty `Progress`
+
+The format for user input is: `p/VOLUME CHAPTER PAGE`.
+
+The valid range of values for `VOLUME`, `CHAPTER` and `PAGE` are identical to that of the `volume`, `chapter` and `page`
+attributes. Similarly, the value of the 3 attributes is identical to the value stored in JSON when the `Bookmark` is
+saved. For example, if `page` has the value `~`, that exact value is saved into the JSON file.
+
+
+#### Design considerations:
+
+**Aspect: What data should `Progress` contain?:**
+
+Currently, Progress stores information about the volume, chapter and page of the book being tracked.
+
+This is believed to be sufficient for tracking basically any book since most, if not all books (online or physical)
+organise themselves with the 3 attributes.
+
+Other possible attributes that were considered include: line number and word number. However, if we consider a user revisiting a book and wanting to continue where they last left off,
+it is very unlikely that they will continue from the word or line that they stopped at.
+
+**Aspect: What data type to use?:**
+
+Currently, `volume`, `chapter` and `page` are all stored as separate `String` objects.
+
+This makes it easy to parse user input (which is a `String`) into a `Progress` object, and easy for a `Progress`
+object to be converted into a set of `String` objects to be saved into a JSON file for storage.
+
+A considered alternative is to use 3 `Integer` objects instead. The benefit of this would be allowing integer
+arithmetic while requiring slightly less memory. However, there are no plans for allowing a user to update `Progress`
+in a way that would require integer arithmetic and the difference in memory cost is negligible. Furthermore, like other
+`Bookmark` fields, `Progress` is designed to be immutable.
+
+**Aspect: How to represent a value that does not exist?:**
+
+Currently, `~` is used to represent absence of a value.
+
+The main reason is to simplify the logic for parsing user input.
+
+A considered alternative is to simply leave empty fields as an empty string `""`. However, a possible user input would
+then look like `"1 50"` and it becomes impossible to differentiate between the 3 attributes. It is possible to use a
+prefixes to differentiate them, but parsing becomes more complex.
+
+
### \[Proposed\] Undo/redo feature
#### Proposed Implementation
-The proposed 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:
+The proposed undo/redo mechanism is facilitated by `VersionedLibrary`. It extends `Library` with an undo/redo history, stored internally as an `libraryStateList` and `currentStatePointer`. Additionally, it implements the following operations:
-* `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.
+* `VersionedLibrary#commit()` — Saves the current Library state in its history.
+* `VersionedLibrary#undo()` — Restores the previous Library state from its history.
+* `VersionedLibrary#redo()` — Restores a previously undone Library state from its history.
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+These operations are exposed in the `Model` interface as `Model#commitLibrary()`, `Model#undoLibrary()` and `Model#redoLibrary()` respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
-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.
+Step 1. The user launches the application for the first time. The `VersionedLibrary` will be initialized with the initial library state, and the `currentStatePointer` pointing to that single Library state.

+
-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.
+Step 2. The user executes `delete 5` command to delete the 5th bookmark in the library. The `delete` command calls `Model#commitLibrary()`, causing the modified state of the Library after the `delete 5` command executes to be saved in the `libraryStateList`, and the `currentStatePointer` is shifted to the newly inserted Library state.

-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`.
+Step 3. The user executes `add n/Hobbit …` to add a new bookmark. The `add` command also calls `Model#commitLibrary()`, causing another modified library state to be saved into the `libaryStateList`.

-
:information_source: **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`.
+
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitLibrary()`, so the library state will not be saved into the `libraryStateList`.
-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.
+Step 4. The user now decides that adding the bookmark was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoLibrary()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous library state, and restores the library to that state.

-
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook 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
+
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial Library state, then there are no previous Library states to restore. The `undo` command uses `Model#canUndoLibrary()` to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.
@@ -201,19 +509,21 @@ The following sequence diagram shows how the undo operation works:
-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.
+The `redo` command does the opposite — it calls `Model#redoLibrary()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the Library to that state.
-
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook 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.
+
:information_source: **Note:** If the `currentStatePointer` is at index `libraryStateList.size() - 1`, pointing to the latest Library state, then there are no undone Library states to restore. The `redo` command uses `Model#canRedoLibrary()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
+
-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.
+Step 5. The user then decides to execute the command `list`. Commands that do not modify the Library, such as `list`, will usually not call `Model#commitLibrary()`, `Model#undoLibrary()` or `Model#redoLibrary()`. Thus, the `libraryStateList` remains unchanged.

-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. Reason: It no longer makes sense to redo the `add n/David …` command. This is the behavior that most modern desktop applications follow.
+Step 6. The user executes `clear`, which calls `Model#commitLibrary()`. Since the `currentStatePointer` is not pointing at the end of the `libraryStateList`, all Library states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …` command. This is the behavior that most modern desktop applications follow.

+
The following activity diagram summarizes what happens when a user executes a new command:
@@ -223,23 +533,17 @@ The following activity diagram summarizes what happens when a user executes a ne
**Aspect: How undo & redo executes:**
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+* **Alternative 1 (current choice):** Saves the entire Library.
+ * 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.
-
-_{more aspects and alternatives to be added}_
-
-### \[Proposed\] Data archiving
-
-_{Explain here how the data archiving feature will be implemented}_
-
+ * Pros: Will use less memory (e.g. for `delete`, just save the bookmark being deleted).
+ * Cons: We must ensure that the implementation of each individual command are correct.
--------------------------------------------------------------------------------------------------------------------
+
## **Documentation, logging, testing, configuration, dev-ops**
@@ -250,49 +554,72 @@ _{Explain here how the data archiving feature will be implemented}_
* [DevOps guide](DevOps.md)
--------------------------------------------------------------------------------------------------------------------
-
## **Appendix: Requirements**
### Product scope
**Target user profile**:
-* has a need to manage a significant number of contacts
-* prefer desktop apps over other types
-* can type fast
-* prefers typing to mouse interactions
-* is reasonably comfortable using CLI apps
-
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+* Consumer of comics and web novels
+* Has a need to manage the large number of books he consumes
+* Prefer desktop apps over other types
+* Can type fast
+* Prefers typing to mouse interactions
+* Is reasonably comfortable using CLI apps
+**Value proposition**:
+* Manage books for the user.
+* Keeps track of books they have not started, is currently reading, has finished reading.
+* Manage books faster than a typical mouse/GUI driven app
+
### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| 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 |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
-
-*{More to be added}*
+| 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 |
+| `* * *` | user | add a new bookmark | start tracking a book |
+| `* * *` | user | delete a bookmark | remove entries that I no longer need |
+| `* * *` | user | edit a bookmark | update the information in my bookmark |
+| `* *` | user | view the details of a single bookmark | see information about a particular book I am tracking |
+| `* *` | user with mostly unnecessary bookmarks | clear all bookmarks | not delete each bookmark one by one |
+| `* *` | user with many bookmarks | find bookmarks by book type | view bookmarks of only a certain type |
+| `* *` | user with many bookmarks | find bookmarks by book genre | view bookmarks of only a certain genre |
+| `* *` | user | rate a book through its bookmark | remember how much I enjoyed the book |
+| `* *` | user with many bookmarks | sort bookmarks by book title | locate a bookmark easily |
+| `* *` | user with many bookmarks | sort bookmarks by rating | locate bookmarks of books I enjoyed easily |
+| `* *` | user who likes detail | add tags to bookmark | give additional labels to a bookmark |
+| `* *` | user with many bookmarks | find bookmarks by their tags | view only bookmarks who have certain tags |
+| `* *` | user with many bookmarks | find bookmarks by book author | view bookmarks of books written by a specific author |
+| `* *` | user | add hyperlinks to bookmarks | link the website where I am reading the book's chapters from |
+| `* *` | user | goto url of bookmarks | easily go to site of bookmark |
+| `*` | user | add book characters to a bookmark | store noteworthy characters which I remember the book by |
+| `*` | user | find bookmarks using name of characters | locate books with certain characters easily |
+| `* *` | user with many bookmarks | sort bookmarks by their rating | view bookmarks in order of their rating |
+| `* *` | user with many bookmarks | find bookmarks by last modified date | view bookmarks in order of most recently updated |
+| `* *` | user | add the current reading progress to a bookmark | know where I last left off with a certain book |
+| `* *` | user | find bookmarks based on their progress | view only bookmarks of a certain progress easily |
+| `* *` | user | add tags to an approved tag list | standardize the tags used and make finding bookmark by tags easily |
+| `* *` | user | delete a tag from the approved tag list | remove tags that I no longer need |
+| `* *` | user | view tags in the approved tag list | see that tags have been added and available for use |
+| `* *` | user | view the list of valid genres | see what are genres that can be added to a bookmark |
+
+
### Use cases
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+(For all use cases below, the **System** is the `MyLib` and the **Actor** is the `user`, unless specified otherwise)
-**Use case: Delete a person**
+**Use case: Delete a bookmark**
**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 list bookmarks
+2. MyLib shows a list of bookmarks
+3. User requests to delete a specific bookmark in the list
+4. MyLib deletes the bookmark
Use case ends.
@@ -304,74 +631,498 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
* 3a. The given index is invalid.
- * 3a1. AddressBook shows an error message.
+ * 3a1. MyLib shows an error message.
Use case resumes at step 2.
-*{More to be added}*
+**Use case: Edit a bookmark**
-### Non-Functional Requirements
+**MSS**
+
+1. User requests to list bookmarks
+2. MyLib shows a list of bookmarks
+3. User requests to edit a specific bookmark in the list
+4. MyLib edits the bookmark
+
+ Use case ends.
+
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+
+ * 3a1. MyLib shows an error message.
+
+ Use case resumes at step 2.
+
+* 3b. Less than one field to edit provided.
+
+ * 3b1. MyLib shows an error message.
+
+ Use case resumes at step 2
+
+* 3c. New value is invalid for any field.
+
+ * 3c1. MyLib shows an error message.
+
+ Use case resumes at step 2.
+
+**Use case: Add a bookmark**
+
+**MSS**
+
+1. User requests to add a bookmark
+2. MyLib adds a bookmark
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The given index is invalid.
+
+ * 1a1. MyLib shows an error message.
+
+ Use case resumes at step 2.
+
+* 1b. Not all compulsory fields provided.
+
+ * 1b1. MyLib shows an error message.
+
+ Use case resumes at step 2
+
+* 1c. Value is invalid for any field.
+
+ * 1c1. MyLib shows an error message.
+
+ Use case resumes at step 2.
+
+**Use case: Finding a bookmark**
+
+**MSS**
+
+1. User requests to find a bookmark by title of some keyword
+2. MyLib finds and displays all bookmarks which contains keyword in its title
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. Not all compulsory fields provided.
+
+ * 1a1. MyLib shows an error message.
+
+ Use case resumes at step 2
+
+* 1b. Value is invalid for any field.
+
+ * 1b1. MyLib shows an error message.
+
+ Use case resumes at step 2.
+
+**Use case: Sorting all bookmark**
-1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
-2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
-3. 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.
+**MSS**
+
+1. User requests to list bookmarks
+2. MyLib shows a list of bookmarks
+3. User requests to sort all bookmark
+4. MyLib sorts all bookmarks by rating.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. Not all compulsory fields provided.
+
+ * 1a1. MyLib shows an error message.
+
+ Use case resumes at step 2
+
+* 1b. Value is invalid for any field.
+
+ * 1b1. MyLib shows an error message.
+
+ Use case resumes at step 2.
+
+
+**Use case: View a bookmark**
+
+**MSS**
+
+1. User requests to list bookmarks
+2. MyLib shows a list of bookmarks
+3. User requests to view a specific bookmark in the list
+4. MyLib views the bookmark in right panel of UI
+
+ Use case ends.
+
+**Extensions**
-*{More to be added}*
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+
+ * 3a1. MyLib shows an error message.
+
+ Use case resumes at step 2.
+
+**Use case: Goto bookmark's Url**
+
+**MSS**
+
+1. User requests to list bookmarks
+2. MyLib shows a list of bookmarks
+3. User requests to goto a specific bookmark's Url in the list
+4. MyLib opens url in user's default browser
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+
+ * 3a1. MyLib shows an error message.
+
+ Use case resumes at step 2.
+
+
+
+### Non-Functional Requirements
+
+1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
+2. Should be able to hold up to 1000 bookmark without a noticeable sluggishness in performance for typical usage.
+3. 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.
+4. Saved data should be stored locally and in a human editable text file to allow advanced users to manipulate the data by editing the file.
+5. The software should work without requiring an installer.
+6. The Product JAR/ZIP file should not exceed 100MB.
+7. A user should be able to effectively use the application after reading the help page.
### Glossary
* **Mainstream OS**: Windows, Linux, Unix, OS-X
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **Bookmark**: Tracker for a book that contains information about the book and a user's reading progress
+* **Library**: A collection of stored Bookmarks
+* **GUI**: Graphical User Interface. The visual display that the user interacts with for MyLib.
--------------------------------------------------------------------------------------------------------------------
+
-## **Appendix: Instructions for manual testing**
+## **Appendix A: Instructions for Manual Testing**
-Given below are instructions to test the app manually.
+Given below are instructions and test cases to test MyLib manually.
-
:information_source: **Note:** These instructions only provide a starting point for testers to work on;
-testers are expected to do more *exploratory* testing.
+
:information_source: **Note:** These instructions only provide a starting point for testers to work on.
+Testers are expected to do more *exploratory* testing. Also, each test case is independent of the other test cases.
-### Launch and shutdown
+### Launch and Shutdown
+
+1. **Initial launch**
+
+ 1. Download the [MyLib jar file](https://github.com/AY2223S2-CS2103T-T13-4/tp/releases) and copy into an empty folder.
+
+ 2. Double-click the jar file.
+
+ **Expected**: Shows the GUI with a set of sample bookmarks. The window size may not be optimal.
+
+
+2. **Saving window preferences**
+
+ 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+
+ 2. Re-launch the app by double-clicking the jar file.
+
+ **Expected**: The most recent window size and location is retained.
+
+
+### Listing all Bookmarks
+
+1. `list`
+
+ **Expected**: All bookmark entries are listed out and displayed in the List Panel.
+
+
+2. `list hello`
+
+ **Expected**: All bookmark entries are listed out and displayed in the List Panel.
+
+### Adding a Bookmark
+
+1. `add n/The Odyssey a/Homer p/1 1 1 g/Fantasy r/4 u/http://classics.mit.edu/Homer/odyssey.html t/Literature`
+
+ **Expected**: A new bookmark entry is successfully added. The bookmark will have Title `The Odyssey`, author `Homer`, progress `Vol 1 Chapter 1 Page 1`, genre `Fantasy`, rating `4`, URL `http://classics.mit.edu/Homer/odyssey.html` and tag `Literature`. The View Panel displays all these information except URL, and a success message is displayed in the Result Display.
+
+2. `add n/Hobbit a/J. R. R. Tolkien p/1 ~ 256 r/4 g/Fantasy`
+
+ **Expected**: A new bookmark entry is successfully added. The new bookmark entry will have Title `Hobbit`, author `J. R. R. Tolkien`, progress `Vol 1 Chapter ~ Page 256`, Rating `4` and genre `Fantasy`. The View Panel displays the information for this new bookmark entry, where tag is will be empty. A success message is displayed in the Result Display.
+
+3. `add n/Chainsaw Man r/5`
+
+ **Expected**: No new bookmark is added. An error message is displayed in the Result Display. This is because the compulsory field Genre is missing.
+
+
+
+### Editing a Bookmark
+Assumptions: The sample data provided by MyLib is used, where there is a total of 4 bookmark entries.
+
+1. `edit 2 n/Kimetsu No Yaiba`
+
+ **Expected**: The Title of the second bookmark is updated to `Kimetsu No Yaiba`. The View Panel displays the updated details of the second bookmark entry.
+
+2. `edit 2 n/Darwin's Game r/1`
+
+ **Expected**: The Title and Rating of the second bookmark entry are updated to`Darwin's Game` and `1` respectively. The View Panel displays the updated details of the second bookmark entry.
+
+3. `edit 2 t/`
+
+ **Expected**: All previous tags for the second bookmark entry are removed. The View Panel displays the updated details fo the second bookmark
+ entry.
+
+4. Unsuccessful editing after finding a bookmark
+ 1. `find n/Solo Leveling t/Cheats`
+ 2. `edit 3 n/No Game No Life`
+
+ **Expected**: An error message is displayed in the Result Display. This is because in the filtered bookmark list, there is only 1 bookmark entries, so `3` is not a valid value for the
+ `INDEX` field.
+
+5. `edit`
-1. Initial launch
+ **Expected**: An error message is displayed in the Result Display. This is because a minimum of 1 optional field must be specified.
- 1. Download the jar file and copy into an empty folder
+
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+### Viewing a Bookmark
+Assumptions: The sample data provided by MyLib is used, where there is a total of 4 bookmark entries.
+1. `view 1`
-1. Saving window preferences
+ **Expected**: The View Panel displays the details for the first Bookmark.
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+2. Successful viewing after finding
- 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained.
+ 1. `find n/Solo n/Cheats`
+ 2. `view 1`
-1. _{ more test cases … }_
+ **Expected**: The View Panel displays the details for the first Bookmark entry in the filtered bookmark list. In this case, it displays the details for the entry whose Title name is `Solo Leveling`.
-### Deleting a person
+3. Unsuccessful viewing after finding
+ 1. `find n/Solo n/Cheats`
+ 2. `view 2`
-1. Deleting a person while all persons are being shown
+ **Expected**: An error message is displayed in the Result Display. This is because in the filtered bookmark list, there is only 1 bookmark entry, implying that `2` is not a valid value for the `INDEX` field.
+
+4. `view -1`
+
+ **Expected**: An error message is displayed in the Result Display. This is because the `INDEX` field must be a positive integer greater than or equal to 1.
+
+
+
+### Finding Bookmarks
+Assumptions: The sample data provided by MyLib is used, where there is a total of 4 bookmark entries.
+1. `find n/Solo`
+
+ **Expected**: The List Panel shows the bookmark entry whose Title matches with`Solo`. A success message is displayed in the Result Display.
+
+2. `find n/Solo n/Defense`
+
+ **Expected**: The List Panel shows the bookmark entries whose Title matches with `Defense`. This is because if only one field is required, find ignores all fields of the same prefix except the last. A success message is displayed in the Result Display.
+
+3. `find`
+
+ **Expected**: An error message is displayed in the Result Display. This is because a minimum of 1 optional field must be specified.
+
+5. `find t/Weird`
+
+ **Expected**: An error message is displayed in the Result Display. This is because `Weird` is not in the valid tag list.
+
+
+
+
+### Deleting bookmarks
+Prerequisites: List all bookmarks using the `list` command. Multiple bookmarks are present in the list.
+Assumptions: The sample data provided by MyLib is used, where there is a total of 4 bookmark entries.
+
+1. `delete 1`
+
+ **Expected**: The first bookmark entry in the List Panel is deleted. A success message is displayed in the Result Display.
+
+2. `delete 1 2`
+
+ **Expected**: An error message is displayed in the Result Display. This is because delete only takes in 1 positive index.
+
+3. `delete`
+
+ **Expected**: An error message is displayed in the Result Display. This is because a minimum of 1 index must be specified.
+
+3. Deleting bookmark after finding
+ 1. `find n/Solo`
+ 2. `delete 1`
+
+ **Expected**: The first bookmark of title `Solo Leveling` is deleted. A success message is displayed in the Result Display.
+
+
+### Going to bookmarks' url
+Prerequisites: List all bookmarks using the `list` command. Multiple bookmarks are present in the list.
+Assumptions: The sample data provided by MyLib is used, where there is a total of 4 bookmark entries.
+
+1. `goto 1`
+
+ **Expected**: The first bookmark's url is opened in users default browser. A success message is displayed in the Result Display.
+
+2. `goto 1 2`
+
+ **Expected**: An error message is displayed in the Result Display. This is because goto only takes in 1 positive index.
+
+3. `goto`
+
+ **Expected**: An error message is displayed in the Result Display. This is because a minimum of 1 index must be specified.
+
+3. Going to bookmark's url after finding
+ 1. `find n/Solo`
+ 2. `goto 1`
+
+ **Expected**: The first bookmark's url of title `Solo Leveling` is opened in browser. A success message is displayed in the Result Display.
+
+
+### Clear all bookmark
+
+1. `clear`
+
+ **Expected**: All bookmark entries are deleted.
+
+
+2. `clear hello`
+
+ **Expected**: All bookmark entries are deleted.
+
+
+
+### Listing valid genres
+1. `genre`
+
+ **Expected**: A list of valid genres are displayed in Result Display.
+
+### Listing valid tags
+1. `tags`
+
+ **Expected**: A list of valid tags are displayed in Result Display.
+
+
+2. `tags hello`
+
+**Expected**: A list of valid tags are displayed in Result Display.
+
+### Adding tags to the tag list
+Assumptions: The default tags provided by MyLib is used.
+1. `addtag t/Hero`
+
+ **Expected**: A new tag "Hero" is successfully added to the tag list. A success message is displayed in the Result Display.
+
+
+2. `addtag t/HighSchool t/Security`
+
+ **Expected**: Two new tags "HighSchool" and "Security" are successfully added to the tag list. A success message is displayed in the Result Display.
+
+
+3. `addtag t/Novel`
+
+ **Expected**: No new tag added to the tag list. An error message is displayed in the Result Display. This is because the tag "Novel" already exists in the tag list.
+
+
+### Deleting tags from the tag list
+Assumptions: The sample data provided by MyLib is used, where there is a total of 4 bookmark entries. The default tags provided by MyLib is used.
+
+1. `dtag Novel`
+
+ **Expected**: The tag "Novel" is successfully deleted from the tag list. A success message is displayed in the Result Display.
+
+
+
+2. `dtag Korean`
+
+ **Expected**: No tag is deleted from the tag list. An error message is displayed in the Result Display. This is because there is no "Korean" tag in the tag list.
+
+
+3. `dtag MaleProtagonist FemaleProtagonist`
+
+ **Expected**: No tag is deleted from the tag list. An error message is displayed in the Result Display. This is because tags can only be deleted one at a time and each tag can only be one word long with no spaces in between.
+
+
+### Get Help
+
+1. `help`
+
+ **Expected**: The help window opens.
+
+
+2. `help hello`
+
+ **Expected**: The help window opens.
+
+### Exit MyLib
+
+1. `exit`
+
+ **Expected**: MyLib closes.
+
+
+2. `exit hello`
+
+ **Expected**: MyLib closes.
+
+
+### Save Data
+
+1. Missing Data File
+
+ Prerequisite: There is no file called `library.json` in the `data` subfolder of the folder
+ where MyLib is located.
+
+ 1. If you have an existing `library.json` file, delete the file.
+ 2. Double-click MyLib's jar file.
+
+ **Expected**: MyLib launches with the sample bookmark data shown in the List Panel. There
+ is a total of 4 bookmark entries.
+--------------------------------------------------------------------------------------------------------------------
+
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+## **Appendix B: Planned Enhancements**
+Currently, there a few feature flaws with the application. These are some proposed fixes to address them and improve functionality for the user:
- 1. 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.
+* `edit 0` as show in Figure 1 and `edit` with any other postitive index in Figure 2 below have differing response/result in the result display box.
- 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+
+
+ Figure 1
+
+ : After executing edit 0
+
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
+
+
+ Figure 2
+
+ : After executing edit 8
+
-1. _{ more test cases … }_
+Currently, there is a discrepancy where `edit 0` with missing prefix causes an error message of invalid command format
+while `edit` with any positive index and missing prefix causes an error message of at least 1 field must be present.
-### Saving data
+**Potential Enhancement and Suggested Implementation:**
+It would be great to streamline this error message by perhaps having a separate error message of "index cannot be less
+than 1 " since the bookmarklist index starts from 1. And keep the current error message for indexes more than 0
-1. Dealing with missing/corrupted data files
+In the `parse` method of `EditCommandParser` class , change the message thrown to "index cannot be less than 1" when
+ParseException is thrown.
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
-1. _{ more test cases … }_
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index e7df68b01ea..fff31079210 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -3,152 +3,449 @@ layout: page
title: User Guide
---
-AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via 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.
-
+## **Table of Contents**
* Table of Contents
{:toc}
+--------------------------------------------------------------------------------------------------------------------
+
+
+## **Introduction**
+
+
+
+MyLib is a desktop bookmarking application originally built to serve as a single platform for organising and tracking all the online webnovels and comics that you may be reading. However, its general bookmarking features is more than capable of handling any other bookmarking tasks you might have. This not only includes other types of novels, but also blogs, articles, reddit posts, Youtube videos and anything else that you want to track!
+
+With MyLib, you have the ability to throw all your bookmarks onto a **single platform**, and organise them in a **highly personalized** way via a custom set of tags or labels that you can define on your own.
+
+MyLib is optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). This means that most of MyLib's features are meant to be accessed through typed commands rather than mouse clicks. However, the commands are simple enough such that typing them out will not be much slower than using a GUI, if at all!
+
+--------------------------------------------------------------------------------------------------------------------
+[Back to Table of Contents](#table-of-contents)
+
+
+## **About this User Guide**
+
+### Target Audience
+This User Guide is mainly targeted towards new users who want to get started using MyLib to bookmark their content. It can also serve as a comprehensive reference and guide for current users of the application.
+
+### Objectives of this User Guide
+
+This User Guide provides an easy-to-understand and comprehensive documentation, so you can easily start using MyLib. It covers how to download the application, launch the application and the various features in MyLib that will make it easy for you to bookmark all your content.
+
+[Back to Table of Contents](#table-of-contents)
+
+
+### How to use the User Guide
+
+This User Guide is split into multiple important sections:
+* The [Getting Started](#getting-started) section provides step-by-step instructions to download and get started with MyLib.
+* The [Key Definitions](#key-definitions) section provides a concise explanation of the various key terms used in this User Guide. It will explain what a bookmark is in the context of MyLib.
+* The [Graphical User Interface](#graphical-user-interface) section provides a quick rundown of the different components of MyLib's user interface.
+* The [Commands](#commands) section provides detailed explanations of all the various features in MyLib to help you bookmark your content.
+
+If you are a new user, we recommend going through the sections in the order provided above. If you are an experienced user and are just looking for a quick reference, we recommend either going through the [Commands](#commands) section or the [Command Summary](#command-summary) table. The [Commands](#commands) section will provide a detailed explanation of each command. If you're only looking for a brief overview of the commands, we recommend the [Command Summary](#command-summary) table.
+
+The user guide will contain certain visuals to aid in conveying information more effectively. These include:
+
+:information_source: **Info** - Useful supplementary information
+
+:bulb: **Tip** - Suggestions on how to enhance your experience
+
+:exclamation: **Warning** - Warning of a potentially dangerous action that you should be aware of
--------------------------------------------------------------------------------------------------------------------
+[Back to Table of Contents](#table-of-contents)
+
-## Quick start
+## **Getting Started**
1. Ensure you have Java `11` or above installed in your Computer.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+2. Download the latest `MyLib.jar` from [here](https://github.com/AY2223S2-CS2103T-T13-4/tp/releases).
+
+3. Copy the file to the folder you want to use as the _home folder_ for your Library.
+
+4. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar MyLib.jar` command to run the application.
+
+5. A GUI similar to the one below should appear in a few seconds. You can get an overview of the various components that make up MyLib's GUI [here](#graphical-user-interface).
+
+
+
+6. If this is your first time running the application, it should contain some sample bookmarks.
+
+7. MyLib's functionality is accessed through typed commands. These commands are entered into the [command box](#graphical-user-interface) at the very top of the GUI. After entering the command, press enter to execute it and the result of that command will be displayed below the command box.
+
+
+### Let's try out some of the features
+1. Let's start by trying to add a bookmark.
+
+ * Enter `add n/My Book a/My Book's Author g/Fantasy r/4` into the command box and press the Enter key.
+ * Adds a bookmark for the book with the title `My Book`, the author `My Book's Author` and the genre `Fantasy` to your bookmark library.
+
+2. Now, let's try editing the title in the bookmark you just added
+
+ * Enter `edit 5 n/Edited Title` into the command box and press the Enter key.
+
+ * This edits the title of your bookmark, changing it from `My Book` to `Edited Title`
+
+3. Finally, let's delete that bookmark and exit the application
+
+ * Enter `delete 5` into the command box and press the Enter key.
+
+ * This will delete your bookmark
+
+ * Next, use `exit` to exit the application.
+
+4. You will be able to find a detailed guide on the list of available commands in the [Commands](#commands) section.
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+--------------------------------------------------------------------------------------------------------------------
+[Back to Table of Contents](#table-of-contents)
+
+
+## **Key Definitions**
+This section provides explanations of important terms that will be used in this User Guide.
+
+### Bookmark
+As a bookmarking application, MyLib naturally uses bookmarks to bookmark your content. While MyLib was originally intended to be used for tracking web novels and comics, it's bookmarking features are general enough that your content can basically be anything.
+
+A bookmark in MyLib contains:
+* Title - the title of the content that is being tracked by this bookmark
+* Author - the author of the content that is being tracked by this bookmark
+* Progress - consists of volume, chapter and page, and is used to track your progress with the content being tracked by this bookmark.
+* Genre - the genre your content falls under. More details can be found [here](#genre).
+* Rating - to indicate how much you enjoyed the content being tracked by this bookmark.
+* Tags - a custom labels attached to a bookmark for custom categorization purposes. More details can be found [here](#tags).
+* URL - to hold the URL of the website that the content being tracked by this bookmark is hosted at.
+
+For a bookmark in MyLib, everything except for title and genre is optional.
+
+
+### Genre
+As mentioned in [Bookmark](#bookmark), a genre in a bookmark indicates the genre of the content the bookmark is tracking.
+
+In MyLib, a bookmark's genre may only be selected from a fixed list of genres provided by MyLib.
+
+To find out how to view this fixed list of genres, go [here](#viewing-genres-genre).
+
+[Back to Table of Contents](#table-of-contents)
+
+
+### Tags
+As mentioned in [Bookmark](#bookmark), tags are custom labels that you can attach to a bookmark to categorize them.
+
+MyLib has a tag list, which is a list of all available tags that can be attached to a bookmark. MyLib provides a default set of tags in this tag list that you can use to tag your bookmarks. In addition, you may also view, add and delete tags from the tag list. Your tag list will be saved along with your bookmarks when you close the application.
+
+The commands to modify your tag list can be found at [Tag Commands](#tag-commands).
+
+--------------------------------------------------------------------------------------------------------------------
+[Back to Table of Contents](#table-of-contents)
+
+
+
+## **Graphical User Interface**
+This section provides a quick rundown of the various components of MyLib's user interface.
-1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
- A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- 
+
-1. 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.
- Some example commands you can try:
+### Purpose of each GUI component
- * `list` : Lists all contacts.
+| Component | Purpose |
+|:------------------:|:---------------------------------------------------------:|
+| Command Box | To accept user commands. |
+| Result Box | To display the result of the commands that user executed. |
+| BookmarkList Panel | To display the current list of bookmarks |
+| View Panel | To display the details of a specified bookmark |
- * `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.
+[Back to Table of Contents](#table-of-contents)
+
- * `delete 3` : Deletes the 3rd contact shown in the current list.
+### Bookmark UI details
- * `clear` : Deletes all contacts.
+
- * `exit` : Exits the app.
+The bookmark in the BookmarkList panel will only contain the:
+* Title
+* Author
+* Progress
+* Genre
+* Rating
+* Tag
-1. Refer to the [Features](#features) below for details of each command.
--------------------------------------------------------------------------------------------------------------------
+[Back to Table of Contents](#table-of-contents)
+
-## Features
+## **Commands**
+This section provides an in-depth explanation of MyLib's commands. For a quick reference of the available commands, use the [Command Summary](#command-summary) table.
**:information_source: Notes about the command format:**
* 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`.
+ e.g. in `add n/TITLE`, `TITLE` or name of `TITLE` is a parameter which can be used as `add n/The Odessey`.
* 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`.
+ e.g `n/TITLE [t/TAG]` can be used as `n/The Odessey t/School` or as `n/The Odessey`.
* 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.
+ e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/School`, `t/School t/Literature` 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.
+ e.g. if the command specifies `n/TITLE a/AUTHOR`, `a/AUTHOR n/TITLE` is also acceptable.
-* If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of the parameter will be taken.
- e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken.
+* If a parameter is expected only once in the command, but you specified it multiple times, only the last occurrence of the parameter will be taken.
+ e.g. if you specify `a/John Butcher a/Jim Butcher`, only `a/Jim Butcher` will be taken.
-* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
+* Extra parameters for commands that do not take in parameters (such as `help`, `list`, `exit`, `genre`, `tags` and `clear`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`.
-
-### Viewing help : `help`
+[Back to Table of Contents](#table-of-contents)
+
-Shows a message explaning how to access the help page.
+### Tag Commands
+This section goes through the commands for viewing and modifying your tag list.
-
+#### Viewing tags: `tags`
+To view your list of tags, use the `tags` command.
-Format: `help`
+The format for the command is simply: `tags`.
+Since MyLib comes with a default set of tags, you can expect a non-empty list of tags even as a new user.
-### Adding a person: `add`
+#### Adding tags: `addtag`
+To add new tags to your tag list, use the `addtag` command.
-Adds a person to the address book.
+The format for the `addtag` command is as follows:
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+`addtag [t/TAG]…`
-
:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
+* `TAG` must be alphanumeric (must only contain english letters and numbers).
+* Each `TAG` must be a single word with no spaces in between.
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`
+* `addtag t/Novel t/MaleProtagonist`
+* `addtag t/FemaleProtagonist`
-### Listing all persons : `list`
+#### Deleting a tag: `dtag`
+To delete a tag from your tag list, use the `dtag` command.
-Shows a list of all persons in the address book.
+Format: `dtag TAG`
-Format: `list`
+Example:
+* `dtag MaleProtagonist`
+
+[Back to Table of Contents](#table-of-contents)
+
+
+### Viewing genres: `genre`
+You can view MyLib's fixed list of genres using the `genre` command.
+
+The format for the command is simply: `genre`
+
+The command should display the list of available genres in the `Result Box`.
+
+
+
+[Back to Table of Contents](#table-of-contents)
+
+
+### Adding a bookmark: `add`
+
+To create a new bookmark and add it to your bookmark library you will need to use the `add` command.
+
+The format for the `add` command is as follows:
-### Editing a person : `edit`
+`add n/TITLE g/GENRE [a/AUTHOR] [p/PROGRESS] [r/RATING] [u/URL] [t/TAG]…`
-Edits an existing person in the address book.
+The `add` command accepts the following items as user input:
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+| Prefix | Parameter | Description |
+|:------:|:---------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `n/` | TITLE | This is the title that you want to give to the bookmark. Usually, this is the name of the content the bookmark is tracking.
**Restrictions:** The title can contain any characters be it alphabets, numbers or symbols.
❗ **Caution**: certain non-English alphabets or symbols may not display correctly in the application. |
+| `a/` | AUTHOR | This is the author of the content the bookmark is tracking.
**Restrictions:** The title can contain any characters be it alphabets, numbers or symbols.
❗ **Caution**: certain non-English alphabets or symbols may not display correctly in the application. |
+| `p/` | PROGRESS | This is used to remember your progress with the content being tracked by this bookmark. For example, if the bookmark is tracking a novel, the progress can be used to denote the latest read chapter.
**Restrictions:** PROGRESS should have the format: `VOLUME CHAPTER PAGE`.
`VOLUME`, `CHAPTER` and `PAGE` should either be a positive number (without +) or `~`.
`~` is used to denote an empty `VOLUME`, `CHAPTER` and `PAGE`. For example, if you only want to use `CHAPTER` to track your progress you would do: `~ CHAPTER ~`. At least one of `VOLUME`, `CHAPTER` and `PAGE` must not be `~`. |
+| `g/` | GENRE | The genre of the content the bookmark is tracking.
**Restrictions:** MyLib provides a fixed list of genres. Only genres in that list can be used as the genre of a bookmark. To find out more about this list, go [here](#viewing-genres-genre). |
+| `u/` | URL | This is the url to the website containing the bookmarked content.
**Restrictions:** Must contain [Protocol][Domain name] for example: [http://]www.[example.com] |
+| `r/` | RATING | This is the rating to give the bookmark.
**Restrictions:** Must be a number from 0 to 5 (without any additional symbols like +/-) |
+| `t/` | TAG | This is a tag that you want to attach to the bookmark.
**Restrictions:** Only tags that are in your tag list can be added to a bookmark. For more information on how to modify your tag list, go to the [Tag Commands](#tag-commands) section. |
-* 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, …
+Examples:
+* `add n/Solo Leveling a/Chugong p/~ 110 ~ r/4 g/Fantasy t/Novel`
+ * Adds a bookmark for a fantasy novel called Solo Leveling, authored by Chugong, giving it a rating of 4 and with the last read chapter being the 110th chapter.
+* `add n/The Odyssey g/Action`
+ * Adds a bookmark for a book called The Odyssey with the Action genre. All other items are optional and are left empty.
+
+
+
+### Deleting a bookmark : `delete`
+
+Deletes the specified bookmark from the library.
+
+Format: `delete INDEX`
+
+* Deletes the bookmark at the specified `INDEX`.
+* The index refers to the index number shown in the displayed bookmark list.
+* The index **must be a positive integer** 1, 2, 3, …
+
+Examples:
+* `list` followed by `delete 2` deletes the 2nd bookmark in the library.
+* `find n/Chainsaw Man` followed by `delete 1` deletes the 1st bookmark in the results of the `find` command.
+
+### Editing a bookmark : `edit`
+
+Edits an existing bookmark in the library.
+
+Format: `edit INDEX [n/TITLE] [a/AUTHOR] [p/PROGRESS] [g/GENRE] [r/RATING] [u/URL] [t/TAG]…`
+
+* Edits the bookmark at the specified `INDEX`. The index refers to the index number shown in the displayed bookmark list. The index **must be a positive integer** 1, 2, 3, …
* At least one of the optional fields must be provided.
+* The valid values for each item is the same as the [`add` command](#adding-a-bookmark-add).
* 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.
+* When editing tags, the existing tags of the bookmark will be removed i.e adding of tags is not cumulative.
+* You can remove all the bookmark’s tags by typing `t/` without specifying any tags after it.
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.
+* `edit 1 n/Hobbit a/J. R. R. Tolkien` Edits the title and author of the 1st bookmark to be `Hobbit` and `J. R. R. Tolkien` respectively.
+* `edit 2 n/The Odyssey t/` Edits the name of the 2nd bookmark to be `The Odyssey` and clears all existing tags.
-### Locating persons by name: `find`
+[Back to Table of Contents](#table-of-contents)
+
-Finds persons whose names contain any of the given keywords.
+### Sorting bookmarks : `sort`
-Format: `find KEYWORD [MORE_KEYWORDS]`
+Sorts the list of bookmarks by ratings in either ascending or descending order.
-* 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 : sort [ORDER]
+* ORDER can only be either `asc` or `desc`
+* ORDER is case-sensitive. e.g. `sort ASC` does not work.
Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- 
+* sort asc
+* sort desc
-### Deleting a person : `delete`
+### Locating bookmarks by specific fields: `find`
-Deletes the specified person from the address book.
+Find bookmarks whose specified fields contain the given keywords.
-Format: `delete INDEX`
+`find` helps you to find bookmarks whose specified fields contain the given keywords. You can use this when you
+want to filter out certain bookmarks from your large list of bookmarks. `find` allows you to search for bookmarks
+using the title, author, genre and/or tags of a bookmark.
+
+
:bulb: **Tip:**
+You can use the `list` command to get back the bookmarks that you have filtered out after `find`.
+
+
+Format: `find [n/TITLE] [a/AUTHOR] [g/GENRE] [t/TAG]…`
+
+* At least one of the optional fields must be provided.
+* The search for name and author is case-insensitive. e.g. `rankers` will match `Rankers`
+* The search for genre and tag is case-sensitive. e.g. `fantasy` will not match `Fantasy`
+* The valid values for each item is the same as the [`add` command](#adding-a-bookmark-add).
+* The order of the keywords matter. e.g. `Guide Rankers` will not match `Rankers Guide`
+* Only the fields of the specified prefixes are searched.
+* Only full words will be matched e.g. `Ranker` will not match `Ranker's`.
+* The search for tags will return any bookmark that has a tag that matches the given tag.
+* If multiple tags are provided, any bookmarks containing at least one of the tags would be returned.
+
+[Back to Table of Contents](#table-of-contents)
+
+
+Examples:
+* `find n/ranker's g/Fantasy` returns `Ranker's Guide to an Ordinary Life` that has the genre `Fantasy`
+* `find n/Chainsaw Man` after `list` returns `chainsaw man` and `Chainsaw Man` as shown in figure 1 below.
+
+
+
+ Figure 1
+
+ : Executing find after start up
+
+
+
+### Listing all bookmarks/ Resetting filters : `list`
+
+Shows a list of all bookmarks in the library.
+
+
:bulb: **Tip:**
+Use this command to get back the original list of bookmarks after using `find` command to filter out bookmarks.
+
+
+Format: `list`
+
+[Back to Table of Contents](#table-of-contents)
+
+
+### Viewing a bookmark's details : `view`
-* Deletes the person at the specified `INDEX`.
-* The index refers to the index number shown in the displayed person list.
+Display details of Bookmark on the right side panel.
+
+Format: `view INDEX`
+
+* gets bookmark at the specified `INDEX` and displays its details.
+* The index refers to the index number shown in the displayed bookmark list.
* The index **must be a positive integer** 1, 2, 3, …
Examples:
-* `list` followed by `delete 2` deletes the 2nd person in the address book.
-* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command.
+* `list` followed by `view 2` displays the 2nd bookmark in the library as shown in figure 2 below.
+* `find n/Chainsaw Man` followed by `goto 1` displays 1st bookmark in the results of the `find` command.
+
+
+
+
+
+ Figure 2
+
+ : Executing view after list
+
+
+
:bulb: **Tip:**
+Our Application also supports this feature in GUI format, simply click onto the bookmark you want and watch the magic happen.
+But do note that there will not be a response in result box since this is not a CLI command.
+
+
+[Back to Table of Contents](#table-of-contents)
+
+
+### Going to a url : `goto`
+
+Opens up specified bookmark's url in default browser
+
+Format: `goto INDEX`
+
+* Opens the url of bookmark at the specified `INDEX`.
+* The index refers to the index number shown in the displayed bookmark list.
+* The index **must be a positive integer** 1, 2, 3, …
+
+Examples:
+* `list` followed by `goto 2` opens up the url of 2nd bookmark in the library.
+* `find n/Chainsaw Man` followed by `goto 1` opens url of the 1st bookmark in the results of the `find` command.
+
+
:bulb: **Tip:**
+Our Application also supports this feature in GUI format, clicking on the url in the right panel will open it on your default browser .
+But do note that there will not be a response in result box since this is not a CLI command.
+
### Clearing all entries : `clear`
-Clears all entries from the address book.
+Clears all bookmark entries from the MyLib. You will still keep your list of genres and tags after using the `clear` command.
Format: `clear`
+[Back to Table of Contents](#table-of-contents)
+
+
+### Viewing help : `help`
+
+Shows a message explaning how to access the help page.
+
+
+
+Format: `help`
+
+
### Exiting the program : `exit`
Exits the program.
@@ -157,37 +454,85 @@ Format: `exit`
### Saving the data
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+MyLib data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
### Editing the data file
-AddressBook data are saved as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+MyLib data are saved as a JSON file `[JAR file location]/data/library.json`. Advanced users are welcome to update data directly by editing that data file.
:exclamation: **Caution:**
-If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run.
+If your changes to the data file makes its format invalid, MyLib will discard all data and start with an empty data file at the next run.
+[Back to Table of Contents](#table-of-contents)
+
+
### Archiving data files `[coming in v2.0]`
_Details coming soon ..._
--------------------------------------------------------------------------------------------------------------------
-## FAQ
+
+## **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 AddressBook home 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 MyLib home folder.
+
+**Q**: Do I need an internet connection to run MyLib?
+**A**: No, MyLib can boot up and run all functionalities without an internet connection.
+
+**Q**: Can I use MyLib on my mobile device?
+**A**: Unfortunately, MyLib is only designed to run on your desktop/laptop such that you can use the command line interface.
--------------------------------------------------------------------------------------------------------------------
-## Command summary
+[Back to Table of Contents](#table-of-contents)
+
+
+## **Command summary**
-Action | Format, Examples
+ Action | Format, Examples
--------|------------------
-**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`
+**Add a bookmark** | `add n/TITLE g/GENRE [a/AUTHOR] [p/PROGRESS] [r/RATING] [u/URL] [t/TAG]…` e.g., `add n/The Odyssey 2 a/Homer p/1 ~ 32 g/Others t/Literature`
+**Clear bookmarks** | `clear`
+**Delete a bookmark** | `delete INDEX` e.g., `delete 3`
+**Edit a bookmark** | `edit INDEX [n/TITLE] [a/AUTHOR] [p/PROGRESS] [g/GENRE] [r/RATING] [u/URL] [t/TAG]…` e.g.,`edit 1 n/Hobbit a/J. R. R. Tolkien`
+**Find bookmarks** | `find [n/TITLE] [a/AUTHOR] [g/GENRE] [t/TAG]…` e.g., `find n/ Chainsaw Man`
+**GoTo url of bookmark** | `goto INDEX` e.g., `goto 3`
+**List all bookmarks** | `list`
+**Sort bookmark by ratings** | `sort [ORDER]` e.g., `sort asc`, `sort desc`
+**Help** | `help`
+**List all tags** | `tags`
+**Add a tag** | `addtag [t/TAG]…` e.g., `addtag t/Novel`
+**Delete a tag** | `dtag TAGNAME` e.g., `dtag MaleProtagonist`
+**List all genres** | `genre`
+
+## **Parameters Summary**
+
+| Prefix | Parameter | Description |
+|:---------:|:---------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `n/` | TITLE | This is the title that you want to give to the bookmark. Usually, this is the name of the content the bookmark is tracking.
**Restrictions:** The title can contain any characters be it alphabets, numbers or symbols.
❗ **Caution**: certain non-English alphabets or symbols may not display correctly in the application.
|
+| `a/` | AUTHOR | This is the author of the content the bookmark is tracking.
**Restrictions:** The title can contain any characters be it alphabets, numbers or symbols.
❗ **Caution**: certain non-English alphabets or symbols may not display correctly in the application.
|
+| `p/` | PROGRESS | This is used to remember your progress with the content being tracked by this bookmark. For example, if the bookmark is tracking a novel, the progress can be used to denote the latest read chapter.
PROGRESS should have the format: `VOLUME CHAPTER PAGE`.
`VOLUME`, `CHAPTER` and `PAGE` should either be a positive number (without +) or `~`. `~` is used to denote an empty `VOLUME`, `CHAPTER` and `PAGE`. For example, if you only want to use `CHAPTER` to track your progress you would do: `~ CHAPTER ~`. At least one of `VOLUME`, `CHAPTER` and `PAGE` must not be `~`. |
+| `p/` | PROGRESS | This is used to remember your progress with the content being tracked by this bookmark. For example, if the bookmark is tracking a novel, the progress can be used to denote the latest read chapter.
**Restrictions:** PROGRESS should have the format: `VOLUME CHAPTER PAGE`.
`VOLUME`, `CHAPTER` and `PAGE` should either be a positive number (without +) or `~`.
`~` is used to denote an empty `VOLUME`, `CHAPTER` and `PAGE`. For example, if you only want to use `CHAPTER` to track your progress you would do: `~ CHAPTER ~`. At least one of `VOLUME`, `CHAPTER` and `PAGE` must not be `~`. |
+| `g/` | GENRE | The genre of the content the bookmark is tracking.
**Restrictions:** MyLib provides a fixed list of genres. Only genres in that list can be used as the genre of a bookmark. To find out more about this list, go to the [Genres](#genres) section. |
+| `u/` | URL | This is the url to the website containing the bookmarked content.
**Restrictions:** Must contain [Protocol][Domain name] for example: [http://]www.[example.com] |
+| `r/` | RATING | This is the rating to give the bookmark.
**Restrictions:** Must be a number from 0 to 5 (without any additional symbols like +/-) |
+| `t/` | TAG | This is a tag that you want to attach to the bookmark.
**Restrictions:** Only tags that are in your tag list can be added to a bookmark. For more information on how to modify your tag list, go to the [Tags](#tags) section. |
+
+[Back to Table of Contents](#table-of-contents)
+
+
+## **Glossary**
+
+| Term | Explanation |
+|:------------------------:|:----------------------------------------------------------------------------------------------------------------------------------:|
+| Command Line Interface | A text-based user interface used to run programs and interact with the computer by typing in textual commands |
+| Graphical User Interface | interface that uses icons, menus and a mouse (to click on the icon or pull down the menus) to manage interaction with the system |
+| Terminal | Text-based interface used to interact with the computer's operating system |
+| Parameter | A named value that is passed in by the user. This value changes depending on what the user enters. |
+| Hard disk | A data storage device that maintain stored data when computer is turned off |
+| Bookmark | The type of data being tracked by our app, It contains a compulsory TITLE and GENRE associated to it and other optional Parameters |
+
+[Back to Table of Contents](#table-of-contents)
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..3aeef0b812a 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "MyLib"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2223S2-CS2103T-T13-4/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..fefa28d7117 100644
--- a/docs/_sass/minima/_base.scss
+++ b/docs/_sass/minima/_base.scss
@@ -288,7 +288,7 @@ table {
text-align: center;
}
.site-header:before {
- content: "AB-3";
+ content: "MyLib";
font-size: 32px;
}
}
diff --git a/docs/_sass/minima/_layout.scss b/docs/_sass/minima/_layout.scss
index ca99f981701..f74ddfee89d 100644
--- a/docs/_sass/minima/_layout.scss
+++ b/docs/_sass/minima/_layout.scss
@@ -261,3 +261,8 @@
width: calc(50% - (#{$spacing-unit} / 2));
}
}
+
+img[src*='#center'] {
+ display: block;
+ margin: auto;
+}
diff --git a/docs/diagrams/AddSequenceDiagram.puml b/docs/diagrams/AddSequenceDiagram.puml
new file mode 100644
index 00000000000..e3298c4af34
--- /dev/null
+++ b/docs/diagrams/AddSequenceDiagram.puml
@@ -0,0 +1,87 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":LibaryParser" as LibraryParser LOGIC_COLOR
+participant ":AddCommandParser" as AddCommandParser LOGIC_COLOR
+participant "a:AddCommand" as AddCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+participant ":Bookmark" as Bookmark MODEL_COLOR
+end box
+
+note left of LogicManager
+Let {input} be
+"n/Solo Leveling
+a/Chugong
+p/~ 110 ~
+r/4
+g/Fantasy
+t/Hero"
+end note
+
+[-> LogicManager : execute("add {input}")
+activate LogicManager
+
+LogicManager -> LibraryParser : parseCommand("add {input}")
+activate LibraryParser
+
+create AddCommandParser
+LibraryParser -> AddCommandParser
+activate AddCommandParser
+
+AddCommandParser --> LibraryParser
+deactivate AddCommandParser
+
+LibraryParser -> AddCommandParser : parse("{input}")
+activate AddCommandParser
+
+create Bookmark
+AddCommandParser -> Bookmark
+activate Bookmark
+
+Bookmark --> AddCommandParser : newBookmark
+deactivate Bookmark
+
+create AddCommand
+AddCommandParser -> AddCommand
+activate AddCommand
+
+AddCommand --> AddCommandParser : a
+deactivate AddCommand
+
+AddCommandParser --> LibraryParser : a
+deactivate AddCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+AddCommandParser -[hidden]-> LibraryParser
+destroy AddCommandParser
+
+LibraryParser --> LogicManager : a
+deactivate LibraryParser
+
+LogicManager -> AddCommand : execute()
+activate AddCommand
+
+AddCommand -> Model : addBookmark(newBookmark)
+activate Model
+
+Model --> AddCommand
+deactivate Model
+
+create CommandResult
+AddCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> AddCommand
+deactivate CommandResult
+
+AddCommand --> LogicManager : result
+deactivate AddCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..dadce33b667 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -13,13 +13,13 @@ 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 : deleteBookmark(b)
activate model MODEL_COLOR
model -[MODEL_COLOR]-> logic
deactivate model
-logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook)
+logic -[LOGIC_COLOR]> storage : saveLibrary(library)
activate storage STORAGE_COLOR
storage -[STORAGE_COLOR]> storage : Save to file
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 598474a5c82..f9be657143d 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -4,18 +4,20 @@ skinparam arrowThickness 1.1
skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
-AddressBook *-right-> "1" UniquePersonList
-AddressBook *-right-> "1" UniqueTagList
-UniqueTagList -[hidden]down- UniquePersonList
-UniqueTagList -[hidden]down- UniquePersonList
+Library *-right-> "1" UniqueBookmarkList
+Library *-right-> "1" UniqueTagList
+UniqueBookmarkList -[hidden]down- UniqueBookmarkList
+UniqueTagList -[hidden]down- UniqueBookmarkList
UniqueTagList -right-> "*" Tag
-UniquePersonList -right-> Person
+UniqueBookmarkList -right-> Bookmark
-Person -up-> "*" Tag
+Bookmark -up-> "*" Tag
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
+Bookmark *--> Title
+Bookmark *--> Author
+Bookmark *--> Progress
+Bookmark *--> Genre
+Bookmark *--> URL
+Bookmark *--> Rating
@enduml
diff --git a/docs/diagrams/CommitActivityDiagram.puml b/docs/diagrams/CommitActivityDiagram.puml
index 6a6b23a006f..d6d15eb58a4 100644
--- a/docs/diagrams/CommitActivityDiagram.puml
+++ b/docs/diagrams/CommitActivityDiagram.puml
@@ -1,14 +1,18 @@
@startuml
+!include style.puml
+skinparam activity {
+BackgroundColor #FFFFD0
+}
start
:User executes command;
'Since the beta syntax does not support placing the condition outside the
'diamond we place it as the true branch instead.
-if () then ([command commits AddressBook])
+if () then ([command commits Library])
:Purge redundant states;
- :Save AddressBook to
- addressBookStateList;
+ :Save Library to
+ libraryStateList;
else ([else])
endif
stop
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 1dc2311b245..3afe48419e0 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -3,7 +3,7 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":LibaryParser" as LibraryParser LOGIC_COLOR
participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
participant ":CommandResult" as CommandResult LOGIC_COLOR
@@ -13,20 +13,20 @@ box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
end box
-[-> LogicManager : execute("delete 1")
+[-> LogicManager : execute("del 1")
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand("delete 1")
-activate AddressBookParser
+LogicManager -> LibraryParser : parseCommand("del 1")
+activate LibraryParser
create DeleteCommandParser
-AddressBookParser -> DeleteCommandParser
+LibraryParser -> DeleteCommandParser
activate DeleteCommandParser
-DeleteCommandParser --> AddressBookParser
+DeleteCommandParser --> LibraryParser
deactivate DeleteCommandParser
-AddressBookParser -> DeleteCommandParser : parse("1")
+LibraryParser -> DeleteCommandParser : parse("1")
activate DeleteCommandParser
create DeleteCommand
@@ -36,19 +36,19 @@ activate DeleteCommand
DeleteCommand --> DeleteCommandParser : d
deactivate DeleteCommand
-DeleteCommandParser --> AddressBookParser : d
+DeleteCommandParser --> LibraryParser : d
deactivate DeleteCommandParser
'Hidden arrow to position the destroy marker below the end of the activation bar.
-DeleteCommandParser -[hidden]-> AddressBookParser
+DeleteCommandParser -[hidden]-> LibraryParser
destroy DeleteCommandParser
-AddressBookParser --> LogicManager : d
-deactivate AddressBookParser
+LibraryParser --> LogicManager : d
+deactivate LibraryParser
LogicManager -> DeleteCommand : execute()
activate DeleteCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteCommand -> Model : deleteBookmark(1)
activate Model
Model --> DeleteCommand
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index d4193173e18..b79951db179 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -6,7 +6,7 @@ skinparam classBackgroundColor LOGIC_COLOR
package Logic {
-Class AddressBookParser
+Class LibraryParser
Class XYZCommand
Class CommandResult
Class "{abstract}\nCommand" as Command
@@ -27,8 +27,8 @@ Class HiddenOutside #FFFFFF
HiddenOutside ..> Logic
LogicManager .right.|> Logic
-LogicManager -right->"1" AddressBookParser
-AddressBookParser ..> XYZCommand : creates >
+LogicManager -right->"1" LibraryParser
+LibraryParser ..> XYZCommand : creates >
XYZCommand -up-|> Command
LogicManager .left.> Command : executes >
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 4439108973a..81a2a703ee2 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -5,46 +5,50 @@ skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
Package Model <>{
-Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook
+Class "<>\nReadOnlyLibrary" as ReadOnlyLibrary
Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs
-Class "<>\nModel" as Model
-Class AddressBook
+Class "<>\nModel" as Model1
+Class Library
Class ModelManager
Class UserPrefs
-Class UniquePersonList
-Class Person
-Class Address
-Class Email
-Class Name
-Class Phone
+Class UniqueBookmarkList
+Class Bookmark
+Class Genre
+Class Progress
+Class Title
+Class Author
Class Tag
+Class URL
+class Rating
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> Model
+HiddenOutside ..> Model1
-AddressBook .up.|> ReadOnlyAddressBook
+Library .up.|> ReadOnlyLibrary
-ModelManager .up.|> Model
-Model .right.> ReadOnlyUserPrefs
-Model .left.> ReadOnlyAddressBook
-ModelManager -left-> "1" AddressBook
+ModelManager .up.|> Model1
+Model1 .right.> ReadOnlyUserPrefs
+Model1 .left.> ReadOnlyLibrary
+ModelManager -left-> "1" Library
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
-
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
-
-ModelManager -->"~* filtered" Person
+Library *--> "1" UniqueBookmarkList
+UniqueBookmarkList --> "~* all" Bookmark
+Bookmark *--> Title
+Bookmark *--> Author
+Bookmark *--> Genre
+Bookmark *--> Progress
+Bookmark *--> "*" Tag
+Bookmark *--> URL
+Bookmark *--> Rating
+
+Title -[hidden]right-> Author
+Author -[hidden]right-> Genre
+Genre -[hidden]right-> Progress
+
+ModelManager -->"~* filtered" Bookmark
@enduml
diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml
index 0c7424de6e0..efde4561c70 100644
--- a/docs/diagrams/ParserClasses.puml
+++ b/docs/diagrams/ParserClasses.puml
@@ -9,7 +9,7 @@ Class XYZCommand
package "Parser classes"{
Class "<>\nParser" as Parser
-Class AddressBookParser
+Class LibraryParser
Class XYZCommandParser
Class CliSyntax
Class ParserUtil
@@ -19,12 +19,12 @@ Class Prefix
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> AddressBookParser
+HiddenOutside ..> LibraryParser
-AddressBookParser .down.> XYZCommandParser: creates >
+LibraryParser .down.> XYZCommandParser: creates >
XYZCommandParser ..> XYZCommand : creates >
-AddressBookParser ..> Command : returns >
+LibraryParser ..> Command : returns >
XYZCommandParser .up.|> Parser
XYZCommandParser ..> ArgumentMultimap
XYZCommandParser ..> ArgumentTokenizer
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 760305e0e58..5e611e24d71 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -14,11 +14,11 @@ Class JsonUserPrefsStorage
Class "<>\nStorage" as Storage
Class StorageManager
-package "AddressBook Storage" #F4F6F6{
-Class "<>\nAddressBookStorage" as AddressBookStorage
-Class JsonAddressBookStorage
-Class JsonSerializableAddressBook
-Class JsonAdaptedPerson
+package "Library Storage" #F4F6F6{
+Class "<>\nLibraryStorage" as LibraryStorage
+Class JsonLibraryStorage
+Class JsonSerializableLibrary
+Class JsonAdaptedBookmark
Class JsonAdaptedTag
}
@@ -29,15 +29,15 @@ HiddenOutside ..> Storage
StorageManager .up.|> Storage
StorageManager -up-> "1" UserPrefsStorage
-StorageManager -up-> "1" AddressBookStorage
+StorageManager -up-> "1" LibraryStorage
Storage -left-|> UserPrefsStorage
-Storage -right-|> AddressBookStorage
+Storage -right-|> LibraryStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
-JsonAddressBookStorage .up.|> AddressBookStorage
-JsonAddressBookStorage ..> JsonSerializableAddressBook
-JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonLibraryStorage .up.|> LibraryStorage
+JsonLibraryStorage ..> JsonSerializableLibrary
+JsonSerializableLibrary --> "*" JsonAdaptedBookmark
+JsonAdaptedBookmark --> "*" JsonAdaptedTag
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..1cec9e4167c 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -11,10 +11,11 @@ Class UiManager
Class MainWindow
Class HelpWindow
Class ResultDisplay
-Class PersonListPanel
-Class PersonCard
+Class BookmarkListPanel
+Class BookmarkCard
Class StatusBarFooter
Class CommandBox
+Class ZoomView
}
package Model <> {
@@ -30,28 +31,32 @@ HiddenOutside ..> Ui
UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
+MainWindow *-> "1" ZoomView
MainWindow *-down-> "1" CommandBox
MainWindow *-down-> "1" ResultDisplay
-MainWindow *-down-> "1" PersonListPanel
+MainWindow *-down-> "1" BookmarkListPanel
MainWindow *-down-> "1" StatusBarFooter
+
MainWindow --> "0..1" HelpWindow
-PersonListPanel -down-> "*" PersonCard
+
+BookmarkListPanel -down-> "*" BookmarkCard
MainWindow -left-|> UiPart
ResultDisplay --|> UiPart
CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
+BookmarkListPanel --|> UiPart
+BookmarkCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
+ZoomView --|> UiPart
-PersonCard ..> Model
+BookmarkCard ..> Model
UiManager -right-> Logic
MainWindow -left-> Logic
-PersonListPanel -[hidden]left- HelpWindow
+BookmarkListPanel -[hidden]left- HelpWindow
HelpWindow -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml
index 96e30744d24..10e689fb8ef 100644
--- a/docs/diagrams/UndoRedoState0.puml
+++ b/docs/diagrams/UndoRedoState0.puml
@@ -3,18 +3,19 @@
skinparam ClassFontColor #000000
skinparam ClassBorderColor #000000
-title Initial state
+title After command "clear" state
package States {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "lib0:Library"#FFFFD0
+ class State2 as "lib1:Library"#FFFFD0
+ class State3 as "lib2:Library"#FFFFD0
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-hide State2
-hide State3
-class Pointer as "Current State" #FFFFF
-Pointer -up-> State1
+
+
+class Pointer as "Current State" #FFFFFF
+Pointer -up-> State3
+note right on link: State lib2 deleted.
@end
diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml
index 01fcb9b2b96..0e2c8c72d33 100644
--- a/docs/diagrams/UndoRedoState1.puml
+++ b/docs/diagrams/UndoRedoState1.puml
@@ -16,7 +16,7 @@ State2 -[hidden]right-> State3
hide State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml
index bccc230a5d1..0ce7073e187 100644
--- a/docs/diagrams/UndoRedoState2.puml
+++ b/docs/diagrams/UndoRedoState2.puml
@@ -14,7 +14,7 @@ package States <> {
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State3
@end
diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml
index ea29c9483e4..50bf43b3f34 100644
--- a/docs/diagrams/UndoRedoState3.puml
+++ b/docs/diagrams/UndoRedoState3.puml
@@ -14,7 +14,7 @@ package States <> {
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml
index 1b784cece80..83cbe4c740c 100644
--- a/docs/diagrams/UndoRedoState4.puml
+++ b/docs/diagrams/UndoRedoState4.puml
@@ -14,7 +14,7 @@ package States <> {
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml
index 88927be32bc..fc89dd99d2d 100644
--- a/docs/diagrams/UndoRedoState5.puml
+++ b/docs/diagrams/UndoRedoState5.puml
@@ -14,7 +14,7 @@ package States <> {
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State3
note right on link: State ab2 deleted.
diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml
index 410aab4e412..29714e2352a 100644
--- a/docs/diagrams/UndoSequenceDiagram.puml
+++ b/docs/diagrams/UndoSequenceDiagram.puml
@@ -3,42 +3,42 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":LibraryParser" as LibraryParser LOGIC_COLOR
participant "u:UndoCommand" as UndoCommand LOGIC_COLOR
end box
box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
-participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR
+participant ":VersionedLibrary" as VersionedLibrary MODEL_COLOR
end box
[-> LogicManager : execute(undo)
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand(undo)
-activate AddressBookParser
+LogicManager -> LibraryParser : parseCommand(undo)
+activate LibraryParser
create UndoCommand
-AddressBookParser -> UndoCommand
+LibraryParser -> UndoCommand
activate UndoCommand
-UndoCommand --> AddressBookParser
+UndoCommand --> LibraryParser
deactivate UndoCommand
-AddressBookParser --> LogicManager : u
-deactivate AddressBookParser
+LibraryParser --> LogicManager : u
+deactivate LibraryParser
LogicManager -> UndoCommand : execute()
activate UndoCommand
-UndoCommand -> Model : undoAddressBook()
+UndoCommand -> Model : undoLibrry()
activate Model
-Model -> VersionedAddressBook : undo()
-activate VersionedAddressBook
+Model -> VersionedLibrary: undo()
+activate VersionedLibrary
-VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook)
-VersionedAddressBook --> Model :
-deactivate VersionedAddressBook
+VersionedLibrary -> VersionedLibrary :resetData(ReadOnlyLibrary)
+VersionedLibrary --> Model :
+deactivate VersionedLibrary
Model --> UndoCommand
deactivate Model
diff --git a/docs/diagrams/tracing/LogicSequenceDiagram.puml b/docs/diagrams/tracing/LogicSequenceDiagram.puml
index fdcbe1c0ccc..a0498898e2e 100644
--- a/docs/diagrams/tracing/LogicSequenceDiagram.puml
+++ b/docs/diagrams/tracing/LogicSequenceDiagram.puml
@@ -2,7 +2,7 @@
!include ../style.puml
Participant ":LogicManager" as logic LOGIC_COLOR
-Participant ":AddressBookParser" as abp LOGIC_COLOR
+Participant ":LibraryParser" as abp LOGIC_COLOR
Participant ":EditCommandParser" as ecp LOGIC_COLOR
Participant "command:EditCommand" as ec LOGIC_COLOR
@@ -13,7 +13,7 @@ create ecp
abp -> ecp
abp -> ecp ++: parse(arguments)
create ec
-ecp -> ec ++: index, editPersonDescriptor
+ecp -> ec ++: index, editBookmarkDescriptor
ec --> ecp --
ecp --> abp --: command
abp --> logic --: command
diff --git a/docs/images/AddSequenceDiagram.png b/docs/images/AddSequenceDiagram.png
new file mode 100644
index 00000000000..4072da03ad4
Binary files /dev/null and b/docs/images/AddSequenceDiagram.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..db420b9e41f 100644
Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
index 94440f0ac4a..8e678858c1a 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/CommitActivityDiagram.png b/docs/images/CommitActivityDiagram.png
index c08c13f5c8b..9f62e99b327 100644
Binary files a/docs/images/CommitActivityDiagram.png and b/docs/images/CommitActivityDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index fa327b39618..4629941ef3b 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/GoToActivityDiagram.png b/docs/images/GoToActivityDiagram.png
new file mode 100644
index 00000000000..f302293aff3
Binary files /dev/null and b/docs/images/GoToActivityDiagram.png differ
diff --git a/docs/images/GoToSequenceDiagram.png b/docs/images/GoToSequenceDiagram.png
new file mode 100644
index 00000000000..618b995b43b
Binary files /dev/null and b/docs/images/GoToSequenceDiagram.png differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index 9e9ba9f79e5..4a12692aaa4 100644
Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index 04070af60d8..4e9af4ea2e4 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/MyLibLogo.png b/docs/images/MyLibLogo.png
new file mode 100644
index 00000000000..f81e8fc90a1
Binary files /dev/null and b/docs/images/MyLibLogo.png differ
diff --git a/docs/images/ParserClasses.png b/docs/images/ParserClasses.png
index e7b4c8880cd..f18d8e373e9 100644
Binary files a/docs/images/ParserClasses.png and b/docs/images/ParserClasses.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 2533a5c1af0..fd7ea971217 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..8b5e4879d63 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 785e04dbab4..367037cdfae 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png
index 8f7538cd884..ccc5e380288 100644
Binary files a/docs/images/UndoRedoState0.png and b/docs/images/UndoRedoState0.png differ
diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png
index df9908d0948..36cee543cf8 100644
Binary files a/docs/images/UndoRedoState1.png and b/docs/images/UndoRedoState1.png differ
diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png
index 36519c1015b..9e53448519d 100644
Binary files a/docs/images/UndoRedoState2.png and b/docs/images/UndoRedoState2.png differ
diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png
index 19959d01712..a10c388155b 100644
Binary files a/docs/images/UndoRedoState3.png and b/docs/images/UndoRedoState3.png differ
diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png
index 4c623e4f2c5..e50b184322f 100644
Binary files a/docs/images/UndoRedoState4.png and b/docs/images/UndoRedoState4.png differ
diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png
index 84ad2afa6bd..d7864cbc263 100644
Binary files a/docs/images/UndoRedoState5.png and b/docs/images/UndoRedoState5.png differ
diff --git a/docs/images/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png
index 6addcd3a8d9..666ead02294 100644
Binary files a/docs/images/UndoSequenceDiagram.png and b/docs/images/UndoSequenceDiagram.png differ
diff --git a/docs/images/View-command.png b/docs/images/View-command.png
new file mode 100644
index 00000000000..f85b1e1c4ea
Binary files /dev/null and b/docs/images/View-command.png differ
diff --git a/docs/images/Wong-Jia-Jun.png b/docs/images/Wong-Jia-Jun.png
new file mode 100644
index 00000000000..a2f718cb0af
Binary files /dev/null and b/docs/images/Wong-Jia-Jun.png differ
diff --git a/docs/images/add-tag.png b/docs/images/add-tag.png
new file mode 100644
index 00000000000..4441f1147b6
Binary files /dev/null and b/docs/images/add-tag.png differ
diff --git a/docs/images/annotated-UI.png b/docs/images/annotated-UI.png
new file mode 100644
index 00000000000..8d939066d2e
Binary files /dev/null and b/docs/images/annotated-UI.png differ
diff --git a/docs/images/bookmarkCardUI.png b/docs/images/bookmarkCardUI.png
new file mode 100644
index 00000000000..c9c59add6d0
Binary files /dev/null and b/docs/images/bookmarkCardUI.png differ
diff --git a/docs/images/chapter.png b/docs/images/chapter.png
new file mode 100644
index 00000000000..96c85c54c01
Binary files /dev/null and b/docs/images/chapter.png differ
diff --git a/docs/images/edit-0.png b/docs/images/edit-0.png
new file mode 100644
index 00000000000..12c4f7a5802
Binary files /dev/null and b/docs/images/edit-0.png differ
diff --git a/docs/images/edit-8.png b/docs/images/edit-8.png
new file mode 100644
index 00000000000..7902e75c01f
Binary files /dev/null and b/docs/images/edit-8.png differ
diff --git a/docs/images/find-chainsaw man.png b/docs/images/find-chainsaw man.png
new file mode 100644
index 00000000000..86f43d9cf79
Binary files /dev/null and b/docs/images/find-chainsaw man.png differ
diff --git a/docs/images/genres.png b/docs/images/genres.png
new file mode 100644
index 00000000000..3336e69fab1
Binary files /dev/null and b/docs/images/genres.png differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
index b1f70470137..07ab2fc7f04 100644
Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ
diff --git a/docs/images/noyaroet.png b/docs/images/noyaroet.png
new file mode 100644
index 00000000000..6924722ec39
Binary files /dev/null and b/docs/images/noyaroet.png differ
diff --git a/docs/images/page.png b/docs/images/page.png
new file mode 100644
index 00000000000..89906dec5eb
Binary files /dev/null and b/docs/images/page.png differ
diff --git a/docs/images/volume.png b/docs/images/volume.png
new file mode 100644
index 00000000000..8e26c3a372f
Binary files /dev/null and b/docs/images/volume.png differ
diff --git a/docs/images/wong-jia-jun.png b/docs/images/wong-jia-jun.png
new file mode 100644
index 00000000000..a2f718cb0af
Binary files /dev/null and b/docs/images/wong-jia-jun.png differ
diff --git a/docs/images/wongyx.png b/docs/images/wongyx.png
new file mode 100644
index 00000000000..b77c40d233a
Binary files /dev/null and b/docs/images/wongyx.png differ
diff --git a/docs/images/zenithyap.png b/docs/images/zenithyap.png
new file mode 100644
index 00000000000..bf47bbe031c
Binary files /dev/null and b/docs/images/zenithyap.png differ
diff --git a/docs/images/zhoyx.png b/docs/images/zhoyx.png
new file mode 100644
index 00000000000..8466079e305
Binary files /dev/null and b/docs/images/zhoyx.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..5e3a841ab09 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,6 +1,6 @@
---
layout: page
-title: AddressBook Level-3
+title: MyLib
---
[](https://github.com/se-edu/addressbook-level3/actions)
@@ -8,10 +8,10 @@ title: AddressBook Level-3

-**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+MyLib is a desktop application originally developed to bookmark webnovels and comics. However, its bookmarking features can accomodate basically any form of content you want to track. While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
-* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
-* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
+* If you are interested in using MyLib, head over to the [**User Guide**](UserGuide.html).
+* If you are interested about developing MyLib, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
diff --git a/docs/team/Wong-Jia-Jun.md b/docs/team/Wong-Jia-Jun.md
new file mode 100644
index 00000000000..d94a32d0db5
--- /dev/null
+++ b/docs/team/Wong-Jia-Jun.md
@@ -0,0 +1,45 @@
+---
+layout: page
+title: Wong-Jia-Jun's Project Portfolio Page
+---
+
+### Project: MyLib
+
+MyLib is a desktop bookmarking application used for keeping track of books a user is reading. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java.
+
+Given below are my contributions to the project.
+
+* **Code Contributed**: [RepoSense hyperlink](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=wong-jia-jun&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17)
+
+* **New Feature**: Added GoTo command functionality. This involves opening url of bookmark in user's default browser [#135](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/135/files), [#184](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/184)
+ * What it does: Opens url of a bookmark in user's browser
+ * Justification: This provides convenience to the user instead of having to copy the url field and pasting after opening a browser
+
+* **New Feature**: Added the View Command functionality [#176](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/176/files)
+ * What it does: Allows the user to view specifics of a bookmark more clearly in a separate panel
+ * Justification: This feature allows users to see more clearly each field of the bookmark as well as longer fields like url which is not present in bookmark on left panel since it may be quite long
+
+* **Enhancements**:
+ * Revamp GUI and add on-click support for some commands [#80](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/80), [#99](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/99/files), [#153](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/153/files), [#160](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/160/files)
+
+* Add Test cases for Code Coverage [#253](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/253/files)
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `view` and `goto` [#195](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/195/files), [#159](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/159), [#135](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/135/files)
+ * Added new pictures for UI, UI components, bookmark details and commands `find` and `view` [#256](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/256/files)
+ * Added Glossary table, GUI components table and Prefix table [#169](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/169/files), [#200](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/200/files)
+ * Added About User Guide
+ * Update FAQ [#184](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/184/files)
+
+ * Developer Guide:
+ * Added implementation details of the `view` and `goto` features. [#135](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/135/files)
+ * Update delete sequence diagram
+ * Add diagrams for `goto` feature [#135](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/135/files)
+ * Update Appendix A Manual Testing [#278](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/278/files)
+ * Add Intended Audience, About MyLib, Using the Guide portion [#178](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/178/files)
+ * Update page breaks for pdf conversion [#337](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/337)
+
+* **Contributions to team-based tasks**
+ * Created release for V1.3
+ * Maintain issue tracker for tasks
diff --git a/docs/team/noyaroet.md b/docs/team/noyaroet.md
new file mode 100644
index 00000000000..17a4e8799d0
--- /dev/null
+++ b/docs/team/noyaroet.md
@@ -0,0 +1,45 @@
+---
+layout: page
+title: Teo Rayon's Project Portfolio Page
+---
+
+### Project: MyLib
+
+MyLib is a desktop bookmarking application used for keeping track of webnovels and comic a user is reading. Its bookmarking features are general enough to perform bookmarking tasks for other things like blogs, articles and basically anything. The user interacts with the application using a CLI, and it has a GUI created with JavaFX. It is written in Java.
+
+Given below are my contributions to the project.
+* **Code Contributed**: [Reposense Link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=CS2103T-T13-4&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17&tabOpen=true&tabType=authorship&tabAuthor=NoyaRoeT&tabRepo=AY2223S2-CS2103T-T13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+* **New Feature**: Added the ability to find bookmarks by title using keywords
+ * What it does: allows the user to find bookmarks whose title contains at least one of the provided keywords.
+ * Justification: this feature improves the product significantly since it allows a user to quickly find a bookmark whose title contains one of the provided keywords. Being able to quickly find a bookmark is an important aspect of any bookmarking application.
+ * Credits: the implementation of this feature made use of existing infrastructure from AB3. Specifically, AB3 already had a feature that allowed finding people whose name contains at least one word in a provided set of keywords. That existing implementation was modified to be used for finding bookmarks instead.
+
+* **New Feature**: Changed most of bookmark data to be optional
+ * What it does: allows the user to omit certain bookmark data when adding bookmarks
+ * Justification: many fields that a bookmark can contain may not be required for bookmarking tasks. For example, some users may not care about the author of a book. Hence, it is more convenient for the user if only certain fields were made compulsory.
+ * Highlights: many issues arose due to the fact that we inherited most of AB3's code, where all the fields in a Person object were compulsory.
+ * The Bookmark class was created by modifying the Person class. It inherited all of Person's test cases which expects all fields to be compulsory. These test cases needed to be tracked down, updated or deleted.
+ * When loading the data for MyLib from json, the conversion from json to a `Bookmark` object expects the fields to be present and non-null. Needed to modify the conversion from json to a Bookmark object to accept optional fields that are not present.
+
+
+* **New Feature**: Added a `Progress` field to a bookmark
+ * What it does: allows a bookmark to track a user's progress with regards to the book being bookmarked.
+ * Justification: one of the goals of our application is to track books the user is reading, so they may revisit the book in the future. Tracking progress allows them to easily see where they last left off with a book and continue from there if they decide to do so.
+ * Highlights: as a field in the Bookmark class which forms the core data of our application, this enhancement will affect all future updates to the application. Hence, it required more thorough considerations of the various design alternatives. These include considerations such as how user input should be represented, how should the interface of the class look like to blend well with the other existing bookmark data, whether there is a need to separate volume, chapter and page which are contained in `Progress` into their own separate classes and how should progress input from the user be parsed and used to construct a `Progress` object. There was also a need to consider how `Progress` is adapted for JSON storage.
+
+* **Contributions to UG**:
+ * Added documentation for Introduction section, which gives a brief overview of what to expect from MyLib.
+ * Added documentation for Getting Started section, which gives a step-by-step guide on how to download and start using MyLib.
+ * Added documentation for About User Guide section, which informs the reader on the objective of the user guide and how to use it.
+ * Added documentation for Key Definitions section to explain what a bookmark, genre and a tag is.
+ * Added documentation for Adding a Bookmark in Commands section.
+
+* **Contributions to DG**:
+ * Added a detailed description of the implementation of the `Progress` class and its related classes.
+ * Added product scope, user stories, use cases, non-functional requirements and glossary.
+
+* **Contributions to team-based tasks**:
+ * Arranged and lead the discussion for project meetings.
+ * Lead the brainstorming and confirmation of features for each iteration.
+ * Set up most of the Github issues that need to be addressed for each milestone.
diff --git a/docs/team/wong-jia-jun.md b/docs/team/wong-jia-jun.md
new file mode 100644
index 00000000000..d94a32d0db5
--- /dev/null
+++ b/docs/team/wong-jia-jun.md
@@ -0,0 +1,45 @@
+---
+layout: page
+title: Wong-Jia-Jun's Project Portfolio Page
+---
+
+### Project: MyLib
+
+MyLib is a desktop bookmarking application used for keeping track of books a user is reading. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java.
+
+Given below are my contributions to the project.
+
+* **Code Contributed**: [RepoSense hyperlink](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=wong-jia-jun&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17)
+
+* **New Feature**: Added GoTo command functionality. This involves opening url of bookmark in user's default browser [#135](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/135/files), [#184](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/184)
+ * What it does: Opens url of a bookmark in user's browser
+ * Justification: This provides convenience to the user instead of having to copy the url field and pasting after opening a browser
+
+* **New Feature**: Added the View Command functionality [#176](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/176/files)
+ * What it does: Allows the user to view specifics of a bookmark more clearly in a separate panel
+ * Justification: This feature allows users to see more clearly each field of the bookmark as well as longer fields like url which is not present in bookmark on left panel since it may be quite long
+
+* **Enhancements**:
+ * Revamp GUI and add on-click support for some commands [#80](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/80), [#99](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/99/files), [#153](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/153/files), [#160](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/160/files)
+
+* Add Test cases for Code Coverage [#253](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/253/files)
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `view` and `goto` [#195](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/195/files), [#159](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/159), [#135](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/135/files)
+ * Added new pictures for UI, UI components, bookmark details and commands `find` and `view` [#256](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/256/files)
+ * Added Glossary table, GUI components table and Prefix table [#169](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/169/files), [#200](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/200/files)
+ * Added About User Guide
+ * Update FAQ [#184](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/184/files)
+
+ * Developer Guide:
+ * Added implementation details of the `view` and `goto` features. [#135](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/135/files)
+ * Update delete sequence diagram
+ * Add diagrams for `goto` feature [#135](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/135/files)
+ * Update Appendix A Manual Testing [#278](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/278/files)
+ * Add Intended Audience, About MyLib, Using the Guide portion [#178](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/178/files)
+ * Update page breaks for pdf conversion [#337](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/337)
+
+* **Contributions to team-based tasks**
+ * Created release for V1.3
+ * Maintain issue tracker for tasks
diff --git a/docs/team/wongyx.md b/docs/team/wongyx.md
new file mode 100644
index 00000000000..c44d4fa6c00
--- /dev/null
+++ b/docs/team/wongyx.md
@@ -0,0 +1,29 @@
+---
+layout: page
+title: Wong Yong Xiang's Project Portfolio Page
+---
+
+### Project: MyLib
+
+MyLib is a desktop bookmarking application used for keeping track of books a user is reading. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java.
+
+Given below are my contributions to the project.
+
+* **Code Contributed**: [RepoSense hyperlink](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=wongyx&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17&tabOpen=true&tabType=authorship&zFR=false&tabAuthor=wongyx&tabRepo=AY2223S2-CS2103T-T13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+* **New Feature**: Add the ability for users to find bookmarks using multiple optional fields.
+ * What it does: Provide users with a more efficient way of searching for bookmarks.
+ * Justification: This provides convenience for the users.
+
+* **Enhancement to existing features**:
+ * Updated Title to only accept up to 180 characters.
+ * Updated BookmarkContainsPredicate to accept name, genre, tags, and author.
+
+* Added test cases to increase code coverage. (Pull request [\#276](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/276))
+
+* **Documentation**:
+ * User Guide:
+ * Updated documentations of feature `find`. (Pull request [\#145](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/145))
+ * Updated examples commands for `add` to fix inconsistency between UG and the app itself. (Pull request [\#252](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/252))
+ * Developer Guide:
+ * Added implementation details of `find`.
diff --git a/docs/team/zenithyap.md b/docs/team/zenithyap.md
new file mode 100644
index 00000000000..c550f8ce24e
--- /dev/null
+++ b/docs/team/zenithyap.md
@@ -0,0 +1,33 @@
+---
+layout: page
+title: Zenith's Project Portfolio Page
+---
+
+### Project: MyLib
+
+MyLib is a desktop bookmarking application used for keeping track of books a user is reading. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java.
+
+Given below are my contributions to the project.
+
+* **Code Contributed**: [RepoSense hyperlink](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=zenithyap&breakdown=true&sort=groupTitle%20dsc&sortWithin=title&since=2023-02-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&tabType=authorship&tabAuthor=zenithyap&tabRepo=AY2223S2-CS2103T-T13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+* **New Feature**: Added extra tags functionality. This includes, adding a tag to the tag list, deleting a tag from the tag list and listing all tags from the tag list.
+ * What it does: Provides the user with a personalized tag list.
+ * Justification: This provides a more consistent of the usage of tagging, to reduce errors such as typo errors.
+ * Highlights: This enhancement required the addition of several new functionalities as well as the need to store the tag list in a json file, which was quite challenging.
+
+* **New Feature**: Added the ability to sort bookmarks by rating.
+ * What it does: Allows the user to sort the bookmarks by rating in either ascending or descending order.
+ * Justification: This feature improves the user's ability to manage the bookmarks as the user may have many different bookmarks and the app should provide a way of sorting the bookmarks.
+
+* **Enhancements to existing features**:
+ * Changed the naming of the codebase to fit our application (Pull request [\#65](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/65))
+
+* Added test cases to increase code coverage [\#270](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/270) [\#280](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/280)
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `addtag`, `dtag`, and `tags` [\#159](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/159)
+ * Added documentation for the feature `sort` [\#190](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/190)
+ * Developer Guide:
+ * Added implementation details of the `addtag`, `dtag`, and `tags` features.
diff --git a/docs/team/zhoyx.md b/docs/team/zhoyx.md
new file mode 100644
index 00000000000..82f644ba4e4
--- /dev/null
+++ b/docs/team/zhoyx.md
@@ -0,0 +1,49 @@
+---
+layout: page
+title: Zhou Yuxin's Project Portfolio Page
+---
+
+### Project: MyLib
+
+MyLib is a desktop bookmarking application used for keeping track of books a user is reading. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java.
+
+Given below are my contributions to the project.
+
+* **Code Contributed**: [RepoSense hyperlink](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17&tabOpen=true&tabType=authorship&tabAuthor=zhoyx&tabRepo=AY2223S2-CS2103T-T13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+* **New Feature**: Added new Rating field. [#157](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/157)
+ * What it does: Allow users add a numeric rating from 0 to 5 to each bookmark.
+ * Justification: This field can then be used for sorting based on rating to allow users to easily find the best and worst content stored in the library.
+
+* **New Feature**: Created fixed list of Genres. [#139](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/139)
+ * What it does: Added validation to only allow Genres from that list to be added.
+ * Justification: Ensure consistency of Genres and reduce overhead
+
+* **New Feature**: Added command to list valid Genres. [#139](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/139)
+ * What it does: Displays the list of valid Genres
+ * Justification: Allows users to check what are the valid genres available.
+
+* **Enhancements**:
+ * Created Progress field when modifying AddressBook to MyLib. [#75](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/75)
+ * Updated Test cases for Fixed set of Genres. [#155](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/155)
+
+
+
+* **Documentation**:
+ * User Guide:
+ * Added Target Audience [#287](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/287)
+ * Added Key Definitions Section [#287](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/287)
+ * Updated Add and Edit Section to include new Genre requirement and Ratings field. [#167](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/167)
+ * Developer Guide:
+ * Updated plantUML diagrams to reflect new fields and classes. [#140](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/140)
+ * Added Implementation for Rating Field. [#167](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/167)
+ * Added User Stories for Tag, Sort and Delete [#328](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/328)
+ * Added to Instructions for Manual testing for Tag related commands [#334](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/334)
+ * Added Implementation for Add Feature. [#335](https://github.com/AY2223S2-CS2103T-T13-4/tp/pull/335)
+
+
+* **Contributions to team-based tasks**
+ * Created release for V1.3.1.trial and V1.4
+ * Maintain issue tracker for tasks
+
+
diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java
deleted file mode 100644
index 1deb3a1e469..00000000000
--- a/src/main/java/seedu/address/commons/core/Messages.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package seedu.address.commons.core;
-
-/**
- * Container for user visible messages.
- */
-public class Messages {
-
- public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
- public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
- public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
- public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
-
-}
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
deleted file mode 100644
index 92cd8fa605a..00000000000
--- a/src/main/java/seedu/address/logic/Logic.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package seedu.address.logic;
-
-import java.nio.file.Path;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * API of the Logic component
- */
-public interface Logic {
- /**
- * Executes the command and returns the result.
- * @param commandText The command as entered by the user.
- * @return the result of the command execution.
- * @throws CommandException If an error occurs during command execution.
- * @throws ParseException If an error occurs during parsing.
- */
- CommandResult execute(String commandText) throws CommandException, ParseException;
-
- /**
- * Returns the AddressBook.
- *
- * @see seedu.address.model.Model#getAddressBook()
- */
- ReadOnlyAddressBook getAddressBook();
-
- /** Returns an unmodifiable view of the filtered list of persons */
- ObservableList getFilteredPersonList();
-
- /**
- * Returns the user prefs' address book file path.
- */
- Path getAddressBookFilePath();
-
- /**
- * Returns the user prefs' GUI settings.
- */
- GuiSettings getGuiSettings();
-
- /**
- * Set the user prefs' GUI settings.
- */
- void setGuiSettings(GuiSettings guiSettings);
-}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
deleted file mode 100644
index 71656d7c5c8..00000000000
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-
-/**
- * Adds a person to the address book.
- */
-public class AddCommand extends Command {
-
- public static final String COMMAND_WORD = "add";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. "
- + "Parameters: "
- + PREFIX_NAME + "NAME "
- + PREFIX_PHONE + "PHONE "
- + PREFIX_EMAIL + "EMAIL "
- + PREFIX_ADDRESS + "ADDRESS "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " "
- + PREFIX_NAME + "John Doe "
- + PREFIX_PHONE + "98765432 "
- + PREFIX_EMAIL + "johnd@example.com "
- + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
- + PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
-
- public static final String MESSAGE_SUCCESS = "New person added: %1$s";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
-
- private final Person toAdd;
-
- /**
- * Creates an AddCommand to add the specified {@code Person}
- */
- public AddCommand(Person person) {
- requireNonNull(person);
- toAdd = person;
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
-
- if (model.hasPerson(toAdd)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.addPerson(toAdd);
- return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddCommand // instanceof handles nulls
- && toAdd.equals(((AddCommand) other).toAdd));
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
deleted file mode 100644
index 9c86b1fa6e4..00000000000
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-
-/**
- * Clears the address book.
- */
-public class ClearCommand extends Command {
-
- public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
-
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.setAddressBook(new AddressBook());
- return new CommandResult(MESSAGE_SUCCESS);
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
deleted file mode 100644
index 7e36114902f..00000000000
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.CollectionUtil;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Edits the details of an existing person in the address book.
- */
-public class EditCommand extends Command {
-
- public static final String COMMAND_WORD = "edit";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the displayed person list. "
- + "Existing values will be overwritten by the input values.\n"
- + "Parameters: INDEX (must be a positive integer) "
- + "[" + PREFIX_NAME + "NAME] "
- + "[" + PREFIX_PHONE + "PHONE] "
- + "[" + PREFIX_EMAIL + "EMAIL] "
- + "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " 1 "
- + PREFIX_PHONE + "91234567 "
- + PREFIX_EMAIL + "johndoe@example.com";
-
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
- public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
-
- private final Index index;
- private final EditPersonDescriptor editPersonDescriptor;
-
- /**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
- */
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
- requireNonNull(index);
- requireNonNull(editPersonDescriptor);
-
- this.index = index;
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
-
- if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
-
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson));
- }
-
- /**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
- */
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
-
- Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName());
- Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
- Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
- Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof EditCommand)) {
- return false;
- }
-
- // state check
- EditCommand e = (EditCommand) other;
- return index.equals(e.index)
- && editPersonDescriptor.equals(e.editPersonDescriptor);
- }
-
- /**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
- */
- public static class EditPersonDescriptor {
- private Name name;
- private Phone phone;
- private Email email;
- private Address address;
- private Set tags;
-
- public EditPersonDescriptor() {}
-
- /**
- * Copy constructor.
- * A defensive copy of {@code tags} is used internally.
- */
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
- setName(toCopy.name);
- setPhone(toCopy.phone);
- setEmail(toCopy.email);
- setAddress(toCopy.address);
- setTags(toCopy.tags);
- }
-
- /**
- * Returns true if at least one field is edited.
- */
- public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
- }
-
- public void setName(Name name) {
- this.name = name;
- }
-
- public Optional getName() {
- return Optional.ofNullable(name);
- }
-
- public void setPhone(Phone phone) {
- this.phone = phone;
- }
-
- public Optional getPhone() {
- return Optional.ofNullable(phone);
- }
-
- public void setEmail(Email email) {
- this.email = email;
- }
-
- public Optional getEmail() {
- return Optional.ofNullable(email);
- }
-
- public void setAddress(Address address) {
- this.address = address;
- }
-
- public Optional getAddress() {
- return Optional.ofNullable(address);
- }
-
- /**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
- */
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
- }
-
- /**
- * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
- */
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof EditPersonDescriptor)) {
- return false;
- }
-
- // state check
- EditPersonDescriptor e = (EditPersonDescriptor) other;
-
- return getName().equals(e.getName())
- && getPhone().equals(e.getPhone())
- && getEmail().equals(e.getEmail())
- && getAddress().equals(e.getAddress())
- && getTags().equals(e.getTags());
- }
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
deleted file mode 100644
index d6b19b0a0de..00000000000
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-
-/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
- * Keyword matching is case insensitive.
- */
-public class FindCommand extends Command {
-
- public static final String COMMAND_WORD = "find";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
- + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
- + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
-
- private final NameContainsKeywordsPredicate predicate;
-
- public FindCommand(NameContainsKeywordsPredicate predicate) {
- this.predicate = predicate;
- }
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.updateFilteredPersonList(predicate);
- return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof FindCommand // instanceof handles nulls
- && predicate.equals(((FindCommand) other).predicate)); // state check
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
deleted file mode 100644
index 84be6ad2596..00000000000
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
-import seedu.address.model.Model;
-
-/**
- * Lists all persons in the address book to the user.
- */
-public class ListCommand extends Command {
-
- public static final String COMMAND_WORD = "list";
-
- public static final String MESSAGE_SUCCESS = "Listed all persons";
-
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
- }
-}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
deleted file mode 100644
index 3b8bfa035e8..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Set;
-import java.util.stream.Stream;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new AddCommand object
- */
-public class AddCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the AddCommand
- * and returns an AddCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public AddCommand parse(String args) throws ParseException {
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
- }
-
- Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
- Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
- Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
- Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
-
- Person person = new Person(name, phone, email, address, tagList);
-
- return new AddCommand(person);
- }
-
- /**
- * Returns true if none of the prefixes contains empty {@code Optional} values in the given
- * {@code ArgumentMultimap}.
- */
- private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
- return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
deleted file mode 100644
index 75b1a9bf119..00000000000
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package seedu.address.logic.parser;
-
-/**
- * Contains Command Line Interface (CLI) syntax definitions common to multiple commands
- */
-public class CliSyntax {
-
- /* Prefix definitions */
- public static final Prefix PREFIX_NAME = new Prefix("n/");
- public static final Prefix PREFIX_PHONE = new Prefix("p/");
- public static final Prefix PREFIX_EMAIL = new Prefix("e/");
- public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
- public static final Prefix PREFIX_TAG = new Prefix("t/");
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
deleted file mode 100644
index 845644b7dea..00000000000
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package seedu.address.logic.parser;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new EditCommand object
- */
-public class EditCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the EditCommand
- * and returns an EditCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public EditCommand parse(String args) throws ParseException {
- requireNonNull(args);
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- Index index;
-
- try {
- index = ParserUtil.parseIndex(argMultimap.getPreamble());
- } catch (ParseException pe) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
- }
-
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
- }
- if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
- }
- if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
- }
- if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
- }
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
-
- if (!editPersonDescriptor.isAnyFieldEdited()) {
- throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
- }
-
- return new EditCommand(index, editPersonDescriptor);
- }
-
- /**
- * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Set} containing zero tags.
- */
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
- }
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
deleted file mode 100644
index 4fb71f23103..00000000000
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
-import java.util.Arrays;
-
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-
-/**
- * Parses input arguments and creates a new FindCommand object
- */
-public class FindCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the FindCommand
- * and returns a FindCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public FindCommand parse(String args) throws ParseException {
- String trimmedArgs = args.trim();
- if (trimmedArgs.isEmpty()) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
- }
-
- String[] nameKeywords = trimmedArgs.split("\\s+");
-
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
deleted file mode 100644
index b117acb9c55..00000000000
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package seedu.address.logic.parser;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Contains utility methods used for parsing strings in the various *Parser classes.
- */
-public class ParserUtil {
-
- public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer.";
-
- /**
- * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
- * trimmed.
- * @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
- */
- public static Index parseIndex(String oneBasedIndex) throws ParseException {
- String trimmedIndex = oneBasedIndex.trim();
- if (!StringUtil.isNonZeroUnsignedInteger(trimmedIndex)) {
- throw new ParseException(MESSAGE_INVALID_INDEX);
- }
- return Index.fromOneBased(Integer.parseInt(trimmedIndex));
- }
-
- /**
- * Parses a {@code String name} into a {@code Name}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code name} is invalid.
- */
- public static Name parseName(String name) throws ParseException {
- requireNonNull(name);
- String trimmedName = name.trim();
- if (!Name.isValidName(trimmedName)) {
- throw new ParseException(Name.MESSAGE_CONSTRAINTS);
- }
- return new Name(trimmedName);
- }
-
- /**
- * Parses a {@code String phone} into a {@code Phone}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code phone} is invalid.
- */
- public static Phone parsePhone(String phone) throws ParseException {
- requireNonNull(phone);
- String trimmedPhone = phone.trim();
- if (!Phone.isValidPhone(trimmedPhone)) {
- throw new ParseException(Phone.MESSAGE_CONSTRAINTS);
- }
- return new Phone(trimmedPhone);
- }
-
- /**
- * Parses a {@code String address} into an {@code Address}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code address} is invalid.
- */
- public static Address parseAddress(String address) throws ParseException {
- requireNonNull(address);
- String trimmedAddress = address.trim();
- if (!Address.isValidAddress(trimmedAddress)) {
- throw new ParseException(Address.MESSAGE_CONSTRAINTS);
- }
- return new Address(trimmedAddress);
- }
-
- /**
- * Parses a {@code String email} into an {@code Email}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code email} is invalid.
- */
- public static Email parseEmail(String email) throws ParseException {
- requireNonNull(email);
- String trimmedEmail = email.trim();
- if (!Email.isValidEmail(trimmedEmail)) {
- throw new ParseException(Email.MESSAGE_CONSTRAINTS);
- }
- return new Email(trimmedEmail);
- }
-
- /**
- * Parses a {@code String tag} into a {@code Tag}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code tag} is invalid.
- */
- public static Tag parseTag(String tag) throws ParseException {
- requireNonNull(tag);
- String trimmedTag = tag.trim();
- if (!Tag.isValidTagName(trimmedTag)) {
- throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
- }
- return new Tag(trimmedTag);
- }
-
- /**
- * Parses {@code Collection tags} into a {@code Set}.
- */
- public static Set parseTags(Collection tags) throws ParseException {
- requireNonNull(tags);
- final Set tagSet = new HashSet<>();
- for (String tagName : tags) {
- tagSet.add(parseTag(tagName));
- }
- return tagSet;
- }
-}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
deleted file mode 100644
index 1a943a0781a..00000000000
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.UniquePersonList;
-
-/**
- * Wraps all data at the address-book level
- * Duplicates are not allowed (by .isSamePerson comparison)
- */
-public class AddressBook implements ReadOnlyAddressBook {
-
- private final UniquePersonList persons;
-
- /*
- * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
- * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
- *
- * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
- * among constructors.
- */
- {
- persons = new UniquePersonList();
- }
-
- public AddressBook() {}
-
- /**
- * Creates an AddressBook using the Persons in the {@code toBeCopied}
- */
- public AddressBook(ReadOnlyAddressBook toBeCopied) {
- this();
- resetData(toBeCopied);
- }
-
- //// list overwrite operations
-
- /**
- * Replaces the contents of the person list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- this.persons.setPersons(persons);
- }
-
- /**
- * Resets the existing data of this {@code AddressBook} with {@code newData}.
- */
- public void resetData(ReadOnlyAddressBook newData) {
- requireNonNull(newData);
-
- setPersons(newData.getPersonList());
- }
-
- //// person-level operations
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return persons.contains(person);
- }
-
- /**
- * Adds a person to the address book.
- * The person must not already exist in the address book.
- */
- public void addPerson(Person p) {
- persons.add(p);
- }
-
- /**
- * Replaces the given person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireNonNull(editedPerson);
-
- persons.setPerson(target, editedPerson);
- }
-
- /**
- * Removes {@code key} from this {@code AddressBook}.
- * {@code key} must exist in the address book.
- */
- public void removePerson(Person key) {
- persons.remove(key);
- }
-
- //// util methods
-
- @Override
- public String toString() {
- return persons.asUnmodifiableObservableList().size() + " persons";
- // TODO: refine later
- }
-
- @Override
- public ObservableList getPersonList() {
- return persons.asUnmodifiableObservableList();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddressBook // instanceof handles nulls
- && persons.equals(((AddressBook) other).persons));
- }
-
- @Override
- public int hashCode() {
- return persons.hashCode();
- }
-}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
deleted file mode 100644
index d54df471c1f..00000000000
--- a/src/main/java/seedu/address/model/Model.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package seedu.address.model;
-
-import java.nio.file.Path;
-import java.util.function.Predicate;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.Person;
-
-/**
- * The API of the Model component.
- */
-public interface Model {
- /** {@code Predicate} that always evaluate to true */
- Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
-
- /**
- * Replaces user prefs data with the data in {@code userPrefs}.
- */
- void setUserPrefs(ReadOnlyUserPrefs userPrefs);
-
- /**
- * Returns the user prefs.
- */
- ReadOnlyUserPrefs getUserPrefs();
-
- /**
- * Returns the user prefs' GUI settings.
- */
- GuiSettings getGuiSettings();
-
- /**
- * Sets the user prefs' GUI settings.
- */
- void setGuiSettings(GuiSettings guiSettings);
-
- /**
- * Returns the user prefs' address book file path.
- */
- Path getAddressBookFilePath();
-
- /**
- * Sets the user prefs' address book file path.
- */
- void setAddressBookFilePath(Path addressBookFilePath);
-
- /**
- * Replaces address book data with the data in {@code addressBook}.
- */
- void setAddressBook(ReadOnlyAddressBook addressBook);
-
- /** Returns the AddressBook */
- ReadOnlyAddressBook getAddressBook();
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- boolean hasPerson(Person person);
-
- /**
- * Deletes the given person.
- * The person must exist in the address book.
- */
- void deletePerson(Person target);
-
- /**
- * Adds the given person.
- * {@code person} must not already exist in the address book.
- */
- void addPerson(Person person);
-
- /**
- * Replaces the given person {@code target} with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- void setPerson(Person target, Person editedPerson);
-
- /** Returns an unmodifiable view of the filtered person list */
- ObservableList getFilteredPersonList();
-
- /**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
- * @throws NullPointerException if {@code predicate} is null.
- */
- void updateFilteredPersonList(Predicate predicate);
-}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
deleted file mode 100644
index 86c1df298d7..00000000000
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.nio.file.Path;
-import java.util.function.Predicate;
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.collections.transformation.FilteredList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Represents the in-memory model of the address book data.
- */
-public class ModelManager implements Model {
- private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
-
- private final AddressBook addressBook;
- private final UserPrefs userPrefs;
- private final FilteredList filteredPersons;
-
- /**
- * Initializes a ModelManager with the given addressBook and userPrefs.
- */
- public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
- requireAllNonNull(addressBook, userPrefs);
-
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
-
- this.addressBook = new AddressBook(addressBook);
- this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
- }
-
- public ModelManager() {
- this(new AddressBook(), new UserPrefs());
- }
-
- //=========== UserPrefs ==================================================================================
-
- @Override
- public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
- requireNonNull(userPrefs);
- this.userPrefs.resetData(userPrefs);
- }
-
- @Override
- public ReadOnlyUserPrefs getUserPrefs() {
- return userPrefs;
- }
-
- @Override
- public GuiSettings getGuiSettings() {
- return userPrefs.getGuiSettings();
- }
-
- @Override
- public void setGuiSettings(GuiSettings guiSettings) {
- requireNonNull(guiSettings);
- userPrefs.setGuiSettings(guiSettings);
- }
-
- @Override
- public Path getAddressBookFilePath() {
- return userPrefs.getAddressBookFilePath();
- }
-
- @Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- userPrefs.setAddressBookFilePath(addressBookFilePath);
- }
-
- //=========== AddressBook ================================================================================
-
- @Override
- public void setAddressBook(ReadOnlyAddressBook addressBook) {
- this.addressBook.resetData(addressBook);
- }
-
- @Override
- public ReadOnlyAddressBook getAddressBook() {
- return addressBook;
- }
-
- @Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return addressBook.hasPerson(person);
- }
-
- @Override
- public void deletePerson(Person target) {
- addressBook.removePerson(target);
- }
-
- @Override
- public void addPerson(Person person) {
- addressBook.addPerson(person);
- updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- }
-
- @Override
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- addressBook.setPerson(target, editedPerson);
- }
-
- //=========== Filtered Person List Accessors =============================================================
-
- /**
- * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
- * {@code versionedAddressBook}
- */
- @Override
- public ObservableList getFilteredPersonList() {
- return filteredPersons;
- }
-
- @Override
- public void updateFilteredPersonList(Predicate predicate) {
- requireNonNull(predicate);
- filteredPersons.setPredicate(predicate);
- }
-
- @Override
- public boolean equals(Object obj) {
- // short circuit if same object
- if (obj == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(obj instanceof ModelManager)) {
- return false;
- }
-
- // state check
- ModelManager other = (ModelManager) obj;
- return addressBook.equals(other.addressBook)
- && userPrefs.equals(other.userPrefs)
- && filteredPersons.equals(other.filteredPersons);
- }
-
-}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
deleted file mode 100644
index 6ddc2cd9a29..00000000000
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package seedu.address.model;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-
-/**
- * Unmodifiable view of an address book
- */
-public interface ReadOnlyAddressBook {
-
- /**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
- */
- ObservableList getPersonList();
-
-}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
deleted file mode 100644
index 60472ca22a0..00000000000
--- a/src/main/java/seedu/address/model/person/Address.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's address in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
- */
-public class Address {
-
- public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[^\\s].*";
-
- public final String value;
-
- /**
- * Constructs an {@code Address}.
- *
- * @param address A valid address.
- */
- public Address(String address) {
- requireNonNull(address);
- checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS);
- value = address;
- }
-
- /**
- * Returns true if a given string is a valid email.
- */
- public static boolean isValidAddress(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Address // instanceof handles nulls
- && value.equals(((Address) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/person/Email.java
deleted file mode 100644
index f866e7133de..00000000000
--- a/src/main/java/seedu/address/model/person/Email.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's email in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)}
- */
-public class Email {
-
- private static final String SPECIAL_CHARACTERS = "+_.-";
- public static final String MESSAGE_CONSTRAINTS = "Emails should be of the format local-part@domain "
- + "and adhere to the following constraints:\n"
- + "1. The local-part should only contain alphanumeric characters and these special characters, excluding "
- + "the parentheses, (" + SPECIAL_CHARACTERS + "). The local-part may not start or end with any special "
- + "characters.\n"
- + "2. This is followed by a '@' and then a domain name. The domain name is made up of domain labels "
- + "separated by periods.\n"
- + "The domain name must:\n"
- + " - end with a domain label at least 2 characters long\n"
- + " - have each domain label start and end with alphanumeric characters\n"
- + " - have each domain label consist of alphanumeric characters, separated only by hyphens, if any.";
- // alphanumeric and special characters
- private static final String ALPHANUMERIC_NO_UNDERSCORE = "[^\\W_]+"; // alphanumeric characters except underscore
- private static final String LOCAL_PART_REGEX = "^" + ALPHANUMERIC_NO_UNDERSCORE + "([" + SPECIAL_CHARACTERS + "]"
- + ALPHANUMERIC_NO_UNDERSCORE + ")*";
- private static final String DOMAIN_PART_REGEX = ALPHANUMERIC_NO_UNDERSCORE
- + "(-" + ALPHANUMERIC_NO_UNDERSCORE + ")*";
- private static final String DOMAIN_LAST_PART_REGEX = "(" + DOMAIN_PART_REGEX + "){2,}$"; // At least two chars
- private static final String DOMAIN_REGEX = "(" + DOMAIN_PART_REGEX + "\\.)*" + DOMAIN_LAST_PART_REGEX;
- public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@" + DOMAIN_REGEX;
-
- public final String value;
-
- /**
- * Constructs an {@code Email}.
- *
- * @param email A valid email address.
- */
- public Email(String email) {
- requireNonNull(email);
- checkArgument(isValidEmail(email), MESSAGE_CONSTRAINTS);
- value = email;
- }
-
- /**
- * Returns if a given string is a valid email.
- */
- public static boolean isValidEmail(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Email // instanceof handles nulls
- && value.equals(((Email) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java
deleted file mode 100644
index 79244d71cf7..00000000000
--- a/src/main/java/seedu/address/model/person/Name.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's name in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidName(String)}
- */
-public class Name {
-
- public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
-
- public final String fullName;
-
- /**
- * Constructs a {@code Name}.
- *
- * @param name A valid name.
- */
- public Name(String name) {
- requireNonNull(name);
- checkArgument(isValidName(name), MESSAGE_CONSTRAINTS);
- fullName = name;
- }
-
- /**
- * Returns true if a given string is a valid name.
- */
- public static boolean isValidName(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
-
- @Override
- public String toString() {
- return fullName;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Name // instanceof handles nulls
- && fullName.equals(((Name) other).fullName)); // state check
- }
-
- @Override
- public int hashCode() {
- return fullName.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
deleted file mode 100644
index c9b5868427c..00000000000
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package seedu.address.model.person;
-
-import java.util.List;
-import java.util.function.Predicate;
-
-import seedu.address.commons.util.StringUtil;
-
-/**
- * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
- */
-public class NameContainsKeywordsPredicate implements Predicate {
- private final List keywords;
-
- public NameContainsKeywordsPredicate(List keywords) {
- this.keywords = keywords;
- }
-
- @Override
- public boolean test(Person person) {
- return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof NameContainsKeywordsPredicate // instanceof handles nulls
- && keywords.equals(((NameContainsKeywordsPredicate) other).keywords)); // state check
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
deleted file mode 100644
index 8ff1d83fe89..00000000000
--- a/src/main/java/seedu/address/model/person/Person.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package seedu.address.model.person;
-
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-import seedu.address.model.tag.Tag;
-
-/**
- * Represents a Person in the address book.
- * Guarantees: details are present and not null, field values are validated, immutable.
- */
-public class Person {
-
- // Identity fields
- private final Name name;
- private final Phone phone;
- private final Email email;
-
- // Data fields
- private final Address address;
- private final Set tags = new HashSet<>();
-
- /**
- * Every field must be present and not null.
- */
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- this.tags.addAll(tags);
- }
-
- public Name getName() {
- return name;
- }
-
- public Phone getPhone() {
- return phone;
- }
-
- public Email getEmail() {
- return email;
- }
-
- public Address getAddress() {
- return address;
- }
-
- /**
- * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- */
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
- }
-
- /**
- * Returns true if both persons have the same name.
- * This defines a weaker notion of equality between two persons.
- */
- public boolean isSamePerson(Person otherPerson) {
- if (otherPerson == this) {
- return true;
- }
-
- return otherPerson != null
- && otherPerson.getName().equals(getName());
- }
-
- /**
- * Returns true if both persons have the same identity and data fields.
- * This defines a stronger notion of equality between two persons.
- */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (!(other instanceof Person)) {
- return false;
- }
-
- Person otherPerson = (Person) other;
- return otherPerson.getName().equals(getName())
- && otherPerson.getPhone().equals(getPhone())
- && otherPerson.getEmail().equals(getEmail())
- && otherPerson.getAddress().equals(getAddress())
- && otherPerson.getTags().equals(getTags());
- }
-
- @Override
- public int hashCode() {
- // use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append(getName())
- .append("; Phone: ")
- .append(getPhone())
- .append("; Email: ")
- .append(getEmail())
- .append("; Address: ")
- .append(getAddress());
-
- Set tags = getTags();
- if (!tags.isEmpty()) {
- builder.append("; Tags: ");
- tags.forEach(builder::append);
- }
- return builder.toString();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java
deleted file mode 100644
index 872c76b382f..00000000000
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's phone number in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)}
- */
-public class Phone {
-
-
- public static final String MESSAGE_CONSTRAINTS =
- "Phone numbers should only contain numbers, and it should be at least 3 digits long";
- public static final String VALIDATION_REGEX = "\\d{3,}";
- public final String value;
-
- /**
- * Constructs a {@code Phone}.
- *
- * @param phone A valid phone number.
- */
- public Phone(String phone) {
- requireNonNull(phone);
- checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS);
- value = phone;
- }
-
- /**
- * Returns true if a given string is a valid phone number.
- */
- public static boolean isValidPhone(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Phone // instanceof handles nulls
- && value.equals(((Phone) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
deleted file mode 100644
index 0fee4fe57e6..00000000000
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-
-/**
- * A list of persons that enforces uniqueness between its elements and does not allow nulls.
- * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of
- * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is
- * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so
- * as to ensure that the person with exactly the same fields will be removed.
- *
- * Supports a minimal set of list operations.
- *
- * @see Person#isSamePerson(Person)
- */
-public class UniquePersonList implements Iterable {
-
- private final ObservableList internalList = FXCollections.observableArrayList();
- private final ObservableList internalUnmodifiableList =
- FXCollections.unmodifiableObservableList(internalList);
-
- /**
- * Returns true if the list contains an equivalent person as the given argument.
- */
- public boolean contains(Person toCheck) {
- requireNonNull(toCheck);
- return internalList.stream().anyMatch(toCheck::isSamePerson);
- }
-
- /**
- * Adds a person to the list.
- * The person must not already exist in the list.
- */
- public void add(Person toAdd) {
- requireNonNull(toAdd);
- if (contains(toAdd)) {
- throw new DuplicatePersonException();
- }
- internalList.add(toAdd);
- }
-
- /**
- * Replaces the person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the list.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the list.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- int index = internalList.indexOf(target);
- if (index == -1) {
- throw new PersonNotFoundException();
- }
-
- if (!target.isSamePerson(editedPerson) && contains(editedPerson)) {
- throw new DuplicatePersonException();
- }
-
- internalList.set(index, editedPerson);
- }
-
- /**
- * Removes the equivalent person from the list.
- * The person must exist in the list.
- */
- public void remove(Person toRemove) {
- requireNonNull(toRemove);
- if (!internalList.remove(toRemove)) {
- throw new PersonNotFoundException();
- }
- }
-
- public void setPersons(UniquePersonList replacement) {
- requireNonNull(replacement);
- internalList.setAll(replacement.internalList);
- }
-
- /**
- * Replaces the contents of this list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- requireAllNonNull(persons);
- if (!personsAreUnique(persons)) {
- throw new DuplicatePersonException();
- }
-
- internalList.setAll(persons);
- }
-
- /**
- * Returns the backing list as an unmodifiable {@code ObservableList}.
- */
- public ObservableList asUnmodifiableObservableList() {
- return internalUnmodifiableList;
- }
-
- @Override
- public Iterator iterator() {
- return internalList.iterator();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof UniquePersonList // instanceof handles nulls
- && internalList.equals(((UniquePersonList) other).internalList));
- }
-
- @Override
- public int hashCode() {
- return internalList.hashCode();
- }
-
- /**
- * Returns true if {@code persons} contains only unique persons.
- */
- private boolean personsAreUnique(List persons) {
- for (int i = 0; i < persons.size() - 1; i++) {
- for (int j = i + 1; j < persons.size(); j++) {
- if (persons.get(i).isSamePerson(persons.get(j))) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
deleted file mode 100644
index d7290f59442..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same
- * identity).
- */
-public class DuplicatePersonException extends RuntimeException {
- public DuplicatePersonException() {
- super("Operation would result in duplicate persons");
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
deleted file mode 100644
index fa764426ca7..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation is unable to find the specified person.
- */
-public class PersonNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
deleted file mode 100644
index 1806da4facf..00000000000
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.model.util;
-
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Contains utility methods for populating {@code AddressBook} with sample data.
- */
-public class SampleDataUtil {
- public static Person[] getSamplePersons() {
- return new Person[] {
- new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
- new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
- new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
- new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- getTagSet("colleagues", "friends")),
- new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
- new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
- new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
- new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
- new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
- new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
- new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
- new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
- };
- }
-
- public static ReadOnlyAddressBook getSampleAddressBook() {
- AddressBook sampleAb = new AddressBook();
- for (Person samplePerson : getSamplePersons()) {
- sampleAb.addPerson(samplePerson);
- }
- return sampleAb;
- }
-
- /**
- * Returns a tag set containing the list of strings given.
- */
- public static Set getTagSet(String... strings) {
- return Arrays.stream(strings)
- .map(Tag::new)
- .collect(Collectors.toSet());
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java
deleted file mode 100644
index 4599182b3f9..00000000000
--- a/src/main/java/seedu/address/storage/AddressBookStorage.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * Represents a storage for {@link seedu.address.model.AddressBook}.
- */
-public interface AddressBookStorage {
-
- /**
- * Returns the file path of the data file.
- */
- Path getAddressBookFilePath();
-
- /**
- * Returns AddressBook data as a {@link ReadOnlyAddressBook}.
- * Returns {@code Optional.empty()} if storage file is not found.
- * @throws DataConversionException if the data in storage is not in the expected format.
- * @throws IOException if there was any problem when reading from the storage.
- */
- Optional readAddressBook() throws DataConversionException, IOException;
-
- /**
- * @see #getAddressBookFilePath()
- */
- Optional readAddressBook(Path filePath) throws DataConversionException, IOException;
-
- /**
- * Saves the given {@link ReadOnlyAddressBook} to the storage.
- * @param addressBook cannot be null.
- * @throws IOException if there was any problem writing to the file.
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
- /**
- * @see #saveAddressBook(ReadOnlyAddressBook)
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
deleted file mode 100644
index a6321cec2ea..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Person}.
- */
-class JsonAdaptedPerson {
-
- public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
-
- private final String name;
- private final String phone;
- private final String email;
- private final String address;
- private final List tagged = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonAdaptedPerson} with the given person details.
- */
- @JsonCreator
- public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tagged") List tagged) {
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- if (tagged != null) {
- this.tagged.addAll(tagged);
- }
- }
-
- /**
- * Converts a given {@code Person} into this class for Jackson use.
- */
- public JsonAdaptedPerson(Person source) {
- name = source.getName().fullName;
- phone = source.getPhone().value;
- email = source.getEmail().value;
- address = source.getAddress().value;
- tagged.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
- }
-
- /**
- * Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted person.
- */
- public Person toModelType() throws IllegalValueException {
- final List personTags = new ArrayList<>();
- for (JsonAdaptedTag tag : tagged) {
- personTags.add(tag.toModelType());
- }
-
- if (name == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
- }
- if (!Name.isValidName(name)) {
- throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
- }
- final Name modelName = new Name(name);
-
- if (phone == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()));
- }
- if (!Phone.isValidPhone(phone)) {
- throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS);
- }
- final Phone modelPhone = new Phone(phone);
-
- if (email == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
- }
- if (!Email.isValidEmail(email)) {
- throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
- }
- final Email modelEmail = new Email(email);
-
- if (address == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()));
- }
- if (!Address.isValidAddress(address)) {
- throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS);
- }
- final Address modelAddress = new Address(address);
-
- final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
deleted file mode 100644
index dfab9daaa0d..00000000000
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package seedu.address.storage;
-
-import static java.util.Objects.requireNonNull;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.commons.util.FileUtil;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * A class to access AddressBook data stored as a json file on the hard disk.
- */
-public class JsonAddressBookStorage implements AddressBookStorage {
-
- private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class);
-
- private Path filePath;
-
- public JsonAddressBookStorage(Path filePath) {
- this.filePath = filePath;
- }
-
- public Path getAddressBookFilePath() {
- return filePath;
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException {
- return readAddressBook(filePath);
- }
-
- /**
- * Similar to {@link #readAddressBook()}.
- *
- * @param filePath location of the data. Cannot be null.
- * @throws DataConversionException if the file is not in the correct format.
- */
- public Optional readAddressBook(Path filePath) throws DataConversionException {
- requireNonNull(filePath);
-
- Optional jsonAddressBook = JsonUtil.readJsonFile(
- filePath, JsonSerializableAddressBook.class);
- if (!jsonAddressBook.isPresent()) {
- return Optional.empty();
- }
-
- try {
- return Optional.of(jsonAddressBook.get().toModelType());
- } catch (IllegalValueException ive) {
- logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
- throw new DataConversionException(ive);
- }
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, filePath);
- }
-
- /**
- * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}.
- *
- * @param filePath location of the data. Cannot be null.
- */
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- requireNonNull(addressBook);
- requireNonNull(filePath);
-
- FileUtil.createIfMissing(filePath);
- JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
deleted file mode 100644
index 5efd834091d..00000000000
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonRootName;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * An Immutable AddressBook that is serializable to JSON format.
- */
-@JsonRootName(value = "addressbook")
-class JsonSerializableAddressBook {
-
- public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
-
- private final List persons = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonSerializableAddressBook} with the given persons.
- */
- @JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
- this.persons.addAll(persons);
- }
-
- /**
- * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
- *
- * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}.
- */
- public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
- }
-
- /**
- * Converts this address book into the model's {@code AddressBook} object.
- *
- * @throws IllegalValueException if there were any data constraints violated.
- */
- public AddressBook toModelType() throws IllegalValueException {
- AddressBook addressBook = new AddressBook();
- for (JsonAdaptedPerson jsonAdaptedPerson : persons) {
- Person person = jsonAdaptedPerson.toModelType();
- if (addressBook.hasPerson(person)) {
- throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON);
- }
- addressBook.addPerson(person);
- }
- return addressBook;
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java
deleted file mode 100644
index beda8bd9f11..00000000000
--- a/src/main/java/seedu/address/storage/Storage.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-
-/**
- * API of the Storage component
- */
-public interface Storage extends AddressBookStorage, UserPrefsStorage {
-
- @Override
- Optional readUserPrefs() throws DataConversionException, IOException;
-
- @Override
- void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
-
- @Override
- Path getAddressBookFilePath();
-
- @Override
- Optional readAddressBook() throws DataConversionException, IOException;
-
- @Override
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java
deleted file mode 100644
index 6cfa0162164..00000000000
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-
-/**
- * Manages storage of AddressBook data in local storage.
- */
-public class StorageManager implements Storage {
-
- private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
- private AddressBookStorage addressBookStorage;
- private UserPrefsStorage userPrefsStorage;
-
- /**
- * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}.
- */
- public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) {
- this.addressBookStorage = addressBookStorage;
- this.userPrefsStorage = userPrefsStorage;
- }
-
- // ================ UserPrefs methods ==============================
-
- @Override
- public Path getUserPrefsFilePath() {
- return userPrefsStorage.getUserPrefsFilePath();
- }
-
- @Override
- public Optional readUserPrefs() throws DataConversionException, IOException {
- return userPrefsStorage.readUserPrefs();
- }
-
- @Override
- public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
- userPrefsStorage.saveUserPrefs(userPrefs);
- }
-
-
- // ================ AddressBook methods ==============================
-
- @Override
- public Path getAddressBookFilePath() {
- return addressBookStorage.getAddressBookFilePath();
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException, IOException {
- return readAddressBook(addressBookStorage.getAddressBookFilePath());
- }
-
- @Override
- public Optional readAddressBook(Path filePath) throws DataConversionException, IOException {
- logger.fine("Attempting to read data from file: " + filePath);
- return addressBookStorage.readAddressBook(filePath);
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath());
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- logger.fine("Attempting to write to data file: " + filePath);
- addressBookStorage.saveAddressBook(addressBook, filePath);
- }
-
-}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
deleted file mode 100644
index 7fc927bc5d9..00000000000
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package seedu.address.ui;
-
-import java.util.Comparator;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.Label;
-import javafx.scene.layout.FlowPane;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Region;
-import seedu.address.model.person.Person;
-
-/**
- * An UI component that displays information of a {@code Person}.
- */
-public class PersonCard extends UiPart {
-
- private static final String FXML = "PersonListCard.fxml";
-
- /**
- * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
- * As a consequence, UI elements' variable names cannot be set to such keywords
- * or an exception will be thrown by JavaFX during runtime.
- *
- * @see The issue on AddressBook level 4
- */
-
- public final Person person;
-
- @FXML
- private HBox cardPane;
- @FXML
- private Label name;
- @FXML
- private Label id;
- @FXML
- private Label phone;
- @FXML
- private Label address;
- @FXML
- private Label email;
- @FXML
- private FlowPane tags;
-
- /**
- * Creates a {@code PersonCode} with the given {@code Person} and index to display.
- */
- public PersonCard(Person person, int displayedIndex) {
- super(FXML);
- this.person = person;
- id.setText(displayedIndex + ". ");
- name.setText(person.getName().fullName);
- phone.setText(person.getPhone().value);
- address.setText(person.getAddress().value);
- email.setText(person.getEmail().value);
- person.getTags().stream()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof PersonCard)) {
- return false;
- }
-
- // state check
- PersonCard card = (PersonCard) other;
- return id.getText().equals(card.id.getText())
- && person.equals(card.person);
- }
-}
diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java
deleted file mode 100644
index f4c501a897b..00000000000
--- a/src/main/java/seedu/address/ui/PersonListPanel.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package seedu.address.ui;
-
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.fxml.FXML;
-import javafx.scene.control.ListCell;
-import javafx.scene.control.ListView;
-import javafx.scene.layout.Region;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Panel containing the list of persons.
- */
-public class PersonListPanel extends UiPart {
- private static final String FXML = "PersonListPanel.fxml";
- private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
-
- @FXML
- private ListView personListView;
-
- /**
- * Creates a {@code PersonListPanel} with the given {@code ObservableList}.
- */
- public PersonListPanel(ObservableList personList) {
- super(FXML);
- personListView.setItems(personList);
- personListView.setCellFactory(listView -> new PersonListViewCell());
- }
-
- /**
- * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}.
- */
- class PersonListViewCell extends ListCell {
- @Override
- protected void updateItem(Person person, boolean empty) {
- super.updateItem(person, empty);
-
- if (empty || person == null) {
- setGraphic(null);
- setText(null);
- } else {
- setGraphic(new PersonCard(person, getIndex() + 1).getRoot());
- }
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/seedu/library/AppParameters.java
similarity index 93%
rename from src/main/java/seedu/address/AppParameters.java
rename to src/main/java/seedu/library/AppParameters.java
index ab552c398f3..512649ca35a 100644
--- a/src/main/java/seedu/address/AppParameters.java
+++ b/src/main/java/seedu/library/AppParameters.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.library;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -7,8 +7,8 @@
import java.util.logging.Logger;
import javafx.application.Application;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.util.FileUtil;
+import seedu.library.commons.core.LogsCenter;
+import seedu.library.commons.util.FileUtil;
/**
* Represents the parsed command-line parameters given to the application.
diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/seedu/library/Main.java
similarity index 97%
rename from src/main/java/seedu/address/Main.java
rename to src/main/java/seedu/library/Main.java
index 052a5068631..44cf616dcb4 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/seedu/library/Main.java
@@ -1,7 +1,8 @@
-package seedu.address;
+package seedu.library;
import javafx.application.Application;
+
/**
* The main entry point to the application.
*
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/library/MainApp.java
similarity index 58%
rename from src/main/java/seedu/address/MainApp.java
rename to src/main/java/seedu/library/MainApp.java
index 4133aaa0151..0f1ee36a224 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/library/MainApp.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.library;
import java.io.IOException;
import java.nio.file.Path;
@@ -7,36 +7,40 @@
import javafx.application.Application;
import javafx.stage.Stage;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.core.Version;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.util.ConfigUtil;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.Logic;
-import seedu.address.logic.LogicManager;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.util.SampleDataUtil;
-import seedu.address.storage.AddressBookStorage;
-import seedu.address.storage.JsonAddressBookStorage;
-import seedu.address.storage.JsonUserPrefsStorage;
-import seedu.address.storage.Storage;
-import seedu.address.storage.StorageManager;
-import seedu.address.storage.UserPrefsStorage;
-import seedu.address.ui.Ui;
-import seedu.address.ui.UiManager;
+import seedu.library.commons.core.Config;
+import seedu.library.commons.core.LogsCenter;
+import seedu.library.commons.core.Version;
+import seedu.library.commons.exceptions.DataConversionException;
+import seedu.library.commons.util.ConfigUtil;
+import seedu.library.commons.util.StringUtil;
+import seedu.library.logic.Logic;
+import seedu.library.logic.LogicManager;
+import seedu.library.model.Library;
+import seedu.library.model.Model;
+import seedu.library.model.ModelManager;
+import seedu.library.model.ReadOnlyLibrary;
+import seedu.library.model.ReadOnlyTags;
+import seedu.library.model.ReadOnlyUserPrefs;
+import seedu.library.model.Tags;
+import seedu.library.model.UserPrefs;
+import seedu.library.model.util.SampleDataUtil;
+import seedu.library.storage.JsonLibraryStorage;
+import seedu.library.storage.JsonTagsStorage;
+import seedu.library.storage.JsonUserPrefsStorage;
+import seedu.library.storage.LibraryStorage;
+import seedu.library.storage.Storage;
+import seedu.library.storage.StorageManager;
+import seedu.library.storage.TagsStorage;
+import seedu.library.storage.UserPrefsStorage;
+import seedu.library.ui.Ui;
+import seedu.library.ui.UiManager;
/**
* Runs the application.
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 0, true);
+ public static final Version VERSION = new Version(1, 4, 0, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -48,7 +52,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing Library ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -56,8 +60,9 @@ public void init() throws Exception {
UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath());
UserPrefs userPrefs = initPrefs(userPrefsStorage);
- AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath());
- storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ LibraryStorage libraryStorage = new JsonLibraryStorage(userPrefs.getLibraryFilePath());
+ TagsStorage tagsStorage = new JsonTagsStorage(userPrefs.getTagsFilePath());
+ storage = new StorageManager(libraryStorage, userPrefsStorage, tagsStorage);
initLogging(config);
@@ -69,28 +74,45 @@ public void init() throws Exception {
}
/**
- * Returns a {@code ModelManager} with the data from {@code storage}'s address book and {@code userPrefs}.
- * The data from the sample address book will be used instead if {@code storage}'s address book is not found,
- * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book.
+ * Returns a {@code ModelManager} with the data from {@code storage}'s library, {@code userPrefs}
+ * and {@code tagsStorage}. The data from the sample library will be used instead if {@code storage}'s
+ * library is not found, or an empty library will be used instead if errors
+ * occur when reading {@code storage}'s library.
*/
private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
- Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ Optional libraryOptional;
+ ReadOnlyLibrary initialData;
+ Optional tagsOptional;
+ ReadOnlyTags initialTags;
try {
- addressBookOptional = storage.readAddressBook();
- if (!addressBookOptional.isPresent()) {
- logger.info("Data file not found. Will be starting with a sample AddressBook");
+ tagsOptional = storage.readTags();
+ if (!tagsOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample Library");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ initialTags = tagsOptional.orElseGet(SampleDataUtil::getSampleTagList);
} catch (DataConversionException e) {
- logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook");
- initialData = new AddressBook();
+ logger.warning("Data file not in the correct format. Will be starting with an empty tag list");
+ initialTags = new Tags();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
- initialData = new AddressBook();
+ logger.warning("Problem while reading from the file. Will be starting with an empty tag list");
+ initialTags = new Tags();
}
- return new ModelManager(initialData, userPrefs);
+ try {
+ libraryOptional = storage.readLibrary();
+ if (!libraryOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample Library");
+ }
+ initialData = libraryOptional.orElseGet(SampleDataUtil::getSampleLibrary);
+ } catch (DataConversionException e) {
+ logger.warning("Data file not in the correct format. Will be starting with an empty Library");
+ initialData = new Library();
+ } catch (IOException e) {
+ logger.warning("Problem while reading from the file. Will be starting with an empty Library");
+ initialData = new Library();
+ }
+
+ return new ModelManager(initialData, userPrefs, initialTags);
}
private void initLogging(Config config) {
@@ -151,7 +173,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
+ "Using default user prefs");
initializedPrefs = new UserPrefs();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
+ logger.warning("Problem while reading from the file. Will be starting with an empty Library");
initializedPrefs = new UserPrefs();
}
@@ -167,13 +189,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting Library " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping Library ] =============================");
try {
storage.saveUserPrefs(model.getUserPrefs());
} catch (IOException e) {
diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/seedu/library/commons/core/Config.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/Config.java
rename to src/main/java/seedu/library/commons/core/Config.java
index 91145745521..9872524b681 100644
--- a/src/main/java/seedu/address/commons/core/Config.java
+++ b/src/main/java/seedu/library/commons/core/Config.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.library.commons.core;
import java.nio.file.Path;
import java.nio.file.Paths;
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/library/commons/core/GuiSettings.java
similarity index 93%
rename from src/main/java/seedu/address/commons/core/GuiSettings.java
rename to src/main/java/seedu/library/commons/core/GuiSettings.java
index ba33653be67..b69c2fb3fc0 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/library/commons/core/GuiSettings.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.library.commons.core;
import java.awt.Point;
import java.io.Serializable;
@@ -10,8 +10,8 @@
*/
public class GuiSettings implements Serializable {
- private static final double DEFAULT_HEIGHT = 600;
- private static final double DEFAULT_WIDTH = 740;
+ private static final double DEFAULT_HEIGHT = 800;
+ private static final double DEFAULT_WIDTH = 1050;
private final double windowWidth;
private final double windowHeight;
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/library/commons/core/LogsCenter.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/LogsCenter.java
rename to src/main/java/seedu/library/commons/core/LogsCenter.java
index 431e7185e76..09eba2216aa 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/library/commons/core/LogsCenter.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.library.commons.core;
import java.io.IOException;
import java.util.Arrays;
@@ -18,7 +18,7 @@
public class LogsCenter {
private static final int MAX_FILE_COUNT = 5;
private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB
- private static final String LOG_FILE = "addressbook.log";
+ private static final String LOG_FILE = "Library.log";
private static Level currentLogLevel = Level.INFO;
private static final Logger logger = LogsCenter.getLogger(LogsCenter.class);
private static FileHandler fileHandler;
diff --git a/src/main/java/seedu/library/commons/core/Messages.java b/src/main/java/seedu/library/commons/core/Messages.java
new file mode 100644
index 00000000000..6ff1537fabf
--- /dev/null
+++ b/src/main/java/seedu/library/commons/core/Messages.java
@@ -0,0 +1,14 @@
+package seedu.library.commons.core;
+
+/**
+ * Container for user visible messages.
+ */
+public class Messages {
+
+ public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
+ public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
+ public static final String MESSAGE_INVALID_BOOKMARK_DISPLAYED_INDEX = "The bookmark index provided is invalid";
+ public static final String MESSAGE_INVALID_TAG_NAME = "The tag name provided does not exists in the tag list";
+ public static final String MESSAGE_BOOKMARKS_LISTED_OVERVIEW = "%1$d bookmarks listed!";
+
+}
diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/library/commons/core/Version.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/Version.java
rename to src/main/java/seedu/library/commons/core/Version.java
index 12142ec1e32..a85efe519de 100644
--- a/src/main/java/seedu/address/commons/core/Version.java
+++ b/src/main/java/seedu/library/commons/core/Version.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.library.commons.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/seedu/library/commons/core/index/Index.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/index/Index.java
rename to src/main/java/seedu/library/commons/core/index/Index.java
index 19536439c09..28474f7dae1 100644
--- a/src/main/java/seedu/address/commons/core/index/Index.java
+++ b/src/main/java/seedu/library/commons/core/index/Index.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core.index;
+package seedu.library.commons.core.index;
/**
* Represents a zero-based or one-based index.
diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/library/commons/exceptions/DataConversionException.java
similarity index 84%
rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java
rename to src/main/java/seedu/library/commons/exceptions/DataConversionException.java
index 1f689bd8e3f..e4e0564751d 100644
--- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java
+++ b/src/main/java/seedu/library/commons/exceptions/DataConversionException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.library.commons.exceptions;
/**
* Represents an error during conversion of data from one format to another
diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/library/commons/exceptions/IllegalValueException.java
similarity index 93%
rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
rename to src/main/java/seedu/library/commons/exceptions/IllegalValueException.java
index 19124db485c..02dd63dd35d 100644
--- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
+++ b/src/main/java/seedu/library/commons/exceptions/IllegalValueException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.library.commons.exceptions;
/**
* Signals that some given data does not fulfill some constraints.
diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/seedu/library/commons/util/AppUtil.java
similarity index 94%
rename from src/main/java/seedu/address/commons/util/AppUtil.java
rename to src/main/java/seedu/library/commons/util/AppUtil.java
index 87aa89c0326..48c87508f8c 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/seedu/library/commons/util/AppUtil.java
@@ -1,9 +1,9 @@
-package seedu.address.commons.util;
+package seedu.library.commons.util;
import static java.util.Objects.requireNonNull;
import javafx.scene.image.Image;
-import seedu.address.MainApp;
+import seedu.library.MainApp;
/**
* A container for App specific utility functions
diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/seedu/library/commons/util/CollectionUtil.java
similarity index 96%
rename from src/main/java/seedu/address/commons/util/CollectionUtil.java
rename to src/main/java/seedu/library/commons/util/CollectionUtil.java
index eafe4dfd681..db6eecb1eaa 100644
--- a/src/main/java/seedu/address/commons/util/CollectionUtil.java
+++ b/src/main/java/seedu/library/commons/util/CollectionUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.library.commons.util;
import static java.util.Objects.requireNonNull;
diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/library/commons/util/ConfigUtil.java
similarity index 77%
rename from src/main/java/seedu/address/commons/util/ConfigUtil.java
rename to src/main/java/seedu/library/commons/util/ConfigUtil.java
index f7f8a2bd44c..d76929ebf60 100644
--- a/src/main/java/seedu/address/commons/util/ConfigUtil.java
+++ b/src/main/java/seedu/library/commons/util/ConfigUtil.java
@@ -1,11 +1,11 @@
-package seedu.address.commons.util;
+package seedu.library.commons.util;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.library.commons.core.Config;
+import seedu.library.commons.exceptions.DataConversionException;
/**
* A class for accessing the Config File.
diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/library/commons/util/FileUtil.java
similarity index 98%
rename from src/main/java/seedu/address/commons/util/FileUtil.java
rename to src/main/java/seedu/library/commons/util/FileUtil.java
index b1e2767cdd9..0d9170025e9 100644
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ b/src/main/java/seedu/library/commons/util/FileUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.library.commons.util;
import java.io.IOException;
import java.nio.file.Files;
diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/library/commons/util/JsonUtil.java
similarity index 97%
rename from src/main/java/seedu/address/commons/util/JsonUtil.java
rename to src/main/java/seedu/library/commons/util/JsonUtil.java
index 8ef609f055d..a9790d5c8fe 100644
--- a/src/main/java/seedu/address/commons/util/JsonUtil.java
+++ b/src/main/java/seedu/library/commons/util/JsonUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.library.commons.util;
import static java.util.Objects.requireNonNull;
@@ -20,8 +20,8 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.library.commons.core.LogsCenter;
+import seedu.library.commons.exceptions.DataConversionException;
/**
* Converts a Java object instance to JSON and vice versa
diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/library/commons/util/StringUtil.java
similarity index 95%
rename from src/main/java/seedu/address/commons/util/StringUtil.java
rename to src/main/java/seedu/library/commons/util/StringUtil.java
index 61cc8c9a1cb..e2a150c6a79 100644
--- a/src/main/java/seedu/address/commons/util/StringUtil.java
+++ b/src/main/java/seedu/library/commons/util/StringUtil.java
@@ -1,7 +1,7 @@
-package seedu.address.commons.util;
+package seedu.library.commons.util;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
+import static seedu.library.commons.util.AppUtil.checkArgument;
import java.io.PrintWriter;
import java.io.StringWriter;
diff --git a/src/main/java/seedu/library/logic/Logic.java b/src/main/java/seedu/library/logic/Logic.java
new file mode 100644
index 00000000000..eb3537879d4
--- /dev/null
+++ b/src/main/java/seedu/library/logic/Logic.java
@@ -0,0 +1,57 @@
+package seedu.library.logic;
+
+import java.nio.file.Path;
+
+import javafx.collections.ObservableList;
+import seedu.library.commons.core.GuiSettings;
+import seedu.library.logic.commands.CommandResult;
+import seedu.library.logic.commands.exceptions.CommandException;
+import seedu.library.logic.parser.exceptions.ParseException;
+import seedu.library.model.ReadOnlyLibrary;
+import seedu.library.model.bookmark.Bookmark;
+
+/**
+ * API of the Logic component
+ */
+public interface Logic {
+ /**
+ * Executes the command and returns the result.
+ * @param commandText The command as entered by the user.
+ * @return the result of the command execution.
+ * @throws CommandException If an error occurs during command execution.
+ * @throws ParseException If an error occurs during parsing.
+ */
+ CommandResult execute(String commandText) throws CommandException, ParseException;
+
+ /**
+ * Returns the Library.
+ *
+ * @see seedu.library.model.Model#getLibrary()
+ */
+ ReadOnlyLibrary getLibrary();
+
+ /** Returns an unmodifiable view of the filtered list of bookmarks */
+ ObservableList getFilteredBookmarkList();
+
+ /** Returns selected bookmark */
+ Bookmark getSelectedBookmark();
+
+ /** Returns selected indexx */
+ int getSelectedIndex();
+
+
+ /**
+ * Returns the user prefs' library file path.
+ */
+ Path getLibraryFilePath();
+
+ /**
+ * Returns the user prefs' GUI settings.
+ */
+ GuiSettings getGuiSettings();
+
+ /**
+ * Set the user prefs' GUI settings.
+ */
+ void setGuiSettings(GuiSettings guiSettings);
+}
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/library/logic/LogicManager.java
similarity index 52%
rename from src/main/java/seedu/address/logic/LogicManager.java
rename to src/main/java/seedu/library/logic/LogicManager.java
index 9d9c6d15bdc..10e5ae37293 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/library/logic/LogicManager.java
@@ -1,21 +1,21 @@
-package seedu.address.logic;
+package seedu.library.logic;
import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Logger;
import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.AddressBookParser;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.Model;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-import seedu.address.storage.Storage;
+import seedu.library.commons.core.GuiSettings;
+import seedu.library.commons.core.LogsCenter;
+import seedu.library.logic.commands.Command;
+import seedu.library.logic.commands.CommandResult;
+import seedu.library.logic.commands.exceptions.CommandException;
+import seedu.library.logic.parser.LibraryParser;
+import seedu.library.logic.parser.exceptions.ParseException;
+import seedu.library.model.Model;
+import seedu.library.model.ReadOnlyLibrary;
+import seedu.library.model.bookmark.Bookmark;
+import seedu.library.storage.Storage;
/**
* The main LogicManager of the app.
@@ -26,7 +26,7 @@ public class LogicManager implements Logic {
private final Model model;
private final Storage storage;
- private final AddressBookParser addressBookParser;
+ private final LibraryParser libraryParser;
/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
@@ -34,7 +34,7 @@ public class LogicManager implements Logic {
public LogicManager(Model model, Storage storage) {
this.model = model;
this.storage = storage;
- addressBookParser = new AddressBookParser();
+ libraryParser = new LibraryParser();
}
@Override
@@ -42,11 +42,12 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
logger.info("----------------[USER COMMAND][" + commandText + "]");
CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
+ Command command = libraryParser.parseCommand(commandText);
commandResult = command.execute(model);
try {
- storage.saveAddressBook(model.getAddressBook());
+ storage.saveLibrary(model.getLibrary());
+ storage.saveTags(model.getTags());
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}
@@ -55,18 +56,27 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return model.getAddressBook();
+ public ReadOnlyLibrary getLibrary() {
+ return model.getLibrary();
}
@Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
+ public ObservableList getFilteredBookmarkList() {
+ return model.getFilteredBookmarkList();
}
@Override
- public Path getAddressBookFilePath() {
- return model.getAddressBookFilePath();
+ public Bookmark getSelectedBookmark() {
+ return model.getSelectedBookmark();
+ }
+ @Override
+ public int getSelectedIndex() {
+ return model.getSelectedIndex();
+ }
+
+ @Override
+ public Path getLibraryFilePath() {
+ return model.getLibraryFilePath();
}
@Override
diff --git a/src/main/java/seedu/library/logic/commands/AddCommand.java b/src/main/java/seedu/library/logic/commands/AddCommand.java
new file mode 100644
index 00000000000..9543ab5947d
--- /dev/null
+++ b/src/main/java/seedu/library/logic/commands/AddCommand.java
@@ -0,0 +1,91 @@
+package seedu.library.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_AUTHOR;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_GENRE;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_PROGRESS;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_RATING;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_TITLE;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_URL;
+
+import seedu.library.logic.commands.exceptions.CommandException;
+import seedu.library.model.Model;
+import seedu.library.model.bookmark.Bookmark;
+
+/**
+ * Adds a bookmark to the address book.
+ */
+public class AddCommand extends Command {
+
+ public static final String COMMAND_WORD = "add";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a bookmark to the library. "
+ + "Parameters: "
+ + PREFIX_TITLE + "TITLE "
+ + PREFIX_GENRE + "GENRE "
+ + "[" + PREFIX_AUTHOR + "AUTHOR] "
+ + "[" + PREFIX_PROGRESS + "PROGRESS] "
+ + "[" + PREFIX_RATING + "RATING] "
+ + "[" + PREFIX_URL + "URL] "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_TITLE + "Hobbit "
+ + PREFIX_AUTHOR + "J. R. R. Tolkien "
+ + PREFIX_PROGRESS + "1 1 1 "
+ + PREFIX_GENRE + "Fantasy "
+ + PREFIX_RATING + "5 "
+ + PREFIX_URL + "https://allnovel.net/the-hobbit.html "
+ + PREFIX_TAG + "Literature Reading "
+ + PREFIX_TAG + "Holiday reading list";
+
+ public static final String MESSAGE_SUCCESS = "New bookmark added: %1$s";
+ public static final String MESSAGE_DUPLICATE_BOOKMARK = "This bookmark already exists in the library";
+ public static final String MESSAGE_ERROR_TAG = "Tag not in tag list.";
+
+ private final Bookmark toAdd;
+ private final boolean hasTags;
+
+ /**
+ * Creates an AddCommand to add the specified {@code Bookmark}
+ */
+ public AddCommand(Bookmark bookmark, boolean hasTags) {
+ requireNonNull(bookmark);
+ toAdd = bookmark;
+ this.hasTags = hasTags;
+ }
+
+ /**
+ * Creates an AddCommand to add the specified {@code Bookmark}
+ * with default value false for hasTags
+ */
+ public AddCommand(Bookmark bookmark) {
+ requireNonNull(bookmark);
+ this.toAdd = bookmark;
+ this.hasTags = false;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasBookmark(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_BOOKMARK);
+ }
+
+ if (hasTags && !model.hasTag(toAdd.getTags())) {
+ throw new CommandException(MESSAGE_ERROR_TAG);
+ }
+
+ model.addBookmark(toAdd);
+ model.updateSelectedIndex(-1);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddCommand // instanceof handles nulls
+ && toAdd.equals(((AddCommand) other).toAdd));
+ }
+}
diff --git a/src/main/java/seedu/library/logic/commands/AddTagCommand.java b/src/main/java/seedu/library/logic/commands/AddTagCommand.java
new file mode 100644
index 00000000000..0a9ce0e9c4a
--- /dev/null
+++ b/src/main/java/seedu/library/logic/commands/AddTagCommand.java
@@ -0,0 +1,59 @@
+package seedu.library.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Set;
+
+import seedu.library.logic.commands.exceptions.CommandException;
+import seedu.library.model.Model;
+import seedu.library.model.tag.Tag;
+
+/**
+ * Adds a bookmark to the address book.
+ */
+public class AddTagCommand extends Command {
+
+ public static final String COMMAND_WORD = "addtag";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds tags to list of tags. "
+ + "Parameters: "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_TAG + "Literature Reading "
+ + PREFIX_TAG + "Holiday reading list";
+
+ public static final String MESSAGE_SUCCESS = "New tags added: %1$s";
+ public static final String MESSAGE_DUPLICATE_TAGS = "This tag already exists in the tag list";
+
+ private final Set toAdd;
+
+ /**
+ * Creates an AddTagCommand to add the specified {@code Tag}
+ */
+ public AddTagCommand(Set tagList) {
+ requireNonNull(tagList);
+ toAdd = tagList;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasTag(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_TAGS);
+ }
+
+ model.addTags(toAdd);
+ model.updateSelectedIndex(-1);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddTagCommand // instanceof handles nulls
+ && toAdd.equals(((AddTagCommand) other).toAdd));
+ }
+}
+
diff --git a/src/main/java/seedu/library/logic/commands/ClearCommand.java b/src/main/java/seedu/library/logic/commands/ClearCommand.java
new file mode 100644
index 00000000000..42d77c6857e
--- /dev/null
+++ b/src/main/java/seedu/library/logic/commands/ClearCommand.java
@@ -0,0 +1,24 @@
+package seedu.library.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.library.model.Library;
+import seedu.library.model.Model;
+
+/**
+ * Clears the library.
+ */
+public class ClearCommand extends Command {
+
+ public static final String COMMAND_WORD = "clear";
+ public static final String MESSAGE_SUCCESS = "Library has been cleared!";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.setLibrary(new Library());
+ model.updateSelectedIndex(-1);
+ return new CommandResult(MESSAGE_SUCCESS, false, false, true);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/library/logic/commands/Command.java
similarity index 78%
rename from src/main/java/seedu/address/logic/commands/Command.java
rename to src/main/java/seedu/library/logic/commands/Command.java
index 64f18992160..6f13418800c 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/library/logic/commands/Command.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.commands;
+package seedu.library.logic.commands;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
+import seedu.library.logic.commands.exceptions.CommandException;
+import seedu.library.model.Model;
/**
* Represents a command with hidden internal logic and the ability to be executed.
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/library/logic/commands/CommandResult.java
similarity index 84%
rename from src/main/java/seedu/address/logic/commands/CommandResult.java
rename to src/main/java/seedu/library/logic/commands/CommandResult.java
index 92f900b7916..0b89fe64f44 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/library/logic/commands/CommandResult.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands;
+package seedu.library.logic.commands;
import static java.util.Objects.requireNonNull;
@@ -17,13 +17,17 @@ public class CommandResult {
/** The application should exit. */
private final boolean exit;
+ /** Update the display on rightside of UI */
+ private final boolean update;
+
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
- public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean update) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
+ this.update = update;
}
/**
@@ -31,7 +35,7 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser) {
- this(feedbackToUser, false, false);
+ this(feedbackToUser, false, false, false);
}
public String getFeedbackToUser() {
@@ -45,6 +49,9 @@ public boolean isShowHelp() {
public boolean isExit() {
return exit;
}
+ public boolean isUpdate() {
+ return update;
+ }
@Override
public boolean equals(Object other) {
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/library/logic/commands/DeleteCommand.java
similarity index 52%
rename from src/main/java/seedu/address/logic/commands/DeleteCommand.java
rename to src/main/java/seedu/library/logic/commands/DeleteCommand.java
index 02fd256acba..7397e37b984 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/library/logic/commands/DeleteCommand.java
@@ -1,28 +1,28 @@
-package seedu.address.logic.commands;
+package seedu.library.logic.commands;
import static java.util.Objects.requireNonNull;
import java.util.List;
-import seedu.address.commons.core.Messages;
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import seedu.library.commons.core.Messages;
+import seedu.library.commons.core.index.Index;
+import seedu.library.logic.commands.exceptions.CommandException;
+import seedu.library.model.Model;
+import seedu.library.model.bookmark.Bookmark;
/**
- * Deletes a person identified using it's displayed index from the address book.
+ * Deletes a bookmark identified using it's displayed index from the library.
*/
public class DeleteCommand extends Command {
public static final String COMMAND_WORD = "delete";
public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Deletes the person identified by the index number used in the displayed person list.\n"
+ + ": Deletes the bookmark identified by the index number used in the displayed bookmark list.\n"
+ "Parameters: INDEX (must be a positive integer)\n"
+ "Example: " + COMMAND_WORD + " 1";
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
+ public static final String MESSAGE_DELETE_BOOKMARK_SUCCESS = "Deleted Bookmark: %1$s";
private final Index targetIndex;
@@ -33,15 +33,16 @@ public DeleteCommand(Index targetIndex) {
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getFilteredBookmarkList();
if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ throw new CommandException(Messages.MESSAGE_INVALID_BOOKMARK_DISPLAYED_INDEX);
}
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
- model.deletePerson(personToDelete);
- return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete));
+ Bookmark bookmarkToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteBookmark(bookmarkToDelete);
+ model.updateSelectedIndex(-1);
+ return new CommandResult(String.format(MESSAGE_DELETE_BOOKMARK_SUCCESS, bookmarkToDelete), false, false, true);
}
@Override
diff --git a/src/main/java/seedu/library/logic/commands/DeleteTagCommand.java b/src/main/java/seedu/library/logic/commands/DeleteTagCommand.java
new file mode 100644
index 00000000000..4c885b3f5fc
--- /dev/null
+++ b/src/main/java/seedu/library/logic/commands/DeleteTagCommand.java
@@ -0,0 +1,54 @@
+package seedu.library.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.library.commons.core.Messages;
+import seedu.library.logic.commands.exceptions.CommandException;
+import seedu.library.model.Model;
+import seedu.library.model.tag.Tag;
+
+/**
+ * Deletes a tag identified by its name from the tag list.
+ */
+public class DeleteTagCommand extends Command {
+
+ public static final String COMMAND_WORD = "dtag";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the tag identified by the name used in displayed tag list.\n"
+ + "Parameters: Tag name\n"
+ + "Example: " + COMMAND_WORD + " MaleProtagonist";
+
+ public static final String MESSAGE_DELETE_TAG_SUCCESS = "Deleted Tag: %1$s";
+ public static final String PREVENT_USED_TAG_DELETION = "Cannot delete tags that are currently used by bookmarks";
+
+ private final Tag tag;
+
+ public DeleteTagCommand(Tag tag) {
+ this.tag = tag;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.tagInUse(tag)) {
+ throw new CommandException(PREVENT_USED_TAG_DELETION);
+ }
+
+ if (!model.hasTag(tag)) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TAG_NAME);
+ }
+
+ model.deleteTag(tag);
+ model.updateSelectedIndex(-1);
+ return new CommandResult(String.format(MESSAGE_DELETE_TAG_SUCCESS, tag), false, false, true);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteTagCommand // instanceof handles nulls
+ && tag.equals(((DeleteTagCommand) other).tag)); // state check
+ }
+}
diff --git a/src/main/java/seedu/library/logic/commands/EditCommand.java b/src/main/java/seedu/library/logic/commands/EditCommand.java
new file mode 100644
index 00000000000..6f6640db8a7
--- /dev/null
+++ b/src/main/java/seedu/library/logic/commands/EditCommand.java
@@ -0,0 +1,264 @@
+package seedu.library.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_AUTHOR;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_GENRE;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_PROGRESS;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_RATING;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_TITLE;
+import static seedu.library.logic.parser.CliSyntax.PREFIX_URL;
+import static seedu.library.model.Model.PREDICATE_SHOW_ALL_BOOKMARKS;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.library.commons.core.Messages;
+import seedu.library.commons.core.index.Index;
+import seedu.library.commons.util.CollectionUtil;
+import seedu.library.logic.commands.exceptions.CommandException;
+import seedu.library.model.Model;
+import seedu.library.model.bookmark.Author;
+import seedu.library.model.bookmark.Bookmark;
+import seedu.library.model.bookmark.Genre;
+import seedu.library.model.bookmark.Progress;
+import seedu.library.model.bookmark.Rating;
+import seedu.library.model.bookmark.Title;
+import seedu.library.model.bookmark.Url;
+import seedu.library.model.tag.Tag;
+
+/**
+ * Edits the details of an existing bookmark in the library.
+ */
+public class EditCommand extends Command {
+
+ public static final String COMMAND_WORD = "edit";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the bookmark identified "
+ + "by the index number used in the displayed bookmark list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_TITLE + "TITLE] "
+ + "[" + PREFIX_AUTHOR + "AUTHOR] "
+ + "[" + PREFIX_PROGRESS + "PROGRESS] "
+ + "[" + PREFIX_GENRE + "GENRE] "
+ + "[" + PREFIX_RATING + "RATING] "
+ + "[" + PREFIX_URL + "URL] "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_PROGRESS + "Finished "
+ + PREFIX_GENRE + "Fantasy";
+
+ public static final String MESSAGE_EDIT_BOOKMARK_SUCCESS = "Edited Bookmark: %1$s";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_DUPLICATE_BOOKMARK = "This bookmark already exists in the library.";
+ public static final String MESSAGE_ERROR_TAG = "Tag not in tag list.";
+
+ private final Index index;
+ private final EditBookmarkDescriptor editBookmarkDescriptor;
+
+ /**
+ * @param index of the bookmark in the filtered bookmark list to edit
+ * @param editBookmarkDescriptor details to edit the bookmark with
+ */
+ public EditCommand(Index index, EditBookmarkDescriptor editBookmarkDescriptor) {
+ requireNonNull(index);
+ requireNonNull(editBookmarkDescriptor);
+
+ this.index = index;
+ this.editBookmarkDescriptor = new EditBookmarkDescriptor(editBookmarkDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredBookmarkList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_BOOKMARK_DISPLAYED_INDEX);
+ }
+
+ Bookmark bookmarkToEdit = lastShownList.get(index.getZeroBased());
+ Bookmark editedBookmark = createEditedBookmark(bookmarkToEdit, editBookmarkDescriptor);
+
+ if (!bookmarkToEdit.isSameBookmark(editedBookmark) && model.hasBookmark(editedBookmark)) {
+ throw new CommandException(MESSAGE_DUPLICATE_BOOKMARK);
+ }
+
+ if (!model.hasTag(editedBookmark.getTags())) {
+ throw new CommandException(MESSAGE_ERROR_TAG);
+ }
+
+ model.setBookmark(bookmarkToEdit, editedBookmark);
+ model.updateFilteredBookmarkList(PREDICATE_SHOW_ALL_BOOKMARKS);
+ model.updateSelectedIndex(-1);
+ return new CommandResult(String.format(MESSAGE_EDIT_BOOKMARK_SUCCESS, editedBookmark), false, false, true);
+ }
+
+ /**
+ * Creates and returns a {@code Bookmark} with the details of {@code bookmarkToEdit}
+ * edited with {@code editBookmarkDescriptor}.
+ */
+ private static Bookmark createEditedBookmark(Bookmark bookmarkToEdit,
+ EditBookmarkDescriptor editBookmarkDescriptor) {
+ assert bookmarkToEdit != null;
+
+ Title updatedTitle = editBookmarkDescriptor.getTitle().orElse(bookmarkToEdit.getTitle());
+ Progress updatedProgress = editBookmarkDescriptor.getProgress().orElse(bookmarkToEdit.getProgress());
+ Genre updatedGenre = editBookmarkDescriptor.getGenre().orElse(bookmarkToEdit.getGenre());
+ Author updatedAuthor = editBookmarkDescriptor.getAuthor().orElse(bookmarkToEdit.getAuthor());
+ Rating updatedRating = editBookmarkDescriptor.getRating().orElse(bookmarkToEdit.getRating());
+ Url updatedUrl = editBookmarkDescriptor.getUrl().orElse(bookmarkToEdit.getUrl());
+ Set updatedTags = editBookmarkDescriptor.getTags().orElse(bookmarkToEdit.getTags());
+
+ return new Bookmark(updatedTitle, updatedProgress, updatedGenre,
+ updatedAuthor, updatedRating, updatedUrl, updatedTags);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditCommand)) {
+ return false;
+ }
+
+ // state check
+ EditCommand e = (EditCommand) other;
+ return index.equals(e.index)
+ && editBookmarkDescriptor.equals(e.editBookmarkDescriptor);
+ }
+
+ /**
+ * Stores the details to edit the bookmark with. Each non-empty field value will replace the
+ * corresponding field value of the bookmark.
+ */
+ public static class EditBookmarkDescriptor {
+ private Title title;
+ private Progress progress;
+ private Genre genre;
+ private Author author;
+ private Rating rating;
+ private Set tags;
+ private Url url;
+
+ public EditBookmarkDescriptor() {}
+
+ /**
+ * Copy constructor.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public EditBookmarkDescriptor(EditBookmarkDescriptor toCopy) {
+ setTitle(toCopy.title);
+ setProgress(toCopy.progress);
+ setGenre(toCopy.genre);
+ setAuthor(toCopy.author);
+ setRating(toCopy.rating);
+ setTags(toCopy.tags);
+ setUrl(toCopy.url);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(title, progress, genre, author, rating, url, tags);
+ }
+
+ public void setTitle(Title title) {
+ this.title = title;
+ }
+
+ public Optional getTitle() {
+ return Optional.ofNullable(title);
+ }
+
+ public void setProgress(Progress progress) {
+ this.progress = progress;
+ }
+
+ public Optional