diff --git a/config/checkstyle.xml b/config/checkstyle.xml index 87f758f..2a2405f 100644 --- a/config/checkstyle.xml +++ b/config/checkstyle.xml @@ -673,7 +673,7 @@ --> - + - + diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index e491766..e231db7 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -22,7 +22,6 @@ import interface_adapter.creategrouptasks.CreateGroupTasksController; import interface_adapter.creategrouptasks.CreateGroupTasksPresenter; import interface_adapter.creategrouptasks.CreateGroupTasksViewModel; -import interface_adapter.create_schedule.CreateScheduleViewModel; import interface_adapter.dashboard.DashboardViewModel; import interface_adapter.joingroup.JoinGroupController; import interface_adapter.joingroup.JoinGroupPresenter; @@ -32,7 +31,6 @@ import use_case.join_group.JoinGroupInputBoundary; import use_case.join_group.JoinGroupInteractor; import use_case.join_group.JoinGroupOutputBoundary; -import view.JoinGroupView; import interface_adapter.editgrouptask.EditGroupTaskController; import interface_adapter.editgrouptask.EditGroupTaskPresenter; import interface_adapter.editgrouptask.EditGroupTaskViewModel; @@ -50,6 +48,11 @@ import interface_adapter.manage_members.update_role.UpdateRoleControllerFactory; import interface_adapter.manage_members.view_members.ViewMembersControllerFactory; import interface_adapter.manage_members.view_pending.ViewPendingControllerFactory; +import interface_adapter.schedule.create_schedule.CreateScheduleController; +import interface_adapter.schedule.create_schedule.CreateScheduleControllerFactory; +import interface_adapter.schedule.create_schedule.CreateScheduleViewModel; +import interface_adapter.schedule.view_schedule.ScheduleTabPresenter; +import interface_adapter.schedule.view_schedule.ScheduleTabViewModel; import interface_adapter.signup.SignupController; import interface_adapter.signup.SignupPresenter; import interface_adapter.signup.SignupViewModel; @@ -102,6 +105,9 @@ public class AppBuilder { final ViewManagerModel viewManagerModel = new ViewManagerModel(); final PeopleTabViewModel peopleTabViewModel = new PeopleTabViewModel(); ViewManager viewManager = new ViewManager(cardPanel, cardLayout, viewManagerModel); + CreateScheduleViewModel createScheduleViewModel = new CreateScheduleViewModel(); + ScheduleTabViewModel groupScheduleViewModel = new ScheduleTabViewModel(); + final ScheduleTabViewModel scheduleTabViewModel = new ScheduleTabViewModel(); private final java.util.Map viewSizes = new java.util.HashMap<>(); @@ -155,7 +161,7 @@ public class AppBuilder { private EditGroupTaskViewModel editGroupTaskViewModel; private CreateGroupTasksViewModel createGroupTasksViewModel; private CreateScheduleView createScheduleView; - private CreateScheduleViewModel createScheduleViewModel; + private ScheduleTabPresenter groupSchedulePresenter; private JFrame application; private ViewTasksView viewTasksView; @@ -291,6 +297,8 @@ public AppBuilder addGroupTasksUseCases() { this.dashboardView.setCreateGroupTasksViewModel(createGroupTasksViewModel); this.dashboardView.setEditGroupTasksViewModel(editGroupTaskViewModel); this.dashboardView.setViewGroupTasksViewModel(viewGroupTasksViewModel); + this.dashboardView.setCreateScheduleViewModel(createScheduleViewModel); + this.dashboardView.setCreateScheduleView(createScheduleView); return this; } @@ -492,14 +500,38 @@ public AppBuilder addLogoutUseCase() { } /** - * Adds create schedule use case to application (Not done). - * @return this builder + * Adds create schedule view. + * @return app builder */ public AppBuilder addCreateScheduleView() { createScheduleViewModel = new CreateScheduleViewModel(); createScheduleView = new CreateScheduleView(createScheduleViewModel); return this; } + + /** + * Method to add the Create Group Use Case. + * + * @return App Builder + */ + public AppBuilder addCreateScheduleUseCase() { + CreateScheduleControllerFactory factory = new CreateScheduleControllerFactory( + userDataAccessObject, + groupDataAccessObject, + membershipDataAccessObject, + viewManagerModel, + createScheduleViewModel, + groupScheduleViewModel + ); + + CreateScheduleController modalController = + factory.create(scheduleTabViewModel); + + dashboardView.setCreateScheduleControllerFactory(factory); + createScheduleView.setCreateScheduleController(modalController); + createScheduleView.hookCreateScheduleModalOpen(application); + return this; + } /** * Build the JFrame. diff --git a/src/main/java/app/Main.java b/src/main/java/app/Main.java index 8bd252c..e767b7b 100644 --- a/src/main/java/app/Main.java +++ b/src/main/java/app/Main.java @@ -21,6 +21,7 @@ public static void main(String[] args) { .addSignupView() .addViewTasksUseCase() .addDashboardView() + .addCreateScheduleView() .addCreateGroupView() .addJoinGroupView() .addSignupUseCase() @@ -35,7 +36,7 @@ public static void main(String[] args) { .addRemoveMemberUseCase() .addRespondRequestUseCase() .addUpdateRoleUseCase() - .addCreateScheduleView() + .addCreateScheduleUseCase() .build(); application.pack(); diff --git a/src/main/java/data_access/DBMembershipDataAccessObject.java b/src/main/java/data_access/DBMembershipDataAccessObject.java index 3e8ae78..2ea17e0 100644 --- a/src/main/java/data_access/DBMembershipDataAccessObject.java +++ b/src/main/java/data_access/DBMembershipDataAccessObject.java @@ -10,6 +10,7 @@ import entity.user.UserRole; import org.bson.Document; import use_case.create_group.CreateGroupMembershipDataAccessInterface; +import use_case.create_schedule.CreateScheduleMembershipDataAccessInterface; import use_case.join_group.JoinGroupMembershipDataAccessInterface; import use_case.manage_members.remove_member.RemoveMemberDataAccessInterface; import use_case.manage_members.respond_request.RespondRequestDataAccessInterface; @@ -41,7 +42,8 @@ public class DBMembershipDataAccessObject implements EditGroupTasksMembershipDataAccessInterface, RemoveMemberDataAccessInterface, RespondRequestDataAccessInterface, - UpdateRoleDataAccessInterface { + UpdateRoleDataAccessInterface, + CreateScheduleMembershipDataAccessInterface { private static final String USER_FIELD = "user"; private static final String GROUP_FIELD = "group"; diff --git a/src/main/java/entity/group/Group.java b/src/main/java/entity/group/Group.java index 1cf362d..4eb2d0d 100644 --- a/src/main/java/entity/group/Group.java +++ b/src/main/java/entity/group/Group.java @@ -37,7 +37,7 @@ public Group(String name, String groupId, GroupType groupType) { this.groupType = groupType; this.memberships = new ArrayList<>(); this.tasks = new ArrayList<>(); - this.masterSchedule = new int[7][12]; + this.masterSchedule = new int[12][7]; } public String getGroupID() { @@ -84,8 +84,6 @@ public int[][] getMasterSchedule() { /** * Method to get the moderator of this group. - * TODO: modify so it returns ALL the moderators - * * @return The moderator of this group * @throws NoSuchElementException if the group has no moderator */ diff --git a/src/main/java/entity/user/User.java b/src/main/java/entity/user/User.java index 6961c32..31c81aa 100644 --- a/src/main/java/entity/user/User.java +++ b/src/main/java/entity/user/User.java @@ -44,7 +44,7 @@ public User(String name, String email, String password) { this.password = password; this.memberships = new ArrayList<>(); this.tasks = new ArrayList<>(); - this.schedule = new boolean[7][12]; + this.schedule = new boolean[12][7]; } public String getUserID() { diff --git a/src/main/java/interface_adapter/create_schedule/CreateScheduleState.java b/src/main/java/interface_adapter/create_schedule/CreateScheduleState.java deleted file mode 100644 index 8bec41c..0000000 --- a/src/main/java/interface_adapter/create_schedule/CreateScheduleState.java +++ /dev/null @@ -1,33 +0,0 @@ -package interface_adapter.create_schedule; - -import java.awt.Color; - -public class CreateScheduleState { - private Color[][] masterSchedule; - private boolean openModal; - private String error = ""; - - public Color[][] getMasterSched() { - return masterSchedule; - } - - public boolean getOpenModal() { - return openModal; - } - - public String getError() { - return error; - } - - public void setMasterSchedule(Color[][] masterSchedule) { - this.masterSchedule = masterSchedule; - } - - public void setOpenModal(boolean modalState) { - this.openModal = modalState; - } - - public void setError(String error) { - this.error = error; - } -} diff --git a/src/main/java/interface_adapter/create_schedule/CreateScheduleController.java b/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleController.java similarity index 66% rename from src/main/java/interface_adapter/create_schedule/CreateScheduleController.java rename to src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleController.java index 071e43b..762286c 100644 --- a/src/main/java/interface_adapter/create_schedule/CreateScheduleController.java +++ b/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleController.java @@ -1,4 +1,4 @@ -package interface_adapter.create_schedule; +package interface_adapter.schedule.create_schedule; import use_case.create_schedule.CreateScheduleInputBoundary; import use_case.create_schedule.CreateScheduleInputData; @@ -12,13 +12,12 @@ public CreateScheduleController(CreateScheduleInputBoundary createScheduleIntera /** * Executes the Create Schedule use case. - * @param userID the user creating the schedule. - * @param groupID the group this user is creating the schedule in. * @param availabilityGrid the grid of the user's available time slots. + * @param groupID the group ID. */ - public void execute(String userID, String groupID, boolean[][] availabilityGrid) { + public void execute(boolean[][] availabilityGrid, String groupID) { final CreateScheduleInputData createScheduleInputData = - new CreateScheduleInputData(userID, groupID, availabilityGrid); + new CreateScheduleInputData(groupID, availabilityGrid); createScheduleInteractor.execute(createScheduleInputData); } @@ -30,5 +29,13 @@ public void execute(String userID, String groupID, boolean[][] availabilityGrid) public void openScheduleModal() { createScheduleInteractor.openCreateScheduleModal(); } + + /** + * Load the existing schedule for a group. + * @param groupID the group ID to load the schedule for + */ + public void loadSchedule(String groupID) { + createScheduleInteractor.loadSchedule(groupID); + } } diff --git a/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleControllerFactory.java b/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleControllerFactory.java new file mode 100644 index 0000000..3d06cb9 --- /dev/null +++ b/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleControllerFactory.java @@ -0,0 +1,70 @@ +package interface_adapter.schedule.create_schedule; + +import interface_adapter.ViewManagerModel; +import interface_adapter.schedule.view_schedule.ScheduleTabViewModel; +import interface_adapter.schedule.view_schedule.ScheduleTabPresenter; +import use_case.create_schedule.CreateScheduleGroupDataAccessInterface; +import use_case.create_schedule.CreateScheduleInputBoundary; +import use_case.create_schedule.CreateScheduleUserDataAccessInterface; +import use_case.create_schedule.CreateScheduleOutputBoundary; +import use_case.create_schedule.CreateScheduleInteractor; +import use_case.create_schedule.CreateScheduleMembershipDataAccessInterface; + +public class CreateScheduleControllerFactory { + + private final CreateScheduleUserDataAccessInterface userDao; + private final CreateScheduleGroupDataAccessInterface groupDao; + private final CreateScheduleMembershipDataAccessInterface membershipDao; + private final ViewManagerModel viewManagerModel; + private final CreateScheduleViewModel createScheduleViewModel; + private final ScheduleTabViewModel groupScheduleViewModel; + + public CreateScheduleControllerFactory( + CreateScheduleUserDataAccessInterface userDao, + CreateScheduleGroupDataAccessInterface groupDao, + CreateScheduleMembershipDataAccessInterface membershipDao, + ViewManagerModel viewManagerModel, + CreateScheduleViewModel createScheduleViewModel, + ScheduleTabViewModel groupScheduleViewModel + ) { + this.userDao = userDao; + this.groupDao = groupDao; + this.membershipDao = membershipDao; + this.viewManagerModel = viewManagerModel; + this.createScheduleViewModel = createScheduleViewModel; + this.groupScheduleViewModel = groupScheduleViewModel; + } + + /** + * Creates a fully wired CreateScheduleController for the given ScheduleTabViewModel. + * This method sets up the presenter and interactor so that the controller can + * retrieve members for a specific group and update the People tab UI. + * + * @param viewModel the view model that will be updated with retrieved member data + * @return a new RemoveMemberController wired to the appropriate interactor and presenter + */ + public CreateScheduleController create(ScheduleTabViewModel viewModel) { + + CreateScheduleOutputBoundary presenter = + new CreateSchedulePresenter( + createScheduleViewModel, + viewManagerModel, + groupScheduleViewModel + ); + + ScheduleTabPresenter groupSchedulePresenter = + new ScheduleTabPresenter(viewModel); + + CreateScheduleInputBoundary interactor = + new CreateScheduleInteractor( + userDao, + groupDao, + presenter, + membershipDao, + groupSchedulePresenter + ); + + return new CreateScheduleController(interactor); + } +} + diff --git a/src/main/java/interface_adapter/schedule/create_schedule/CreateSchedulePresenter.java b/src/main/java/interface_adapter/schedule/create_schedule/CreateSchedulePresenter.java new file mode 100644 index 0000000..2e73320 --- /dev/null +++ b/src/main/java/interface_adapter/schedule/create_schedule/CreateSchedulePresenter.java @@ -0,0 +1,46 @@ +package interface_adapter.schedule.create_schedule; + +import interface_adapter.ViewManagerModel; +import interface_adapter.schedule.view_schedule.ScheduleTabViewModel; +import use_case.create_schedule.CreateScheduleOutputBoundary; +import use_case.create_schedule.CreateScheduleOutputData; + +public class CreateSchedulePresenter implements CreateScheduleOutputBoundary { + private final CreateScheduleViewModel createScheduleViewModel; + private final ViewManagerModel viewManagerModel; + private final ScheduleTabViewModel groupScheduleViewModel; + + public CreateSchedulePresenter(CreateScheduleViewModel createScheduleViewModel, ViewManagerModel viewManagerModel, + ScheduleTabViewModel groupScheduleViewModel + ) { + this.createScheduleViewModel = createScheduleViewModel; + this.viewManagerModel = viewManagerModel; + this.groupScheduleViewModel = groupScheduleViewModel; + } + + @Override + public void prepareSuccessView(CreateScheduleOutputData response) { + createScheduleViewModel.getState().setOpenModal(false); + createScheduleViewModel.firePropertyChange("openModal"); + + createScheduleViewModel.setState(new CreateScheduleState()); + viewManagerModel.firePropertyChange("view"); + + } + + @Override + public void prepareFailView(String error) { + final CreateScheduleState state = createScheduleViewModel.getState(); + state.setError(error); + + createScheduleViewModel.setState(state); + createScheduleViewModel.firePropertyChange("state"); + } + + @Override + public void openCreateScheduleModal() { + createScheduleViewModel.getState().setOpenModal(true); + createScheduleViewModel.firePropertyChange("openModal"); + } + +} diff --git a/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleState.java b/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleState.java new file mode 100644 index 0000000..5469e54 --- /dev/null +++ b/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleState.java @@ -0,0 +1,52 @@ +package interface_adapter.schedule.create_schedule; + +public class CreateScheduleState { + + private boolean[][] selectedSlots; + private boolean openModal; + private String groupId; + private String error = ""; + + public CreateScheduleState() { + this.selectedSlots = new boolean[12][7]; + + for (int row = 0; row < 12; row++) { + for (int col = 0; col < 7; col++) { + selectedSlots[row][col] = false; + } + } + error = ""; + } + + public boolean[][] getSelectedSlots() { + return selectedSlots; + } + + public boolean getOpenModal() { + return openModal; + } + + public String getError() { + return error; + } + + public void setSelectedSlots(boolean[][] newSelectedSlots) { + this.selectedSlots = newSelectedSlots; + } + + public void setOpenModal(boolean modalState) { + this.openModal = modalState; + } + + public void setError(String error) { + this.error = error; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } +} diff --git a/src/main/java/interface_adapter/create_schedule/CreateScheduleViewModel.java b/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleViewModel.java similarity index 71% rename from src/main/java/interface_adapter/create_schedule/CreateScheduleViewModel.java rename to src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleViewModel.java index 611b76d..2b16b74 100644 --- a/src/main/java/interface_adapter/create_schedule/CreateScheduleViewModel.java +++ b/src/main/java/interface_adapter/schedule/create_schedule/CreateScheduleViewModel.java @@ -1,11 +1,11 @@ -package interface_adapter.create_schedule; +package interface_adapter.schedule.create_schedule; import interface_adapter.ViewModel; public class CreateScheduleViewModel extends ViewModel { public CreateScheduleViewModel() { - super("create schedule"); + super("group schedule"); setState(new CreateScheduleState()); } } diff --git a/src/main/java/interface_adapter/create_schedule/CreateSchedulePresenter.java b/src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabPresenter.java similarity index 51% rename from src/main/java/interface_adapter/create_schedule/CreateSchedulePresenter.java rename to src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabPresenter.java index 3112166..fe7ce6b 100644 --- a/src/main/java/interface_adapter/create_schedule/CreateSchedulePresenter.java +++ b/src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabPresenter.java @@ -1,30 +1,24 @@ -package interface_adapter.create_schedule; - -import interface_adapter.ViewManagerModel; -import use_case.create_schedule.CreateScheduleOutputBoundary; -import use_case.create_schedule.CreateScheduleOutputData; +package interface_adapter.schedule.view_schedule; import java.awt.Color; -public class CreateSchedulePresenter implements CreateScheduleOutputBoundary { - private final CreateScheduleViewModel createScheduleViewModel; - private final ViewManagerModel viewManagerModel; +import use_case.create_schedule.CreateScheduleOutputData; +import use_case.create_schedule.ViewScheduleOutputBoundary; + +public class ScheduleTabPresenter implements ViewScheduleOutputBoundary { + private final ScheduleTabViewModel groupScheduleViewModel; static final Color NO_COLOR = new Color(255, 255, 255); static final Color LIGHT_GREEN = new Color(180, 255, 180); static final Color MED_GREEN = new Color(0, 150, 0); static final Color DARK_GREEN = new Color(0, 100, 0); - public CreateSchedulePresenter(CreateScheduleViewModel createScheduleViewModel, ViewManagerModel viewManagerModel) { - this.createScheduleViewModel = createScheduleViewModel; - this.viewManagerModel = viewManagerModel; + public ScheduleTabPresenter(ScheduleTabViewModel groupScheduleViewModel) { + this.groupScheduleViewModel = groupScheduleViewModel; } @Override public void prepareSuccessView(CreateScheduleOutputData response) { - createScheduleViewModel.firePropertyChange("openModal"); - - // Create the object to pass into Create Schedule State int[][] masterSchedule = response.getMasterSchedule(); int groupSize = response.getGroupSize(); Color[][] colorSchedule = new Color[masterSchedule.length][masterSchedule[0].length]; @@ -35,15 +29,21 @@ public void prepareSuccessView(CreateScheduleOutputData response) { } } - CreateScheduleState state = createScheduleViewModel.getState(); - state.setOpenModal(false); + ScheduleTabState state = groupScheduleViewModel.getState(); state.setMasterSchedule(colorSchedule); + state.setGroupSize(groupSize); - createScheduleViewModel.setState(state); - createScheduleViewModel.firePropertyChange("state"); + groupScheduleViewModel.setState(state); + groupScheduleViewModel.firePropertyChange("schedule"); } + /** + * Algorithm for what color to fill each time slot. + * @param num the number of users available in the group at this time slot + * @param groupSize the size of the group (for calculating percent) + * @return the color to fill the time slot with + */ private static Color pickColor(int num, int groupSize) { int percent = (num * 100) / groupSize; Color color; @@ -62,15 +62,10 @@ private static Color pickColor(int num, int groupSize) { @Override public void prepareFailView(String error) { - final CreateScheduleState createScheduleState = createScheduleViewModel.getState(); - createScheduleState.setError(error); - createScheduleViewModel.firePropertyChange(); - } + final ScheduleTabState state = groupScheduleViewModel.getState(); + state.setError(error); - @Override - public void openCreateScheduleModal() { - createScheduleViewModel.getState().setOpenModal(true); - createScheduleViewModel.firePropertyChange("open modal"); + groupScheduleViewModel.setState(state); + groupScheduleViewModel.firePropertyChange("schedule"); } - } diff --git a/src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabState.java b/src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabState.java new file mode 100644 index 0000000..ae3e29a --- /dev/null +++ b/src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabState.java @@ -0,0 +1,46 @@ +package interface_adapter.schedule.view_schedule; + +import java.awt.Color; + +public class ScheduleTabState { + + private Color[][] masterSchedule; + private int groupSize; + private String error = ""; + + public ScheduleTabState() { + masterSchedule = new Color[12][7]; + + // all cells for group schedule display are initially white + for (int i = 0; i < 12; i++) { + for (int j = 0; j < 7; j++) { + masterSchedule[i][j] = Color.WHITE; + } + } + error = ""; + } + + public Color[][] getMasterSchedule() { + return masterSchedule; + } + + public void setMasterSchedule(Color[][] masterSchedule) { + this.masterSchedule = masterSchedule; + } + + public int getGroupSize() { + return groupSize; + } + + public void setGroupSize(int groupSize) { + this.groupSize = groupSize; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } +} diff --git a/src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabViewModel.java b/src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabViewModel.java new file mode 100644 index 0000000..0b1d858 --- /dev/null +++ b/src/main/java/interface_adapter/schedule/view_schedule/ScheduleTabViewModel.java @@ -0,0 +1,11 @@ +package interface_adapter.schedule.view_schedule; + +import interface_adapter.ViewModel; + +public class ScheduleTabViewModel extends ViewModel { + + public ScheduleTabViewModel() { + super("schedule"); + setState(new ScheduleTabState()); + } +} diff --git a/src/main/java/use_case/create_schedule/CreateScheduleInputBoundary.java b/src/main/java/use_case/create_schedule/CreateScheduleInputBoundary.java index 67263e4..a0eb2d6 100644 --- a/src/main/java/use_case/create_schedule/CreateScheduleInputBoundary.java +++ b/src/main/java/use_case/create_schedule/CreateScheduleInputBoundary.java @@ -13,4 +13,10 @@ public interface CreateScheduleInputBoundary { * Opens the modal for user to create a schedule. */ void openCreateScheduleModal(); + + /** + * Loads the existing schedule for a group. + * @param groupID the group ID to load the schedule for + */ + void loadSchedule(String groupID); } diff --git a/src/main/java/use_case/create_schedule/CreateScheduleInputData.java b/src/main/java/use_case/create_schedule/CreateScheduleInputData.java index 25ef5c3..a56d094 100644 --- a/src/main/java/use_case/create_schedule/CreateScheduleInputData.java +++ b/src/main/java/use_case/create_schedule/CreateScheduleInputData.java @@ -1,25 +1,19 @@ package use_case.create_schedule; public class CreateScheduleInputData { - private final String userID; private final String groupID; private final boolean[][] availabilityGrid; - public CreateScheduleInputData(String userID, String groupID, boolean[][] availabilityGrid) { - this.userID = userID; + public CreateScheduleInputData(String groupID, boolean[][] availabilityGrid) { this.groupID = groupID; this.availabilityGrid = availabilityGrid; } - public String getUserID() { - return userID; + public boolean[][] getAvailabilityGrid() { + return availabilityGrid; } public String getGroupID() { return groupID; } - - public boolean[][] getAvailabilityGrid() { - return availabilityGrid; - } } diff --git a/src/main/java/use_case/create_schedule/CreateScheduleInteractor.java b/src/main/java/use_case/create_schedule/CreateScheduleInteractor.java index e35bf9b..36de527 100644 --- a/src/main/java/use_case/create_schedule/CreateScheduleInteractor.java +++ b/src/main/java/use_case/create_schedule/CreateScheduleInteractor.java @@ -3,26 +3,28 @@ import entity.group.Group; import entity.membership.Membership; import entity.user.User; +import interface_adapter.schedule.view_schedule.ScheduleTabPresenter; import java.util.ArrayList; import java.util.List; -import data_access.DBMembershipDataAccessObject; - public class CreateScheduleInteractor implements CreateScheduleInputBoundary { private final CreateScheduleUserDataAccessInterface userDataAccessObject; private final CreateScheduleGroupDataAccessInterface groupDataAccessObject; private final CreateScheduleOutputBoundary createSchedulePresenter; - private final DBMembershipDataAccessObject membershipDataAccessObject; + private final CreateScheduleMembershipDataAccessInterface membershipDataAccessObject; + private final ScheduleTabPresenter groupSchedulePresenter; public CreateScheduleInteractor(CreateScheduleUserDataAccessInterface userDataAccessObject, CreateScheduleGroupDataAccessInterface groupDataAccessObject, CreateScheduleOutputBoundary createScheduleOutputBoundary, - DBMembershipDataAccessObject membershipDataAccessObject) { + CreateScheduleMembershipDataAccessInterface membershipDataAccessObject, + ScheduleTabPresenter groupSchedulePresenter) { this.userDataAccessObject = userDataAccessObject; this.groupDataAccessObject = groupDataAccessObject; this.createSchedulePresenter = createScheduleOutputBoundary; this.membershipDataAccessObject = membershipDataAccessObject; + this.groupSchedulePresenter = groupSchedulePresenter; } @@ -31,7 +33,7 @@ public void execute(CreateScheduleInputData createScheduleInputData) { final User user = userDataAccessObject.get(userDataAccessObject.getCurrentUsername()); // get id of current group - final String groupID = groupDataAccessObject.getCurrentGroupID(); + final String groupID = createScheduleInputData.getGroupID(); // save user schedule in db final boolean[][] availabilityGrid = createScheduleInputData.getAvailabilityGrid(); @@ -51,7 +53,7 @@ public void execute(CreateScheduleInputData createScheduleInputData) { // update master sched with user schedule // add method to get user schedule in user entity - int[][] masterSchedule = new int[7][12]; + int[][] masterSchedule = new int[12][7]; for (User member: allUsers) { boolean[][] userSched = member.getSchedule(); @@ -65,10 +67,12 @@ public void execute(CreateScheduleInputData createScheduleInputData) { } } + group.setMasterSchedule(masterSchedule); groupDataAccessObject.saveMasterSchedule(group); final CreateScheduleOutputData createScheduleOutputData = new CreateScheduleOutputData(masterSchedule, group.getSize()); createSchedulePresenter.prepareSuccessView(createScheduleOutputData); + groupSchedulePresenter.prepareSuccessView(createScheduleOutputData); } @@ -76,4 +80,15 @@ public void execute(CreateScheduleInputData createScheduleInputData) { public void openCreateScheduleModal() { createSchedulePresenter.openCreateScheduleModal(); } + + @Override + public void loadSchedule(String groupID) { + final Group group = groupDataAccessObject.getGroup(groupID); + final int[][] masterSchedule = group.getMasterSchedule(); + final int groupSize = group.getSize(); + + final CreateScheduleOutputData outputData = + new CreateScheduleOutputData(masterSchedule, groupSize); + groupSchedulePresenter.prepareSuccessView(outputData); + } } diff --git a/src/main/java/use_case/create_schedule/CreateScheduleMembershipDataAccessInterface.java b/src/main/java/use_case/create_schedule/CreateScheduleMembershipDataAccessInterface.java new file mode 100644 index 0000000..0d35dfd --- /dev/null +++ b/src/main/java/use_case/create_schedule/CreateScheduleMembershipDataAccessInterface.java @@ -0,0 +1,14 @@ +package use_case.create_schedule; + +import java.util.List; +import entity.membership.Membership; + +public interface CreateScheduleMembershipDataAccessInterface { + + /** + * Return all the memberships for the given group. + * @param groupID the group to search memberships + * @return a list of all the memberships. + */ + List getMembersForGroup(String groupID); +} diff --git a/src/main/java/use_case/create_schedule/GroupScheduleOutputBoundary.java b/src/main/java/use_case/create_schedule/GroupScheduleOutputBoundary.java new file mode 100644 index 0000000..ca0941b --- /dev/null +++ b/src/main/java/use_case/create_schedule/GroupScheduleOutputBoundary.java @@ -0,0 +1,21 @@ +package use_case.create_schedule; + +public interface GroupScheduleOutputBoundary { + /** + * Prepares the success view for the Create Schedule use case. + * This method is called when the schedule creation is successful and is responsible + * for presenting the successful output to the user. + * + * @param outputData the output data containing the updated schedule + */ + void prepareSuccessView(CreateScheduleOutputData outputData); + + /** + * Prepares the failure view for the Create Schedule use case. + * This method is called when the schedule creation fails and is responsible + * for presenting the error message to the user. + * + * @param errorMessage the error message describing the reason for the failure + */ + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/create_schedule/ViewScheduleOutputBoundary.java b/src/main/java/use_case/create_schedule/ViewScheduleOutputBoundary.java new file mode 100644 index 0000000..a6d587a --- /dev/null +++ b/src/main/java/use_case/create_schedule/ViewScheduleOutputBoundary.java @@ -0,0 +1,26 @@ +package use_case.create_schedule; + +/** + * Output boundary interface for viewing the group schedule. + * This handles displaying the aggregated schedule after individual schedules are created. + */ +public interface ViewScheduleOutputBoundary { + + /** + * Prepares the success view for displaying the group schedule. + * This method is called when the schedule data is successfully retrieved + * and is responsible for presenting it to the user. + * + * @param outputData the output data containing the updated schedule + */ + void prepareSuccessView(CreateScheduleOutputData outputData); + + /** + * Prepares the failure view for the group schedule. + * This method is called when retrieving the schedule fails and is responsible + * for presenting the error message to the user. + * + * @param errorMessage the error message describing the reason for the failure + */ + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/view/CreateScheduleView.java b/src/main/java/view/CreateScheduleView.java index 65f0d43..b7ce822 100644 --- a/src/main/java/view/CreateScheduleView.java +++ b/src/main/java/view/CreateScheduleView.java @@ -1,34 +1,54 @@ package view; +import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; - +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.border.LineBorder; + +import interface_adapter.schedule.create_schedule.CreateScheduleController; +import interface_adapter.schedule.create_schedule.CreateScheduleState; +import interface_adapter.schedule.create_schedule.CreateScheduleViewModel; -import interface_adapter.create_schedule.CreateScheduleViewModel; -// trying to fix checkstyle +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; -public class CreateScheduleView extends JPanel { +public class CreateScheduleView extends JPanel implements PropertyChangeListener { private final String viewName = "create schedule"; private final CreateScheduleViewModel createScheduleViewModel; + private final JLabel errorField = new JLabel(); private final JLabel title; + private JButton[][] buttons; + private final JButton createSchedule; + + private CreateScheduleController createScheduleController; public CreateScheduleView(CreateScheduleViewModel createScheduleViewModel) { this.createScheduleViewModel = createScheduleViewModel; + this.createScheduleViewModel.addPropertyChangeListener(this); title = new JLabel("Select your available time slots."); title.setAlignmentX(Component.CENTER_ALIGNMENT); title.setFont(title.getFont().deriveFont(Font.BOLD, 16f)); - + createSchedule = new JButton("Create Schedule"); buildLayout(); + attachListeners(); } /** @@ -36,9 +56,169 @@ public CreateScheduleView(CreateScheduleViewModel createScheduleViewModel) { */ public void buildLayout() { this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - this.setMinimumSize(new Dimension(300, 200)); + this.setMinimumSize(new Dimension(500, 500)); // Add rigid areas for spacing this.add(Box.createRigidArea(new Dimension(0, 10))); this.add(title); + + createSchedule.setAlignmentX(Component.CENTER_ALIGNMENT); + this.add(Box.createRigidArea(new Dimension(0, 10))); + this.add(createSchedule); + + String[] days = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; + JPanel mainPanel = new JPanel(new BorderLayout()); + JPanel topRow = addDaysLabel(days); + mainPanel.add(topRow, BorderLayout.NORTH); + + JPanel buttonPanel = new JPanel(new GridLayout(12, 8, 1, 1)); + buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + addButtonGrid(buttonPanel); + + mainPanel.add(buttonPanel, BorderLayout.CENTER); + this.add(mainPanel); + } + + /** + * Add the row with day labels. + * @param days the list of weekdays + * @return the JPanel top row with labels + */ + private JPanel addDaysLabel(String[] days) { + JPanel result = new JPanel(new GridLayout(1, 8)); + result.add(new JLabel("")); + for (String day : days) { + JLabel dayLabel = new JLabel(day, SwingConstants.CENTER); + dayLabel.setBorder(new LineBorder(Color.BLACK)); + result.add(dayLabel); + } + return result; + } + + private JPanel addButtonGrid(JPanel buttonPanel) { + buttons = new JButton[12][7]; + + for (int row = 0; row < 12; row++) { + + int hour = 8 + row; + JLabel hourLabel = new JLabel(hour + ":00", SwingConstants.CENTER); + hourLabel.setBorder(new LineBorder(Color.BLACK)); + buttonPanel.add(hourLabel); + + for (int col = 0; col < 7; col++) { + JButton cell = new JButton(); + Color originalColor = cell.getBackground(); + cell.setPreferredSize(new Dimension(40, 30)); + cell.setBorder(new LineBorder(Color.BLACK, 1)); + cell.setMargin(new Insets(0, 0, 0, 0)); + + final int r = row; + final int c = col; + cell.addActionListener(evt -> { + boolean[][] slots = createScheduleViewModel.getState().getSelectedSlots(); + slots[r][c] = !slots[r][c]; + if (slots[r][c]) { + cell.setBackground(Color.GREEN); + } else { + cell.setBackground(originalColor); + } + }); + + buttons[row][col] = cell; + buttonPanel.add(cell); + } + } + return buttonPanel; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + final CreateScheduleState state = (CreateScheduleState) evt.getNewValue(); + setFields(state); + + errorField.setText(state.getError()); + } + + /** + * Updates the input fields based on the given state. + * + * @param state the current state of the Create Schedule view + */ + private void setFields(CreateScheduleState state) { + + errorField.setText(state.getError()); + } + + /** + * Returns the name of the view. + * + * @return the name of the view + */ + public String getViewName() { + return viewName; + } + + /** + * Sets the Create Schedule controller and attaches listeners to the buttons. + * + * @param scheduleController the controller for handling Create Schedule actions + */ + public void setCreateScheduleController(CreateScheduleController scheduleController) { + this.createScheduleController = scheduleController; + } + + /** + * Attach listeners to the Create Schedule button. + */ + public void attachListeners() { + createSchedule.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + if (!evt.getSource().equals(createSchedule)) { + return; + } + + final CreateScheduleState currentState = createScheduleViewModel.getState(); + + createScheduleController.execute( + currentState.getSelectedSlots(), + currentState.getGroupId() + ); + } + } + ); + } + + /** + * Hooks the Create Schedule modal to the application frame. + * This method listens for changes in the view model to open or close the modal. + * + * @param application the main application frame + */ + public void hookCreateScheduleModalOpen(JFrame application) { + JDialog dialog = new JDialog(application, "Create Schedule", true); + createScheduleViewModel.addPropertyChangeListener(evt -> { + if ("openModal".equals(evt.getPropertyName())) { + if (createScheduleViewModel.getState().getOpenModal()) { + openCreateScheduleModal(dialog, application); + } else { + dialog.dispose(); + } + } + }); + } + + /** + * Opens the Create Group modal dialog. + * + * @param dialog the modal dialog to display + * @param parentFrame the parent frame of the modal dialog + */ + private void openCreateScheduleModal(JDialog dialog, JFrame parentFrame) { + dialog.setMinimumSize(new Dimension(400, 250)); + dialog.setContentPane(this); + dialog.setLocationRelativeTo(parentFrame); + dialog.pack(); + dialog.setVisible(true); } } diff --git a/src/main/java/view/DashboardView.java b/src/main/java/view/DashboardView.java index ac8c1f3..d05c7c2 100644 --- a/src/main/java/view/DashboardView.java +++ b/src/main/java/view/DashboardView.java @@ -15,6 +15,10 @@ import interface_adapter.manage_members.update_role.UpdateRoleControllerFactory; import interface_adapter.manage_members.view_members.ViewMembersControllerFactory; import interface_adapter.manage_members.view_pending.ViewPendingControllerFactory; +import interface_adapter.schedule.create_schedule.CreateScheduleController; +import interface_adapter.schedule.create_schedule.CreateScheduleControllerFactory; +import interface_adapter.schedule.create_schedule.CreateScheduleViewModel; +import interface_adapter.schedule.view_schedule.ScheduleTabViewModel; import interface_adapter.viewgrouptasks.ViewGroupTasksController; import interface_adapter.viewgrouptasks.ViewGroupTasksViewModel; @@ -43,6 +47,7 @@ public class DashboardView extends JPanel implements ActionListener, PropertyCha private ViewGroupTasksViewModel viewGroupTasksViewModel; private EditGroupTaskViewModel editGroupTasksViewModel; private CreateGroupTasksViewModel createGroupTasksViewModel; + private CreateScheduleViewModel createScheduleViewModel; // Views private ViewTasksView viewTasksView; @@ -51,6 +56,7 @@ public class DashboardView extends JPanel implements ActionListener, PropertyCha private LogoutController logoutController; private CreateGroupController createGroupController; private JoinGroupController joinGroupController; + private CreateScheduleController createScheduleController; private ViewGroupTasksController viewGroupTasksController; private EditGroupTaskController editGroupTaskController; private CreateGroupTasksController createGroupTasksController; @@ -71,6 +77,8 @@ public class DashboardView extends JPanel implements ActionListener, PropertyCha private RemoveMemberControllerFactory removeMemberControllerFactory; private RespondRequestControllerFactory respondRequestControllerFactory; private UpdateRoleControllerFactory updateRoleControllerFactory; + private CreateScheduleControllerFactory createScheduleControllerFactory; + private CreateScheduleView createScheduleView; // Maps group IDs to their names private final java.util.Map groupIdToName = new java.util.HashMap<>(); @@ -260,7 +268,7 @@ private JPanel createGroupPanel(String groupId) { tabs.addTab("People", createPeopleTab(groupId)); tabs.addTab("Meets", placeholderPanel("Meetings tab for " + groupName)); tabs.addTab("Tasks", placeholderPanel("Tasks tab for " + groupName)); - tabs.addTab("Sched", new ScheduleTabView("Schedule tab for " + groupName)); + tabs.addTab("Sched", createScheduleTab("", groupId)); tabs.addTab("Optional", placeholderPanel("Optional tab for " + groupName)); tabs.setForegroundAt(0, new Color(0x1E88E5)); @@ -304,6 +312,21 @@ private PeopleTabView createPeopleTab(String groupId) { return view; } + private ScheduleTabView createScheduleTab(String groupName, String groupID) { + ScheduleTabViewModel vm = new ScheduleTabViewModel(); + ScheduleTabView scheduleTab = + new ScheduleTabView("", vm, groupID); + CreateScheduleController controller = + createScheduleControllerFactory.create(scheduleTab.getViewModel()); + scheduleTab.setCreateScheduleController(controller); + scheduleTab.setCreateScheduleViewModel(createScheduleViewModel); + scheduleTab.setCreateScheduleView(createScheduleView); + + controller.loadSchedule(groupID); + + return scheduleTab; + } + private JPanel placeholderPanel(String text) { JPanel panel = new JPanel(new BorderLayout()); JTextArea area = new JTextArea(text + "\n\nThis is a placeholder panel."); @@ -488,6 +511,10 @@ public void setJoinGroupController(JoinGroupController joinGroupController) { this.joinGroupController = joinGroupController; } + public void setCreateScheduleController(CreateScheduleController createScheduleController) { + this.createScheduleController = createScheduleController; + } + public void setViewMembersControllerFactory(ViewMembersControllerFactory factory) { this.viewMembersControllerFactory = factory; } @@ -532,6 +559,18 @@ public void setCreateGroupTasksViewModel(CreateGroupTasksViewModel viewModel) { this.createGroupTasksViewModel = viewModel; } + public void setCreateScheduleViewModel(CreateScheduleViewModel viewModel) { + this.createScheduleViewModel = viewModel; + } + + public void setCreateScheduleView(CreateScheduleView view) { + this.createScheduleView = view; + } + + public void setCreateScheduleControllerFactory(CreateScheduleControllerFactory factory) { + this.createScheduleControllerFactory = factory; + } + private JPanel buildGroupTasksTab(String groupId) { if (viewGroupTasksViewModel == null || editGroupTasksViewModel == null diff --git a/src/main/java/view/ScheduleTabView.java b/src/main/java/view/ScheduleTabView.java index d5917fe..d7d6b26 100644 --- a/src/main/java/view/ScheduleTabView.java +++ b/src/main/java/view/ScheduleTabView.java @@ -1,37 +1,46 @@ package view; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Component; import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridLayout; import javax.swing.*; import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; -import interface_adapter.create_schedule.CreateScheduleController; +import interface_adapter.schedule.create_schedule.CreateScheduleController; +import interface_adapter.schedule.create_schedule.CreateScheduleViewModel; +import interface_adapter.schedule.view_schedule.ScheduleTabViewModel; -public class ScheduleTabView extends JPanel { +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +public class ScheduleTabView extends JPanel implements PropertyChangeListener { private final JButton createSched = new JButton("Add Your Availability"); private CreateScheduleController createScheduleController; + private CreateScheduleViewModel createScheduleViewModel; + private ScheduleTabViewModel viewModel; + private final String groupId; + private JPanel[][] gridCells; + private CreateScheduleView createScheduleView; - public ScheduleTabView(String groupName) { + public ScheduleTabView(String groupName, ScheduleTabViewModel viewModel, String groupId) { + this.groupId = groupId; + this.viewModel = viewModel; + this.viewModel.addPropertyChangeListener(this); setLayout(new BorderLayout()); setBorder(new EmptyBorder(10, 10, 10, 10)); - this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - addCreateSchedButton(); + buildScheduleDisplay(); addGroupSched(groupName); } - /** - * Make the button where user can input availability. - */ - public void addCreateSchedButton() { - createSched.setAlignmentY(Component.TOP_ALIGNMENT); - createSched.setMaximumSize(new Dimension(180, 20)); - add(createSched); - - createSched.addActionListener(evt -> createScheduleController.openScheduleModal()); + public ScheduleTabViewModel getViewModel() { + return viewModel; } /** @@ -45,4 +54,114 @@ public void addGroupSched(String groupName) { add(groupSched); } + /** + * Set the schedule controller. + * @param createScheduleController controller + */ + public void setCreateScheduleController(CreateScheduleController createScheduleController) { + this.createScheduleController = createScheduleController; + } + + public void setCreateScheduleViewModel(CreateScheduleViewModel createScheduleViewModel) { + this.createScheduleViewModel = createScheduleViewModel; + } + + public void setCreateScheduleView(CreateScheduleView createScheduleView) { + this.createScheduleView = createScheduleView; + } + + public String getGroupId() { + return groupId; + } + + private void buildScheduleDisplay() { + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(Box.createRigidArea(new Dimension(0, 10))); + + JLabel title = new JLabel("Group Schedule", SwingConstants.CENTER); + title.setAlignmentX(Component.CENTER_ALIGNMENT); + title.setFont(title.getFont().deriveFont(Font.BOLD, 16f)); + this.add(title); + this.add(Box.createRigidArea(new Dimension(0, 10))); + + createSched.setAlignmentX(Component.CENTER_ALIGNMENT); + createSched.addActionListener(evt -> { + if (createScheduleController != null && createScheduleViewModel != null) { + // Set the correct controller on the modal before opening + if (createScheduleView != null) { + createScheduleView.setCreateScheduleController(createScheduleController); + } + // Set the groupId right before opening the modal + createScheduleViewModel.getState().setGroupId(groupId); + createScheduleController.openScheduleModal(); + } + }); + this.add(createSched); + this.add(Box.createRigidArea(new Dimension(0, 10))); + + JPanel mainPanel = new JPanel(new BorderLayout()); + + String[] days = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; + JPanel topRow = buildDaysRow(days); + mainPanel.add(topRow, BorderLayout.NORTH); + + JPanel schedulePanel = new JPanel(new GridLayout(12, 8, 1, 1)); + schedulePanel.setAlignmentX(Component.CENTER_ALIGNMENT); + + buildGrid(schedulePanel); + mainPanel.add(schedulePanel, BorderLayout.CENTER); + this.add(mainPanel); + + } + + private JPanel buildDaysRow(String[] days) { + JPanel row = new JPanel(new GridLayout(1, 8)); + row.add(new JLabel("")); + + for (String day: days) { + JLabel label = new JLabel(day, SwingConstants.CENTER); + label.setBorder(new LineBorder(Color.BLACK)); + row.add(label); + } + return row; + } + + private void buildGrid(JPanel panel) { + int start = 8; + Color[][] slots = viewModel.getState().getMasterSchedule(); + gridCells = new JPanel[12][7]; + + for (int r = 0; r < 12; r++) { + int hour = start + r; + JLabel hourLabel = new JLabel(hour + ":00", SwingConstants.CENTER); + hourLabel.setBorder(new LineBorder(Color.BLACK)); + panel.add(hourLabel); + + for (int c = 0; c < 7; c++) { + JPanel cell = new JPanel(); + cell.setPreferredSize(new Dimension(40, 30)); + cell.setBorder(new LineBorder(Color.BLACK, 1)); + cell.setBackground(slots[r][c]); + gridCells[r][c] = cell; + panel.add(cell); + + } + } + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("schedule".equals(evt.getPropertyName())) { + Color[][] updatedSchedule = viewModel.getState().getMasterSchedule(); + if (gridCells != null) { + for (int r = 0; r < 12; r++) { + for (int c = 0; c < 7; c++) { + gridCells[r][c].setBackground(updatedSchedule[r][c]); + } + } + repaint(); + } + } + } + }