Spruce up JavaFX client, README

This commit is contained in:
Charles Gould 2020-05-20 00:17:07 -05:00
parent 79884e8e8e
commit 47b7980f24
18 changed files with 93 additions and 118 deletions

View File

@ -5,7 +5,7 @@ packages:
sources: sources:
- https://git.sr.ht/~crg/lingo - https://git.sr.ht/~crg/lingo
artifacts: artifacts:
- lingo/server/target/lingo-server-1.0.jar - lingo/server/target/lingo-server.jar
tasks: tasks:
- build: | - build: |
cd lingo cd lingo

View File

@ -1,19 +1,24 @@
# Lingo WebSocket ## Lingo
Lingo with WebSockets A word guessing game based on the [game show](https://en.wikipedia.org/wiki/Lingo_(American_game_show)).
## Build #### Browser client
`mvn clean install` - Practice: https://lingo.charego.com/practice.html
- Competitive: https://lingo.charego.com
## Launch server #### JavaFX client
`mvn -f ./server/pom.xml spring-boot:run` - Requirements: Java 11, Maven 3
- Build: `mvn clean install`
- Start client: `mvn -f client javafx:run`
## Launch client #### Running locally
`mvn -f ./client/pom.xml exec:java` - Build: `mvn clean install`
- Start server
Practice: <http://localhost:8080/practice.html> * Default port (8080): `java -jar server/target/lingo-server.jar`
* Custom port: `java -jar server/target/lingo-server.jar --server.port=<port>`
Multiplayer: <http://localhost:8080> - Start client
* Browser: `open http://localhost:<port>`
* JavaFX: `mvn -f client javafx:run -Dlingo-url=http://localhost:<port>`

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/lingo-websocket-client/src/main/java/lingo/client/bootstrap/LingoClient.java"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/lingo-websocket-client/src/main/config&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;lingo-websocket-client&quot; type=&quot;1&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER&quot; path=&quot;3&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="lingo.client.bootstrap.LingoClient"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="lingo-websocket-client"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
</launchConfiguration>

View File

@ -13,6 +13,7 @@
<properties> <properties>
<javafx.version>11.0.2</javafx.version> <javafx.version>11.0.2</javafx.version>
<lingo.url>https://lingo.charego.com</lingo.url>
</properties> </properties>
<dependencies> <dependencies>
@ -48,15 +49,23 @@
<build> <build>
<plugins> <plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.4</version>
<configuration>
<mainClass>com.charego.lingo.client.bootstrap.LingoClient</mainClass>
<options>
<option>-Dlingo.url=${lingo.url}</option>
</options>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId> <artifactId>exec-maven-plugin</artifactId>
<configuration> <configuration>
<mainClass>com.charego.lingo.client.bootstrap.LingoClient</mainClass> <mainClass>com.charego.lingo.client.bootstrap.LingoClient</mainClass>
<addResourcesToClasspath>true</addResourcesToClasspath> <addResourcesToClasspath>true</addResourcesToClasspath>
<additionalClasspathElements>
<additionalClasspathElement>src/main/config</additionalClasspathElement>
</additionalClasspathElements>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>

View File

@ -1,14 +0,0 @@
# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
# Development
web.base.url: http://localhost:8080
web.socket.url: ws://localhost:8080/sockjs
# Production
#web.base.url: https://lingo.charego.com
#web.socket.url: wss://lingo.charego.com/sockjs
# Logging
logging:
level:
com.charego.lingo: DEBUG

View File

@ -66,8 +66,9 @@ public class MultiplayerConfig {
@Bean @Bean
public RestTemplate restTemplate(Environment env) { public RestTemplate restTemplate(Environment env) {
String webServerUrl = env.getRequiredProperty("lingo.url");
RestTemplate restTemplate = new RestTemplate(); RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(new RootUriTemplateHandler(env.getProperty("web.base.url"))); restTemplate.setUriTemplateHandler(new RootUriTemplateHandler(webServerUrl));
return restTemplate; return restTemplate;
} }

View File

@ -10,7 +10,7 @@ import javax.annotation.PreDestroy;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment;
import org.springframework.core.task.TaskExecutor; import org.springframework.core.task.TaskExecutor;
import org.springframework.messaging.simp.stomp.StompCommand; import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompFrameHandler; import org.springframework.messaging.simp.stomp.StompFrameHandler;
@ -26,8 +26,8 @@ public class StompTemplate {
private static final Logger log = LoggerFactory.getLogger(StompTemplate.class); private static final Logger log = LoggerFactory.getLogger(StompTemplate.class);
@Value("${web.socket.url}") @Autowired
private String webSocketUrl; private Environment env;
@Autowired @Autowired
private TaskExecutor taskExecutor; private TaskExecutor taskExecutor;
@ -49,6 +49,8 @@ public class StompTemplate {
@PostConstruct @PostConstruct
private void postConstruct() { private void postConstruct() {
String webServerUrl = env.getRequiredProperty("lingo.url");
String webSocketUrl = webServerUrl.replace("http", "ws") + "/sockjs";
log.info("Connecting to STOMP endpoint: " + webSocketUrl); log.info("Connecting to STOMP endpoint: " + webSocketUrl);
taskExecutor.execute(() -> stompClient.connect(webSocketUrl, new WebSocketSessionHandler())); taskExecutor.execute(() -> stompClient.connect(webSocketUrl, new WebSocketSessionHandler()));
taskExecutor.execute(new WebSocketSessionListener()); taskExecutor.execute(new WebSocketSessionListener());

View File

@ -44,7 +44,7 @@ public class SinglePlayerPresenter {
public SinglePlayerPresenter(WordRepository wordRepo, int wordLength, EventHandler<ActionEvent> backButtonHandler) { public SinglePlayerPresenter(WordRepository wordRepo, int wordLength, EventHandler<ActionEvent> backButtonHandler) {
backButton = new Button("Back"); backButton = new Button("Back");
backButton.getStyleClass().add("game-nav"); backButton.getStyleClass().add("navigation");
StackPane.setAlignment(backButton, Pos.BOTTOM_LEFT); StackPane.setAlignment(backButton, Pos.BOTTOM_LEFT);
StackPane.setMargin(backButton, new Insets(0, 0, 10, 10)); StackPane.setMargin(backButton, new Insets(0, 0, 10, 10));
backButton.setOnAction(backButtonHandler); backButton.setOnAction(backButtonHandler);

View File

@ -15,4 +15,8 @@ module com.charego.lingo.client {
requires spring.messaging; requires spring.messaging;
requires spring.web; requires spring.web;
requires spring.websocket; requires spring.websocket;
exports com.charego.lingo.client.bootstrap;
exports com.charego.lingo.client.multiplayer;
opens com.charego.lingo.client.bootstrap to javafx.fxml, spring.core;
opens com.charego.lingo.client.multiplayer to javafx.fxml, spring.core;
} }

View File

@ -0,0 +1,2 @@
# https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html
logging.level.com.charego.lingo = DEBUG

View File

@ -3,6 +3,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.geometry.Pos?> <?import javafx.geometry.Pos?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?> <?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
@ -14,16 +15,20 @@
<center> <center>
<BorderPane fx:id="gameModeChooser"> <BorderPane fx:id="gameModeChooser">
<top>
<VBox alignment="CENTER" prefHeight="100.0" prefWidth="100.0" styleClass="header">
<Label text="Lingo" styleClass="title"/>
<Label text="word guessing game" styleClass="subtitle"/>
</VBox>
</top>
<center> <center>
<VBox spacing="20" alignment="CENTER"> <VBox spacing="20" alignment="CENTER">
<children> <Button text="Play a practice game" onAction="#showSinglePlayer" prefWidth="350" styleClass="gamemode,practice" />
<Button text="Practice" onAction="#showSinglePlayer" prefWidth="350" styleClass="game-mode" /> <Button text="Join a multiplayer game" onAction="#showMultiplayer" prefWidth="350" styleClass="gamemode,multiplayer" />
<Button text="Multiplayer" onAction="#showMultiplayer" prefWidth="350" styleClass="game-mode" />
</children>
</VBox> </VBox>
</center> </center>
<bottom> <bottom>
<Button text="Exit" onAction="#exit" prefWidth="50" styleClass="game-nav"> <Button text="Exit" onAction="#exit" prefWidth="50" styleClass="navigation">
<BorderPane.alignment> <BorderPane.alignment>
<Pos fx:value="BOTTOM_LEFT" /> <Pos fx:value="BOTTOM_LEFT" />
</BorderPane.alignment> </BorderPane.alignment>

View File

@ -14,7 +14,7 @@
<children> <children>
<Canvas fx:id="canvas" width="650" height="420" onKeyPressed="#keyPressed" /> <Canvas fx:id="canvas" width="650" height="420" onKeyPressed="#keyPressed" />
<WebView fx:id="webView" prefWidth="650" prefHeight="420" /> <WebView fx:id="webView" prefWidth="650" prefHeight="420" />
<Button fx:id="backButton" text="Back" prefWidth="50" styleClass="game-nav"> <Button fx:id="backButton" text="Back" prefWidth="50" styleClass="navigation">
<StackPane.alignment> <StackPane.alignment>
<Pos fx:value="BOTTOM_LEFT" /> <Pos fx:value="BOTTOM_LEFT" />
</StackPane.alignment> </StackPane.alignment>

View File

@ -1,12 +1,43 @@
.button {
-fx-cursor: hand;
}
.text { .text {
-fx-font-family: Helvetica; -fx-font-family: Helvetica;
-fx-font-smoothing-type: gray; -fx-font-smoothing-type: gray;
} }
.game-mode { .header {
-fx-background-color: steelblue;
}
.title {
-fx-font-size: 32px;
-fx-text-fill: white;
}
.subtitle {
-fx-font-size: 24px;
-fx-text-fill: lightgray;
}
.gamemode {
-fx-background-radius: 10px;
-fx-border-color: black;
-fx-border-radius: 10px;
-fx-font-size: 24px; -fx-font-size: 24px;
} }
.game-nav { .gamemode.practice {
-fx-font-size: 12px; -fx-text-fill: forestgreen;
}
.gamemode.multiplayer {
-fx-text-fill: steelblue;
}
.navigation {
-fx-background-color: steelblue;
-fx-font-size: 12px;
-fx-text-fill: white;
} }

12
pom.xml
View File

@ -23,18 +23,8 @@
<modules> <modules>
<module>api</module> <module>api</module>
<module>common</module> <module>common</module>
<module>client</module>
<module>server</module> <module>server</module>
</modules> </modules>
<profiles>
<!-- Disable client module by default -->
<!-- The build fails under headless JDK -->
<profile>
<id>javafx</id>
<modules>
<module>client</module>
</modules>
</profile>
</profiles>
</project> </project>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/lingo-websocket-server/src/main/java/lingo/server/LingoServer.java"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/lingo-websocket-server/src/main/config&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;lingo-websocket-server&quot; type=&quot;1&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER&quot; path=&quot;3&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="lingo.server.LingoServer"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="lingo-websocket-server"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
</launchConfiguration>

View File

@ -43,10 +43,7 @@
<!-- Add src/main/resources to the classpath --> <!-- Add src/main/resources to the classpath -->
<!-- Remove duplicate resources from target/classes --> <!-- Remove duplicate resources from target/classes -->
<addResources>true</addResources> <addResources>true</addResources>
<folders> <finalName>${project.artifactId}</finalName>
<!-- Add src/main/config to the classpath -->
<folder>${project.basedir}/src/main/config</folder>
</folders>
</configuration> </configuration>
<executions> <executions>
<!-- Repackage as executable JAR (java -jar) --> <!-- Repackage as executable JAR (java -jar) -->

View File

@ -1,11 +0,0 @@
# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
server:
address: localhost
port: 8080
# Logging
logging:
level:
lingo: DEBUG
web: DEBUG

View File

@ -0,0 +1,2 @@
# https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html
logging.level.com.charego.lingo = DEBUG