Merge remote-tracking branch 'origin/Main-UI' into Main-UI

This commit is contained in:
2025-09-03 17:31:57 +03:30
17 changed files with 682 additions and 42 deletions
@@ -29,6 +29,7 @@ public class AddMembersController {
private final Set<Contact> selectedContacts = new HashSet<>();
private String groupName;
private String groupId;
private File groupImageFile;
// Sample data for testing
@@ -239,8 +240,9 @@ public class AddMembersController {
searchIcon.setGraphic(icon);
}
public void setGroupInfo(String groupName, File groupImageFile) {
public void setGroupInfo(String groupName, String groupId, File groupImageFile) {
this.groupName = groupName;
this.groupId = groupId;
this.groupImageFile = groupImageFile;
// You can use these later when creating the group
@@ -29,6 +29,7 @@ public class AddSubscriberController {
private final Set<Contact> selectedContacts = new HashSet<>();
private String channelName;
private String channelId;
private File channelImageFile;
private String description;
@@ -201,8 +202,9 @@ public class AddSubscriberController {
searchIcon.setGraphic(icon);
}
public void setChannelInfo(String name, String description, File image) {
public void setChannelInfo(String name, String id, String description, File image) {
this.channelName = name;
this.channelId = id;
this.channelImageFile = image;
this.description = description;
}
@@ -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);
@@ -62,6 +62,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");
@@ -84,6 +87,9 @@ public class MainController {
public static MainController getInstance() {
return instance;
}
// Keep track of the scene user comes from
private final Deque<Node> navigationStack = new ArrayDeque<>();
private final Map<UUID, ChatItemController> itemControllers = new HashMap<>();
@@ -590,13 +596,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<SearchResult> searchBacking = new java.util.ArrayList<>();
@@ -30,6 +30,8 @@ public class NewChannelController {
@FXML private Button createButton;
@FXML private StackPane overlayRoot; // the root
@FXML private Label descCounter;
@FXML private Label channelIdLabel;
@FXML private TextField channelIdField;
private File channelImageFile;
@@ -67,6 +69,7 @@ public class NewChannelController {
// Create button → validate name + submit
createButton.setOnAction(e -> {
String channelName = channelNameField.getText().trim();
String channelId = channelIdField.getText().trim();
String description = channelDescField.getText().trim();
if (channelName.isEmpty()) {
@@ -76,6 +79,13 @@ public class NewChannelController {
return;
}
if (channelId.isEmpty()) {
// Apply error style
channelIdField.getStyleClass().add("error");
channelIdLabel.getStyleClass().add("error");
return;
}
try {
// Load Add Members overlay
FXMLLoader loader = new FXMLLoader(getClass().getResource(
@@ -84,7 +94,7 @@ public class NewChannelController {
// Pass channel info to AddMembersController
AddSubscriberController controller = loader.getController();
controller.setChannelInfo(channelName, description, channelImageFile);
controller.setChannelInfo(channelName, channelId, description, channelImageFile);
// Close the current "New Channel" overlay
MainController.getInstance().closeOverlay(overlayRoot);
@@ -133,6 +143,14 @@ public class NewChannelController {
}
});
// Reset error state when typing
channelIdField.textProperty().addListener((obs, oldVal, newVal) -> {
if (!newVal.trim().isEmpty()) {
channelIdField.getStyleClass().remove("error");
channelIdLabel.getStyleClass().remove("error");
}
});
// Auto-focus channel name on open
Platform.runLater(() -> channelNameField.requestFocus());
@@ -24,6 +24,8 @@ public class NewGroupController {
@FXML private Button cancelButton;
@FXML private Button nextButton;
@FXML private StackPane overlayRoot; // the root
@FXML private TextField groupIdField;
@FXML private Label groupIdLabel;
private File groupImageFile;
@@ -58,6 +60,7 @@ public class NewGroupController {
nextButton.setOnAction(e -> {
String groupName = groupNameField.getText().trim();
String groupId = groupIdField.getText().trim();
if (groupName.isEmpty()) {
// Apply error style
@@ -67,6 +70,14 @@ public class NewGroupController {
return;
}
if (groupId.isEmpty()) {
// Apply error style
groupIdField.getStyleClass().add("error");
groupIdLabel.getStyleClass().add("error");
return;
}
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"/org/to/telegramfinalproject/Fxml/add_member.fxml"));
@@ -74,7 +85,7 @@ public class NewGroupController {
// Optional: pass groupName and image to AddMembersController
AddMembersController controller = loader.getController();
controller.setGroupInfo(groupName, groupImageFile);
controller.setGroupInfo(groupName, groupId, groupImageFile);
// Close the current "New Group" overlay
MainController.getInstance().closeOverlay(overlayRoot);
@@ -87,6 +98,7 @@ public class NewGroupController {
}
});
// Reset error state when typing
groupNameField.textProperty().addListener((obs, oldVal, newVal) -> {
if (!newVal.trim().isEmpty()) {
groupNameField.getStyleClass().remove("error");
@@ -94,6 +106,14 @@ public class NewGroupController {
}
});
// Reset error state when typing
groupIdField.textProperty().addListener((obs, oldVal, newVal) -> {
if (!newVal.trim().isEmpty()) {
groupIdField.getStyleClass().remove("error");
groupIdLabel.getStyleClass().remove("error");
}
});
// Auto_focus search bar when overlay opens
Platform.runLater(() -> groupNameField.requestFocus());
}
@@ -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());
}
}
@@ -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..."); }
@@ -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;
}
@@ -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;
}
@@ -166,11 +166,15 @@
</items>
</SplitPane>
<!-- Overlay (for sidebar) -->
<!-- ===== Overlay background for sidebar only ===== -->
<Pane fx:id="overlay"
mouseTransparent="true"
onMouseClicked="#closeSidebar"
styleClass="overlay"
visible="false"/>
<!-- ===== Overlay layer for profile/settings/etc. ===== -->
<StackPane fx:id="overlayLayer"
pickOnBounds="false"/>
</children>
</StackPane>
@@ -17,7 +17,7 @@
spacing="16"
alignment="CENTER"
prefWidth="400" maxWidth="400"
prefHeight="280" maxHeight="280">
prefHeight="380" maxHeight="380">
<!-- Header Row: Picture + Name -->
<HBox alignment="CENTER_LEFT" spacing="12">
@@ -42,6 +42,15 @@
</VBox>
</HBox>
<!-- ID -->
<VBox spacing="4" alignment="CENTER_LEFT">
<Label fx:id="channelIdLabel" text="Channel ID" styleClass="group-name-label"/>
<TextField fx:id="channelIdField"
promptText="Enter channel ID"
styleClass="group-name-field"
HBox.hgrow="ALWAYS"/>
</VBox>
<!-- Channel Description -->
<VBox spacing="4" alignment="CENTER_LEFT">
<Label fx:id="channelDescLabel" text="Description (optional)" styleClass="group-name-label"/>
@@ -42,6 +42,15 @@
</VBox>
</HBox>
<!-- Group ID (below the name) -->
<VBox spacing="4" alignment="CENTER_LEFT">
<Label fx:id="groupIdLabel" text="Group ID" styleClass="group-name-label"/>
<TextField fx:id="groupIdField"
promptText="Enter group ID"
styleClass="group-name-field"
HBox.hgrow="ALWAYS"/>
</VBox>
<!-- Footer: Cancel + Next -->
<HBox alignment="CENTER_RIGHT" spacing="16">
<Button fx:id="cancelButton" text="Cancel" styleClass="footer-button"/>
@@ -0,0 +1,132 @@
<?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?>
<?import javafx.scene.image.Image?>
<StackPane styleClass="overlay-root" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="org.to.telegramfinalproject.UI.SettingsController">
<children>
<!-- Dimmed background -->
<Pane fx:id="overlayBackground" styleClass="overlay-background" />
<!-- Settings Card -->
<VBox fx:id="settingsCard" maxHeight="470" maxWidth="350" prefHeight="470" prefWidth="350" spacing="12" styleClass="settings-card">
<children>
<!-- ===== Header ===== -->
<HBox alignment="CENTER_RIGHT" spacing="10" styleClass="settings-header">
<children>
<Label styleClass="settings-title" text="Settings" />
<Region HBox.hgrow="ALWAYS" /> <!-- pushes buttons to the right -->
<!-- 3-dots Menu -->
<MenuButton fx:id="menuButton" styleClass="icon-button">
<graphic>
<ImageView fitHeight="18" fitWidth="18" pickOnBounds="true" preserveRatio="true" styleClass="icon-image">
<image>
<Image url="@/org/to/telegramfinalproject/Icons/more_dark.png" />
</image>
</ImageView>
</graphic>
<items>
<MenuItem fx:id="editProfileItem" text="Edit Profile">
<graphic>
<ImageView fitHeight="14" fitWidth="14" preserveRatio="true">
<image>
<Image url="@/org/to/telegramfinalproject/Icons/edit_dark.png" />
</image>
</ImageView>
</graphic>
</MenuItem>
<MenuItem fx:id="logoutItem" text="Log Out">
<graphic>
<ImageView fitHeight="14" fitWidth="14" preserveRatio="true">
<image>
<Image url="@/org/to/telegramfinalproject/Icons/log_out.png" />
</image>
</ImageView>
</graphic>
</MenuItem>
</items>
</MenuButton>
<!-- Close Button -->
<Button fx:id="closeButton" styleClass="icon-button" text="✕" />
</children>
</HBox>
<!-- ===== Profile Info ===== -->
<HBox alignment="CENTER_LEFT" spacing="12" styleClass="profile-header">
<children>
<!-- Profile Picture -->
<ImageView fx:id="profileImage" fitHeight="92" fitWidth="92" preserveRatio="true" styleClass="profile-avatar" />
<!-- Name + ID -->
<VBox alignment="CENTER_LEFT" spacing="2">
<children>
<Label fx:id="profileName" styleClass="profile-name" text="User Name" />
<Label fx:id="profileId" styleClass="profile-id" />
</children>
</VBox>
</children>
</HBox>
<Separator />
<!-- ===== Options ===== -->
<VBox spacing="8" styleClass="settings-options">
<children>
<!-- My Account -->
<Button fx:id="myAccountButton" prefHeight="25.0" prefWidth="361.0" styleClass="settings-option" text="My Account">
<graphic>
<ImageView fitWidth="25" fitHeight="25" preserveRatio="true">
<image>
<Image url="@/org/to/telegramfinalproject/Icons/my_profile_dark.png"/>
</image>
</ImageView>
</graphic>
</Button>
<!-- Privacy and Security -->
<Button fx:id="privacyButton" prefHeight="25.0" prefWidth="376.0" styleClass="settings-option" text="Privacy and Security">
<graphic>
<ImageView fitWidth="25" fitHeight="25" preserveRatio="true">
<image>
<Image url="@/org/to/telegramfinalproject/Icons/lock_dark.png"/>
</image>
</ImageView>
</graphic>
</Button>
<!-- Telegram Q&A -->
<Button fx:id="faqButton" prefHeight="25.0" prefWidth="390.0" styleClass="settings-option" text="Telegram Q&amp;A">
<graphic>
<ImageView fitWidth="25" fitHeight="25" preserveRatio="true">
<image>
<Image url="@/org/to/telegramfinalproject/Icons/telegram_qna_dark.png"/>
</image>
</ImageView>
</graphic>
</Button>
<!-- Telegram Features -->
<Button fx:id="featuresButton" prefHeight="25.0" prefWidth="370.0" styleClass="settings-option" text="Telegram Features">
<graphic>
<ImageView fitWidth="25" fitHeight="25" preserveRatio="true">
<image>
<Image url="@/org/to/telegramfinalproject/Icons/telegram_features_dark.png"/>
</image>
</ImageView>
</graphic>
</Button>
</children>
</VBox>
</children>
</VBox>
</children>
</StackPane>
Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B