From 3d401385ae2f93f4c2b86a2a1d7d61e091ac1dfb Mon Sep 17 00:00:00 2001 From: Asal Lotfi Date: Mon, 8 Sep 2025 09:06:26 +0330 Subject: [PATCH] Manage Administrator UI + backend implemented. --- .../Database/GroupDatabase.java | 23 ++ .../Server/ClientHandler.java | 32 +++ .../UI/AddAdminsController.java | 125 ++++++++++ .../UI/ManageAdminsController.java | 228 ++++++++++++++++++ .../UI/ManageGroupController.java | 32 ++- .../SetGroupAdminPermissionsController.java | 148 ++++++++++++ .../telegramfinalproject/CSS/dark_theme.css | 48 +++- .../telegramfinalproject/CSS/light_theme.css | 48 +++- .../telegramfinalproject/Fxml/add_admins.fxml | 48 ++++ .../Fxml/manage_admins.fxml | 43 ++++ .../Fxml/set_group_admin_permissions.fxml | 46 ++++ 11 files changed, 812 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/to/telegramfinalproject/UI/AddAdminsController.java create mode 100644 src/main/java/org/to/telegramfinalproject/UI/ManageAdminsController.java create mode 100644 src/main/java/org/to/telegramfinalproject/UI/SetGroupAdminPermissionsController.java create mode 100644 src/main/resources/org/to/telegramfinalproject/Fxml/add_admins.fxml create mode 100644 src/main/resources/org/to/telegramfinalproject/Fxml/manage_admins.fxml create mode 100644 src/main/resources/org/to/telegramfinalproject/Fxml/set_group_admin_permissions.fxml diff --git a/src/main/java/org/to/telegramfinalproject/Database/GroupDatabase.java b/src/main/java/org/to/telegramfinalproject/Database/GroupDatabase.java index 259fe86..e8eecaa 100644 --- a/src/main/java/org/to/telegramfinalproject/Database/GroupDatabase.java +++ b/src/main/java/org/to/telegramfinalproject/Database/GroupDatabase.java @@ -758,4 +758,27 @@ public class GroupDatabase { return result; } + public static JSONObject getAdminPermissions(UUID groupId, UUID adminId) throws SQLException { + String sql = """ + SELECT permissions + FROM group_members + WHERE group_id = ? AND user_id = ? AND role = 'admin' + """; + + try (Connection conn = ConnectionDb.connect(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setObject(1, groupId); + ps.setObject(2, adminId); + + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + String jsonStr = rs.getString("permissions"); + if (jsonStr != null && !jsonStr.isBlank()) { + return new JSONObject(jsonStr); + } + } + } + return null; // not found or no permissions + } + } \ No newline at end of file diff --git a/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java b/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java index a3c63fe..d40f564 100644 --- a/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java +++ b/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java @@ -3029,6 +3029,38 @@ public class ClientHandler implements Runnable { break; } + case "get_group_admin_permissions": { + if (currentUser == null) { + response = new ResponseModel("error", "Unauthorized. Please login first."); + break; + } + + try { + UUID groupId = UUID.fromString(requestJson.getString("group_id")); + UUID adminId = UUID.fromString(requestJson.getString("admin_id")); + + // Only owner/admins can view + String myRole = GroupDatabase.getGroupRole(groupId, currentUser.getInternal_uuid()); + if (!"owner".equalsIgnoreCase(myRole) && !"admin".equalsIgnoreCase(myRole)) { + response = new ResponseModel("error", "You are not authorized to view admin permissions."); + break; + } + + JSONObject perms = GroupDatabase.getAdminPermissions(groupId, adminId); + + if (perms != null) { + JSONObject data = new JSONObject().put("permissions", perms); + response = new ResponseModel("success", "Permissions fetched successfully.", data); + } else { + response = new ResponseModel("error", "Admin permissions not found."); + } + + } catch (Exception e) { + response = new ResponseModel("error", "Error fetching admin permissions: " + e.getMessage()); + } + break; + } + default: response = new ResponseModel("error", "Unknown action: " + action); diff --git a/src/main/java/org/to/telegramfinalproject/UI/AddAdminsController.java b/src/main/java/org/to/telegramfinalproject/UI/AddAdminsController.java new file mode 100644 index 0000000..027da9e --- /dev/null +++ b/src/main/java/org/to/telegramfinalproject/UI/AddAdminsController.java @@ -0,0 +1,125 @@ +package org.to.telegramfinalproject.UI; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.*; +import org.json.JSONArray; +import org.json.JSONObject; +import org.to.telegramfinalproject.Client.ActionHandler; +import org.to.telegramfinalproject.Client.AvatarLocalResolver; + +import java.io.IOException; +import java.util.UUID; + +public class AddAdminsController { + + @FXML private VBox addAdminsCard; + @FXML private Pane overlayBackground; + @FXML private Button closeButton; + @FXML private Button closeFooterButton; + @FXML private ScrollPane membersScroll; + @FXML private VBox membersList; + + private String groupId; + + @FXML + private void initialize() { + closeButton.setOnAction(e -> MainController.getInstance().closeOverlay(addAdminsCard.getParent())); + closeFooterButton.setOnAction(e -> MainController.getInstance().closeOverlay(addAdminsCard.getParent())); + overlayBackground.setOnMouseClicked(e -> MainController.getInstance().closeOverlay(addAdminsCard.getParent())); + + // Smooth scroll feel + membersScroll.getStylesheets().add(getClass().getResource("/org/to/telegramfinalproject/CSS/scrollpane.css").toExternalForm()); + membersScroll.setPannable(true); + membersScroll.setFitToWidth(true); + membersScroll.setFitToHeight(false); + membersScroll.getContent().setOnScroll(event -> { + double deltaY = event.getDeltaY() * 0.003; + membersScroll.setVvalue(membersScroll.getVvalue() - deltaY); + }); + } + + public void setGroupData(String groupId, JSONArray members) { + this.groupId = groupId; + membersList.getChildren().clear(); + + for (int i = 0; i < members.length(); i++) { + JSONObject m = members.getJSONObject(i); + + String role = m.optString("role", "member"); + if ("owner".equalsIgnoreCase(role) || "admin".equalsIgnoreCase(role)) { + continue; // skip existing admins/owner + } + + addMemberRow(m); + } + } + + private void addMemberRow(JSONObject m) { + HBox row = new HBox(10); + row.getStyleClass().add("member-row"); + row.setAlignment(Pos.CENTER_LEFT); + + // Avatar + ImageView avatar = new ImageView(); + avatar.setFitWidth(36); + avatar.setFitHeight(36); + avatar.setPreserveRatio(true); + + String imgUrl = m.optString("image_url", ""); + if (!imgUrl.isBlank()) { + Image img = AvatarLocalResolver.load(imgUrl); + if (img != null) avatar.setImage(img); + } else { + avatar.setImage(new Image(getClass().getResourceAsStream( + "/org/to/telegramfinalproject/Avatars/default_user_profile.png" + ))); + } + + // Name + Status + VBox details = new VBox(2); + Label name = new Label(m.optString("profile_name", "Unknown")); + name.getStyleClass().add("member-name"); + + Label status = new Label(m.optBoolean("is_online", false) ? "online" : "last seen recently"); + status.getStyleClass().add("member-status"); + + details.getChildren().addAll(name, status); + + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + + Button promoteBtn = new Button("Promote"); + promoteBtn.getStyleClass().add("link-btn"); + promoteBtn.setOnAction(e -> promoteToAdmin(m.optString("internal_uuid"), row)); + + row.getChildren().addAll(avatar, details, spacer, promoteBtn); + membersList.getChildren().add(row); + } + + private void promoteToAdmin(String internalUuid, HBox row) { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource( + "/org/to/telegramfinalproject/Fxml/set_group_admin_permissions.fxml")); + Node overlay = loader.load(); + + SetGroupAdminPermissionsController controller = loader.getController(); + controller.setTarget(UUID.fromString(groupId), UUID.fromString(internalUuid), false); + + // Pass a callback to remove row if promotion succeeds + controller.setOnSuccess(() -> membersList.getChildren().remove(row)); + + MainController.getInstance().showOverlay(overlay); + } catch (IOException e) { + e.printStackTrace(); + MainController.getInstance().showAlert( + "Error", "Could not load permissions scene.", Alert.AlertType.ERROR + ); + } + } +} diff --git a/src/main/java/org/to/telegramfinalproject/UI/ManageAdminsController.java b/src/main/java/org/to/telegramfinalproject/UI/ManageAdminsController.java new file mode 100644 index 0000000..f0de29e --- /dev/null +++ b/src/main/java/org/to/telegramfinalproject/UI/ManageAdminsController.java @@ -0,0 +1,228 @@ +package org.to.telegramfinalproject.UI; + +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.*; +import org.json.JSONArray; +import org.json.JSONObject; +import org.to.telegramfinalproject.Client.ActionHandler; +import org.to.telegramfinalproject.Client.AvatarLocalResolver; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class ManageAdminsController { + + @FXML private VBox adminsCard; + @FXML private Pane overlayBackground; + @FXML private Button closeButton; + @FXML private Button closeFooterButton; + @FXML private Button addAdminButton; + + @FXML private ScrollPane adminsScroll; + @FXML private VBox adminsList; + + private String groupId; + + @FXML + private void initialize() { + closeButton.setOnAction(e -> MainController.getInstance().closeOverlay(adminsCard.getParent())); + closeFooterButton.setOnAction(e -> MainController.getInstance().closeOverlay(adminsCard.getParent())); + overlayBackground.setOnMouseClicked(e -> MainController.getInstance().closeOverlay(adminsCard.getParent())); + + addAdminButton.setOnAction(e -> openAddAdminOverlay()); + + // Smooth scroll feel + adminsScroll.getStylesheets().add(getClass().getResource("/org/to/telegramfinalproject/CSS/scrollpane.css").toExternalForm()); + adminsScroll.setPannable(true); + adminsScroll.setFitToWidth(true); + adminsScroll.setFitToHeight(false); + adminsScroll.getContent().setOnScroll(event -> { + double deltaY = event.getDeltaY() * 0.003; + adminsScroll.setVvalue(adminsScroll.getVvalue() - deltaY); + }); + } + + public void setGroupData(String groupId, JSONArray admins) { + this.groupId = groupId; + + adminsList.getChildren().clear(); + + // Convert to list for sorting + List adminList = new ArrayList<>(); + for (int i = 0; i < admins.length(); i++) { + adminList.add(admins.getJSONObject(i)); + } + + // Sort: owner first, then admins + adminList.sort((a, b) -> { + String roleA = a.optString("role", "member"); + String roleB = b.optString("role", "member"); + if ("owner".equalsIgnoreCase(roleA) && !"owner".equalsIgnoreCase(roleB)) return -1; + if ("owner".equalsIgnoreCase(roleB) && !"owner".equalsIgnoreCase(roleA)) return 1; + return 0; // keep relative order for admins + }); + + // Add rows + for (JSONObject a : adminList) { + addAdminRow(a); + } + } + + private void addAdminRow(JSONObject a) { + HBox row = new HBox(10); + row.getStyleClass().add("member-row"); + row.setAlignment(Pos.CENTER_LEFT); + + // Avatar + ImageView avatar = new ImageView(); + avatar.setFitWidth(36); + avatar.setFitHeight(36); + avatar.setPreserveRatio(true); + + String imgUrl = a.optString("image_url", ""); + if (!imgUrl.isBlank()) { + Image img = AvatarLocalResolver.load(imgUrl); + if (img != null) avatar.setImage(img); + } else { + avatar.setImage(new Image(getClass().getResourceAsStream( + "/org/to/telegramfinalproject/Avatars/default_user_profile.png" + ))); + } + + // Name + Status + VBox details = new VBox(2); + Label name = new Label(a.optString("profile_name", "Unknown")); + name.getStyleClass().add("member-name"); + + Label status = new Label( + a.optBoolean("is_online", false) ? "online" + : "last seen recently" + ); + status.getStyleClass().add("member-status"); + + details.getChildren().addAll(name, status); + + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + + row.getChildren().addAll(avatar, details, spacer); + + // Remove admin (cannot remove owner) + String role = a.optString("role", "admin"); + if (!"owner".equalsIgnoreCase(role)) { + Button removeBtn = new Button("Remove"); + removeBtn.getStyleClass().add("link-btn"); + removeBtn.setOnAction(e -> removeAdmin(a.optString("user_id"), row)); + row.getChildren().add(removeBtn); + } + + adminsList.getChildren().add(row); + + // User clicks on a admin --> open set admin permission's scene + row.setOnMouseClicked(e -> { + if (!"owner".equalsIgnoreCase(role)) { + try { + // request current permissions from server + JSONObject req = new JSONObject() + .put("action", "get_group_admin_permissions") + .put("group_id", groupId) + .put("admin_id", a.optString("user_id")); + + JSONObject resp = ActionHandler.sendWithResponse(req); + JSONObject oldPerms = (resp != null) ? resp.optJSONObject("permissions") : null; + + FXMLLoader loader = new FXMLLoader(getClass().getResource( + "/org/to/telegramfinalproject/Fxml/set_group_admin_permissions.fxml")); + Node overlay = loader.load(); + + SetGroupAdminPermissionsController controller = loader.getController(); + controller.setTarget( + UUID.fromString(groupId), + UUID.fromString(a.optString("user_id")), + true, + oldPerms + ); + + MainController.getInstance().showOverlay(overlay); + } catch (IOException ex) { + ex.printStackTrace(); + MainController.getInstance().showAlert("Error", "Could not open permissions scene.", Alert.AlertType.ERROR); + } + } + }); + } + + private void removeAdmin(String userId, HBox row) { + JSONObject req = new JSONObject() + .put("action", "remove_admin_from_group") + .put("group_id", groupId) + .put("target_user_id", userId); + + System.out.println("Sending remove_admin_from_group request: " + req.toString(2)); + + row.setDisable(true); + + new Thread(() -> { + JSONObject resp = ActionHandler.sendWithResponse(req); + if (resp != null && "success".equalsIgnoreCase(resp.optString("status"))) { + Platform.runLater(() -> adminsList.getChildren().remove(row)); + } else { + Platform.runLater(() -> { + row.setDisable(false); + Alert a = new Alert(Alert.AlertType.ERROR, + resp != null ? resp.optString("message", "Failed to remove admin.") : "No response from server.", + ButtonType.OK); + a.show(); + }); + } + }).start(); + } + + private void openAddAdminOverlay() { + try { + // === Query the server for full members list === + JSONObject req = new JSONObject() + .put("action", "view_group_members") + .put("group_id", groupId); + + JSONObject resp = ActionHandler.sendWithResponse(req); + + if (resp == null || !"success".equalsIgnoreCase(resp.optString("status"))) { + MainController.getInstance().showAlert( + "Error", + "Could not fetch members.", + Alert.AlertType.ERROR + ); + return; + } + + JSONObject data = resp.optJSONObject("data"); + JSONArray members = (data != null) ? data.optJSONArray("members") : new JSONArray(); + + // === Load Add Admins FXML === + FXMLLoader loader = new FXMLLoader(getClass().getResource( + "/org/to/telegramfinalproject/Fxml/add_admins.fxml")); + Node overlay = loader.load(); + + AddAdminsController controller = loader.getController(); + controller.setGroupData(groupId, members); // send raw members, filtering is done in AddAdminsController + + MainController.getInstance().showOverlay(overlay); + + } catch (IOException e) { + e.printStackTrace(); + MainController.getInstance().showAlert( + "Error", "Could not load Add Admins scene.", Alert.AlertType.ERROR + ); + } + } +} diff --git a/src/main/java/org/to/telegramfinalproject/UI/ManageGroupController.java b/src/main/java/org/to/telegramfinalproject/UI/ManageGroupController.java index daf2ea1..78490c4 100644 --- a/src/main/java/org/to/telegramfinalproject/UI/ManageGroupController.java +++ b/src/main/java/org/to/telegramfinalproject/UI/ManageGroupController.java @@ -8,12 +8,14 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.*; import javafx.stage.FileChooser; +import org.json.JSONArray; import org.json.JSONObject; import org.to.telegramfinalproject.Client.ActionHandler; import java.io.File; import java.io.IOException; import java.util.Objects; +import java.util.UUID; public class ManageGroupController { @@ -44,18 +46,34 @@ public class ManageGroupController { changePicButton.setOnAction(e -> choosePicture()); saveButton.setOnAction(e -> saveChanges()); - manageAdminsButton.setOnAction(e -> openManageAdminsScene()); + manageAdminsButton.setOnAction(e -> openManageAdminsScene(data)); manageMembersButton.setOnAction(e -> openManageMembersScene(data)); } - private void openManageAdminsScene() { + private void openManageAdminsScene(JSONObject data) { try { FXMLLoader loader = new FXMLLoader(getClass().getResource( "/org/to/telegramfinalproject/Fxml/manage_admins.fxml")); Node overlay = loader.load(); -// ManageAdminsController controller = loader.getController(); -// controller.setGroupId(UUID.fromString(groupId)); + ManageAdminsController controller = loader.getController(); + + String gid = data.optString("internal_uuid"); + JSONArray members = data.optJSONArray("members"); + JSONArray admins = new JSONArray(); + + // filter only admins + if (members != null) { + for (int i = 0; i < members.length(); i++) { + JSONObject m = members.getJSONObject(i); + String role = m.optString("role", "member"); + if ("admin".equalsIgnoreCase(role) || "owner".equalsIgnoreCase(role)) { + admins.put(m); + } + } + } + + controller.setGroupData(gid, admins); MainController.getInstance().showOverlay(overlay); } catch (IOException e) { @@ -101,8 +119,8 @@ public class ManageGroupController { groupImage.setImage(new Image(originalImageUrl, true)); } - adminCount.setText(String.valueOf(countRole(data, "admin"))); - memberCount.setText(String.valueOf(countRole(data, "member"))); + adminCount.setText(String.valueOf(countRole(data, "admin") + 1)); + memberCount.setText(String.valueOf(countRole(data, "member") + Integer.parseInt(adminCount.getText()))); } private int countRole(JSONObject groupData, String role) { @@ -112,7 +130,7 @@ public class ManageGroupController { for (int i = 0; i < arr.length(); i++) { if (role.equalsIgnoreCase(arr.getJSONObject(i).optString("role"))) count++; } - return count + 1; + return count; } private void choosePicture() { diff --git a/src/main/java/org/to/telegramfinalproject/UI/SetGroupAdminPermissionsController.java b/src/main/java/org/to/telegramfinalproject/UI/SetGroupAdminPermissionsController.java new file mode 100644 index 0000000..3f1aba9 --- /dev/null +++ b/src/main/java/org/to/telegramfinalproject/UI/SetGroupAdminPermissionsController.java @@ -0,0 +1,148 @@ +package org.to.telegramfinalproject.UI; + +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.scene.control.*; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; +import org.json.JSONObject; +import org.to.telegramfinalproject.Client.ActionHandler; + +import java.util.UUID; + +public class SetGroupAdminPermissionsController { + + @FXML private VBox permissionsCard; + @FXML private Pane overlayBackground; + @FXML private Button closeButton; + @FXML private Button cancelButton; + @FXML private Button saveButton; + + @FXML private CheckBox canAddMember; + @FXML private CheckBox canRemoveMember; + @FXML private CheckBox canAddAdmin; + @FXML private CheckBox canRemoveAdmin; + @FXML private CheckBox canEditGroup; + + private UUID groupId; + private UUID userId; + private Runnable onSuccess; + + private JSONObject oldPermissions; // store existing permissions + private boolean isEditMode = false; // true if editing existing admin + + public void setTarget(UUID groupId, UUID userId, boolean isEditMode) { + this.groupId = groupId; + this.userId = userId; + this.isEditMode = isEditMode; + + if (isEditMode) { + loadCurrentPermissions(); + } + } + + public void setTarget(UUID groupId, UUID userId, boolean isEditMode, JSONObject oldPermissions) { + this.groupId = groupId; + this.userId = userId; + this.isEditMode = isEditMode; + this.oldPermissions = oldPermissions; + } + + public void setOnSuccess(Runnable r) { + this.onSuccess = r; + } + + @FXML + private void initialize() { + closeButton.setOnAction(e -> MainController.getInstance().closeOverlay(permissionsCard.getParent())); + cancelButton.setOnAction(e -> MainController.getInstance().closeOverlay(permissionsCard.getParent())); + overlayBackground.setOnMouseClicked(e -> MainController.getInstance().closeOverlay(permissionsCard.getParent())); + + saveButton.setOnAction(e -> savePermissions()); + + // Register for dark mode updates + Platform.runLater(() -> { + if (permissionsCard.getScene() != null) { + ThemeManager.getInstance().registerScene(permissionsCard.getScene()); + } + }); + } + + private void loadCurrentPermissions() { + JSONObject req = new JSONObject() + .put("action", "get_group_admin_permissions") + .put("group_id", groupId.toString()) + .put("admin_id", userId.toString()); + + JSONObject resp = ActionHandler.sendWithResponse(req); + System.out.println("Permissions response: " + resp); // full server response + + if (resp != null && "success".equalsIgnoreCase(resp.optString("status"))) { + // "data" is an object containing { "permissions": { ... } } + JSONObject data = resp.optJSONObject("data"); + System.out.println("Data object: " + data); + + if (data != null) { + JSONObject perms = data.optJSONObject("permissions"); + System.out.println("Extracted permissions object: " + perms); + + if (perms != null) { + oldPermissions = perms; + + // Update checkboxes safely on FX thread + Platform.runLater(() -> { + canAddMember.setSelected(perms.optBoolean("can_add_member", false)); + canRemoveMember.setSelected(perms.optBoolean("can_remove_member", false)); + canAddAdmin.setSelected(perms.optBoolean("can_add_admin", false)); + canRemoveAdmin.setSelected(perms.optBoolean("can_remove_admin", false)); + canEditGroup.setSelected(perms.optBoolean("can_edit_group", false)); + }); + } else { + System.out.println("⚠️ Permissions object was null inside data."); + } + } else { + System.out.println("⚠️ Data object was null in response."); + } + } else { + System.out.println("⚠️ Response was null or status != success"); + } + } + + private void savePermissions() { + JSONObject newPermissions = new JSONObject() + .put("can_add_member", canAddMember.isSelected()) + .put("can_remove_member", canRemoveMember.isSelected()) + .put("can_add_admin", canAddAdmin.isSelected()) + .put("can_remove_admin", canRemoveAdmin.isSelected()) + .put("can_edit_group", canEditGroup.isSelected()); + + JSONObject req; + if (isEditMode) { + // --- Editing existing admin permissions --- + req = new JSONObject() + .put("action", "edit_admin_permissions") + .put("chat_id", groupId.toString()) + .put("chat_type", "group") // since this controller is only for groups + .put("admin_id", userId.toString()) + .put("permissions", newPermissions); + } else { + // --- Adding a new admin --- + req = new JSONObject() + .put("action", "add_admin_to_group") + .put("group_id", groupId.toString()) + .put("user_id", userId.toString()) + .put("permissions", newPermissions); + } + + JSONObject resp = ActionHandler.sendWithResponse(req); + if (resp != null && "success".equalsIgnoreCase(resp.optString("status"))) { + MainController.getInstance().closeOverlay(permissionsCard.getParent()); + if (onSuccess != null) onSuccess.run(); // update UI after success + } else { + Alert a = new Alert(Alert.AlertType.ERROR, + resp != null ? resp.optString("message") : "Failed to save admin permissions.", + ButtonType.OK); + a.show(); + } + } +} diff --git a/src/main/resources/org/to/telegramfinalproject/CSS/dark_theme.css b/src/main/resources/org/to/telegramfinalproject/CSS/dark_theme.css index a1fa9df..bacf34a 100644 --- a/src/main/resources/org/to/telegramfinalproject/CSS/dark_theme.css +++ b/src/main/resources/org/to/telegramfinalproject/CSS/dark_theme.css @@ -1337,7 +1337,7 @@ -fx-text-fill: #ffffff; -fx-padding: 4 0 2 0; -fx-border-color: #333; - -fx-border-width: 0 0 1 0; + -fx-border-width: 0 0 0 0; } .tf-item-title { @@ -1364,3 +1364,49 @@ -fx-text-fill: #ffb74d; -fx-background-color: #e65100; } + +/* Permissions card checkboxes */ +.check-box { + -fx-font-size: 13px; + -fx-text-fill: -fx-text-base-color; +} + +/* === Permissions overlay === */ +.permissions-card { + -fx-background-color: #1f1f1f; + -fx-background-radius: 12; + -fx-padding: 16; +} + +/* Checkboxes */ +.permissions-card .check-box { + -fx-text-fill: #e0e0e0; +} + +.permissions-card .check-box:selected .box { + -fx-background-color: #3390ec; + -fx-border-color: #3390ec; +} + +.permissions-card .check-box .box { + -fx-background-color: #2c2c2c; + -fx-border-color: #555; + -fx-border-radius: 4; +} + +/* Buttons */ +.permissions-card .button { + -fx-font-size: 13px; + -fx-background-radius: 6; +} + +.permissions-card .button.primary-btn { + -fx-background-color: #3390ec; + -fx-text-fill: white; +} + +.permissions-card .button.secondary-btn { + -fx-background-color: transparent; + -fx-border-color: #555; + -fx-text-fill: #aaa; +} diff --git a/src/main/resources/org/to/telegramfinalproject/CSS/light_theme.css b/src/main/resources/org/to/telegramfinalproject/CSS/light_theme.css index fe18596..31456ff 100644 --- a/src/main/resources/org/to/telegramfinalproject/CSS/light_theme.css +++ b/src/main/resources/org/to/telegramfinalproject/CSS/light_theme.css @@ -1315,7 +1315,7 @@ -fx-text-fill: #2c2c2c; -fx-padding: 4 0 2 0; -fx-border-color: #ddd; - -fx-border-width: 0 0 1 0; + -fx-border-width: 0 0 0 0; } .tf-item-title { @@ -1341,3 +1341,49 @@ -fx-text-fill: #e65100; -fx-background-color: #fff3e0; } + +/* Permissions card checkboxes */ +.check-box { + -fx-font-size: 13px; + -fx-text-fill: -fx-text-base-color; +} + +/* === Permissions overlay === */ +.permissions-card { + -fx-background-color: white; + -fx-background-radius: 12; + -fx-padding: 16; +} + +/* Checkboxes */ +.permissions-card .check-box { + -fx-text-fill: #222; +} + +.permissions-card .check-box:selected .box { + -fx-background-color: #3390ec; /* blue tick */ + -fx-border-color: #3390ec; +} + +.permissions-card .check-box .box { + -fx-background-color: white; + -fx-border-color: #ccc; + -fx-border-radius: 4; +} + +/* Buttons */ +.permissions-card .button { + -fx-font-size: 13px; + -fx-background-radius: 6; +} + +.permissions-card .button.primary-btn { + -fx-background-color: #3390ec; + -fx-text-fill: white; +} + +.permissions-card .button.secondary-btn { + -fx-background-color: transparent; + -fx-border-color: #ccc; + -fx-text-fill: #222; +} diff --git a/src/main/resources/org/to/telegramfinalproject/Fxml/add_admins.fxml b/src/main/resources/org/to/telegramfinalproject/Fxml/add_admins.fxml new file mode 100644 index 0000000..c7db2bf --- /dev/null +++ b/src/main/resources/org/to/telegramfinalproject/Fxml/add_admins.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + +