Refine period tracking logic and UI feedback in DayDetailScreen.

- Update `DayDetailUiState` to include `hasActiveCycle` and `cycleStartDate` to better track ongoing cycles.
- Replace `periodActive` check with `hasActiveCycle` for displaying the "Period day" badge and toggle icons.
- Improve validation for the "Period ended" action:
    - Enable the chip only if a cycle is active and the current date is after the cycle's start date.
- Update `DayDetailViewModel` to accurately calculate `periodDayNumber` and cycle status by fetching records from the repository.
- Ensure period state is correctly reset or initialized when toggling period start/end.

Signed-off-by: whitlocktech <whitlocktech@gmail.com>
This commit is contained in:
2026-05-22 17:52:18 -05:00
parent 5b900a4823
commit cd276ed44c
2 changed files with 17 additions and 9 deletions

View File

@@ -152,7 +152,7 @@ private fun CycleSection(
} }
// Period day-of-period badge // Period day-of-period badge
if (state.periodActive && state.periodDayNumber > 0) { if (state.hasActiveCycle && state.periodDayNumber > 0) {
Text( Text(
"Period day ${state.periodDayNumber}", "Period day ${state.periodDayNumber}",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
@@ -171,7 +171,7 @@ private fun CycleSection(
label = { Text("Period started") }, label = { Text("Period started") },
leadingIcon = { leadingIcon = {
Icon( Icon(
if (state.isPeriodStart) Icons.Default.Check else Icons.Default.PlayArrow, if (state.isPeriodStart || state.hasActiveCycle) Icons.Default.Check else Icons.Default.PlayArrow,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(16.dp) modifier = Modifier.size(16.dp)
) )
@@ -180,7 +180,8 @@ private fun CycleSection(
FilterChip( FilterChip(
selected = state.isPeriodEnd, selected = state.isPeriodEnd,
onClick = onTogglePeriodEnd, onClick = onTogglePeriodEnd,
enabled = state.isPeriodStart || state.periodActive || state.isPeriodEnd, enabled = state.isPeriodEnd ||
(state.hasActiveCycle && state.cycleStartDate != null && state.date > state.cycleStartDate),
label = { Text("Period ended") }, label = { Text("Period ended") },
leadingIcon = { leadingIcon = {
Icon( Icon(

View File

@@ -31,6 +31,8 @@ data class DayDetailUiState(
val isPeriodStart: Boolean = false, val isPeriodStart: Boolean = false,
val isPeriodEnd: Boolean = false, val isPeriodEnd: Boolean = false,
val periodDayNumber: Int = 0, // day-of-period for this date (1 = first day) val periodDayNumber: Int = 0, // day-of-period for this date (1 = first day)
val hasActiveCycle: Boolean = false, // a cycle record spans this date (start logged, regardless of which day)
val cycleStartDate: LocalDate? = null,
val notes: String = "", val notes: String = "",
val conditions: Map<String, Int> = emptyMap(), val conditions: Map<String, Int> = emptyMap(),
val definitions: List<ConditionDefinitionEntity> = emptyList(), val definitions: List<ConditionDefinitionEntity> = emptyList(),
@@ -88,12 +90,11 @@ class DayDetailViewModel @Inject constructor(
val isPeriodStart = isFemale && cycleRepository.isPeriodStart(activeProfile.id, dateStr) val isPeriodStart = isFemale && cycleRepository.isPeriodStart(activeProfile.id, dateStr)
val isPeriodEnd = isFemale && cycleRepository.isPeriodEnd(activeProfile.id, dateStr) val isPeriodEnd = isFemale && cycleRepository.isPeriodEnd(activeProfile.id, dateStr)
// Calculate day-of-period: how many days from the period start to this date val cycleRecord = if (isFemale) cycleRepository.getRecordContainingDate(activeProfile.id, dateStr) else null
val periodDayNumber = if (isFemale && dayLog.periodActive) { val hasActiveCycle = cycleRecord != null
val record = cycleRepository.getRecordContainingDate(activeProfile.id, dateStr) val cycleStartDate = cycleRecord?.let { LocalDate.parse(it.cycleStart) }
if (record != null) { val periodDayNumber = if (cycleRecord != null) {
(date.toEpochDay() - LocalDate.parse(record.cycleStart).toEpochDay()).toInt() + 1 (date.toEpochDay() - LocalDate.parse(cycleRecord.cycleStart).toEpochDay()).toInt() + 1
} else 0
} else 0 } else 0
_uiState.value = DayDetailUiState( _uiState.value = DayDetailUiState(
@@ -105,6 +106,8 @@ class DayDetailViewModel @Inject constructor(
isPeriodStart = isPeriodStart, isPeriodStart = isPeriodStart,
isPeriodEnd = isPeriodEnd, isPeriodEnd = isPeriodEnd,
periodDayNumber = periodDayNumber, periodDayNumber = periodDayNumber,
hasActiveCycle = hasActiveCycle,
cycleStartDate = cycleStartDate,
notes = dayLog.notes ?: "", notes = dayLog.notes ?: "",
conditions = conditions, conditions = conditions,
definitions = defsToShow, definitions = defsToShow,
@@ -136,6 +139,8 @@ class DayDetailViewModel @Inject constructor(
periodActive = false, periodActive = false,
dayLog = updatedLog, dayLog = updatedLog,
periodDayNumber = 0, periodDayNumber = 0,
hasActiveCycle = false,
cycleStartDate = null,
isDirty = true isDirty = true
) )
} else { } else {
@@ -150,6 +155,8 @@ class DayDetailViewModel @Inject constructor(
periodActive = true, periodActive = true,
dayLog = updatedLog, dayLog = updatedLog,
periodDayNumber = 1, periodDayNumber = 1,
hasActiveCycle = true,
cycleStartDate = date,
isDirty = true isDirty = true
) )
} }