A bunch of Packet changes

This commit is contained in:
2023-12-11 18:07:31 +02:00
parent 085fc2ee36
commit 22ee07a5b3
45 changed files with 1667 additions and 171 deletions
+6
View File
@@ -45,6 +45,12 @@
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>16.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
@@ -1,24 +1,37 @@
package dev.wiing.gossip.client;
import dev.wiing.gossip.lib.PacketHandler;
import dev.wiing.gossip.lib.PacketManager;
import dev.wiing.gossip.lib.models.SecretUser;
import dev.wiing.gossip.lib.models.User;
import dev.wiing.gossip.lib.packets.FetchUserPacket;
import dev.wiing.gossip.lib.packets.Packet;
import dev.wiing.gossip.lib.packets.UserDataPacket;
import javafx.application.Platform;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class Connection {
private static final Connection instance = new Connection();
private final PacketManager packetManager;
private final PacketManager packetManager = new PacketManager();
private final PacketHandler packetHandler = new PacketHandler();
private Thread handlerThread;
private Socket socket;
private SecretUser self;
private final List<Packet> queuedPackets = Collections.synchronizedList(new LinkedList<>());
private Connection() {
packetManager = new PacketManager();
packetManager.registerPackets();
}
@@ -30,6 +43,35 @@ public class Connection {
return packetManager;
}
public PacketHandler getPacketHandler() {
return packetHandler;
}
public static class PacketHandlerRunnable implements Runnable {
private final Connection connection;
public PacketHandlerRunnable(Connection connection) {
this.connection = connection;
}
@Override
public void run() {
while (true) {
try {
Packet packet = connection.nextPacket();
connection.getPacketHandler().runPacket(packet);
} catch (SocketException e) {
break;
}
}
}
}
public void beginHandlingPackets() {
handlerThread = new Thread(new PacketHandlerRunnable(this));
handlerThread.start();
}
public Socket getSocket() {
return socket;
}
@@ -46,20 +88,81 @@ public class Connection {
}
}
public Packet nextPacket() {
public Packet nextPacket(boolean useQueue) throws SocketException {
if (!queuedPackets.isEmpty()) {
return queuedPackets.remove(0);
}
try {
return getPacketManager().readPacket(getSocket().getInputStream());
} catch (SocketException e) {
throw e;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public Packet nextPacket() throws SocketException {
return nextPacket(true);
}
public Packet nextPacket(short packetType) throws SocketException {
while (true) {
Packet packet = nextPacket(false);
if (packet.getType() != packetType) {
queuedPackets.add(packet);
continue;
}
return packet;
}
}
public SecretUser getSelf() {
return self;
}
public void setSelf(SecretUser self) {
this.self = self;
userCache.put(self.getUserID(), new User(
self.getUsername(),
self.getAvatarID(),
self.getUserID()
));
}
private final Map<Long, User> userCache = new ConcurrentHashMap<>();
public User getUser(long userID) {
User result;
if ((result = userCache.getOrDefault(userID, null)) != null) {
return result;
}
FetchUserPacket fetch = new FetchUserPacket();
fetch.setUserID(userID);
Connection.getInstance().sendPacket(fetch);
Packet resp;
try {
resp = Connection.getInstance().nextPacket(UserDataPacket.TYPE);
} catch (SocketException e) {
throw new RuntimeException(e);
}
if (resp.getType() == UserDataPacket.TYPE) {
UserDataPacket userData = (UserDataPacket)resp;
result = new User(
userData.getUsername(),
userData.getAvatarID(),
userData.getUserID()
);
userCache.put(result.getUserID(), result);
}
return result;
}
}
@@ -2,7 +2,7 @@ package dev.wiing.gossip.client.controllers;
import dev.wiing.gossip.client.Connection;
import dev.wiing.gossip.client.data.UserIcon;
import dev.wiing.gossip.client.data.UserAvatar;
import dev.wiing.gossip.lib.models.SecretUser;
import dev.wiing.gossip.lib.packets.CredentialsPacket;
import dev.wiing.gossip.lib.packets.Packet;
@@ -12,12 +12,15 @@ import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.net.SocketException;
import java.net.URL;
import java.util.ResourceBundle;
@@ -34,15 +37,7 @@ public class LoginController implements Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
paneIcon.setBackground(new Background(
new BackgroundImage(
UserIcon.MORNING.getImage(),
BackgroundRepeat.NO_REPEAT,
BackgroundRepeat.NO_REPEAT,
BackgroundPosition.CENTER,
new BackgroundSize(100.0, 100.0, true, true, false, true)
)
));
UserAvatar.MORNING.applyToRegionBackground(paneIcon, false);
Circle circle = new Circle(paneIcon.getMinWidth() * 0.5);
paneIcon.setShape(circle);
@@ -57,17 +52,27 @@ public class LoginController implements Initializable {
@FXML
public void onLogin(ActionEvent event) {
RegisterPacket packet = new RegisterPacket();
packet.setIconID((char)0);
packet.setAvatarID((byte)0);
packet.setUsername(txtUsername.getText());
Connection.getInstance().sendPacket(packet);
Packet result = Connection.getInstance().nextPacket();
Packet result = null;
try {
result = Connection.getInstance().nextPacket();
} catch (SocketException e) {
throw new RuntimeException(e);
}
if (result != null && result.getType() == CredentialsPacket.TYPE) {
CredentialsPacket creds = (CredentialsPacket)result;
SecretUser user = new SecretUser(packet.getUsername(), packet.getIconID(), creds.getUID(), creds.getSecret());
SecretUser user = new SecretUser(packet.getUsername(), packet.getAvatarID(), creds.getUID(), creds.getSecret());
Connection.getInstance().setSelf(user);
var pair = MainController.createInstance();
((Stage)Stage.getWindows().get(0)).setScene(new Scene(pair.first()));
}
}
@@ -0,0 +1,114 @@
package dev.wiing.gossip.client.controllers;
import dev.wiing.gossip.client.Connection;
import dev.wiing.gossip.client.generic.Pair;
import dev.wiing.gossip.client.utils.Utils;
import dev.wiing.gossip.lib.models.Topic;
import dev.wiing.gossip.lib.models.User;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
public class MainChatController {
private Topic topic;
@FXML
private Label lblBabblersCount;
@FXML
private Label lblTopicName;
@FXML
private Label lblTyping;
@FXML
private Label lblVisitBabblerCount;
@FXML
private Label lblVisitHostName;
@FXML
private Label lblVisitTopicDescription;
@FXML
private Label lblVisitTopicName;
@FXML
private TextArea txtCompose;
@FXML
private VBox vboxChatPage;
@FXML
private VBox vboxMessages;
@FXML
private VBox vboxVisitPage;
public void setTopic(Topic topic) {
this.topic = topic;
boolean participating = topic.hasUser(Connection.getInstance().getSelf());
togglePages(participating);
setTopicName(topic.getName());
lblVisitTopicDescription.setText(topic.getDescription());
setBabblerCount(topic.getUsersReadOnly().size());
lblVisitHostName.setText(topic.getHost().getUsernameDisplay());
this.topic.addChangeListener(evt -> {
if (evt.getPropertyName().equals("userAdd") || evt.getPropertyName().equals("userRemove")) {
setBabblerCount(topic.getUsersReadOnly().size());
}
});
}
private void setTopicName(String name) {
lblTopicName.setText(name);
lblVisitTopicName.setText(name);
}
private void setBabblerCount(int count) {
String res = "No Babblers";
if (count == 1) {
res = "1 Babbler";
} else if (count > 1) {
res = Integer.toString(count) + " Babblers";
}
lblBabblersCount.setText(res);
lblVisitBabblerCount.setText(res + " active");
}
private void togglePages(boolean participating) {
vboxChatPage.setVisible(participating);
vboxVisitPage.setVisible(!participating);
}
@FXML
void onJoinTopic(ActionEvent event) {
topic.addUser(Connection.getInstance().getSelf());
togglePages(true);
}
@FXML
void onSend(MouseEvent event) {
}
public static Pair<Parent, MainChatController> createInstance() {
return Utils.createInstance("views/main-chat-view.fxml");
}
}
@@ -0,0 +1,140 @@
package dev.wiing.gossip.client.controllers;
import dev.wiing.gossip.client.Connection;
import dev.wiing.gossip.client.controllers.item.MainTopicItemController;
import dev.wiing.gossip.client.data.UserAvatar;
import dev.wiing.gossip.client.generic.Pair;
import dev.wiing.gossip.client.utils.Utils;
import dev.wiing.gossip.lib.models.Topic;
import dev.wiing.gossip.lib.models.User;
import dev.wiing.gossip.lib.packets.*;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import java.net.URL;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
public class MainController implements Initializable {
Topic activeTopic = null;
Parent activeTopicElement = null;
private final Map<Long, Parent> topicContentMap = new ConcurrentHashMap<>();
@FXML
private VBox vboxRoot;
@FXML
private VBox vboxTopics;
@FXML
private Label lblUsername;
@FXML
private Pane paneIcon;
@FXML
private AnchorPane paneContent;
@FXML
private Label lblJoinMessage;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
User user = Connection.getInstance().getSelf();
lblUsername.setText(user.getUsernameDisplay());
UserAvatar.getAvatar(user.getAvatarID()).applyToRegionBackground(paneIcon, true);
Connection.getInstance().getPacketHandler().addListener(TopicAddedPacket.class, packet -> {
User host = Connection.getInstance().getUser(packet.getHostID());
Topic topic = new Topic(
packet.getTopicID(),
packet.getTopicName(),
packet.getTopicDescription(),
host,
packet.getTopicColor()
);
var pair = MainTopicItemController.createInstance();
pair.second().setTopic(topic);
var contentPair = MainChatController.createInstance();
contentPair.second().setTopic(topic);
topicContentMap.put(topic.getId(), contentPair.first());
AnchorPane.setLeftAnchor(contentPair.first(), 0.0);
AnchorPane.setBottomAnchor(contentPair.first(), 0.0);
AnchorPane.setTopAnchor(contentPair.first(), 0.0);
AnchorPane.setRightAnchor(contentPair.first(), 0.0);
contentPair.first().setVisible(false);
Platform.runLater(() -> {
paneContent.getChildren().add(contentPair.first());
vboxTopics.getChildren().add(pair.first());
});
pair.second().setOnMouseClicked(event -> {
setActiveTopic(topic, pair.first());
});
});
Connection.getInstance().beginHandlingPackets();
vboxTopics.getChildren().clear();
}
public void setActiveTopic(Topic topic, Parent element) {
if (activeTopic != null) {
activeTopicElement.getStyleClass().remove("tag-min");
topicContentMap.get(activeTopic.getId()).setVisible(false);
} else {
lblJoinMessage.setVisible(false);
}
if (topic == null) {
activeTopic = null;
activeTopicElement = null;
lblJoinMessage.setVisible(true);
vboxRoot.setStyle("-accent: hsb(250, 10%, 50%);");
return;
}
vboxRoot.setStyle("-accent: hsb(" + topic.getColor() + ", 70%, 100%);");
element.getStyleClass().add("tag-min");
activeTopic = topic;
activeTopicElement = element;
topicContentMap.get(activeTopic.getId()).setVisible(true);
}
@FXML
void onCreateTopic(ActionEvent event) {
CreateTopicPacket packet = new CreateTopicPacket();
packet.setUserSecret(Connection.getInstance().getSelf().getUserSecret());
packet.setTopicName("Point Nemo");
packet.setTopicDescription("We are so gone XDD");
Connection.getInstance().sendPacket(packet);
}
public static Pair<Parent, MainController> createInstance() {
return Utils.createInstance("views/main-view.fxml");
}
}
@@ -0,0 +1,41 @@
package dev.wiing.gossip.client.controllers.item;
import dev.wiing.gossip.client.generic.Pair;
import dev.wiing.gossip.client.utils.Utils;
import dev.wiing.gossip.lib.models.Topic;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
public class MainTopicItemController {
private Topic topic;
@FXML
private HBox hboxParent;
@FXML
private Label lblTopicName;
public void setTopic(Topic topic) {
this.topic = topic;
this.lblTopicName.setText(topic.getName());
}
public Topic getTopic() {
return topic;
}
public static Pair<Parent, MainTopicItemController> createInstance() {
return Utils.createInstance("views/main-topic-item.fxml");
}
public void setOnMouseClicked(EventHandler<MouseEvent> eventHandler) {
hboxParent.setOnMouseClicked(eventHandler);
}
}
@@ -0,0 +1,102 @@
package dev.wiing.gossip.client.data;
import dev.wiing.gossip.client.Program;
import javafx.scene.image.Image;
import javafx.scene.layout.*;
import javafx.scene.shape.Circle;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
public class UserAvatar {
public static final UserAvatar MORNING = new UserAvatar("Morning", "Eggs and Bacon", 0, "avatars/avatar-0.png");
public static final UserAvatar VINTAGE = new UserAvatar("Vintage", "Red Car", 1, "avatars/avatar-1.png");
public static final UserAvatar ROUTINE = new UserAvatar("Routine", "Coffee Cup", 2, "avatars/avatar-2.png");
public static final UserAvatar SILLY = new UserAvatar("Silly", "Ghost Toy", 3, "avatars/avatar-3.png");
public static final UserAvatar ADVENTURE = new UserAvatar("Adventure", "Slide with a Plant", 4, "avatars/avatar-4.png");
public static final UserAvatar REBELLION = new UserAvatar("Rebellion", "Potted Cactus", 5, "avatars/avatar-5.png");
public static final UserAvatar DIGITAL = new UserAvatar("Digital", "Game Controller", 6, "avatars/avatar-6.png");
public static final UserAvatar MYSTERY = new UserAvatar("Mystery", "Floating Sphere", 7, "avatars/avatar-7.png");
public static final UserAvatar VACATION = new UserAvatar("Vacation", "Cat under an Umbrella", 8, "avatars/avatar-8.png");
public static final UserAvatar SIMPLE = new UserAvatar("Simple", "Potted Succulent", 9, "avatars/avatar-9.png");
public static UserAvatar getAvatar(int avatarID) {
return Arrays.stream(getAvatars())
.skip(avatarID)
.findFirst()
.orElse(null);
}
public static UserAvatar[] getAvatars() {
return new UserAvatar[]{
MORNING,
VINTAGE,
ROUTINE,
SILLY,
ADVENTURE,
REBELLION,
DIGITAL,
MYSTERY,
VACATION,
SIMPLE
};
}
private final String name;
private final String description;
private final int id;
private final URL url;
private UserAvatar(String name, String description, int id, String path) {
this.name = name;
this.description = description;
this.id = id;
this.url = Program.class.getResource(path);
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public int getId() {
return id;
}
public URL getUrl() {
return url;
}
public Image getImage() {
try {
return new Image(url.openStream());
} catch (IOException e) {
return null;
}
}
public void applyToRegionBackground(Region region, boolean applyShape) {
if (getImage() == null) return;
region.setBackground(new Background(
new BackgroundImage(
getImage(),
BackgroundRepeat.NO_REPEAT,
BackgroundRepeat.NO_REPEAT,
BackgroundPosition.CENTER,
new BackgroundSize(100.0, 100.0, true, true, false, true)
)
));
region.setStyle("");
if (applyShape) {
Circle circle = new Circle(region.getMinWidth() * 0.5);
region.setShape(circle);
}
}
}
@@ -1,72 +0,0 @@
package dev.wiing.gossip.client.data;
import dev.wiing.gossip.client.Program;
import javafx.scene.image.Image;
import java.io.IOException;
import java.net.URL;
public class UserIcon {
public static final UserIcon MORNING = new UserIcon("Morning", "Eggs and Bacon", 0, "icons/icon_0.png");
public static final UserIcon VINTAGE = new UserIcon("Vintage", "Red Car", 1, "icons/icon_1.png");
public static final UserIcon ROUTINE = new UserIcon("Routine", "Coffee Cup", 2, "icons/icon_2.png");
public static final UserIcon SILLY = new UserIcon("Silly", "Ghost Toy", 3, "icons/icon_3.png");
public static final UserIcon ADVENTURE = new UserIcon("Adventure", "Slide with a Plant", 4, "icons/icon_4.png");
public static final UserIcon REBELLION = new UserIcon("Rebellion", "Potted Cactus", 5, "icons/icon_5.png");
public static final UserIcon DIGITAL = new UserIcon("Digital", "Game Controller", 6, "icons/icon_6.png");
public static final UserIcon MYSTERY = new UserIcon("Mystery", "Floating Sphere", 7, "icons/icon_7.png");
public static final UserIcon VACATION = new UserIcon("Vacation", "Cat under an Umbrella", 8, "icons/icon_8.png");
public static final UserIcon SIMPLE = new UserIcon("Simple", "Potted Succulent", 9, "icons/icon_9.png");
public static UserIcon[] getIcons() {
return new UserIcon[]{
MORNING,
VINTAGE,
ROUTINE,
SILLY,
ADVENTURE,
REBELLION,
DIGITAL,
MYSTERY,
VACATION,
SIMPLE
};
}
private final String name;
private final String description;
private final int id;
private final URL url;
private UserIcon(String name, String description, int id, String path) {
this.name = name;
this.description = description;
this.id = id;
this.url = Program.class.getResource(path);
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public int getId() {
return id;
}
public URL getUrl() {
return url;
}
public Image getImage() {
try {
return new Image(url.openStream());
} catch (IOException e) {
return null;
}
}
}
@@ -0,0 +1,20 @@
package dev.wiing.gossip.client.generic;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public record Pair<U, V>(@NotNull U first, @NotNull V second) {
public static <X, Y> Pair<X, Y> cast(Pair<? extends X, ? extends Y> second) {
return new Pair<>(second.first, second.second);
}
@Override
public String toString() {
return "Pair[" +
"first=" + first + ", " +
"second=" + second + ']';
}
}
@@ -0,0 +1,57 @@
package dev.wiing.gossip.client.utils;
import dev.wiing.gossip.client.Program;
import dev.wiing.gossip.client.generic.Pair;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Arrays;
public class Utils {
public static <T> Pair<Parent, T> createInstance(String res) {
FXMLLoader loader = new FXMLLoader(Program.class.getResource(res));
Parent parent;
try {
parent = loader.load();
} catch (IOException e) {
e.printStackTrace();
return null;
}
T controller = loader.getController();
return new Pair<>(parent, controller);
}
public static void openParentAsWindow(Parent parent, String title) {
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(parent));
stage.show();
}
public static void updateLabelColorOnText(Label label, TextField... texts) {
for (TextField text : texts) {
text.setOnKeyTyped(keyEvent -> updateLabelColorOnTextCallback(label, texts));
}
}
private static void updateLabelColorOnTextCallback(Label label, TextField... texts) {
boolean hadItems = label.getStyleClass().contains("accent");
if (Arrays.stream(texts).allMatch(textField -> textField.getText().isEmpty())) {
label.getStyleClass().remove("accent");
}
else if (Arrays.stream(texts).allMatch(textField -> !textField.getText().isEmpty() && !hadItems)) {
label.getStyleClass().add("accent");
}
}
}
+3
View File
@@ -2,8 +2,11 @@ module dev.wiing.gossip.client {
requires javafx.controls;
requires javafx.fxml;
requires dev.wiing.gossip.lib;
requires annotations;
requires java.desktop;
exports dev.wiing.gossip.client;
opens dev.wiing.gossip.client to javafx.fxml;
opens dev.wiing.gossip.client.controllers to javafx.fxml;
opens dev.wiing.gossip.client.controllers.item to javafx.fxml;
}

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1,11 @@
.gradient {
-fx-background-color: radial-gradient(radius 130%, ladder(#eee, -accent, #111), #111);
}
.topic-button.clickable:hover {
-fx-background-color: #fff1;
}
.topic-button.clickable.tag-min:hover {
-fx-background-color: ladder(hsb(0, 0%, 50%), -color, #0000);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

@@ -19,10 +19,10 @@
-fx-background-radius: 16px;
}
.list.container .viewport,
.list.container > .viewport,
.section,
.pane.list.container {
-fx-background-color: #19191d;
-fx-background-color: #88f1;
}
.list.container.dim .viewport {
@@ -34,12 +34,12 @@ SplitPane {
}
SplitPane .split-pane-divider {
-fx-background-color: #19191d;
-fx-background-color: #88f1;
-fx-padding: 0.0 5.0 0.0 0.0;
}
.elevated {
-fx-background-color: #25252c;
-fx-background-color: #88f2;
}
.border-radius {
@@ -52,18 +52,29 @@ SplitPane .split-pane-divider {
Label,
RadioButton,
TextField {
TextField,
TextArea {
-fx-text-fill: #fff;
-fx-fill: #fff;
}
TextArea,
TextArea .scroll-pane {
-fx-background-color: transparent;
}
TextArea .scroll-pane .content {
-fx-background-color: red;
}
ChoiceBox,
TextField {
-fx-background-color: #19191d;
TextField,
TextArea .scroll-pane .content {
-fx-background-color: #88f1;
}
ColorPicker {
-fx-background-color: #29292F;
-fx-background-color: #88f1;
-fx-padding: 4px 14px;
}
@@ -77,6 +88,12 @@ ColorPicker {
-fx-fill: #556;
}
.transparent,
.transparent.list.container .viewport,
TextArea.transparent .scroll-pane .content {
-fx-background-color: transparent;
}
.accent {
-fx-text-fill: -accent;
}
@@ -85,15 +102,10 @@ Separator {
-fx-opacity: 0.1;
}
Button {
-fx-background-color: -accent;
-fx-background-insets: 0;
-fx-text-fill: white;
-fx-padding: 4px 14px;
}
Button.gray {
Button.secondary {
-fx-background-color: #4a4a55;
-fx-border-width: 0px;
-fx-text-fill: white;
}
Button,
@@ -101,6 +113,17 @@ Button,
-fx-cursor: hand;
}
Button:hover {
-fx-background-color: ladder(hsb(0, 0%, 40%), -color, #0000);
-fx-text-fill: ladder(hsb(0, 0%, 50%), -color, #fff);
-fx-border-color: ladder(hsb(0, 0%, 50%), -color, #fff);
}
Button.secondary:hover {
-fx-background-color: #6c6c80;
-fx-text-fill: white;
}
ChoiceBox {
-fx-background-insets: 0;
}
@@ -109,7 +132,9 @@ ChoiceBox {
-fx-font-family: "AXIS Extra Bold";
}
Button,
Label.tag {
-color: -accent;
-fx-background-color: ladder(hsb(0, 0%, 70%), -color, #0000);
-fx-background-radius: 8px;
-fx-border-radius: 8px;
@@ -119,6 +144,21 @@ Label.tag {
-fx-padding: 6px 14px;
}
.tag-min {
-color: -accent;
-fx-background-color: ladder(hsb(0, 0%, 60%), -color, #0000);
-fx-text-fill: -color;
}
Label.tag.small {
-fx-background-color: -color;
-fx-background-radius: 4px;
-fx-border-width: 0;
-fx-text-fill: white;
-fx-font-size: 10px;
-fx-padding: 2px 8px;
}
CheckBox .box {
-fx-background-color: #25252c;
}
@@ -12,10 +12,11 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" spacing="16.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.LoginController">
<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" spacing="16.0" styleClass="gradient" xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.LoginController">
<stylesheets>
<URL value="@../styling.css" />
<URL value="@../scroll.css" />
<URL value="@../custom.css" />
</stylesheets>
<children>
<ImageView fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true">
@@ -31,13 +32,13 @@
</Label>
<HBox alignment="CENTER" spacing="16.0" VBox.vgrow="ALWAYS">
<children>
<AnchorPane fx:id="paneIcon" maxHeight="64.0" maxWidth="64.0" minHeight="64.0" minWidth="64.0" onMouseClicked="#onChangeIcon" onMouseEntered="#onIconMouseEnter" onMouseExited="#onIconMouseExit">
<AnchorPane fx:id="paneIcon" maxHeight="64.0" maxWidth="64.0" minHeight="64.0" minWidth="64.0" onMouseClicked="#onChangeIcon" onMouseEntered="#onIconMouseEnter" onMouseExited="#onIconMouseExit" style="-fx-background-color: white;">
<children>
<HBox fx:id="hboxEditOverlay" alignment="CENTER" mouseTransparent="true" opacity="0.0" style="-fx-background-color: #0006;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ImageView blendMode="HARD_LIGHT" fitHeight="32.0" fitWidth="32.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../edit.png" />
<Image url="@../icons/icon-edit.png" />
</image>
</ImageView>
</children>
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<AnchorPane xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.MainChatController">
<children>
<VBox fx:id="vboxVisitPage" alignment="CENTER" layoutX="10.0" layoutY="10.0" spacing="8.0" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<AnchorPane maxHeight="64.0" maxWidth="64.0" minHeight="64.0" minWidth="64.0">
<children>
<Circle blendMode="OVERLAY" fill="WHITE" opacity="0.7" radius="32.0" stroke="BLACK" strokeType="INSIDE" strokeWidth="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
<ImageView fitHeight="48.0" fitWidth="48.0" layoutX="8.0" layoutY="8.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="8.0" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="8.0" AnchorPane.topAnchor="8.0">
<image>
<Image url="@../icons/icon-hash.png" />
</image>
</ImageView>
</children>
</AnchorPane>
<Label fx:id="lblVisitTopicName" style="-fx-font-size: 20;" styleClass="axis" text="Topic name" />
<Label fx:id="lblVisitTopicDescription" text="Topic Description" />
<Label fx:id="lblVisitHostName" styleClass="accent" text="\@ Username" />
<Separator orientation="VERTICAL" prefHeight="20.0" visible="false" />
<Button mnemonicParsing="false" onAction="#onJoinTopic" text="Join">
<styleClass>
<String fx:value="axis" />
<String fx:value="secondary" />
</styleClass>
</Button>
<Label fx:id="lblVisitBabblerCount" styleClass="faint" text="2 babblers active" />
</children>
</VBox>
<VBox fx:id="vboxChatPage" spacing="16.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<HBox alignment="CENTER_LEFT" spacing="4.0">
<children>
<ImageView fitHeight="24.0" fitWidth="24.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/icon-hash.png" />
</image>
</ImageView>
<Label fx:id="lblTopicName" style="-fx-font-size: 16;" styleClass="axis" text="Label" />
<Label fx:id="lblBabblersCount" alignment="CENTER_RIGHT" maxWidth="1.7976931348623157E308" style="-fx-font-size: 12;" styleClass="faint" text="2 babblers" HBox.hgrow="ALWAYS" />
</children>
</HBox>
<ScrollPane fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
<content>
<VBox fx:id="vboxMessages" spacing="16.0">
<children>
<HBox spacing="8.0">
<children>
<Pane maxHeight="40.0" maxWidth="40.0" minHeight="40.0" minWidth="40.0" style="-fx-background-color: white;" />
<VBox alignment="CENTER_LEFT" minHeight="40.0" spacing="4.0" HBox.hgrow="ALWAYS">
<children>
<HBox alignment="BOTTOM_LEFT" spacing="8.0">
<children>
<Label style="-fx-font-size: 14;" text="\@ Username">
<styleClass>
<String fx:value="axis" />
<String fx:value="accent" />
</styleClass>
</Label>
<Label text="You">
<styleClass>
<String fx:value="tag" />
<String fx:value="small" />
<String fx:value="axis" />
</styleClass>
</Label>
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" maxWidth="1.7976931348623157E308" style="-fx-font-size: 10;" styleClass="faint" text="10 minutes ago" textAlignment="RIGHT" HBox.hgrow="ALWAYS" />
</children>
</HBox>
<VBox spacing="4.0">
<children>
<Label text="Message contents" />
</children>
</VBox>
</children>
</VBox>
</children>
</HBox>
<HBox alignment="CENTER_LEFT" layoutX="26.0" layoutY="26.0" spacing="8.0">
<children>
<ImageView fitHeight="20.0" fitWidth="20.0" opacity="0.5" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/door-enter.png" />
</image>
</ImageView>
<Label style="-fx-font-size: 14;" styleClass="axis" text="\@ Username" />
<Label layoutX="46.0" layoutY="19.0" style="-fx-font-size: 12;" text="joined the Topic" />
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" maxWidth="1.7976931348623157E308" style="-fx-font-size: 10;" styleClass="faint" text="10 minutes ago" textAlignment="RIGHT" HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets />
</HBox.margin>
</Label>
</children>
<padding>
<Insets bottom="8.0" left="16.0" right="16.0" top="8.0" />
</padding>
<styleClass>
<String fx:value="elevated" />
<String fx:value="border-radius-small" />
</styleClass>
</HBox>
</children>
<padding>
<Insets bottom="16.0" left="16.0" right="16.0" top="16.0" />
</padding>
</VBox>
</content>
<styleClass>
<String fx:value="container" />
<String fx:value="list" />
</styleClass>
</ScrollPane>
<VBox spacing="8.0">
<children>
<Label fx:id="lblTyping" style="-fx-font-size: 11;" styleClass="faint" text="Username, Username is typing ...">
<padding>
<Insets left="16.0" right="16.0" />
</padding>
</Label>
<HBox alignment="CENTER_LEFT" spacing="8.0">
<styleClass>
<String fx:value="container" />
<String fx:value="pane" />
<String fx:value="list" />
</styleClass>
<children>
<TextArea fx:id="txtCompose" maxHeight="1.7976931348623157E308" minHeight="1.0" prefHeight="24.0" prefRowCount="1" promptText="Compose..." styleClass="transparent" wrapText="true" HBox.hgrow="ALWAYS" />
<ImageView fitHeight="20.0" fitWidth="20.0" onMouseClicked="#onSend" opacity="0.5" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/icon-send-2.png" />
</image>
</ImageView>
</children>
<padding>
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
</padding>
</HBox>
</children>
</VBox>
</children>
</VBox>
</children>
<stylesheets>
<URL value="@../styling.css" />
<URL value="@../scroll.css" />
<URL value="@../custom.css" />
</stylesheets>
</AnchorPane>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<HBox fx:id="hboxParent" opacity="0.8" spacing="4.0" xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.item.MainTopicItemController">
<children>
<ImageView blendMode="OVERLAY" fitHeight="16.0" fitWidth="16.0" opacity="0.4" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/icon-hash.png" />
</image>
</ImageView>
<Label fx:id="lblTopicName" text="Label" />
</children>
<padding>
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
</padding>
<styleClass>
<String fx:value="border-radius-small" />
<String fx:value="clickable" />
<String fx:value="topic-button" />
</styleClass>
<stylesheets>
<URL value="@../styling.css" />
<URL value="@../custom.css" />
</stylesheets>
</HBox>
@@ -3,26 +3,63 @@
<?import java.lang.String?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<VBox alignment="TOP_RIGHT" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="594.0" prefWidth="948.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
<VBox fx:id="vboxRoot" alignment="TOP_RIGHT" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="486.0" prefWidth="750.0" spacing="16.0" style="-accent: hsb(0, 0%, 50%);;" styleClass="gradient" xmlns="http://javafx.com/javafx/20.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.wiing.gossip.client.controllers.MainController">
<stylesheets>
<URL value="@../styling.css" />
<URL value="@../scroll.css" />
<URL value="@../custom.css" />
</stylesheets>
<children>
<ImageView fitHeight="30.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../logo.png" />
</image>
</ImageView>
<SplitPane dividerPositions="0.29797979797979796" prefHeight="160.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
<HBox>
<children>
<ImageView blendMode="OVERLAY" fitHeight="30.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../logo.png" />
</image>
</ImageView>
<Separator maxWidth="1.7976931348623157E308" visible="false" HBox.hgrow="ALWAYS" />
<HBox spacing="8.0">
<children>
<VBox alignment="CENTER_RIGHT" minHeight="40.0" spacing="4.0" HBox.hgrow="ALWAYS">
<children>
<HBox alignment="BOTTOM_LEFT" spacing="8.0">
<children>
<Label fx:id="lblUsername" style="-fx-font-size: 14;" text="\@ Username">
<styleClass>
<String fx:value="axis" />
<String fx:value="accent" />
</styleClass>
</Label>
</children>
</HBox>
<Label style="-fx-font-size: 12;" text="Log out">
<styleClass>
<String fx:value="axis" />
<String fx:value="faint" />
</styleClass>
</Label>
</children>
</VBox>
<Pane fx:id="paneIcon" maxHeight="40.0" maxWidth="40.0" minHeight="40.0" minWidth="40.0" style="-fx-background-color: white;" />
</children>
</HBox>
</children>
</HBox>
<SplitPane dividerPositions="0.29797979797979796" prefHeight="160.0" prefWidth="200.0" styleClass="transparent" VBox.vgrow="ALWAYS">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<styleClass>
@@ -30,26 +67,210 @@
<String fx:value="pane" />
</styleClass>
<children>
<ScrollPane prefHeight="200.0" prefWidth="200.0" vbarPolicy="NEVER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0">
<children>
<VBox prefHeight="200.0" prefWidth="100.0" />
</children>
</AnchorPane>
</content>
<padding>
<Insets right="4.0" />
</padding>
<styleClass>
<String fx:value="container" />
<String fx:value="list" />
<String fx:value="dim" />
</styleClass>
</ScrollPane>
<VBox alignment="TOP_CENTER" spacing="16.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ScrollPane fitToHeight="true" fitToWidth="true" hbarPolicy="NEVER" VBox.vgrow="ALWAYS">
<content>
<VBox fx:id="vboxTopics" maxHeight="1.7976931348623157E308" spacing="8.0">
<children>
<HBox spacing="4.0">
<styleClass>
<String fx:value="tag-min" />
<String fx:value="border-radius-small" />
</styleClass>
<children>
<ImageView blendMode="OVERLAY" fitHeight="16.0" fitWidth="16.0" opacity="0.4" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/icon-hash.png" />
</image>
</ImageView>
<Label text="Label" />
</children>
<padding>
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
</padding>
</HBox>
<HBox layoutX="10.0" layoutY="10.0" opacity="0.8" spacing="4.0" styleClass="border-radius-small">
<children>
<ImageView blendMode="OVERLAY" fitHeight="16.0" fitWidth="16.0" opacity="0.4" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/icon-hash.png" />
</image>
</ImageView>
<Label text="Label" />
</children>
<padding>
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
</padding>
</HBox>
<HBox layoutX="10.0" layoutY="50.0" opacity="0.8" spacing="4.0" styleClass="border-radius-small">
<children>
<ImageView blendMode="OVERLAY" fitHeight="16.0" fitWidth="16.0" opacity="0.4" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/icon-hash.png" />
</image>
</ImageView>
<Label text="Label" />
</children>
<padding>
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
</padding>
</HBox>
</children>
</VBox>
</content>
<padding>
<Insets right="4.0" />
</padding>
<styleClass>
<String fx:value="container" />
<String fx:value="list" />
<String fx:value="transparent" />
</styleClass>
</ScrollPane>
<Button mnemonicParsing="false" onAction="#onCreateTopic" text="New TOPIC">
<styleClass>
<String fx:value="axis" />
<String fx:value="tag" />
</styleClass>
</Button>
</children>
</VBox>
</children>
<padding>
<Insets right="16.0" />
</padding>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane fx:id="paneContent" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<Label fx:id="lblJoinMessage" alignment="CENTER" style="-fx-font-size: 20;" text="Start or Join a Topic!" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<styleClass>
<String fx:value="axis" />
<String fx:value="accent" />
</styleClass>
</Label>
<AnchorPane layoutX="16.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<VBox alignment="CENTER" spacing="8.0" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<AnchorPane maxHeight="64.0" maxWidth="64.0" minHeight="64.0" minWidth="64.0">
<children>
<Circle blendMode="OVERLAY" fill="WHITE" opacity="0.7" radius="32.0" stroke="BLACK" strokeType="INSIDE" strokeWidth="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
<ImageView fitHeight="48.0" fitWidth="48.0" layoutX="8.0" layoutY="8.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="8.0" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="8.0" AnchorPane.topAnchor="8.0">
<image>
<Image url="@../icons/icon-hash.png" />
</image>
</ImageView>
</children>
</AnchorPane>
<Label style="-fx-font-size: 20;" styleClass="axis" text="Topic name" />
<Label text="Topic Description" />
<Label styleClass="accent" text="\@ Username" />
<Separator orientation="VERTICAL" prefHeight="20.0" visible="false" />
<Button mnemonicParsing="false" text="Join">
<styleClass>
<String fx:value="axis" />
<String fx:value="secondary" />
</styleClass>
</Button>
<Label styleClass="faint" text="2 babblers active" />
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="16.0" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<HBox alignment="CENTER_LEFT" spacing="4.0">
<children>
<ImageView fitHeight="24.0" fitWidth="24.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/icon-hash.png" />
</image>
</ImageView>
<Label style="-fx-font-size: 16;" styleClass="axis" text="Label" />
<Label alignment="CENTER_RIGHT" maxWidth="1.7976931348623157E308" style="-fx-font-size: 12;" styleClass="faint" text="2 babblers" HBox.hgrow="ALWAYS" />
</children>
</HBox>
<ScrollPane fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
<content>
<VBox spacing="16.0">
<children>
<HBox spacing="8.0">
<children>
<Pane maxHeight="40.0" maxWidth="40.0" minHeight="40.0" minWidth="40.0" style="-fx-background-color: white;" />
<VBox alignment="CENTER_LEFT" minHeight="40.0" spacing="4.0" HBox.hgrow="ALWAYS">
<children>
<HBox alignment="BOTTOM_LEFT" spacing="8.0">
<children>
<Label style="-fx-font-size: 14;" text="\@ Username">
<styleClass>
<String fx:value="axis" />
<String fx:value="accent" />
</styleClass>
</Label>
<Label text="You">
<styleClass>
<String fx:value="tag" />
<String fx:value="small" />
<String fx:value="axis" />
</styleClass>
</Label>
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" maxWidth="1.7976931348623157E308" style="-fx-font-size: 10;" styleClass="faint" text="10 minutes ago" textAlignment="RIGHT" HBox.hgrow="ALWAYS" />
</children>
</HBox>
<VBox spacing="4.0">
<children>
<Label text="Message contents" />
</children>
</VBox>
</children>
</VBox>
</children>
</HBox>
</children>
<padding>
<Insets bottom="16.0" left="16.0" right="16.0" top="16.0" />
</padding>
</VBox>
</content>
<styleClass>
<String fx:value="container" />
<String fx:value="list" />
</styleClass>
</ScrollPane>
<VBox spacing="8.0">
<children>
<Label style="-fx-font-size: 11;" styleClass="faint" text="Username, Username is typing ...">
<padding>
<Insets left="16.0" right="16.0" />
</padding>
</Label>
<HBox alignment="CENTER_LEFT" spacing="8.0">
<styleClass>
<String fx:value="container" />
<String fx:value="pane" />
<String fx:value="list" />
</styleClass>
<children>
<TextArea maxHeight="1.7976931348623157E308" minHeight="1.0" prefHeight="24.0" prefRowCount="1" promptText="Compose..." styleClass="transparent" wrapText="true" HBox.hgrow="ALWAYS" />
<ImageView fitHeight="20.0" fitWidth="20.0" opacity="0.5" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../icons/icon-send-2.png" />
</image>
</ImageView>
</children>
<padding>
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
</padding>
</HBox>
</children>
</VBox>
</children>
</VBox>
</children>
</AnchorPane>
</children>
<padding>
<Insets left="16.0" />
</padding></AnchorPane>
</items>
</SplitPane>
</children>