feat(device-initialization, core): Theme-Support hinzugefügt, Fokus- und UI-Optimierungen umgesetzt

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-29 15:02:55 +02:00
parent fd78404d72
commit b94984043c
21 changed files with 447 additions and 293 deletions
@@ -7,8 +7,11 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.input.key.*
import androidx.compose.ui.unit.dp
import at.mocode.frontend.core.designsystem.theme.Dimens
import kotlinx.coroutines.launch
/**
* Ein generischer Dropdown zur Auswahl von Enum-Werten.
@@ -55,35 +58,46 @@ fun <T : Enum<T>> MsEnumDropdown(
) {
Text(label, style = MaterialTheme.typography.bodySmall)
if (helpDescription != null) {
var showHelp by remember { mutableStateOf(false) }
Box {
val tooltipState = rememberTooltipState(isPersistent = true)
val scope = rememberCoroutineScope()
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
TooltipAnchorPosition.Above
),
tooltip = {
PlainTooltip(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
shape = MaterialTheme.shapes.small
) {
Text(
text = helpDescription,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(Dimens.SpacingS)
)
}
},
state = tooltipState
) {
IconButton(
onClick = { showHelp = !showHelp },
modifier = Modifier.size(16.dp)
onClick = {
scope.launch {
if (tooltipState.isVisible) tooltipState.dismiss()
else tooltipState.show()
}
},
modifier = Modifier
.size(16.dp)
.focusProperties { canFocus = false }
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.HelpOutline,
contentDescription = "Hilfe",
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f),
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f),
modifier = Modifier.size(14.dp)
)
}
if (showHelp) {
@OptIn(ExperimentalMaterial3Api::class)
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
TooltipAnchorPosition.Above
),
tooltip = {
PlainTooltip {
Text(helpDescription)
}
},
state = rememberTooltipState(isPersistent = true)
) {
// Tooltip wird durch Klick auf das Icon getriggert
}
}
}
}
}
@@ -7,8 +7,11 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.input.key.*
import androidx.compose.ui.unit.dp
import at.mocode.frontend.core.designsystem.theme.Dimens
import kotlinx.coroutines.launch
/**
* Ein generischer Dropdown zur Auswahl von Strings (z. B. Druckernamen).
@@ -45,35 +48,46 @@ fun MsStringDropdown(
) {
Text(label, style = MaterialTheme.typography.bodySmall)
if (helpDescription != null) {
var showHelp by remember { mutableStateOf(false) }
Box {
val tooltipState = rememberTooltipState(isPersistent = true)
val scope = rememberCoroutineScope()
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
TooltipAnchorPosition.Above
),
tooltip = {
PlainTooltip(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
shape = MaterialTheme.shapes.small
) {
Text(
text = helpDescription,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(Dimens.SpacingS)
)
}
},
state = tooltipState
) {
IconButton(
onClick = { showHelp = !showHelp },
modifier = Modifier.size(16.dp)
onClick = {
scope.launch {
if (tooltipState.isVisible) tooltipState.dismiss()
else tooltipState.show()
}
},
modifier = Modifier
.size(16.dp)
.focusProperties { canFocus = false }
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.HelpOutline,
contentDescription = "Hilfe",
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f),
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f),
modifier = Modifier.size(14.dp)
)
}
if (showHelp) {
@OptIn(ExperimentalMaterial3Api::class)
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
TooltipAnchorPosition.Above
),
tooltip = {
PlainTooltip {
Text(helpDescription)
}
},
state = rememberTooltipState(isPersistent = true)
) {
// Tooltip wird durch Klick auf das Icon getriggert
}
}
}
}
}
@@ -9,6 +9,7 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@@ -16,6 +17,7 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import at.mocode.frontend.core.designsystem.theme.Dimens
import kotlinx.coroutines.launch
@Composable
fun MsTextField(
@@ -56,35 +58,48 @@ fun MsTextField(
color = if (isError) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant
)
if (helpDescription != null) {
var showHelp by remember { mutableStateOf(false) }
Box {
@OptIn(ExperimentalMaterial3Api::class)
val tooltipState = rememberTooltipState(isPersistent = true)
val scope = rememberCoroutineScope()
@OptIn(ExperimentalMaterial3Api::class)
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
TooltipAnchorPosition.Above
),
tooltip = {
PlainTooltip(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
shape = MaterialTheme.shapes.small
) {
Text(
text = helpDescription,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(Dimens.SpacingS)
)
}
},
state = tooltipState
) {
IconButton(
onClick = { showHelp = !showHelp },
modifier = Modifier.size(16.dp)
onClick = {
scope.launch {
if (tooltipState.isVisible) tooltipState.dismiss()
else tooltipState.show()
}
},
modifier = Modifier
.size(16.dp)
.focusProperties { canFocus = false }
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.HelpOutline,
contentDescription = "Hilfe",
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f),
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f),
modifier = Modifier.size(14.dp)
)
}
if (showHelp) {
@OptIn(ExperimentalMaterial3Api::class)
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
TooltipAnchorPosition.Above
),
tooltip = {
PlainTooltip {
Text(helpDescription)
}
},
state = rememberTooltipState(isPersistent = true)
) {
// Tooltip wird durch Klick auf das Icon getriggert
}
}
}
}
}
@@ -121,7 +136,9 @@ fun MsTextField(
unfocusedContainerColor = MaterialTheme.colorScheme.surface,
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f),
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.outline.copy(alpha = 0.5f),
unfocusedBorderColor = MaterialTheme.colorScheme.outline.copy(alpha = 0.3f),
focusedLabelColor = MaterialTheme.colorScheme.primary,
unfocusedLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
),
keyboardOptions = KeyboardOptions(
keyboardType = keyboardType,
@@ -1,5 +1,6 @@
package at.mocode.frontend.core.designsystem.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
@@ -38,7 +39,8 @@ private val DarkColorScheme = darkColorScheme(
background = AppColors.BackgroundDark,
surface = AppColors.SurfaceDark,
onBackground = AppColors.OnBackgroundDark,
onSurface = AppColors.OnBackgroundDark,
onSurface = AppColors.OnSurfaceDark,
outline = AppColors.OutlineDark,
error = AppColors.Error,
onError = AppColors.OnError
@@ -63,7 +65,7 @@ private val AppMaterialTypography = Typography(
@Composable
fun AppTheme(
darkTheme: Boolean = false, // Kann später via Settings gesteuert werden
darkTheme: Boolean = isSystemInDarkTheme(), // Nutzt Systemeinstellung als Default
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme
@@ -28,9 +28,11 @@ object AppColors {
val OnBackgroundLight = Color(0xFF172B4D) // Fast Schwarz (besser lesbar)
// Neutral & Hintergrund (Dark Mode)
val BackgroundDark = Color(0xFF1E1E1E) // Angenehmes, dunkles Grau
val SurfaceDark = Color(0xFF2C2C2C)
val OnBackgroundDark = Color(0xFFEBECF0)
val BackgroundDark = Color(0xFF121212) // Tieferes Schwarz für Dark Mode
val SurfaceDark = Color(0xFF1E1E1E)
val OnBackgroundDark = Color(0xFFE1E1E1)
val OnSurfaceDark = Color(0xFFE1E1E1)
val OutlineDark = Color(0xFF333333)
// System Status
val Error = Color(0xFFDE350B)
@@ -34,7 +34,7 @@ object Dimens {
val CornerRadiusL = 12.dp
// Form-Elemente (Eingabefelder, Buttons)
val TextFieldHeight = 44.dp // Kompakte Höhe für Desktop-Enterprise-Apps
val TextFieldHeightL = 56.dp // Standard Material Höhe (für prominente Felder)
val ButtonHeight = 40.dp
val TextFieldHeight = 40.dp // Kompakte Höhe für Desktop-Enterprise-Apps
val TextFieldHeightL = 48.dp // Etwas weniger als Standard Material (56.dp)
val ButtonHeight = 36.dp // Kompakterer Button
}