feat(design-system): add MsDialogShell and MsConfirmDialog components, and update roadmap
- Introduced `MsDialogShell` for a standardized modal dialog framework. - Added `MsConfirmDialog` as a utility for common confirmation dialogs. - Updated `Frontend_Komponenten_Roadmap.md` to mark `MsDialogShell` as complete. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
@@ -53,7 +53,7 @@ Hier bringen wir alles zusammen, bevor das finale Routing implementiert wird.
|
|||||||
|
|
||||||
* [x] **`MsMasterDetailLayout`:** Standard-Layout für alle Stammdaten-Screens (Liste & Editor).
|
* [x] **`MsMasterDetailLayout`:** Standard-Layout für alle Stammdaten-Screens (Liste & Editor).
|
||||||
* [x] **`MsActionToolbar`:** Einheitliche Platzierung von Hauptaktionen (Neu, Speichern, Drucken).
|
* [x] **`MsActionToolbar`:** Einheitliche Platzierung von Hauptaktionen (Neu, Speichern, Drucken).
|
||||||
* [ ] **`MsDialogShell`:** Standardisierter Rahmen für Modale und Bestätigungsdialoge.
|
* [x] **`MsDialogShell`:** Standardisierter Rahmen für Modale und Bestätigungsdialoge.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
enum class ButtonVariant {
|
enum class ButtonVariant {
|
||||||
@@ -25,7 +26,8 @@ fun MsButton(
|
|||||||
size: ButtonSize = ButtonSize.MEDIUM,
|
size: ButtonSize = ButtonSize.MEDIUM,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
isLoading: Boolean = false,
|
isLoading: Boolean = false,
|
||||||
fullWidth: Boolean = false
|
fullWidth: Boolean = false,
|
||||||
|
containerColor: Color? = null
|
||||||
) {
|
) {
|
||||||
val buttonModifier = modifier.then(
|
val buttonModifier = modifier.then(
|
||||||
if (fullWidth) Modifier.fillMaxWidth() else Modifier
|
if (fullWidth) Modifier.fillMaxWidth() else Modifier
|
||||||
@@ -41,7 +43,8 @@ fun MsButton(
|
|||||||
ButtonVariant.PRIMARY -> Button(
|
ButtonVariant.PRIMARY -> Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
modifier = buttonModifier,
|
modifier = buttonModifier,
|
||||||
enabled = enabled && !isLoading
|
enabled = enabled && !isLoading,
|
||||||
|
colors = if (containerColor != null) ButtonDefaults.buttonColors(containerColor = containerColor) else ButtonDefaults.buttonColors()
|
||||||
) {
|
) {
|
||||||
ButtonContent(text = text, isLoading = isLoading)
|
ButtonContent(text = text, isLoading = isLoading)
|
||||||
}
|
}
|
||||||
@@ -49,7 +52,8 @@ fun MsButton(
|
|||||||
ButtonVariant.SECONDARY -> FilledTonalButton(
|
ButtonVariant.SECONDARY -> FilledTonalButton(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
modifier = buttonModifier,
|
modifier = buttonModifier,
|
||||||
enabled = enabled && !isLoading
|
enabled = enabled && !isLoading,
|
||||||
|
colors = if (containerColor != null) ButtonDefaults.filledTonalButtonColors(containerColor = containerColor) else ButtonDefaults.filledTonalButtonColors()
|
||||||
) {
|
) {
|
||||||
ButtonContent(text = text, isLoading = isLoading)
|
ButtonContent(text = text, isLoading = isLoading)
|
||||||
}
|
}
|
||||||
|
|||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
package at.mocode.frontend.core.designsystem.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import at.mocode.frontend.core.designsystem.theme.Dimens
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ein einheitlicher Rahmen für modale Dialoge.
|
||||||
|
*
|
||||||
|
* @param title Die Überschrift des Dialogs.
|
||||||
|
* @param onDismissRequest Callback, wenn der Dialog geschlossen werden soll (z.B. Klick außerhalb).
|
||||||
|
* @param confirmButton Die primäre Aktion (z.B. OK, Speichern).
|
||||||
|
* @param dismissButton Die sekundäre Aktion (z.B. Abbrechen).
|
||||||
|
* @param modifier Modifier für das Surface des Dialogs.
|
||||||
|
* @param content Der eigentliche Inhalt des Dialogs.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun MsDialogShell(
|
||||||
|
title: String,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
confirmButton: @Composable () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
dismissButton: @Composable (() -> Unit)? = null,
|
||||||
|
content: @Composable ColumnScope.() -> Unit
|
||||||
|
) {
|
||||||
|
Dialog(onDismissRequest = onDismissRequest) {
|
||||||
|
Surface(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth(0.9f)
|
||||||
|
.wrapContentHeight(),
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
tonalElevation = 6.dp
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(Dimens.SpacingM)
|
||||||
|
) {
|
||||||
|
// --- 1. Titel-Bereich ---
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
modifier = Modifier.padding(bottom = Dimens.SpacingM)
|
||||||
|
)
|
||||||
|
|
||||||
|
// --- 2. Content-Bereich ---
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(weight = 1f, fill = false)
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(Dimens.SpacingM))
|
||||||
|
|
||||||
|
// --- 3. Button-Leiste ---
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
if (dismissButton != null) {
|
||||||
|
dismissButton()
|
||||||
|
Spacer(modifier = Modifier.width(Dimens.SpacingS))
|
||||||
|
}
|
||||||
|
confirmButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hilfs-Funktion für einen Standard-Bestätigungsdialog.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun MsConfirmDialog(
|
||||||
|
title: String,
|
||||||
|
message: String,
|
||||||
|
onConfirm: () -> Unit,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
confirmText: String = "Bestätigen",
|
||||||
|
dismissText: String = "Abbrechen",
|
||||||
|
isDestructive: Boolean = false
|
||||||
|
) {
|
||||||
|
MsDialogShell(
|
||||||
|
title = title,
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
confirmButton = {
|
||||||
|
MsButton(
|
||||||
|
text = confirmText,
|
||||||
|
onClick = onConfirm,
|
||||||
|
variant = if (isDestructive) ButtonVariant.PRIMARY else ButtonVariant.PRIMARY,
|
||||||
|
// Bei destruktiven Aktionen könnten wir hier später eine rote Farbe erzwingen
|
||||||
|
containerColor = if (isDestructive) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary,
|
||||||
|
size = ButtonSize.SMALL
|
||||||
|
)
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
MsButton(
|
||||||
|
text = dismissText,
|
||||||
|
onClick = onDismiss,
|
||||||
|
variant = ButtonVariant.TEXT,
|
||||||
|
size = ButtonSize.SMALL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = message,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user