fixing(client)

This commit is contained in:
2025-08-13 00:07:08 +02:00
parent 23b6708197
commit 26e826d32c
23 changed files with 3650 additions and 1077 deletions
@@ -1,29 +0,0 @@
package at.mocode.client.data.api
import at.mocode.client.data.model.PingResponse
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
class PingApiClient {
private val httpClient = HttpClient {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
}
suspend fun ping(): String {
return try {
// HINWEIS: Wir rufen hier Port 8081 an, den Port unseres Gateways.
val response = httpClient.get("http://localhost:8081/ping").body<PingResponse>()
response.status
} catch (e: Exception) {
"Fehler: ${e.message}"
}
}
}
@@ -1,8 +0,0 @@
package at.mocode.client.data.model
import kotlinx.serialization.Serializable
@Serializable
data class PingResponse(
val status: String
)
@@ -0,0 +1,32 @@
package at.mocode.client.data.service
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.serialization.Serializable
@Serializable
data class PingResponse(val status: String)
class PingService {
private val client = HttpClient {
install(ContentNegotiation) {
json()
}
}
suspend fun ping(): Result<PingResponse> = try {
val response = client.get("http://localhost:8082/ping").body<PingResponse>()
Result.success(response)
} catch (e: Exception) {
Result.failure(e)
}
fun pingFlow(): Flow<Result<PingResponse>> = flow {
emit(ping())
}
}
@@ -1,12 +1,90 @@
package at.mocode.client.ui
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import at.mocode.client.ui.features.ping.PingScreen
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import at.mocode.client.ui.components.PingTestComponent
@Composable
fun App() {
fun App(baseUrl: String = "http://localhost:8080") {
MaterialTheme {
PingScreen()
PingScreen(baseUrl)
}
}
@Composable
fun PingScreen(baseUrl: String) {
val pingComponent = remember { PingTestComponent() }
var pingState by remember { mutableStateOf(pingComponent.state) }
LaunchedEffect(pingComponent) {
pingComponent.onStateChanged = { newState ->
pingState = newState
}
}
DisposableEffect(pingComponent) {
onDispose {
pingComponent.dispose()
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Ping Backend Service",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(bottom = 16.dp)
)
when {
pingState.isLoading -> {
CircularProgressIndicator()
Text(
text = "Testing connection...",
modifier = Modifier.padding(top = 8.dp)
)
}
pingState.error != null -> {
Text(
text = "Error: ${pingState.error}",
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(bottom = 16.dp)
)
}
pingState.response != null -> {
Text(
text = "Response: ${pingState.response?.status ?: "Unknown"}",
color = if (pingState.isConnected) MaterialTheme.colorScheme.primary
else MaterialTheme.colorScheme.error,
modifier = Modifier.padding(bottom = 16.dp)
)
Text(
text = if (pingState.isConnected) "✓ Connected" else "✗ Not Connected",
color = if (pingState.isConnected) MaterialTheme.colorScheme.primary
else MaterialTheme.colorScheme.error
)
}
}
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = { pingComponent.testConnection() },
enabled = !pingState.isLoading
) {
Text("Test Connection")
}
}
}
@@ -0,0 +1,57 @@
package at.mocode.client.ui.components
import at.mocode.client.data.service.PingService
import at.mocode.client.data.service.PingResponse
import kotlinx.coroutines.*
data class PingTestState(
val isLoading: Boolean = false,
val response: PingResponse? = null,
val error: String? = null,
val isConnected: Boolean = false
)
class PingTestComponent {
private val pingService = PingService()
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
var state: PingTestState = PingTestState()
private set
var onStateChanged: ((PingTestState) -> Unit)? = null
fun testConnection() {
updateState(state.copy(isLoading = true, error = null))
scope.launch {
pingService.ping()
.onSuccess { response ->
updateState(
state.copy(
isLoading = false,
response = response,
isConnected = response.status == "pong"
)
)
}
.onFailure { error ->
updateState(
state.copy(
isLoading = false,
error = error.message ?: "Unbekannter Fehler",
isConnected = false
)
)
}
}
}
private fun updateState(newState: PingTestState) {
state = newState
onStateChanged?.invoke(state)
}
fun dispose() {
scope.cancel()
}
}
@@ -1,35 +0,0 @@
package at.mocode.client.ui.features.ping
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun PingScreen() {
val viewModel = remember { PingViewModel() }
val responseText by viewModel.responseText.collectAsState()
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(onClick = { viewModel.onPingClicked() }) {
Text("Ping Backend")
}
Text(
text = responseText,
modifier = Modifier.padding(top = 16.dp)
)
}
}
@@ -1,24 +0,0 @@
package at.mocode.client.ui.features.ping
import at.mocode.client.data.api.PingApiClient
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
class PingViewModel {
private val apiClient = PingApiClient()
private val viewModelScope = CoroutineScope(Dispatchers.Default)
private val _responseText = MutableStateFlow("Klicke auf den Button, um das Backend zu pingen.")
val responseText = _responseText.asStateFlow()
fun onPingClicked() {
_responseText.value = "Pinge Backend..."
viewModelScope.launch {
val response = apiClient.ping()
_responseText.value = "Antwort vom Backend: $response"
}
}
}