Skip to content

Commit

Permalink
Merge branch 'master' into branch-UserGuide
Browse files Browse the repository at this point in the history
  • Loading branch information
joytqt-1202 authored Mar 30, 2023
2 parents 19641c9 + 9a827f3 commit 14daf72
Show file tree
Hide file tree
Showing 66 changed files with 1,226 additions and 289 deletions.
82 changes: 81 additions & 1 deletion docs/DeveloperGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ The following diagram shows the Class Diagram of the `DeleteCommand` hierarchy:

The following diagram shows the Sequence Diagram of executing a `DeleteMultipleModulesCommand`:

![DeleteMultpleModulesCommandSequential](images/delete/deleteCommandSequenceDiagram.png)
![DeleteMultpleModulesCommandSequential](images/delete/DeleteModuleSequenceDiagram.png)

The following is a description of the code execution flow
1. `DeleteCommandParser#parse(String)` takes the user's input as a `String` argument and determines the intention of the command (delete module, lecture or video).
Expand Down Expand Up @@ -281,6 +281,86 @@ The following table below depicts the consideration of inputs against the user'

### Mark / UnMARK

The proposed mark command supports:
1. Marking unmarked videos as watched
2. Marking marked videos as unwatched
3. Marking multiple videos in 1. and 2.

- E.g.: User wishes to mark a video "Vid 1" in lecture "Week 1" of module "CS2040S" as watched.
Executing `mark Vid 1 /mod CS2040S /lec Week 1` would allow the user to do so, unless either one of the following conditions are true:
1. the module (CS2040S) does not exist in the Tracker
2. the lecture (Week 1) does not exist in the module (CS2040S)
3. the video (Vid 1) does not exist in the lecture of the module (CS2040S > Week 1)
4. the video (CS2040S > Week 1 > Vid 1) has already been marked as watched
- E.g.: User wishes to mark multiple videos "Vid 3", "Vid 4" and "Lecture Summary" in lecture "Topic 4" of module "ST2334" as unwatched.
Executing `unmark Vid 3, Vid 4, Lecture Summary /mod ST2334 /lec Topic 1` would allow the user to do so, unless either on of the following conditions are true:
1. the module (ST2334) doese not exist in the Tracker
2. the lecture (Topic 1) does not exist in the module (ST2334)
3. either of the videos (Vid 3, Vid 4, Lecture Summary) does not exist in the lecture of the module (ST2334 > Topic 1)
4. either of the videos (Vid 3, Vid 4, Lecture Summary) has already been marked as unwatched

This feature's behaviour is dependent on the arguments provided by the user, as well as the state of Le Tracker.

#### Implementation Details

The feature utilises the following classes:
- `MarkCommand`: Abstract class extending from `Command` for commands that mark a specified video as watched or unwatched
- `MarkAsWatchedCommandParser`: parses arguments appropriately for `MarkAsWatchedCommand` to be returned to be executed
- `MarkAsWatchedCommand`: Subclass of `MarkCommand` which handles marking a video as watched. Can handle marking multiple videos as well

- `MarkAsUnwatchedCommandParser`: parses arguments appropriately for `MarkAsUnwatchedCommand` and `MarkMultipleAsUnwatchedCommand` to be returned to be executed
- `MarkAsUnwatchedCommand`: Subclass of `MarkCommand` which handles marking a video as unwatched
- `MarkMultipleAsUnwatchedCommand`: Subclass of `MarkCommand` which handles marking multiple videos as unwatched

The following diagram shows the Sequence Diagram of executing a `MarkAsWatchedCommand`:

![MarkAsWatched](diagrams/MarkAsWatchedSequenceDiagram.png)

The following is a description of the code execution flow
1. `MarkAsWatchedCommandParser#parse(String)` / `MarkAsUnwatchedCommandParser#parse(String` takes the user's input as a `String` argument and determines the target video to be marked. The following table below depicts the command returned against the user's intent

| Parser | Has Multiple Videos | Command |
| --- | --- | --- |
| `MarkAsWatchedCommandParser` | -- | `MarkAsWatchedCommand` |
| `MarkAsUnwatchedCommandParser` | Yes | `MarkAsUnwatchedCommand` |
| | No | `MarkMultipleAsUnwatchedCommand` |
| --- | --- | --- |

