Archived chats
This commit is contained in:
@@ -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,18 +1156,63 @@ 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(() -> {
|
||||||
} else {
|
JSONObject req = new JSONObject()
|
||||||
archiveItem.setText("Archive chat");
|
.put("chat_id", entry.getId().toString());
|
||||||
System.out.println("Pretend: chat " + entry.getName() + " unarchived.");
|
|
||||||
}
|
if (!currentlyArchived) {
|
||||||
|
// ARCHIVE
|
||||||
|
req.put("action", "archive_chat")
|
||||||
|
.put("chat_type", entry.getType()); // سرور میخواهد
|
||||||
|
} else {
|
||||||
|
// UNARCHIVE
|
||||||
|
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();
|
||||||
req.put("action", "get_messages_UI");
|
req.put("action", "get_messages_UI");
|
||||||
@@ -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 : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user