Edit profile and username/Password from setting

This commit is contained in:
2025-09-05 00:12:25 +03:30
parent 9dbdf89831
commit fbdf10fb13
4 changed files with 241 additions and 87 deletions
@@ -4,13 +4,16 @@ import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.json.JSONObject;
import org.to.telegramfinalproject.Client.ActionHandler;
import org.to.telegramfinalproject.Client.Session;
public class ChangeCredentialsController {
@FXML private VBox credentialsCard;
@FXML private Pane overlayBackground;
@FXML private TextField usernameField;
@FXML private Label usernameLabel;
@@ -31,22 +34,21 @@ public class ChangeCredentialsController {
private boolean passwordVisible = false;
private boolean confirmVisible = false;
// ↓↓↓ متدی که از CheckPasswordController مقدار می‌گیرد
private String currentPassword;
public void setCurrentPassword(String p) { this.currentPassword = p; }
@FXML
private void initialize() {
// Toggle password visibility
togglePasswordBtn.setOnAction(e -> togglePasswordVisibility());
toggleConfirmBtn.setOnAction(e -> toggleConfirmVisibility());
saveButton.setOnAction(e -> validateAndSave());
// Close the overlay
closeButton.setOnAction(e ->
MainController.getInstance().closeOverlay(credentialsCard.getParent()));
cancelButton.setOnAction(e ->
MainController.getInstance().closeOverlay(credentialsCard.getParent()));
overlayBackground.setOnMouseClicked(e ->
MainController.getInstance().closeOverlay(credentialsCard.getParent())
);
// «ذخیره و بستن» مثل ادیت پروفایل
saveButton.setOnAction(e -> saveAndClose());
closeButton.setOnAction(e -> saveAndClose());
cancelButton.setOnAction(e -> saveAndClose());
overlayBackground.setOnMouseClicked(e -> saveAndClose());
// Reset error when typing
usernameField.textProperty().addListener((obs, o, n) -> removeError(usernameField, usernameLabel));
@@ -73,10 +75,19 @@ public class ChangeCredentialsController {
removeError(visibleConfirmPasswordField, confirmPasswordLabel);
});
// Auto_focus password field when overlay opens
Platform.runLater(() -> usernameField.requestFocus());
}
// ← از CheckPasswordController بلافاصله بعد از load صدا بزن
public void prefillFromSession() {
var u = Session.currentUser;
if (u == null) return;
String handle = u.optString("user_id",
u.optString("username",
u.optString("display_id","")));
usernameField.setText(handle);
}
private void togglePasswordVisibility() {
passwordVisible = !passwordVisible;
visiblePasswordField.setText(passwordField.getText());
@@ -101,47 +112,68 @@ public class ChangeCredentialsController {
toggleConfirmBtn.setText(confirmVisible ? "👁" : "👁");
}
private void validateAndSave() {
boolean hasError = false;
// ارسال تغییرات (در صورت پر بودن/تغییر) و بستن
private void saveAndClose() {
boolean anyError = false;
boolean sentSomething = false;
// --- Username check ---
if (usernameField.getText().trim().isEmpty()) {
addError(usernameField, usernameLabel);
hasError = true;
} else {
removeError(usernameField, usernameLabel);
// 1) یوزرنیم
var cu = Session.currentUser;
String oldUsername = cu != null ? cu.optString("user_id",
cu.optString("username",
cu.optString("display_id",""))) : "";
String newUsername = usernameField.getText().trim();
if (!newUsername.isEmpty() && !newUsername.equals(oldUsername)) {
sentSomething = true;
JSONObject req = new JSONObject()
.put("action", "update_username")
.put("current_password", currentPassword) // با اینکه سرور فعلاً چک نمی‌کند، می‌فرستیم
.put("new_username", newUsername);
JSONObject resp = ActionHandler.sendWithResponse(req);
if (resp == null || !"success".equalsIgnoreCase(resp.optString("status"))) {
anyError = true;
showError("Changing username failed",
resp != null ? resp.optString("message","Unknown error") : "No response");
} else {
if (cu != null) cu.put("user_id", newUsername);
}
}
// --- Password check ---
String pwd = passwordVisible ? visiblePasswordField.getText().trim() : passwordField.getText().trim();
if (pwd.isEmpty()) {
addError(passwordField, passwordLabel);
addError(visiblePasswordField, passwordLabel);
hasError = true;
} else {
removeError(passwordField, passwordLabel);
removeError(visiblePasswordField, passwordLabel);
// 2) پسورد
String newPwd = (passwordVisible ? visiblePasswordField.getText() : passwordField.getText()).trim();
String confirm = (confirmVisible ? visibleConfirmPasswordField.getText() : confirmPasswordField.getText()).trim();
if (!newPwd.isEmpty()) {
if (confirm.isEmpty() || !confirm.equals(newPwd)) {
addError(confirmPasswordField, confirmPasswordLabel);
addError(visibleConfirmPasswordField, confirmPasswordLabel);
return; // نذار بسته شه تا کاربر درست کنه
}
sentSomething = true;
JSONObject req = new JSONObject()
.put("action", "update_password")
.put("current_password", currentPassword)
.put("new_password", newPwd);
JSONObject resp = ActionHandler.sendWithResponse(req);
if (resp == null || !"success".equalsIgnoreCase(resp.optString("status"))) {
anyError = true;
showError("Changing password failed",
resp != null ? resp.optString("message","Unknown error") : "No response");
}
}
// --- Confirm password check ---
String confirm = confirmVisible ? visibleConfirmPasswordField.getText().trim() : confirmPasswordField.getText().trim();
if (confirm.isEmpty()) {
addError(confirmPasswordField, confirmPasswordLabel);
addError(visibleConfirmPasswordField, confirmPasswordLabel);
hasError = true;
} else if (!confirm.equals(pwd)) {
addError(confirmPasswordField, confirmPasswordLabel);
addError(visibleConfirmPasswordField, confirmPasswordLabel);
hasError = true;
} else {
removeError(confirmPasswordField, confirmPasswordLabel);
removeError(visibleConfirmPasswordField, confirmPasswordLabel);
// اگر چیزی نفرستادیم یا همه‌چیز OK بود → ببند و رفرش Settings
if (!sentSomething || !anyError) {
var sc = SettingsController.getInstance();
if (sc != null) sc.populateFromSession();
MainController.getInstance().closeOverlay(credentialsCard.getParent());
}
if (hasError) return;
// TODO: send to server
System.out.println("Saving new credentials...");
}
private void addError(TextField field, Label label) {
@@ -157,4 +189,15 @@ public class ChangeCredentialsController {
field.getStyleClass().remove("error-input");
label.getStyleClass().remove("error-label");
}
private void showError(String title, String msg) {
Alert a = new Alert(Alert.AlertType.ERROR);
a.setTitle(title);
a.setHeaderText(null);
a.setContentText(msg);
if (a.getDialogPane().getScene()!=null) {
ThemeManager.getInstance().registerScene(a.getDialogPane().getScene());
}
a.showAndWait();
}
}
@@ -98,26 +98,38 @@ public class CheckPasswordController {
}
private void validatePassword() {
String entered = passwordField.getText().trim();
String correct = "12345"; // demo only
String entered = (passwordVisible ? visiblePasswordField.getText() : passwordField.getText()).trim();
if (entered.isEmpty()) {
// استایل خطا مثل قبل
if (!passwordField.getStyleClass().contains("error"))
passwordField.getStyleClass().add("error");
if (!visiblePasswordField.getStyleClass().contains("error"))
visiblePasswordField.getStyleClass().add("error");
if (!passwordLabel.getStyleClass().contains("error"))
passwordLabel.getStyleClass().add("error");
return;
}
if (entered.equals(correct)) {
// Success → reset error styles
// تماس با سرور
org.json.JSONObject req = new org.json.JSONObject()
.put("action", "verify_password")
.put("current_password", entered);
org.json.JSONObject resp = org.to.telegramfinalproject.Client.ActionHandler.sendWithResponse(req);
boolean ok = (resp != null && "success".equalsIgnoreCase(resp.optString("status")));
if (ok) {
// پاک کردن خطاها
passwordField.getStyleClass().remove("error");
visiblePasswordField.getStyleClass().remove("error");
passwordLabel.getStyleClass().remove("error");
// Go to the next scene
openChangeCredentials();
openChangeCredentials(entered); // ← پسورد فعلی را پاس بده
} else {
// Error → add error styles
if (!passwordField.getStyleClass().contains("error"))
passwordField.getStyleClass().add("error");
if (!visiblePasswordField.getStyleClass().contains("error"))
visiblePasswordField.getStyleClass().add("error");
if (!passwordLabel.getStyleClass().contains("error"))
passwordLabel.getStyleClass().add("error");
}
@@ -146,15 +158,17 @@ public class CheckPasswordController {
backButton.setGraphic(icon);
}
private void openChangeCredentials() {
private void openChangeCredentials(String currentPassword) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"/org/to/telegramfinalproject/Fxml/change_credentials.fxml"));
Node overlay = loader.load();
// Show new overlay
MainController.getInstance().showOverlay(overlay);
ChangeCredentialsController c = loader.getController();
c.setCurrentPassword(currentPassword); // ← مهم
c.prefillFromSession(); // ← پیش‌پر کردن
MainController.getInstance().showOverlay(overlay);
} catch (IOException ex) {
ex.printStackTrace();
}
@@ -49,6 +49,13 @@ public class EditProfileController {
@FXML private TextField bioField;
@FXML private TextField usernameField;
// EditProfileController.java
private SettingsController parentSettings;
public void setParentSettings(SettingsController sc) {
this.parentSettings = sc;
}
@FXML
private void initialize() {
backButton.setGraphic(new ImageView(
@@ -56,19 +63,34 @@ public class EditProfileController {
));
// close on background click
// overlayBackground.setOnMouseClicked(e -> {
// saveChangesAndClose();
// closeEdit();
// });
//
// closeButton.setOnAction(e -> {
// saveChangesAndClose();
// closeEdit();
// });
//
// backButton.setOnAction(e -> {
// saveChangesAndClose();
// MainController.getInstance().goBack(overlayBackground);
// });
overlayBackground.setOnMouseClicked(e -> {
saveChangesAndClose();
closeEdit();
closeEdit(); // ← همینه
});
closeButton.setOnAction(e -> {
saveChangesAndClose();
closeEdit();
closeEdit(); // ← همینه
});
backButton.setOnAction(e -> {
saveChangesAndClose();
MainController.getInstance().goBack(overlayBackground);
closeEdit(); // ← قبلاً goBack بود
});
// Load your camera icon image (white camera icon for visibility)
@@ -122,7 +144,9 @@ public class EditProfileController {
private void closeEdit() {
//MainController.getInstance().closeOverlay(editCard.getParent());
MainController.getInstance().goBack(overlayBackground);
// MainController.getInstance().goBack(overlayBackground);
MainController.getInstance().closeOverlay(editCard.getParent());
}
@@ -233,21 +257,33 @@ public class EditProfileController {
}
if (!anyError) {
MyProfileController.getInstance().setProfileData(
currentUser.optString("profile_name"),
"online",
currentUser.optString("bio"),
currentUser.optString("user_id"),
currentUser.optString("image_url", "/org/to/telegramfinalproject/Avatars/default_user_profile.png")
// 1) اگر صفحه‌ی MyProfile باز است
var mp = MyProfileController.getInstance();
if (mp != null) {
mp.setProfileData(
currentUser.optString("profile_name"),
"online",
currentUser.optString("bio"),
currentUser.optString("user_id"),
currentUser.optString("image_url", "/org/to/telegramfinalproject/Avatars/default_user_profile.png")
);
}
// 2) خودِ کارت Settings را فوراً از Session ریفرش کن
if (parentSettings != null) {
parentSettings.populateFromSession();
}
);
// MainController mc = MainController.getInstance();
// 3) سایدبار بالایی (اسم/آواتار خود کاربر) اگر داری
MainController.getInstance().refreshSidebarUserFromSession();
MainController.getInstance().goBack(overlayBackground);
// MainController.getInstance().closeOverlay(bioField.getParent().getParent());
// 4) بستن اورلی ادیت
// MainController.getInstance().goBack(overlayBackground);
MainController.getInstance().closeOverlay(editCard.getParent());
}
}
private void showAlert(String title, String message, Alert.AlertType type) {
@@ -8,7 +8,6 @@ import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Circle;
@@ -33,17 +32,25 @@ public class SettingsController {
private static final String ICON_PATH = "/org/to/telegramfinalproject/Icons/";
private Image cachedAvatar;
private String cachedName = "";
private String cachedUsername = "";
private String cachedStatus = "";
private String cachedBio = "";
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 SettingsController instance;
public static SettingsController getInstance() { return instance; }
@FXML
public void initialize() {
instance = this;
editProfileItem.setOnAction(e -> openEditProfile());
logoutItem.setOnAction(e -> System.out.println("Log Out clicked"));
// Example data load from DB or user session later
profileName.setText("Asal");
profileId.setText("@Whales_suicide");
profileImage.setImage(new Image(
getClass().getResourceAsStream("/org/to/telegramfinalproject/Avatars/default_user_profile.png")
));
populateFromSession();
// Make it circular
Circle clip = new Circle(48, 28, 38); // centerX, centerY, radius
@@ -104,19 +111,20 @@ public class SettingsController {
EditProfileController controller = loader.getController();
controller.setProfileData(
profileName.getText(),
"online",
"Pass me that lovely little gun♡.",
"@Whales_suicide",
profileImage.getImage()
cachedName,
cachedStatus,
cachedBio,
cachedUsername,
cachedAvatar
);
controller.setParentSettings(this);
MainController.getInstance().showOverlay(editOverlay);
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void updateEditIcon(boolean darkMode) {
String editPath = darkMode
? "/org/to/telegramfinalproject/Icons/edit_light.png"
@@ -169,4 +177,57 @@ public class SettingsController {
}
return new Image(res.toExternalForm());
}
void populateFromSession() {
var u = org.to.telegramfinalproject.Client.Session.currentUser;
if (u == null) return;
// نام
String name = nz(u.optString("profile_name",
u.optString("name",
u.optString("first_name",""))));
// یوزرنیم/آی‌دی نمایشی
String handle = nz(u.optString("username",
u.optString("display_id",
u.optString("user_name",""))));
// وضعیت
String status = u.optBoolean("online", false) ? "online" : "online";
String lastSeen = nz(u.optString("last_seen", ""));
if (!u.optBoolean("online", false) && hasVal(lastSeen)) status = "online"; // ساده
// بیو (اگر داری)
String bio = nz(u.optString("bio",""));
// آواتار
Image avatar = null;
String imageUrl = nz(u.optString("image_url",""));
if (hasVal(imageUrl)) {
try { avatar = org.to.telegramfinalproject.Client.AvatarLocalResolver.load(imageUrl); }
catch (Exception ignore) {}
}
if (avatar == null) {
avatar = new Image(getClass().getResourceAsStream(
"/org/to/telegramfinalproject/Avatars/default_user_profile.png"));
}
// کش محلی برای استفاده در صفحه‌ی ویرایش
cachedName = hasVal(name) ? name : "User";
cachedUsername = hasVal(handle) ? handle : "";
cachedStatus = status;
cachedBio = bio;
cachedAvatar = avatar;
// ست کردن در UI
profileName.setText(cachedName);
profileId.setText(cachedUsername);
profileImage.setImage(cachedAvatar);
// گرد کردن تصویر (با توجه به اندازه‌ی واقعی)
Circle clip = new Circle(38, 38, 38); // centerX, centerY, radius
profileImage.setClip(clip);
}
}