diff --git a/.idea/compiler.xml b/.idea/compiler.xml index ede0b46..abaf24f 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -11,10 +11,5 @@ - - - - - \ No newline at end of file diff --git a/Client/pom.xml b/Client/pom.xml index 1a04367..8855526 100644 --- a/Client/pom.xml +++ b/Client/pom.xml @@ -45,6 +45,12 @@ ${junit.version} test + + org.jetbrains + annotations + 16.0.1 + compile + diff --git a/Client/src/main/java/dev/wiing/gossip/client/Connection.java b/Client/src/main/java/dev/wiing/gossip/client/Connection.java index c400349..efb88db 100644 --- a/Client/src/main/java/dev/wiing/gossip/client/Connection.java +++ b/Client/src/main/java/dev/wiing/gossip/client/Connection.java @@ -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 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 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; } } diff --git a/Client/src/main/java/dev/wiing/gossip/client/controllers/LoginController.java b/Client/src/main/java/dev/wiing/gossip/client/controllers/LoginController.java index 95105ab..119daad 100644 --- a/Client/src/main/java/dev/wiing/gossip/client/controllers/LoginController.java +++ b/Client/src/main/java/dev/wiing/gossip/client/controllers/LoginController.java @@ -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())); } } diff --git a/Client/src/main/java/dev/wiing/gossip/client/controllers/MainChatController.java b/Client/src/main/java/dev/wiing/gossip/client/controllers/MainChatController.java new file mode 100644 index 0000000..91c1c5e --- /dev/null +++ b/Client/src/main/java/dev/wiing/gossip/client/controllers/MainChatController.java @@ -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 createInstance() { + return Utils.createInstance("views/main-chat-view.fxml"); + } + +} diff --git a/Client/src/main/java/dev/wiing/gossip/client/controllers/MainController.java b/Client/src/main/java/dev/wiing/gossip/client/controllers/MainController.java new file mode 100644 index 0000000..42bab5b --- /dev/null +++ b/Client/src/main/java/dev/wiing/gossip/client/controllers/MainController.java @@ -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 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 createInstance() { + return Utils.createInstance("views/main-view.fxml"); + } + +} diff --git a/Client/src/main/java/dev/wiing/gossip/client/controllers/item/MainTopicItemController.java b/Client/src/main/java/dev/wiing/gossip/client/controllers/item/MainTopicItemController.java new file mode 100644 index 0000000..db76afd --- /dev/null +++ b/Client/src/main/java/dev/wiing/gossip/client/controllers/item/MainTopicItemController.java @@ -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 createInstance() { + return Utils.createInstance("views/main-topic-item.fxml"); + } + + public void setOnMouseClicked(EventHandler eventHandler) { + hboxParent.setOnMouseClicked(eventHandler); + } + +} diff --git a/Client/src/main/java/dev/wiing/gossip/client/data/UserAvatar.java b/Client/src/main/java/dev/wiing/gossip/client/data/UserAvatar.java new file mode 100644 index 0000000..6ff88e0 --- /dev/null +++ b/Client/src/main/java/dev/wiing/gossip/client/data/UserAvatar.java @@ -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); + } + } +} diff --git a/Client/src/main/java/dev/wiing/gossip/client/data/UserIcon.java b/Client/src/main/java/dev/wiing/gossip/client/data/UserIcon.java deleted file mode 100644 index fc7d2b8..0000000 --- a/Client/src/main/java/dev/wiing/gossip/client/data/UserIcon.java +++ /dev/null @@ -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; - } - } -} diff --git a/Client/src/main/java/dev/wiing/gossip/client/generic/Pair.java b/Client/src/main/java/dev/wiing/gossip/client/generic/Pair.java new file mode 100644 index 0000000..c06836d --- /dev/null +++ b/Client/src/main/java/dev/wiing/gossip/client/generic/Pair.java @@ -0,0 +1,20 @@ +package dev.wiing.gossip.client.generic; + +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public record Pair(@NotNull U first, @NotNull V second) { + + public static Pair cast(Pair second) { + return new Pair<>(second.first, second.second); + } + + @Override + public String toString() { + return "Pair[" + + "first=" + first + ", " + + "second=" + second + ']'; + } + +} diff --git a/Client/src/main/java/dev/wiing/gossip/client/utils/Utils.java b/Client/src/main/java/dev/wiing/gossip/client/utils/Utils.java new file mode 100644 index 0000000..942269a --- /dev/null +++ b/Client/src/main/java/dev/wiing/gossip/client/utils/Utils.java @@ -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 Pair 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"); + } + } + +} diff --git a/Client/src/main/java/module-info.java b/Client/src/main/java/module-info.java index 9736d4f..41d05ac 100644 --- a/Client/src/main/java/module-info.java +++ b/Client/src/main/java/module-info.java @@ -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; } \ No newline at end of file diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_0.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-0.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_0.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-0.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_1.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-1.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_1.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-1.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_2.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-2.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_2.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-2.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_3.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-3.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_3.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-3.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_4.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-4.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_4.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-4.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_5.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-5.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_5.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-5.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_6.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-6.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_6.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-6.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_7.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-7.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_7.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-7.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_8.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-8.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_8.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-8.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon_9.png b/Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-9.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/icons/icon_9.png rename to Client/src/main/resources/dev/wiing/gossip/client/avatars/avatar-9.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/custom.css b/Client/src/main/resources/dev/wiing/gossip/client/custom.css new file mode 100644 index 0000000..68a6b85 --- /dev/null +++ b/Client/src/main/resources/dev/wiing/gossip/client/custom.css @@ -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); +} \ No newline at end of file diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/door-enter.png b/Client/src/main/resources/dev/wiing/gossip/client/icons/door-enter.png new file mode 100644 index 0000000..f43fdca Binary files /dev/null and b/Client/src/main/resources/dev/wiing/gossip/client/icons/door-enter.png differ diff --git a/Client/src/main/resources/dev/wiing/gossip/client/edit.png b/Client/src/main/resources/dev/wiing/gossip/client/icons/icon-edit.png similarity index 100% rename from Client/src/main/resources/dev/wiing/gossip/client/edit.png rename to Client/src/main/resources/dev/wiing/gossip/client/icons/icon-edit.png diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon-hash.png b/Client/src/main/resources/dev/wiing/gossip/client/icons/icon-hash.png new file mode 100644 index 0000000..bdc27ed Binary files /dev/null and b/Client/src/main/resources/dev/wiing/gossip/client/icons/icon-hash.png differ diff --git a/Client/src/main/resources/dev/wiing/gossip/client/icons/icon-send-2.png b/Client/src/main/resources/dev/wiing/gossip/client/icons/icon-send-2.png new file mode 100644 index 0000000..46eda0d Binary files /dev/null and b/Client/src/main/resources/dev/wiing/gossip/client/icons/icon-send-2.png differ diff --git a/Client/src/main/resources/dev/wiing/gossip/client/styling.css b/Client/src/main/resources/dev/wiing/gossip/client/styling.css index 1545f52..ab0a444 100644 --- a/Client/src/main/resources/dev/wiing/gossip/client/styling.css +++ b/Client/src/main/resources/dev/wiing/gossip/client/styling.css @@ -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; } diff --git a/Client/src/main/resources/dev/wiing/gossip/client/views/login-view.fxml b/Client/src/main/resources/dev/wiing/gossip/client/views/login-view.fxml index 8d2ee5c..8c4c8f6 100644 --- a/Client/src/main/resources/dev/wiing/gossip/client/views/login-view.fxml +++ b/Client/src/main/resources/dev/wiing/gossip/client/views/login-view.fxml @@ -12,10 +12,11 @@ - + + @@ -31,13 +32,13 @@ - + - + diff --git a/Client/src/main/resources/dev/wiing/gossip/client/views/main-chat-view.fxml b/Client/src/main/resources/dev/wiing/gossip/client/views/main-chat-view.fxml new file mode 100644 index 0000000..154e3ba --- /dev/null +++ b/Client/src/main/resources/dev/wiing/gossip/client/views/main-chat-view.fxml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +