Merge branch 'refs/heads/Main-UI' into Connection-UI
# Conflicts: # src/main/java/org/to/telegramfinalproject/UI/ChatItemController.java # src/main/java/org/to/telegramfinalproject/UI/MainController.java
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
package org.to.telegramfinalproject.UI;
|
package org.to.telegramfinalproject.UI;
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class ChatItemController {
|
public class ChatItemController {
|
||||||
|
|
||||||
@@ -15,13 +16,74 @@ public class ChatItemController {
|
|||||||
@FXML private Label lastMessage;
|
@FXML private Label lastMessage;
|
||||||
@FXML private Label chatTime;
|
@FXML private Label chatTime;
|
||||||
@FXML private Label unreadCount;
|
@FXML private Label unreadCount;
|
||||||
|
@FXML private StackPane systemAvatar;
|
||||||
|
@FXML private ImageView profileImageUser;
|
||||||
|
@FXML private ImageView profileImageSystem;
|
||||||
|
@FXML private Circle systemCircle;
|
||||||
|
|
||||||
public void setChatData(String name, String lastMsg, String time, int unread) {
|
// Default avatar resource path
|
||||||
|
private static final String DEFAULT_AVATAR =
|
||||||
|
"/org/to/telegramfinalproject/Avatars/default_avatar.png";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set chat item data, including a profile image (or default).
|
||||||
|
*
|
||||||
|
* @param name Chat name
|
||||||
|
* @param lastMsg Last message text
|
||||||
|
* @param time Last message time
|
||||||
|
* @param unread Unread message count
|
||||||
|
* @param imageUrl Path/URL of profile image (can be null/empty)
|
||||||
|
*/
|
||||||
|
public void setChatData(String name, String lastMsg, String time, int unread, String imageUrl) {
|
||||||
chatName.setText(name);
|
chatName.setText(name);
|
||||||
lastMessage.setText(lastMsg);
|
lastMessage.setText(lastMsg);
|
||||||
chatTime.setText(time);
|
chatTime.setText(time);
|
||||||
unreadCount.setVisible(unread > 0);
|
|
||||||
|
// Unread count
|
||||||
|
if (unread > 0) {
|
||||||
|
unreadCount.setVisible(true);
|
||||||
unreadCount.setText(String.valueOf(unread));
|
unreadCount.setText(String.valueOf(unread));
|
||||||
|
} else {
|
||||||
|
unreadCount.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset all avatar states
|
||||||
|
profileImageUser.setVisible(false);
|
||||||
|
profileImageUser.setManaged(false);
|
||||||
|
systemAvatar.setVisible(false);
|
||||||
|
systemAvatar.setManaged(false);
|
||||||
|
|
||||||
|
if ("Saved Messages".equals(name)) {
|
||||||
|
systemCircle.setFill(javafx.scene.paint.Color.web("#2ca4ff")); // Telegram blue
|
||||||
|
profileImageSystem.setImage(new Image(
|
||||||
|
Objects.requireNonNull(getClass().getResourceAsStream(
|
||||||
|
"/org/to/telegramfinalproject/Icons/saved_messages_light.png"))
|
||||||
|
));
|
||||||
|
systemAvatar.setVisible(true);
|
||||||
|
systemAvatar.setManaged(true);
|
||||||
|
|
||||||
|
} else if ("Archived Chats".equals(name)) {
|
||||||
|
systemCircle.setFill(javafx.scene.paint.Color.web("#808080")); // gray
|
||||||
|
profileImageSystem.setImage(new Image(
|
||||||
|
Objects.requireNonNull(getClass().getResourceAsStream(
|
||||||
|
"/org/to/telegramfinalproject/Icons/archived_chats_light.png"))
|
||||||
|
));
|
||||||
|
systemAvatar.setVisible(true);
|
||||||
|
systemAvatar.setManaged(true);
|
||||||
|
|
||||||
|
} else if (imageUrl != null && !imageUrl.isEmpty()) {
|
||||||
|
profileImageUser.setImage(new Image(imageUrl, true));
|
||||||
|
profileImageUser.setVisible(true);
|
||||||
|
profileImageUser.setManaged(true);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
profileImageUser.setImage(new Image(
|
||||||
|
Objects.requireNonNull(getClass().getResourceAsStream(
|
||||||
|
"/org/to/telegramfinalproject/Icons/default_profile.png"))
|
||||||
|
));
|
||||||
|
profileImageUser.setVisible(true);
|
||||||
|
profileImageUser.setManaged(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUnread(int unread) {
|
public void setUnread(int unread) {
|
||||||
|
|||||||
@@ -245,6 +245,10 @@ public class MainController {
|
|||||||
|
|
||||||
String preview = chat.getLastMessagePreview() == null ? "" : chat.getLastMessagePreview();
|
String preview = chat.getLastMessagePreview() == null ? "" : chat.getLastMessagePreview();
|
||||||
String timeText = formatChatTime(chat.getLastMessageTime());
|
String timeText = formatChatTime(chat.getLastMessageTime());
|
||||||
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/chat_item.fxml"));
|
||||||
|
Node chatItem = loader.load();
|
||||||
|
ChatItemController controller = loader.getController();
|
||||||
|
controller.setChatData(name, lastMsg, time, unread, "/org/to/telegramfinalproject/Avatars/default_profile.png");
|
||||||
|
|
||||||
cc.setChatData(chat.getName(), preview, timeText, chat.getUnreadCount());
|
cc.setChatData(chat.getName(), preview, timeText, chat.getUnreadCount());
|
||||||
item.setOnMouseClicked(e -> openChat(chat));
|
item.setOnMouseClicked(e -> openChat(chat));
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class SidebarMenuController {
|
|||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
// Load default profile image
|
// Load default profile image
|
||||||
Image profile = loadImage("/org/to/telegramfinalproject/Avatars/profile.png");
|
Image profile = loadImage("/org/to/telegramfinalproject/Avatars/default_profile.png");
|
||||||
if (profile != null) profileImage.setImage(profile);
|
if (profile != null) profileImage.setImage(profile);
|
||||||
|
|
||||||
setupButtonActions();
|
setupButtonActions();
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
@@ -124,17 +124,17 @@
|
|||||||
|
|
||||||
/* Input bubble */
|
/* Input bubble */
|
||||||
.msg-input {
|
.msg-input {
|
||||||
-fx-background-color: white;
|
-fx-background-color: #1b2b39; /* dark bluish background */
|
||||||
|
-fx-control-inner-background: #1b2b39;
|
||||||
|
-fx-text-fill: #e8f1f8;
|
||||||
|
-fx-prompt-text-fill: #8ea1b2;
|
||||||
-fx-background-radius: 18;
|
-fx-background-radius: 18;
|
||||||
-fx-padding: 6 12 6 12;
|
-fx-padding: 6 12 6 12;
|
||||||
-fx-text-fill: #0f141a;
|
|
||||||
-fx-prompt-text-fill: #9aa6b2;
|
|
||||||
-fx-border-color: transparent;
|
-fx-border-color: transparent;
|
||||||
|
|
||||||
-fx-control-inner-background: white;
|
|
||||||
-fx-focus-color: transparent;
|
-fx-focus-color: transparent;
|
||||||
-fx-faint-focus-color: transparent;
|
-fx-faint-focus-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.msg-input .scroll-pane {
|
.msg-input .scroll-pane {
|
||||||
-fx-vbar-policy: never;
|
-fx-vbar-policy: never;
|
||||||
-fx-hbar-policy: never;
|
-fx-hbar-policy: never;
|
||||||
@@ -144,6 +144,7 @@
|
|||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Context menu */
|
||||||
.context-menu {
|
.context-menu {
|
||||||
-fx-background-color: #1b2735;
|
-fx-background-color: #1b2735;
|
||||||
-fx-background-radius: 6;
|
-fx-background-radius: 6;
|
||||||
@@ -162,17 +163,134 @@
|
|||||||
-fx-background-radius: 4;
|
-fx-background-radius: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Search panel ===== */
|
|
||||||
.chat-search-pane {
|
/* ===== Search panel (dark) ===== */
|
||||||
-fx-background-color: #1b2735; /* matches sidebar */
|
.chat-search-pane { -fx-background-color: #1b2735; }
|
||||||
|
.chat-search-bar { -fx-background-color: transparent; -fx-padding: 8 10; }
|
||||||
|
.search-placeholder { -fx-text-fill: #8ea1b2; -fx-font-size: 13px; }
|
||||||
|
|
||||||
|
/* ===== Global search bar ===== */
|
||||||
|
.global-search {
|
||||||
|
-fx-background-color: #1b2b39;
|
||||||
|
-fx-background-radius: 15;
|
||||||
|
-fx-text-fill: #e8f1f8;
|
||||||
|
-fx-prompt-text-fill: #8ea1b2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-search-bar {
|
/* ===== Chat list ===== */
|
||||||
|
.chat-list { -fx-background-color: #0f1c26; }
|
||||||
|
.chat-list .label { -fx-text-fill: #e8f1f8; }
|
||||||
|
|
||||||
|
/* ===== Sidebar / Left Pane ===== */
|
||||||
|
.sidebar-pane {
|
||||||
|
-fx-background-color: #1b2735; /* Telegram dark */
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-topbar {
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
-fx-padding: 8 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-placeholder {
|
.menu-btn {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-search {
|
||||||
|
-fx-background-color: #2a3a4a;
|
||||||
|
-fx-background-radius: 15;
|
||||||
|
-fx-text-fill: #e8f1f8;
|
||||||
|
-fx-prompt-text-fill: #8ea1b2;
|
||||||
|
-fx-border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat list */
|
||||||
|
.chat-list {
|
||||||
|
-fx-background-color: #0f1c26;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-scroll {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Search Panel ===== */
|
||||||
|
.chat-search-pane {
|
||||||
|
-fx-background-color: #1b2735;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-label {
|
||||||
-fx-text-fill: #8ea1b2;
|
-fx-text-fill: #8ea1b2;
|
||||||
-fx-font-size: 13px;
|
-fx-font-size: 11px;
|
||||||
|
-fx-padding: 10 0 5 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-separator {
|
||||||
|
-fx-background-color: #2e3948;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-scope-bar {
|
||||||
|
-fx-padding: 8 10;
|
||||||
|
-fx-border-color: #2e3948;
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-scope {
|
||||||
|
-fx-text-fill: #8ea1b2;
|
||||||
|
-fx-font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
-fx-text-fill: #e8f1f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Right Chat Panel ===== */
|
||||||
|
.chat-display {
|
||||||
|
-fx-background-color: #0f1c26;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Overlay ===== */
|
||||||
|
.overlay {
|
||||||
|
-fx-background-color: rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat item container */
|
||||||
|
.chat-item {
|
||||||
|
-fx-background-color: #0f1c26;
|
||||||
|
-fx-padding: 10;
|
||||||
|
-fx-border-color: #2e3948;
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-item:hover {
|
||||||
|
-fx-background-color: #223446;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat details */
|
||||||
|
.chat-name {
|
||||||
|
-fx-font-size: 14;
|
||||||
|
-fx-font-weight: bold;
|
||||||
|
-fx-text-fill: #e8f1f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-last-message {
|
||||||
|
-fx-text-fill: #8ea1b2;
|
||||||
|
-fx-font-size: 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time + unread */
|
||||||
|
.chat-time {
|
||||||
|
-fx-font-size: 11;
|
||||||
|
-fx-text-fill: #8ea1b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unread counter (same for both modes) */
|
||||||
|
.unread-count {
|
||||||
|
-fx-background-color: #2196f3; /* blue bubble */
|
||||||
|
-fx-text-fill: white !important; /* always white */
|
||||||
|
-fx-font-size: 10px;
|
||||||
|
-fx-padding: 3 6;
|
||||||
|
-fx-background-radius: 10;
|
||||||
|
-fx-font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,12 +51,12 @@
|
|||||||
-fx-text-fill: black;
|
-fx-text-fill: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Thin Telegram-like SplitPane divider (light) */
|
/* SplitPane divider */
|
||||||
.split-pane:horizontal > .split-pane-divider {
|
.split-pane:horizontal > .split-pane-divider {
|
||||||
-fx-background-color: transparent; /* no big solid block */
|
-fx-background-color: transparent;
|
||||||
-fx-border-color: #cccccc; /* the visible thin line */
|
-fx-border-color: #cccccc;
|
||||||
-fx-border-width: 0 1px 0 1px; /* 1px vertical line */
|
-fx-border-width: 0 1px 0 1px;
|
||||||
-fx-padding: 0 0 0 0.5px; /* big invisible hitbox for the mouse */
|
-fx-padding: 0 0 0 0.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder-label {
|
.placeholder-label {
|
||||||
@@ -144,6 +144,7 @@
|
|||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Context menu */
|
||||||
.context-menu {
|
.context-menu {
|
||||||
-fx-background-color: white;
|
-fx-background-color: white;
|
||||||
-fx-background-radius: 6;
|
-fx-background-radius: 6;
|
||||||
@@ -162,17 +163,133 @@
|
|||||||
-fx-background-radius: 4;
|
-fx-background-radius: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Search panel ===== */
|
|
||||||
|
/* ===== Search panel (light) ===== */
|
||||||
|
.chat-search-pane { -fx-background-color: #f5f5f5; }
|
||||||
|
.chat-search-bar { -fx-background-color: transparent; -fx-padding: 8 10; }
|
||||||
|
.search-placeholder { -fx-text-fill: #7e8a97; -fx-font-size: 13px; }
|
||||||
|
|
||||||
|
/* ===== Global search bar ===== */
|
||||||
|
.global-search {
|
||||||
|
-fx-background-color: #f5f5f5;
|
||||||
|
-fx-background-radius: 15;
|
||||||
|
-fx-text-fill: #0f141a;
|
||||||
|
-fx-prompt-text-fill: #9aa6b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Chat list ===== */
|
||||||
|
.chat-list { -fx-background-color: #ffffff; }
|
||||||
|
.chat-list .label { -fx-text-fill: #0f141a; }
|
||||||
|
|
||||||
|
/* ===== Sidebar / Left Pane ===== */
|
||||||
|
.sidebar-pane {
|
||||||
|
-fx-background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-topbar {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-btn {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
.global-search {
|
||||||
|
-fx-background-color: #f5f5f5;
|
||||||
|
-fx-background-radius: 15;
|
||||||
|
-fx-text-fill: #0f141a;
|
||||||
|
-fx-prompt-text-fill: #7e8a97;
|
||||||
|
-fx-border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat list */
|
||||||
|
.chat-list {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-scroll {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Search Panel ===== */
|
||||||
.chat-search-pane {
|
.chat-search-pane {
|
||||||
-fx-background-color: #f5f5f5;
|
-fx-background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-search-bar {
|
.search-label {
|
||||||
-fx-background-color: transparent;
|
-fx-text-fill: #7e8a97;
|
||||||
-fx-padding: 8 10;
|
-fx-font-size: 11px;
|
||||||
|
-fx-padding: 10 0 5 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-placeholder {
|
.search-separator {
|
||||||
|
-fx-background-color: #e6e6e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-scope-bar {
|
||||||
|
-fx-padding: 8 10;
|
||||||
|
-fx-border-color: #e6e6e6;
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-scope {
|
||||||
-fx-text-fill: #7e8a97;
|
-fx-text-fill: #7e8a97;
|
||||||
-fx-font-size: 13px;
|
-fx-font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Right Chat Panel ===== */
|
||||||
|
.chat-display {
|
||||||
|
-fx-background-color: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Overlay ===== */
|
||||||
|
.overlay {
|
||||||
|
-fx-background-color: rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat item container */
|
||||||
|
.chat-item {
|
||||||
|
-fx-background-color: #ffffff;
|
||||||
|
-fx-padding: 10;
|
||||||
|
-fx-border-color: #ddd;
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-item:hover {
|
||||||
|
-fx-background-color: #f5f5f5;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chat details */
|
||||||
|
.chat-name {
|
||||||
|
-fx-font-size: 14;
|
||||||
|
-fx-font-weight: bold;
|
||||||
|
-fx-text-fill: #0f141a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-last-message {
|
||||||
|
-fx-text-fill: #7e8a97;
|
||||||
|
-fx-font-size: 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time + unread */
|
||||||
|
.chat-time {
|
||||||
|
-fx-font-size: 11;
|
||||||
|
-fx-text-fill: #7e8a97;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unread counter (same for both modes) */
|
||||||
|
.unread-count {
|
||||||
|
-fx-background-color: #2196f3; /* blue bubble */
|
||||||
|
-fx-text-fill: white !important; /* always white */
|
||||||
|
-fx-font-size: 10px;
|
||||||
|
-fx-padding: 3 6;
|
||||||
|
-fx-background-radius: 10;
|
||||||
|
-fx-font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,26 +5,50 @@
|
|||||||
<?import javafx.scene.image.ImageView?>
|
<?import javafx.scene.image.ImageView?>
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<?import javafx.scene.shape.Circle?>
|
||||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||||
fx:controller="org.to.telegramfinalproject.UI.ChatItemController"
|
fx:controller="org.to.telegramfinalproject.UI.ChatItemController"
|
||||||
spacing="10" alignment="CENTER_LEFT"
|
spacing="10" alignment="CENTER_LEFT"
|
||||||
style="-fx-padding: 10; -fx-background-color: white; -fx-border-color: #ddd; -fx-border-width: 0 0 1 0;">
|
styleClass="chat-item">
|
||||||
|
|
||||||
<!-- Profile Image -->
|
<!-- Avatar container with fixed size -->
|
||||||
<ImageView fx:id="profileImage" fitWidth="40" fitHeight="40" preserveRatio="true"
|
<StackPane fx:id="avatarContainer"
|
||||||
style="-fx-background-radius: 50; -fx-border-radius: 50;"/>
|
prefWidth="40" prefHeight="40"
|
||||||
|
minWidth="40" minHeight="40"
|
||||||
|
maxWidth="40" maxHeight="40"
|
||||||
|
alignment="CENTER">
|
||||||
|
|
||||||
|
<!-- User profile image -->
|
||||||
|
<ImageView fx:id="profileImageUser"
|
||||||
|
fitWidth="60" fitHeight="60"
|
||||||
|
preserveRatio="true"
|
||||||
|
visible="true" managed="true"/>
|
||||||
|
|
||||||
|
<!-- System avatar (circle + icon) -->
|
||||||
|
<StackPane fx:id="systemAvatar"
|
||||||
|
prefWidth="40" prefHeight="40"
|
||||||
|
visible="false" managed="false"
|
||||||
|
alignment="CENTER">
|
||||||
|
|
||||||
|
<Circle fx:id="systemCircle"
|
||||||
|
radius="20"
|
||||||
|
fill="gray"/>
|
||||||
|
|
||||||
|
<ImageView fx:id="profileImageSystem"
|
||||||
|
fitWidth="28" fitHeight="28"
|
||||||
|
preserveRatio="true"/>
|
||||||
|
</StackPane>
|
||||||
|
</StackPane>
|
||||||
|
|
||||||
<!-- Chat Details -->
|
<!-- Chat Details -->
|
||||||
<VBox alignment="CENTER_LEFT" HBox.hgrow="ALWAYS">
|
<VBox alignment="CENTER_LEFT" HBox.hgrow="ALWAYS">
|
||||||
<Label fx:id="chatName" style="-fx-font-size: 14; -fx-font-weight: bold;"/>
|
<Label fx:id="chatName" styleClass="chat-name"/>
|
||||||
<Label fx:id="lastMessage" style="-fx-text-fill: gray; -fx-font-size: 12;"/>
|
<Label fx:id="lastMessage" styleClass="chat-last-message"/>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
|
||||||
<!-- Time + Unread -->
|
<!-- Time + Unread -->
|
||||||
<VBox alignment="CENTER_RIGHT" spacing="5">
|
<VBox alignment="CENTER_RIGHT" spacing="5">
|
||||||
<Label fx:id="chatTime" style="-fx-font-size: 11; -fx-text-fill: gray;"/>
|
<Label fx:id="chatTime" styleClass="chat-time"/>
|
||||||
<Label fx:id="unreadCount"
|
<Label fx:id="unreadCount" styleClass="unread-count"/>
|
||||||
style="-fx-background-color: #2196f3; -fx-text-fill: white; -fx-font-size: 10;
|
|
||||||
-fx-padding: 3 6; -fx-background-radius: 10;"/>
|
|
||||||
</VBox>
|
</VBox>
|
||||||
</HBox>
|
</HBox>
|
||||||
@@ -21,18 +21,19 @@
|
|||||||
<items>
|
<items>
|
||||||
|
|
||||||
<!-- LEFT: Sidebar -->
|
<!-- LEFT: Sidebar -->
|
||||||
<VBox fx:id="leftPane" minWidth="72" style="-fx-background-color: #FFFFFF;">
|
<VBox fx:id="leftPane" minWidth="72" styleClass="sidebar-pane">
|
||||||
|
|
||||||
<!-- Top bar (always visible) -->
|
<!-- Top bar (always visible) -->
|
||||||
<HBox spacing="10">
|
<HBox spacing="10" styleClass="search-bar-container">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="10" left="10" right="10" top="10"/>
|
<Insets bottom="10" left="10" right="10" top="10"/>
|
||||||
</padding>
|
</padding>
|
||||||
<children>
|
<children>
|
||||||
<Button fx:id="menuButton" minHeight="29.0" minWidth="40"
|
<Button fx:id="menuButton"
|
||||||
|
minHeight="29.0" minWidth="40"
|
||||||
onAction="#toggleSidebar"
|
onAction="#toggleSidebar"
|
||||||
prefHeight="29.0" prefWidth="40.0"
|
prefHeight="29.0" prefWidth="40.0"
|
||||||
style="-fx-background-color: transparent;">
|
styleClass="menu-btn">
|
||||||
<graphic>
|
<graphic>
|
||||||
<ImageView fx:id="menuIcon" fitHeight="24" fitWidth="17"
|
<ImageView fx:id="menuIcon" fitHeight="24" fitWidth="17"
|
||||||
preserveRatio="true" smooth="true">
|
preserveRatio="true" smooth="true">
|
||||||
@@ -46,7 +47,7 @@
|
|||||||
<TextField fx:id="searchBar"
|
<TextField fx:id="searchBar"
|
||||||
prefHeight="36" prefWidth="430.0"
|
prefHeight="36" prefWidth="430.0"
|
||||||
promptText="Search"
|
promptText="Search"
|
||||||
style="-fx-background-color: #f5f5f5; -fx-background-radius: 15;"/>
|
styleClass="global-search"/>
|
||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
|
|
||||||
@@ -55,12 +56,12 @@
|
|||||||
|
|
||||||
<!-- Chat list (default) -->
|
<!-- Chat list (default) -->
|
||||||
<ScrollPane fx:id="scrollPane" fitToWidth="true" hbarPolicy="NEVER"
|
<ScrollPane fx:id="scrollPane" fitToWidth="true" hbarPolicy="NEVER"
|
||||||
style="-fx-background-color: transparent;"
|
|
||||||
vbarPolicy="AS_NEEDED"
|
vbarPolicy="AS_NEEDED"
|
||||||
visible="true" managed="true">
|
visible="true" managed="true"
|
||||||
|
styleClass="chat-scroll">
|
||||||
<content>
|
<content>
|
||||||
<VBox fx:id="chatListContainer" spacing="5"
|
<VBox fx:id="chatListContainer" spacing="5"
|
||||||
style="-fx-background-color: transparent;">
|
styleClass="chat-list">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="10" left="10" right="10" top="10"/>
|
<Insets bottom="10" left="10" right="10" top="10"/>
|
||||||
</padding>
|
</padding>
|
||||||
@@ -69,18 +70,18 @@
|
|||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
|
|
||||||
<!-- Search panel (hidden initially) -->
|
<!-- Search panel (hidden initially) -->
|
||||||
<VBox fx:id="chatSearchPane" visible="false" managed="false"
|
<VBox fx:id="chatSearchPane"
|
||||||
|
visible="false" managed="false"
|
||||||
styleClass="chat-search-pane">
|
styleClass="chat-search-pane">
|
||||||
|
|
||||||
<!-- Section label -->
|
<!-- Section label -->
|
||||||
<Label text="Search messages in"
|
<Label text="Search messages in" styleClass="search-label"/>
|
||||||
style="-fx-text-fill: #7e8a97; -fx-font-size: 11px; -fx-padding: 10 0 5 10;"/>
|
|
||||||
|
|
||||||
<!-- Tiny separator line -->
|
<!-- Tiny separator line -->
|
||||||
<Separator style="-fx-background-color: #e6e6e6;" prefHeight="0.5"/>
|
<Separator styleClass="search-separator" prefHeight="0.5"/>
|
||||||
|
|
||||||
<!-- User profile + "This chat" + close -->
|
<!-- User profile + "This chat" + close -->
|
||||||
<HBox spacing="10" alignment="CENTER_LEFT" style="-fx-padding: 8 10; -fx-border-color: #e6e6e6; -fx-border-width: 0 0 1 0;">
|
<HBox spacing="10" alignment="CENTER_LEFT" styleClass="search-scope-bar">
|
||||||
<!-- Avatar -->
|
<!-- Avatar -->
|
||||||
<ImageView fx:id="searchChatAvatar" fitWidth="32" fitHeight="32" preserveRatio="true">
|
<ImageView fx:id="searchChatAvatar" fitWidth="32" fitHeight="32" preserveRatio="true">
|
||||||
<image>
|
<image>
|
||||||
@@ -90,12 +91,11 @@
|
|||||||
|
|
||||||
<!-- scope -->
|
<!-- scope -->
|
||||||
<VBox alignment="CENTER_LEFT">
|
<VBox alignment="CENTER_LEFT">
|
||||||
<Label text="This chat" style="-fx-text-fill: #7e8a97; -fx-font-size: 11px;"/>
|
<Label text="This chat" styleClass="search-scope"/>
|
||||||
</VBox>
|
</VBox>
|
||||||
<Region HBox.hgrow="ALWAYS"/>
|
<Region HBox.hgrow="ALWAYS"/>
|
||||||
<!-- Close button -->
|
<!-- Close button -->
|
||||||
<Button text="✕" onAction="#closeSearchPanel"
|
<Button text="✕" onAction="#closeSearchPanel" styleClass="close-btn"/>
|
||||||
style="-fx-background-color: transparent; -fx-cursor: hand;"/>
|
|
||||||
</HBox>
|
</HBox>
|
||||||
|
|
||||||
<!-- Placeholder -->
|
<!-- Placeholder -->
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
</VBox>
|
</VBox>
|
||||||
|
|
||||||
<!-- RIGHT: Chat panel -->
|
<!-- RIGHT: Chat panel -->
|
||||||
<StackPane fx:id="chatDisplayArea" minWidth="360" style="-fx-background-color: #FAFAFA;">
|
<StackPane fx:id="chatDisplayArea" minWidth="360" styleClass="chat-display">
|
||||||
<children>
|
<children>
|
||||||
<Label fx:id="placeholderLabel" alignment="CENTER"
|
<Label fx:id="placeholderLabel" alignment="CENTER"
|
||||||
prefHeight="21.0" prefWidth="248.0"
|
prefHeight="21.0" prefWidth="248.0"
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
<Pane fx:id="overlay"
|
<Pane fx:id="overlay"
|
||||||
mouseTransparent="true"
|
mouseTransparent="true"
|
||||||
onMouseClicked="#closeSidebar"
|
onMouseClicked="#closeSidebar"
|
||||||
style="-fx-background-color: rgba(0,0,0,0.3);"
|
styleClass="overlay"
|
||||||
visible="false"/>
|
visible="false"/>
|
||||||
</children>
|
</children>
|
||||||
</StackPane>
|
</StackPane>
|
||||||
|
|||||||
Reference in New Issue
Block a user