meldestelle/client/src/commonMain/kotlin/at/mocode/App.kt
2025-09-15 17:48:57 +02:00

198 lines
7.4 KiB
Kotlin

package at.mocode
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
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.launch
import kotlinx.serialization.Serializable
import at.mocode.components.*
import at.mocode.http.GlobalHttpClient
@Serializable
data class PingResponse(
val status: String,
val timestamp: String? = null,
val message: String? = null
)
sealed class PingState {
object Idle : PingState()
object Loading : PingState()
data class Success(val response: PingResponse) : PingState()
data class Error(val message: String) : PingState()
}
@Composable
fun App() {
MaterialTheme {
var showContent by remember { mutableStateOf(false) }
var pingState by remember { mutableStateOf<PingState>(PingState.Idle) }
val coroutineScope = rememberCoroutineScope()
// Use optimized global HTTP client for minimal bundle size
val httpClient = GlobalHttpClient.client
// Cleanup global client on disposal
DisposableEffect(Unit) {
onDispose {
GlobalHttpClient.cleanup()
}
}
Column(
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.safeContentPadding()
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Meldestelle",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(top = 32.dp, bottom = 16.dp)
)
// Platform Info Button
Button(
onClick = { showContent = !showContent },
modifier = Modifier.padding(16.dp)
) {
Text(if (showContent) "Platform-Info ausblenden" else "Platform-Info anzeigen")
}
// Ping Backend Button
Button(
onClick = {
coroutineScope.launch {
pingState = PingState.Loading
try {
// Konfigurierbare API-URL basierend auf Deployment-Umgebung
val response: PingResponse = httpClient.get(ApiConfig.pingEndpoint).body()
pingState = PingState.Success(response)
} catch (e: Exception) {
pingState = PingState.Error(e.message ?: "Unknown error occurred")
}
}
},
enabled = pingState !is PingState.Loading,
modifier = Modifier.padding(8.dp)
) {
if (pingState is PingState.Loading) {
CircularProgressIndicator(
modifier = Modifier.height(16.dp),
color = MaterialTheme.colorScheme.onPrimary
)
Spacer(modifier = Modifier.height(8.dp))
}
Text("Ping Backend")
}
// Ping Status Display
when (val state = pingState) {
is PingState.Success -> {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
text = "✅ Ping erfolgreich!",
style = MaterialTheme.typography.titleMedium,
color = Color(0xFF4CAF50)
)
Text(
text = "Status: ${state.response.status}",
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 4.dp)
)
state.response.timestamp?.let {
Text(
text = "Zeit: $it",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(top = 2.dp)
)
}
}
}
}
is PingState.Error -> {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
text = "❌ Ping fehlgeschlagen",
style = MaterialTheme.typography.titleMedium,
color = Color(0xFFF44336)
)
Text(
text = "Fehler: ${state.message}",
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
else -> {
// Idle or Loading state - no additional display needed
}
}
AnimatedVisibility(showContent) {
val greeting = remember { Greeting().greet() }
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = greeting,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.padding(8.dp)
)
Text(
text = "Willkommen in der Meldestelle-Anwendung!",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(top = 8.dp)
)
}
}
// Feature Control Panel für conditional loading
Spacer(modifier = Modifier.height(16.dp))
FeatureControlPanel()
// Conditional Features - nur laden wenn aktiviert
Spacer(modifier = Modifier.height(8.dp))
ConditionalDebugPanel()
ConditionalAdminPanel()
ConditionalAdvancedFeatures()
}
}
}