diff --git a/build.gradle.kts b/build.gradle.kts index bf0fc45..c303232 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,5 +10,5 @@ plugins { subprojects { group = "de.jeanlucmakiola.floret" - version = "0.1.0" + version = "0.2.0" } diff --git a/components/src/main/kotlin/de/jeanlucmakiola/floret/components/DialogControls.kt b/components/src/main/kotlin/de/jeanlucmakiola/floret/components/DialogControls.kt index b7c65e3..9238b0f 100644 --- a/components/src/main/kotlin/de/jeanlucmakiola/floret/components/DialogControls.kt +++ b/components/src/main/kotlin/de/jeanlucmakiola/floret/components/DialogControls.kt @@ -1,8 +1,11 @@ package de.jeanlucmakiola.floret.components +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape @@ -10,8 +13,12 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SegmentedButton +import androidx.compose.material3.SegmentedButtonDefaults +import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -57,6 +64,83 @@ fun DialogAmountField( } } +/** + * The expanded "Custom" editor card shared by the family's presets-plus-custom + * pickers (reminder lead time, agenda range, snooze delay). A tonal surface with + * the connected-shape that meets the "Custom" row above it (tight top corners, + * full bottom), holding — top to bottom — an optional single-choice unit toggle, + * then a row of [DialogAmountField] + a live [preview] of what the amount + * resolves to + a tonal confirm. + * + * Purely presentational: the caller owns the amount/unit state and computes + * [preview] and [confirmEnabled] from its own domain, so this component carries + * no units, ranges, or strings of its own. Pass [unitLabels] empty for an + * amount-only editor (no toggle row). [onConfirm] fires on the confirm button. + */ +@Composable +fun CustomAmountEditor( + amountText: String, + onAmountChange: (String) -> Unit, + preview: String, + setLabel: String, + confirmEnabled: Boolean, + onConfirm: () -> Unit, + modifier: Modifier = Modifier, + placeholder: String = "10", + unitLabels: List = emptyList(), + selectedUnit: Int = 0, + onUnitChange: (Int) -> Unit = {}, +) { + Surface( + color = MaterialTheme.colorScheme.surfaceContainerHigh, + // A Position.Bottom shape: tight top corners meeting the row, full bottom. + shape = RoundedCornerShape(topStart = 6.dp, topEnd = 6.dp, bottomStart = 22.dp, bottomEnd = 22.dp), + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) { + Column( + modifier = Modifier.padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + // Unit toggle first (when present) so it stays visible above the + // keyboard once the amount field below it is focused and scrolled in. + if (unitLabels.isNotEmpty()) { + SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) { + unitLabels.forEachIndexed { index, label -> + SegmentedButton( + selected = index == selectedUnit, + onClick = { onUnitChange(index) }, + shape = SegmentedButtonDefaults.itemShape(index, unitLabels.size), + label = { Text(label) }, + ) + } + } + } + // Amount, a live preview of what it resolves to, and confirm — all on + // one row, sitting just above the keyboard. + Row(verticalAlignment = Alignment.CenterVertically) { + DialogAmountField( + value = amountText, + onValueChange = onAmountChange, + placeholder = placeholder, + ) + Spacer(Modifier.width(16.dp)) + Text( + text = preview, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.weight(1f), + ) + Spacer(Modifier.width(16.dp)) + FilledTonalButton(onClick = onConfirm, enabled = confirmEnabled) { + Text(setLabel) + } + } + } + } +} + /** Tonal dropdown trigger + menu shared by the custom reminder/recurrence steps and pickers. */ @Composable fun DialogUnitDropdown(