From d826bf5e9561a8c66a2c52bb1c2a3835fc6de32c Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Mon, 29 Jun 2026 09:39:06 +0000 Subject: feat: show tomorrow section in widget; note web view Widget now renders a TOMORROW block below the today grid: events with inline time labels (slightly dimmed) and task rows. Separated by a divider. Covers both explicit-start tomorrow items and slot-packed fragments that overflow from today. Web view: TODO comment to flatten the tomorrow section to match widget. Co-Authored-By: Claude Sonnet 4.6 --- .../java/org/terst/doot/widget/ui/DootWidget.kt | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'android/app/src') 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 5d27fb8..0331928 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 @@ -72,6 +72,13 @@ fun WidgetRoot(items: List, now: Instant) { val gridStart = calcGridStart(scheduledEvents, nowZoned.hour) val gridEnd = calcGridEnd(scheduledEvents, nowZoned.hour) + val tomorrowStart = nowZoned.toLocalDate().plusDays(1).atStartOfDay(zone).toInstant() + val tomorrowEnd = tomorrowStart.plus(1, ChronoUnit.DAYS) + val tomorrowItems = scheduledEvents + .filter { Instant.parse(it.start!!) >= tomorrowStart && Instant.parse(it.start!!) < tomorrowEnd } + val tomorrowFrags = fragments + .filter { it.startTime >= tomorrowStart && it.startTime < tomorrowEnd } + Column( modifier = GlanceModifier .fillMaxSize() @@ -92,6 +99,10 @@ fun WidgetRoot(items: List, now: Instant) { for (hour in gridStart..gridEnd) { HourRow(hour, nowZoned, scheduledEvents, fragments, zone) } + + if (tomorrowItems.isNotEmpty() || tomorrowFrags.any { it.slots.isNotEmpty() }) { + TomorrowSection(tomorrowItems, tomorrowFrags, zone) + } } } @@ -256,6 +267,64 @@ fun TaskRow(task: WidgetItem) { } } +@Composable +fun TomorrowSection(items: List, fragments: List, zone: ZoneId) { + Box(modifier = GlanceModifier.fillMaxWidth().height(1.dp).padding(vertical = 4.dp).background(Color(0x1AFFFFFF))) {} + + Row(modifier = GlanceModifier.fillMaxWidth().padding(top = 6.dp, bottom = 2.dp)) { + Text( + "TOMORROW", + style = TextStyle( + color = ColorProvider(Color(0x66FFFFFF)), + fontSize = 11.sp, + fontWeight = FontWeight.Bold + ) + ) + } + + items.forEach { item -> + val isPast = false + if (item.type == "event") { + TomorrowEventRow(item, zone) + } else { + TaskRow(item) + } + } + + fragments.forEach { frag -> + frag.slots.forEach { slot -> TaskRow(slot.task) } + } +} + +@Composable +fun TomorrowEventRow(event: WidgetItem, zone: ZoneId) { + val color = sourceColor(event.source) + val timeLabel = event.start?.let { + val t = Instant.parse(it).atZone(zone) + hourLabel(t.hour) + if (t.minute > 0) t.minute.toString().padStart(2, '0') else "" + } ?: "" + Row( + modifier = GlanceModifier + .fillMaxWidth() + .padding(vertical = 3.dp) + .clickable(actionStartActivity(Intent(Intent.ACTION_VIEW, android.net.Uri.parse(event.url.ifEmpty { "https://calendar.google.com" })))), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = timeLabel, + style = TextStyle(color = ColorProvider(Color(0x4DFFFFFF)), fontSize = 10.sp), + modifier = GlanceModifier.width(32.dp) + ) + Box(modifier = GlanceModifier.width(3.dp).height(16.dp).background(color)) {} + Text( + text = event.title, + style = TextStyle(color = ColorProvider(Color.White.copy(alpha = 0.75f)), fontSize = 13.sp), + modifier = GlanceModifier.padding(start = 8.dp), + maxLines = 1 + ) + } +} + private fun hourLabel(hour: Int): String = when { hour == 0 -> "12a" hour < 12 -> "${hour}a" -- cgit v1.2.3