Greatly Overhaul GUI and get server in a usable state
This commit is contained in:
parent
9a1e6e925a
commit
61edfb42af
@ -2,21 +2,25 @@ package net.xircon.xenon.client;
|
||||
|
||||
|
||||
import com.formdev.flatlaf.FlatDarkLaf;
|
||||
import net.xircon.xenon.client.io.CustomOutputStream;
|
||||
import net.xircon.xenon.client.io.Log;
|
||||
import net.xircon.xenon.client.io.Util;
|
||||
import net.xircon.xenon.client.networking.Networking;
|
||||
import net.xircon.xenon.client.networking.textclient.TextClient;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.PrintStream;
|
||||
import java.net.Socket;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Xenon implements Runnable {
|
||||
private Thread mainThread;
|
||||
public static void main(String[] args) {new Xenon().start();}
|
||||
private static Socket mainSocket;
|
||||
public Color buttonColour = new Color(55, 90, 129);
|
||||
public Image xenonIcon;
|
||||
|
||||
static final String propertiesFile = "client.properties";
|
||||
// Properties
|
||||
@ -28,12 +32,39 @@ public class Xenon implements Runnable {
|
||||
private static String nickname = "Test User";
|
||||
|
||||
public void start() {
|
||||
mainThread = new Thread(this, "mainThread");
|
||||
Thread mainThread = new Thread(this, "mainThread");
|
||||
mainThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Load Icon
|
||||
xenonIcon = Util.loadIcon("xenon.png");
|
||||
|
||||
// Set Swing LaF before all Swing Stuff gets init
|
||||
try {
|
||||
UIManager.setLookAndFeel( new FlatDarkLaf());
|
||||
} catch (UnsupportedLookAndFeelException e) {
|
||||
Log.err("Java Swing GUI Look and Feel Did Not Correctly Apply! Falling Back to Default!");
|
||||
}
|
||||
// Start Swing Logger ASAP
|
||||
// Disable this If the entire thing dies :)
|
||||
JFrame logFrame = new JFrame("Xenon Log");
|
||||
logFrame.setIconImage(xenonIcon);
|
||||
// logFrame.setLayout(new BorderLayout());
|
||||
logFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
logFrame.setSize(640,480);
|
||||
JTextArea logText = new JTextArea();
|
||||
logText.setAutoscrolls(true);
|
||||
logText.setLineWrap(true);
|
||||
logText.setEditable(false);
|
||||
JScrollPane logScrollPane = new JScrollPane(logText);
|
||||
logFrame.add(logScrollPane);
|
||||
PrintStream systemOutput = new PrintStream(new CustomOutputStream(logText));
|
||||
System.setOut(systemOutput);
|
||||
System.setErr(systemOutput);
|
||||
|
||||
|
||||
Log.info("Starting Xenon Client!");
|
||||
// Get Property Values
|
||||
PortVoIP = Objects.requireNonNull(Util.GetProperties(propertiesFile, "PortVoIP", Util.PROPERTY_TYPE_INT)).intValue;
|
||||
@ -43,21 +74,17 @@ public class Xenon implements Runnable {
|
||||
|
||||
// Start Java Swing GUI
|
||||
JFrame mainFrame = new JFrame("Xenon Client");
|
||||
mainFrame.setIconImage(xenonIcon);
|
||||
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
mainFrame.setSize(Width, Height);
|
||||
try {
|
||||
UIManager.setLookAndFeel( new FlatDarkLaf());
|
||||
} catch (UnsupportedLookAndFeelException e) {
|
||||
Log.err("Java Swing GUI Look and Feel Did Not Correctly Apply! Falling Back to Default!");
|
||||
}
|
||||
|
||||
// Creating the MenuBar and adding components
|
||||
JMenuBar mb = new JMenuBar();
|
||||
JMenuBar menubar = new JMenuBar();
|
||||
// Menu 1
|
||||
JMenu m1 = new JMenu("File");
|
||||
JMenuItem m11 = new JMenuItem("Open");
|
||||
JMenuItem m12 = new JMenuItem("Save as");
|
||||
mb.add(m1);
|
||||
menubar.add(m1);
|
||||
m1.add(m11);
|
||||
m1.add(m12);
|
||||
// Menu 2
|
||||
@ -66,8 +93,7 @@ public class Xenon implements Runnable {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String IPAddress = JOptionPane.showInputDialog(null, "IP Address Of Server", "127.0.0.1");
|
||||
if (IPAddress == null) {return;}
|
||||
else {
|
||||
if (IPAddress != null) {
|
||||
mainSocket = Networking.connectToServer(IPAddress, PortText);
|
||||
}
|
||||
}
|
||||
@ -82,27 +108,53 @@ public class Xenon implements Runnable {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String Nick = JOptionPane.showInputDialog(null, "New Nickname", nickname);
|
||||
if (Nick == null) {return;}
|
||||
else {
|
||||
if (Nick != null) {
|
||||
nickname = Nick;
|
||||
}
|
||||
}
|
||||
});
|
||||
mb.add(m2);
|
||||
menubar.add(m2);
|
||||
m2.add(m21);
|
||||
m2.add(m22);
|
||||
m2.add(m23);
|
||||
|
||||
// Menu 3
|
||||
JMenu m3 = new JMenu("Help");
|
||||
JMenuItem m31 = new JMenuItem(new AbstractAction("About") {
|
||||
JMenu m3 = new JMenu("Edit");
|
||||
// Preferences Menu
|
||||
JFrame preferences = preferencesJFrame();
|
||||
JMenuItem m31 = new JMenuItem(new AbstractAction("Preferences") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
preferences.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
menubar.add(m3);
|
||||
m3.add(m31);
|
||||
|
||||
//Menu 4
|
||||
JMenu m4 = new JMenu("View");
|
||||
JMenuItem m41 = new JMenuItem(new AbstractAction("Log") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
logFrame.setVisible(true);
|
||||
}
|
||||
});
|
||||
menubar.add(m4);
|
||||
m4.add(m41);
|
||||
|
||||
// Menu 5
|
||||
JMenu m5 = new JMenu("Help");
|
||||
JMenuItem m51 = new JMenuItem(new AbstractAction("About") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
JOptionPane.showMessageDialog(null, "Xenon Created By Xircon\nLicenced under the GNU GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.en.html)",
|
||||
"About Xenon", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
});
|
||||
mb.add(m3);
|
||||
m3.add(m31);
|
||||
menubar.add(m5);
|
||||
m5.add(m51);
|
||||
|
||||
|
||||
// Creating the panel at bottom and adding components
|
||||
@ -112,7 +164,9 @@ public class Xenon implements Runnable {
|
||||
sendField.setToolTipText("Enter Message");
|
||||
sendField.setPreferredSize(new Dimension(200 ,20 ));
|
||||
JButton send = new JButton("Send");
|
||||
send.setBackground(buttonColour);
|
||||
JButton upload = new JButton("Upload");
|
||||
upload.setBackground(buttonColour);
|
||||
panel.add(sendField, BorderLayout.CENTER);
|
||||
JPanel buttonPanel = new JPanel();
|
||||
buttonPanel.setLayout(new BorderLayout());
|
||||
@ -125,19 +179,98 @@ public class Xenon implements Runnable {
|
||||
if (mainSocket == null) {JOptionPane.showMessageDialog(null, "Ensure you are Connected to a Server!", "Error", JOptionPane.ERROR_MESSAGE);}
|
||||
else {
|
||||
Log.info("Sending " + sendField.getText());
|
||||
Networking.sendMessage(sendField.getText(), nickname, mainSocket);
|
||||
Thread textClient = new Thread(new TextClient(mainSocket, nickname, sendField.getText()));
|
||||
textClient.start();
|
||||
SwingUtilities.invokeLater(() -> sendField.setText(""));
|
||||
}
|
||||
});
|
||||
|
||||
// Text Area at the Center
|
||||
JTextArea ta = new JTextArea();
|
||||
// Central Panel With Text Stuffs
|
||||
JPanel centrePanel = new JPanel();
|
||||
JTextArea textarea = new JTextArea();
|
||||
textarea.setAutoscrolls(true);
|
||||
textarea.setLineWrap(true);
|
||||
textarea.setEditable(false);
|
||||
textarea.setBackground(new Color(70,73,75));
|
||||
centrePanel.setLayout(new BorderLayout());
|
||||
centrePanel.add(panel, BorderLayout.SOUTH);
|
||||
centrePanel.add(textarea, BorderLayout.CENTER);
|
||||
|
||||
// Side Panel
|
||||
JPanel sidePanel = sideJPanel();
|
||||
|
||||
//Adding Components to the Frame.
|
||||
mainFrame.getContentPane().add(BorderLayout.SOUTH, panel);
|
||||
mainFrame.getContentPane().add(BorderLayout.NORTH, mb);
|
||||
mainFrame.getContentPane().add(BorderLayout.CENTER, ta);
|
||||
mainFrame.getContentPane().add(BorderLayout.NORTH, menubar);
|
||||
mainFrame.getContentPane().add(BorderLayout.CENTER, centrePanel);
|
||||
mainFrame.getContentPane().add(BorderLayout.WEST, sidePanel);
|
||||
// Set GUI To Visible
|
||||
mainFrame.setVisible(true);
|
||||
}
|
||||
|
||||
private @NonNull JPanel sideJPanel() {
|
||||
JPanel sidePanel = new JPanel(new BorderLayout());
|
||||
sidePanel.setBackground(new Color(60,63,65));
|
||||
JPanel bottomSidePanel = new JPanel(new BorderLayout());
|
||||
// Mute Button
|
||||
JToggleButton muteButton = muteJToggleButton();
|
||||
|
||||
// Deaf Button
|
||||
JToggleButton deafButton = deafJToggleButton();
|
||||
|
||||
bottomSidePanel.add(muteButton, BorderLayout.WEST);
|
||||
bottomSidePanel.add(deafButton, BorderLayout.CENTER);
|
||||
sidePanel.add(bottomSidePanel, BorderLayout.SOUTH);
|
||||
return sidePanel;
|
||||
}
|
||||
|
||||
private @NonNull JToggleButton deafJToggleButton() {
|
||||
JToggleButton deafButton = new JToggleButton("Deafen");
|
||||
deafButton.setBackground(buttonColour);
|
||||
deafButton.setForeground(Color.WHITE);
|
||||
deafButton.setFocusPainted(false);
|
||||
deafButton.setBorderPainted(false);
|
||||
deafButton.addActionListener(e -> {
|
||||
if (deafButton.isSelected()) {
|
||||
deafButton.setBackground(Color.RED); // Change to RED
|
||||
} else {
|
||||
deafButton.setBackground(buttonColour);
|
||||
}
|
||||
});
|
||||
return deafButton;
|
||||
}
|
||||
|
||||
private @NonNull JToggleButton muteJToggleButton() {
|
||||
JToggleButton muteButton = new JToggleButton("Mute");
|
||||
muteButton.setBackground(buttonColour);
|
||||
muteButton.setForeground(Color.WHITE);
|
||||
muteButton.setFocusPainted(false);
|
||||
muteButton.setBorderPainted(false);
|
||||
muteButton.addActionListener(e -> {
|
||||
if (muteButton.isSelected()) {
|
||||
muteButton.setBackground(Color.RED); // Change to RED
|
||||
} else {
|
||||
muteButton.setBackground(buttonColour);
|
||||
}
|
||||
});
|
||||
return muteButton;
|
||||
}
|
||||
|
||||
private @NonNull JFrame preferencesJFrame() {
|
||||
JFrame preferences = new JFrame("Preferences");
|
||||
preferences.setSize(800,600);
|
||||
preferences.setIconImage(xenonIcon);
|
||||
preferences.setLayout(new BorderLayout());
|
||||
preferences.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
JPanel preferencesSidePanel = new JPanel(new BorderLayout());
|
||||
JButton preferencesGeneralButton = new JButton(new AbstractAction("General") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
}
|
||||
});
|
||||
preferencesSidePanel.add(preferencesGeneralButton);
|
||||
preferences.add(preferencesSidePanel, BorderLayout.WEST);
|
||||
|
||||
return preferences;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package net.xircon.xenon.client.io;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class CustomOutputStream extends OutputStream {
|
||||
private JTextArea textArea;
|
||||
|
||||
public CustomOutputStream(JTextArea textArea) {
|
||||
this.textArea = textArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
// redirects data to the text area
|
||||
textArea.append(String.valueOf((char)b));
|
||||
// scrolls the text area to the end of data
|
||||
textArea.setCaretPosition(textArea.getDocument().getLength());
|
||||
// keeps the textArea up to date
|
||||
textArea.update(textArea.getGraphics());
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ package net.xircon.xenon.client.io;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.core.Appender;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
@ -23,3 +24,4 @@ public class Log {
|
||||
logger.info(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package net.xircon.xenon.client.io;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
public class Util {
|
||||
@ -47,6 +47,7 @@ public class Util {
|
||||
Log.warn("[Property Loader] Unable to Find Property/Invalid Type!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String GetExternalIP() throws IOException {
|
||||
URL whatismyip = new URL("http://checkip.amazonaws.com");
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(
|
||||
@ -55,4 +56,13 @@ public class Util {
|
||||
// Return IP As String
|
||||
return in.readLine();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static BufferedImage loadIcon(String path) {
|
||||
try {
|
||||
return ImageIO.read(Objects.requireNonNull(Util.class.getClassLoader().getResource(path)));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import java.net.SocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
||||
public class Networking {
|
||||
private static final String nameTerminator = "\uffff";
|
||||
|
||||
|
||||
@Nullable
|
||||
public static Socket connectToServer(String Address, int Port) {
|
||||
@ -44,18 +44,4 @@ public class Networking {
|
||||
Log.warn("Ignoring Disconnect Request, Null Socket!");
|
||||
}
|
||||
}
|
||||
|
||||
public static String sendMessage(String message, String nickname, Socket socket) {
|
||||
try {
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
|
||||
output.println(nickname + nameTerminator + message);
|
||||
String messageFromServer = input.readLine();
|
||||
Log.info("Server Message: " + messageFromServer);
|
||||
return messageFromServer;
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not Read/Send Message!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,33 @@
|
||||
package net.xircon.xenon.client.networking.textclient;
|
||||
|
||||
import net.xircon.xenon.client.io.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
|
||||
public class TextClient implements Runnable {
|
||||
private final String nameTerminator = "\uffff";
|
||||
private String nickname;
|
||||
private String message;
|
||||
private Socket socket;
|
||||
|
||||
public TextClient(Socket serverSocket) {
|
||||
|
||||
public TextClient(Socket serverSocket, String nickname, String message) {
|
||||
this.socket = serverSocket; this.message = message; this.nickname = nickname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
|
||||
output.println(nickname + nameTerminator + message);
|
||||
String messageFromServer = input.readLine();
|
||||
Log.info("Server Message: " + messageFromServer);
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not Read/Send Message!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
client/src/main/resources/xenon.jpg
Normal file
BIN
client/src/main/resources/xenon.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
client/src/main/resources/xenon.png
Normal file
BIN
client/src/main/resources/xenon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Loading…
x
Reference in New Issue
Block a user