diff --git a/pom.xml b/pom.xml index bfabd47..fe62cbc 100644 --- a/pom.xml +++ b/pom.xml @@ -1,43 +1,167 @@ 4.0.0 - uk.ac.soton.comp1206 + uk.mgrove.ac.soton.comp1206 app 1.0-SNAPSHOT UTF-8 - 11 - 11 + 19 + 19 + 21-ea+5 + + + shade + + + org.openjfx + javafx-graphics + ${javafx.version} + win + + + org.openjfx + javafx-graphics + ${javafx.version} + mac + + + org.openjfx + javafx-graphics + ${javafx.version} + linux + + + org.openjfx + javafx-media + ${javafx.version} + win + + + org.openjfx + javafx-media + ${javafx.version} + mac + + + org.openjfx + javafx-media + ${javafx.version} + linux + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.4.1 + + + package + + shade + + + true + + + uk.mgrove.ac.soton.comp1206.Launcher + + + + + + + + + + org.openjfx javafx-controls - 19.0.2.1 + ${javafx.version} + + + org.openjfx + javafx-fxml + ${javafx.version} + + + org.openjfx + javafx-swing + ${javafx.version} + + + org.openjfx + javafx-media + ${javafx.version} + + + com.neovisionaries + nv-websocket-client + 2.14 + + + org.apache.logging.log4j + log4j-api + 2.20.0 + + + org.apache.logging.log4j + log4j-core + 2.20.0 + + org.apache.maven.plugins + maven-javadoc-plugin + 3.5.0 + org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.11.0 - 11 + 19 + 19 + 19 org.openjfx javafx-maven-plugin - 0.0.6 + 0.0.8 + + uk.mgrove.ac.soton.comp1206/uk.mgrove.ac.soton.comp1206.App + + + + maven-assembly-plugin + + + + + uk.mgrove.ac.soton.comp1206.Launcher + + + + + jar-with-dependencies + + true + - - - default-cli - - uk.ac.soton.comp1206.App - + make-assembly + package + + single + diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 48723d7..5b217dd 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,4 +1,22 @@ -module uk.ac.soton.comp1206 { +module uk.mgrove.ac.soton.comp1206 { + requires java.scripting; requires javafx.controls; - exports uk.ac.soton.comp1206; + requires javafx.fxml; + requires javafx.media; + requires javafx.swing; + requires java.desktop; + requires javafx.base; + requires org.apache.logging.log4j; + requires nv.websocket.client; + opens uk.mgrove.ac.soton.comp1206.ui to javafx.fxml; + opens uk.mgrove.ac.soton.comp1206.utility to javafx.fxml; + exports uk.mgrove.ac.soton.comp1206; + exports uk.mgrove.ac.soton.comp1206.ui; + exports uk.mgrove.ac.soton.comp1206.network; + exports uk.mgrove.ac.soton.comp1206.utility; + exports uk.mgrove.ac.soton.comp1206.ui.game; + opens uk.mgrove.ac.soton.comp1206.ui.game to javafx.fxml; + exports uk.mgrove.ac.soton.comp1206.ui.chat; + opens uk.mgrove.ac.soton.comp1206.ui.chat to javafx.fxml; } + diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/App.java b/src/main/java/uk/mgrove/ac/soton/comp1206/App.java index 6715fab..2e509ad 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/App.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/App.java @@ -1,30 +1,185 @@ -package uk.ac.soton.comp1206; +package uk.mgrove.ac.soton.comp1206; import javafx.application.Application; -import javafx.scene.Scene; -import javafx.scene.control.Label; -import javafx.scene.layout.StackPane; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.image.Image; import javafx.stage.Stage; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import uk.mgrove.ac.soton.comp1206.network.Communicator; +import uk.mgrove.ac.soton.comp1206.ui.BaseWindow; +import uk.mgrove.ac.soton.comp1206.ui.chat.ChatWindow; +import uk.mgrove.ac.soton.comp1206.ui.game.GameWindow; +import uk.mgrove.ac.soton.comp1206.ui.LoginWindow; +import uk.mgrove.ac.soton.comp1206.utility.Utility; + +import java.util.HashMap; +import java.util.Map; /** - * JavaFX App + * Our Chat application main class. This will be responsible for co-ordinating the application and handling the GUI. */ public class App extends Application { - @Override - public void start(Stage stage) { - var javaVersion = SystemInfo.javaVersion(); - var javafxVersion = SystemInfo.javafxVersion(); - - var label = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "."); - var scene = new Scene(new StackPane(label), 640, 480); - stage.setScene(scene); - stage.show(); - } + private static final Logger logger = LogManager.getLogger(App.class); + private Communicator communicator; + private Stage stage; + private final StringProperty username = new SimpleStringProperty("Guest"); + private final BooleanProperty gameOpen = new SimpleBooleanProperty(false); + private final Map windowStageMap = new HashMap<>(); + private ChatWindow chatWindow; + /** + * Launch the JavaFX application + * + * @param args arguments given when starting the client + */ public static void main(String[] args) { + logger.info("Starting client"); launch(); } -} \ No newline at end of file + /** + * Start the Java FX process - prepare and display the first window + * + * @param stage the stage to use + */ + @Override + public void start(Stage stage) { + this.stage = stage; + communicator = new Communicator("ws://ofb-labs.soton.ac.uk:9500"); + + stage.setTitle("ECS Instant Messenger (EIM)"); + stage.getIcons().add(new Image(getClass().getResourceAsStream("/uos_logo_square.png"))); + stage.setOnCloseRequest(ev -> { + shutdown(); + }); + + openLogin(); + } + + /** + * Display the login window + */ + public void openLogin() { + logger.info("Opening login window"); + var window = new LoginWindow(this); + stage.setScene(window.getScene()); + + stage.show(); + stage.centerOnScreen(); + } + + /** + * Display the chat window + */ + public void openChat() { + logger.info("Opening chat window"); + chatWindow = new ChatWindow(this, communicator); + + stage.setScene(chatWindow.getScene()); + + stage.show(); + stage.centerOnScreen(); + + Utility.playAudio("connected.mp3"); + } + + /** + * Display the game + */ + public void openGame() { + if (gameOpen.get()) return; + + logger.info("Opening game window"); + gameOpen.set(true); + + Stage stage = new Stage(); + stage.setTitle("Game - ECS Instant Messenger (EIM)"); + stage.getIcons().add(new Image(getClass().getResourceAsStream("/uos_logo_square.png"))); + var window = new GameWindow(this, communicator); + + stage.setScene(window.getScene()); + stage.show(); + stage.centerOnScreen(); + + windowStageMap.put(window, stage); + + hideChat(); + + stage.setOnCloseRequest((e) -> { + shutdown(); + }); + } + + /** + * Set the value of the gameOpen variable, which is used to track if the game window is open + * @param value value to set + */ + public void setGameOpen(boolean value) { + gameOpen.set(value); + } + + /** + * Return to chat window from other open window + * @param window current window, which should be closed + */ + public void returnToChat(BaseWindow window) { + if (windowStageMap.containsKey(window)) windowStageMap.get(window).close(); + showChat(); + } + + /** + * Move chat window to the background + */ + private void hideChat() { + if (chatWindow != null) stage.hide(); + } + + /** + * Show chat window + */ + private void showChat() { + if (chatWindow != null) stage.show(); + } + + /** + * Shutdown the application + */ + public void shutdown() { + logger.info("Shutting down"); + System.exit(0); + } + + /** + * Set the username from the login window + * + * @param username new username for current user + */ + public void setUsername(String username) { + logger.info("Username set to: " + username); + this.username.set(username); + } + + /** + * Get the currently logged-in username + * + * @return username of current user + */ + public String getUsername() { + return this.username.get(); + } + + /** + * Get the username property + * @return username property + */ + public StringProperty usernameProperty() { + return username; + } +} diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/Launcher.java b/src/main/java/uk/mgrove/ac/soton/comp1206/Launcher.java new file mode 100644 index 0000000..c7c0453 --- /dev/null +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/Launcher.java @@ -0,0 +1,21 @@ +package uk.mgrove.ac.soton.comp1206; + +/** + * Launcher class (which is used to launch the main App) + * + * This is used to allow creation of a shaded jar file, + * which cannot extend from the JavaFX Application + * + * You do not need to worry about this class + */ +public class Launcher { + + /** + * Start the main application and pass the arguments along + * @param args commandline arguments + */ + public static void main(String[] args) { + App.main(args); + } + +} diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/SystemInfo.java b/src/main/java/uk/mgrove/ac/soton/comp1206/SystemInfo.java deleted file mode 100644 index 67fb4a9..0000000 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/SystemInfo.java +++ /dev/null @@ -1,13 +0,0 @@ -package uk.ac.soton.comp1206; - -public class SystemInfo { - - public static String javaVersion() { - return System.getProperty("java.version"); - } - - public static String javafxVersion() { - return System.getProperty("javafx.version"); - } - -} \ No newline at end of file diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/network/Communicator.java b/src/main/java/uk/mgrove/ac/soton/comp1206/network/Communicator.java new file mode 100644 index 0000000..eacc292 --- /dev/null +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/network/Communicator.java @@ -0,0 +1,102 @@ +package uk.mgrove.ac.soton.comp1206.network; + +import com.neovisionaries.ws.client.WebSocket; +import com.neovisionaries.ws.client.WebSocketAdapter; +import com.neovisionaries.ws.client.WebSocketFactory; +import javafx.application.Platform; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import javafx.scene.control.Alert; +import uk.mgrove.ac.soton.comp1206.ui.chat.ChatWindow; +import uk.mgrove.ac.soton.comp1206.ui.chat.MessageListener; + +import java.util.ArrayList; +import java.util.List; + +/** + * Uses web sockets to talk to a web socket server and relays communication to the ChatWindow + * + * YOU DO NOT NEED TO WORRY ABOUT THIS CLASS! Leave it be :-) + */ +public class Communicator { + + private static final Logger logger = LogManager.getLogger(Communicator.class); + + private WebSocket ws = null; + private String server; + private ChatWindow window; + private final List listeners = new ArrayList<>(); + + /** + * Create a new communicator to the given web socket server + * + * @param server server to connect to + */ + public Communicator(String server) { + this.server = server; + + try { + var socketFactory = new WebSocketFactory(); + + //Connect to the server + ws = socketFactory.createSocket(server); + ws.connect(); + logger.info("Connected to " + server); + + //When a message is received, call the receive method + ws.addListener(new WebSocketAdapter() { + @Override + public void onTextMessage(WebSocket websocket, String message) throws Exception { + Communicator.this.receive(websocket, message); + } + }); + + } catch (Exception e){ + logger.error("Socket error: " + e.getMessage()); + e.printStackTrace(); + + Alert error = new Alert(Alert.AlertType.ERROR,"Unable to communicate with the ECSChat server\n\n" + e.getMessage() + "\n\nPlease ensure you are connected to the VPN"); + error.showAndWait(); + System.exit(1); + } + } + + /** Send a message to the server + * + * @param message Message to send + */ + public void send(String message) { + logger.info("Sending message: " + message); + + ws.sendText(message); + } + + /** Receive a message from the server. Relay to the Chat Window to handle + * + * @param websocket the socket + * @param message the message that was received + */ + private void receive(WebSocket websocket, String message) { + logger.info("Received: " + message); + + for (MessageListener listener : listeners) { + Platform.runLater(() -> listener.receiveMessage(message)); + } + } + + /** + * Add listener for when messages are received + * @param listener listener to add + */ + public void addListener(MessageListener listener) { + listeners.add(listener); + } + + /** + * Set the ChatWindow so the communicator can message it appropriately + * @param window chat window + */ + public void setWindow(ChatWindow window) { + this.window = window; + } +} diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/BaseWindow.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/BaseWindow.java index 74cc18a..93ef56a 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/BaseWindow.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/BaseWindow.java @@ -20,6 +20,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import uk.mgrove.ac.soton.comp1206.App; import uk.mgrove.ac.soton.comp1206.network.Communicator; +import uk.mgrove.ac.soton.comp1206.ui.chat.ChatWindow; import java.util.Arrays; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/LoginWindow.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/LoginWindow.java new file mode 100644 index 0000000..a765d4d --- /dev/null +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/LoginWindow.java @@ -0,0 +1,121 @@ +package uk.mgrove.ac.soton.comp1206.ui; + +import javafx.animation.FadeTransition; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.TextField; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.util.Duration; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import uk.mgrove.ac.soton.comp1206.App; + +import java.net.URL; +import java.util.ResourceBundle; + +/** + * Displays the Login Window, to collect the username and then start the chat + */ +public class LoginWindow implements Initializable { + + private static final Logger logger = LogManager.getLogger(LoginWindow.class); + private final App app; + + Scene scene = null; + Parent root = null; + + @FXML + private TextField myUsernameInput; + + /** + * Create a new Login Window, linked to the main app. This should get the username of the user. + * @param app the main app + */ + public LoginWindow(App app) { + this.app = app; + + //Load the Login Window GUI + try { + //Instead of building this GUI programmatically, we are going to use FXML + var loader = new FXMLLoader(getClass().getResource("/login.fxml")); + + //Link the GUI in the FXML to this class + loader.setController(this); + root = loader.load(); + } catch (Exception e) { + //Handle any exceptions with loading the FXML + logger.error("Unable to read file: " + e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + + root.setOpacity(0); + fadeInWindow(); + + //We are the login window + scene = new Scene(root); + } + + /** + * Get the scene contained inside the Login Window + * @return login window scene + */ + public Scene getScene() { + return scene; + } + + /** + * Handle what happens when the user presses the login button + * @param event button clicked + */ + @FXML protected void handleLogin(ActionEvent event) { + String user = myUsernameInput.getText(); + if(user.isBlank()) return; + app.setUsername(user); + app.openChat(); + } + + /** + * Handle what happens when the user presses enter on the username field + * @param event key pressed + */ + @FXML protected void handleUsernameKeypress(KeyEvent event) { + if(event.getCode() != KeyCode.ENTER) return; + handleLogin(null); + } + +// /** +// * Initialise the Login Window +// * @param url +// * @param bundle +// */ +// @Override +// public void initialize(URL url, ResourceBundle bundle) { +// //TODO: Any setting up of the window when it is initialised +// } + + /** + * Fade the root node from invisible to visible + */ + public void fadeInWindow() { + FadeTransition ft = new FadeTransition(Duration.millis(500),root); + ft.setFromValue(0); + ft.setToValue(1); + ft.play(); + } + + /** + * Initialise window - none required + * @param url URL to use + * @param resourceBundle resource bundle to use + */ + @Override + public void initialize(URL url, ResourceBundle resourceBundle) { + // no initialisation required + } +} diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/ChatWindow.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/ChatWindow.java index 737d9a4..97b8d0e 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/ChatWindow.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/ChatWindow.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.chat; import javafx.animation.FadeTransition; import javafx.application.Platform; @@ -17,6 +17,9 @@ import javafx.scene.text.Text; import javafx.util.Duration; import uk.mgrove.ac.soton.comp1206.App; import uk.mgrove.ac.soton.comp1206.network.Communicator; +import uk.mgrove.ac.soton.comp1206.ui.BaseWindow; +import uk.mgrove.ac.soton.comp1206.ui.chat.Message; +import uk.mgrove.ac.soton.comp1206.ui.chat.UserList; import uk.mgrove.ac.soton.comp1206.utility.Utility; import java.awt.event.ActionEvent; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/Message.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/Message.java index 659c370..9ccf370 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/Message.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/Message.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.chat; import javafx.scene.control.Hyperlink; import javafx.scene.text.Text; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/MessageListener.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/MessageListener.java index c0aceac..9c0197d 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/MessageListener.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/MessageListener.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.chat; /** * Interface for listeners that handle new messages being received by the Communicator class diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/User.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/User.java index 5fa5266..56151e3 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/User.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/User.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.chat; import javafx.animation.FadeTransition; import javafx.beans.binding.Bindings; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/UserList.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/UserList.java index 00d0e0d..7722bd0 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/UserList.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/chat/UserList.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.chat; import javafx.animation.FadeTransition; import javafx.beans.property.IntegerProperty; @@ -6,8 +6,7 @@ import javafx.beans.property.StringProperty; import javafx.scene.control.ScrollPane; import javafx.scene.layout.VBox; import javafx.util.Duration; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import uk.mgrove.ac.soton.comp1206.ui.chat.User; import java.util.ArrayList; import java.util.Comparator; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/BlockClickedListener.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/BlockClickedListener.java index 18ddf63..bf540f8 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/BlockClickedListener.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/BlockClickedListener.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.game; /** * Interface for listeners that handle a game block being clicked diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameBlock.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameBlock.java index 2d10140..4d1203f 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameBlock.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameBlock.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.game; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameGrid.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameGrid.java index 0f0f7b1..cca2fd8 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameGrid.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameGrid.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.game; import javafx.scene.layout.GridPane; import javafx.scene.paint.Color; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameWindow.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameWindow.java index 23ded6e..e127426 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameWindow.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/GameWindow.java @@ -1,31 +1,20 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.game; import javafx.application.Platform; -import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; -import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.control.Button; import javafx.scene.control.ProgressBar; -import javafx.scene.control.SplitPane; -import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; -import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Text; -import javafx.stage.Stage; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import uk.mgrove.ac.soton.comp1206.App; import uk.mgrove.ac.soton.comp1206.network.Communicator; -import uk.mgrove.ac.soton.comp1206.utility.Utility; +import uk.mgrove.ac.soton.comp1206.ui.BaseWindow; import java.util.*; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/Grid.java b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/Grid.java index 129f29c..af16d00 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/Grid.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/ui/game/Grid.java @@ -1,4 +1,4 @@ -package uk.mgrove.ac.soton.comp1206.ui; +package uk.mgrove.ac.soton.comp1206.ui.game; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/utility/Utility.java b/src/main/java/uk/mgrove/ac/soton/comp1206/utility/Utility.java new file mode 100644 index 0000000..53b00d2 --- /dev/null +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/utility/Utility.java @@ -0,0 +1,60 @@ +package uk.mgrove.ac.soton.comp1206.utility; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.regex.Pattern; + +/** + * A utility class for quick and handy static functions + */ +public class Utility { + + private static final Logger logger = LogManager.getLogger(Utility.class); + private static BooleanProperty audioEnabled = new SimpleBooleanProperty(true); + private static MediaPlayer mediaPlayer; + private static final String urlRegex = "((https?|file):((//)|(\\\\))+[\\w:#@%/;$()~_?+-=\\\\.&]*)"; + private static final Pattern urlPattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE); + + /** + * Play an audio file + * @param file filepath of file to play + */ + public static void playAudio(String file) { + if (!audioEnabled.get()) return; + + String toPlay = Utility.class.getResource("/" + file).toExternalForm(); + logger.info("Playing audio: " + toPlay); + + try { + Media play = new Media(toPlay); + mediaPlayer = new MediaPlayer(play); + mediaPlayer.play(); + } catch (Exception e) { + audioEnabled.set(false); + e.printStackTrace(); + logger.error("Unable to play audio file, disabling audio"); + } + } + + /** + * Get property for whether audio is enabled + * @return property + */ + public static BooleanProperty audioEnabledProperty() { + return audioEnabled; + } + + /** + * Get regex pattern for URLs + * @return URL pattern + */ + public static Pattern getUrlPattern() { + return urlPattern; + } + +}