initial commit - source

This commit is contained in:
Hartmut Bauer committed 2026-02-03 22:36:35 +01:00
1 parent 003b5501f0
commit e89bb29070
45 files changed
+5997

No files matched your search

@@ -0,0 +1,166 @@
package net.keinekekse.app
//import org.koin.plugin.module.dsl.startKoin
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.keinekekse.app.auth.AuthResult
import net.keinekekse.app.auth.Authenticator
import net.keinekekse.app.books.di.KoinApp
import net.keinekekse.app.ui.ProgressIndicator
import org.koin.compose.koinInject
import org.koin.plugin.module.dsl.startKoin
//@PropertyValue("kc_server")
//var keycloakServer: String = ""
//
//@PropertyValue("kc_realm")
//var keycloakRealm: String = ""
//
//@PropertyValue("kc_client")
//var keycloakClient: String = ""
fun main() = application {
startKoin<KoinApp>()
// keycloakServer = "kec.keinekekse.net"
// keycloakRealm = "app-server-realm"
// keycloakClient = "pkce-book-app"
// val inj = koinInject<String>(named("AppString"))
val authResultState = remember { mutableStateOf<AuthResult?>(null) }
val authenticator: Authenticator = koinInject()
LaunchedEffect(Unit) {
authResultState.value = withContext(Dispatchers.IO) {
// TODO - (~) Verständnis für App-Aufbau und DI
// - (x) das object muss global angelegt werden -> DI singleton
// - (x) globale Speicherung der Tokens
// - Tokens persistieren? Multiplatform! (evtl. library)
// - (x) globaler httpClient mit Konfig für Tokens -> DI
// - (x) Error-Handling: 401 -> refresh -> 401 -> reauth [implizit]
// Authenticator(
// "kec.keinekekse.net",
// "app-server-realm",
// "pkce-book-app",
// ).use {
val result = authenticator.authenticate()
when (result) {
is AuthResult.Success -> {
// println("Access Token: ${result.tokens?.accessToken}")
// println("Refresh Token: ${result.tokens?.refreshToken}")
// delay(3000)
/*
// klappt, gibt aber nicht mehr her, als ohnehin im Token steht
it.requestUserInfo(result.tokens!!.accessToken)
*/
/*
// funktioniert -> jetzt fehlt die DI-Mimik für die compose app
when (val res = it.requestRefreshToken(result.tokens)) {
is AuthResult.Success -> {
println("Access Token: ${res.tokens?.accessToken}")
println("Refresh Token: ${res.tokens?.refreshToken}")
}
is AuthResult.Error -> {
println("Refresh Token fehlgeschlagen ${res.code}: ${res.details ?: ""}")
}
is AuthResult.Fatal -> {
println("Refresh Token fehlgeschlagen ${res.code}: ${res.details ?: ""}")
}
}
*/
}
else -> {}
}
result
// }
}
}
Window(
onCloseRequest = ::exitApplication,
title = "app",
) {
when (val result = authResultState.value) {
null -> {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("Warten auf Anmeldung...")
// Icon(
// imageVector = Icons.Default.HourglassTop,
// contentDescription = "Home",
// modifier = Modifier.padding(top = 16.dp).size(32.dp)
// )
ProgressIndicator()
}
}
is AuthResult.Error -> {
// TODO show an error UI (and maybe a retry button)
Text("Fehler bei der Anmeldung: ${result.message} (${result.code})")
Text("Fehlerbeschreibung: ${result.details ?: ""}")
// App()
}
is AuthResult.Fatal -> {
Text("Fataler Fehler bei der Anmeldung: ${result.message} (${result.code})")
Text("Fehlerbeschreibung: ${result.details ?: ""}")
}
is AuthResult.Success -> {
val test = koinInject<TestAuth>()
CoroutineScope(Dispatchers.Default).launch {
println("requesting '/'")
test.request("/")
}
App()
}
}
}
}
//
//@Composable
//fun ProgressIndicator(animationSize: Int = 48, paddingTop: Int = 16, strokeWidth: Int = 5) {
// val primaryColor = MaterialTheme.colorScheme.primary
// val backgroundColor = MaterialTheme.colorScheme.background
// val strokewidth = strokeWidth.dp
// CircularProgressIndicator(
// modifier =
// Modifier.padding(top = paddingTop.dp).size(animationSize.dp).drawBehind {
// drawCircle(
// primaryColor,
// radius = size.width / 2 - strokewidth.toPx() / 2,
// style = Stroke(strokewidth.toPx()),
//
// )
// },
// color = backgroundColor,
// strokeWidth = strokewidth
// )
//}