Cleaning
This commit is contained in:
@@ -100,7 +100,6 @@ public class CheckPasswordController {
|
|||||||
private void validatePassword() {
|
private void validatePassword() {
|
||||||
String entered = (passwordVisible ? visiblePasswordField.getText() : passwordField.getText()).trim();
|
String entered = (passwordVisible ? visiblePasswordField.getText() : passwordField.getText()).trim();
|
||||||
if (entered.isEmpty()) {
|
if (entered.isEmpty()) {
|
||||||
// استایل خطا مثل قبل
|
|
||||||
if (!passwordField.getStyleClass().contains("error"))
|
if (!passwordField.getStyleClass().contains("error"))
|
||||||
passwordField.getStyleClass().add("error");
|
passwordField.getStyleClass().add("error");
|
||||||
if (!visiblePasswordField.getStyleClass().contains("error"))
|
if (!visiblePasswordField.getStyleClass().contains("error"))
|
||||||
@@ -110,7 +109,6 @@ public class CheckPasswordController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// تماس با سرور
|
|
||||||
org.json.JSONObject req = new org.json.JSONObject()
|
org.json.JSONObject req = new org.json.JSONObject()
|
||||||
.put("action", "verify_password")
|
.put("action", "verify_password")
|
||||||
.put("current_password", entered);
|
.put("current_password", entered);
|
||||||
@@ -119,12 +117,11 @@ public class CheckPasswordController {
|
|||||||
boolean ok = (resp != null && "success".equalsIgnoreCase(resp.optString("status")));
|
boolean ok = (resp != null && "success".equalsIgnoreCase(resp.optString("status")));
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
// پاک کردن خطاها
|
|
||||||
passwordField.getStyleClass().remove("error");
|
passwordField.getStyleClass().remove("error");
|
||||||
visiblePasswordField.getStyleClass().remove("error");
|
visiblePasswordField.getStyleClass().remove("error");
|
||||||
passwordLabel.getStyleClass().remove("error");
|
passwordLabel.getStyleClass().remove("error");
|
||||||
|
|
||||||
openChangeCredentials(entered); // ← پسورد فعلی را پاس بده
|
openChangeCredentials(entered);
|
||||||
} else {
|
} else {
|
||||||
if (!passwordField.getStyleClass().contains("error"))
|
if (!passwordField.getStyleClass().contains("error"))
|
||||||
passwordField.getStyleClass().add("error");
|
passwordField.getStyleClass().add("error");
|
||||||
@@ -165,8 +162,8 @@ public class CheckPasswordController {
|
|||||||
Node overlay = loader.load();
|
Node overlay = loader.load();
|
||||||
|
|
||||||
ChangeCredentialsController c = loader.getController();
|
ChangeCredentialsController c = loader.getController();
|
||||||
c.setCurrentPassword(currentPassword); // ← مهم
|
c.setCurrentPassword(currentPassword);
|
||||||
c.prefillFromSession(); // ← پیشپر کردن
|
c.prefillFromSession();
|
||||||
|
|
||||||
MainController.getInstance().showOverlay(overlay);
|
MainController.getInstance().showOverlay(overlay);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
|||||||
@@ -30,15 +30,12 @@ public class ContactsController {
|
|||||||
@FXML private ScrollPane contactsScroll;
|
@FXML private ScrollPane contactsScroll;
|
||||||
@FXML private Button searchIcon;
|
@FXML private Button searchIcon;
|
||||||
|
|
||||||
/** منبع داده UI — با کانتکتهای واقعی پر میشود */
|
|
||||||
private final List<ContactVM> allContacts = new ArrayList<>();
|
private final List<ContactVM> allContacts = new ArrayList<>();
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
// 1) لود اولیهی کانتکتها از سشن/سرور
|
|
||||||
loadContactsAndRender();
|
loadContactsAndRender();
|
||||||
|
|
||||||
// 2) سرچ محلی روی لیست
|
|
||||||
searchField.textProperty().addListener((obs, ov, nv) -> {
|
searchField.textProperty().addListener((obs, ov, nv) -> {
|
||||||
String f = nv == null ? "" : nv.trim().toLowerCase();
|
String f = nv == null ? "" : nv.trim().toLowerCase();
|
||||||
List<ContactVM> filtered = allContacts.stream()
|
List<ContactVM> filtered = allContacts.stream()
|
||||||
@@ -49,14 +46,11 @@ public class ContactsController {
|
|||||||
renderContacts(filtered);
|
renderContacts(filtered);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3) فوکوس خودکار روی سرچ
|
|
||||||
Platform.runLater(() -> searchField.requestFocus());
|
Platform.runLater(() -> searchField.requestFocus());
|
||||||
|
|
||||||
// 4) بستن اورلی
|
|
||||||
closeFooterButton.setOnAction(e -> MainController.getInstance().closeOverlay(contactsCard.getParent()));
|
closeFooterButton.setOnAction(e -> MainController.getInstance().closeOverlay(contactsCard.getParent()));
|
||||||
overlayBackground.setOnMouseClicked(e -> MainController.getInstance().closeOverlay(contactsCard.getParent()));
|
overlayBackground.setOnMouseClicked(e -> MainController.getInstance().closeOverlay(contactsCard.getParent()));
|
||||||
|
|
||||||
// 5) اسکرول نرم
|
|
||||||
contactsScroll.getStylesheets().add(getClass().getResource("/org/to/telegramfinalproject/CSS/scrollpane.css").toExternalForm());
|
contactsScroll.getStylesheets().add(getClass().getResource("/org/to/telegramfinalproject/CSS/scrollpane.css").toExternalForm());
|
||||||
contactsScroll.setPannable(true);
|
contactsScroll.setPannable(true);
|
||||||
contactsScroll.setFitToWidth(true);
|
contactsScroll.setFitToWidth(true);
|
||||||
@@ -66,23 +60,18 @@ public class ContactsController {
|
|||||||
contactsScroll.setVvalue(contactsScroll.getVvalue() - deltaY);
|
contactsScroll.setVvalue(contactsScroll.getVvalue() - deltaY);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 6) ثبت صحنه برای ThemeManager
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (contactsCard.getScene() != null) {
|
if (contactsCard.getScene() != null) {
|
||||||
ThemeManager.getInstance().registerScene(contactsCard.getScene());
|
ThemeManager.getInstance().registerScene(contactsCard.getScene());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 7) واکنش به تغییر تم
|
|
||||||
ThemeManager.getInstance().darkModeProperty().addListener((obs, oldVal, newVal) -> updateSearchIcon(newVal));
|
ThemeManager.getInstance().darkModeProperty().addListener((obs, oldVal, newVal) -> updateSearchIcon(newVal));
|
||||||
updateSearchIcon(ThemeManager.getInstance().isDarkMode());
|
updateSearchIcon(ThemeManager.getInstance().isDarkMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------
|
|
||||||
// لود داده و رندر لیست
|
|
||||||
// -----------------------
|
|
||||||
private void loadContactsAndRender() {
|
private void loadContactsAndRender() {
|
||||||
// اگر Session.contactEntries از قبل لود شده، از همان استفاده میکنیم.
|
|
||||||
CompletableFuture
|
CompletableFuture
|
||||||
.supplyAsync(() -> {
|
.supplyAsync(() -> {
|
||||||
try {
|
try {
|
||||||
@@ -181,23 +170,19 @@ public class ContactsController {
|
|||||||
private Image loadAvatarSafe(String urlOrResource) {
|
private Image loadAvatarSafe(String urlOrResource) {
|
||||||
try {
|
try {
|
||||||
if (urlOrResource != null) {
|
if (urlOrResource != null) {
|
||||||
// حالت Resource داخلی
|
|
||||||
if (urlOrResource.startsWith("/")) {
|
if (urlOrResource.startsWith("/")) {
|
||||||
return new Image(Objects.requireNonNull(
|
return new Image(Objects.requireNonNull(
|
||||||
getClass().getResourceAsStream(urlOrResource)));
|
getClass().getResourceAsStream(urlOrResource)));
|
||||||
}
|
}
|
||||||
// حالت URL وب یا مسیر فایل
|
|
||||||
if (urlOrResource.startsWith("http://") ||
|
if (urlOrResource.startsWith("http://") ||
|
||||||
urlOrResource.startsWith("https://") ||
|
urlOrResource.startsWith("https://") ||
|
||||||
urlOrResource.startsWith("file:")) {
|
urlOrResource.startsWith("file:")) {
|
||||||
return new Image(urlOrResource, true); // true = لود async
|
return new Image(urlOrResource, true); // true = لود async
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fallback به پیشفرض
|
|
||||||
return new Image(Objects.requireNonNull(
|
return new Image(Objects.requireNonNull(
|
||||||
getClass().getResourceAsStream("/org/to/telegramfinalproject/Avatars/default_user_profile.png")));
|
getClass().getResourceAsStream("/org/to/telegramfinalproject/Avatars/default_user_profile.png")));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// هر مشکلی → پیشفرض
|
|
||||||
return new Image(Objects.requireNonNull(
|
return new Image(Objects.requireNonNull(
|
||||||
getClass().getResourceAsStream("/org/to/telegramfinalproject/Avatars/default_user_profile.png")));
|
getClass().getResourceAsStream("/org/to/telegramfinalproject/Avatars/default_user_profile.png")));
|
||||||
}
|
}
|
||||||
@@ -291,12 +276,10 @@ public class ContactsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------
|
|
||||||
// ViewModel سادهی کانتکت
|
|
||||||
// -----------------------
|
|
||||||
private static class ContactVM {
|
private static class ContactVM {
|
||||||
final UUID contactId; // internal UUID (واقعی)
|
final UUID contactId; // internal UUID
|
||||||
final String userId; // @id نمایش (اختیاری)
|
final String userId; // @id
|
||||||
final String profileName;
|
final String profileName;
|
||||||
final String imageUrl;
|
final String imageUrl;
|
||||||
|
|
||||||
|
|||||||
@@ -137,8 +137,8 @@ public class EditProfileController {
|
|||||||
File file = fileChooser.showOpenDialog(profileImageView.getScene().getWindow());
|
File file = fileChooser.showOpenDialog(profileImageView.getScene().getWindow());
|
||||||
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
pickedAvatarFile = file; // ← ذخیره کن برای ارسال هنگام خروج
|
pickedAvatarFile = file;
|
||||||
profileImageView.setImage(new Image(file.toURI().toString())); // پیشنمایش
|
profileImageView.setImage(new Image(file.toURI().toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,16 +192,13 @@ public class EditProfileController {
|
|||||||
if (ActionHandler.instance.wasSuccess()) {
|
if (ActionHandler.instance.wasSuccess()) {
|
||||||
String url = ActionHandler.instance.getLastMessage();
|
String url = ActionHandler.instance.getLastMessage();
|
||||||
if (url != null && !url.isBlank()) {
|
if (url != null && !url.isBlank()) {
|
||||||
// قبلاً اینجا مستقیم bust میزدیم → مشکل ایجاد میکرد
|
|
||||||
// currentUser.put("image_url", url);
|
|
||||||
|
|
||||||
// ✔️ نسخهی امن:
|
|
||||||
String extracted = extractImageUrl(url); // از helper پایین
|
String extracted = extractImageUrl(url);
|
||||||
if (isLikelyImageUrl(extracted)) {
|
if (isLikelyImageUrl(extracted)) {
|
||||||
String finalUrl = addCacheBusterIfHttp(extracted); // فقط برای http/https
|
String finalUrl = addCacheBusterIfHttp(extracted);
|
||||||
Session.currentUser.put("image_url", finalUrl);
|
Session.currentUser.put("image_url", finalUrl);
|
||||||
} else {
|
} else {
|
||||||
// اگر سرور چیز عجیبی مثل "Welcome Farid" برگردوند، نادیده بگیر
|
|
||||||
System.out.println("Upload avatar returned a non-image value: " + url);
|
System.out.println("Upload avatar returned a non-image value: " + url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,15 +264,12 @@ public class EditProfileController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) خودِ کارت Settings را فوراً از Session ریفرش کن
|
|
||||||
if (parentSettings != null) {
|
if (parentSettings != null) {
|
||||||
parentSettings.populateFromSession();
|
parentSettings.populateFromSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) سایدبار بالایی (اسم/آواتار خود کاربر) اگر داری
|
|
||||||
MainController.getInstance().refreshSidebarUserFromSession();
|
MainController.getInstance().refreshSidebarUserFromSession();
|
||||||
|
|
||||||
// 4) بستن اورلی ادیت
|
|
||||||
// MainController.getInstance().goBack(overlayBackground);
|
// MainController.getInstance().goBack(overlayBackground);
|
||||||
MainController.getInstance().closeOverlay(editCard.getParent());
|
MainController.getInstance().closeOverlay(editCard.getParent());
|
||||||
|
|
||||||
@@ -302,7 +296,6 @@ public class EditProfileController {
|
|||||||
|
|
||||||
private boolean isLikelyImageUrl(String s) {
|
private boolean isLikelyImageUrl(String s) {
|
||||||
if (s == null || s.isBlank()) return false;
|
if (s == null || s.isBlank()) return false;
|
||||||
// URL کامل، مسیر نسبی سرور، یا file: و پسوند تصویر
|
|
||||||
return s.startsWith("http://") || s.startsWith("https://")
|
return s.startsWith("http://") || s.startsWith("https://")
|
||||||
|| s.startsWith("file:")
|
|| s.startsWith("file:")
|
||||||
|| s.startsWith("/")
|
|| s.startsWith("/")
|
||||||
@@ -314,19 +307,15 @@ public class EditProfileController {
|
|||||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||||
return url + (url.contains("?") ? "&" : "?") + "v=" + System.currentTimeMillis();
|
return url + (url.contains("?") ? "&" : "?") + "v=" + System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
// برای مسیر لوکال/نسبی اصلاً ?v اضافه نکن (روی ویندوز مشکل میدهد)
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** اگر سرور بهجای URL، JSON یا متن دیگری داد، اینجا URL را دربیار. */
|
|
||||||
private String extractImageUrl(String raw) {
|
private String extractImageUrl(String raw) {
|
||||||
if (raw == null) return null;
|
if (raw == null) return null;
|
||||||
String s = raw.trim();
|
String s = raw.trim();
|
||||||
// اگر برگشتی JSON است (بعضی سرویسها data.display_url برمیگردانند)
|
|
||||||
if (s.startsWith("{") && s.endsWith("}")) {
|
if (s.startsWith("{") && s.endsWith("}")) {
|
||||||
try {
|
try {
|
||||||
org.json.JSONObject j = new org.json.JSONObject(s);
|
org.json.JSONObject j = new org.json.JSONObject(s);
|
||||||
// هر کلیدی که سرویسات استفاده میکند را امتحان کن
|
|
||||||
if (j.has("display_url")) return j.optString("display_url", null);
|
if (j.has("display_url")) return j.optString("display_url", null);
|
||||||
if (j.has("url")) return j.optString("url", null);
|
if (j.has("url")) return j.optString("url", null);
|
||||||
if (j.has("data")) {
|
if (j.has("data")) {
|
||||||
@@ -338,7 +327,7 @@ public class EditProfileController {
|
|||||||
}
|
}
|
||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {}
|
||||||
}
|
}
|
||||||
return s; // در غیر این صورت همان raw
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ public class IntroController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void handleStartMessaging(ActionEvent event) {
|
private void handleStartMessaging(ActionEvent event) {
|
||||||
AppRouter.showLogin(); // همون Scene میمونه، فقط Root عوض میشه
|
AppRouter.showLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML private void goRegister() { AppRouter.showRegister(); }
|
@FXML private void goRegister() { AppRouter.showRegister(); }
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ public class LoginController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// موفق: Session از داخل send پر شده
|
|
||||||
goMain(); // بدون Alert → مستقیم به main.fxml
|
goMain();
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@@ -200,7 +200,7 @@ public class LoginController {
|
|||||||
PauseTransition pause = new PauseTransition(Duration.millis(50));
|
PauseTransition pause = new PauseTransition(Duration.millis(50));
|
||||||
pause.setOnFinished(event -> {
|
pause.setOnFinished(event -> {
|
||||||
errorLabel.setText(message);
|
errorLabel.setText(message);
|
||||||
errorLabel.setStyle("-fx-text-fill: red;"); // 🔴 force red
|
errorLabel.setStyle("-fx-text-fill: red;");
|
||||||
errorLabel.setVisible(true);
|
errorLabel.setVisible(true);
|
||||||
});
|
});
|
||||||
pause.play();
|
pause.play();
|
||||||
|
|||||||
@@ -1060,7 +1060,6 @@ public class MainController {
|
|||||||
private void openSearchResult(SearchResult r) {
|
private void openSearchResult(SearchResult r) {
|
||||||
switch (r.type) {
|
switch (r.type) {
|
||||||
case USER: {
|
case USER: {
|
||||||
// 1) اگه قبلاً چت پرایوت با این یوزر داری، از همون استفاده کن
|
|
||||||
UUID existingChatId = findExistingPrivateChatId(r.uuid);
|
UUID existingChatId = findExistingPrivateChatId(r.uuid);
|
||||||
|
|
||||||
ChatEntry ce = new ChatEntry();
|
ChatEntry ce = new ChatEntry();
|
||||||
@@ -1074,8 +1073,7 @@ public class MainController {
|
|||||||
ce.setId(existingChatId.toString());
|
ce.setId(existingChatId.toString());
|
||||||
mode = ChatViewMode.NORMAL;
|
mode = ChatViewMode.NORMAL;
|
||||||
} else {
|
} else {
|
||||||
// هنوز چتی وجود ندارد → Preview (بدون ساخت چت)
|
|
||||||
// برای Preview از uuid خودِ طرف مقابل بهعنوان id موقت استفاده میکنیم
|
|
||||||
ce.setId(r.uuid.toString());
|
ce.setId(r.uuid.toString());
|
||||||
mode = isContact(r.uuid) ? ChatViewMode.NORMAL : ChatViewMode.NEEDS_ADD_CONTACT;
|
mode = isContact(r.uuid) ? ChatViewMode.NORMAL : ChatViewMode.NEEDS_ADD_CONTACT;
|
||||||
}
|
}
|
||||||
@@ -1188,19 +1186,16 @@ public class MainController {
|
|||||||
private boolean isSavedMessages(ChatEntry c) {
|
private boolean isSavedMessages(ChatEntry c) {
|
||||||
if (c == null) return false;
|
if (c == null) return false;
|
||||||
|
|
||||||
// اگر تایپ اختصاصی داری
|
|
||||||
if ("saved".equalsIgnoreCase(c.getType())) return true;
|
if ("saved".equalsIgnoreCase(c.getType())) return true;
|
||||||
|
|
||||||
// اگر با نام مشخص ذخیره میکنی
|
|
||||||
String n = c.getName();
|
String n = c.getName();
|
||||||
if (n != null && n.equalsIgnoreCase("Saved Messages")) return true;
|
if (n != null && n.equalsIgnoreCase("Saved Messages")) return true;
|
||||||
|
|
||||||
// حالت پرایوت با خودِ کاربر
|
|
||||||
String me = (org.to.telegramfinalproject.Client.Session.currentUser != null)
|
String me = (org.to.telegramfinalproject.Client.Session.currentUser != null)
|
||||||
? org.to.telegramfinalproject.Client.Session.currentUser.optString("internal_uuid", "")
|
? org.to.telegramfinalproject.Client.Session.currentUser.optString("internal_uuid", "")
|
||||||
: "";
|
: "";
|
||||||
try {
|
try {
|
||||||
UUID other = c.getOtherUserId(); // اگر این فیلد را داری
|
UUID other = c.getOtherUserId();
|
||||||
if ("private".equalsIgnoreCase(c.getType()) &&
|
if ("private".equalsIgnoreCase(c.getType()) &&
|
||||||
other != null && other.toString().equalsIgnoreCase(me)) {
|
other != null && other.toString().equalsIgnoreCase(me)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -1294,12 +1289,10 @@ public class MainController {
|
|||||||
org.to.telegramfinalproject.Client.Session.chatList.add(0, entry);
|
org.to.telegramfinalproject.Client.Session.chatList.add(0, entry);
|
||||||
org.to.telegramfinalproject.Client.Session.activeChats.add(0, entry);
|
org.to.telegramfinalproject.Client.Session.activeChats.add(0, entry);
|
||||||
}
|
}
|
||||||
// سایدبارت اگر متدی برای رفرش دارد صداش بزن (اسمش را با کلاس خودت هماهنگ کن)
|
|
||||||
try {
|
try {
|
||||||
this.refreshChatListUI(); // اگر نداری، این خط را حذف کن
|
this.refreshChatListUI();
|
||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {}
|
||||||
|
|
||||||
// نمایش پیج چت
|
|
||||||
if (getChatPageController() != null) {
|
if (getChatPageController() != null) {
|
||||||
getChatPageController().showChat(entry);
|
getChatPageController().showChat(entry);
|
||||||
}
|
}
|
||||||
@@ -1320,13 +1313,11 @@ public class MainController {
|
|||||||
public void ensureArchivedHeaderRow() {
|
public void ensureArchivedHeaderRow() {
|
||||||
boolean hasArchived = Session.archivedChats != null && !Session.archivedChats.isEmpty();
|
boolean hasArchived = Session.archivedChats != null && !Session.archivedChats.isEmpty();
|
||||||
|
|
||||||
// اگر آرشیو نداریم، هدر قبلی را حذف کن و برگرد
|
|
||||||
if (!hasArchived) {
|
if (!hasArchived) {
|
||||||
chatListContainer.getChildren().removeIf(n -> ARCHIVED_ROW_KEY.equals(n.getUserData()));
|
chatListContainer.getChildren().removeIf(n -> ARCHIVED_ROW_KEY.equals(n.getUserData()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// اگر قبلاً هست، دوباره نساز
|
|
||||||
boolean exists = chatListContainer.getChildren().stream()
|
boolean exists = chatListContainer.getChildren().stream()
|
||||||
.anyMatch(n -> ARCHIVED_ROW_KEY.equals(n.getUserData()));
|
.anyMatch(n -> ARCHIVED_ROW_KEY.equals(n.getUserData()));
|
||||||
if (exists) return;
|
if (exists) return;
|
||||||
@@ -1343,7 +1334,6 @@ public class MainController {
|
|||||||
headerRow.getChildren().addAll(title, spacer, openBtn);
|
headerRow.getChildren().addAll(title, spacer, openBtn);
|
||||||
headerRow.setMinHeight(36); headerRow.setPrefHeight(36);
|
headerRow.setMinHeight(36); headerRow.setPrefHeight(36);
|
||||||
|
|
||||||
// در ابتدای همان لیست اصلیِ چتها
|
|
||||||
chatListContainer.getChildren().add(0, headerRow);
|
chatListContainer.getChildren().add(0, headerRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1355,7 +1345,6 @@ public class MainController {
|
|||||||
public void refreshArchivedListUI() {
|
public void refreshArchivedListUI() {
|
||||||
chatListContainer.getChildren().clear();
|
chatListContainer.getChildren().clear();
|
||||||
|
|
||||||
// Back row (بماند)
|
|
||||||
HBox backRow = new HBox();
|
HBox backRow = new HBox();
|
||||||
Label back = new Label("← Back to Active");
|
Label back = new Label("← Back to Active");
|
||||||
back.getStyleClass().add("archived-back");
|
back.getStyleClass().add("archived-back");
|
||||||
@@ -1367,10 +1356,9 @@ public class MainController {
|
|||||||
backRow.setStyle("-fx-padding: 6 10 8 10;");
|
backRow.setStyle("-fx-padding: 6 10 8 10;");
|
||||||
chatListContainer.getChildren().add(backRow);
|
chatListContainer.getChildren().add(backRow);
|
||||||
|
|
||||||
// ✅ از همین سلساز FXML استفاده کن تا دقیقا همشکل اکتیو باشد
|
|
||||||
if (Session.archivedChats != null && !Session.archivedChats.isEmpty()) {
|
if (Session.archivedChats != null && !Session.archivedChats.isEmpty()) {
|
||||||
for (ChatEntry e : Session.archivedChats) {
|
for (ChatEntry e : Session.archivedChats) {
|
||||||
addChatNode(e); // ⬅️ همونی که در اکتیو استفاده میکنی
|
addChatNode(e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Label empty = new Label("No archived chats");
|
Label empty = new Label("No archived chats");
|
||||||
@@ -1381,31 +1369,27 @@ public class MainController {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ساخت یک سل آیتم (برای اکتیو/آرشیو)
|
|
||||||
private HBox buildChatCell(ChatEntry e, boolean archivedView) {
|
private HBox buildChatCell(ChatEntry e, boolean archivedView) {
|
||||||
HBox row = new HBox(8);
|
HBox row = new HBox(8);
|
||||||
ImageView avatar = new ImageView(); avatar.setFitWidth(36); avatar.setFitHeight(36);
|
ImageView avatar = new ImageView(); avatar.setFitWidth(36); avatar.setFitHeight(36);
|
||||||
// ... لود تصویر از e.getImageUrl() اگر داری
|
|
||||||
Label name = new Label(e.getName());
|
Label name = new Label(e.getName());
|
||||||
Region spacer = new Region(); HBox.setHgrow(spacer, javafx.scene.layout.Priority.ALWAYS);
|
Region spacer = new Region(); HBox.setHgrow(spacer, javafx.scene.layout.Priority.ALWAYS);
|
||||||
Label last = new Label(safeLastLine(e)); // آخرین پیام/زمان (اختیاری)
|
Label last = new Label(safeLastLine(e));
|
||||||
|
|
||||||
row.getChildren().addAll(avatar, name, spacer, last);
|
row.getChildren().addAll(avatar, name, spacer, last);
|
||||||
row.getStyleClass().add("chat-row");
|
row.getStyleClass().add("chat-row");
|
||||||
|
|
||||||
// کلیک روی آیتم → openChat
|
|
||||||
row.setOnMouseClicked(ev -> openChat(e));
|
row.setOnMouseClicked(ev -> openChat(e));
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String safeLastLine(ChatEntry e) {
|
private String safeLastLine(ChatEntry e) {
|
||||||
String s = e.getLastMessagePreview(); // اگر داری
|
String s = e.getLastMessagePreview();
|
||||||
return s != null ? s : "";
|
return s != null ? s : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// title fallback: اول name بعد displayId، در نهایت پیشفرض
|
|
||||||
private String safeTitle(ChatEntry e) {
|
private String safeTitle(ChatEntry e) {
|
||||||
if (e.getName() != null && !e.getName().isBlank()) return e.getName();
|
if (e.getName() != null && !e.getName().isBlank()) return e.getName();
|
||||||
if (e.getDisplayId() != null && !e.getDisplayId().isBlank()) return e.getDisplayId();
|
if (e.getDisplayId() != null && !e.getDisplayId().isBlank()) return e.getDisplayId();
|
||||||
@@ -1413,7 +1397,6 @@ public class MainController {
|
|||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
// image fallback: اگر خالی بود، آواتار پیشفرض
|
|
||||||
private String safeImage(String img) {
|
private String safeImage(String img) {
|
||||||
return (img != null && !img.isBlank())
|
return (img != null && !img.isBlank())
|
||||||
? img
|
? img
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
Reference in New Issue
Block a user