diff --git a/src/main/java/com/maestro/desktop/controllers/AppController.java b/src/main/java/com/maestro/desktop/controllers/AppController.java index 7c5b647..99026a9 100644 --- a/src/main/java/com/maestro/desktop/controllers/AppController.java +++ b/src/main/java/com/maestro/desktop/controllers/AppController.java @@ -10,9 +10,18 @@ import javafx.fxml.FXMLLoader; import javafx.geometry.Insets; import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Scene; import javafx.scene.control.Button; +import javafx.scene.control.DialogPane; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Region; import javafx.scene.layout.VBox; +import javafx.scene.shape.Circle; +import javafx.stage.Modality; +import javafx.stage.Stage; import java.io.IOException; import java.sql.SQLException; @@ -52,6 +61,10 @@ public static AppController getInstance() { return INSTANCE; } + public User getUser() { return this.user; } + + public NavigableView getAllProjects() { return allProjects; } + /** * initialize - Sets the user and displays the items from the sidebar. * @param user - User logged in. @@ -66,6 +79,9 @@ public void initialize(User user) throws SQLException { System.out.println("Password: "+this.user.getPassword()); System.out.println("Picture: "+this.user.getProfilePhotoPath()); this.profileBtn.setText(this.user.getName()); + Circle clipShape = new Circle(15, 15, 15); + this.profileBtn.getGraphic().setClip(clipShape); + ((ImageView) this.profileBtn.getGraphic()).setImage(new Image(this.user.getProfilePhotoPath())); AppController.INSTANCE = this; this.dashboard = new NavigableView(this.user, NavigableView.FxmlView.DASHBOARD, dashboardButton); this.allProjects = new NavigableView(this.user.getProjects(), NavigableView.FxmlView.ALL_PROJECTS, allProjectsButton); @@ -149,7 +165,12 @@ public void navigateWithData(Object data) { // Check if already in recent Navigable Views for (NavigableView nav : recents) { - if (nav.getData() == data) { + if ((data instanceof Project + && nav.getData() instanceof Project + && ((Project) data).getId() == ((Project) nav.getData()).getId()) + || (data instanceof Task + && nav.getData() instanceof Task + && ((Task) data).getId() == ((Task) nav.getData()).getId()) ) { AppController.getInstance().updateView(nav); return; } @@ -195,26 +216,35 @@ public void navigateWithData(Object data) { * @param event - ActionEvent raised when clicking on the "New project" button. */ public void createNewProject(ActionEvent event) { - Project project = new Project( - 420, - "Test", - "Delete Later", - new Date(), - new Date(), - new Date(), - new Date(), - this.user - ); try { - DatabaseConnection.getInstance().insertProject(project); - DatabaseConnection.getInstance().updateAllProjects(this.user); - System.out.println("Projects updated: "+this.user.getProjects()); - this.navigateWithData(project); - } catch (SQLException e) { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/dialogs/new-project-dialog.fxml")); + DialogPane pane = loader.load(); + NewProjectDialogController controller = loader.getController(); + Stage stage = new Stage(); + stage.initOwner(((Node) event.getSource()).getScene().getWindow()); + stage.initModality(Modality.APPLICATION_MODAL); + controller.initialize(stage); + stage.setTitle("New Project"); + stage.setScene(new Scene(pane)); + stage.setResizable(false); + stage.show(); + } catch (IOException e) { e.printStackTrace(); } } + public void updateRecentContainer() { + for (NavigableView nav : this.recents) { + ((Button) nav.getNavSource()).setText(nav.getData().toString()); + } + ((VBox) this.recentContainer.getChildren().getLast()).getChildren().setAll(this.recents.stream().map(NavigableView::getNavSource).toList()); + } + + public void deleteRecent(Object data) { + NavigableView nav = this.recents.stream().filter(obj -> obj.getData() == data).toList().getFirst(); + this.recents.remove(nav); + } + /** * getAccount - Getter for the account member of the AppController class. * @return NavigableView - The account member of the class. @@ -222,5 +252,4 @@ public void createNewProject(ActionEvent event) { public NavigableView getAccount(){ return this.account; } - } diff --git a/src/main/java/com/maestro/desktop/controllers/EditProjectDialogController.java b/src/main/java/com/maestro/desktop/controllers/EditProjectDialogController.java new file mode 100644 index 0000000..5446f90 --- /dev/null +++ b/src/main/java/com/maestro/desktop/controllers/EditProjectDialogController.java @@ -0,0 +1,154 @@ +package com.maestro.desktop.controllers; + +import com.maestro.desktop.App; +import com.maestro.desktop.models.Project; +import com.maestro.desktop.models.User; +import com.maestro.desktop.utils.DatabaseConnection; +import javafx.fxml.FXML; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.TilePane; +import javafx.stage.Stage; + +import java.sql.SQLException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class EditProjectDialogController { + + private List collaborators; + private List newCollaborators; + private Stage stage; + private Project project; + + @FXML + private TextField name; + @FXML + private TextArea description; + @FXML + private DatePicker startDate; + @FXML + private DatePicker endDate; + @FXML + private TextField findCollaborators; + @FXML + private TilePane collaboratorPane; + @FXML + private Button updateButton; + @FXML + private Button cancelButton; + @FXML + private Button deleteButton; + + public void initialize(Stage stage, Project project) { + this.stage = stage; + this.project = project; + this.updateButton.setDisable(true); + this.updateButton.setOnAction(event -> this.updateProject()); + this.cancelButton.setOnAction(event -> this.stage.close()); + this.deleteButton.setOnAction(event -> this.deleteProject()); + this.name.textProperty().addListener((observable, oldValue, newValue) -> { this.updateButton.setDisable(this.name.getText().isBlank()); }); + this.findCollaborators.setOnAction(event -> this.checkUser()); + this.findCollaborators.textProperty().addListener((observable, oldValue, newValue) -> { this.findCollaborators.getStyleClass().setAll("text-field"); }); + this.collaborators = new ArrayList<>(this.project.getUsers()); + this.newCollaborators = new ArrayList<>(); + for (User user : this.collaborators) { + Label collaborator = new Label(user.getName()); + Button deleteBtn = new Button(); + deleteBtn.setId("delete-collaborator"); + deleteBtn.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + deleteBtn.setPrefSize(12, 12); + + HBox hBox = new HBox(5, deleteBtn, collaborator); + hBox.getStyleClass().setAll("collaborator"); + hBox.setAlignment(Pos.CENTER_LEFT); + hBox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + this.collaboratorPane.getChildren().add(hBox); + deleteBtn.setOnAction(event -> { + this.collaborators.remove(user); + this.collaboratorPane.getChildren().remove(hBox); + this.stage.sizeToScene(); + }); + this.stage.sizeToScene(); + } + this.name.setText(this.project.getName()); + this.description.setText(this.project.getDescription()); + this.startDate.setValue(new java.sql.Date(this.project.getStartDate().getTime()).toLocalDate()); + this.endDate.setValue(new java.sql.Date(this.project.getEndDate().getTime()).toLocalDate()); + } + + public void updateProject() { + this.project.setName(this.name.getText()); + this.project.setDescription(this.description.getText()); + this.project.setStartDate(java.sql.Date.valueOf(this.startDate.getValue())); + this.project.setEndDate(java.sql.Date.valueOf(this.endDate.getValue())); + this.project.setUpdatedAt(new Date()); + this.project.setUsers(this.collaborators); + try { + DatabaseConnection.getInstance().updateProject(this.project, this.newCollaborators); + DatabaseConnection.getInstance().updateAllProjects(AppController.getInstance().getUser()); + AppController.getInstance().navigateWithData(this.project); + AppController.getInstance().updateRecentContainer(); + } catch (SQLException e) { + e.printStackTrace(); + } + this.stage.close(); + } + + public void checkUser() { + String email = this.findCollaborators.getText().toLowerCase().strip(); + try { + User fetchedUser = DatabaseConnection.getInstance().fetchUserFromEmail(email); + if (fetchedUser == null) { + this.findCollaborators.getStyleClass().setAll("error-container"); + return; + } else if (collaborators.stream().anyMatch(user -> user.getId() == fetchedUser.getId())) { + return; + } else { + Label collaborator = new Label(fetchedUser.getName()); + Button deleteBtn = new Button(); + deleteBtn.setId("delete-collaborator"); + deleteBtn.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + deleteBtn.setPrefSize(12, 12); + + HBox hBox = new HBox(5, deleteBtn, collaborator); + hBox.getStyleClass().setAll("collaborator"); + hBox.setAlignment(Pos.CENTER_LEFT); + hBox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + this.collaboratorPane.getChildren().add(hBox); + deleteBtn.setOnAction(event -> { + this.collaborators.remove(fetchedUser); + this.newCollaborators.remove(fetchedUser); + this.collaboratorPane.getChildren().remove(hBox); + this.stage.sizeToScene(); + }); + this.collaborators.add(fetchedUser); + this.newCollaborators.add(fetchedUser); + this.stage.sizeToScene(); + this.findCollaborators.clear(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public void deleteProject() { + try { + DatabaseConnection.getInstance().deleteProject(this.project); + AppController.getInstance().getUser().removeProject(this.project); + DatabaseConnection.getInstance().updateAllProjects(AppController.getInstance().getUser()); + AppController.getInstance().updateView(AppController.getInstance().getAllProjects()); + AppController.getInstance().deleteRecent(this.project); + AppController.getInstance().updateRecentContainer(); + } catch (SQLException e) { + e.printStackTrace(); + } + this.stage.close(); + } +} diff --git a/src/main/java/com/maestro/desktop/controllers/EditTaskDialogController.java b/src/main/java/com/maestro/desktop/controllers/EditTaskDialogController.java new file mode 100644 index 0000000..77b2559 --- /dev/null +++ b/src/main/java/com/maestro/desktop/controllers/EditTaskDialogController.java @@ -0,0 +1,148 @@ +package com.maestro.desktop.controllers; + +import com.maestro.desktop.App; +import com.maestro.desktop.models.Project; +import com.maestro.desktop.models.Task; +import com.maestro.desktop.models.User; +import com.maestro.desktop.utils.DatabaseConnection; +import javafx.fxml.FXML; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.TilePane; +import javafx.stage.Stage; + +import java.sql.SQLException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class EditTaskDialogController { + + private Stage stage; + private Task task; + private List selectedUsers; + private List newActors; + + @FXML + private TextField name; + @FXML + private TextArea description; + @FXML + private DatePicker deadline; + @FXML + private MenuButton status; + @FXML + private MenuButton priority; + @FXML + private MenuButton collaboratorMenu; + + @FXML + private Button updateButton; + @FXML + private Button cancelButton; + @FXML + private Button deleteButton; + + public void initialize(Stage stage, Task task) { + this.stage = stage; + this.task = task; + this.selectedUsers = new ArrayList<>(task.getActors()); + this.newActors = new ArrayList<>(); + this.collaboratorMenu.setText(task.getActors().size() + " user(s) selected"); + this.updateButton.setDisable(true); + this.updateButton.setOnAction(event -> this.updateProject()); + this.cancelButton.setOnAction(event -> this.stage.close()); + this.deleteButton.setOnAction(event -> this.deleteTask()); + this.name.textProperty().addListener((observable, oldValue, newValue) -> { this.updateButton.setDisable(this.name.getText().isBlank()); }); + this.status.getItems().clear(); + this.status.setUserData(this.task.getStatus()); + this.status.setText(((Task.Status) this.status.getUserData()).getName()); + this.status.setId(((Task.Status) this.status.getUserData()).name()); + for (Task.Status status : Task.Status.values()) { + var menuItem = new MenuItem(status.getName()); + menuItem.setOnAction(event -> { + this.status.setText(menuItem.getText()); + this.status.setUserData(status); + this.status.setId(((Task.Status) this.status.getUserData()).name()); + }); + this.status.getItems().add(menuItem); + } + this.priority.getItems().clear(); + this.priority.setUserData(Task.Priority.LOW); + this.priority.setText(((Task.Priority) this.priority.getUserData()).getName()); + this.priority.setId(((Task.Priority) this.priority.getUserData()).name()); + for (Task.Priority priority : Task.Priority.values()) { + var menuItem = new MenuItem(priority.getName()); + menuItem.setOnAction(event -> { + this.priority.setText(menuItem.getText()); + this.priority.setUserData(priority); + this.priority.setId(((Task.Priority) this.priority.getUserData()).name()); + }); + this.priority.getItems().add(menuItem); + } + this.collaboratorMenu.getItems().clear(); + for (User user : this.task.getParentProject().getUsers()) { + var checkMenuItem = new CheckMenuItem(user.getName()); + if (this.selectedUsers.stream().map(User::getId).toList().contains(user.getId())) { + checkMenuItem.setSelected(true); + } + checkMenuItem.setOnAction(event -> { + if (checkMenuItem.isSelected()) { + this.selectedUsers.add(user); + this.newActors.add(user); + } else { + this.selectedUsers.removeIf(obj -> obj.getId() == user.getId()); + this.newActors.removeIf(obj -> obj.getId() == user.getId()); + } + this.collaboratorMenu.setText(this.selectedUsers.size() + " user(s) selected"); + System.out.println(this.selectedUsers.toString()); + System.out.println(this.task.getParentProject().getUsers().toString()); + }); + this.collaboratorMenu.getItems().add(checkMenuItem); + } + + this.name.setText(this.task.getName()); + this.description.setText(this.task.getDescription()); + this.deadline.setValue(new java.sql.Date(this.task.getDeadline().getTime()).toLocalDate()); + } + + public void updateProject() { + this.task.setName(this.name.getText()); + this.task.setDescription(this.description.getText()); + this.task.setDeadline(java.sql.Date.valueOf(this.deadline.getValue())); + this.task.setPriority((Task.Priority) this.priority.getUserData()); + this.task.setStatus((Task.Status) this.status.getUserData()); + this.task.setUpdatedAt(new Date()); + this.task.setActors(this.selectedUsers); + try { + DatabaseConnection.getInstance().updateTask(this.task, this.newActors); + DatabaseConnection.getInstance().updateAllTasks(this.task.getParentProject()); + AppController.getInstance().navigateWithData(this.task); + AppController.getInstance().updateRecentContainer(); + } catch (SQLException e) { + e.printStackTrace(); + } + this.stage.close(); + } + + + + public void deleteTask() { + try { + DatabaseConnection.getInstance().deleteTask(this.task); + this.task.getParentProject().getTasks().remove(this.task); + DatabaseConnection.getInstance().updateAllTasks(this.task.getParentProject()); + AppController.getInstance().navigateWithData(this.task.getParentProject()); + AppController.getInstance().deleteRecent(this.task); + AppController.getInstance().updateRecentContainer(); + } catch (SQLException e) { + e.printStackTrace(); + } + this.stage.close(); + } +} diff --git a/src/main/java/com/maestro/desktop/controllers/NewProjectDialogController.java b/src/main/java/com/maestro/desktop/controllers/NewProjectDialogController.java new file mode 100644 index 0000000..fbb2991 --- /dev/null +++ b/src/main/java/com/maestro/desktop/controllers/NewProjectDialogController.java @@ -0,0 +1,117 @@ +package com.maestro.desktop.controllers; + +import com.maestro.desktop.models.Project; +import com.maestro.desktop.models.Task; +import com.maestro.desktop.models.User; +import com.maestro.desktop.utils.DatabaseConnection; +import javafx.animation.Animation; +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; +import javafx.fxml.FXML; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.TilePane; +import javafx.stage.Stage; +import javafx.util.Duration; + +import java.sql.SQLException; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class NewProjectDialogController { + private List collaborators; + private Stage stage; + + @FXML + private TextField name; + @FXML + private TextArea description; + @FXML + private DatePicker startDate; + @FXML + private DatePicker endDate; + @FXML + private TextField findCollaborators; + @FXML + private TilePane collaboratorPane; + @FXML + private Button createButton; + @FXML + private Button cancelButton; + + public void initialize(Stage stage) { + this.stage = stage; + this.startDate.setValue(LocalDate.now()); + this.endDate.setValue(LocalDate.now().plusMonths(1)); + this.createButton.setDisable(true); + this.createButton.setOnAction(event -> this.createProject()); + this.cancelButton.setOnAction(event -> this.stage.close()); + this.name.textProperty().addListener((observable, oldValue, newValue) -> { this.createButton.setDisable(this.name.getText().isBlank()); }); + this.findCollaborators.setOnAction(event -> this.checkUser()); + this.findCollaborators.textProperty().addListener((observable, oldValue, newValue) -> { this.findCollaborators.getStyleClass().setAll("text-field"); }); + this.collaborators = new ArrayList<>(); + } + + public void checkUser() { + String email = this.findCollaborators.getText().toLowerCase().strip(); + try { + User fetchedUser = DatabaseConnection.getInstance().fetchUserFromEmail(email); + if (fetchedUser == null) { + this.findCollaborators.getStyleClass().setAll("error-container"); + return; + } else if (collaborators.stream().anyMatch(user -> user.getId() == fetchedUser.getId())) { + return; + } else { + Label collaborator = new Label(fetchedUser.getName()); + Button deleteBtn = new Button(); + deleteBtn.setId("delete-collaborator"); + deleteBtn.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + deleteBtn.setPrefSize(12, 12); + + HBox hBox = new HBox(5, deleteBtn, collaborator); + hBox.getStyleClass().setAll("collaborator"); + hBox.setAlignment(Pos.CENTER_LEFT); + hBox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + this.collaboratorPane.getChildren().add(hBox); + deleteBtn.setOnAction(event -> { + this.collaborators.remove(fetchedUser); + this.collaboratorPane.getChildren().remove(hBox); + this.stage.sizeToScene(); + }); + this.collaborators.add(fetchedUser); + this.stage.sizeToScene(); + this.findCollaborators.clear(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + public void createProject() { + Project project = new Project( + -1, + this.name.getText(), + this.description.getText(), + java.sql.Date.valueOf(this.startDate.getValue()), + java.sql.Date.valueOf(this.endDate.getValue()), + new Date(), + new Date(), + AppController.getInstance().getUser() + ); + project.setUsers(this.collaborators); + try { + DatabaseConnection.getInstance().insertProject(project); + DatabaseConnection.getInstance().updateAllProjects(AppController.getInstance().getUser()); + AppController.getInstance().navigateWithData(project); + } catch (SQLException e) { + e.printStackTrace(); + } + + this.stage.close(); + } +} diff --git a/src/main/java/com/maestro/desktop/controllers/NewTaskDialogController.java b/src/main/java/com/maestro/desktop/controllers/NewTaskDialogController.java index bdc611a..5e59501 100644 --- a/src/main/java/com/maestro/desktop/controllers/NewTaskDialogController.java +++ b/src/main/java/com/maestro/desktop/controllers/NewTaskDialogController.java @@ -2,6 +2,7 @@ import com.maestro.desktop.models.Project; import com.maestro.desktop.models.Task; +import com.maestro.desktop.models.User; import com.maestro.desktop.utils.DatabaseConnection; import javafx.fxml.FXML; import javafx.scene.control.*; @@ -9,6 +10,8 @@ import java.sql.Date; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; /** * NewTaskDialogController - Controller's methods related to the create task popup window. @@ -16,6 +19,7 @@ public class NewTaskDialogController { private Stage stage; private Project parentProject; + private List selectedUsers; @FXML private TextField name; @@ -27,6 +31,8 @@ public class NewTaskDialogController { private MenuButton status; @FXML private MenuButton priority; + @FXML + private MenuButton collaboratorMenu; @FXML private Button createButton; @@ -41,35 +47,62 @@ public class NewTaskDialogController { public void initialize(Stage stage, Project parentProject) { this.parentProject = parentProject; this.stage = stage; + this.selectedUsers = new ArrayList<>(); + this.collaboratorMenu.setText("0 user(s) selected"); this.deadline.setValue(new Date(this.parentProject.getEndDate().getTime()).toLocalDate()); this.createButton.setDisable(true); - this.name.setOnAction(event -> { this.createButton.setDisable(this.name.getText().isBlank()); }); this.name.textProperty().addListener((observable, oldValue, newValue) -> { this.createButton.setDisable(this.name.getText().isBlank()); }); this.createButton.setOnAction(event -> this.createTask()); this.cancelButton.setOnAction(event -> this.stage.close()); this.status.getItems().clear(); + this.status.setUserData(Task.Status.TO_DO); + this.status.setText(((Task.Status) this.status.getUserData()).getName()); + this.status.setId(((Task.Status) this.status.getUserData()).name()); for (Task.Status status : Task.Status.values()) { var menuItem = new MenuItem(status.getName()); menuItem.setOnAction(event -> { this.status.setText(menuItem.getText()); this.status.setUserData(status); + this.status.setId(((Task.Status) this.status.getUserData()).name()); }); this.status.getItems().add(menuItem); } this.priority.getItems().clear(); + this.priority.setUserData(Task.Priority.LOW); + this.priority.setText(((Task.Priority) this.priority.getUserData()).getName()); + this.priority.setId(((Task.Priority) this.priority.getUserData()).name()); for (Task.Priority priority : Task.Priority.values()) { var menuItem = new MenuItem(priority.getName()); menuItem.setOnAction(event -> { this.priority.setText(menuItem.getText()); this.priority.setUserData(priority); + this.priority.setId(((Task.Priority) this.priority.getUserData()).name()); }); this.priority.getItems().add(menuItem); } + this.collaboratorMenu.getItems().clear(); + if (this.parentProject.getUsers().isEmpty()){ + this.collaboratorMenu.setText("No users found"); + this.collaboratorMenu.setDisable(true); + } + for (User user : this.parentProject.getUsers()) { + var checkMenuItem = new CheckMenuItem(user.getName()); + checkMenuItem.setOnAction(event -> { + if (checkMenuItem.isSelected()) { + this.selectedUsers.add(user); + } else { + this.selectedUsers.removeIf(obj -> obj.getId() == user.getId()); + } + this.collaboratorMenu.setText(this.selectedUsers.size() + " user(s) selected"); + }); + this.collaboratorMenu.getItems().add(checkMenuItem); + } } - + /** * createTask - Creates a new task and adds it in the database. */ + public void createTask() { if (name.getText().isBlank()) { return; @@ -86,6 +119,7 @@ public void createTask() { new java.util.Date(), new java.util.Date() ); + task.setActors(this.selectedUsers); try { DatabaseConnection.getInstance().insertTask(task); DatabaseConnection.getInstance().updateAllTasks(this.parentProject); diff --git a/src/main/java/com/maestro/desktop/controllers/ProjectController.java b/src/main/java/com/maestro/desktop/controllers/ProjectController.java index 030bb61..900e343 100644 --- a/src/main/java/com/maestro/desktop/controllers/ProjectController.java +++ b/src/main/java/com/maestro/desktop/controllers/ProjectController.java @@ -1,6 +1,5 @@ package com.maestro.desktop.controllers; -import com.maestro.desktop.App; import com.maestro.desktop.models.Project; import com.maestro.desktop.models.Task; import com.maestro.desktop.utils.ComponentFactory; @@ -10,12 +9,6 @@ import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.*; -import javafx.scene.image.Image; -import javafx.scene.input.DataFormat; -import javafx.scene.input.DragEvent; -import javafx.scene.input.Dragboard; -import javafx.scene.input.TransferMode; -import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Modality; @@ -49,6 +42,8 @@ public class ProjectController extends NavigationViewController { private VBox inProgressTasks; @FXML private VBox completedTasks; + @FXML + private Button accessProjects; /** * initialize - Sets the project and displays the items of the page. @@ -63,6 +58,7 @@ public void initialize(Object data) { this.date.setText(this.project.getEndDate() != null ? df.format(this.project.getEndDate()) : "Not specified"); ComponentFactory.getInstance().displayActors(this.actors, 10, this.project.getActors()); this.displayTasks(); + this.accessProjects.setOnAction(event -> AppController.getInstance().updateView(AppController.getInstance().getAllProjects())); } /** @@ -126,7 +122,28 @@ public void addTask(ActionEvent event) { controller.initialize(stage, this.project); stage.setScene(new Scene(pane)); stage.setTitle("New Task"); + stage.setResizable(false); + stage.getIcons().add(new Image(getClass().getResourceAsStream("/com/maestro/desktop/images/logo.png"))); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void editProject(ActionEvent event) { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/dialogs/edit-project-dialog.fxml")); + DialogPane pane = loader.load(); + EditProjectDialogController controller = loader.getController(); + Stage stage = new Stage(); + stage.initOwner(((Node) event.getSource()).getScene().getWindow()); + stage.initModality(Modality.APPLICATION_MODAL); + controller.initialize(stage, this.project); + stage.setScene(new Scene(pane)); + stage.setTitle("Edit Project"); + stage.setResizable(false); stage.getIcons().add(new Image(getClass().getResourceAsStream("/com/maestro/desktop/images/logo.png"))); + stage.show(); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/com/maestro/desktop/controllers/TaskController.java b/src/main/java/com/maestro/desktop/controllers/TaskController.java index 8c4f45f..f155b7f 100644 --- a/src/main/java/com/maestro/desktop/controllers/TaskController.java +++ b/src/main/java/com/maestro/desktop/controllers/TaskController.java @@ -1,16 +1,128 @@ package com.maestro.desktop.controllers; +import com.maestro.desktop.models.Comment; import com.maestro.desktop.models.Task; +import com.maestro.desktop.utils.ComponentFactory; +import com.maestro.desktop.utils.DatabaseConnection; +import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.control.Label; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Insets; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.stage.Modality; +import javafx.stage.Stage; + +import java.io.IOException; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.util.Comparator; +import java.util.Date; +import java.util.Locale; public class TaskController extends NavigationViewController{ private Task task; @FXML private Label title; + @FXML + private Label description; + @FXML + private Label date; + @FXML + private HBox actors; + @FXML + private Label priority; + @FXML + private MenuButton status; + @FXML + private Button accessProject; + @FXML + private VBox commentContainer; + @FXML + private TextArea commentTextArea; + @FXML + private Button publishCommentBtn; + public void initialize(Object data){ this.task = (Task) data; this.title.setText(this.task.getName()); + this.description.setText(this.task.getDescription()); + var df = new SimpleDateFormat("MMM. d, yyyy", Locale.ENGLISH); + this.date.setText(this.task.getDeadline() != null ? df.format(this.task.getDeadline()) : "Not specified"); + ComponentFactory.getInstance().displayActors(this.actors, 10, this.task.getActors()); + this.priority.setText(task.getPriority().getName()); + this.priority.setId(task.getPriority().name()); + this.status.getItems().clear(); + this.status.setId(this.task.getStatus().name()); + this.status.setText(this.task.getStatus().getName()); + for (Task.Status status : Task.Status.values()) { + var menuItem = new MenuItem(status.getName()); + menuItem.setOnAction(event -> { + this.status.setText(menuItem.getText()); + try { + DatabaseConnection.getInstance().updateTaskStatus(this.task, status); + } catch (SQLException e) { + e.printStackTrace(); + } + this.task.setStatus(status); + AppController.getInstance().navigateWithData(this.task); + }); + this.status.getItems().add(menuItem); + } + this.accessProject.setText(this.task.getParentProject().getName()); + this.accessProject.setOnAction(event -> AppController.getInstance().navigateWithData(this.task.getParentProject())); + this.commentContainer.getChildren().clear(); + for (Comment comment : this.task.getComments()) { + this.commentContainer.getChildren().add(ComponentFactory.getInstance().createCommentItem(comment)); + } + this.publishCommentBtn.setDisable(true); + this.commentTextArea.textProperty().addListener((observable, oldValue, newValue) -> { this.publishCommentBtn.setDisable(this.commentTextArea.getText().isBlank()); }); + + } + + public void publishComment(ActionEvent event) { + if (this.commentTextArea.getText().isBlank()) { + return; + } + var comment = new Comment( + -1, + this.commentTextArea.getText(), + AppController.getInstance().getUser(), + new Date(), + new Date() + ); + try { + System.out.println(comment.getId()); + DatabaseConnection.getInstance().insertComment(comment, this.task.getId()); + System.out.println(comment.getId()); + this.commentTextArea.clear(); + this.task.getComments().add(this.task.getComments().stream().filter(obj -> obj.getCreatedAt().compareTo(comment.getCreatedAt()) <= 0) + .findFirst().map(obj -> this.task.getComments().indexOf(obj)).orElse(this.task.getComments().size()), comment); + AppController.getInstance().navigateWithData(this.task); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public void editTask(ActionEvent event) { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/dialogs/edit-task-dialog.fxml")); + DialogPane pane = loader.load(); + EditTaskDialogController controller = loader.getController(); + Stage stage = new Stage(); + stage.initOwner(((Node) event.getSource()).getScene().getWindow()); + stage.initModality(Modality.APPLICATION_MODAL); + controller.initialize(stage, this.task); + stage.setScene(new Scene(pane)); + stage.setTitle("Edit Task"); + stage.setResizable(false); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/src/main/java/com/maestro/desktop/models/Comment.java b/src/main/java/com/maestro/desktop/models/Comment.java new file mode 100644 index 0000000..5a1131b --- /dev/null +++ b/src/main/java/com/maestro/desktop/models/Comment.java @@ -0,0 +1,39 @@ +package com.maestro.desktop.models; + +import java.util.Date; + +public class Comment { + private int id; + private String content; + private User author; + private Date createdAt; + private Date updatedAt; + + public Comment(int id, String content, User author, Date createdAt, Date updatedAt) { + this.id = id; + this.content = content; + this.author = author; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public User getAuthor() { + return author; + } + + public Date getCreatedAt() { + return createdAt; + } +} diff --git a/src/main/java/com/maestro/desktop/models/Task.java b/src/main/java/com/maestro/desktop/models/Task.java index f638cda..c5b8fce 100644 --- a/src/main/java/com/maestro/desktop/models/Task.java +++ b/src/main/java/com/maestro/desktop/models/Task.java @@ -75,6 +75,7 @@ public static Priority fromValue(int value) { private Date updatedAt; private List actors; + private List comments; public Task(int id, String name, String description, Date deadline, Status status, Priority priority, Project parentProject, Date createdAt, Date updatedAt) { this.id = id; @@ -87,6 +88,7 @@ public Task(int id, String name, String description, Date deadline, Status statu this.createdAt = createdAt; this.updatedAt = updatedAt; this.actors = new ArrayList<>(); + this.comments = new ArrayList<>(); } public int getId() { return id; } @@ -111,6 +113,10 @@ public Status getStatus() { return status; } + public void setStatus(Status status) { + this.status = status; + } + public Priority getPriority() { return priority; } @@ -125,6 +131,34 @@ public void setActors(List actors) { this.actors = actors; } + public List getComments() { + return comments; + } + + public void setComments(List comments) { + this.comments = comments; + } + + public void setName(String name) { + this.name = name; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setDeadline(Date deadline) { + this.deadline = deadline; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + @Override public String toString() { return this.name; diff --git a/src/main/java/com/maestro/desktop/models/User.java b/src/main/java/com/maestro/desktop/models/User.java index 0fb308d..85f25ca 100644 --- a/src/main/java/com/maestro/desktop/models/User.java +++ b/src/main/java/com/maestro/desktop/models/User.java @@ -121,6 +121,9 @@ public void setProjects(List projects) { this.projects = projects; } + + public void removeProject(Project project) { this.projects.remove(project); } + public int getTasksToDo(){ int counter = 0; for(Project project : this.projects){ @@ -152,6 +155,5 @@ public int getNumberOfTasks(){ } return counter; } - } diff --git a/src/main/java/com/maestro/desktop/utils/ComponentFactory.java b/src/main/java/com/maestro/desktop/utils/ComponentFactory.java index 06f99cf..2beab2d 100644 --- a/src/main/java/com/maestro/desktop/utils/ComponentFactory.java +++ b/src/main/java/com/maestro/desktop/utils/ComponentFactory.java @@ -1,5 +1,7 @@ package com.maestro.desktop.utils; +import com.maestro.desktop.controllers.AppController; +import com.maestro.desktop.models.Comment; import com.maestro.desktop.models.Task; import com.maestro.desktop.models.User; import javafx.geometry.Insets; @@ -36,36 +38,40 @@ public void displayActors(HBox container, int limit, List actorList) { if (actorList.isEmpty()) { System.out.println("No actors found"); } else if (actorList.size() <= limit) { - for(int i=0; i btn.getParent().fireEvent(event)); btn.getStyleClass().setAll("actor-pfp"); ImageView iv = new ImageView(); - iv.setUserData(actorList.get(i).getProfilePhotoPath()); + iv.setUserData(actorList.get(i).getProfilePhotoPath().isEmpty() ? getClass().getResource("/images/default-pfp.png").toString() : actorList.get(i).getProfilePhotoPath()); iv.setFitWidth(24); iv.setFitHeight(24); Circle clipShape = new Circle(12, 12, 12); iv.setClip(clipShape); btn.setGraphic(iv); - if (i!=0) { + if (i != 0) { HBox.setMargin(btn, new Insets(0, 0, 0, -5)); } container.getChildren().add(btn); new Thread(() -> { + System.out.println(iv.getUserData()); iv.setImage(new Image((String) iv.getUserData())); }).start(); } } else { - for(int i=0; i<3; i++) { + for (int i = 0; i < 3; i++) { Button btn = new Button(); + btn.setMouseTransparent(true); btn.getStyleClass().setAll("actor-pfp"); ImageView iv = new ImageView(); - iv.setUserData(actorList.get(i).getProfilePhotoPath()); + iv.setUserData(actorList.get(i).getProfilePhotoPath().isEmpty() ? getClass().getResource("/images/default-pfp.png").toString() : actorList.get(i).getProfilePhotoPath()); iv.setFitWidth(24); iv.setFitHeight(24); Circle clipShape = new Circle(12, 12, 12); iv.setClip(clipShape); btn.setGraphic(iv); - if (i!=0) { + if (i != 0) { HBox.setMargin(btn, new Insets(0, 0, 0, -5)); } container.getChildren().add(btn); @@ -74,9 +80,10 @@ public void displayActors(HBox container, int limit, List actorList) { }).start(); } Button btn = new Button(); + btn.setMouseTransparent(true); btn.getStyleClass().setAll("actor-pfp"); HBox.setMargin(btn, new Insets(0, 0, 0, -5)); - Label label = new Label("+" + (actorList.size()-3)); + Label label = new Label("+" + (actorList.size() - 3)); label.setAlignment(Pos.CENTER); label.setPrefWidth(24); label.setPrefHeight(24); @@ -97,13 +104,16 @@ public HBox createTaskItem(Task task) { sep.getStyleClass().setAll("line"); Line sep2 = new Line(0, 0, 0, 20); sep2.getStyleClass().setAll("line"); + Line sep3 = new Line(0, 0, 0, 20); + sep3.getStyleClass().setAll("line"); Button calendarIcon = new Button(); + calendarIcon.setMouseTransparent(true); calendarIcon.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); calendarIcon.setPrefSize(16, 16); calendarIcon.setId("calendar-icon"); var df = new SimpleDateFormat("MMM. d, yyyy", Locale.ENGLISH); - Label deadlineText = new Label(task.getDeadline()!= null ? df.format(task.getDeadline()) : "Not specified"); + Label deadlineText = new Label(task.getDeadline() != null ? df.format(task.getDeadline()) : "Not specified"); deadlineText.getStyleClass().setAll("item-due-date"); HBox deadline = new HBox(5, calendarIcon, deadlineText); deadline.setAlignment(Pos.CENTER_LEFT); @@ -111,11 +121,15 @@ public HBox createTaskItem(Task task) { HBox taskActors = new HBox(); this.displayActors(taskActors, 4, task.getActors()); + Label priority = new Label(task.getPriority().getName()); + priority.setId(task.getPriority().name()); + priority.setPadding(new Insets(2, 7, 2, 7)); + Region filler = new Region(); filler.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE); HBox.setHgrow(filler, Priority.ALWAYS); - HBox item = new HBox(15, itemTitle, sep, deadline, sep2, taskActors, filler); + HBox item = new HBox(15, itemTitle, sep, deadline, sep2, priority, sep3, taskActors, filler); item.setPadding(new Insets(10, 15, 10, 15)); item.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE); item.setAlignment(Pos.CENTER_LEFT); @@ -126,11 +140,29 @@ public HBox createTaskItem(Task task) { acceptBtn.setId("accept-icon"); acceptBtn.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); acceptBtn.setPrefSize(20, 20); + acceptBtn.setOnAction(event -> { + try { + DatabaseConnection.getInstance().updateTaskStatus(task, Task.Status.COMPLETED); + } catch (SQLException e) { + e.printStackTrace(); + } + task.setStatus(Task.Status.COMPLETED); + AppController.getInstance().navigateWithData(task.getParentProject()); + }); Button rejectBtn = new Button(); rejectBtn.setId("refuse-icon"); rejectBtn.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); rejectBtn.setPrefSize(20, 20); + rejectBtn.setOnAction(event -> { + try { + DatabaseConnection.getInstance().updateTaskStatus(task, Task.Status.IN_PROGRESS); + } catch (SQLException e) { + e.printStackTrace(); + } + task.setStatus(Task.Status.IN_PROGRESS); + AppController.getInstance().navigateWithData(task.getParentProject()); + }); item.getChildren().addAll(acceptBtn, rejectBtn); } @@ -138,4 +170,41 @@ public HBox createTaskItem(Task task) { return item; } -} + + public VBox createCommentItem(Comment comment) { + if (comment == null) { + return null; + } + ImageView iv = new ImageView(); + iv.setUserData(comment.getAuthor().getProfilePhotoPath()); + iv.setFitWidth(32); + iv.setFitHeight(32); + Circle clipShape = new Circle(16, 16, 16); + iv.setClip(clipShape); + + Label author = new Label(comment.getAuthor().getName()); + author.getStyleClass().setAll("comment-author"); + var df = new SimpleDateFormat("MMM. d, yyyy", Locale.ENGLISH); + Label publishedDate = new Label(comment.getCreatedAt() != null ? df.format(comment.getCreatedAt()) : "No date specified"); + publishedDate.getStyleClass().setAll("published-date"); + VBox vBox = new VBox(1, author, publishedDate); + + HBox hbox = new HBox(10, iv, vBox); + Label content = new Label(comment.getContent()); + content.setWrapText(true); + content.setMinHeight(Region.USE_PREF_SIZE); + content.setMaxSize(Integer.MAX_VALUE, Integer.MAX_VALUE); + + VBox item = new VBox(15, hbox, content); + item.setPadding(new Insets(15, 15, 15, 15)); + item.setPrefSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + item.setMaxWidth(500); + item.getStyleClass().setAll("new-comment"); + + new Thread(() -> { + iv.setImage(new Image((String) iv.getUserData())); + }).start(); + + return item; + } +} \ No newline at end of file diff --git a/src/main/java/com/maestro/desktop/utils/DatabaseConnection.java b/src/main/java/com/maestro/desktop/utils/DatabaseConnection.java index 725217c..f0e251a 100644 --- a/src/main/java/com/maestro/desktop/utils/DatabaseConnection.java +++ b/src/main/java/com/maestro/desktop/utils/DatabaseConnection.java @@ -1,11 +1,15 @@ package com.maestro.desktop.utils; +import com.maestro.desktop.controllers.AppController; import com.maestro.desktop.controllers.NavigableView; import com.maestro.desktop.controllers.ProjectController; +import com.maestro.desktop.models.Comment; import com.maestro.desktop.models.Project; import com.maestro.desktop.models.Task; import com.maestro.desktop.models.User; +import java.time.Instant; +import java.time.Period; import java.util.ArrayList; import java.util.Date; import java.sql.*; @@ -13,6 +17,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.List; +import java.util.stream.Collectors; public class DatabaseConnection { private static DatabaseConnection instance; @@ -78,6 +83,7 @@ public List fetchAllProjects(User user) throws SQLException { user ); project.setTasks(this.fetchAllTasks(project)); + project.setUsers(this.fetchProjectUsers(project)); list.add(project); } return list; @@ -101,6 +107,7 @@ public List fetchAllTasks(Project project) throws SQLException { this.dateFromString(rs.getString("updated_at")) ); task.setActors(this.fetchTaskActors(task)); + task.setComments(this.fetchTaskComments(task)); list.add(task); } return list; @@ -125,6 +132,86 @@ public List fetchTaskActors(Task task) throws SQLException { } return list; } + public List fetchTaskComments(Task task) throws SQLException{ + var list = new ArrayList(); + String query = "select * from comments where task_id = ? order by created_at desc"; + PreparedStatement preparedStatement = this.connection.prepareStatement(query); + preparedStatement.setInt(1, task.getId()); + ResultSet rs = preparedStatement.executeQuery(); + while (rs.next()) { + var comment = new Comment( + rs.getInt("id"), + rs.getString("content"), + this.fetchUserFromID(rs.getInt("user_id")), + this.dateFromString(rs.getString("created_at")), + this.dateFromString(rs.getString("updated_at")) + ); + list.add(comment); + } + return list; + } + + public User fetchUserFromID(int id) throws SQLException{ + String query = "select u.id, u.first_name, u.last_name, u.email, u.profile_photo_path, u.created_at, u.updated_at from users u where u.id = ?"; + PreparedStatement preparedStatement = this.connection.prepareStatement(query); + preparedStatement.setInt(1, id); + ResultSet rs = preparedStatement.executeQuery(); + if(rs.next()) { + var user = new User( + rs.getInt("id"), + rs.getString("first_name"), + rs.getString("last_name"), + rs.getString("email"), + rs.getString("profile_photo_path"), + this.dateFromString(rs.getString("created_at")), + this.dateFromString(rs.getString("updated_at")) + ); + return user; + } else { + return null; + } + } + public User fetchUserFromEmail(String email) throws SQLException{ + String query = "select u.id, u.first_name, u.last_name, u.email, u.profile_photo_path, u.created_at, u.updated_at from users u where u.email = ?"; + PreparedStatement preparedStatement = this.connection.prepareStatement(query); + preparedStatement.setString(1, email); + ResultSet rs = preparedStatement.executeQuery(); + if(rs.next()) { + var user = new User( + rs.getInt("id"), + rs.getString("first_name"), + rs.getString("last_name"), + rs.getString("email"), + rs.getString("profile_photo_path"), + this.dateFromString(rs.getString("created_at")), + this.dateFromString(rs.getString("updated_at")) + ); + return user; + } else { + return null; + } + } + + public List fetchProjectUsers(Project project) throws SQLException{ + var list = new ArrayList(); + String query = "select u.id, u.first_name, u.last_name, u.email, u.profile_photo_path, u.created_at, u.updated_at from users u, user_project up where up.project_id = ? and up.user_id = u.id and up.is_admin = 0"; + PreparedStatement preparedStatement = this.connection.prepareStatement(query); + preparedStatement.setInt(1, project.getId()); + ResultSet rs = preparedStatement.executeQuery(); + while (rs.next()) { + var user = new User( + rs.getInt("id"), + rs.getString("first_name"), + rs.getString("last_name"), + rs.getString("email"), + rs.getString("profile_photo_path"), + this.dateFromString(rs.getString("created_at")), + this.dateFromString(rs.getString("updated_at")) + ); + list.add(user); + } + return list; + } public User updateUser(int userId) { User userCreation = null; PreparedStatement ps; @@ -135,7 +222,6 @@ public User updateUser(int userId) { ps.setInt(1, userId); rs = ps.executeQuery(); - if (rs.next()) { // Assuming your password column in the database is named "password" userCreation = new User(rs.getInt("id"), rs.getString("first_name"), rs.getString("last_name"), rs.getString("email"), rs.getString("password"), rs.getString("profile_photo_path")); @@ -154,6 +240,7 @@ public User updateUser(int userId) { } return userCreation; } + public void insertProject(Project project) throws SQLException { String query = "insert into projects(name, description, start_date, end_date, created_at, updated_at) values (?, ?, ?, ?, ?, NOW())"; PreparedStatement prepStatement = this.connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS); @@ -201,7 +288,7 @@ public void insertTask(Task task) throws SQLException { } for (User user : task.getActors()){ - String query3 = "insert into user-task(user_id, task_id, created_at, updated_at) values (?, ?, NOW(), NOW())"; + String query3 = "insert into user_task(user_id, task_id, created_at, updated_at) values (?, ?, NOW(), NOW())"; PreparedStatement preparedStatement = this.connection.prepareStatement(query3); preparedStatement.setInt(1, user.getId()); preparedStatement.setInt(2, task.getId()); @@ -209,6 +296,19 @@ public void insertTask(Task task) throws SQLException { } } + public void insertComment(Comment comment, int taskID) throws SQLException{ + String query = "insert into comments(content, user_id, task_id, created_at, updated_at) values (?, ?, ?, NOW(), NOW())"; + PreparedStatement prepStatement = this.connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS); + prepStatement.setString(1, comment.getContent()); + prepStatement.setInt(2, AppController.getInstance().getUser().getId()); + prepStatement.setInt(3, taskID); + prepStatement.executeUpdate(); + ResultSet rs = prepStatement.getGeneratedKeys(); + if (rs.next()) { + comment.setId(rs.getInt(1)); + } + } + public void updateAllProjects(User user) throws SQLException { user.setProjects(this.fetchAllProjects(user)); } @@ -217,21 +317,93 @@ public void updateAllTasks(Project project) throws SQLException { project.setTasks(this.fetchAllTasks(project)); } - public void checkProjectUpdate(Project project) throws SQLException{ - String query = "select p.name, p.description, p.start_date, p.end_date, p.updated_at from projects p where p.id = ? and p.updated_at != ?"; + public void updateTaskStatus(Task task, Task.Status status) throws SQLException{ + String query = "update tasks set status = ? where id = ?"; + PreparedStatement preparedStatement = this.connection.prepareStatement(query); + preparedStatement.setInt(1, status.getValue()); + preparedStatement.setInt(2, task.getId()); + preparedStatement.executeUpdate(); + } + + public void updateProject(Project project, List newCollaborators) throws SQLException{ + String query = "update projects set name = ?, description = ?, start_date = ?, end_date = ?, updated_at = NOW() where id = ?"; + PreparedStatement preparedStatement = this.connection.prepareStatement(query); + preparedStatement.setString(1, project.getName()); + preparedStatement.setString(2, project.getDescription()); + preparedStatement.setTimestamp(3, new Timestamp(project.getStartDate().getTime())); + preparedStatement.setTimestamp(4, new Timestamp(project.getEndDate().getTime())); + preparedStatement.setInt(5, project.getId()); + preparedStatement.executeUpdate(); + + String query2 = "delete from user_project where id in (select id from (select * from user_project where project_id = ? and is_admin = 0 and user_id not in ("+this.getIdsFromList(project.getUsers().stream().map(User::getId).toList())+")) as to_delete)"; + PreparedStatement preparedStatement2 = this.connection.prepareStatement(query2); + preparedStatement2.setInt(1, project.getId()); + preparedStatement2.executeUpdate(); + + for (User user : newCollaborators){ + String query3 = "insert into user_project(user_id, project_id, is_admin, created_at, updated_at) values (?, ?, ?, NOW(), NOW())"; + PreparedStatement preparedStatement3 = this.connection.prepareStatement(query3); + preparedStatement3.setInt(1, user.getId()); + preparedStatement3.setInt(2, project.getId()); + preparedStatement3.setInt(3, 0); + preparedStatement3.executeUpdate(); + } + } + + public void deleteProject(Project project) throws SQLException { + String query = "delete from projects where id = ?"; PreparedStatement preparedStatement = this.connection.prepareStatement(query); preparedStatement.setInt(1, project.getId()); - preparedStatement.setTimestamp(2, new Timestamp(project.getUpdatedAt().getTime())); - ResultSet rs = preparedStatement.executeQuery(); - if (rs.next()) { - project.setName(rs.getString("name")); - project.setDescription(rs.getString("description")); - project.setStartDate(this.dateFromString(rs.getString("start_date"))); - project.setEndDate(this.dateFromString(rs.getString("end_date"))); - project.setUpdatedAt(this.dateFromString(rs.getString("updated_at"))); + preparedStatement.executeUpdate(); + } + + public void updateTask(Task task, List newActors) throws SQLException { + String query = "update tasks set name = ?, description = ?, deadline = ?, status = ?, priority = ?, updated_at = NOW() where id = ?"; + PreparedStatement preparedStatement = this.connection.prepareStatement(query); + preparedStatement.setString(1, task.getName()); + preparedStatement.setString(2, task.getDescription()); + preparedStatement.setTimestamp(3, new Timestamp(task.getDeadline().getTime())); + preparedStatement.setInt(4, task.getStatus().getValue()); + preparedStatement.setInt(5, task.getPriority().getValue()); + preparedStatement.setInt(6, task.getId()); + preparedStatement.executeUpdate(); + + String query2 = "delete from user_task where id in (select id from (select * from user_task where task_id = ? and user_id not in ("+this.getIdsFromList(task.getActors().stream().map(User::getId).toList())+")) as to_delete)"; + PreparedStatement preparedStatement2 = this.connection.prepareStatement(query2); + preparedStatement2.setInt(1, task.getId()); + preparedStatement2.executeUpdate(); + + for (User user : newActors){ + String query3 = "insert into user_task(user_id, task_id, created_at, updated_at) values (?, ?, NOW(), NOW())"; + PreparedStatement preparedStatement3 = this.connection.prepareStatement(query3); + preparedStatement3.setInt(1, user.getId()); + preparedStatement3.setInt(2, task.getId()); + preparedStatement3.executeUpdate(); } } + public void deleteTask(Task task) throws SQLException { + String query = "delete from tasks where id = ?"; + PreparedStatement preparedStatement = this.connection.prepareStatement(query); + preparedStatement.setInt(1, task.getId()); + preparedStatement.executeUpdate(); + } + +// public void checkProjectUpdate(Project project) throws SQLException{ +// String query = "select p.name, p.description, p.start_date, p.end_date, p.updated_at from projects p where p.id = ? and p.updated_at != ?"; +// PreparedStatement preparedStatement = this.connection.prepareStatement(query); +// preparedStatement.setInt(1, project.getId()); +// preparedStatement.setTimestamp(2, new Timestamp(project.getUpdatedAt().getTime())); +// ResultSet rs = preparedStatement.executeQuery(); +// if (rs.next()) { +// project.setName(rs.getString("name")); +// project.setDescription(rs.getString("description")); +// project.setStartDate(this.dateFromString(rs.getString("start_date"))); +// project.setEndDate(this.dateFromString(rs.getString("end_date"))); +// project.setUpdatedAt(this.dateFromString(rs.getString("updated_at"))); +// } +// } + private Date dateFromString(String str) { System.out.println("str: "+str); if(str!= null) { @@ -270,4 +442,10 @@ public void editTable(String table, String column, String row, int rowValue, Str throw new RuntimeException(e); } } -} + + private String getIdsFromList(List ints) { + return ints.isEmpty() ? "-1" : ints.stream() + .map(Object::toString) + .collect(Collectors.joining(", ")); + } +} \ No newline at end of file diff --git a/src/main/resources/styles/all-projects.css b/src/main/resources/styles/all-projects.css index 630d910..2cfdc84 100644 --- a/src/main/resources/styles/all-projects.css +++ b/src/main/resources/styles/all-projects.css @@ -64,4 +64,9 @@ .description { -fx-text-fill: #818181; -fx-font-size: 12; +} + +ScrollPane { + -fx-focus-color: transparent; + -fx-border-width: 0; } \ No newline at end of file diff --git a/src/main/resources/styles/app.css b/src/main/resources/styles/app.css index 29ef2a3..37c68b2 100644 --- a/src/main/resources/styles/app.css +++ b/src/main/resources/styles/app.css @@ -11,6 +11,10 @@ -fx-shape: "M24.375 30.4688C24.375 30.792 24.2466 31.102 24.018 31.3305C23.7895 31.5591 23.4795 31.6875 23.1562 31.6875H3.65625C3.33302 31.6875 3.02302 31.5591 2.79446 31.3305C2.5659 31.102 2.4375 30.792 2.4375 30.4688V8.53125C2.4375 8.20802 2.5659 7.89802 2.79446 7.66946C3.02302 7.4409 3.33302 7.3125 3.65625 7.3125H23.1562C23.4795 7.3125 23.7895 7.4409 24.018 7.66946C24.2466 7.89802 24.375 8.20802 24.375 8.53125V13.4062C24.375 13.7295 24.5034 14.0395 24.732 14.268C24.9605 14.4966 25.2705 14.625 25.5938 14.625C25.917 14.625 26.227 14.4966 26.4555 14.268C26.6841 14.0395 26.8125 13.7295 26.8125 13.4062V8.53125C26.8125 7.56155 26.4273 6.63157 25.7416 5.94589C25.0559 5.26021 24.1259 4.875 23.1562 4.875H3.65625C2.68655 4.875 1.75657 5.26021 1.07089 5.94589C0.385211 6.63157 0 7.56155 0 8.53125L0 30.4688C0 31.4384 0.385211 32.3684 1.07089 33.0541C1.75657 33.7398 2.68655 34.125 3.65625 34.125H23.1562C24.1259 34.125 25.0559 33.7398 25.7416 33.0541C26.4273 32.3684 26.8125 31.4384 26.8125 30.4688V25.5938C26.8125 25.2705 26.6841 24.9605 26.4555 24.732C26.227 24.5034 25.917 24.375 25.5938 24.375C25.2705 24.375 24.9605 24.5034 24.732 24.732C24.5034 24.9605 24.375 25.2705 24.375 25.5938V30.4688Z M38.6441 20.363C38.7576 20.2497 38.8477 20.1152 38.9091 19.9672C38.9706 19.8191 39.0022 19.6604 39.0022 19.5001C39.0022 19.3398 38.9706 19.181 38.9091 19.033C38.8477 18.8849 38.7576 18.7504 38.6441 18.6372L31.3316 11.3247C31.1028 11.0959 30.7924 10.9673 30.4688 10.9673C30.1451 10.9673 29.8347 11.0959 29.6059 11.3247C29.377 11.5535 29.2485 11.8639 29.2485 12.1876C29.2485 12.5112 29.377 12.8216 29.6059 13.0505L34.8392 18.2813H13.4062C13.083 18.2813 12.773 18.4097 12.5445 18.6383C12.3159 18.8668 12.1875 19.1768 12.1875 19.5001C12.1875 19.8233 12.3159 20.1333 12.5445 20.3619C12.773 20.5904 13.083 20.7188 13.4062 20.7188H34.8392L29.6059 25.9497C29.377 26.1785 29.2485 26.4889 29.2485 26.8126C29.2485 27.1362 29.377 27.4466 29.6059 27.6755C29.8347 27.9043 30.1451 28.0329 30.4688 28.0329C30.7924 28.0329 31.1028 27.9043 31.3316 27.6755L38.6441 20.363Z"; } +#new-project-icon { + -fx-shape: "M11.28 1.02299L10.72 1.08299C8.83203 1.28299 6.99103 2.02299 5.36003 3.23499C4.75103 3.68799 3.68403 4.75499 3.22603 5.36699C0.728033 8.71399 0.301033 13.032 2.09703 16.78C2.64303 17.918 3.27603 18.801 4.23803 19.762C5.19903 20.724 6.08203 21.357 7.22003 21.903C10.967 23.699 15.288 23.27 18.637 20.77C19.246 20.316 20.316 19.246 20.77 18.637C23.744 14.652 23.744 9.34799 20.77 5.36299C20.316 4.75499 19.247 3.68599 18.64 3.23499C17.045 2.04899 15.365 1.35999 13.423 1.09599C13 1.03799 11.574 0.989989 11.28 1.02299ZM13.32 3.10099C15.883 3.48799 18.124 4.93099 19.56 7.11999C19.863 7.58299 20.303 8.47899 20.492 9.01999C20.838 10.013 20.977 10.865 20.977 12C20.977 13.493 20.72 14.621 20.08 15.94C19.375 17.394 18.311 18.607 16.927 19.532C16.138 20.06 14.876 20.588 13.908 20.797C12.5983 21.0767 11.2428 21.0622 9.9393 20.7548C8.6358 20.4473 7.41675 19.8545 6.37003 19.019C4.85703 17.807 3.72203 16.029 3.26703 14.16C3.08103 13.397 3.02303 12.888 3.02303 12C3.02303 10.507 3.28003 9.37899 3.92003 8.05999C4.44342 6.98382 5.17656 6.02307 6.0764 5.23416C6.97624 4.44526 8.02464 3.8441 9.16003 3.46599C9.86503 3.23299 10.432 3.11799 11.34 3.02399C11.662 2.99099 12.911 3.03899 13.32 3.10099ZM11.695 7.05699C11.4568 7.13651 11.2554 7.29955 11.128 7.51599L11.02 7.69999L11.008 9.34999L10.997 11H9.44503C7.75803 11 7.65803 11.011 7.38203 11.221C7.30203 11.282 7.18703 11.415 7.12803 11.516C7.03703 11.672 7.02003 11.746 7.02003 12C7.02003 12.256 7.03603 12.328 7.13103 12.489C7.19203 12.592 7.30403 12.725 7.38103 12.783C7.65403 12.991 7.70003 12.996 9.40803 12.998L10.997 13L11.008 14.653L11.02 16.306L11.141 16.503C11.209 16.613 11.346 16.756 11.452 16.828C11.923 17.144 12.554 16.999 12.859 16.503L12.98 16.306L12.992 14.653L13.003 13L14.592 12.998C16.3 12.996 16.346 12.991 16.619 12.783C16.696 12.725 16.808 12.592 16.869 12.489C16.964 12.328 16.98 12.256 16.98 12C16.98 11.746 16.963 11.672 16.872 11.516C16.8039 11.4046 16.7181 11.305 16.618 11.221C16.342 11.011 16.242 11 14.555 11H13.003L12.992 9.34999L12.98 7.69999L12.872 7.51599C12.7579 7.3164 12.5789 7.16196 12.3647 7.07843C12.1505 6.9949 11.9141 6.98733 11.695 7.05699Z"; +} + .sidebar { @@ -35,6 +39,15 @@ -fx-text-fill: #818181; } +.special-sidebar-item { + -fx-border-color: #818181; + -fx-border-radius: 7; +} + +.special-sidebar-item:hover { + -fx-background-color: #bbbbbb; +} + .icon { -fx-background-color: #818181; } diff --git a/src/main/resources/styles/dialog.css b/src/main/resources/styles/dialog.css new file mode 100644 index 0000000..7602f50 --- /dev/null +++ b/src/main/resources/styles/dialog.css @@ -0,0 +1,125 @@ +#valid-btn { + -fx-background-color: #F7422B; + -fx-background-radius: 10; + -fx-text-fill: #fff; + -fx-font-weight: bold; + -fx-effect: dropshadow(three-pass-box, rgba(123, 123, 123, 0.5), 4, 0, -2, 2); +} + +#cancel-btn { + -fx-background-color: #ffffff; + -fx-background-radius: 10; + -fx-text-fill: #000; + -fx-font-weight: bold; + -fx-effect: dropshadow(three-pass-box, rgba(123, 123, 123, 0.5), 4, 0, -2, 2); + +} + +#delete-btn { + -fx-background-color: #dd0c0c; + -fx-background-radius: 10; + -fx-text-fill: #fff; + -fx-font-weight: bold; + -fx-effect: dropshadow(three-pass-box, rgba(123, 123, 123, 0.5), 4, 0, -2, 2); +} + +.status, .priority, .collaboratorMenu { + -fx-background-color: #d1d1d1; +} + +#IN_REVISION { + -fx-text-fill: #C64FE4; + -fx-background-color: rgba(198, 79, 228, 0.25); + -fx-border-color: #C64FE4; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#TO_DO { + -fx-text-fill: #4f6ae4; + -fx-background-color: rgba(79, 106, 228, 0.25); + -fx-border-color: #4f6ae4; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#IN_PROGRESS { + -fx-text-fill: #e07232; + -fx-background-color: rgba(224, 114, 50, 0.25); + -fx-border-color: #e07232; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#COMPLETED { + -fx-text-fill: #52b62e; + -fx-background-color: rgba(82, 182, 46, 0.25); + -fx-border-color: #52b62e; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#HIGH { + -fx-text-fill: #e03232; + -fx-background-color: rgba(224, 50, 50, 0.25); + -fx-border-color: #e03232; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#MEDIUM { + -fx-text-fill: #e07232; + -fx-background-color: rgba(224, 114, 50, 0.25); + -fx-border-color: #e07232; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#LOW { + -fx-text-fill: #e0b432; + -fx-background-color: rgba(224, 189, 50, 0.25); + -fx-border-color: #e0b432; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +.text-area .content{ + -fx-background-color: #e0e0e0; + -fx-background-radius: 5; +} + +.text-area { + -fx-background-color: transparent; + -fx-background-radius: 5; +} + +.text-field, .date-picker, .date-picker .arrow-button { + -fx-background-color: #e0e0e0; + -fx-background-radius: 5; +} + +.date-picker .arrow-button { + -fx-background-color: #c0c0c0; +} + +.date-picker { + -fx-border-color: transparent; +} + +.error-container { + -fx-background-color: #d89890; + -fx-background-radius: 5; +} + +.collaborator { + -fx-background-color: #e0e0e0; + -fx-border-color: #989898; + -fx-background-radius: 5; + -fx-border-radius: 8; + -fx-padding: 3 5 3 5; +} + +#delete-collaborator { + -fx-shape: "M23.5001 2.13135L22.3334 2.25635C18.4001 2.67302 14.5647 4.21468 11.1668 6.73968C9.89803 7.68343 7.67511 9.90635 6.72094 11.1813C1.51678 18.1543 0.627192 27.1501 4.36886 34.9584C5.50636 37.3293 6.82511 39.1688 8.82928 41.1709C10.8314 43.1751 12.6709 44.4938 15.0418 45.6313C22.848 49.373 31.8501 48.4793 38.8272 43.2709C40.0959 42.3251 42.3251 40.0959 43.2709 38.8272C49.4668 30.5251 49.4668 19.4751 43.2709 11.173C42.3251 9.90635 40.098 7.67927 38.8334 6.73968C35.5105 4.26885 32.0105 2.83343 27.9647 2.28343C27.0834 2.1626 24.1126 2.0626 23.5001 2.13135ZM27.7501 6.46052C33.0897 7.26677 37.7584 10.273 40.7501 14.8334C41.3814 15.798 42.298 17.6647 42.6918 18.7918C43.4126 20.8605 43.7022 22.6355 43.7022 25.0001C43.7022 28.1105 43.1668 30.4605 41.8334 33.2084C40.3647 36.2376 38.148 38.7647 35.2647 40.6918C33.6209 41.7918 30.9918 42.8918 28.9751 43.3272C26.2465 43.9098 23.4225 43.8798 20.7069 43.2392C17.9913 42.5987 15.4516 41.3636 13.2709 39.623C10.1189 37.098 7.75428 33.3938 6.80636 29.5001C6.41886 27.9105 6.29803 26.8501 6.29803 25.0001C6.29803 21.8897 6.83344 19.5397 8.16678 16.7918C9.25717 14.5497 10.7845 12.5482 12.6592 10.9046C14.5339 9.26108 16.718 8.00866 19.0834 7.22093C20.5522 6.73552 21.7334 6.49593 23.6251 6.3001C24.2959 6.23135 26.898 6.33135 27.7501 6.46052ZM18.0626 16.7938C17.6001 16.9626 17.1876 17.3105 16.9334 17.7418C16.7418 18.0668 16.7084 18.2188 16.7105 18.7501C16.7105 19.1938 16.7564 19.4605 16.8647 19.6668C16.9501 19.8272 18.148 21.0938 19.5293 22.4793L22.0376 25.0001L19.5293 27.5209C18.148 28.9084 16.9543 30.1688 16.8772 30.323C16.4001 31.2689 16.7834 32.5022 17.7251 33.0563C18.0689 33.2584 18.2126 33.2918 18.7501 33.2897C19.1939 33.2897 19.4605 33.2438 19.6668 33.1355C19.8272 33.0501 21.0939 31.8522 22.4793 30.4709L25.0001 27.9626L27.5209 30.4709C28.9084 31.8522 30.1689 33.0459 30.323 33.123C31.2689 33.6001 32.5022 33.2168 33.0564 32.2751C33.2584 31.9313 33.2918 31.7876 33.2897 31.2501C33.2897 30.8063 33.2439 30.5397 33.1355 30.3334C33.0501 30.173 31.8522 28.9084 30.4709 27.5209L27.9626 25.0001L30.4709 22.4793C31.8522 21.0938 33.0501 19.8272 33.1355 19.6668C33.2439 19.4605 33.2897 19.1938 33.2897 18.7501C33.2918 18.2188 33.2584 18.0668 33.0668 17.7418C32.8248 17.3105 32.4373 16.9794 31.9735 16.8076C31.5098 16.6359 31.0001 16.6347 30.5355 16.8043C30.1751 16.9251 29.8168 17.248 27.5626 19.4876L25.0001 22.0334L22.4376 19.4876C20.1834 17.248 19.8251 16.9251 19.4647 16.8043C19.0125 16.6394 18.5172 16.6357 18.0626 16.7938Z"; + -fx-background-color: #989898; +} \ No newline at end of file diff --git a/src/main/resources/styles/project.css b/src/main/resources/styles/project.css index b891b94..db40fcf 100644 --- a/src/main/resources/styles/project.css +++ b/src/main/resources/styles/project.css @@ -18,6 +18,10 @@ -fx-shape: "M23.5001 2.13135L22.3334 2.25635C18.4001 2.67302 14.5647 4.21468 11.1668 6.73968C9.89803 7.68343 7.67511 9.90635 6.72094 11.1813C1.51678 18.1543 0.627192 27.1501 4.36886 34.9584C5.50636 37.3293 6.82511 39.1688 8.82928 41.1709C10.8314 43.1751 12.6709 44.4938 15.0418 45.6313C22.848 49.373 31.8501 48.4793 38.8272 43.2709C40.0959 42.3251 42.3251 40.0959 43.2709 38.8272C49.4668 30.5251 49.4668 19.4751 43.2709 11.173C42.3251 9.90635 40.098 7.67927 38.8334 6.73968C35.5105 4.26885 32.0105 2.83343 27.9647 2.28343C27.0834 2.1626 24.1126 2.0626 23.5001 2.13135ZM27.7501 6.46052C33.0897 7.26677 37.7584 10.273 40.7501 14.8334C41.3814 15.798 42.298 17.6647 42.6918 18.7918C43.4126 20.8605 43.7022 22.6355 43.7022 25.0001C43.7022 28.1105 43.1668 30.4605 41.8334 33.2084C40.3647 36.2376 38.148 38.7647 35.2647 40.6918C33.6209 41.7918 30.9918 42.8918 28.9751 43.3272C26.2465 43.9098 23.4225 43.8798 20.7069 43.2392C17.9913 42.5987 15.4516 41.3636 13.2709 39.623C10.1189 37.098 7.75428 33.3938 6.80636 29.5001C6.41886 27.9105 6.29803 26.8501 6.29803 25.0001C6.29803 21.8897 6.83344 19.5397 8.16678 16.7918C9.25717 14.5497 10.7845 12.5482 12.6592 10.9046C14.5339 9.26108 16.718 8.00866 19.0834 7.22093C20.5522 6.73552 21.7334 6.49593 23.6251 6.3001C24.2959 6.23135 26.898 6.33135 27.7501 6.46052ZM18.0626 16.7938C17.6001 16.9626 17.1876 17.3105 16.9334 17.7418C16.7418 18.0668 16.7084 18.2188 16.7105 18.7501C16.7105 19.1938 16.7564 19.4605 16.8647 19.6668C16.9501 19.8272 18.148 21.0938 19.5293 22.4793L22.0376 25.0001L19.5293 27.5209C18.148 28.9084 16.9543 30.1688 16.8772 30.323C16.4001 31.2689 16.7834 32.5022 17.7251 33.0563C18.0689 33.2584 18.2126 33.2918 18.7501 33.2897C19.1939 33.2897 19.4605 33.2438 19.6668 33.1355C19.8272 33.0501 21.0939 31.8522 22.4793 30.4709L25.0001 27.9626L27.5209 30.4709C28.9084 31.8522 30.1689 33.0459 30.323 33.123C31.2689 33.6001 32.5022 33.2168 33.0564 32.2751C33.2584 31.9313 33.2918 31.7876 33.2897 31.2501C33.2897 30.8063 33.2439 30.5397 33.1355 30.3334C33.0501 30.173 31.8522 28.9084 30.4709 27.5209L27.9626 25.0001L30.4709 22.4793C31.8522 21.0938 33.0501 19.8272 33.1355 19.6668C33.2439 19.4605 33.2897 19.1938 33.2897 18.7501C33.2918 18.2188 33.2584 18.0668 33.0668 17.7418C32.8248 17.3105 32.4373 16.9794 31.9735 16.8076C31.5098 16.6359 31.0001 16.6347 30.5355 16.8043C30.1751 16.9251 29.8168 17.248 27.5626 19.4876L25.0001 22.0334L22.4376 19.4876C20.1834 17.248 19.8251 16.9251 19.4647 16.8043C19.0125 16.6394 18.5172 16.6357 18.0626 16.7938Z"; -fx-background-color: #C62B2B; } +#left-chevron-icon { + -fx-shape: "M14.64 5.06782C14.485 5.12082 14.036 5.55282 11.347 8.23482C9.57002 10.0078 8.18802 11.4168 8.12702 11.5198C8.03602 11.6718 8.02002 11.7458 8.02002 11.9998C8.02002 12.2538 8.03602 12.3278 8.12702 12.4798C8.26302 12.7068 14.37 18.8068 14.555 18.8988C15.01 19.1278 15.601 18.9438 15.867 18.4918C15.964 18.3268 15.98 18.2578 15.979 17.9998C15.979 17.7878 15.957 17.6588 15.905 17.5598C15.865 17.4828 14.614 16.1998 13.126 14.7098L10.421 11.9998L13.126 9.28982C14.614 7.79982 15.865 6.51682 15.905 6.43982C15.957 6.34082 15.979 6.21182 15.979 5.99982C15.98 5.74482 15.964 5.67182 15.872 5.51582C15.7526 5.30769 15.5634 5.14854 15.3379 5.06654C15.1124 4.98454 14.8652 4.985 14.64 5.06782Z"; + -fx-background-color: #818181; +} .header { -fx-font-size: 32; @@ -90,6 +94,30 @@ -fx-border-color: #52b62e; } +#HIGH { + -fx-text-fill: #e03232; + -fx-background-color: rgba(224, 50, 50, 0.25); + -fx-border-color: #e03232; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#MEDIUM { + -fx-text-fill: #e07232; + -fx-background-color: rgba(224, 114, 50, 0.25); + -fx-border-color: #e07232; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#LOW { + -fx-text-fill: #e0b432; + -fx-background-color: rgba(224, 189, 50, 0.25); + -fx-border-color: #e0b432; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + .no-tasks{ -no-tasks-color: #aeaeae; -fx-border-color: -no-tasks-color; @@ -119,5 +147,19 @@ } .line { - -fx-stroke: #818181; + -fx-stroke: #bdbdbd; +} + +.back-button { + -fx-background-color: transparent; + -fx-text-fill: #818181; +} + +.back-button:hover { + -fx-background-color: #E4E4E4; +} + +ScrollPane { + -fx-focus-color: transparent; + -fx-border-width: 0; } \ No newline at end of file diff --git a/src/main/resources/styles/task.css b/src/main/resources/styles/task.css index e69de29..6bcc0d5 100644 --- a/src/main/resources/styles/task.css +++ b/src/main/resources/styles/task.css @@ -0,0 +1,145 @@ +#edit-icon { + -fx-shape: "M17.52 0.0230399L17.191 0.0820399C16.821 0.16405 16.4692 0.313181 16.153 0.52204C15.803 0.75504 6.22902 10.316 6.12102 10.54C6.02502 10.74 5.00002 14.83 5.00002 15.014C5.00002 15.339 5.20802 15.691 5.49902 15.862C5.84902 16.067 5.88102 16.062 8.20002 15.482C9.35502 15.193 10.372 14.921 10.46 14.879C10.684 14.771 20.287 5.15204 20.502 4.82004C20.7686 4.40079 20.9325 3.92451 20.9803 3.42997C21.0281 2.93542 20.9584 2.43658 20.777 1.97404C20.5949 1.53072 20.3154 1.13406 19.9591 0.813462C19.6029 0.492867 19.179 0.256555 18.719 0.12204C18.431 0.0420399 17.737 -0.0149601 17.52 0.0230399ZM2.49902 1.04304C1.38302 1.23004 0.46102 2.04804 0.11402 3.16004L0.0200195 3.46004V18.54L0.11402 18.84C0.261864 19.3223 0.525678 19.761 0.882365 20.1177C1.23905 20.4744 1.67774 20.7382 2.16002 20.886L2.46002 20.98H17.54L17.84 20.886C18.3223 20.7382 18.761 20.4744 19.1177 20.1177C19.4744 19.761 19.7382 19.3223 19.886 18.84L19.98 18.54V10.7L19.871 10.514C19.7819 10.3622 19.6546 10.2363 19.5018 10.1489C19.3491 10.0614 19.1761 10.0154 19 10.0154C18.824 10.0154 18.651 10.0614 18.4982 10.1489C18.3454 10.2363 18.2181 10.3622 18.129 10.514L18.02 10.7L18 14.48C17.985 17.383 17.968 18.286 17.93 18.373C17.8343 18.58 17.679 18.7538 17.484 18.872L17.3 18.98H2.70002L2.51602 18.872C2.4063 18.8052 2.30805 18.7211 2.22502 18.623C1.98602 18.309 2.00002 18.796 2.00002 11.002C2.00002 2.96804 1.97402 3.63304 2.30602 3.30004C2.62002 2.98604 2.41902 3.00004 6.53702 2.99804C9.47602 2.99704 10.209 2.98604 10.33 2.94304C10.551 2.86404 10.744 2.70204 10.869 2.48904C10.964 2.32804 10.98 2.25604 10.98 2.00004C10.98 1.74604 10.963 1.67204 10.872 1.51604C10.8038 1.40463 10.7181 1.30501 10.618 1.22104C10.32 0.99404 10.426 1.00004 6.40402 1.00504C4.36702 1.00704 2.60902 1.02504 2.49902 1.04304ZM18.388 2.14304C18.77 2.32804 18.976 2.67804 18.975 3.14004C18.975 3.36404 18.954 3.46004 18.87 3.62004C18.791 3.77104 17.632 4.95104 14.113 8.46504L9.46002 13.11L8.44902 13.36C7.89202 13.498 7.42602 13.6 7.41302 13.587C7.40002 13.574 7.50202 13.108 7.64002 12.551L7.89002 11.54L12.535 6.88704C15.396 4.02204 17.241 2.20204 17.34 2.15104C17.428 2.10504 17.554 2.05304 17.62 2.03504C17.813 1.98504 18.164 2.03404 18.388 2.14304Z"; + -fx-background-color: #fff; +} +#calendar-icon { + -fx-shape: "M7.695 1.057a1.04 1.04 0 0 0-.567.459c-.103.176-.109.212-.121.831l-.014.646-1.266.016c-1.209.016-1.282.021-1.588.115A3.077 3.077 0 0 0 2.114 5.16l-.094.3v15.08l.094.3a3.111 3.111 0 0 0 2.026 2.045c.276.091.308.093 2.398.106 2.369.015 2.316.021 2.635-.267a.936.936 0 0 0 .315-.721c0-.388-.194-.705-.548-.897-.157-.084-.204-.086-2.2-.106l-2.04-.02-.184-.108a1.199 1.199 0 0 1-.291-.249C3.989 20.314 4 20.557 4 15.575V11l2.09-.002c1.641-.001 2.122-.013 2.24-.055.221-.079.414-.241.539-.454.095-.161.111-.233.111-.489 0-.254-.017-.328-.108-.484a1.209 1.209 0 0 0-.254-.295C8.334 9.004 8.283 9 6.054 9H4V7.447c0-1.797.007-1.848.303-2.144.281-.281.4-.303 1.641-.303h1.049l.014.653c.013.647.014.655.134.85a.998.998 0 0 0 1.718 0c.12-.195.121-.203.134-.85L9.007 5h5.986l.014.653c.013.647.014.655.134.85a.998.998 0 0 0 1.718 0c.12-.195.121-.203.134-.85L17.007 5h1.049c1.241 0 1.36.022 1.641.303.274.275.303.415.303 1.494.001.866.005.911.095 1.103.181.382.5.588.908.588a.936.936 0 0 0 .721-.315c.273-.303.286-.384.267-1.639-.016-1.023-.024-1.137-.108-1.394a3.095 3.095 0 0 0-2.022-2.016c-.306-.094-.379-.099-1.588-.115l-1.266-.016-.014-.646c-.012-.621-.017-.654-.122-.833a1.01 1.01 0 0 0-1.742 0c-.105.179-.11.212-.122.836l-.014.65H9.007l-.014-.65c-.012-.622-.018-.658-.121-.834a1.005 1.005 0 0 0-1.177-.459m7.845 7.966c-1.062.102-1.848.312-2.63.703-2.072 1.036-3.462 2.94-3.836 5.254-.066.413-.066 1.627 0 2.04.5 3.092 2.814 5.406 5.906 5.906.412.066 1.627.066 2.04 0 3.089-.498 5.408-2.817 5.906-5.906.028-.176.051-.635.051-1.02 0-.944-.101-1.538-.404-2.38-.858-2.383-2.992-4.147-5.471-4.522-.376-.057-1.289-.101-1.562-.075m1.012 2.02a5.008 5.008 0 0 1 4.128 3.205c.412 1.072.405 2.472-.017 3.545a5.076 5.076 0 0 1-3.063 2.939c-.556.19-.93.248-1.6.248s-1.044-.058-1.6-.248a5.041 5.041 0 0 1-3.239-3.492c-.241-.933-.178-2.115.159-2.992a4.997 4.997 0 0 1 5.232-3.205m-.857 2.014a1.04 1.04 0 0 0-.567.459l-.108.184v2.802l.102.199c.083.162.253.326.92.887.969.815 1.11.902 1.453.902a.972.972 0 0 0 .997-.99c-.003-.425-.094-.553-.829-1.166l-.643-.538-.02-1.048-.02-1.048-.108-.184a1.005 1.005 0 0 0-1.177-.459"; + -fx-background-color: #818181; +} +#left-chevron-icon { + -fx-shape: "M14.64 5.06782C14.485 5.12082 14.036 5.55282 11.347 8.23482C9.57002 10.0078 8.18802 11.4168 8.12702 11.5198C8.03602 11.6718 8.02002 11.7458 8.02002 11.9998C8.02002 12.2538 8.03602 12.3278 8.12702 12.4798C8.26302 12.7068 14.37 18.8068 14.555 18.8988C15.01 19.1278 15.601 18.9438 15.867 18.4918C15.964 18.3268 15.98 18.2578 15.979 17.9998C15.979 17.7878 15.957 17.6588 15.905 17.5598C15.865 17.4828 14.614 16.1998 13.126 14.7098L10.421 11.9998L13.126 9.28982C14.614 7.79982 15.865 6.51682 15.905 6.43982C15.957 6.34082 15.979 6.21182 15.979 5.99982C15.98 5.74482 15.964 5.67182 15.872 5.51582C15.7526 5.30769 15.5634 5.14854 15.3379 5.06654C15.1124 4.98454 14.8652 4.985 14.64 5.06782Z"; + -fx-background-color: #818181; +} +#publish-icon { + -fx-shape: "M11.6549 4.55593C3.35194 7.46593 1.50194 8.12792 1.36894 8.23292C0.921937 8.58692 0.886937 9.29092 1.29494 9.69592C1.44094 9.84092 1.95694 10.0809 5.81994 11.7949C8.21794 12.8589 10.1999 13.7499 10.2249 13.7749C10.2499 13.7999 11.1369 15.7719 12.1969 18.1579C13.2559 20.5439 14.1679 22.5549 14.2229 22.6269C14.2779 22.6989 14.4079 22.8079 14.5109 22.8689C14.8979 23.0959 15.4839 22.9859 15.7709 22.6319C15.9489 22.4119 22.9989 2.26992 22.9989 1.97992C22.995 1.7184 22.8877 1.46907 22.7005 1.28639C22.5133 1.10371 22.2615 1.00252 21.9999 1.00492C21.8149 1.00692 20.1529 1.57793 11.6549 4.55593ZM14.4769 8.10292L10.7739 11.8059L7.76794 10.4729C6.11494 9.73992 4.76194 9.12992 4.76094 9.11692C4.75994 9.09892 18.0769 4.41292 18.1599 4.40292C18.1709 4.40092 16.5139 6.06592 14.4769 8.10292ZM19.4249 6.32992L17.0789 13.0309C15.8839 16.4469 14.8919 19.2279 14.8749 19.2109C14.8579 19.1939 14.2489 17.8399 13.5209 16.2019L12.1969 13.2229L15.8879 9.53192C17.9189 7.50092 19.5839 5.83992 19.5889 5.83992C19.5939 5.83992 19.5199 6.05992 19.4249 6.32992Z"; + -fx-background-color: #fff; +} + + +.header { + -fx-font-size: 32; + -fx-font-weight: bold; +} + +.subheader { + -fx-font-size: 18; + -fx-font-weight: bold; +} + +.description { + -fx-max-height: 2em; +} + +.action-btn { + -fx-background-color: #F7422B; + -fx-background-radius: 10; + -fx-text-fill: #fff; + -fx-font-weight: bold; + -fx-effect: dropshadow(three-pass-box, rgba(123, 123, 123, 0.5), 4, 0, -2, 2); +} + +.back-button { + -fx-background-color: transparent; + -fx-text-fill: #818181; +} + +.back-button:hover { + -fx-background-color: #E4E4E4; +} + +ScrollPane { + -fx-focus-color: transparent; + -fx-border-width: 0; +} + +.status { + -fx-background-color: #d1d1d1; +} + +#IN_REVISION { + -fx-text-fill: #C64FE4; + -fx-background-color: rgba(198, 79, 228, 0.25); + -fx-border-color: #C64FE4; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#TO_DO { + -fx-text-fill: #4f6ae4; + -fx-background-color: rgba(79, 106, 228, 0.25); + -fx-border-color: #4f6ae4; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#IN_PROGRESS { + -fx-text-fill: #e07232; + -fx-background-color: rgba(224, 114, 50, 0.25); + -fx-border-color: #e07232; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#COMPLETED { + -fx-text-fill: #52b62e; + -fx-background-color: rgba(82, 182, 46, 0.25); + -fx-border-color: #52b62e; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#HIGH { + -fx-text-fill: #e03232; + -fx-background-color: rgba(224, 50, 50, 0.25); + -fx-border-color: #e03232; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#MEDIUM { + -fx-text-fill: #e07232; + -fx-background-color: rgba(224, 114, 50, 0.25); + -fx-border-color: #e07232; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +#LOW { + -fx-text-fill: #e0b432; + -fx-background-color: rgba(224, 189, 50, 0.25); + -fx-border-color: #e0b432; + -fx-border-radius: 10; + -fx-background-radius: 10; +} + +.text-area .content{ + -fx-background-color: #e0e0e0; + -fx-background-radius: 5; +} + +.text-area { + -fx-background-color: transparent; + -fx-background-radius: 5; +} + +.new-comment { + -fx-background-color: #fff; + -fx-effect: dropshadow(three-pass-box, rgba(123, 123, 123, 0.8), 4, 0, 0, 2); + -fx-background-radius: 15; +} + +.comment { + -fx-background-color: #fff; + -fx-effect: dropshadow(three-pass-box, rgba(123, 123, 123, 0.8), 4, 0, 0, 2); + -fx-background-radius: 15; +} + +.published-date { + -fx-font-size: 11; + -fx-text-fill: #818181; + +} + +.comment-author { + -fx-font-weight: bold; +} \ No newline at end of file diff --git a/src/main/resources/views/all-projects-view.fxml b/src/main/resources/views/all-projects-view.fxml index 8ed7db5..c1ec468 100644 --- a/src/main/resources/views/all-projects-view.fxml +++ b/src/main/resources/views/all-projects-view.fxml @@ -2,20 +2,25 @@ + - - - - + + + + + + + + + + + - - - diff --git a/src/main/resources/views/app-view.fxml b/src/main/resources/views/app-view.fxml index fb1ac5d..74ff3ad 100644 --- a/src/main/resources/views/app-view.fxml +++ b/src/main/resources/views/app-view.fxml @@ -1,5 +1,6 @@ + @@ -35,9 +36,9 @@ - - diff --git a/src/main/resources/views/dialogs/edit-project-dialog.fxml b/src/main/resources/views/dialogs/edit-project-dialog.fxml new file mode 100644 index 0000000..dde878f --- /dev/null +++ b/src/main/resources/views/dialogs/edit-project-dialog.fxml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + +