summaryrefslogtreecommitdiff
path: root/android/app/src
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-07-13 09:47:41 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-07-16 02:39:57 +0000
commit6fc04aa3162d3d0eb9b869574ddadc032d6d3754 (patch)
tree9b4e97b45edea9b9e8564f81b40145c7bbcbe72d /android/app/src
parent99b9e252eaaadac7790788bdf9e1efb52afab53a (diff)
fix(widget): stop tomorrow's events from stretching today's grid bounds
calcGridStart/calcGridEnd only looked at hour-of-day, so a tomorrow event's early or late hour could inflate today's grid range with empty rows, pushing the non-scrolling TomorrowSection below the widget's visible area. Filter to today-only events before computing bounds.
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt13
-rw-r--r--android/app/src/test/java/org/terst/doot/widget/ui/DootWidgetGridTest.kt34
2 files changed, 43 insertions, 4 deletions
diff --git a/android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt b/android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt
index ae749fb..4a352fc 100644
--- a/android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt
+++ b/android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt
@@ -94,8 +94,13 @@ fun WidgetRoot(items: List<WidgetItem>, now: Instant, isRefreshing: Boolean) {
val scheduledEvents = allScheduled.filter { it.type != "task" || Instant.parse(it.start!!) >= now }
val floating = rest.filter { it.start == null }
val fragments = SlotPacker.pack(pastTasks + floating, scheduledEvents, now)
- val gridStart = calcGridStart(scheduledEvents, nowZoned.hour)
- val gridEnd = calcGridEnd(scheduledEvents, nowZoned.hour)
+ // Grid bounds must only reflect TODAY's events -- a tomorrow event's hour-of-day
+ // would otherwise stretch today's grid (see calcGridStart/calcGridEnd), manufacturing
+ // empty hour rows that push the non-scrolling TomorrowSection below the widget's
+ // visible area.
+ val todayScheduledEvents = scheduledEvents.filter { Instant.parse(it.start!!) < tomorrowStart }
+ val gridStart = calcGridStart(todayScheduledEvents, nowZoned.hour)
+ val gridEnd = calcGridEnd(todayScheduledEvents, nowZoned.hour)
val tomorrowItems = scheduledEvents
.filter { Instant.parse(it.start!!) >= tomorrowStart && Instant.parse(it.start!!) < tomorrowEnd }
@@ -479,7 +484,7 @@ private fun hourLabel(hour: Int): String = when {
else -> "${hour - 12}p"
}
-private fun calcGridStart(events: List<WidgetItem>, nowHour: Int): Int {
+internal fun calcGridStart(events: List<WidgetItem>, nowHour: Int): Int {
val earliest = events.mapNotNull { it.start }
.mapNotNull { runCatching { Instant.parse(it) }.getOrNull() }
.minOrNull()
@@ -488,7 +493,7 @@ private fun calcGridStart(events: List<WidgetItem>, nowHour: Int): Int {
return maxOf(0, minOf(earliest, nowHour) - 1)
}
-private fun calcGridEnd(events: List<WidgetItem>, nowHour: Int): Int {
+internal fun calcGridEnd(events: List<WidgetItem>, nowHour: Int): Int {
val latest = events.mapNotNull { it.end }
.mapNotNull { runCatching { Instant.parse(it) }.getOrNull() }
.maxOrNull()
diff --git a/android/app/src/test/java/org/terst/doot/widget/ui/DootWidgetGridTest.kt b/android/app/src/test/java/org/terst/doot/widget/ui/DootWidgetGridTest.kt
new file mode 100644
index 0000000..b3d8384
--- /dev/null
+++ b/android/app/src/test/java/org/terst/doot/widget/ui/DootWidgetGridTest.kt
@@ -0,0 +1,34 @@
+package org.terst.doot.widget.ui
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.terst.doot.widget.data.WidgetItem
+
+class DootWidgetGridTest {
+
+ private fun tomorrowEvent(startIso: String, endIso: String): WidgetItem = WidgetItem(
+ id = "tmrw", title = "Tomorrow Event", source = "calendar", type = "event",
+ start = startIso, end = endIso
+ )
+
+ @Test
+ fun `calcGridStart on an unfiltered mixed list is skewed by tomorrow's event hour`() {
+ // Documents why WidgetRoot MUST pre-filter to today-only events before calling
+ // this function: it has no date awareness, only hour-of-day. "now" is 22:00
+ // today (2026-07-12); the only item is tomorrow's (2026-07-13) 10:00 event.
+ val mixedList = listOf(tomorrowEvent("2026-07-13T10:00:00Z", "2026-07-13T14:30:00Z"))
+ assertEquals(9, calcGridStart(mixedList, nowHour = 22))
+ }
+
+ @Test
+ fun `calcGridStart on the correctly today-filtered (empty) list falls back to nowHour`() {
+ val gridStart = calcGridStart(emptyList(), nowHour = 22)
+ assertEquals(21, gridStart)
+ }
+
+ @Test
+ fun `calcGridEnd falls back to nowHour plus eight when no today events, capped at 23`() {
+ val gridEnd = calcGridEnd(emptyList(), nowHour = 22)
+ assertEquals(23, gridEnd)
+ }
+}