Merge pull request 'playerFeedback' (#1) from playerFeedback into master

Reviewed-on: https://git.pheerai.de/pheerai/webbuzzer/pulls/1
This commit is contained in:
Oliver Rümpelein 2021-09-27 11:19:16 +02:00
commit 45e07d9393
7 changed files with 150 additions and 13 deletions

View File

@ -43,3 +43,7 @@ fun HTMLTag.xText(text: String) {
fun HTMLTag.xBind(type: String, data: String) {
attributes["x-bind:$type"] = data
}
fun HTMLTag.xEffect(effect: String) {
attributes["x-effect"] = effect
}

View File

@ -12,6 +12,11 @@ fun HTML.createGameMasterDocument() {
rel = "stylesheet",
type = "text/css"
)
link(
href = "/assets/gamemaster.css",
rel = "stylesheet",
type = "text/css"
)
script {
src = "https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"
defer = true
@ -19,28 +24,61 @@ fun HTML.createGameMasterDocument() {
script { src = "/assets/buzzerWebSocket.js" }
}
body {
xData("{receivedNames: [], buzzerWebSocket: null}")
xData("{receivedNames: [], buzzerWebSocket: null, firstPlayer: null }")
xInit(
//language=JavaScript
"""
() => {
startWebSocket('/socket/master', (ev) => {
if (receivedNames.length === 0) {
firstPlayer = ev.data
}
receivedNames.push(ev.data)
});
}
""".trimIndent()
)
div(classes = "parent") {
button {
xOn("click", "receivedNames = []")
+"Reset"
xEffect(
//language=JavaScript
"""
if (firstPlayer !== null) {
Alpine.data.buzzerWebSocket.send(`PLAYER:${"$"}{firstPlayer}`);
} else {
Alpine.data.buzzerWebSocket.send("CLEAR:");
}
ol {
""".trimIndent()
)
div(classes = "parent") {
div(classes = "player") {
xShow("firstPlayer")
xText("firstPlayer")
}
div { xShow("!firstPlayer") }
div(classes = "playerlist") list@{
template {
attributes["x-for"] = "name in receivedNames"
this@ol.li { xText("name") }
this@list.div(classes = "listedname") { xText("name") }
}
}
button(classes = "submit") {
xData("{clicked: false}")
xOn(
"click",
//language=JavaScript
"""
() => {
receivedNames = []
firstPlayer = null
clicked = true
setTimeout(() => {clicked = false}, 50)
}
""".trimIndent()
)
xOn("mousedown", "clicked = true")
xOn("touchstart", "clicked = true")
xBind("class", "{'active': clicked}")
+"Reset"
}
}
}
}

View File

@ -29,13 +29,23 @@ fun HTML.createPlayerDocument() {
}
}
body {
xData("{playerName: \"\", buzzerWebSocket: null}")
xData("{playerName: \"\", buzzerWebSocket: null, firstPlayer: null}")
div(classes = "parent") {
xEffect("console.log(firstPlayer)")
xInit(
//language=JavaScript
"""
() => {
startWebSocket('/socket/player')
startWebSocket('/socket/player', (ev) => {
console.log("received: " + ev.data)
if (ev.data === "CLEAR:") {
firstPlayer = null;
} else {
let newName = ev.data.split(":")[1]
console.log(newName)
setTimeout(() => { firstPlayer = newName }, 500)
}
});
}
""".trimIndent()
)
@ -54,7 +64,7 @@ fun HTML.createPlayerDocument() {
+"Enter a name first!"
}
button(classes = "submit") {
xShow("playerName")
xShow("playerName && !firstPlayer")
xData("{clicked: false}")
xOn(
"click",
@ -78,6 +88,11 @@ fun HTML.createPlayerDocument() {
}
p { +"and I know this!" }
}
div(classes = "lockindicator") {
xShow("firstPlayer")
xBind("class", "{'self': firstPlayer === playerName, 'other': firstPlayer !== playerName }")
xText("firstPlayer")
}
}
}
}

View File

@ -4,13 +4,15 @@ import de.pheerai.buzzer.data.GameMasterSocket
import de.pheerai.buzzer.data.SessionStorage
import io.ktor.http.cio.websocket.*
import kotlinx.coroutines.isActive
import org.slf4j.Logger
suspend fun WebSocketSession.handleGameMasterSocket() {
suspend fun WebSocketSession.handleGameMasterSocket(log: Logger) {
SessionStorage.gameMasterSessions.add(GameMasterSocket(this))
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val text = frame.readText()
log.info("GM Socket received $text")
SessionStorage.playerSessions.filter { it.session.isActive }
.forEach { it.session.send(text) }
}

View File

@ -21,7 +21,7 @@ fun Application.configureRoutes() {
private fun Routing.websocketRoutes(log: Logger) {
webSocket("/socket/player") { handlePlayerSocket(log) }
webSocket("/socket/master") { handleGameMasterSocket() }
webSocket("/socket/master") { handleGameMasterSocket(log) }
}
private fun Routing.clientRoutes() {

View File

@ -0,0 +1,58 @@
body, html {
height: 100%;
overflow: hidden;
font-size: var(--font-size);
box-sizing: border-box;
padding: var(--bumper-small-size);
margin: 0;
background-color: var(--background);
color: var(--text);
}
div.parent {
display: grid;
grid-template-rows: 3fr auto 1fr;
height: 100%;
max-width: 100%;
}
.player {
background-color: var(--foreground02);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
border-radius: var(--border-radius);
}
.playerlist {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.listedname + .listedname::before {
content: "»";
padding-left: var(--bumper-small-size);
padding-right: var(--bumper-small-size);
}
.submit {
border-radius: var(--border-radius);
width: 100%;
max-width: 100%;
font-size: var(--font-size);
height: 100%;
border: solid 0.25vh var(--highlight-dark);
background-color: var(--foreground);
color: var(--text);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.submit.active {
background-color: var(--highlight01);
}

View File

@ -59,6 +59,26 @@ div > .submit {
flex-direction: column;
}
div > button.active {
div > .submit.active {
background-color: var(--highlight01);
}
.lockindicator {
width: 100%;
max-width: 100%;
height: 100%;
border: solid 0.25vh var(--highlight-dark);
border-radius: var(--border-radius);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.lockindicator.self {
background-color: darkgreen;
}
.lockindicator.other {
background-color: darkred;
}