Drop the editor's pass-through wrappers
This commit is contained in:
@@ -84,7 +84,6 @@ import de.jeanlucmakiola.calendula.domain.EventForm
|
||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||
import de.jeanlucmakiola.calendula.domain.EventStatus
|
||||
import de.jeanlucmakiola.calendula.domain.InlineStyle
|
||||
import de.jeanlucmakiola.calendula.domain.Reminder
|
||||
import de.jeanlucmakiola.calendula.domain.RichText
|
||||
import de.jeanlucmakiola.calendula.domain.TimeZoneOption
|
||||
import de.jeanlucmakiola.calendula.domain.timeZoneOptionOf
|
||||
@@ -303,7 +302,7 @@ private fun EventDetailContent(
|
||||
val detail = state.detail
|
||||
val instance = detail.instance
|
||||
val dark = LocalFloretDarkTheme.current
|
||||
val locale = currentDetailLocale()
|
||||
val locale = currentLocale()
|
||||
val accent = eventAccent(instance.color, dark, LocalSoftenColors.current)
|
||||
|
||||
Column(
|
||||
@@ -536,7 +535,7 @@ private fun EventDetailContent(
|
||||
.sortedBy { it.minutes }
|
||||
.forEach { reminder ->
|
||||
Text(
|
||||
text = reminderLeadText(reminder),
|
||||
text = reminderLeadTimeLabel(reminder.minutes),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier.padding(vertical = 2.dp),
|
||||
)
|
||||
@@ -683,11 +682,6 @@ private fun SkeletonBar(widthFraction: Float, height: Dp) {
|
||||
|
||||
// --- helpers -------------------------------------------------------------
|
||||
|
||||
// Observable locale read (shared helper) — avoids NonObservableLocale /
|
||||
// LocalContextConfigurationRead lint by going through LocalConfiguration.
|
||||
@Composable
|
||||
private fun currentDetailLocale(): Locale = currentLocale()
|
||||
|
||||
private fun attendeeStatusLabel(status: AttendeeStatus): Int = when (status) {
|
||||
AttendeeStatus.Accepted -> R.string.event_attendee_accepted
|
||||
AttendeeStatus.Declined -> R.string.event_attendee_declined
|
||||
@@ -707,10 +701,6 @@ private fun attendeeRoleLabel(attendee: Attendee): Int? = when {
|
||||
else -> null
|
||||
}
|
||||
|
||||
/** Humanise a reminder's lead time, e.g. "10 minutes before" / "At time of event". */
|
||||
@Composable
|
||||
private fun reminderLeadText(reminder: Reminder): String = reminderLeadTimeLabel(reminder.minutes)
|
||||
|
||||
/**
|
||||
* [tz] resolved as a [TimeZoneOption], but only when the event is timed and
|
||||
* pinned to a zone different from the device's — the cases where showing it
|
||||
|
||||
@@ -133,7 +133,6 @@ import de.jeanlucmakiola.calendula.domain.timeZoneOptionOf
|
||||
import de.jeanlucmakiola.calendula.domain.EventFormProblem
|
||||
import de.jeanlucmakiola.calendula.domain.RecurrenceEnd
|
||||
import de.jeanlucmakiola.calendula.domain.RecurrenceFreq
|
||||
import de.jeanlucmakiola.calendula.domain.RecurringWriteScope
|
||||
import de.jeanlucmakiola.calendula.domain.SimpleRecurrence
|
||||
import de.jeanlucmakiola.calendula.domain.parseSimpleRecurrence
|
||||
import de.jeanlucmakiola.calendula.domain.toRRule
|
||||
@@ -450,10 +449,13 @@ fun EventEditScreen(
|
||||
}
|
||||
|
||||
if (state?.saveState == SaveUiState.AwaitingScope) {
|
||||
SaveScopeDialog(
|
||||
recurrenceChanged = state?.recurrenceChanged == true,
|
||||
// A changed rule rules out the single occurrence — an exception row
|
||||
// can't carry its own rule.
|
||||
RecurringScopeDialog(
|
||||
title = stringResource(R.string.event_edit_recurring_title),
|
||||
onSelect = viewModel::saveWithScope,
|
||||
onDismiss = viewModel::consumeSaveResult,
|
||||
allowOccurrence = state?.recurrenceChanged != true,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -654,26 +656,6 @@ private fun SaveConflictDialog(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope choice when saving a dirty recurring event: one tap writes just the
|
||||
* tapped occurrence, it and everything after (series split), or the whole
|
||||
* series. A changed recurrence rule rules out the single occurrence — an
|
||||
* exception row can't carry its own rule.
|
||||
*/
|
||||
@Composable
|
||||
private fun SaveScopeDialog(
|
||||
recurrenceChanged: Boolean,
|
||||
onSelect: (RecurringWriteScope) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
RecurringScopeDialog(
|
||||
title = stringResource(R.string.event_edit_recurring_title),
|
||||
onSelect = onSelect,
|
||||
onDismiss = onDismiss,
|
||||
allowOccurrence = !recurrenceChanged,
|
||||
)
|
||||
}
|
||||
|
||||
private enum class PickerTarget { StartDate, StartTime, EndDate, EndTime }
|
||||
|
||||
/**
|
||||
@@ -799,7 +781,7 @@ private fun EventEditContent(
|
||||
// titles wrap instead of scrolling off one line (#33); newlines are
|
||||
// stripped in setTitle, so this stays a single logical line — the Enter
|
||||
// key just has no effect.
|
||||
InlineField(
|
||||
InlineTextField(
|
||||
value = form.title,
|
||||
onValueChange = viewModel::setTitle,
|
||||
placeholder = stringResource(R.string.event_edit_title_hint),
|
||||
@@ -1018,7 +1000,7 @@ private fun EventEditContent(
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.Top) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
InlineField(
|
||||
InlineTextField(
|
||||
value = form.location,
|
||||
onValueChange = viewModel::setLocation,
|
||||
placeholder = stringResource(R.string.event_detail_location),
|
||||
@@ -1086,7 +1068,7 @@ private fun EventEditContent(
|
||||
iconAlignment = Alignment.Top,
|
||||
iconTopPadding = ((firstLineHeight() - 24.dp) / 2).coerceAtLeast(0.dp),
|
||||
) {
|
||||
InlineField(
|
||||
InlineTextField(
|
||||
value = form.description,
|
||||
onValueChange = viewModel::setDescription,
|
||||
placeholder = stringResource(R.string.event_detail_description),
|
||||
@@ -1106,7 +1088,7 @@ private fun EventEditContent(
|
||||
GroupedItemCard(
|
||||
position = positionOf(index, rows),
|
||||
icon = Icons.Default.Notifications,
|
||||
title = reminderLabel(minutes),
|
||||
title = reminderLeadTimeLabel(minutes),
|
||||
removeContentDescription = stringResource(R.string.event_edit_remove_reminder),
|
||||
onRemove = { viewModel.removeReminder(minutes) },
|
||||
)
|
||||
@@ -1497,9 +1479,6 @@ private fun FieldPickerDialog(
|
||||
}
|
||||
}
|
||||
|
||||
/** Quick-pick lead times offered as chips in the reminder dialog. */
|
||||
private val REMINDER_QUICK_PICKS = REMINDER_PRESETS
|
||||
|
||||
/**
|
||||
* Reminder picker, two steps: the common lead times as a tappable list
|
||||
* (one tap adds and closes), with "Custom" at the bottom switching to an
|
||||
@@ -1533,11 +1512,11 @@ private fun ReminderPickerDialog(
|
||||
},
|
||||
) {
|
||||
if (!customMode) {
|
||||
val presets = REMINDER_QUICK_PICKS.filterNot { it in alreadyChosen }
|
||||
val presets = REMINDER_PRESETS.filterNot { it in alreadyChosen }
|
||||
val rowCount = presets.size + 1
|
||||
presets.forEachIndexed { index, minutes ->
|
||||
GroupedRow(
|
||||
title = reminderLabel(minutes),
|
||||
title = reminderLeadTimeLabel(minutes),
|
||||
position = positionOf(index, rowCount),
|
||||
onClick = { onSelect(minutes) },
|
||||
)
|
||||
@@ -2344,10 +2323,6 @@ private fun accessLevelSummary(level: AccessLevel): Int = when (level) {
|
||||
AccessLevel.Confidential -> R.string.event_access_confidential_summary
|
||||
}
|
||||
|
||||
/** Humanise a reminder lead time, mirroring the detail screen's rendering. */
|
||||
@Composable
|
||||
private fun reminderLabel(minutes: Int): String = reminderLeadTimeLabel(minutes)
|
||||
|
||||
/**
|
||||
* "2:00 PM – 3:00 PM" in [zone], honouring the user's 12/24-hour setting. Collapses
|
||||
* to one time for an instant event, which shouldn't read as a range against
|
||||
@@ -2369,45 +2344,7 @@ private fun formatTimeRange(start: Instant, end: Instant, zone: TimeZone, locale
|
||||
}
|
||||
|
||||
/**
|
||||
* Borderless text input used inside the cards (and as the headline title).
|
||||
* Thin wrapper over the shared [InlineTextField] so the form and the rest of
|
||||
* the app share one input style. Sentence-case by default, as floret-kit is;
|
||||
* a field holding an identifier rather than prose passes
|
||||
* [KeyboardCapitalization.None].
|
||||
*/
|
||||
@Composable
|
||||
private fun InlineField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
placeholder: String,
|
||||
textStyle: TextStyle = MaterialTheme.typography.titleMedium,
|
||||
singleLine: Boolean = true,
|
||||
minLines: Int = 1,
|
||||
enabled: Boolean = true,
|
||||
keyboardType: KeyboardType = KeyboardType.Text,
|
||||
capitalization: KeyboardCapitalization = KeyboardCapitalization.Sentences,
|
||||
imeAction: ImeAction = ImeAction.Default,
|
||||
modifier: Modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
) {
|
||||
InlineTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
placeholder = placeholder,
|
||||
modifier = modifier,
|
||||
textStyle = textStyle,
|
||||
singleLine = singleLine,
|
||||
minLines = minLines,
|
||||
enabled = enabled,
|
||||
keyboardType = keyboardType,
|
||||
capitalization = capitalization,
|
||||
imeAction = imeAction,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A right-aligned "n/max" counter for a capped [InlineField] (#331), hidden
|
||||
* A right-aligned "n/max" counter for a capped [InlineTextField] (#331), hidden
|
||||
* until [length] gets close enough to [max] to matter — nobody needs to see
|
||||
* "12/255" while typing a short title.
|
||||
*/
|
||||
@@ -2429,7 +2366,7 @@ private fun FieldLengthCounter(length: Int, max: Int, modifier: Modifier = Modif
|
||||
}
|
||||
|
||||
/**
|
||||
* Height of one [InlineField] line: the resolved [TextStyle.lineHeight] plus the
|
||||
* Height of one [InlineTextField] line: the resolved [TextStyle.lineHeight] plus the
|
||||
* field's 4dp vertical padding. In dp, so it tracks the user's font scale
|
||||
* instead of assuming the 24sp line of a 1.0 scale (#165).
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user