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) { fun HTMLTag.xBind(type: String, data: String) {
attributes["x-bind:$type"] = data 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", rel = "stylesheet",
type = "text/css" type = "text/css"
) )
link(
href = "/assets/gamemaster.css",
rel = "stylesheet",
type = "text/css"
)
script { script {
src = "https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" src = "https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"
defer = true defer = true
@ -19,27 +24,60 @@ fun HTML.createGameMasterDocument() {
script { src = "/assets/buzzerWebSocket.js" } script { src = "/assets/buzzerWebSocket.js" }
} }
body { body {
xData("{receivedNames: [], buzzerWebSocket: null}") xData("{receivedNames: [], buzzerWebSocket: null, firstPlayer: null }")
xInit( xInit(
//language=JavaScript //language=JavaScript
""" """
() => { () => {
startWebSocket('/socket/master', (ev) => { startWebSocket('/socket/master', (ev) => {
if (receivedNames.length === 0) {
firstPlayer = ev.data
}
receivedNames.push(ev.data) receivedNames.push(ev.data)
}); });
} }
""".trimIndent() """.trimIndent()
) )
div(classes = "parent") { xEffect(
button { //language=JavaScript
xOn("click", "receivedNames = []") """
+"Reset" 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 { template {
attributes["x-for"] = "name in receivedNames" 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 { body {
xData("{playerName: \"\", buzzerWebSocket: null}") xData("{playerName: \"\", buzzerWebSocket: null, firstPlayer: null}")
div(classes = "parent") { div(classes = "parent") {
xEffect("console.log(firstPlayer)")
xInit( xInit(
//language=JavaScript //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() """.trimIndent()
) )
@ -54,7 +64,7 @@ fun HTML.createPlayerDocument() {
+"Enter a name first!" +"Enter a name first!"
} }
button(classes = "submit") { button(classes = "submit") {
xShow("playerName") xShow("playerName && !firstPlayer")
xData("{clicked: false}") xData("{clicked: false}")
xOn( xOn(
"click", "click",
@ -78,6 +88,11 @@ fun HTML.createPlayerDocument() {
} }
p { +"and I know this!" } 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 de.pheerai.buzzer.data.SessionStorage
import io.ktor.http.cio.websocket.* import io.ktor.http.cio.websocket.*
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import org.slf4j.Logger
suspend fun WebSocketSession.handleGameMasterSocket() { suspend fun WebSocketSession.handleGameMasterSocket(log: Logger) {
SessionStorage.gameMasterSessions.add(GameMasterSocket(this)) SessionStorage.gameMasterSessions.add(GameMasterSocket(this))
for (frame in incoming) { for (frame in incoming) {
when (frame) { when (frame) {
is Frame.Text -> { is Frame.Text -> {
val text = frame.readText() val text = frame.readText()
log.info("GM Socket received $text")
SessionStorage.playerSessions.filter { it.session.isActive } SessionStorage.playerSessions.filter { it.session.isActive }
.forEach { it.session.send(text) } .forEach { it.session.send(text) }
} }

View file

@ -21,7 +21,7 @@ fun Application.configureRoutes() {
private fun Routing.websocketRoutes(log: Logger) { private fun Routing.websocketRoutes(log: Logger) {
webSocket("/socket/player") { handlePlayerSocket(log) } webSocket("/socket/player") { handlePlayerSocket(log) }
webSocket("/socket/master") { handleGameMasterSocket() } webSocket("/socket/master") { handleGameMasterSocket(log) }
} }
private fun Routing.clientRoutes() { 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; flex-direction: column;
} }
div > button.active { div > .submit.active {
background-color: var(--highlight01); 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;
}