diff --git a/README.md b/README.md new file mode 100644 index 0000000..70366a3 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Funky Log Client + +App to view logs from robot code. Utilizes custom compression algorithm to reduce log size by 25% on average. Also includes filtering and searches, which driver station console does not currently provide. Logs are sent over UDP from robot code. FunkyLogServer must be running on robot to receive logs. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6c39f7b --- /dev/null +++ b/pom.xml @@ -0,0 +1,51 @@ + + 4.0.0 + com.funkylogclient + funkylogclient + 1.0 + + UTF-8 + 11 + 11 + + + + org.openjfx + javafx-controls + 13 + + + org.openjfx + javafx-fxml + 13 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + + + + org.openjfx + javafx-maven-plugin + 0.0.6 + + + + + default-cli + + com.funkylogclient.App + + + + + + + diff --git a/src/main/java/com/funkylogclient/FunkyLogSorter.java b/src/main/java/com/funkylogclient/FunkyLogSorter.java new file mode 100644 index 0000000..1a0a54e --- /dev/null +++ b/src/main/java/com/funkylogclient/FunkyLogSorter.java @@ -0,0 +1,160 @@ +package com.funkylogclient; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.LinkedList; + +import javafx.stage.FileChooser; +import javafx.stage.Stage; + +public class FunkyLogSorter { + private static int MAX_LEN = 1200; + + private static boolean allowErrors = true; + private static boolean allowWarnings = true; + private static boolean allowLogs = true; + + private static String searchTerm = ""; + + public static LinkedList messages = new LinkedList<>(); + public static LinkedList filtered = new LinkedList<>(); + + public static void clear() { + messages.clear(); + filtered.clear(); + } + + public static void reFilter() { + filtered.clear(); + + for (Message m : messages) { + if (!checkMessageBySearch(m)) { + continue; + } else if (allowLogs && m.isLog()) { + filtered.add(m); + } else if (allowWarnings && m.isWarning()) { + filtered.add(m); + } else if (allowErrors && m.isError()) { + filtered.add(m); + } + } + } + + private static boolean checkMessageBySearch(Message msg) { + if (searchTerm.equals("")) return true; + + return msg.getSender().contains(searchTerm) || msg.getContent().contains(searchTerm); + } + + public static void trimMessages() { + int currentLength = messages.size(); + + if (currentLength <= MAX_LEN) + return; + + for (int i = 0; i <= currentLength - MAX_LEN; i++) { + messages.removeFirst(); + } + + if (filtered.size() > MAX_LEN) { + reFilter(); + } + } + + public static void addMessage(Message m) { + System.out.println(m); + + messages.add(m); + + if (!checkMessageBySearch(m)) { + + } else if (allowLogs && m.isLog()) { + filtered.add(m); + } else if (allowWarnings && m.isWarning()) { + filtered.add(m); + } else if (allowErrors && m.isError()) { + filtered.add(m); + } + + trimMessages(); + } + + public static void setErrorsAllowed(boolean allow) { + allowErrors = allow; + reFilter(); + } + + public static void setWarningsAllowed(boolean allow) { + allowWarnings = allow; + reFilter(); + } + + public static void setLogsAllowed(boolean allow) { + allowLogs = allow; + reFilter(); + } + + public static void changeSearchTerm(String term) { + searchTerm = term; + reFilter(); + } + + // Only for testing + public static void main(String[] args) { + // addMessage(new Message("0;1.0;a;abc")); + // addMessage(new Message("1;2.0;a;cde")); + // addMessage(new Message("2;2.0;a;cdef")); + + // logAllMessages(); + } + + public static void logAllMessages() { + System.out.println("\nSTART"); + for (Message m : filtered) { + System.out.println(m); + } + System.out.println("END\n"); + } + + public static String stringifyAllMessages() { + StringBuilder result = new StringBuilder(); + for (Message m : messages) { + result.append(m); + result.append("\n"); + } + return result.toString(); + } + + public static void saveToFile(Stage pstage) { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("Save Log File"); + + LocalDateTime dateTime = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); + String dateString = dateTime.format(formatter); + + fileChooser.setInitialFileName(dateString + ".log_846"); + + FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("FunkyLog (*.log_846)", "*.log_846"); + fileChooser.getExtensionFilters().add(extFilter); + + File file = fileChooser.showSaveDialog(pstage); + + if (file != null) { + try (FileWriter fileWriter = new FileWriter(file)) { + fileWriter.write(stringifyAllMessages()); + System.out.println("File saved to: " + file.getAbsolutePath()); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/src/main/java/com/funkylogclient/FunkyLogs.java b/src/main/java/com/funkylogclient/FunkyLogs.java new file mode 100644 index 0000000..e1eae64 --- /dev/null +++ b/src/main/java/com/funkylogclient/FunkyLogs.java @@ -0,0 +1,193 @@ +package com.funkylogclient; + +import java.util.LinkedList; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.concurrent.Task; +import javafx.geometry.*; +import javafx.scene.Scene; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.stage.Stage; +import javafx.stage.StageStyle; +import javafx.scene.Cursor; +import javafx.scene.text.*; + +public class FunkyLogs extends Application { + + private BorderPane root; + + private double xl = 100; + private double xr = 1100; + private double yu = 70; + private double yd = 650; + + private static VBox messageZone; + + private static boolean auto_scroll = true; + + private static String serverIP = UDPClient.serverIP; + private static int port = UDPClient.port; + + @Override + public void start(Stage primaryStage) { + primaryStage.setTitle("FunkyLogs v1.0.0"); + + root = new BorderPane(); + root.getStyleClass().add("root"); + + VBox center = new VBox(); + center.setStyle(Styles.CENTER); + center.setPadding(new Insets(10, 10, 10, 10)); + + VBox centerSearch = new VBox(); + centerSearch.setPadding(new Insets(5, 5, 15, 5)); + HBox withLabelToo = new HBox(15); + Text searchLabelText = new Text("Search: "); + searchLabelText.setStyle(Styles.TEXT_GMED); + withLabelToo.getChildren().add(searchLabelText); + TextField searchBar = new TextField(); + + searchBar.textProperty().addListener((observable, prevValue, newValue) -> { + FunkyLogSorter.changeSearchTerm(newValue); + }); + + searchBar.setPrefWidth(450); + withLabelToo.getChildren().add(searchBar); + centerSearch.getChildren().add(withLabelToo); + center.getChildren().add(centerSearch); + + messageZone = new VBox(); + messageZone.setPrefSize(100000, 100000); + messageZone.setPadding(new Insets(5, 20, 5, 20)); + messageZone.setSpacing(2.0); + messageZone.setStyle(Styles.SCROLL_PANE_STYLE); + + ScrollPane mScrollPane = new ScrollPane(messageZone); + mScrollPane.setFitToWidth(true); + mScrollPane.setFitToHeight(true); + messageZone.heightProperty().addListener((observable, oldValue, newValue) -> { + if (FunkyLogs.auto_scroll) mScrollPane.setVvalue(1.0); + }); + mScrollPane.setStyle(Styles.SCROLL_PANE_STYLE); + + center.getChildren().add(mScrollPane); + + root.setCenter(center); + + root.setRight(RightSidebar.getRightSidebar(getClass().getResource("logo.png"), + getClass().getResource("exit.png"), primaryStage, + (observable, prev, value) -> { FunkyLogs.auto_scroll = value; }, + (observable, prev, value) -> { FunkyLogs.serverIP = value; }, + (observable, prev, value) -> { FunkyLogs.port = Integer.parseInt(value); }, + (ev) -> { + UDPClient.setConnectionAddress(FunkyLogs.serverIP, FunkyLogs.port); + })); + + Scene scene = new Scene(root, Color.TRANSPARENT); + primaryStage.initStyle(StageStyle.TRANSPARENT); + primaryStage.setScene(scene); + primaryStage.show(); + + setStageSize(primaryStage); + + enableResizing(primaryStage, root); + + root.setStyle("-fx-background-radius: 10; -fx-background-color: #1E1E1E;"); + + Task updateTask = new Task() { + @Override + protected Void call() throws Exception { + for (;;) { + if (isCancelled()) { + break; + } + Thread.sleep(200); + try { + FunkyLogs.updateMessageZone(); + } catch (Exception exc) { + System.out.println(exc); + } + } + return null; + } + }; + + Thread updateThread = new Thread(updateTask); + updateThread.setDaemon(true); + updateThread.start(); + } + + private static void updateMessageZone() { + Platform.runLater(() -> { + FunkyLogs.messageZone.getChildren().clear(); + @SuppressWarnings("unchecked") + LinkedList fmessages_copy = (LinkedList) FunkyLogSorter.filtered.clone(); + for (Message msg : fmessages_copy) { + FunkyLogs.messageZone.getChildren().add(msg.getComponent()); + } + }); + } + + private void setStageSize(Stage stage) { + stage.setX(xl); + stage.setY(yu); + + stage.setWidth(Math.max(1000, xr - xl)); + stage.setHeight(Math.max(580, yd - yu)); + } + + private void enableResizing(Stage stage, BorderPane root) { + final int borderWidth = 14; + + root.setOnMouseMoved(event -> { + double mouseX = event.getX(); + double mouseY = event.getY(); + double width = root.getWidth(); + double height = root.getHeight(); + + if (mouseX > width - borderWidth && mouseY < borderWidth) { + root.setCursor(Cursor.NE_RESIZE); + } else if (mouseX < borderWidth && mouseY < borderWidth) { + root.setCursor(Cursor.NW_RESIZE); + } else if (mouseX < borderWidth && mouseY > height - borderWidth) { + root.setCursor(Cursor.SW_RESIZE); + } else if (mouseX > width - borderWidth && mouseY > height - borderWidth) { + root.setCursor(Cursor.SE_RESIZE); + } else { + root.setCursor(Cursor.CROSSHAIR); + } + }); + + root.setOnMouseDragged(event -> { + double mouseX = event.getScreenX(); + double mouseY = event.getScreenY(); + + if (root.getCursor() == Cursor.NW_RESIZE) { + xl = mouseX; + yu = mouseY; + } else if (root.getCursor() == Cursor.SW_RESIZE) { + xl = mouseX; + yd = mouseY; + } else if (root.getCursor() == Cursor.NE_RESIZE) { + xr = mouseX; + yu = mouseY; + } else if (root.getCursor() == Cursor.SE_RESIZE) { + xr = mouseX; + yd = mouseY; + } + setStageSize(stage); + }); + } + + public static void main(String[] args) { + // FunkyLogSorter.main(args); + + launch(args); + } +} \ No newline at end of file diff --git a/src/main/java/com/funkylogclient/Main.java b/src/main/java/com/funkylogclient/Main.java new file mode 100644 index 0000000..e49dbdb --- /dev/null +++ b/src/main/java/com/funkylogclient/Main.java @@ -0,0 +1,9 @@ +package com.funkylogclient; + +public class Main { + public static void main(String[] args) { + UDPClient.start(); + + FunkyLogs.main(args); + } +} diff --git a/src/main/java/com/funkylogclient/Message.java b/src/main/java/com/funkylogclient/Message.java new file mode 100644 index 0000000..a1822ca --- /dev/null +++ b/src/main/java/com/funkylogclient/Message.java @@ -0,0 +1,125 @@ +package com.funkylogclient; + +import javafx.geometry.Insets; +import javafx.scene.Node; +import javafx.scene.layout.Background; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import javafx.scene.text.Text; + +public class Message { + private int type; + + private String content; + private String sender; + private double time; + + public Message(String unparsed) { + try { + String[] split = unparsed.split(";"); + + type = Integer.parseInt(split[0]); + time = Double.parseDouble(split[3]); + sender = split[1]; + content = split[2]; + } catch (Exception exc) { + System.out.println("Error in parsing message: " + unparsed); + + content = new String(); + sender = new String("Unknown"); + time = 0.0; + } + } + + public Message(int type, String content, String sender, double time) { + this.type = type; + this.content = content; + this.sender = sender; + this.time = time; + } + + public String getContent() { + return content; + } + + public String getSender() { + return sender; + } + + public double getTime() { + return time; + } + + public boolean isLog() { + return type == 0; + } + + public boolean isWarning() { + return type == 1; + } + + public boolean isError() { + return type == 2; + } + + @Override + public String toString() { + String output = new String(); + if (isLog()) + output += "[LOG] "; + else if (isWarning()) + output += "[WARNING] "; + else if (isError()) + output += "[ERROR] "; + + output += "<"; + output += time; + output += "> "; + + output += sender; + output += ": "; + + output += content; + output += " "; + + return output; + } + + public Node getComponent() { + VBox box = new VBox(); + + String msg_style = Styles.DEFAULT_MSG; + + if (isError()) { + msg_style += "-fx-border-color: transparent transparent transparent #FF8272;"; + msg_style += "-fx-background-color: #302222"; + } else if (isWarning()) { + msg_style += "-fx-border-color: transparent transparent transparent #FFCC19;"; + msg_style += "-fx-background-color: #302D22"; + } else { + msg_style += "-fx-border-color: transparent transparent transparent transparent;"; + msg_style += "-fx-background-color: rgba(255, 255, 255, 0.00)"; + } + + box.setStyle(msg_style); + + box.setPadding(new Insets(5, 5, 5, 5)); + + Text top = new Text(time + " [" + sender + "]"); + top.setStyle(Styles.TEXT_STYLE + Styles.TEXT_SMALL); + + HBox body = new HBox(); + body.setPadding(new Insets(5, 5, 5, 30)); + + Text contentText = new Text(content); + contentText.setStyle(Styles.TEXT_STYLE + Styles.TEXT_SMALL); + contentText.setWrappingWidth(500); + + body.getChildren().add(contentText); + + box.getChildren().addAll(top, body); + + return box; + } +}; diff --git a/src/main/java/com/funkylogclient/RightSidebar.java b/src/main/java/com/funkylogclient/RightSidebar.java new file mode 100644 index 0000000..84b959f --- /dev/null +++ b/src/main/java/com/funkylogclient/RightSidebar.java @@ -0,0 +1,38 @@ +package com.funkylogclient; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import java.net.URL; + +import javafx.beans.value.ChangeListener; +import javafx.geometry.Insets; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; +import javafx.stage.Stage; + +public class RightSidebar { + public static VBox getRightSidebar(URL logoURL, URL exitImgURL, Stage primaryStage, ChangeListener autoScrollChangeListener, + ChangeListener addrFieldChangeListener, ChangeListener portFieldChangeListener, + EventHandler confirmButtonListener) { + VBox rightSidebar = new VBox(); + rightSidebar.setPadding(new Insets(5, 5, 10, 5)); + rightSidebar.setPrefWidth(200); + rightSidebar.setMaxWidth(200); + rightSidebar.setStyle(Styles.RIGHT_SIDEBAR_STYLE); + + rightSidebar.getChildren().add(SidebarTopSection.getTopSection(logoURL, exitImgURL, primaryStage)); + + Text title = new Text("FunkyLogs"); + title.setStyle(Styles.TEXT_STYLE + Styles.BOLD_TEXT); + rightSidebar.getChildren().add(title); + + rightSidebar.getChildren().addAll(SidebarFilters.getSidebarFilters()); + + rightSidebar.getChildren().add(SidebarOtherSettings.getSidebarOtherSettings(autoScrollChangeListener, primaryStage)); + + rightSidebar.getChildren().addAll(SidebarNetworkSettings.getSidebarNetworkSettings(addrFieldChangeListener, + portFieldChangeListener, confirmButtonListener)); + + return rightSidebar; + } +} diff --git a/src/main/java/com/funkylogclient/SidebarFilters.java b/src/main/java/com/funkylogclient/SidebarFilters.java new file mode 100644 index 0000000..07e4696 --- /dev/null +++ b/src/main/java/com/funkylogclient/SidebarFilters.java @@ -0,0 +1,100 @@ +package com.funkylogclient; + +import java.util.ArrayList; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.geometry.Insets; +import javafx.scene.Node; +import javafx.scene.control.CheckBox; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; + +public class SidebarFilters { + public static ArrayList getSidebarFilters() { + ArrayList filters = new ArrayList(); + + Region topSpacing = new Region(); + topSpacing.setMinHeight(20); + filters.add(topSpacing); + + Text filterByText = new Text("Filter by:"); + filterByText.setStyle(Styles.TEXT_STYLE); + filters.add(filterByText); + + Region midLinedSpacing = new Region(); + midLinedSpacing.setMinHeight(3); + midLinedSpacing.setStyle("-fx-border-width: 1px; -fx-border-color: transparent transparent #aaa transparent"); + filters.add(midLinedSpacing); + + filters.add(makeFiltersBox()); + + Region bottomLinedSpacing = new Region(); + bottomLinedSpacing.setMinHeight(10); + bottomLinedSpacing.setStyle("-fx-border-width: 1px; -fx-border-color: transparent transparent #aaa transparent"); + filters.add(bottomLinedSpacing); + + return filters; + } + + private static VBox makeFiltersBox() { + VBox filtersBox = new VBox(10); + filtersBox.setPadding(new Insets(15.0, 5.0, 5.0, 5.0)); + + HBox errorBox = new HBox(15); + + CheckBox errorsCheckBox = new CheckBox(); + errorsCheckBox.setSelected(true); + errorsCheckBox.selectedProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { + FunkyLogSorter.setErrorsAllowed(newValue); + } + }); + errorBox.getChildren().add(errorsCheckBox); + + Text errorBoxLabel = new Text("Errors"); + errorBoxLabel.setStyle(Styles.TEXT_MED); + errorBox.getChildren().add(errorBoxLabel); + + HBox warningBox = new HBox(15); + + CheckBox warningsCheckBox = new CheckBox(); + warningsCheckBox.setSelected(true); + warningsCheckBox.selectedProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { + FunkyLogSorter.setWarningsAllowed(newValue); + } + }); + warningBox.getChildren().add(warningsCheckBox); + + Text warningBoxLabel = new Text("Warnings"); + warningBoxLabel.setStyle(Styles.TEXT_MED); + warningBox.getChildren().add(warningBoxLabel); + + HBox logsBox = new HBox(15); + + CheckBox logsCheckBox = new CheckBox(); + logsCheckBox.selectedProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { + FunkyLogSorter.setLogsAllowed(newValue); + } + }); + logsCheckBox.setSelected(true); + logsBox.getChildren().add(logsCheckBox); + + Text logsBoxLabel = new Text("Logs"); + logsBoxLabel.setStyle(Styles.TEXT_MED); + logsBox.getChildren().add(logsBoxLabel); + + filtersBox.getChildren().add(errorBox); + filtersBox.getChildren().add(warningBox); + filtersBox.getChildren().add(logsBox); + + return filtersBox; + } +} diff --git a/src/main/java/com/funkylogclient/SidebarNetworkSettings.java b/src/main/java/com/funkylogclient/SidebarNetworkSettings.java new file mode 100644 index 0000000..97e6375 --- /dev/null +++ b/src/main/java/com/funkylogclient/SidebarNetworkSettings.java @@ -0,0 +1,49 @@ +package com.funkylogclient; + +import java.util.ArrayList; + +import javafx.beans.value.ChangeListener; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.TextField; +import javafx.scene.layout.Region; +import javafx.scene.text.Text; + +public class SidebarNetworkSettings { + public static ArrayList getSidebarNetworkSettings(ChangeListener addrFieldChangeListener, + ChangeListener portFieldChangeListener, EventHandler confirmButtonListener) { + ArrayList networkSettings = new ArrayList(); + + Region topLinedSpacing = new Region(); + topLinedSpacing.setMinHeight(15); + topLinedSpacing.setStyle("-fx-border-width: 1px; -fx-border-color: transparent transparent #aaa transparent"); + networkSettings.add(topLinedSpacing); + + Region topSpacing = new Region(); + topSpacing.setMinHeight(15); + networkSettings.add(topSpacing); + + Text nwSettingsLabel = new Text("Server address, port: "); + nwSettingsLabel.setStyle(Styles.TEXT_GMED); + networkSettings.add(nwSettingsLabel); + + TextField addressField = new TextField(); + addressField.setText(UDPClient.serverIP); + addressField.textProperty().addListener(addrFieldChangeListener); + networkSettings.add(addressField); + + TextField portField = new TextField(); + portField.setText("" + UDPClient.port); + + portField.textProperty().addListener(portFieldChangeListener); + networkSettings.add(portField); + + Button confirmAddrButton = new Button("Confirm"); + confirmAddrButton.setOnAction(confirmButtonListener); + networkSettings.add(confirmAddrButton); + + return networkSettings; + } +} diff --git a/src/main/java/com/funkylogclient/SidebarOtherSettings.java b/src/main/java/com/funkylogclient/SidebarOtherSettings.java new file mode 100644 index 0000000..39fe106 --- /dev/null +++ b/src/main/java/com/funkylogclient/SidebarOtherSettings.java @@ -0,0 +1,47 @@ +package com.funkylogclient; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; +import javafx.stage.Stage; + +public class SidebarOtherSettings { + public static VBox getSidebarOtherSettings(ChangeListener autoScrollChangeListener, Stage primaryStage) { + VBox otherSettingsBox = new VBox(); + otherSettingsBox.setPadding(new Insets(25, 5, 5, 5)); + + Text autoScrollLabel = new Text("Auto-scroll:"); + autoScrollLabel.setStyle(Styles.TEXT_MED); + otherSettingsBox.getChildren().add(autoScrollLabel); + + CheckBox autoScrollCheckBox = new CheckBox(); + autoScrollCheckBox.setSelected(true); + autoScrollCheckBox.selectedProperty().addListener(autoScrollChangeListener); + otherSettingsBox.getChildren().add(autoScrollCheckBox); + + Region midSpacing = new Region(); + midSpacing.setMinHeight(20); + otherSettingsBox.getChildren().add(midSpacing); + + Button clearLogsButton = new Button("Clear logs"); + clearLogsButton.setOnAction((ev) -> {FunkyLogSorter.clear();}); + + otherSettingsBox.getChildren().add(clearLogsButton); + + Region buttonSpacing = new Region(); + buttonSpacing.setMinHeight(20); + otherSettingsBox.getChildren().add(buttonSpacing); + + Button exportButton = new Button("Save logs"); + exportButton.setOnAction((ev) -> {FunkyLogSorter.saveToFile(primaryStage);}); + otherSettingsBox.getChildren().add(exportButton); + + + return otherSettingsBox; + } +} diff --git a/src/main/java/com/funkylogclient/SidebarTopSection.java b/src/main/java/com/funkylogclient/SidebarTopSection.java new file mode 100644 index 0000000..0eba13c --- /dev/null +++ b/src/main/java/com/funkylogclient/SidebarTopSection.java @@ -0,0 +1,53 @@ +package com.funkylogclient; + +import java.net.URL; + +import javafx.geometry.Pos; +import javafx.scene.effect.ColorAdjust; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.stage.Stage; + +public class SidebarTopSection { + public static HBox getTopSection(URL logoURL, URL exitImgURL, Stage primaryStage) { + ImageView logoImage = new ImageView(logoURL.toString()); + logoImage.setStyle(Styles.LOGO_STYLE); + + HBox logoImgBox = new HBox(logoImage); + logoImgBox.setAlignment(Pos.TOP_LEFT); + logoImgBox.setPrefWidth(1000); + + HBox exitImgBox = new HBox(); + exitImgBox.setPrefWidth(30); + exitImgBox.setPrefHeight(20); + exitImgBox.setMaxHeight(20); + + ImageView exitImage = new ImageView(exitImgURL.toString()); + + exitImgBox.getChildren().add(exitImage); + + ColorAdjust normalColorAdjust = new ColorAdjust(); + normalColorAdjust.setBrightness(-0.5); + + ColorAdjust hoverColorAdjust = new ColorAdjust(); + hoverColorAdjust.setBrightness(0.5); + + exitImgBox.setOnMouseClicked((MouseEvent e) -> { + primaryStage.close(); + }); + exitImgBox.setOnMouseEntered((MouseEvent e) -> { + exitImage.setEffect(hoverColorAdjust); + }); + exitImgBox.setOnMouseExited((MouseEvent e) -> { + exitImage.setEffect(normalColorAdjust); + }); + + HBox topSection = new HBox(10); + topSection.setAlignment(Pos.TOP_RIGHT); + + topSection.getChildren().addAll(logoImgBox, exitImgBox); + + return topSection; + } +} diff --git a/src/main/java/com/funkylogclient/Styles.java b/src/main/java/com/funkylogclient/Styles.java new file mode 100644 index 0000000..d14169c --- /dev/null +++ b/src/main/java/com/funkylogclient/Styles.java @@ -0,0 +1,22 @@ +package com.funkylogclient; + +public class Styles { + public static final String CENTER = ""; + + public static final String LOGO_STYLE = "-fx-border-width: 5px;"; + + public static final String TEXT_STYLE = "-fx-font-size: 20px; -fx-fill: #aaa; -fx-font-family: Poppins;"; + public static final String TEXT_MED = "-fx-font-size: 14px; -fx-fill: #aaa; -fx-font-family: Poppins;"; + public static final String TEXT_GMED = "-fx-font-size: 16px; -fx-fill: #aaa; -fx-font-family: Poppins;"; + public static final String TEXT_SMALL = "-fx-font-size: 14px;"; + public static final String BOLD_TEXT = " -fx-font-weight: bold;"; + + public static final String DEFAULT_MSG = "-fx-border-width: 3px;"; + + public static final String SCROLL_PANE_STYLE = "-fx-background-color: #1E1E1E;"; + + public static final String RIGHT_SIDEBAR_STYLE = + "-fx-background-radius:10; -fx-background-color: #1E1E1E;" + + "-fx-border-color: transparent transparent transparent #fff; -fx-border-width: 0.2px;"; + +} \ No newline at end of file diff --git a/src/main/java/com/funkylogclient/UDPClient.java b/src/main/java/com/funkylogclient/UDPClient.java new file mode 100644 index 0000000..fdd8b93 --- /dev/null +++ b/src/main/java/com/funkylogclient/UDPClient.java @@ -0,0 +1,115 @@ +package com.funkylogclient; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class UDPClient { + public static String serverIP = "10.8.46.2"; + public static int port = 5808; + + public static void setConnectionAddress(String newServerIP, int newPort) { + System.out.println("Setting connection address to " + newServerIP + ":" + newPort); + serverIP = newServerIP; + port = newPort; + } + + private static final String ENCODING = "\nabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()[]<>|;:',./?~_- "; + + // private static Queue recv_messages = new LinkedList<>(); + + private static void threadFN() { + try { + DatagramSocket socket = new DatagramSocket(); + socket.setSoTimeout(500); + + long lastKeepAlive = System.currentTimeMillis() - 4000; + for (;;) { + InetAddress serverAddress; + try { + serverAddress = InetAddress.getByName(UDPClient.serverIP); + } catch (Exception exc) { + continue; + } + + long ctime = System.currentTimeMillis(); + if (ctime - lastKeepAlive > 500) { + byte[] sendData = "~~~".getBytes(); + DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, UDPClient.port); + socket.send(sendPacket); + + lastKeepAlive = ctime; + } + + byte[] receiveData = new byte[16800]; + DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); + + try { + socket.receive(receivePacket); + } catch (SocketTimeoutException exc) { + continue; + } catch (Exception exc) { + continue; + } + + for (String line : parse(receivePacket.getData())) { + // UDPClient.recv_messages.add(line); + FunkyLogSorter.addMessage(new Message(line)); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static String decompress(byte[] input) { + StringBuilder xarr = new StringBuilder(); + for (byte b : input) { + String binaryStrX = String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0'); + xarr.append(binaryStrX); + } + + boolean capNext = false; + StringBuilder out = new StringBuilder(); + for (int i = 0; i < xarr.length(); i += 6) { + try { + String bitSegment = xarr.substring(i, Math.min(i + 6, xarr.length())); + int index = Integer.parseInt(bitSegment, 2); + char nextChar = ENCODING.charAt(index); + if (capNext) { + nextChar = Character.toUpperCase(nextChar); + } + capNext = false; + out.append(nextChar); + } catch (Exception e) { + capNext = true; + } + } + + return out.toString(); + } + + private static String[] parse(byte[] input) { + String decompressed = decompress(input); + return decompressed.split("\n"); + } + + public static void start() { + Thread networkingThread = new Thread(UDPClient::threadFN); + networkingThread.setDaemon(true); + networkingThread.start(); + } +} + diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000..12575be --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.funkylogclient { + requires javafx.controls; + requires javafx.fxml; + requires javafx.graphics; + requires javafx.base; + + opens com.funkylogclient to javafx.fxml; + exports com.funkylogclient; +} diff --git a/src/main/resources/com/funkylogclient/exit.png b/src/main/resources/com/funkylogclient/exit.png new file mode 100644 index 0000000..edfecd6 Binary files /dev/null and b/src/main/resources/com/funkylogclient/exit.png differ diff --git a/src/main/resources/com/funkylogclient/logo.png b/src/main/resources/com/funkylogclient/logo.png new file mode 100644 index 0000000..b296293 Binary files /dev/null and b/src/main/resources/com/funkylogclient/logo.png differ diff --git a/target/classes/com/funkylogclient/FunkyLogSorter.class b/target/classes/com/funkylogclient/FunkyLogSorter.class new file mode 100644 index 0000000..35976cc Binary files /dev/null and b/target/classes/com/funkylogclient/FunkyLogSorter.class differ diff --git a/target/classes/com/funkylogclient/FunkyLogs$1.class b/target/classes/com/funkylogclient/FunkyLogs$1.class new file mode 100644 index 0000000..f5c6d72 Binary files /dev/null and b/target/classes/com/funkylogclient/FunkyLogs$1.class differ diff --git a/target/classes/com/funkylogclient/FunkyLogs.class b/target/classes/com/funkylogclient/FunkyLogs.class new file mode 100644 index 0000000..87c7ddc Binary files /dev/null and b/target/classes/com/funkylogclient/FunkyLogs.class differ diff --git a/target/classes/com/funkylogclient/Main.class b/target/classes/com/funkylogclient/Main.class new file mode 100644 index 0000000..e02a17b Binary files /dev/null and b/target/classes/com/funkylogclient/Main.class differ diff --git a/target/classes/com/funkylogclient/Message.class b/target/classes/com/funkylogclient/Message.class new file mode 100644 index 0000000..7101c2b Binary files /dev/null and b/target/classes/com/funkylogclient/Message.class differ diff --git a/target/classes/com/funkylogclient/RightSidebar.class b/target/classes/com/funkylogclient/RightSidebar.class new file mode 100644 index 0000000..1a2347b Binary files /dev/null and b/target/classes/com/funkylogclient/RightSidebar.class differ diff --git a/target/classes/com/funkylogclient/SidebarFilters$1.class b/target/classes/com/funkylogclient/SidebarFilters$1.class new file mode 100644 index 0000000..6d247d8 Binary files /dev/null and b/target/classes/com/funkylogclient/SidebarFilters$1.class differ diff --git a/target/classes/com/funkylogclient/SidebarFilters$2.class b/target/classes/com/funkylogclient/SidebarFilters$2.class new file mode 100644 index 0000000..57c7484 Binary files /dev/null and b/target/classes/com/funkylogclient/SidebarFilters$2.class differ diff --git a/target/classes/com/funkylogclient/SidebarFilters$3.class b/target/classes/com/funkylogclient/SidebarFilters$3.class new file mode 100644 index 0000000..743581d Binary files /dev/null and b/target/classes/com/funkylogclient/SidebarFilters$3.class differ diff --git a/target/classes/com/funkylogclient/SidebarFilters.class b/target/classes/com/funkylogclient/SidebarFilters.class new file mode 100644 index 0000000..fdbdb3b Binary files /dev/null and b/target/classes/com/funkylogclient/SidebarFilters.class differ diff --git a/target/classes/com/funkylogclient/SidebarNetworkSettings.class b/target/classes/com/funkylogclient/SidebarNetworkSettings.class new file mode 100644 index 0000000..b1a9ac5 Binary files /dev/null and b/target/classes/com/funkylogclient/SidebarNetworkSettings.class differ diff --git a/target/classes/com/funkylogclient/SidebarOtherSettings.class b/target/classes/com/funkylogclient/SidebarOtherSettings.class new file mode 100644 index 0000000..24bd18a Binary files /dev/null and b/target/classes/com/funkylogclient/SidebarOtherSettings.class differ diff --git a/target/classes/com/funkylogclient/SidebarTopSection.class b/target/classes/com/funkylogclient/SidebarTopSection.class new file mode 100644 index 0000000..8aad688 Binary files /dev/null and b/target/classes/com/funkylogclient/SidebarTopSection.class differ diff --git a/target/classes/com/funkylogclient/Styles.class b/target/classes/com/funkylogclient/Styles.class new file mode 100644 index 0000000..8db3536 Binary files /dev/null and b/target/classes/com/funkylogclient/Styles.class differ diff --git a/target/classes/com/funkylogclient/UDPClient.class b/target/classes/com/funkylogclient/UDPClient.class new file mode 100644 index 0000000..bc43de6 Binary files /dev/null and b/target/classes/com/funkylogclient/UDPClient.class differ diff --git a/target/classes/com/funkylogclient/exit.png b/target/classes/com/funkylogclient/exit.png new file mode 100644 index 0000000..edfecd6 Binary files /dev/null and b/target/classes/com/funkylogclient/exit.png differ diff --git a/target/classes/com/funkylogclient/logo.png b/target/classes/com/funkylogclient/logo.png new file mode 100644 index 0000000..b296293 Binary files /dev/null and b/target/classes/com/funkylogclient/logo.png differ diff --git a/target/classes/module-info.class b/target/classes/module-info.class new file mode 100644 index 0000000..a8772e0 Binary files /dev/null and b/target/classes/module-info.class differ