Skip to content

Commit 5bd4b9d

Browse files
committed
Android: fix double parse, stale now, and null unit in task list
1 parent 31122d8 commit 5bd4b9d

File tree

1 file changed

+34
-38
lines changed

1 file changed

+34
-38
lines changed

android/app/src/main/java/com/dkhalife/tasks/ui/screen/TaskListScreen.kt

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import java.time.ZonedDateTime
3333
import java.time.format.DateTimeFormatter
3434
import java.time.temporal.ChronoUnit
3535
import java.util.Locale
36+
import kotlinx.coroutines.delay
3637

3738
@OptIn(ExperimentalMaterial3Api::class)
3839
@Composable
@@ -170,6 +171,9 @@ private fun TaskItem(
170171
onDelete: () -> Unit,
171172
onClick: () -> Unit
172173
) {
174+
val ldt = remember(task.nextDueDate) { parseDueDate(task.nextDueDate) }
175+
val now by rememberTickingNow()
176+
173177
Card(
174178
modifier = Modifier
175179
.fillMaxWidth()
@@ -197,8 +201,8 @@ private fun TaskItem(
197201
verticalAlignment = Alignment.CenterVertically,
198202
modifier = Modifier.padding(bottom = 4.dp)
199203
) {
200-
DueDateChip(task.nextDueDate)
201-
RecurrenceChip(task)
204+
DueDateChip(ldt, now)
205+
RecurrenceChip(task, ldt)
202206
if (hasActiveNotification(task)) {
203207
NotificationChip()
204208
}
@@ -245,16 +249,8 @@ private fun TaskItem(
245249
}
246250

247251
@Composable
248-
private fun DueDateChip(dateStr: String?) {
249-
val ldt = remember(dateStr) {
250-
dateStr?.let {
251-
try {
252-
ZonedDateTime.parse(it).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime()
253-
} catch (_: Exception) { null }
254-
}
255-
}
256-
val now = LocalDateTime.now()
257-
val text = if (dateStr == null) "No Due Date" else formatDueDate(dateStr)
252+
private fun DueDateChip(ldt: LocalDateTime?, now: LocalDateTime) {
253+
val text = if (ldt == null) "No Due Date" else formatDueDate(ldt, now)
258254
val (bgColor, fgColor) = when {
259255
ldt == null -> Pair(MaterialTheme.colorScheme.surfaceVariant, MaterialTheme.colorScheme.onSurfaceVariant)
260256
ldt.isBefore(now) -> Pair(MaterialTheme.colorScheme.errorContainer, MaterialTheme.colorScheme.onErrorContainer)
@@ -272,14 +268,7 @@ private fun DueDateChip(dateStr: String?) {
272268
}
273269

274270
@Composable
275-
private fun RecurrenceChip(task: Task) {
276-
val nextDueLdt = remember(task.nextDueDate) {
277-
task.nextDueDate?.let {
278-
try {
279-
ZonedDateTime.parse(it).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime()
280-
} catch (_: Exception) { null }
281-
}
282-
}
271+
private fun RecurrenceChip(task: Task, nextDueLdt: LocalDateTime?) {
283272
val text = getRecurrenceText(task, nextDueLdt)
284273
val isOnce = task.frequency.type == FrequencyType.ONCE
285274
Surface(
@@ -352,22 +341,29 @@ private fun LabelChip(name: String, color: String) {
352341
}
353342
}
354343

355-
private fun formatDueDate(dateStr: String): String {
356-
return try {
357-
val ldt = ZonedDateTime.parse(dateStr)
358-
.withZoneSameInstant(ZoneId.systemDefault())
359-
.toLocalDateTime()
360-
val now = LocalDateTime.now()
361-
val today = LocalDate.now()
362-
val timeStr = ldt.format(DateTimeFormatter.ofPattern("hh:mm a", Locale.ENGLISH))
363-
when {
364-
ldt.isBefore(now) -> "${formatDistance(ldt, now)} ago"
365-
ldt.toLocalDate() == today -> "Today at $timeStr"
366-
ldt.toLocalDate() == today.plusDays(1) -> "Tomorrow at $timeStr"
367-
else -> "in ${formatDistance(now, ldt)}"
368-
}
369-
} catch (_: Exception) {
370-
dateStr
344+
private fun parseDueDate(dateStr: String?): LocalDateTime? =
345+
dateStr?.let {
346+
try {
347+
ZonedDateTime.parse(it).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime()
348+
} catch (_: Exception) { null }
349+
}
350+
351+
@Composable
352+
private fun rememberTickingNow(): State<LocalDateTime> = produceState(LocalDateTime.now()) {
353+
while (true) {
354+
delay(60_000L)
355+
value = LocalDateTime.now()
356+
}
357+
}
358+
359+
private fun formatDueDate(ldt: LocalDateTime, now: LocalDateTime): String {
360+
val today = now.toLocalDate()
361+
val timeStr = ldt.format(DateTimeFormatter.ofPattern("hh:mm a", Locale.ENGLISH))
362+
return when {
363+
ldt.isBefore(now) -> "${formatDistance(ldt, now)} ago"
364+
ldt.toLocalDate() == today -> "Today at $timeStr"
365+
ldt.toLocalDate() == today.plusDays(1) -> "Tomorrow at $timeStr"
366+
else -> "in ${formatDistance(now, ldt)}"
371367
}
372368
}
373369

@@ -407,10 +403,10 @@ private fun getRecurrenceText(task: Task, nextDueLdt: LocalDateTime?): String {
407403
IntervalUnit.WEEKS -> "Weekly"
408404
IntervalUnit.MONTHS -> "Monthly"
409405
IntervalUnit.YEARS -> "Yearly"
410-
else -> "Every $every ${frequency.unit}"
406+
else -> "Custom"
411407
}
412408
} else {
413-
"Every $every ${frequency.unit}"
409+
frequency.unit?.let { "Every $every $it" } ?: "Custom"
414410
}
415411
}
416412
RepeatOn.DAYS_OF_THE_WEEK -> {

0 commit comments

Comments
 (0)