Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ fun ChoreListScreen(

else -> {
val displayed = uiState.displayed
val distantChores = uiState.distantChores
val hiddenChores = uiState.hiddenChores
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(bottom = 88.dp)
Expand Down Expand Up @@ -281,24 +281,28 @@ fun ChoreListScreen(
}
}

if (distantChores.isNotEmpty()) {
if (hiddenChores.isNotEmpty()) {
item {
TextButton(
onClick = { viewModel.toggleShowDistant() },
onClick = { viewModel.toggleShowHidden() },
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)
) {
Text(
if (uiState.showDistant)
"Hide distant (${distantChores.size})"
else
"${distantChores.size} not due for 60+ days",
when {
uiState.showHidden ->
"Collapse hidden chores (${hiddenChores.size})"
uiState.smartVisibility ->
"${hiddenChores.size} hidden until closer to due"
else ->
"${hiddenChores.size} not due for 60+ days"
},
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
if (uiState.showDistant) {
items(distantChores, key = { "distant_${it.id}" }) { chore ->
if (uiState.showHidden) {
items(hiddenChores, key = { "hidden_${it.id}" }) { chore ->
SwipeToLogCard(
chore = chore,
showOwner = uiState.ownerFilter == OwnerFilter.ALL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ data class ChoreUiState(
val zenMode: Boolean = false,
val zenSortAscending: Boolean = true,
val showDueCountdown: Boolean = false,
val showDistant: Boolean = false,
val showHidden: Boolean = false,
// Off until settings load so chores aren't hidden with unconfigured lead times
val smartVisibility: Boolean = false,
val choreLeadDays: Map<CadenceBucket, Int> = emptyMap(),
Expand All @@ -60,31 +60,43 @@ data class ChoreUiState(
val pinnedChoreId: String? = null,
val scanHistory: List<ScanDto> = emptyList()
) {
val distantChores: List<Chore>
private val ownerFiltered: List<Chore>
get() {
var result = active
if (ownerFilter == OwnerFilter.ME && ownerHandle.isNotBlank()) {
result = result.filter { it.owner == null || it.owner == ownerHandle }
}
return result.filter { it.isDistant() }
return result
}

/** True if this chore belongs in the main list under its cadence bucket's lead time. */
private fun withinLeadTime(chore: Chore): Boolean {
val last = chore.lastScanned ?: return true
val intervalDays = chore.intervalDays ?: return true
val bucket = CadenceBucket.forInterval(intervalDays)
val leadDays = choreLeadDays[bucket] ?: bucket.defaultLeadDays
val dueInstant = last.plus((intervalDays * 24).toLong(), ChronoUnit.HOURS)
return Duration.between(Instant.now(), dueInstant).toDays() <= leadDays
}

/**
* Chores kept out of the main list but revealable via the collapsed section:
* everything beyond its lead time when smart visibility is on, otherwise only
* the legacy distant (due 60+ days out) chores.
*/
val hiddenChores: List<Chore>
get() = if (smartVisibility) {
ownerFiltered.filterNot(::withinLeadTime)
} else {
ownerFiltered.filter { it.isDistant() }
}

val displayed: List<Chore>
get() {
var result = active
if (ownerFilter == OwnerFilter.ME && ownerHandle.isNotBlank()) {
result = result.filter { it.owner == null || it.owner == ownerHandle }
}
result = result.filter { !it.isDistant() }
if (smartVisibility) {
result = result.filter { chore ->
val last = chore.lastScanned ?: return@filter true
val intervalDays = chore.intervalDays ?: return@filter true
val bucket = CadenceBucket.forInterval(intervalDays)
val leadDays = choreLeadDays[bucket] ?: bucket.defaultLeadDays
val dueInstant = last.plus((intervalDays * 24).toLong(), ChronoUnit.HOURS)
Duration.between(Instant.now(), dueInstant).toDays() <= leadDays
}
var result = if (smartVisibility) {
ownerFiltered.filter(::withinLeadTime)
} else {
ownerFiltered.filter { !it.isDistant() }
}
result = when (filter) {
ChoreFilter.ALL -> result
Expand Down Expand Up @@ -320,7 +332,7 @@ class ChoreListViewModel @Inject constructor(
viewModelScope.launch { settingsRepository.setShowDueCountdown(enabled) }
}

fun toggleShowDistant() {
_uiState.update { it.copy(showDistant = !it.showDistant) }
fun toggleShowHidden() {
_uiState.update { it.copy(showHidden = !it.showHidden) }
}
}
9 changes: 9 additions & 0 deletions changelog/unreleased/hidden-chores-section.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"bump": "patch",
"changed": [
"The collapsed section at the bottom of the chores list now reveals everything hidden by smart visibility, not just chores due 60+ days out, and its label reflects why chores are hidden"
],
"fixed": [
"Chores hidden by smart visibility could not be viewed or logged from the chores screen"
]
}
Loading