Fix bugs in add contact to chat
This commit is contained in:
@@ -7,6 +7,7 @@ import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.shape.Circle;
|
||||
import org.to.telegramfinalproject.Client.AvatarLocalResolver;
|
||||
import org.to.telegramfinalproject.Models.ChatEntry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -141,4 +142,10 @@ public class ChatItemController {
|
||||
}
|
||||
}
|
||||
|
||||
private String safeTitle(ChatEntry e) {
|
||||
if (e.getName() != null && !e.getName().isBlank()) return e.getName();
|
||||
if (e.getDisplayId() != null && !e.getDisplayId().isBlank()) return e.getDisplayId();
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -90,10 +90,9 @@ public class ContactsController {
|
||||
return new ArrayList<>(Session.contactEntries);
|
||||
}
|
||||
|
||||
// در غیر این صورت از سرور میگیریم (اختیاری)
|
||||
// اگر API «view_contacts» داری، اینجا بفرست:
|
||||
|
||||
JSONObject req = new JSONObject()
|
||||
.put("action", "view_contacts") // 🔧 اگر نام اکشنات فرق دارد، تغییر بده
|
||||
.put("action", "view_contacts")
|
||||
.put("user_id", Session.getUserUUID());
|
||||
|
||||
JSONObject res = ActionHandler.sendWithResponse(req);
|
||||
@@ -122,7 +121,6 @@ public class ContactsController {
|
||||
|
||||
fetched.add(new ContactEntry(contactId, userId, contactDisplay, profileName, imageUrl, isBlocked, lastSeen));
|
||||
}
|
||||
// اگر میخواهی تو سشن هم نگه داری:
|
||||
if (Session.contactEntries == null) Session.contactEntries = new ArrayList<>();
|
||||
Session.contactEntries.clear();
|
||||
Session.contactEntries.addAll(fetched);
|
||||
@@ -161,7 +159,6 @@ public class ContactsController {
|
||||
item.getStyleClass().add("contact-item");
|
||||
item.setCursor(Cursor.HAND);
|
||||
|
||||
// آواتار
|
||||
ImageView avatar = new ImageView(loadAvatarSafe(c.imageUrl));
|
||||
avatar.setFitWidth(58);
|
||||
avatar.setFitHeight(58);
|
||||
@@ -183,13 +180,24 @@ public class ContactsController {
|
||||
|
||||
private Image loadAvatarSafe(String urlOrResource) {
|
||||
try {
|
||||
if (urlOrResource != null && urlOrResource.startsWith("/")) {
|
||||
return new Image(Objects.requireNonNull(getClass().getResourceAsStream(urlOrResource)));
|
||||
if (urlOrResource != null) {
|
||||
// حالت Resource داخلی
|
||||
if (urlOrResource.startsWith("/")) {
|
||||
return new Image(Objects.requireNonNull(
|
||||
getClass().getResourceAsStream(urlOrResource)));
|
||||
}
|
||||
// اگر URL وب هم داری، میتونی مستقیم Image(url) بسازی
|
||||
// حالت URL وب یا مسیر فایل
|
||||
if (urlOrResource.startsWith("http://") ||
|
||||
urlOrResource.startsWith("https://") ||
|
||||
urlOrResource.startsWith("file:")) {
|
||||
return new Image(urlOrResource, true); // true = لود async
|
||||
}
|
||||
}
|
||||
// fallback به پیشفرض
|
||||
return new Image(Objects.requireNonNull(
|
||||
getClass().getResourceAsStream("/org/to/telegramfinalproject/Avatars/default_user_profile.png")));
|
||||
} catch (Exception ignore) {
|
||||
} catch (Exception e) {
|
||||
// هر مشکلی → پیشفرض
|
||||
return new Image(Objects.requireNonNull(
|
||||
getClass().getResourceAsStream("/org/to/telegramfinalproject/Avatars/default_user_profile.png")));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.shape.Circle;
|
||||
import javafx.util.Duration;
|
||||
import org.json.JSONObject;
|
||||
import org.to.telegramfinalproject.Client.Session;
|
||||
import org.to.telegramfinalproject.Models.ChatEntry;
|
||||
import org.to.telegramfinalproject.Client.ActionHandler;
|
||||
@@ -96,8 +97,12 @@ public class MainController {
|
||||
// Keep track of the scene user comes from
|
||||
private final Deque<Node> navigationStack = new ArrayDeque<>();
|
||||
private final Map<UUID, ChatItemController> itemControllers = new HashMap<>();
|
||||
private final java.util.Set<UUID> enrichInFlight = java.util.Collections.newSetFromMap(new java.util.concurrent.ConcurrentHashMap<>());
|
||||
|
||||
|
||||
private static final String SAVED_TITLE = "Saved Messages";
|
||||
private static final String SAVED_AVATAR = "/org/to/telegramfinalproject/Avatars/saved_messages.png";
|
||||
|
||||
//For realtime handling
|
||||
public void onChatUpdated(UUID chatId, String chatType, LocalDateTime lastTs,
|
||||
boolean isIncoming, String lastPreview) {
|
||||
@@ -351,10 +356,8 @@ public class MainController {
|
||||
}
|
||||
}
|
||||
|
||||
// اگر “Archived Chats” یا هدر دیگری داری، قبلش اضافه کن (اختیاری)
|
||||
// addArchivedHeaderIfYouHaveOne();
|
||||
|
||||
// 1) همیشه Saved اول بیاد (اگر وجود داشت)
|
||||
if (saved != null) {
|
||||
addChatNode(saved);
|
||||
}
|
||||
@@ -408,33 +411,98 @@ public class MainController {
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
private void addChatNode(ChatEntry chat) {
|
||||
try {
|
||||
FXMLLoader fx = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/chat_item.fxml"));
|
||||
Node item = fx.load();
|
||||
ChatItemController cc = fx.getController();
|
||||
|
||||
// --- saved detection
|
||||
boolean saved = isSaved(chat);
|
||||
|
||||
String title = safeTitle(chat);
|
||||
String preview = chat.getLastMessagePreview() == null ? "" : chat.getLastMessagePreview();
|
||||
String timeText = chat.getLastMessageTime() == null ? "" : formatChatTime(chat.getLastMessageTime());
|
||||
String imageUrl = safeImage(chat.getImageUrl());
|
||||
|
||||
String timeText = chat.getLastMessageTime() == null
|
||||
? ""
|
||||
: formatChatTime(chat.getLastMessageTime());
|
||||
// --- force Saved Messages title & avatar
|
||||
if (saved) {
|
||||
title = SAVED_TITLE;
|
||||
imageUrl = SAVED_AVATAR;
|
||||
}
|
||||
|
||||
// If chat has a profile picture, pass it; otherwise null
|
||||
String imageUrl = (chat.getImageUrl() != null && !chat.getImageUrl().isEmpty())
|
||||
? chat.getImageUrl()
|
||||
: null;
|
||||
|
||||
cc.setChatData(chat.getName(), preview, timeText, chat.getUnreadCount(), imageUrl, chat.getType());
|
||||
cc.setChatData(title, preview, timeText, chat.getUnreadCount(), imageUrl, chat.getType());
|
||||
item.setOnMouseClicked(e -> openChat(chat));
|
||||
chatListContainer.getChildren().add(item);
|
||||
|
||||
itemControllers.put(chat.getId(), cc);
|
||||
|
||||
// --- no enrich for Saved
|
||||
boolean needName = (chat.getName() == null || chat.getName().isBlank());
|
||||
boolean needImage = (chat.getImageUrl() == null || chat.getImageUrl().isBlank());
|
||||
if (!saved && (needName || needImage)) {
|
||||
enrichChatEntryAsync(chat);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
private boolean isSaved(ChatEntry e) {
|
||||
if (e == null) return false;
|
||||
if (e.isSavedMessages()) return true;
|
||||
return "saved".equalsIgnoreCase(e.getType()); // اگر type اختصاصی داری
|
||||
}
|
||||
|
||||
|
||||
public void updateSingleChatCell(ChatEntry entry) {
|
||||
ChatItemController cc = itemControllers.get(entry.getId());
|
||||
if (cc != null) {
|
||||
Platform.runLater(() -> cc.setChatData(
|
||||
safeTitle(entry),
|
||||
entry.getLastMessagePreview() == null ? "" : entry.getLastMessagePreview(),
|
||||
entry.getLastMessageTime() == null ? "" : formatChatTime(entry.getLastMessageTime()),
|
||||
entry.getUnreadCount(),
|
||||
safeImage(entry.getImageUrl()),
|
||||
entry.getType()
|
||||
));
|
||||
} else {
|
||||
refreshChatListUI(); // اگر پیدا نشد، کل لیست را رفرش کن
|
||||
}
|
||||
}
|
||||
|
||||
public void enrichChatEntryAsync(ChatEntry entry) {
|
||||
if (entry == null) return;
|
||||
// اگر در حال دریافت هستیم، تکراری نفرست
|
||||
if (!enrichInFlight.add(entry.getId())) return;
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
JSONObject req = new JSONObject()
|
||||
.put("action", "get_header_info")
|
||||
.put("receiver_id", entry.getId().toString())
|
||||
.put("receiver_type", entry.getType())
|
||||
.put("viewer_id", Session.getUserUUID());
|
||||
|
||||
JSONObject res = ActionHandler.sendWithResponse(req);
|
||||
if (res != null && "success".equalsIgnoreCase(res.optString("status"))) {
|
||||
JSONObject d = res.optJSONObject("data");
|
||||
if (d != null) {
|
||||
String name = d.optString("name", "");
|
||||
String image = d.optString("image_url", "");
|
||||
Platform.runLater(() -> {
|
||||
if (!name.isBlank()) entry.setName(name);
|
||||
if (!image.isBlank()) entry.setImageUrl(image);
|
||||
updateSingleChatCell(entry); // فقط همان آیتم را نوسازی کن
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
} finally {
|
||||
enrichInFlight.remove(entry.getId());
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
private String mapTypeToLabel(String t) {
|
||||
switch (t.toUpperCase()) {
|
||||
@@ -1201,13 +1269,11 @@ public class MainController {
|
||||
if (Session.chatList == null) Session.chatList = new ArrayList<>();
|
||||
Session.chatList.add(ce);
|
||||
}
|
||||
// اگر activeChats استفاده میکنی:
|
||||
if (Session.activeChats != null && Session.activeChats.stream().noneMatch(c -> id.equals(c.getId()))) {
|
||||
Session.activeChats.add(ce);
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
|
||||
// (اختیاری) مرتبسازی بر اساس زمان آخرین پیام
|
||||
Comparator<ChatEntry> byTimeDesc = (a,b) -> {
|
||||
LocalDateTime t1 = a.getLastMessageTime(), t2 = b.getLastMessageTime();
|
||||
if (t1 == null && t2 == null) return 0;
|
||||
@@ -1340,5 +1406,21 @@ public class MainController {
|
||||
}
|
||||
|
||||
|
||||
// title fallback: اول name بعد displayId، در نهایت پیشفرض
|
||||
private String safeTitle(ChatEntry e) {
|
||||
if (e.getName() != null && !e.getName().isBlank()) return e.getName();
|
||||
if (e.getDisplayId() != null && !e.getDisplayId().isBlank()) return e.getDisplayId();
|
||||
if ("saved".equalsIgnoreCase(e.getType()) || e.isSavedMessages()) return "Saved Messages";
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// image fallback: اگر خالی بود، آواتار پیشفرض
|
||||
private String safeImage(String img) {
|
||||
return (img != null && !img.isBlank())
|
||||
? img
|
||||
: "/org/to/telegramfinalproject/Avatars/default_user_profile.png";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user