Archived chats

This commit is contained in:
2025-09-06 00:45:24 +03:30
parent 58d80cd11d
commit f79eeb2086
3 changed files with 207 additions and 27 deletions
@@ -172,4 +172,40 @@ public class Session {
return entry; return entry;
} }
public static boolean inArchivedView = false;
public static boolean isArchived(UUID chatId) {
if (archivedChats == null) return false;
for (ChatEntry e : archivedChats) if (e.getId().equals(chatId)) return true;
return false;
}
public static void moveToArchived(ChatEntry e) {
if (e == null) return;
if (chatList != null) chatList.removeIf(x -> x.getId().equals(e.getId()));
if (activeChats != null) activeChats.removeIf(x -> x.getId().equals(e.getId()));
if (archivedChats != null) archivedChats.removeIf(x -> x.getId().equals(e.getId()));
if (archivedChats != null) archivedChats.add(e);
}
public static void moveToActive(ChatEntry e) {
if (e == null) return;
if (archivedChats != null) archivedChats.removeIf(x -> x.getId().equals(e.getId()));
if (activeChats != null) activeChats.removeIf(x -> x.getId().equals(e.getId()));
if (chatList != null) chatList.removeIf(x -> x.getId().equals(e.getId()));
if (activeChats != null) activeChats.add(e);
}
// مرتب‌سازی بر اساس آخرین پیام (در صورت داشتن فیلد)
public static void sortListsByLastMessage() {
java.util.Comparator<ChatEntry> cmp =
java.util.Comparator.comparing(ChatEntry::getLastMessageTime, java.util.Comparator.nullsLast(java.util.Comparator.naturalOrder()))
.reversed();
if (activeChats != null) activeChats.sort(cmp);
if (archivedChats != null) archivedChats.sort(cmp);
}
} }
@@ -294,14 +294,9 @@ public class ChatPageController {
if (archiveItem != null) { if (archiveItem != null) {
archiveItem.setOnAction(e -> { archiveItem.setOnAction(e -> {
System.out.println("Toggling archive for chat " + chatName); ChatEntry entry = Session.currentChatEntry;
// TODO: backend call → toggleArchive(chatId, type) if (entry == null) return;
// Also update text: "Archive chat" ↔ "Unarchive chat" toggleArchive(entry);
if ("Archive chat".equals(archiveItem.getText())) {
archiveItem.setText("Unarchive chat");
} else {
archiveItem.setText("Archive chat");
}
}); });
} }
@@ -1161,17 +1156,62 @@ public class ChatPageController {
} }
private void toggleArchive(ChatEntry entry) { private void toggleArchive(ChatEntry entry) {
if (entry == null) return; boolean currentlyArchived = Session.isArchived(entry.getId());
// Just toggle the text for now // Disable UI source while processing
if ("Archive chat".equals(archiveItem.getText())) { if (archiveItem != null) archiveItem.setDisable(true);
archiveItem.setText("Unarchive chat");
System.out.println("Pretend: chat " + entry.getName() + " archived."); new Thread(() -> {
JSONObject req = new JSONObject()
.put("chat_id", entry.getId().toString());
if (!currentlyArchived) {
// ARCHIVE
req.put("action", "archive_chat")
.put("chat_type", entry.getType()); // سرور می‌خواهد
} else { } else {
archiveItem.setText("Archive chat"); // UNARCHIVE
System.out.println("Pretend: chat " + entry.getName() + " unarchived."); req.put("action", "unarchive_chat");
} }
JSONObject resp = ActionHandler.sendWithResponse(req);
Platform.runLater(() -> {
if (archiveItem != null) archiveItem.setDisable(false);
if (resp != null && "success".equalsIgnoreCase(resp.optString("status"))) {
// 1) جابه‌جایی در Session
if (!currentlyArchived) {
Session.moveToArchived(entry);
if (archiveItem != null) archiveItem.setText("Unarchive chat");
} else {
Session.moveToActive(entry);
if (archiveItem != null) archiveItem.setText("Archive chat");
} }
Session.sortListsByLastMessage();
// 2) تازه‌سازی UI لیست‌ها
try {
MainController.getInstance().refreshChatListUI(); // پیاده‌سازی در بخش 3
} catch (Exception ignore) {}
// 3) اگر وارد نمای آرشیو هستیم و آن‌آرشیو شد، بلافاصله از لیست آرشیو حذف شود
if (Session.inArchivedView && !Session.isArchived(entry.getId())) {
try { MainController.getInstance().refreshArchivedListUI(); } catch (Exception ignore) {}
}
// 4) اگر تازه برای اولین بار آرشیو داریم، ردیف "Archived Chats" در بالای لیست ظاهر شود
try { MainController.getInstance().ensureArchivedHeaderRow(); } catch (Exception ignore) {}
} else {
String msg = (resp != null ? resp.optString("message", "Unknown error")
: "No response from server.");
new Alert(Alert.AlertType.ERROR, "Failed to toggle archive: " + msg).showAndWait();
}
});
}).start();
}
private void loadMessages(ChatEntry entry) { private void loadMessages(ChatEntry entry) {
JSONObject req = new JSONObject(); JSONObject req = new JSONObject();
@@ -2184,7 +2224,6 @@ public class ChatPageController {
.put("user_id", myInternalUuid) // UUID من .put("user_id", myInternalUuid) // UUID من
.put("id", targetId); // UUID مقصد .put("id", targetId); // UUID مقصد
// ⛔ روی ترد FX کال شبکه نزن!
new Thread(() -> { new Thread(() -> {
JSONObject res = ActionHandler.sendWithResponse(req); JSONObject res = ActionHandler.sendWithResponse(req);
boolean ok = (res != null && "success".equalsIgnoreCase(res.optString("status"))); boolean ok = (res != null && "success".equalsIgnoreCase(res.optString("status")));
@@ -2699,7 +2738,7 @@ public class ChatPageController {
currentChat.getType().equalsIgnoreCase(target.type)) { currentChat.getType().equalsIgnoreCase(target.type)) {
loadMessages(currentChat); loadMessages(currentChat);
} else { } else {
addSystemMessage("Forwarded to " + (target.name.isBlank() ? target.id : target.name)); // addSystemMessage("Forwarded to " + (target.name.isBlank() ? target.id : target.name));
} }
} }
}); });
@@ -10,11 +10,7 @@ import javafx.scene.Node;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Circle; import javafx.scene.shape.Circle;
import javafx.util.Duration; import javafx.util.Duration;
import org.to.telegramfinalproject.Client.Session; import org.to.telegramfinalproject.Client.Session;
@@ -38,6 +34,10 @@ public class MainController {
@FXML private ScrollPane globalSearchScroll; @FXML private ScrollPane globalSearchScroll;
@FXML private VBox globalSearchResultsContainer; @FXML private VBox globalSearchResultsContainer;
//Archives
@FXML private VBox chatListVBox;
@FXML private Label chatListHeader;
private boolean blockedByMeFlag = false; private boolean blockedByMeFlag = false;
private boolean blockedMeFlag = false; private boolean blockedMeFlag = false;
@@ -153,11 +153,26 @@ public class MainController {
} }
// public void refreshChatListUI() {
// Platform.runLater(() -> {
// chatListContainer.getChildren().clear();
// itemControllers.clear();
// populateChatListFromSession(); // همون متدی که نودها رو می‌سازه و می‌چسبونه
// });
// }
public void refreshChatListUI() { public void refreshChatListUI() {
Platform.runLater(() -> { Platform.runLater(() -> {
chatListContainer.getChildren().clear(); chatListContainer.getChildren().clear();
itemControllers.clear(); itemControllers.clear();
populateChatListFromSession(); // همون متدی که نودها رو می‌سازه و می‌چسبونه
if (Session.inArchivedView) {
refreshArchivedListUI(); // همین ظرف chatListContainer را پر می‌کند
} else {
ensureArchivedHeaderRow(); // اول هدر را در chatListContainer بگذار
populateChatListFromSession();
}
}); });
} }
@@ -170,7 +185,8 @@ public class MainController {
@FXML @FXML
public void initialize() { public void initialize() {
// Populate chat list // Populate chat list
populateChatListFromSession(); // populateChatListFromSession();
refreshChatListUI();
// Register the scene for automatic CSS updates // Register the scene for automatic CSS updates
Platform.runLater(() -> { Platform.runLater(() -> {
@@ -316,7 +332,7 @@ public class MainController {
} }
private void populateChatListFromSession() { private void populateChatListFromSession() {
chatListContainer.getChildren().clear(); // chatListContainer.getChildren().clear();
var list = (org.to.telegramfinalproject.Client.Session.activeChats != null var list = (org.to.telegramfinalproject.Client.Session.activeChats != null
&& !org.to.telegramfinalproject.Client.Session.activeChats.isEmpty()) && !org.to.telegramfinalproject.Client.Session.activeChats.isEmpty())
@@ -1234,6 +1250,95 @@ public class MainController {
private static final String ARCHIVED_ROW_KEY = "ARCHIVED_HEADER_ROW";
public void ensureArchivedHeaderRow() {
boolean hasArchived = Session.archivedChats != null && !Session.archivedChats.isEmpty();
// اگر آرشیو نداریم، هدر قبلی را حذف کن و برگرد
if (!hasArchived) {
chatListContainer.getChildren().removeIf(n -> ARCHIVED_ROW_KEY.equals(n.getUserData()));
return;
}
// اگر قبلاً هست، دوباره نساز
boolean exists = chatListContainer.getChildren().stream()
.anyMatch(n -> ARCHIVED_ROW_KEY.equals(n.getUserData()));
if (exists) return;
HBox headerRow = new HBox(8);
headerRow.setUserData(ARCHIVED_ROW_KEY);
headerRow.getStyleClass().add("archived-header-row");
Label title = new Label("Archived Chats");
Region spacer = new Region(); HBox.setHgrow(spacer, Priority.ALWAYS);
Button openBtn = new Button("Open");
openBtn.setOnAction(e -> showArchivedListUI());
headerRow.getChildren().addAll(title, spacer, openBtn);
headerRow.setMinHeight(36); headerRow.setPrefHeight(36);
// در ابتدای همان لیست اصلیِ چت‌ها
chatListContainer.getChildren().add(0, headerRow);
}
public void showArchivedListUI() {
Session.inArchivedView = true;
refreshChatListUI();
}
public void refreshArchivedListUI() {
chatListContainer.getChildren().clear();
// Back row (بماند)
HBox backRow = new HBox();
Label back = new Label("← Back to Active");
back.getStyleClass().add("archived-back");
back.setOnMouseClicked(e -> {
Session.inArchivedView = false;
refreshChatListUI();
});
backRow.getChildren().add(back);
backRow.setStyle("-fx-padding: 6 10 8 10;");
chatListContainer.getChildren().add(backRow);
// از همین سل‌ساز FXML استفاده کن تا دقیقا هم‌شکل اکتیو باشد
if (Session.archivedChats != null && !Session.archivedChats.isEmpty()) {
for (ChatEntry e : Session.archivedChats) {
addChatNode(e); // همونی که در اکتیو استفاده می‌کنی
}
} else {
Label empty = new Label("No archived chats");
empty.getStyleClass().add("muted");
chatListContainer.getChildren().add(empty);
}
}
// ساخت یک سل آیتم (برای اکتیو/آرشیو)
private HBox buildChatCell(ChatEntry e, boolean archivedView) {
HBox row = new HBox(8);
ImageView avatar = new ImageView(); avatar.setFitWidth(36); avatar.setFitHeight(36);
// ... لود تصویر از e.getImageUrl() اگر داری
Label name = new Label(e.getName());
Region spacer = new Region(); HBox.setHgrow(spacer, javafx.scene.layout.Priority.ALWAYS);
Label last = new Label(safeLastLine(e)); // آخرین پیام/زمان (اختیاری)
row.getChildren().addAll(avatar, name, spacer, last);
row.getStyleClass().add("chat-row");
// کلیک روی آیتم openChat
row.setOnMouseClicked(ev -> openChat(e));
return row;
}
private String safeLastLine(ChatEntry e) {
String s = e.getLastMessagePreview(); // اگر داری
return s != null ? s : "";
}
} }