diff --git a/build.gradle.kts b/build.gradle.kts
index 27ab617..2845e94 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -5,3 +5,4 @@ plugins {
alias(libs.plugins.ktor) apply false
alias(libs.plugins.kotlin.serialization) apply false
}
+
diff --git a/build/wasm/packages/dopewars-web/kotlin/index.html b/build/wasm/packages/dopewars-web/kotlin/index.html
deleted file mode 100644
index be5bedc..0000000
--- a/build/wasm/packages/dopewars-web/kotlin/index.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- KotlinProject
-
-
-
-Web Client HTML
-
-
-
-
\ No newline at end of file
diff --git a/desktop/src/main/kotlin/dev/geekback/dopewars/desktop/ClientState.kt b/desktop/src/main/kotlin/dev/geekback/dopewars/desktop/ClientState.kt
index 7c5854b..a433ce8 100644
--- a/desktop/src/main/kotlin/dev/geekback/dopewars/desktop/ClientState.kt
+++ b/desktop/src/main/kotlin/dev/geekback/dopewars/desktop/ClientState.kt
@@ -3,6 +3,7 @@ package dev.geekback.dopewars.desktop
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import dev.geekback.dopewars.shared.ApiClient
import dev.geekback.dopewars.shared.Player
import dev.geekback.dopewars.shared.api.TravelRequest
diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts
index e8ad46f..4730c28 100644
--- a/shared/build.gradle.kts
+++ b/shared/build.gradle.kts
@@ -18,6 +18,10 @@ kotlin {
commonMain.dependencies {
implementation(libs.kotlinx.serialization)
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 {
diff --git a/desktop/src/main/kotlin/dev/geekback/dopewars/desktop/ApiClient.kt b/shared/src/commonMain/kotlin/dev/geekback/dopewars/shared/ApiClient.kt
similarity index 92%
rename from desktop/src/main/kotlin/dev/geekback/dopewars/desktop/ApiClient.kt
rename to shared/src/commonMain/kotlin/dev/geekback/dopewars/shared/ApiClient.kt
index 04397e9..06c7fd7 100644
--- a/desktop/src/main/kotlin/dev/geekback/dopewars/desktop/ApiClient.kt
+++ b/shared/src/commonMain/kotlin/dev/geekback/dopewars/shared/ApiClient.kt
@@ -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.TravelRequest
-import dev.geekback.dopewars.shared.api.TravelResult
import io.ktor.client.HttpClient
import io.ktor.client.call.body
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.post
import io.ktor.client.request.setBody
-import io.ktor.client.statement.bodyAsText
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.contentType
diff --git a/shared_ui/build.gradle.kts b/shared_ui/build.gradle.kts
index 91ffa78..f66f6a8 100644
--- a/shared_ui/build.gradle.kts
+++ b/shared_ui/build.gradle.kts
@@ -4,12 +4,15 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
plugins {
alias(libs.plugins.kotlin.multiplatform)
+ alias(libs.plugins.compose)
+ alias(libs.plugins.kotlin.compose)
}
kotlin {
jvm()
wasmJs {
+ browser()
}
sourceSets {
diff --git a/web/build.gradle.kts b/web/build.gradle.kts
index 83718c9..bf7b35d 100644
--- a/web/build.gradle.kts
+++ b/web/build.gradle.kts
@@ -16,11 +16,19 @@ kotlin {
sourceSets {
commonMain.dependencies {
implementation(project(":shared"))
+ implementation(project(":shared_ui"))
- implementation(compose.runtime)
- implementation(compose.foundation)
- implementation(compose.material3)
- implementation(compose.ui)
+ // UI Elements
+ implementation(libs.compose.runtime)
+ implementation(libs.compose.foundation)
+ 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 {
diff --git a/web/src/webMain/kotlin/dev/geekback/dopewars/web/AdminApi.kt b/web/src/webMain/kotlin/dev/geekback/dopewars/web/AdminApi.kt
new file mode 100644
index 0000000..8ade445
--- /dev/null
+++ b/web/src/webMain/kotlin/dev/geekback/dopewars/web/AdminApi.kt
@@ -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 {
+ val response = this.client.get("${this.baseUrl}/players") {
+ contentType(ContentType.Application.Json)
+ }
+
+ return response.body()
+ }
+}
\ No newline at end of file
diff --git a/web/src/webMain/kotlin/dev/geekback/dopewars/web/ApiControlBox.kt b/web/src/webMain/kotlin/dev/geekback/dopewars/web/ApiControlBox.kt
new file mode 100644
index 0000000..1a2926f
--- /dev/null
+++ b/web/src/webMain/kotlin/dev/geekback/dopewars/web/ApiControlBox.kt
@@ -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")
+ }
+ }
+ }
+}
diff --git a/web/src/webMain/kotlin/dev/geekback/dopewars/web/App.kt b/web/src/webMain/kotlin/dev/geekback/dopewars/web/App.kt
new file mode 100644
index 0000000..44242a0
--- /dev/null
+++ b/web/src/webMain/kotlin/dev/geekback/dopewars/web/App.kt
@@ -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())
+ 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")
+ }
+ }
+ }
+ )
+ }
+}
+
diff --git a/web/src/webMain/kotlin/dev/geekback/dopewars/web/PlayersList.kt b/web/src/webMain/kotlin/dev/geekback/dopewars/web/PlayersList.kt
new file mode 100644
index 0000000..67a84f9
--- /dev/null
+++ b/web/src/webMain/kotlin/dev/geekback/dopewars/web/PlayersList.kt
@@ -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, 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) })
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/web/src/webMain/kotlin/dev/geekback/dopewars/web/main.kt b/web/src/webMain/kotlin/dev/geekback/dopewars/web/main.kt
index 5de362a..7cb1770 100644
--- a/web/src/webMain/kotlin/dev/geekback/dopewars/web/main.kt
+++ b/web/src/webMain/kotlin/dev/geekback/dopewars/web/main.kt
@@ -1,12 +1,6 @@
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.material3.Text
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.ComposeViewport
@OptIn(ExperimentalComposeUiApi::class)
@@ -15,10 +9,3 @@ fun main() {
App()
}
}
-
-@Composable
-fun App() {
- MaterialTheme {
- Text(modifier = Modifier.padding(16.dp), text = "Taxation is theft")
- }
-}