Web admin app loads list of players
This commit is contained in:
@@ -5,3 +5,4 @@ plugins {
|
|||||||
alias(libs.plugins.ktor) apply false
|
alias(libs.plugins.ktor) apply false
|
||||||
alias(libs.plugins.kotlin.serialization) apply false
|
alias(libs.plugins.kotlin.serialization) apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>KotlinProject</title>
|
|
||||||
<link type="text/css" rel="stylesheet" href="styles.css">
|
|
||||||
</head>
|
|
||||||
<body style="text-align: center; align-content: center">
|
|
||||||
<h1>Web Client HTML</h1>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 50 50" role="presentation">
|
|
||||||
<circle cx="25" cy="25" r="20" stroke="#ccc" stroke-width="4" fill="none"/>
|
|
||||||
<circle cx="25" cy="25" r="20" stroke="#333" stroke-width="4" fill="none" stroke-linecap="round"
|
|
||||||
stroke-dasharray="90 125">
|
|
||||||
<animateTransform attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="1s"
|
|
||||||
repeatCount="indefinite"/>
|
|
||||||
</circle>
|
|
||||||
</svg>
|
|
||||||
<script type="application/javascript" src="web.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -3,6 +3,7 @@ package dev.geekback.dopewars.desktop
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import dev.geekback.dopewars.shared.ApiClient
|
||||||
import dev.geekback.dopewars.shared.Player
|
import dev.geekback.dopewars.shared.Player
|
||||||
import dev.geekback.dopewars.shared.api.TravelRequest
|
import dev.geekback.dopewars.shared.api.TravelRequest
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ kotlin {
|
|||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
implementation(libs.kotlinx.serialization)
|
implementation(libs.kotlinx.serialization)
|
||||||
implementation(libs.kotlinx.datetime)
|
implementation(libs.kotlinx.datetime)
|
||||||
|
implementation(libs.ktor.serialization.kotlinx.json)
|
||||||
|
implementation(libs.ktor.client.core)
|
||||||
|
implementation(libs.ktor.client.cio)
|
||||||
|
implementation(libs.ktor.client.content.negotiation)
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmJsMain.dependencies {
|
wasmJsMain.dependencies {
|
||||||
|
|||||||
+1
-6
@@ -1,11 +1,7 @@
|
|||||||
package dev.geekback.dopewars.desktop
|
package dev.geekback.dopewars.shared
|
||||||
|
|
||||||
import dev.geekback.dopewars.shared.Location
|
|
||||||
import dev.geekback.dopewars.shared.Market
|
|
||||||
import dev.geekback.dopewars.shared.Player
|
|
||||||
import dev.geekback.dopewars.shared.api.PlayerNameUpdateRequest
|
import dev.geekback.dopewars.shared.api.PlayerNameUpdateRequest
|
||||||
import dev.geekback.dopewars.shared.api.TravelRequest
|
import dev.geekback.dopewars.shared.api.TravelRequest
|
||||||
import dev.geekback.dopewars.shared.api.TravelResult
|
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.call.body
|
import io.ktor.client.call.body
|
||||||
import io.ktor.client.engine.cio.CIO
|
import io.ktor.client.engine.cio.CIO
|
||||||
@@ -13,7 +9,6 @@ import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
|||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.client.request.post
|
import io.ktor.client.request.post
|
||||||
import io.ktor.client.request.setBody
|
import io.ktor.client.request.setBody
|
||||||
import io.ktor.client.statement.bodyAsText
|
|
||||||
import io.ktor.http.ContentType
|
import io.ktor.http.ContentType
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.http.contentType
|
import io.ktor.http.contentType
|
||||||
@@ -4,12 +4,15 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlin.multiplatform)
|
alias(libs.plugins.kotlin.multiplatform)
|
||||||
|
alias(libs.plugins.compose)
|
||||||
|
alias(libs.plugins.kotlin.compose)
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvm()
|
jvm()
|
||||||
|
|
||||||
wasmJs {
|
wasmJs {
|
||||||
|
browser()
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
|||||||
+12
-4
@@ -16,11 +16,19 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
implementation(project(":shared"))
|
implementation(project(":shared"))
|
||||||
|
implementation(project(":shared_ui"))
|
||||||
|
|
||||||
implementation(compose.runtime)
|
// UI Elements
|
||||||
implementation(compose.foundation)
|
implementation(libs.compose.runtime)
|
||||||
implementation(compose.material3)
|
implementation(libs.compose.foundation)
|
||||||
implementation(compose.ui)
|
implementation(libs.compose.material3)
|
||||||
|
implementation(libs.compose.ui)
|
||||||
|
|
||||||
|
// HTTP Client
|
||||||
|
implementation(libs.ktor.serialization.kotlinx.json)
|
||||||
|
implementation(libs.ktor.client.core)
|
||||||
|
// implementation(libs.ktor.client.cio)
|
||||||
|
implementation(libs.ktor.client.content.negotiation)
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmJsMain.dependencies {
|
wasmJsMain.dependencies {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package dev.geekback.dopewars.web
|
||||||
|
|
||||||
|
import dev.geekback.dopewars.shared.Player
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.http.ContentType
|
||||||
|
import io.ktor.http.contentType
|
||||||
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
object AdminApi {
|
||||||
|
var baseUrl: String = "http://localhost:8080"
|
||||||
|
private val client = HttpClient {
|
||||||
|
install(ContentNegotiation) {
|
||||||
|
json(
|
||||||
|
Json {
|
||||||
|
allowSpecialFloatingPointValues = true
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
prettyPrint = true
|
||||||
|
isLenient = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBaseUrl(baseUrl: String) {
|
||||||
|
this.baseUrl = baseUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun loadPlayers(): List<Player> {
|
||||||
|
val response = this.client.get("${this.baseUrl}/players") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.body()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package dev.geekback.dopewars.web
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextField
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ApiControlBox(onUrlUpdate: (String) -> Unit) {
|
||||||
|
var localUrl by remember { mutableStateOf("http://localhost:8080") }
|
||||||
|
|
||||||
|
var visible by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
|
Card {
|
||||||
|
Column {
|
||||||
|
Button(onClick = {
|
||||||
|
visible != visible
|
||||||
|
}) {
|
||||||
|
Text("API Config")
|
||||||
|
}
|
||||||
|
TextField(value = AdminApi.baseUrl, onValueChange = {
|
||||||
|
localUrl = it
|
||||||
|
})
|
||||||
|
Button(onClick = {
|
||||||
|
onUrlUpdate(localUrl)
|
||||||
|
}) {
|
||||||
|
Text("Apply")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package dev.geekback.dopewars.web
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import dev.geekback.dopewars.shared.Player
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun App() {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
var players by mutableStateOf (listOf<Player>())
|
||||||
|
MaterialTheme {
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
content = {
|
||||||
|
Column {
|
||||||
|
// List of current Players
|
||||||
|
Button(onClick = {
|
||||||
|
println("Reload Players Now")
|
||||||
|
scope.launch {
|
||||||
|
players = AdminApi.loadPlayers()
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Reload Players")
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiControlBox {
|
||||||
|
println("Setting API BaseUrl to $it")
|
||||||
|
AdminApi.setBaseUrl(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayersList(players) {
|
||||||
|
println("Click on $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package dev.geekback.dopewars.web
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import dev.geekback.dopewars.shared.Player
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PlayersList(players: List<Player>, onPLayerSelected: (Player) -> Unit) {
|
||||||
|
Card {
|
||||||
|
Text("Current Players")
|
||||||
|
LazyColumn {
|
||||||
|
if (players.isEmpty()) {
|
||||||
|
items(1) {
|
||||||
|
Text("No Players.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items(players.size) { i ->
|
||||||
|
val item = players[i];
|
||||||
|
Text("Player ${item.name}", modifier = Modifier.clickable { onPLayerSelected(item) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,6 @@
|
|||||||
package dev.geekback.dopewars.web
|
package dev.geekback.dopewars.web
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.window.ComposeViewport
|
import androidx.compose.ui.window.ComposeViewport
|
||||||
|
|
||||||
@OptIn(ExperimentalComposeUiApi::class)
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
@@ -15,10 +9,3 @@ fun main() {
|
|||||||
App()
|
App()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun App() {
|
|
||||||
MaterialTheme {
|
|
||||||
Text(modifier = Modifier.padding(16.dp), text = "Taxation is theft")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user