Refine MsTextField component: introduce compact mode, enhance visual styling and error handling, and improve placeholder and keyboard interaction logic. Add Dimens and Colors updates, implement navigation rail and header layout for the desktop shell, and update ROADMAP documentation with planned phases.

This commit is contained in:
2026-04-12 23:06:49 +02:00
parent 5eb2dd6904
commit 126522e606
17 changed files with 854 additions and 551 deletions
@@ -4,20 +4,20 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.Chat
import androidx.compose.material.icons.filled.Devices
import androidx.compose.material.icons.filled.Wifi
import androidx.compose.material.icons.filled.WifiOff
import androidx.compose.material.icons.automirrored.filled.*
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import at.mocode.frontend.core.designsystem.theme.AppColors
import at.mocode.frontend.core.designsystem.theme.Dimens
import at.mocode.frontend.core.navigation.AppScreen
import at.mocode.frontend.features.billing.presentation.BillingScreen
import at.mocode.frontend.features.billing.presentation.BillingViewModel
@@ -49,11 +49,9 @@ private val TopBarTextColor = Color.White
* Haupt-Layout der Desktop-App gemäß Vision_03.
*
* Struktur:
* - TopBar (dunkelblau): App-Titel + Breadcrumb + Logout
* - NavigationRail (links): Globale Navigation
* - Header (oben): Breadcrumb + Status + Logout
* - Content: kontextabhängiger Screen
*
* Kein Nav-Rail, keine Sidebar Navigation erfolgt über
* Breadcrumb-Klicks und horizontale Tabs innerhalb der Screens.
*/
@Composable
fun DesktopMainLayout(
@@ -62,18 +60,25 @@ fun DesktopMainLayout(
onBack: () -> Unit,
onLogout: () -> Unit,
) {
// Onboarding-Eingaben zwischen Navigationswechseln behalten → State hier (außerhalb des when) hosten
// Onboarding-Eingaben zwischen Navigationswechseln behalten
var obGeraet by rememberSaveable { mutableStateOf("") }
var obKey by rememberSaveable { mutableStateOf("") }
Column(modifier = Modifier.fillMaxSize()) {
DesktopTopBar(
Row(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
// Navigation Rail (Modernere Seitenleiste)
DesktopNavRail(
currentScreen = currentScreen,
onNavigate = onNavigate,
onBack = onBack,
onLogout = onLogout,
onNavigate = onNavigate
)
Column(modifier = Modifier.fillMaxSize()) {
DesktopTopHeader(
currentScreen = currentScreen,
onNavigate = onNavigate,
onBack = onBack,
onLogout = onLogout,
)
Box(modifier = Modifier.weight(1f).fillMaxWidth()) {
DesktopContentArea(
currentScreen = currentScreen,
@@ -85,247 +90,316 @@ fun DesktopMainLayout(
onObKeyChange = { obKey = it },
)
}
HorizontalDivider(thickness = Dimens.BorderThin, color = MaterialTheme.colorScheme.outlineVariant)
DesktopFooterBar()
}
}
}
/**
* TopBar: dunkelblauer Balken mit Breadcrumb-Navigation und Logout-Button.
*
* Breadcrumb-Logik:
* - Root: "🏠 Admin - Verwaltung"
* - Veranstaltung: "🏠 Admin - Verwaltung / Veranstaltung #<id>"
* - Turnier: "🏠 Admin - Verwaltung / Veranstaltung #<id> / Turnier <tid>"
*/
@Composable
private fun DesktopNavRail(
currentScreen: AppScreen,
onNavigate: (AppScreen) -> Unit
) {
Surface(
modifier = Modifier.fillMaxHeight().width(Dimens.NavRailWidth),
color = AppColors.NavigationSurface,
contentColor = AppColors.NavigationContent,
) {
Column(
modifier = Modifier.fillMaxHeight().padding(vertical = Dimens.SpacingM),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(Dimens.SpacingS)
) {
// App Icon / Logo Platzhalter
Surface(
modifier = Modifier.size(40.dp),
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colorScheme.primary
) {
Icon(
imageVector = Icons.Default.Adjust,
contentDescription = "Logo",
tint = MaterialTheme.colorScheme.onPrimary,
modifier = Modifier.padding(Dimens.SpacingS)
)
}
Spacer(Modifier.height(Dimens.SpacingL))
// Navigations-Items
NavRailItem(
icon = Icons.Default.Dashboard,
label = "Admin",
selected = currentScreen is AppScreen.VeranstaltungVerwaltung || currentScreen is AppScreen.VeranstaltungDetail,
onClick = { onNavigate(AppScreen.VeranstaltungVerwaltung) }
)
NavRailItem(
icon = Icons.Default.People,
label = "Vereine",
selected = currentScreen is AppScreen.VereinVerwaltung,
onClick = { onNavigate(AppScreen.VereinVerwaltung) }
)
NavRailItem(
icon = Icons.Default.Settings,
label = "Tools",
selected = currentScreen is AppScreen.Ping,
onClick = { onNavigate(AppScreen.Ping) }
)
}
}
}
@Composable
private fun DesktopTopBar(
private fun NavRailItem(
icon: ImageVector,
label: String,
selected: Boolean,
onClick: () -> Unit
) {
val tint = if (selected) MaterialTheme.colorScheme.primary else AppColors.NavigationContent
val background = if (selected) MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.5f) else Color.Transparent
Surface(
modifier = Modifier
.size(48.dp)
.clickable(onClick = onClick),
shape = MaterialTheme.shapes.medium,
color = background
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Icon(
imageVector = icon,
contentDescription = label,
tint = tint,
modifier = Modifier.size(Dimens.IconSizeM)
)
}
}
}
/**
* TopHeader: Schlanke Leiste mit Breadcrumb und Logout.
*/
@Composable
private fun DesktopTopHeader(
currentScreen: AppScreen,
onNavigate: (AppScreen) -> Unit,
onBack: () -> Unit,
onLogout: () -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.background(TopBarColor)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
Surface(
modifier = Modifier.fillMaxWidth().height(Dimens.TopBarHeight),
color = MaterialTheme.colorScheme.surface,
tonalElevation = 1.dp
) {
Row(verticalAlignment = Alignment.CenterVertically) {
// Zurück-Pfeil: für alle außer Onboarding anzeigen (damit man von "Verwaltung" zurück kommt)
if (currentScreen !is AppScreen.Onboarding) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Zurück",
tint = TopBarTextColor,
modifier = Modifier
.size(20.dp)
.clickable { onBack() },
)
Spacer(Modifier.width(8.dp))
Row(
modifier = Modifier.fillMaxSize().padding(horizontal = Dimens.SpacingL),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Row(verticalAlignment = Alignment.CenterVertically) {
if (currentScreen !is AppScreen.Onboarding) {
IconButton(onClick = onBack) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Zurück",
modifier = Modifier.size(Dimens.IconSizeM),
tint = MaterialTheme.colorScheme.primary
)
}
Spacer(Modifier.width(Dimens.SpacingS))
}
// Breadcrumb-Segmente
BreadcrumbContent(currentScreen, onNavigate)
}
// Root-Link
Text(
text = "Verwaltung",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstaltungVerwaltung) },
)
// Breadcrumb-Segmente je nach Screen
when (currentScreen) {
is AppScreen.VeranstalterAuswahl -> {
BreadcrumbSeparator()
Text(
text = "Veranstalter auswählen",
color = TopBarTextColor,
fontSize = 14.sp,
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(Dimens.SpacingM)) {
// Profil / Logout Bereich
Text(
text = "Administrator",
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
IconButton(onClick = onLogout) {
Icon(
imageVector = Icons.AutoMirrored.Filled.Logout,
contentDescription = "Abmelden",
modifier = Modifier.size(Dimens.IconSizeM),
tint = MaterialTheme.colorScheme.error
)
}
is AppScreen.VeranstalterNeu -> {
BreadcrumbSeparator()
Text(
text = "Veranstalter-Verwaltung",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstalterVerwaltung) },
)
BreadcrumbSeparator()
Text(
text = "Neuer Veranstalter",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.VeranstalterDetail -> {
BreadcrumbSeparator()
Text(
text = "Veranstalter-Verwaltung",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstalterVerwaltung) },
)
BreadcrumbSeparator()
Text(
text = "Veranstalter #${currentScreen.veranstalterId}",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.VeranstaltungProfil -> {
BreadcrumbSeparator()
Text(
text = "Veranstalter-Verwaltung",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstalterVerwaltung) },
)
BreadcrumbSeparator()
Text(
text = "Veranstalter #${currentScreen.veranstalterId}",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstalterDetail(currentScreen.veranstalterId))
},
)
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.VeranstaltungDetail -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.id}",
color = TopBarTextColor,
fontSize = 14.sp,
)
}
is AppScreen.VeranstaltungNeu -> {
BreadcrumbSeparator()
Text(
text = "Neue Veranstaltung",
color = TopBarTextColor,
fontSize = 14.sp,
)
}
is AppScreen.TurnierDetail -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
},
)
BreadcrumbSeparator()
Text(
text = "Turnier ${currentScreen.turnierId}",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.Billing -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstaltungProfil(0, currentScreen.veranstaltungId))
},
)
BreadcrumbSeparator()
Text(
text = "Turnier ${currentScreen.turnierId}",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable {
onNavigate(AppScreen.TurnierDetail(currentScreen.veranstaltungId, currentScreen.turnierId))
},
)
BreadcrumbSeparator()
Text(
text = "Abrechnung",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.TurnierNeu -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
},
)
BreadcrumbSeparator()
Text(
text = "Neues Turnier",
color = TopBarTextColor,
fontSize = 14.sp,
)
}
is AppScreen.Ping -> {
BreadcrumbSeparator()
Text(
text = "Ping Service",
color = TopBarTextColor,
fontSize = 14.sp,
)
}
is AppScreen.Vereine -> {
BreadcrumbSeparator()
Text(
text = "Vereine",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.Meisterschaften -> {
BreadcrumbSeparator()
Text(
text = "Meisterschaften",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.Cups -> {
BreadcrumbSeparator()
Text(
text = "Cups",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
else -> {}
}
}
}
}
// Logout wurde auf Kundenwunsch entfernt
@Composable
private fun BreadcrumbContent(
currentScreen: AppScreen,
onNavigate: (AppScreen) -> Unit
) {
when (currentScreen) {
is AppScreen.VeranstalterAuswahl -> {
BreadcrumbSeparator()
Text(
text = "Veranstalter auswählen",
style = MaterialTheme.typography.bodyMedium,
)
}
is AppScreen.VeranstalterNeu -> {
BreadcrumbSeparator()
Text(
text = "Veranstalter-Verwaltung",
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstalterVerwaltung) },
)
BreadcrumbSeparator()
Text(
text = "Neuer Veranstalter",
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
)
}
is AppScreen.VeranstalterDetail -> {
BreadcrumbSeparator()
Text(
text = "Veranstalter-Verwaltung",
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstalterVerwaltung) },
)
BreadcrumbSeparator()
Text(
text = "Veranstalter #${currentScreen.veranstalterId}",
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
)
}
is AppScreen.VeranstaltungProfil -> {
BreadcrumbSeparator()
Text(
text = "Veranstalter-Verwaltung",
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstalterVerwaltung) },
)
BreadcrumbSeparator()
Text(
text = "Veranstalter #${currentScreen.veranstalterId}",
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstalterDetail(currentScreen.veranstalterId))
},
)
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
)
}
is AppScreen.VeranstaltungDetail -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.id}",
style = MaterialTheme.typography.bodyMedium,
)
}
is AppScreen.VeranstaltungNeu -> {
BreadcrumbSeparator()
Text(
text = "Neue Veranstaltung",
style = MaterialTheme.typography.bodyMedium,
)
}
is AppScreen.TurnierDetail -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
},
)
BreadcrumbSeparator()
Text(
text = "Turnier ${currentScreen.turnierId}",
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
)
}
is AppScreen.Billing -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstaltungProfil(0, currentScreen.veranstaltungId))
},
)
BreadcrumbSeparator()
Text(
text = "Turnier ${currentScreen.turnierId}",
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
modifier = Modifier.clickable {
onNavigate(AppScreen.TurnierDetail(currentScreen.veranstaltungId, currentScreen.turnierId))
},
)
BreadcrumbSeparator()
Text(
text = "Abrechnung",
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
)
}
is AppScreen.TurnierNeu -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
},
)
BreadcrumbSeparator()
Text(
text = "Neues Turnier",
style = MaterialTheme.typography.bodyMedium,
)
}
is AppScreen.Ping -> {
BreadcrumbSeparator()
Text(
text = "Ping Service",
style = MaterialTheme.typography.bodyMedium,
)
}
is AppScreen.Vereine -> {
BreadcrumbSeparator()
Text(
text = "Vereine",
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
)
}
is AppScreen.Meisterschaften -> {
BreadcrumbSeparator()
Text(
text = "Meisterschaften",
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
)
}
is AppScreen.Cups -> {
BreadcrumbSeparator()
Text(
text = "Cups",
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
)
}
else -> {}
}
}
@@ -733,45 +807,71 @@ private fun DesktopContentArea(
@Composable
private fun DesktopFooterBar() {
// Stub-Status für MVP
// Echte Status-Logik vorbereitet
val online = remember { mutableStateOf(true) }
val deviceConnected = remember { mutableStateOf(true) }
val deviceName = "Richter-Turm"
Row(
modifier = Modifier
.fillMaxWidth()
.height(36.dp)
.background(Color(0xFFF3F4F6))
.padding(horizontal = 12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
Surface(
color = MaterialTheme.colorScheme.surface,
contentColor = MaterialTheme.colorScheme.onSurface,
tonalElevation = 1.dp
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
imageVector = if (online.value) Icons.Filled.Wifi else Icons.Filled.WifiOff,
contentDescription = null,
tint = if (online.value) Color(0xFF059669) else Color(0xFFDC2626)
)
Spacer(Modifier.width(6.dp))
Text(if (online.value) "Online" else "Offline", color = Color(0xFF374151), fontSize = 12.sp)
Spacer(Modifier.width(16.dp))
Icon(Icons.Filled.Devices, contentDescription = null, tint = if (deviceConnected.value) Color(0xFF2563EB) else Color(0xFF9CA3AF))
Spacer(Modifier.width(6.dp))
Text(
if (deviceConnected.value) "Verbunden: $deviceName" else "Kein Gerät verbunden",
color = Color(0xFF374151),
fontSize = 12.sp
)
}
Row(verticalAlignment = Alignment.CenterVertically) {
if (deviceConnected.value) {
OutlinedButton(onClick = { /* öffne Chat-Panel */ }, contentPadding = PaddingValues(horizontal = 10.dp, vertical = 4.dp)) {
Icon(Icons.AutoMirrored.Filled.Chat, contentDescription = null, tint = Color(0xFF2563EB))
Spacer(Modifier.width(6.dp))
Text("Chat", color = Color(0xFF2563EB), fontSize = 12.sp)
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(32.dp)
.padding(horizontal = Dimens.SpacingS),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Row(verticalAlignment = Alignment.CenterVertically) {
// Status: Cloud Sync
StatusIndicator(
icon = if (online.value) Icons.Filled.CloudDone else Icons.Filled.CloudOff,
label = if (online.value) "Cloud synchronisiert" else "Offline (Lokal)",
color = if (online.value) Color(0xFF2E7D32) else MaterialTheme.colorScheme.error
)
Spacer(Modifier.width(Dimens.SpacingM))
// Status: LAN Devices (mDNS)
StatusIndicator(
icon = Icons.Filled.Lan,
label = if (deviceConnected.value) "Verbunden: $deviceName" else "Suche nach Geräten...",
color = if (deviceConnected.value) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline
)
}
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = "v2.4.0-rc1 | Desktop-Alpha",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
@Composable
private fun StatusIndicator(
icon: ImageVector,
label: String,
color: Color
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
imageVector = icon,
contentDescription = null,
tint = color,
modifier = Modifier.size(Dimens.IconSizeS)
)
Spacer(Modifier.width(Dimens.SpacingXS))
Text(
text = label,
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurface
)
}
}
@@ -1,5 +1,6 @@
package at.mocode.desktop.v2
import at.mocode.frontend.core.designsystem.components.MsTextField
import androidx.compose.foundation.clickable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
@@ -51,10 +52,10 @@ fun OnboardingScreen(
val frKey = remember { FocusRequester() }
val frBtn = remember { FocusRequester() }
OutlinedTextField(
MsTextField(
value = geraetName,
onValueChange = { onGeraetNameChange(it) },
label = { Text("Gerätename (Pflicht)") },
label = "Gerätename (Pflicht)",
modifier = Modifier
.fillMaxWidth()
.focusRequester(frName)
@@ -70,18 +71,15 @@ fun OnboardingScreen(
} else false
}
,
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Next),
imeAction = ImeAction.Next,
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
)
OutlinedTextField(
MsTextField(
value = secureKey,
onValueChange = { onSecureKeyChange(it) },
label = { Text("Sicherheitsschlüssel (Pflicht)") },
trailingIcon = {
IconButton(onClick = { showPw = !showPw }) {
Icon(if (showPw) Icons.Default.VisibilityOff else Icons.Default.Visibility, contentDescription = null)
}
},
label = "Sicherheitsschlüssel (Pflicht)",
trailingIcon = if (showPw) Icons.Default.VisibilityOff else Icons.Default.Visibility,
onTrailingIconClick = { showPw = !showPw },
visualTransformation = if (showPw) VisualTransformation.None else PasswordVisualTransformation(),
modifier = Modifier
.fillMaxWidth()
@@ -106,7 +104,7 @@ fun OnboardingScreen(
} else false
}
,
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
imeAction = ImeAction.Done,
keyboardActions = KeyboardActions(onDone = {
if (geraetName.trim().length >= 3 && secureKey.trim().length >= 8) {
onContinue(geraetName, secureKey)
@@ -189,14 +187,14 @@ fun PferdProfilV2(id: Long, onBack: () -> Unit) {
title = { Text("Pferd bearbeiten") },
text = {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(name, { name = it }, label = { Text("Name") }, modifier = Modifier.fillMaxWidth())
MsTextField(name, { name = it }, label = "Name", modifier = Modifier.fillMaxWidth())
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(oeps, { oeps = it }, label = { Text("ÖPS-Nr.") }, modifier = Modifier.weight(1f))
OutlinedTextField(fei, { fei = it }, label = { Text("FEI-ID") }, modifier = Modifier.weight(1f))
MsTextField(oeps, { oeps = it }, label = "ÖPS-Nr.", modifier = Modifier.weight(1f))
MsTextField(fei, { fei = it }, label = "FEI-ID", modifier = Modifier.weight(1f))
}
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(geb, { geb = it }, label = { Text("Geburtsdatum") }, modifier = Modifier.weight(1f))
OutlinedTextField(farbe, { farbe = it }, label = { Text("Farbe") }, modifier = Modifier.weight(1f))
MsTextField(geb, { geb = it }, label = "Geburtsdatum", modifier = Modifier.weight(1f))
MsTextField(farbe, { farbe = it }, label = "Farbe", modifier = Modifier.weight(1f))
}
}
}
@@ -261,16 +259,16 @@ fun ReiterProfilV2(id: Long, onBack: () -> Unit) {
text = {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(vor, { vor = it }, label = { Text("Vorname") }, modifier = Modifier.weight(1f))
OutlinedTextField(nach, { nach = it }, label = { Text("Nachname") }, modifier = Modifier.weight(1f))
MsTextField(vor, { vor = it }, label = "Vorname", modifier = Modifier.weight(1f))
MsTextField(nach, { nach = it }, label = "Nachname", modifier = Modifier.weight(1f))
}
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(oeps, { oeps = it }, label = { Text("ÖPS-Nr.") }, modifier = Modifier.weight(1f))
OutlinedTextField(fei, { fei = it }, label = { Text("FEI-ID") }, modifier = Modifier.weight(1f))
MsTextField(oeps, { oeps = it }, label = "ÖPS-Nr.", modifier = Modifier.weight(1f))
MsTextField(fei, { fei = it }, label = "FEI-ID", modifier = Modifier.weight(1f))
}
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(liz, { liz = it }, label = { Text("Lizenzklasse") }, modifier = Modifier.weight(1f))
OutlinedTextField(verein, { verein = it }, label = { Text("Verein") }, modifier = Modifier.weight(1f))
MsTextField(liz, { liz = it }, label = "Lizenzklasse", modifier = Modifier.weight(1f))
MsTextField(verein, { verein = it }, label = "Verein", modifier = Modifier.weight(1f))
}
}
}