2. The argument values are then checked on as such:
- ModuleCode: valid module code that complies with the module code format
- LectureName: valid lecture name that does not containt symbols
- VideoName: valid lecture name that does not contain symbols

Note: LectureName and VideoName should not contain commas (","). Rather than throwing errors, Le Tracker will treat it as though the user intended to delete multiple videos

3. The appropriate `MarkCommand` subclass object is created then returned to its caller

4. Upon execution, the argument values in the `MarkCommand` subclass object are then checked on as such:
- ModuleCode: if module with ModuleCode exists in Le Tracker
- LectureName: if lecture with LectureName exists in module ModuleCode
- VideoName: if video(s) with VideoName exists in lecture LectureName of module ModuleCode and whether the video(s) is/are marked or unmarked (differs according to whether `mark` or `unmark` is called)

5. If no exceptions are thrown, Le Tracker has successfully managed to mark/unmark the specified video(s)

#### Reasons for such implementation:

1. Adhering to Open-Close Principle: Open for Extension, Closed for Modification
2. Having abstract classes to group mark commands together allows for adherance of DRY (Don't Repeat Yourself) in cases such as success message formats in every class

#### Alternatives considered:
1. Combine all featured classes into one large single class
Pros:
- all file content in one single place
- easily adheres to DRY since there would be no need to repeat information across multiple files
Cons:
- violates Open-Close Principle
- creates a large file that needs to be edited. Hard to search through

#### Possible further implementation
- Collate `MarkAsUnwatchedCommand` and `MarkMultipleAsUnwatchedCommand` into one class, similar to `MarkAsWatchedCommand`



### Find command feature

The proposed find command supports:
Expand Down
43 changes: 30 additions & 13 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ LE TRACKER is a gamified tracking application that allows fast typist to easily
- [Navigate Relatively](#navigate-relatively)
- [Navigate Directly](#navigate-directly)
- [Navigate Backwards](#navigate-backwards)
- [List Modules or Lectures or Videos](#list-modules-or-lectures-or-videos)
- [List Modules](#list-modules)
- [List Lectures of Modules](#list-lectures-of-modules)
- [List Videos of Lectures](#list-videos-of-lectures)
Expand All @@ -30,9 +31,9 @@ LE TRACKER is a gamified tracking application that allows fast typist to easily
- [Edit a Lecture](#edit-a-lecture)
- [Edit a Video](#edit-a-video)
- [Mark or Unmark a Video](#mark-or-unmark-a-video)
- [Delete a Module](#delete-a-module)
- [Delete a Lecture](#delete-a-lecture)
- [Delete a Video](#delete-a-video)
- [Delete Module](#delete-module)
- [Delete Lecture](#delete-lecture)
- [Delete Video](#delete-video)
- [Tag a module](#tag-a-module)
- [Tag a lecture](#tag-a-lecture)
- [Tag a video](#tag-a-video)
Expand Down Expand Up @@ -69,6 +70,7 @@ LE TRACKER is a gamified tracking application that allows fast typist to easily
### List

- `list`: Lists all modules/lectures/videos based on context
- `list /r`: Lists all modules from any context
- `list [/mod {module_code}]`: Lists all the lectures in a specified module
- `list [/lec {lecture_name}]`: Lists all the videos in a navigated module and specified lecture (:exclamation: only works if you are in `module` context)
- `list [/mod {module_code} /lec {lecture_name}]`: Lists all the videos in a specified module and lecture
Expand Down Expand Up @@ -178,11 +180,17 @@ Format: `nav /mod {module_code / lecture_name} [/lec {lecture_name}]`
Format: `navb`

### List Modules or Lectures or Videos

> Root context: modules, Module context: lectures, Lecture context: videos
Format: `list`

### List Modules

> Lists all modules
Format: `list`
Format: `list /r`

### List Lectures of Modules

Expand Down Expand Up @@ -329,23 +337,32 @@ Examples:

- `edit Video 1 /mod CS2040S /lec Week 1 /name Video 01 Grade Breakdown /watch /tags Intro, Short`

### Mark or Unmark a Video
### Mark or Unmark Video(s)

> Marks/Unmarks a video as watched/unwatched in a lecture of its specified module.
> Marks/Unmarks a video as watched/unwatched in a lecture of its specified module
Format:
- `mark {video_name} /mod {module_name} /lec {lecture_index}`
- `unmark {video_name} /mod {module_name} /lec {lecture_index}`

Format: `mark {video_name_1}[, {video_name_2}[, {video_name_3}[, ...]]] /mod {module_code} /lec {lecture_name}`
Parameters:
- `mark` marks `{video_name}` as watched
- `unmark` marks `{video_name}` as unwatched
- `{video_name}` can be names of multiple videos, separated by commas (",")
- if `{video_name}` contains repeated names, the repeats will be ignored

Format: `unmark {video_name_1}[, {video_name_2}[, {video_name_3}[, ...]]] /mod {module_code} /lec {lecture_name}`
Note: Calling mark or unmark would only prompt an error for already marked or unmarked videos if calling on a single video, not when calling on multiple videos in one command

- `video_name_1`, `video_name_2`, `video_name_3`, ...: Multiple videos can be specified to be deleted by specying multiple video namese, separating them by commas(",")
- Video Names must be of valid format
- If any video specified does not exist or has already been marked or unmarked (accordingly to the command called), nothing changes within the model

Examples:
- `mark Vid 1 /mod CS2040 /lec Week 1`
- `unmark Vid 2, Vid 5 /mod ST2334 /lec Topic 4`
- `mark Vid 1, Vid 2 /mod CS2040 /lec Week 1`
- `unmark Vid 2 /mod CS2040 /lec Week 1`
- `unmark Vid 1, Vid 2 /mod CS2040 /lec Week 1`

### Delete Module(s)
### Delete Module

> Deletes the specified module(s) and all its embodied content from the application
Expand All @@ -360,7 +377,7 @@ Examples:
- `delete CS2040`
- `delete CS2040, ST2334`

### Delete Lecture(s)
### Delete Lecture

> Deletes the specified lecture(s) and all its embodied content from the same specified module
Expand All @@ -376,7 +393,7 @@ Examples:
- `delete lecture 1 /mod CS2040` deletes `lecture 1` lecture found in module `CS2040`
- `delete lecture 1, lecture 2 /mod ST2334` deletes `lecture 1` and `lecture 2` lectures found in module `ST2334`

### Delete Video(s)
### Delete Video

> Deletes the specified video(s) and all its embodied content from the same specified lecture of the specified module
Expand Down
65 changes: 65 additions & 0 deletions docs/diagrams/DeleteModuleSequenceDiagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@startuml

--> ":LogicManager"
activate ":LogicManager"

":LogicManager" --> ":TrackerParser": TrackerParser()
activate ":TrackerParser"

":TrackerParser" --> ":DeleteCommandParser": parseCommand(String userInput)
activate ":DeleteCommandParser"

":DeleteCommandParser" --> ":DeleteMultipleModulesCommand": parse(String args)
activate ":DeleteMultipleModulesCommand"

":DeleteCommandParser" <-- ":DeleteMultipleModulesCommand"
deactivate ":DeleteMultipleModulesCommand"

":TrackerParser" <-- ":DeleteCommandParser"
deactivate ":DeleteCommandParser"

":LogicManager" <-- ":TrackerParser"
deactivate ":TrackerParser"

":LogicManager" --> ":DeleteMultipleModulesCommand": execute(Model m)
activate ":DeleteMultipleModulesCommand"

loop for each module specified
":DeleteMultipleModulesCommand" --> ":DeleteModuleCommand": DeleteModuleCommand()
activate ":DeleteModuleCommand"

":DeleteMultipleModulesCommand" <-- ":DeleteModuleCommand"
deactivate ":DeleteModuleCommand"

":DeleteMultipleModulesCommand" --> ":DeleteModuleCommand": execute(Model m)
activate ":DeleteModuleCommand"

":DeleteModuleCommand" --> "m:Model" : hasModule()
activate "m:Model"

":DeleteModuleCommand" <-- "m:Model": true
deactivate "m:Model"

":DeleteModuleCommand" --> "m:Model": deleteModule()
activate "m:Model"

":DeleteModuleCommand" <-- "m:Model"
deactivate "m:Model"

":DeleteModuleCommand" --> "r:CommandResult": CommandResult()
activate "r:CommandResult"

":DeleteModuleCommand" <-- "r:CommandResult": r
deactivate "r:CommandResult"

":DeleteMultipleModulesCommand" <-- ":DeleteModuleCommand": r
deactivate ":DeleteModuleCommand"
end

":LogicManager" <-- ":DeleteMultipleModulesCommand"
deactivate ":DeleteMultipleModulesCommand"

<-- ":LogicManager"
deactivate ":LogicManager"

@enduml
Binary file modified docs/images/Ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 16 additions & 2 deletions src/main/java/seedu/address/logic/commands/ClearCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import static java.util.Objects.requireNonNull;

import java.util.List;
import java.util.stream.Collectors;

import seedu.address.logic.commands.CommandResult.ModuleEditInfo;
import seedu.address.model.Model;
import seedu.address.model.module.ReadOnlyModule;

/**
* Clears the tracker.
Expand All @@ -12,11 +17,20 @@ public class ClearCommand extends Command {
public static final String COMMAND_WORD = "clear";
public static final String MESSAGE_SUCCESS = "Le Tracker has been cleared!";


@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.clearTracker();
return new CommandResult(MESSAGE_SUCCESS);
List<ReadOnlyModule> modules = model.getTracker()
.getModuleList()
.stream()
.map(x -> (ReadOnlyModule) x)
.collect(Collectors.toList());

ModuleEditInfo[] clearedModuleInfos = new ModuleEditInfo[modules.size()];
for (int i = 0; i < modules.size(); i++) {
clearedModuleInfos[i] = new ModuleEditInfo(modules.get(i), null);
}
return new CommandResult(MESSAGE_SUCCESS, clearedModuleInfos);
}
}
23 changes: 21 additions & 2 deletions src/main/java/seedu/address/logic/commands/ListCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static seedu.address.commons.core.Messages.MESSAGE_MODULE_DOES_NOT_EXIST;
import static seedu.address.logic.parser.CliSyntax.PREFIX_LECTURE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_MODULE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ROOT;
import static seedu.address.model.Model.PREDICATE_SHOW_ALL_MODULES;

import seedu.address.logic.commands.exceptions.CommandException;
Expand All @@ -26,7 +27,8 @@ public class ListCommand extends Command {
public static final String COMMAND_WORD = "list";

public static final String MESSAGE_USAGE = "Make sure that you are calling this command from the correct context.\n"
+ COMMAND_WORD + ": List modules or lectures or videos from ANY context.\n"
+ COMMAND_WORD + " " + PREFIX_ROOT + ": List modules from ANY context.\n"
+ COMMAND_WORD + ": List modules or lectures or videos depending on current context.\n"
+ COMMAND_WORD + " " + PREFIX_MODULE + " {module_code}: List lectures from MODULE context.\n"
+ COMMAND_WORD + " " + PREFIX_LECTURE + " {lecture_name}: List videos from LECTURE context.\n"
+ COMMAND_WORD + " " + PREFIX_MODULE + " {module_code} "
Expand All @@ -45,21 +47,33 @@ public class ListCommand extends Command {

public static final String MESSAGE_FAIL_CODE = "Module code format is invalid";

private final boolean isRoot;

private ModuleCode moduleCode;

private LectureName lectureName;

/**
* Creates a ListCommand to list content from current context
*/
public ListCommand() {}
public ListCommand() {
this.isRoot = false;
}

/**
* Creates a ListCommand to list module contents from any context
*/
public ListCommand(boolean isRoot) {
this.isRoot = isRoot;
}

/**
* Creates a ListCommand to list lecture contents from module context
* @param moduleCode
*/
public ListCommand(ModuleCode moduleCode) {
this.moduleCode = moduleCode;
this.isRoot = false;
}

/**
Expand All @@ -70,11 +84,16 @@ public ListCommand(ModuleCode moduleCode) {
public ListCommand(ModuleCode moduleCode, LectureName lectureName) {
this.moduleCode = moduleCode;
this.lectureName = lectureName;
this.isRoot = false;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
if (isRoot) {
return filterByModuleList(model);
}

if (moduleCode != null && lectureName != null) {
if (!model.hasLecture(moduleCode, lectureName)) {
throw new CommandException(
Expand Down
Loading

0 comments on commit 14daf72

Please sign in to comment.