From cc9dcf2ac882ec02343c44a3d1825515bc7c290d Mon Sep 17 00:00:00 2001 From: Asal Lotfi Date: Wed, 3 Sep 2025 14:12:21 +0330 Subject: [PATCH] Settings UI implemented. --- .../UI/EditProfileController.java | 37 +--- .../UI/MainController.java | 27 ++- .../UI/SettingsController.java | 160 ++++++++++++++++++ .../UI/SidebarMenuController.java | 16 +- .../telegramfinalproject/CSS/dark_theme.css | 138 +++++++++++++++ .../telegramfinalproject/CSS/light_theme.css | 138 +++++++++++++++ .../to/telegramfinalproject/Fxml/main.fxml | 6 +- .../telegramfinalproject/Fxml/settings.fxml | 132 +++++++++++++++ .../telegramfinalproject/Icons/lock_dark.png | Bin 0 -> 305 bytes .../telegramfinalproject/Icons/lock_light.png | Bin 0 -> 260 bytes .../to/telegramfinalproject/Icons/log_out.png | Bin 0 -> 553 bytes 11 files changed, 617 insertions(+), 37 deletions(-) create mode 100644 src/main/java/org/to/telegramfinalproject/UI/SettingsController.java create mode 100644 src/main/resources/org/to/telegramfinalproject/Fxml/settings.fxml create mode 100644 src/main/resources/org/to/telegramfinalproject/Icons/lock_dark.png create mode 100644 src/main/resources/org/to/telegramfinalproject/Icons/lock_light.png create mode 100644 src/main/resources/org/to/telegramfinalproject/Icons/log_out.png diff --git a/src/main/java/org/to/telegramfinalproject/UI/EditProfileController.java b/src/main/java/org/to/telegramfinalproject/UI/EditProfileController.java index e98e0c5..de8eba8 100644 --- a/src/main/java/org/to/telegramfinalproject/UI/EditProfileController.java +++ b/src/main/java/org/to/telegramfinalproject/UI/EditProfileController.java @@ -46,7 +46,10 @@ public class EditProfileController { overlayBackground.setOnMouseClicked(e -> closeEdit()); closeButton.setOnAction(e -> closeEdit()); - backButton.setOnAction(e -> goBackToProfile()); + + backButton.setOnAction(e -> { + MainController.getInstance().goBack(overlayBackground); + }); // Load your camera icon image (white camera icon for visibility) cameraIcon.setImage(new Image( @@ -101,38 +104,6 @@ public class EditProfileController { 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); diff --git a/src/main/java/org/to/telegramfinalproject/UI/MainController.java b/src/main/java/org/to/telegramfinalproject/UI/MainController.java index b1ccaf8..95e3687 100644 --- a/src/main/java/org/to/telegramfinalproject/UI/MainController.java +++ b/src/main/java/org/to/telegramfinalproject/UI/MainController.java @@ -61,6 +61,9 @@ public class MainController { @FXML private ImageView menuIcon; private SidebarMenuController sidebarController; //save sidebar controller + // === Overlay === + @FXML private StackPane overlayLayer; + // === Time formatter for messages === private static final java.time.format.DateTimeFormatter FMT_HHMM = java.time.format.DateTimeFormatter.ofPattern("HH:mm"); @@ -83,6 +86,9 @@ public class MainController { public static MainController getInstance() { return instance; } + + // Keep track of the scene user comes from + private final Deque navigationStack = new ArrayDeque<>(); private final Map itemControllers = new HashMap<>(); @@ -562,13 +568,30 @@ public class MainController { // === Overlay Handling === public void showOverlay(Node overlayNode) { - mainRoot.getChildren().add(overlayNode); + if (!overlayLayer.getChildren().isEmpty()) { + Node current = overlayLayer.getChildren().get(overlayLayer.getChildren().size() - 1); + navigationStack.push(current); + overlayLayer.getChildren().remove(current); + } + overlayLayer.getChildren().add(overlayNode); } public void closeOverlay(Node overlayNode) { - mainRoot.getChildren().remove(overlayNode); + overlayLayer.getChildren().remove(overlayNode); } + public void goBack(Pane currentOverlay) { + // Remove the current overlay + closeOverlay(currentOverlay); + + if (!navigationStack.isEmpty()) { + Node previous = navigationStack.pop(); + + // Clear existing overlays before showing previous + overlayLayer.getChildren().clear(); + overlayLayer.getChildren().add(previous); + } + } // ===== Search UI state ===== private final java.util.List searchBacking = new java.util.ArrayList<>(); diff --git a/src/main/java/org/to/telegramfinalproject/UI/SettingsController.java b/src/main/java/org/to/telegramfinalproject/UI/SettingsController.java new file mode 100644 index 0000000..494fa02 --- /dev/null +++ b/src/main/java/org/to/telegramfinalproject/UI/SettingsController.java @@ -0,0 +1,160 @@ +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.*; +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; + +import java.io.IOException; +import java.net.URL; + +public class SettingsController { + + @FXML private VBox settingsCard; + @FXML private ImageView profileImage; + @FXML private Label profileName; + @FXML private Label profileId; + @FXML private MenuButton menuButton; + @FXML private MenuItem editProfileItem; + @FXML private MenuItem logoutItem; + @FXML private Button myAccountButton; + @FXML private Button privacyButton; + @FXML private Button faqButton; + @FXML private Button featuresButton; + @FXML private Pane overlayBackground; + @FXML private Button closeButton; + + private static final String ICON_PATH = "/org/to/telegramfinalproject/Icons/"; + + @FXML + public void initialize() { + 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") + )); + + // Make it circular + Circle clip = new Circle(48, 28, 38); // centerX, centerY, radius + profileImage.setClip(clip); + + // Buttons + myAccountButton.setOnAction(e -> openEditProfile()); + + privacyButton.setOnAction(e -> System.out.println("Privacy and Security")); + faqButton.setOnAction(e -> System.out.println("Telegram Q&A")); + featuresButton.setOnAction(e -> System.out.println("Telegram Features")); + + // Close overlay on background click + overlayBackground.setOnMouseClicked(e -> + MainController.getInstance().closeOverlay(settingsCard.getParent())); + + closeButton.setOnAction(e -> + MainController.getInstance().closeOverlay(settingsCard.getParent()) + ); + + // Register scene for ThemeManager → stylesheet swap will handle colors/icons + Platform.runLater(() -> { + if (settingsCard.getScene() != null) { + ThemeManager.getInstance().registerScene(settingsCard.getScene()); + } + }); + + // Listener for theme change + ThemeManager.getInstance().darkModeProperty().addListener((obs, oldVal, newVal) -> { + updateEditIcon(newVal); + updateMoreIcon(newVal); + updateButtonsIcons(newVal); + }); + + // Set initial state + updateEditIcon(ThemeManager.getInstance().isDarkMode()); + updateMoreIcon(ThemeManager.getInstance().isDarkMode()); + updateButtonsIcons(ThemeManager.getInstance().isDarkMode()); + } + + 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(); + controller.setProfileData( + profileName.getText(), + "online", + "Pass me that lovely little gun♡.", + "@Whales_suicide", + profileImage.getImage() + ); + + MainController.getInstance().showOverlay(editOverlay); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + private void updateEditIcon(boolean darkMode) { + String editPath = darkMode + ? "/org/to/telegramfinalproject/Icons/edit_light.png" + : "/org/to/telegramfinalproject/Icons/edit_dark.png"; + + ImageView icon = new ImageView(new Image(getClass().getResourceAsStream(editPath))); + icon.setFitWidth(16); + icon.setFitHeight(16); + editProfileItem.setGraphic(icon); + } + + private void updateMoreIcon(boolean darkMode) { + String morePath = darkMode + ? "/org/to/telegramfinalproject/Icons/more_light.png" + : "/org/to/telegramfinalproject/Icons/more_dark.png"; + + ImageView icon = new ImageView(new Image(getClass().getResourceAsStream(morePath))); + icon.setFitWidth(16); + icon.setFitHeight(16); + menuButton.setGraphic(icon); + } + + private void updateButtonsIcons(boolean darkMode) { + String suffix = darkMode ? "_light.png" : "_dark.png"; + myAccountButton.setGraphic(makeIcon(ICON_PATH + "my_profile" + suffix)); + privacyButton.setGraphic(makeIcon(ICON_PATH + "lock" + suffix)); + faqButton.setGraphic(makeIcon(ICON_PATH + "telegram_features" + suffix)); + featuresButton.setGraphic(makeIcon(ICON_PATH + "telegram_qna" + suffix)); + } + + // --- helpers ------------------------------------------------------------- + + private ImageView makeIcon(String path) { + ImageView iv = new ImageView(); + Image img = loadImage(path); + if (img != null) { + iv.setImage(img); + iv.setFitWidth(22); + iv.setFitHeight(22); + iv.setPreserveRatio(true); + } + return iv; + } + + private Image loadImage(String path) { + URL res = getClass().getResource(path); + if (res == null) { + System.err.println("Resource not found: " + path); + return null; + } + return new Image(res.toExternalForm()); + } +} diff --git a/src/main/java/org/to/telegramfinalproject/UI/SidebarMenuController.java b/src/main/java/org/to/telegramfinalproject/UI/SidebarMenuController.java index 08208fc..696529d 100644 --- a/src/main/java/org/to/telegramfinalproject/UI/SidebarMenuController.java +++ b/src/main/java/org/to/telegramfinalproject/UI/SidebarMenuController.java @@ -239,7 +239,21 @@ public class SidebarMenuController { } private void openSavedMessages() { System.out.println("Opening Saved Messages..."); } - private void openSettings() { System.out.println("Opening Settings..."); } + + private void openSettings() { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource( + "/org/to/telegramfinalproject/Fxml/settings.fxml")); + Node settingsOverlay = loader.load(); + + // Show overlay on top of everything + MainController.getInstance().showOverlay(settingsOverlay); + + } catch (IOException e) { + e.printStackTrace(); + } + } + private void openTelegramFeatures() { System.out.println("Opening Telegram Features..."); } private void openTelegramQnA() { System.out.println("Opening Telegram Q&A..."); } diff --git a/src/main/resources/org/to/telegramfinalproject/CSS/dark_theme.css b/src/main/resources/org/to/telegramfinalproject/CSS/dark_theme.css index 60b6b8c..6530b57 100644 --- a/src/main/resources/org/to/telegramfinalproject/CSS/dark_theme.css +++ b/src/main/resources/org/to/telegramfinalproject/CSS/dark_theme.css @@ -760,3 +760,141 @@ .channel-desc-area .content { -fx-background-color: #1f2a36; } + +.settings-card { + -fx-background-color: #1f2a36; + -fx-background-radius: 8; + -fx-padding: 12; +} + +.settings-avatar { + -fx-fit-width: 56px; + -fx-fit-height: 56px; +} + +.settings-name { + -fx-font-size: 16px; + -fx-font-weight: bold; + -fx-text-fill: #ffffff; +} + +.settings-id { + -fx-font-size: 13px; + -fx-text-fill: #aaaaaa; +} + +.settings-option { + -fx-background-color: transparent; + -fx-text-fill: #ffffff; + -fx-font-size: 14px; + -fx-alignment: CENTER_LEFT; +} + +.settings-option:hover { + -fx-background-color: #253544; +} + +.settings-menu { + -fx-background-color: transparent; + -fx-font-size: 18px; + -fx-text-fill: #eeeeee; +} + +.settings-header { + -fx-padding: 8 12; + -fx-border-color: -fx-box-border; + -fx-border-width: 0 0 1 0; /* bottom border only */ +} + +.settings-title { + -fx-font-size: 15px; + -fx-font-weight: bold; + -fx-text-fill: #fff; +} + +.icon-button { + -fx-background-color: transparent; + -fx-padding: 0; +} + +.icon-button:hover { + -fx-background-color: rgba(0,0,0,0.05); + -fx-background-radius: 50%; +} + +/* Profile header */ +.profile-header { + -fx-padding: 12 16; +} + +.profile-avatar { + -fx-background-radius: 50%; + -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 4, 0.3, 0, 1); +} + +.profile-name { + -fx-font-size: 14px; + -fx-font-weight: bold; + -fx-text-fill: #fff; +} + +.profile-id { + -fx-font-size: 12px; + -fx-text-fill: #aaa; +} + +/* Hide MenuButton text & arrow */ +.icon-button > .label { + -fx-padding: 0; + -fx-text-fill: transparent; +} + +.icon-button > .arrow-button, +.icon-button > .arrow { + -fx-padding: 0; + -fx-shape: null; /* removes arrow shape */ + -fx-background-color: transparent; + -fx-opacity: 0; +} + +.icon-image { + -fx-smooth: true; /* keeps scaling smooth */ + -fx-opacity: 0.8; /* slightly dim until hover */ +} + +.icon-image:hover { + -fx-opacity: 1.0; /* brighten on hover */ +} + +/* Container for all settings buttons */ +.settings-options { + -fx-background-color: transparent; + -fx-spacing: 4; + -fx-padding: 8 0 8 0; + -fx-border-color: #2a3b47; + -fx-border-width: 0 0 0 0; /* thin top border */ +} + +/* Settings action buttons */ +.settings-option { + -fx-background-color: transparent; + -fx-text-fill: #ddd; + -fx-font-size: 14px; + -fx-alignment: CENTER_LEFT; + -fx-padding: 10 14; + -fx-background-radius: 6; + -fx-cursor: hand; + + /* space between icon and text */ + -fx-graphic-text-gap: 10px; +} + +/* Hover effect */ +.settings-option:hover { + -fx-background-color: #2c3e50; +} + +/* Pressed effect */ +.settings-option:pressed { + -fx-background-color: #1f2a36; +} diff --git a/src/main/resources/org/to/telegramfinalproject/CSS/light_theme.css b/src/main/resources/org/to/telegramfinalproject/CSS/light_theme.css index 9421837..c82925e 100644 --- a/src/main/resources/org/to/telegramfinalproject/CSS/light_theme.css +++ b/src/main/resources/org/to/telegramfinalproject/CSS/light_theme.css @@ -763,3 +763,141 @@ -fx-background-color: #fff; } +.settings-card { + -fx-background-color: #ffffff; + -fx-background-radius: 8; + -fx-padding: 12; +} + +.settings-avatar { + -fx-fit-width: 56px; + -fx-fit-height: 56px; +} + +.settings-name { + -fx-font-size: 16px; + -fx-font-weight: bold; + -fx-text-fill: #000000; +} + +.settings-id { + -fx-font-size: 13px; + -fx-text-fill: #666666; +} + +.settings-option { + -fx-background-color: transparent; + -fx-text-fill: #000000; + -fx-font-size: 14px; + -fx-alignment: CENTER_LEFT; +} + +.settings-option:hover { + -fx-background-color: #f1f1f1; +} + +.settings-menu { + -fx-background-color: transparent; + -fx-font-size: 18px; + -fx-text-fill: #333333; +} + +.settings-header { + -fx-padding: 8 12; + -fx-border-color: -fx-box-border; + -fx-border-width: 0 0 1 0; /* bottom border only */ +} + +.settings-title { + -fx-font-size: 15px; + -fx-font-weight: bold; + -fx-text-fill: -fx-text-base-color; +} + +.icon-button { + -fx-background-color: transparent; + -fx-padding: 0; +} + +.icon-button:hover { + -fx-background-color: rgba(0,0,0,0.05); + -fx-background-radius: 50%; +} + +/* Profile header */ +.profile-header { + -fx-padding: 12 16; +} + +.profile-avatar { + -fx-background-radius: 50%; + -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 4, 0.3, 0, 1); +} + +.profile-name { + -fx-font-size: 14px; + -fx-font-weight: bold; + -fx-text-fill: -fx-text-base-color; +} + +.profile-id { + -fx-font-size: 12px; + -fx-text-fill: #888; +} + +/* Hide MenuButton text & arrow */ +.icon-button > .label { + -fx-padding: 0; + -fx-text-fill: transparent; +} + +.icon-button > .arrow-button, +.icon-button > .arrow { + -fx-padding: 0; + -fx-shape: null; /* removes arrow shape */ + -fx-background-color: transparent; + -fx-opacity: 0; +} + +.icon-image { + -fx-smooth: true; /* keeps scaling smooth */ + -fx-opacity: 0.8; /* slightly dim until hover */ +} + +.icon-image:hover { + -fx-opacity: 1.0; /* brighten on hover */ +} + +/* Container for all settings buttons */ +.settings-options { + -fx-background-color: transparent; + -fx-spacing: 4; + -fx-padding: 8 0 8 0; + -fx-border-color: #e6e6e6; + -fx-border-width: 0 0 0 0; /* thin top border */ +} + +/* Settings action buttons */ +.settings-option { + -fx-background-color: transparent; + -fx-text-fill: #222; + -fx-font-size: 14px; + -fx-alignment: CENTER_LEFT; + -fx-padding: 10 14; + -fx-background-radius: 6; + -fx-cursor: hand; + + /* space between icon and text */ + -fx-graphic-text-gap: 10px; +} + +/* Hover effect */ +.settings-option:hover { + -fx-background-color: #f2f2f2; +} + +/* Pressed effect */ +.settings-option:pressed { + -fx-background-color: #e0e0e0; +} + diff --git a/src/main/resources/org/to/telegramfinalproject/Fxml/main.fxml b/src/main/resources/org/to/telegramfinalproject/Fxml/main.fxml index 4299c06..d3faff1 100644 --- a/src/main/resources/org/to/telegramfinalproject/Fxml/main.fxml +++ b/src/main/resources/org/to/telegramfinalproject/Fxml/main.fxml @@ -166,11 +166,15 @@ - + + + + diff --git a/src/main/resources/org/to/telegramfinalproject/Fxml/settings.fxml b/src/main/resources/org/to/telegramfinalproject/Fxml/settings.fxml new file mode 100644 index 0000000..ea80770 --- /dev/null +++ b/src/main/resources/org/to/telegramfinalproject/Fxml/settings.fxml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/to/telegramfinalproject/Icons/lock_dark.png b/src/main/resources/org/to/telegramfinalproject/Icons/lock_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..80c4ceb600e89716456dcb5247f9294bc0b5565a GIT binary patch literal 305 zcmV-10nYx3P)A^qgu~co@;e7xCvY(FxgI@D0>m zQ$<4vXhe)+lO{L0?fH6dn>x<7&G-E-fCYdR$)h=d2*5lDg3epwB!>VJlBY5U5Uc9o zoywC;XrrnV&+~fbcFx_!wO#^Xc@sC$;=Sv-eUjTOX7)0GI<*1e(dW2E{${=io2VLi~#JaCWqA%m0IpofCauP&K#t%uc@8)zW`MoTl39DBy1dj z++>wC^Y;NF5}I(;y#Ica+XKL-SA|@cUHY+Q=d{hvN3F++IGvGF00000NkvXXu0mjf DXD5W$ literal 0 HcmV?d00001 diff --git a/src/main/resources/org/to/telegramfinalproject/Icons/lock_light.png b/src/main/resources/org/to/telegramfinalproject/Icons/lock_light.png new file mode 100644 index 0000000000000000000000000000000000000000..bf04fb03cf6482c8fa5cb758d978161ba0d4b42c GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-#WqhD z$B>FScc<729a0czeYxd;^ov@d%sn0U$9uvI_ww#+yj9OPQ&&St*!-l%zL{$)^6e8O zdwy8bn!K?Dn-uHjMx6cthVEj2eP(!iqLi+T%ab^o<%i6C>iUj(A!PC{xWt~$( F69B7TW2^uG literal 0 HcmV?d00001 diff --git a/src/main/resources/org/to/telegramfinalproject/Icons/log_out.png b/src/main/resources/org/to/telegramfinalproject/Icons/log_out.png new file mode 100644 index 0000000000000000000000000000000000000000..e7f7fc882cb182dda2c5833ecbc313875ab4cecd GIT binary patch literal 553 zcmV+^0@nSBP)-fZZu5)bpY>6V_w9W`Pk+;8GUce zhAKcvn?&aQD6N1KRe+H5wWWR=Qc5HC(AuXCIITf^E;J>;ujwCzpK8YU)~*Tgbvli- zQ|ON+E+VKRcN{rzWUn%2yKw+fl>wFoKmaS`k5Gk5(liRd7sZN@-=|uPO2}8uS^@G~ ztxwW{NCi+D!(dt+BIPD7ftNE7z;Eevx{awqr8dMo0OOOi7q!VFtA(o5JOB>(l&D)B z!~uBdV^RS0qX2{k%mE)7n?eyzv1&mSy@?GMQq&z1|(>;omE7t00000NkvXXu0mjf4;ks| literal 0 HcmV?d00001