Skip to content

Commit

Permalink
Merge pull request #71 from larrywang0701/more-event-feature
Browse files Browse the repository at this point in the history
  • Loading branch information
zekone authored Nov 1, 2023
2 parents 43b676f + 80c07e5 commit 3ba728f
Show file tree
Hide file tree
Showing 34 changed files with 796 additions and 87 deletions.
17 changes: 14 additions & 3 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,20 @@ Examples:

### Listing all events : `list events`

Shows a list of all events.
Shows a list of all events or events within a specified time interval.

Format: `list events`
Format: `list events [-descending] [-st filter_start_time] [-et filter_end_time]` (start time and end time are inclusive)

Arguments `-st` and `-et` must both present or both not present.
- If they both not present, the application will show you all events in the address book.
- If they both present, the application will show you the events within the time interval.

By default, the list of events are sorted by the start time in ascending order (the event with the earliest start time is in the beginning). If you want to use descending order, add `-descending` to the command.

Examples
* `list events`
* `list events -st 2023-11-01 -et 2023-11-02`
* `list events -descending -st 2023-11-01 -et 2023-11-02`

### Deleting an event : `delete event`

Expand Down Expand Up @@ -226,5 +237,5 @@ Action | Format, Examples
**List Notes** | `list notes`
**Add Event** | `add event -id CONTACT_ID -en EVENT_NAME -st START_TIME [-et END_TIME] [-loc LOCATION] [-info INFORMATION]` <br> e.g., `add event -id 1 -en Meeting with professor -st 12:00 -et 01:00 -loc COM 1 Basement -info Discuss the project implementation with the professor`
**Delete Event** | `delete event -id CONTACT_ID -eid EVENT_ID`<br> e.g., `delete event -id 1 -eid 1`
**List Events** | `list events`
**List Events** | `list events [-descending] [-st filter_start_time] [-et filter_end_time]`<br> e.g., `list events -descending -st 2023-11-01 -et 2023-11-02`
**Help** | `help`
48 changes: 47 additions & 1 deletion src/main/java/seedu/address/commons/util/DateTimeUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package seedu.address.commons.util;

import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
Expand All @@ -15,6 +18,7 @@ public class DateTimeUtil {
* @throws DateTimeParseException If the string cannot be parsed into LocalDateTime
*/
public static LocalDateTime parseString(String str) throws DateTimeParseException {
requireNonNull(str);
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm[:ss]");
LocalDateTime result = null;
try {
Expand All @@ -25,7 +29,10 @@ public static LocalDateTime parseString(String str) throws DateTimeParseExceptio
String appendTime = " 00:00:00";
result = LocalDateTime.parse(str + appendTime, formatter1);
} else {
String appendDate = now.getYear() + "-" + now.getMonthValue() + "-" + now.getDayOfMonth() + " ";
int month = now.getMonthValue();
int day = now.getDayOfMonth();
String appendDate = now.getYear() + "-" + (month <= 9 ? "0" + month : month)
+ "-" + (day <= 9 ? "0" + day : day) + " ";
result = LocalDateTime.parse(appendDate + str, formatter1);
}
}
Expand All @@ -39,7 +46,46 @@ public static LocalDateTime parseString(String str) throws DateTimeParseExceptio
* @return The String representation of this {@code LocalDateTime} object, in the format {@code yyyy-MM-dd HH:mm:ss}
*/
public static String toFormattedString(LocalDateTime time) {
requireNonNull(time);
return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}

/**
* Return {@code true} if {@code timeToCheck} is between {@code intervalStart} and {@code intervalEnd} (inclusive).
* In another word, returns {@code true} when {@code intervalStart} <= {@code timeToCheck} <= {@code intervalEnd}
*
* @param intervalStart The start time for the interval
* @param intervalEnd The end time for the interval
* @param timeToCheck The time that is needed for checking
* @return Whether {@code timeToCheck} is between {@code intervalStart} and {@code intervalEnd} or not
*/
public static boolean withinTimeInterval(LocalDateTime intervalStart,
LocalDateTime intervalEnd, LocalDateTime timeToCheck) {
requireAllNonNull(intervalStart, intervalEnd, timeToCheck);
assert intervalStart.equals(intervalEnd) || intervalStart.isBefore(intervalEnd);
return timeToCheck.equals(intervalStart)
|| timeToCheck.equals(intervalEnd)
|| (timeToCheck.isAfter(intervalStart) && timeToCheck.isBefore(intervalEnd));
}

/**
* Return {@code true} if the time interval {@code intervalAStart}~{@code intervalAEnd}
* overlaps with the time interval {@code intervalBStart}~{@code intervalBEnd} (inclusive of start and end time).
* Start time is inclusive, end time is exclusive
*
* @param intervalAStart The start time for the first interval
* @param intervalAEnd The end time for the first interval
* @param intervalBStart The start time for the second interval
* @param intervalBEnd The end time for the second interval
* @return Whether the two time intervals overlap or not
*/
public static boolean timeIntervalsOverlap(LocalDateTime intervalAStart, LocalDateTime intervalAEnd,
LocalDateTime intervalBStart, LocalDateTime intervalBEnd) {
requireAllNonNull(intervalAStart, intervalAEnd, intervalBStart, intervalBEnd);
return withinTimeInterval(intervalAStart, intervalAEnd, intervalBStart)
|| withinTimeInterval(intervalAStart, intervalAEnd, intervalBEnd)
|| withinTimeInterval(intervalBStart, intervalBEnd, intervalAStart)
|| withinTimeInterval(intervalBStart, intervalBEnd, intervalAEnd);
}

}
17 changes: 17 additions & 0 deletions src/main/java/seedu/address/commons/util/StringUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;

