Editing profile UI implemented.
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
package org.to.telegramfinalproject.UI;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
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.stage.FileChooser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class EditProfileController {
|
||||
|
||||
@FXML private Pane overlayBackground;
|
||||
@FXML private VBox editCard;
|
||||
|
||||
@FXML private Button backButton;
|
||||
@FXML private Button closeButton;
|
||||
|
||||
@FXML private ImageView profileImageView;
|
||||
@FXML private ImageView cameraIcon;
|
||||
@FXML private Button cameraButton;
|
||||
@FXML private Label profileName;
|
||||
@FXML private Label profileStatus;
|
||||
|
||||
@FXML private TextField nameField;
|
||||
@FXML private TextField bioField;
|
||||
@FXML private TextField usernameField;
|
||||
|
||||
@FXML
|
||||
private void initialize() {
|
||||
backButton.setGraphic(new ImageView(
|
||||
new Image(getClass().getResourceAsStream("/org/to/telegramfinalproject/Icons/back_button_dark.png"))
|
||||
));
|
||||
|
||||
// close on background click
|
||||
overlayBackground.setOnMouseClicked(e -> closeEdit());
|
||||
|
||||
closeButton.setOnAction(e -> closeEdit());
|
||||
backButton.setOnAction(e -> goBackToProfile());
|
||||
|
||||
// Load your camera icon image (white camera icon for visibility)
|
||||
cameraIcon.setImage(new Image(
|
||||
Objects.requireNonNull(getClass().getResourceAsStream(
|
||||
"/org/to/telegramfinalproject/Icons/camera.png"))
|
||||
));
|
||||
|
||||
// Handle click to open file chooser
|
||||
cameraButton.setOnMouseClicked(e -> openImageChooser());
|
||||
|
||||
// Register scene for ThemeManager → stylesheet swap will handle colors/icons
|
||||
Platform.runLater(() -> {
|
||||
if (editCard.getScene() != null) {
|
||||
ThemeManager.getInstance().registerScene(editCard.getScene());
|
||||
}
|
||||
});
|
||||
|
||||
// Listener for theme change
|
||||
ThemeManager.getInstance().darkModeProperty().addListener((obs, oldVal, newVal) -> {
|
||||
updateBackIcon(newVal);
|
||||
});
|
||||
|
||||
// Set initial state
|
||||
updateBackIcon(ThemeManager.getInstance().isDarkMode());
|
||||
}
|
||||
|
||||
private void updateBackIcon(boolean darkMode) {
|
||||
String iconPath = darkMode
|
||||
? "/org/to/telegramfinalproject/Icons/back_button_light.png"
|
||||
: "/org/to/telegramfinalproject/Icons/back_button_dark.png";
|
||||
|
||||
ImageView icon = new ImageView(new Image(getClass().getResourceAsStream(iconPath)));
|
||||
icon.setFitWidth(16);
|
||||
icon.setFitHeight(16);
|
||||
backButton.setGraphic(icon);
|
||||
}
|
||||
|
||||
private void openImageChooser() {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.getExtensionFilters().addAll(
|
||||
new FileChooser.ExtensionFilter("Image Files", "*.png", "*.jpg", "*.jpeg")
|
||||
);
|
||||
File file = fileChooser.showOpenDialog(profileImageView.getScene().getWindow());
|
||||
|
||||
if (file != null) {
|
||||
profileImageView.setImage(new Image(file.toURI().toString()));
|
||||
// TODO: save this new image to DB or server
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEdit() {
|
||||
MainController.getInstance().closeOverlay(editCard.getParent());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void goBackToProfile() {
|
||||
// Close edit overlay
|
||||
MainController.getInstance().closeOverlay(editCard.getParent());
|
||||
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource(
|
||||
"/org/to/telegramfinalproject/Fxml/my_profile.fxml"));
|
||||
Node profileOverlay = loader.load();
|
||||
|
||||
// Get the controller for the loaded MyProfile scene
|
||||
MyProfileController controller = loader.getController();
|
||||
|
||||
// Pass updated data from edit fields
|
||||
controller.setProfileData(
|
||||
nameField.getText(),
|
||||
"online",
|
||||
bioField.getText(),
|
||||
usernameField.getText(),
|
||||
profileImageView.getImage() != null ?
|
||||
profileImageView.getImage().getUrl() :
|
||||
"/org/to/telegramfinalproject/Avatars/default_profile.png"
|
||||
);
|
||||
|
||||
// Show updated MyProfile overlay
|
||||
MainController.getInstance().showOverlay(profileOverlay);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void setProfileData(String name, String status, String bio, String userId, Image profileImage) {
|
||||
profileStatus.setText(status);
|
||||
profileName.setText(name);
|
||||
nameField.setText(name);
|
||||
bioField.setText(bio != null ? bio : "");
|
||||
usernameField.setText(userId);
|
||||
profileImageView.setImage(profileImage);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package org.to.telegramfinalproject.UI;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.image.Image;
|
||||
@@ -10,6 +12,7 @@ import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.shape.Circle;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class MyProfileController {
|
||||
@@ -55,6 +58,9 @@ public class MyProfileController {
|
||||
|
||||
// Set initial state
|
||||
updateEditIcon(ThemeManager.getInstance().isDarkMode());
|
||||
|
||||
// === Open edit profile ===
|
||||
editButton.setOnAction(e -> openEditProfile());
|
||||
}
|
||||
|
||||
private void closeProfile() {
|
||||
@@ -93,4 +99,30 @@ public class MyProfileController {
|
||||
icon.setFitHeight(16);
|
||||
editButton.setGraphic(icon);
|
||||
}
|
||||
|
||||
private void openEditProfile() {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource(
|
||||
"/org/to/telegramfinalproject/Fxml/edit_profile.fxml"));
|
||||
Node editOverlay = loader.load();
|
||||
|
||||
EditProfileController controller = loader.getController();
|
||||
// Pass current data (so fields are pre-filled)
|
||||
controller.setProfileData(
|
||||
profileName.getText(),
|
||||
profileStatus.getText(),
|
||||
userBio.isVisible() ? userBio.getText() : null,
|
||||
userId.getText(),
|
||||
profileImage.getImage()
|
||||
);
|
||||
|
||||
// Show new overlay
|
||||
MainController.getInstance().showOverlay(editOverlay);
|
||||
|
||||
// Close the current My Profile overlay
|
||||
closeProfile();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,3 +366,81 @@
|
||||
-fx-font-size: 11px;
|
||||
-fx-text-fill: #999;
|
||||
}
|
||||
|
||||
/* ===== Edit Profile Card ===== */
|
||||
.edit-profile-card {
|
||||
-fx-background-color: #0f1c26;
|
||||
-fx-background-radius: 10;
|
||||
-fx-padding: 16;
|
||||
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.6), 10, 0, 0, 4);
|
||||
}
|
||||
|
||||
/* ===== Header ===== */
|
||||
.edit-profile-title {
|
||||
-fx-font-size: 16px;
|
||||
-fx-font-weight: bold;
|
||||
-fx-text-fill: #eee;
|
||||
}
|
||||
|
||||
.edit-icon-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-cursor: hand;
|
||||
-fx-text-fill: #eee;
|
||||
-fx-font-size: 14px;
|
||||
-fx-padding: 4;
|
||||
}
|
||||
|
||||
/* ===== Profile Picture ===== */
|
||||
.edit-profile-picture {
|
||||
-fx-background-radius: 50%;
|
||||
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.5), 4, 0, 0, 1);
|
||||
}
|
||||
|
||||
/* ===== Inputs ===== */
|
||||
.edit-profile-input {
|
||||
-fx-background-color: #1e2a35; /* darker background */
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-radius: 6;
|
||||
-fx-border-color: #2e3c48;
|
||||
-fx-border-width: 1;
|
||||
-fx-padding: 6 10 6 10;
|
||||
-fx-font-size: 13px;
|
||||
-fx-text-fill: #eee;
|
||||
}
|
||||
|
||||
.edit-profile-input:focused {
|
||||
-fx-border-color: #42a5f5; /* bright blue focus */
|
||||
-fx-background-color: #253443;
|
||||
}
|
||||
|
||||
.edit-input-description {
|
||||
-fx-font-size: 11px;
|
||||
-fx-text-fill: #aaa;
|
||||
}
|
||||
|
||||
/* ===== Section Separators ===== */
|
||||
.edit-section-separator {
|
||||
-fx-background-color: #333;
|
||||
-fx-pref-height: 1;
|
||||
}
|
||||
|
||||
.profile-info-label {
|
||||
-fx-font-size: 14px;
|
||||
-fx-text-fill: #bbb; /* lighter gray for labels */
|
||||
-fx-font-weight: normal;
|
||||
}
|
||||
|
||||
.camera-button {
|
||||
-fx-background-color: #0088cc;
|
||||
-fx-background-radius: 50%;
|
||||
-fx-cursor: hand;
|
||||
-fx-padding: 4;
|
||||
-fx-border-color: white; /* white border to stand out */
|
||||
-fx-border-width: 2;
|
||||
-fx-border-radius: 50%;
|
||||
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.25), 4, 0, 0, 1);
|
||||
}
|
||||
|
||||
.camera-button:hover {
|
||||
-fx-background-color: #0077b6;
|
||||
}
|
||||
|
||||
@@ -364,3 +364,82 @@
|
||||
-fx-font-size: 11px;
|
||||
-fx-text-fill: #888;
|
||||
}
|
||||
|
||||
/* ===== Edit Profile Card ===== */
|
||||
.edit-profile-card {
|
||||
-fx-background-color: white;
|
||||
-fx-background-radius: 10;
|
||||
-fx-padding: 16;
|
||||
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.25), 10, 0, 0, 4);
|
||||
}
|
||||
|
||||
/* ===== Header ===== */
|
||||
.edit-profile-title {
|
||||
-fx-font-size: 16px;
|
||||
-fx-font-weight: bold;
|
||||
-fx-text-fill: #000;
|
||||
}
|
||||
|
||||
.edit-icon-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-cursor: hand;
|
||||
-fx-text-fill: #000;
|
||||
-fx-font-size: 14px;
|
||||
-fx-padding: 4;
|
||||
}
|
||||
|
||||
/* ===== Profile Picture ===== */
|
||||
.edit-profile-picture {
|
||||
-fx-background-radius: 50%;
|
||||
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 4, 0, 0, 1);
|
||||
}
|
||||
|
||||
/* ===== Inputs ===== */
|
||||
.edit-profile-input {
|
||||
-fx-background-color: #f5f5f5; /* light gray background */
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-radius: 6;
|
||||
-fx-border-color: #ddd;
|
||||
-fx-border-width: 1;
|
||||
-fx-padding: 6 10 6 10;
|
||||
-fx-font-size: 13px;
|
||||
-fx-text-fill: #222;
|
||||
}
|
||||
|
||||
|
||||
.edit-profile-input:focused {
|
||||
-fx-border-color: #2196f3; /* blue highlight on focus */
|
||||
-fx-background-color: #fff;
|
||||
}
|
||||
|
||||
.edit-input-description {
|
||||
-fx-font-size: 11px;
|
||||
-fx-text-fill: #666;
|
||||
}
|
||||
|
||||
/* ===== Section Separators ===== */
|
||||
.edit-section-separator {
|
||||
-fx-background-color: #ddd;
|
||||
-fx-pref-height: 1;
|
||||
}
|
||||
|
||||
.profile-info-label {
|
||||
-fx-font-size: 14px;
|
||||
-fx-text-fill: #444; /* darker gray for labels */
|
||||
-fx-font-weight: normal;
|
||||
}
|
||||
|
||||
.camera-button {
|
||||
-fx-background-color: #0088cc;
|
||||
-fx-background-radius: 50%;
|
||||
-fx-cursor: hand;
|
||||
-fx-padding: 4;
|
||||
-fx-border-color: white; /* white border to stand out */
|
||||
-fx-border-width: 2;
|
||||
-fx-border-radius: 50%;
|
||||
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.25), 4, 0, 0, 1);
|
||||
}
|
||||
|
||||
.camera-button:hover {
|
||||
-fx-background-color: #0077b6;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.lang.*?>
|
||||
<?import javafx.scene.image.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
|
||||
<StackPane styleClass="overlay-root" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="org.to.telegramfinalproject.UI.EditProfileController">
|
||||
<children>
|
||||
|
||||
<!-- Background (click to close) -->
|
||||
<Pane fx:id="overlayBackground" styleClass="overlay-background" />
|
||||
|
||||
<!-- Profile edit card -->
|
||||
<VBox fx:id="editCard" maxHeight="520" maxWidth="400" prefHeight="520" prefWidth="400" spacing="16" styleClass="edit-profile-card">
|
||||
<children>
|
||||
|
||||
<!-- ===== Header: Back + Title + Close ===== -->
|
||||
<HBox alignment="CENTER_LEFT" spacing="10">
|
||||
<children>
|
||||
<!-- Back button -->
|
||||
<Button fx:id="backButton" styleClass="edit-icon-button" />
|
||||
|
||||
<!-- Title -->
|
||||
<Label styleClass="edit-profile-title" text="Edit Profile" HBox.hgrow="ALWAYS" />
|
||||
|
||||
<!-- Spacer pushes close button to the right -->
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
|
||||
<!-- Close button -->
|
||||
<Button fx:id="closeButton" styleClass="edit-icon-button" text="✕" />
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<!-- ===== Profile picture with camera overlay + name/status ===== -->
|
||||
<VBox alignment="CENTER" spacing="2">
|
||||
|
||||
<!-- Profile picture + camera button -->
|
||||
<StackPane alignment="CENTER">
|
||||
<!-- Profile Picture -->
|
||||
<ImageView fx:id="profileImageView"
|
||||
fitWidth="100" fitHeight="100"
|
||||
preserveRatio="true"
|
||||
styleClass="edit-profile-picture"/>
|
||||
|
||||
<!-- Camera Button pinned bottom-center -->
|
||||
<Button fx:id="cameraButton"
|
||||
prefWidth="32" prefHeight="32"
|
||||
styleClass="camera-button"
|
||||
StackPane.alignment="BOTTOM_CENTER"
|
||||
translateX="30" translateY="5"> <!-- pushes down so it overlaps -->
|
||||
<graphic>
|
||||
<ImageView fx:id="cameraIcon"
|
||||
fitWidth="16" fitHeight="16"
|
||||
preserveRatio="true"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
</StackPane>
|
||||
|
||||
<!-- Name + Status -->
|
||||
<Label fx:id="profileName" text="User Name" styleClass="profile-name"/>
|
||||
<Label fx:id="profileStatus" text="online" styleClass="profile-status"/>
|
||||
|
||||
</VBox>
|
||||
|
||||
|
||||
<Separator styleClass="edit-section-separator" />
|
||||
|
||||
<!-- ===== Bio (full width field + description) ===== -->
|
||||
<VBox spacing="4">
|
||||
<children>
|
||||
<TextField fx:id="bioField" promptText="Bio" styleClass="edit-profile-input" />
|
||||
<Label styleClass="edit-input-description" text="Any details such as age, occupation, or city." />
|
||||
</children>
|
||||
</VBox>
|
||||
|
||||
<Separator styleClass="section-separator" />
|
||||
|
||||
<!-- ===== Name row (Label left, editable field right) ===== -->
|
||||
<VBox spacing="4">
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="10">
|
||||
<children>
|
||||
<Label styleClass="profile-info-label" text="Name" />
|
||||
<TextField fx:id="nameField" prefHeight="25.0" prefWidth="152.0" styleClass="edit-profile-input" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Label styleClass="edit-input-description" text="This is your profile name. It will be visible to your contacts." />
|
||||
</children>
|
||||
</VBox>
|
||||
|
||||
<Separator styleClass="section-separator" />
|
||||
|
||||
<!-- ===== Username row (Label left, editable field right) ===== -->
|
||||
<VBox spacing="4">
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="10">
|
||||
<children>
|
||||
<Label styleClass="profile-info-label" text="Username" />
|
||||
<TextField fx:id="usernameField" prefHeight="25.0" prefWidth="153.0" styleClass="edit-profile-input" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Label styleClass="edit-input-description" text="Username lets people contact you." />
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
</StackPane>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 173 B |
Binary file not shown.
|
After Width: | Height: | Size: 165 B |
Binary file not shown.
|
After Width: | Height: | Size: 288 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 985 B |
Reference in New Issue
Block a user