Manage block list
This commit is contained in:
@@ -10,6 +10,13 @@ import javafx.scene.layout.Pane;
|
|||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.to.telegramfinalproject.Client.ActionHandler;
|
||||||
|
import org.to.telegramfinalproject.Client.Session;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
public class BlockedUsersController {
|
public class BlockedUsersController {
|
||||||
|
|
||||||
@@ -20,78 +27,148 @@ public class BlockedUsersController {
|
|||||||
@FXML private ListView<HBox> blockedList;
|
@FXML private ListView<HBox> blockedList;
|
||||||
@FXML private VBox blockedCard;
|
@FXML private VBox blockedCard;
|
||||||
|
|
||||||
|
// نگاشت برای حذف سریع ردیف بعد از Unblock
|
||||||
|
private final Map<UUID, HBox> rowByUserId = new HashMap<>();
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
// Back button icon
|
|
||||||
backButton.setGraphic(makeIcon("/org/to/telegramfinalproject/Icons/back_button_dark.png"));
|
backButton.setGraphic(makeIcon("/org/to/telegramfinalproject/Icons/back_button_dark.png"));
|
||||||
|
|
||||||
// Example blocked users (replace with server data)
|
// بارگذاری واقعی از سرور
|
||||||
addBlockedUser("Asal", "@Whales_suicide", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
loadBlockedUsers();
|
||||||
addBlockedUser("Replies", "@replies", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
addBlockedUser("Asal", "@Whales_suicide", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
addBlockedUser("Replies", "@replies", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
addBlockedUser("Asal", "@Whales_suicide", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
addBlockedUser("Replies", "@replies", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
addBlockedUser("Asal", "@Whales_suicide", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
addBlockedUser("Replies", "@replies", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
addBlockedUser("Asal", "@Whales_suicide", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
addBlockedUser("Replies", "@replies", "/org/to/telegramfinalproject/Avatars/default_user_profile.png");
|
|
||||||
|
|
||||||
updateCount();
|
|
||||||
|
|
||||||
closeButton.setOnAction(e -> MainController.getInstance().closeOverlay(overlayBackground.getParent()));
|
closeButton.setOnAction(e -> MainController.getInstance().closeOverlay(overlayBackground.getParent()));
|
||||||
backButton.setOnAction(e -> MainController.getInstance().goBack((StackPane) overlayBackground.getParent()));
|
backButton.setOnAction(e -> MainController.getInstance().goBack((StackPane) overlayBackground.getParent()));
|
||||||
|
|
||||||
overlayBackground.setOnMouseClicked(e -> MainController.getInstance().closeOverlay(blockedCard.getParent()));
|
overlayBackground.setOnMouseClicked(e -> MainController.getInstance().closeOverlay(blockedCard.getParent()));
|
||||||
|
|
||||||
// Register scene for ThemeManager → stylesheet swap will handle colors/icons
|
// Theme
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (blockedCard.getScene() != null) {
|
if (blockedCard.getScene() != null) {
|
||||||
ThemeManager.getInstance().registerScene(blockedCard.getScene());
|
ThemeManager.getInstance().registerScene(blockedCard.getScene());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ThemeManager.getInstance().darkModeProperty().addListener((obs, oldVal, newVal) -> updateBackIcon(newVal));
|
||||||
// Listener for theme change
|
|
||||||
ThemeManager.getInstance().darkModeProperty().addListener((obs, oldVal, newVal) -> {
|
|
||||||
updateBackIcon(newVal);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set initial state
|
|
||||||
updateBackIcon(ThemeManager.getInstance().isDarkMode());
|
updateBackIcon(ThemeManager.getInstance().isDarkMode());
|
||||||
|
|
||||||
// Add CSS
|
// اسکرول نرم
|
||||||
blockedList.getStylesheets().add(
|
blockedList.getStylesheets().add(
|
||||||
getClass().getResource("/org/to/telegramfinalproject/CSS/scrollpane.css").toExternalForm()
|
getClass().getResource("/org/to/telegramfinalproject/CSS/scrollpane.css").toExternalForm()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Wait until skin is ready
|
|
||||||
blockedList.skinProperty().addListener((obs, oldSkin, newSkin) -> {
|
blockedList.skinProperty().addListener((obs, oldSkin, newSkin) -> {
|
||||||
if (newSkin != null) {
|
if (newSkin != null) {
|
||||||
// Look up vertical scrollbar inside the ListView
|
|
||||||
ScrollBar vBar = (ScrollBar) blockedList.lookup(".scroll-bar:vertical");
|
ScrollBar vBar = (ScrollBar) blockedList.lookup(".scroll-bar:vertical");
|
||||||
if (vBar != null) {
|
if (vBar != null) {
|
||||||
blockedList.setOnScroll(event -> {
|
blockedList.setOnScroll(event -> {
|
||||||
double deltaY = event.getDeltaY() * 0.003; // smaller = smoother
|
double deltaY = event.getDeltaY() * 0.003;
|
||||||
double newValue = vBar.getValue() - deltaY;
|
double newValue = vBar.getValue() - deltaY;
|
||||||
vBar.setValue(Math.max(0, Math.min(newValue, 1))); // clamp between 0–1
|
vBar.setValue(Math.max(0, Math.min(newValue, 1)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addBlockedUser(String name, String id, String avatarPath) {
|
/* ===================== Networking ===================== */
|
||||||
|
|
||||||
|
private void loadBlockedUsers() {
|
||||||
|
// درخواست به سرور
|
||||||
|
new Thread(() -> {
|
||||||
|
JSONObject req = new JSONObject().put("action", "get_blocked_users");
|
||||||
|
JSONObject resp = ActionHandler.sendWithResponse(req);
|
||||||
|
|
||||||
|
if (resp == null || !"success".equalsIgnoreCase(resp.optString("status"))) {
|
||||||
|
System.err.println("get_blocked_users failed: " + (resp != null ? resp.optString("message") : "no response"));
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
blockedList.getItems().clear();
|
||||||
|
updateCount();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject data = resp.optJSONObject("data");
|
||||||
|
JSONArray arr = data != null ? data.optJSONArray("blocked_users") : null;
|
||||||
|
if (arr == null) arr = new JSONArray();
|
||||||
|
|
||||||
|
final JSONArray finalArr = arr;
|
||||||
|
Platform.runLater(() -> renderBlockedUsers(finalArr));
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unblockUser(UUID targetId) {
|
||||||
|
String me = Session.currentUser != null ? Session.currentUser.optString("internal_uuid", "") : "";
|
||||||
|
if (me.isBlank() || targetId == null) return;
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
JSONObject req = new JSONObject()
|
||||||
|
.put("action", "toggle_block")
|
||||||
|
.put("user_id", me) // UUID من
|
||||||
|
.put("target_id", targetId.toString()); // UUID طرف
|
||||||
|
|
||||||
|
JSONObject resp = ActionHandler.sendWithResponse(req);
|
||||||
|
boolean ok = resp != null && "success".equalsIgnoreCase(resp.optString("status"));
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (ok) {
|
||||||
|
HBox row = rowByUserId.remove(targetId);
|
||||||
|
if (row != null) blockedList.getItems().remove(row);
|
||||||
|
updateCount();
|
||||||
|
} else {
|
||||||
|
String msg = (resp != null ? resp.optString("message", "Failed to unblock.") : "Failed to unblock.");
|
||||||
|
showToast(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===================== UI build ===================== */
|
||||||
|
|
||||||
|
private void renderBlockedUsers(JSONArray list) {
|
||||||
|
blockedList.getItems().clear();
|
||||||
|
rowByUserId.clear();
|
||||||
|
|
||||||
|
// انتظار میره هر آبجکت حداقل: internal_uuid, profile_name, user_id/username/display_id, image_url داشته باشه
|
||||||
|
IntStream.range(0, list.length()).forEach(i -> {
|
||||||
|
JSONObject o = list.optJSONObject(i);
|
||||||
|
if (o == null) return;
|
||||||
|
|
||||||
|
UUID uid = parseUUID(optS(o, "internal_uuid"));
|
||||||
|
if (uid == null) return;
|
||||||
|
|
||||||
|
String name = nz(optS(o, "profile_name", optS(o, "name", "User")));
|
||||||
|
String handle = firstNonEmpty(
|
||||||
|
optS(o, "username"),
|
||||||
|
optS(o, "display_id"),
|
||||||
|
optS(o, "user_name"),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
String avatarUrl = optS(o, "image_url");
|
||||||
|
|
||||||
|
HBox row = buildRow(uid, name, handle, avatarUrl);
|
||||||
|
rowByUserId.put(uid, row);
|
||||||
|
blockedList.getItems().add(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
updateCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HBox buildRow(UUID uid, String name, String id, String avatarUrl) {
|
||||||
// Avatar
|
// Avatar
|
||||||
ImageView avatar = new ImageView(new Image(getClass().getResourceAsStream(avatarPath)));
|
Image img = null;
|
||||||
|
if (hasVal(avatarUrl)) {
|
||||||
|
try { img = org.to.telegramfinalproject.Client.AvatarLocalResolver.load(avatarUrl); } catch (Exception ignore) {}
|
||||||
|
}
|
||||||
|
if (img == null) {
|
||||||
|
img = new Image(getClass().getResourceAsStream("/org/to/telegramfinalproject/Avatars/default_user_profile.png"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageView avatar = new ImageView(img);
|
||||||
avatar.setFitWidth(60);
|
avatar.setFitWidth(60);
|
||||||
avatar.setFitHeight(60);
|
avatar.setFitHeight(60);
|
||||||
avatar.setPreserveRatio(true);
|
avatar.setPreserveRatio(true);
|
||||||
avatar.setSmooth(true);
|
avatar.setSmooth(true);
|
||||||
avatar.setCache(true);
|
avatar.setCache(true);
|
||||||
|
avatar.setClip(new Circle(20, 20, 40));
|
||||||
// round mask
|
|
||||||
Circle clip = new Circle(20, 20, 40); // x, y, radius (same as half of fit size)
|
|
||||||
avatar.setClip(clip);
|
|
||||||
|
|
||||||
// Name + ID
|
// Name + ID
|
||||||
VBox info = new VBox(2);
|
VBox info = new VBox(2);
|
||||||
@@ -101,27 +178,23 @@ public class BlockedUsersController {
|
|||||||
idLabel.getStyleClass().add("blocked-id");
|
idLabel.getStyleClass().add("blocked-id");
|
||||||
info.getChildren().addAll(nameLabel, idLabel);
|
info.getChildren().addAll(nameLabel, idLabel);
|
||||||
|
|
||||||
// Unblock button
|
// Unblock btn
|
||||||
Button unblockBtn = new Button("Unblock");
|
Button unblockBtn = new Button("Unblock");
|
||||||
unblockBtn.getStyleClass().add("unblock-button");
|
unblockBtn.getStyleClass().add("unblock-button");
|
||||||
unblockBtn.setOnAction(e -> {
|
unblockBtn.setOnAction(e -> unblockUser(uid));
|
||||||
blockedList.getItems().removeIf(h -> h.getChildren().contains(avatar));
|
|
||||||
updateCount();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Row
|
HBox row = new HBox(12, avatar, info, unblockBtn);
|
||||||
HBox row = new HBox(10, avatar, info, unblockBtn);
|
|
||||||
row.setSpacing(12);
|
|
||||||
row.getStyleClass().add("blocked-row");
|
row.getStyleClass().add("blocked-row");
|
||||||
HBox.setHgrow(info, javafx.scene.layout.Priority.ALWAYS);
|
HBox.setHgrow(info, javafx.scene.layout.Priority.ALWAYS);
|
||||||
|
return row;
|
||||||
blockedList.getItems().add(row);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCount() {
|
private void updateCount() {
|
||||||
countLabel.setText(blockedList.getItems().size() + " blocked users");
|
countLabel.setText(blockedList.getItems().size() + " blocked users");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===================== Helpers ===================== */
|
||||||
|
|
||||||
private void updateBackIcon(boolean darkMode) {
|
private void updateBackIcon(boolean darkMode) {
|
||||||
String iconPath = darkMode
|
String iconPath = darkMode
|
||||||
? "/org/to/telegramfinalproject/Icons/back_button_light.png"
|
? "/org/to/telegramfinalproject/Icons/back_button_light.png"
|
||||||
@@ -139,4 +212,28 @@ public class BlockedUsersController {
|
|||||||
iv.setFitHeight(20);
|
iv.setFitHeight(20);
|
||||||
return iv;
|
return iv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String nz(String s){ return s==null? "": s.trim(); }
|
||||||
|
private static boolean hasVal(String s){ return s!=null && !s.trim().isEmpty() && !"null".equalsIgnoreCase(s); }
|
||||||
|
private static String optS(JSONObject j, String k){ return j!=null ? nz(j.optString(k,"")) : ""; }
|
||||||
|
private static String optS(JSONObject j, String k, String fallback){
|
||||||
|
String v = optS(j,k);
|
||||||
|
return hasVal(v) ? v : fallback;
|
||||||
|
}
|
||||||
|
private static String firstNonEmpty(String... vals){
|
||||||
|
for (String v : vals) if (hasVal(v)) return v;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
private static UUID parseUUID(String s){
|
||||||
|
try { return UUID.fromString(nz(s)); } catch (Exception e) { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showToast(String msg) {
|
||||||
|
// ساده: از Alert استفاده کن؛ اگر Toast اختصاصی داری جایگزینش کن
|
||||||
|
Alert a = new Alert(Alert.AlertType.INFORMATION, msg, ButtonType.OK);
|
||||||
|
if (a.getDialogPane().getScene() != null) {
|
||||||
|
ThemeManager.getInstance().registerScene(a.getDialogPane().getScene());
|
||||||
|
}
|
||||||
|
a.showAndWait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2045,23 +2045,20 @@ private void addBubble(
|
|||||||
UUID other = currentChat.getOtherUserId();
|
UUID other = currentChat.getOtherUserId();
|
||||||
if (other == null && currentChat.getDisplayId() == null) return;
|
if (other == null && currentChat.getDisplayId() == null) return;
|
||||||
|
|
||||||
// ⚠️ با API خودت هماهنگ کن:
|
|
||||||
// این یک الگوی معمول است: user_id (کاربر فعلی) + contact_id (کسی که بلاک شده)
|
|
||||||
org.json.JSONObject req = new org.json.JSONObject()
|
org.json.JSONObject req = new org.json.JSONObject()
|
||||||
.put("action", "unblock_user") // یا "unblock_contact" طبق سرور
|
.put("action", "toggle_block")
|
||||||
.put("user_id", org.to.telegramfinalproject.Client.Session.currentUser.getString("user_id"))
|
.put("user_id", org.to.telegramfinalproject.Client.Session.currentUser.getString("user_id"))
|
||||||
.put("contact_id", (other != null) ? other.toString() : currentChat.getDisplayId());
|
.put("target_id", (other != null) ? other.toString() : currentChat.getDisplayId());
|
||||||
|
|
||||||
org.json.JSONObject res = org.to.telegramfinalproject.Client.ActionHandler.sendWithResponse(req);
|
org.json.JSONObject res = org.to.telegramfinalproject.Client.ActionHandler.sendWithResponse(req);
|
||||||
boolean ok = (res != null) && ("ok".equalsIgnoreCase(res.optString("status"))
|
boolean ok = (res != null) && ("ok".equalsIgnoreCase(res.optString("status"))
|
||||||
|| "success".equalsIgnoreCase(res.optString("status")));
|
|| "success".equalsIgnoreCase(res.optString("status")));
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
// برگرد به حالت نرمال: کامپوزر باز شود
|
|
||||||
applyMode(ChatViewMode.NORMAL);
|
applyMode(ChatViewMode.NORMAL);
|
||||||
Platform.runLater(() -> messageInput.requestFocus());
|
Platform.runLater(() -> messageInput.requestFocus());
|
||||||
} else {
|
} else {
|
||||||
// میتونی یک نوتیف کوچک بزنی
|
|
||||||
addSystemMessage("Unblock failed.");
|
addSystemMessage("Unblock failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user