import seedu.address.model.event.Event;

/**
* Helper functions for handling strings.
Expand Down Expand Up @@ -65,4 +68,18 @@ public static boolean isNonZeroUnsignedInteger(String s) {
return false;
}
}

/**
* Convert the event list to a human-readable string
*
* @param eventList The event list
* @return The filtered event list as string
*/
public static String eventListToString(List<? extends Event> eventList) {
StringBuilder str = new StringBuilder();
eventList.forEach(
evt -> str.append(evt.getUiText()).append("\n")
);
return str.toString();
}
}
1 change: 1 addition & 0 deletions src/main/java/seedu/address/logic/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ 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_START_TIME_AFTER_END_TIME = "Start time %s is after the end time %s!\n";
public static final String MESSAGE_INVALID_INTEGER_ARGUMENT =
"The provided argument is not a valid integer! \n%1$s";
public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class AddEventCommand extends AddCommand {

public static final String SECONDARY_COMMAND_WORD = "event";
public static final String MESSAGE_SUCCESS = "New event added: ";
public static final String MESSAGE_ERROR = "Error: ";
public static final String MESSAGE_CONTACT_NOT_FOUND = "Can not find the target contact with ID: ";

public static final String MESSAGE_USAGE = COMMAND_WORD + " " + SECONDARY_COMMAND_WORD
Expand All @@ -41,7 +42,11 @@ public CommandResult execute(Model model) throws CommandException {
if (person == null) {
throw new CommandException(MESSAGE_CONTACT_NOT_FOUND + this.contactId.getId());
}
person.addEvent(this.toAdd);
try {
model.addEvent(this.toAdd, person);
} catch (Exception e) {
return new CommandResult(MESSAGE_ERROR + e.getMessage());
}

return new CommandResult(MESSAGE_SUCCESS + toAdd.getName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import seedu.address.model.Model;
import seedu.address.model.event.Event;
import seedu.address.model.event.EventID;
import seedu.address.model.event.exceptions.EventNotFoundException;
import seedu.address.model.person.ContactID;
import seedu.address.model.person.Person;

Expand Down Expand Up @@ -39,11 +40,12 @@ public CommandResult execute(Model model) throws CommandException {
if (person == null) {
throw new CommandException(MESSAGE_PERSON_NOT_FOUND + this.contactId);
}
Event deletedEvent = person.removeEventByUserFriendlyId(this.eventIdToDelete);
if (deletedEvent == null) {
try {
Event deletedEvent = model.removeEventByID(this.eventIdToDelete, person);
return new CommandResult(MESSAGE_SUCCESS + this.eventIdToDelete
+ ". " + deletedEvent.getName());
} catch (EventNotFoundException e) {
throw new CommandException(MESSAGE_EVENT_NOT_FOUND + this.eventIdToDelete);
}

return new CommandResult(MESSAGE_SUCCESS + this.eventIdToDelete + ". " + deletedEvent.getName());
}
}
58 changes: 52 additions & 6 deletions src/main/java/seedu/address/logic/commands/ListEventCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,73 @@

import static java.util.Objects.requireNonNull;

import java.time.LocalDateTime;
import java.util.List;

import seedu.address.commons.util.DateTimeUtil;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.Person;
import seedu.address.model.event.Event;
import seedu.address.model.event.EventTime;

/**
* The command handler for {@code list events} command
*/
public class ListEventCommand extends ListCommand {
public static final String SECONDARY_COMMAND_WORD = "events";
public static final String MESSAGE = "Here are all the events in this address book:\n";
public static final String MESSAGE_ALL = "Here are all the events in this address book ";
public static final String MESSAGE_FILTERED = "Here are the events in this address book within the time interval ";
public static final String MESSAGE_ASCENDING = "(in ascending order):\n";
public static final String MESSAGE_DESCENDING = "(in descending order):\n";

public static final String MESSAGE_USAGE = COMMAND_WORD + SECONDARY_COMMAND_WORD
+ ": Lists all events in the address book";
public static final String MESSAGE_USAGE = COMMAND_WORD + " " + SECONDARY_COMMAND_WORD
+ " [-descending] [-st filter_start_time] [-et filter_end_time]"
+ " (-st and -et must either both present or both not present)";

private LocalDateTime filterStartTime;
private LocalDateTime filterEndTime;
private boolean sortAscending;

/**
* Constructor for {@code ListEventCommand} class
* @param filterStartTime The start time for filter
* @param filterEndTime The end time for filter
* @param sortAscending Set to {@code true} to sort the events by start time in ascending order,
* {@code false} in descending order.
*/
public ListEventCommand(EventTime filterStartTime, EventTime filterEndTime, boolean sortAscending) {
this.filterStartTime = filterStartTime.getTime();
this.filterEndTime = filterEndTime.getTime();
this.sortAscending = sortAscending;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Person> persons = model.getAddressBook().getPersonList();
String result = MESSAGE + model.getAddressBook().eventListToString();
assert (filterStartTime == null && filterEndTime == null) || (filterStartTime != null && filterEndTime != null);
String result = "";
if (filterStartTime == null) {
model.updateFilteredEventList(evt -> true); // Remove the filter to get the full event list
result = MESSAGE_ALL;
} else {
model.updateFilteredEventList(
evt -> DateTimeUtil.withinTimeInterval(this.filterStartTime, this.filterEndTime,
evt.getStartTime())
);
result = MESSAGE_FILTERED;
}
result += this.sortAscending ? MESSAGE_ASCENDING : MESSAGE_DESCENDING;
List<Event> eventList = model.getSortedFilteredEventList((o1, o2) -> {
LocalDateTime startTime1 = o1.getStartTime();
LocalDateTime startTime2 = o2.getStartTime();
return (startTime1.isBefore(startTime2)
? 1
: startTime1.equals(startTime2)
? 0
: -1) * (sortAscending ? -1 : 1);
});
result += StringUtil.eventListToString(eventList);
return new CommandResult(result);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_END_TIME;
import static seedu.address.logic.Messages.MESSAGE_START_TIME_AFTER_END_TIME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_END_TIME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_INFORMATION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_LOCATION;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EVENT_START_TIME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PERSON_ID;
import static seedu.address.logic.parser.CliSyntax.PREFIX_START_TIME;

import seedu.address.logic.commands.AddEventCommand;
import seedu.address.logic.parser.exceptions.ParseException;
Expand All @@ -26,26 +27,29 @@ public class AddEventCommandParser implements Parser<AddEventCommand> {
@Override
public AddEventCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_PERSON_ID,
PREFIX_EVENT_NAME, PREFIX_EVENT_START_TIME, PREFIX_EVENT_END_TIME,
PREFIX_EVENT_NAME, PREFIX_START_TIME, PREFIX_END_TIME,
PREFIX_EVENT_LOCATION, PREFIX_EVENT_INFORMATION);

if (!ParserUtil.arePrefixesPresent(argMultimap, PREFIX_PERSON_ID, PREFIX_EVENT_NAME,
PREFIX_EVENT_START_TIME) || !argMultimap.getPreamble().isEmpty()) {
PREFIX_START_TIME) || !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddEventCommand.MESSAGE_USAGE));
}

argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_PERSON_ID,
PREFIX_EVENT_NAME, PREFIX_EVENT_START_TIME, PREFIX_EVENT_END_TIME, PREFIX_EVENT_LOCATION,
PREFIX_EVENT_NAME, PREFIX_START_TIME, PREFIX_END_TIME, PREFIX_EVENT_LOCATION,
PREFIX_EVENT_INFORMATION);

EventName eventName = ParserUtil.parseEventName(argMultimap.getValue(PREFIX_EVENT_NAME).get());
EventTime startTime = ParserUtil.parseEventTime(argMultimap.getValue(PREFIX_EVENT_START_TIME).get());
EventTime endTime = ParserUtil.parseEventTime(argMultimap.getValue(PREFIX_EVENT_END_TIME).orElseGet(()->null));
EventTime startTime = ParserUtil.parseEventTime(argMultimap.getValue(PREFIX_START_TIME).get());
EventTime endTime = ParserUtil.parseEventTime(argMultimap.getValue(PREFIX_END_TIME).orElseGet(()->null));
EventLocation location =
ParserUtil.parseEventLocation(argMultimap.getValue(PREFIX_EVENT_LOCATION).orElseGet(()->null));
EventInformation information =
ParserUtil.parseEventInformation(argMultimap.getValue(PREFIX_EVENT_INFORMATION).orElseGet(()->null));
ContactID contactId = ParserUtil.parseContactID(argMultimap.getValue(PREFIX_PERSON_ID).get());
if (startTime.isAfter(endTime)) {
throw new ParseException(String.format(MESSAGE_START_TIME_AFTER_END_TIME, startTime, endTime));
}
Event newEvent = new Event(eventName, startTime, endTime, location, information);

return new AddEventCommand(contactId, newEvent);
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/seedu/address/logic/parser/CliSyntax.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ public class CliSyntax {
public static final Prefix PREFIX_NOTE_TITLE = new Prefix("-tit");
public static final Prefix PREFIX_NOTE_CONTENT = new Prefix("-con");
public static final Prefix PREFIX_EVENT_NAME = new Prefix("-en");
public static final Prefix PREFIX_EVENT_START_TIME = new Prefix("-st");
public static final Prefix PREFIX_EVENT_END_TIME = new Prefix("-et");
public static final Prefix PREFIX_START_TIME = new Prefix("-st");
public static final Prefix PREFIX_END_TIME = new Prefix("-et");
public static final Prefix PREFIX_EVENT_LOCATION = new Prefix("-loc");
public static final Prefix PREFIX_EVENT_INFORMATION = new Prefix("-info");
public static final Prefix PREFIX_SORT_DESCENDING = new Prefix("-descending");

public static final ArrayList<String> COMMAND_LIST = new ArrayList<String>(Arrays.asList(
AddCommand.COMMAND_WORD,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import seedu.address.logic.parser.exceptions.ParseException;

/**
* The parser for all secondary {@code delete} commands
* The parser for {@code help} command
*/
public class HelpCommandParser implements Parser<HelpCommand> {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public ListCommand parse(String userInput) throws ParseException {
case ListNoteCommand.SECONDARY_COMMAND_WORD:
return new ListNoteCommand();
case ListEventCommand.SECONDARY_COMMAND_WORD:
return new ListEventCommand();
return new ListEventCommandParser().parse(args);
default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
Expand Down
Loading

0 comments on commit 3ba728f

Please sign in to comment.