From 3e8ad60431d6cc783f9f7c555bfde5db54ebec75 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Wed, 12 Aug 2026 07:57:51 +0000 Subject: Fix tomorrow's task rows: color and alignment vs tomorrow's events TaskRow always used textPrimary for its title, while tomorrow's timed events (TimeLabeledEventRow) are deliberately de-emphasized with textSecondary -- tomorrow's tasks now match. TaskRow also had no leading gutter of its own outside the hourly grid (where HourRow's hour-label column supplies it externally), so in TomorrowSection its title landed at a variable offset depending on checkbox/dot size and hideCheckboxes, instead of the fixed 32dp gutter AllDayRow and TimeLabeledEventRow use there. Added optional titleColor/gutterWidth params to TaskRow (both default to prior grid behavior) and set them from TomorrowSection. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017GMEkHeqKz6FLkmizowBTK --- .../java/org/terst/doot/widget/ui/WidgetRows.kt | 105 +++++++++++++++------ 1 file changed, 74 insertions(+), 31 deletions(-) diff --git a/android/app/src/main/java/org/terst/doot/widget/ui/WidgetRows.kt b/android/app/src/main/java/org/terst/doot/widget/ui/WidgetRows.kt index 8ac1f91..a5e9d26 100644 --- a/android/app/src/main/java/org/terst/doot/widget/ui/WidgetRows.kt +++ b/android/app/src/main/java/org/terst/doot/widget/ui/WidgetRows.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.net.Uri import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.glance.* import androidx.glance.action.actionParametersOf @@ -300,7 +301,20 @@ fun TaskFragmentBlock(fragment: TaskFragment, textSize: WidgetTextSize, palette: } @Composable -fun TaskRow(task: WidgetItem, textSize: WidgetTextSize, palette: WidgetPalette, hideCheckboxes: Boolean = false) { +fun TaskRow( + task: WidgetItem, + textSize: WidgetTextSize, + palette: WidgetPalette, + hideCheckboxes: Boolean = false, + titleColor: Color = palette.textPrimary, + // Null (default) preserves the grid's existing behavior, where HourRow's own + // hour-label column already supplies the 32dp gutter externally and this row + // starts flush at the Column edge. TomorrowSection passes 32.dp so its task + // rows reserve the same leading width as AllDayRow's Spacer(32.dp) and + // TimeLabeledEventRow's width(32.dp) time label, keeping titles aligned with + // tomorrow's events regardless of hideCheckboxes/completable/dot sizing. + gutterWidth: Dp? = null +) { val context = LocalContext.current val detailIntent = Intent(context, TaskDetailActivity::class.java).apply { putExtra(TaskDetailActivity.EXTRA_ID, task.id) @@ -316,7 +330,12 @@ fun TaskRow(task: WidgetItem, textSize: WidgetTextSize, palette: WidgetPalette, Row( modifier = GlanceModifier .fillMaxWidth() - .padding(horizontal = 8.dp, vertical = 5.dp), + .padding( + start = if (gutterWidth != null) 0.dp else 8.dp, + end = 8.dp, + top = 5.dp, + bottom = 5.dp + ), verticalAlignment = Alignment.CenterVertically ) { // Suppressing checkboxes drops this leading element entirely rather than just @@ -325,36 +344,50 @@ fun TaskRow(task: WidgetItem, textSize: WidgetTextSize, palette: WidgetPalette, // task titles land flush with event titles instead of offset by unused space. // Tradeoff: tap-to-complete-from-the-widget goes with it (TaskDetailActivity's // Complete button still works), which is what "so everything lines up" implies. - if (!hideCheckboxes) { - if (task.completable) { - Box( - modifier = GlanceModifier - .size(24.dp) - .clickable( - actionRunCallback( - actionParametersOf( - CompleteTaskAction.idKey to task.id, - CompleteTaskAction.sourceKey to task.source + // + // When gutterWidth is set (TomorrowSection), that reasoning doesn't apply -- + // the row it's aligning against (TimeLabeledEventRow) always reserves a fixed + // 32dp leading width whether or not there's a visible label there, so this + // leading slot is reserved too, checkboxes shown or not. + val leadingContent: @Composable () -> Unit = { + if (!hideCheckboxes) { + if (task.completable) { + Box( + modifier = GlanceModifier + .size(24.dp) + .clickable( + actionRunCallback( + actionParametersOf( + CompleteTaskAction.idKey to task.id, + CompleteTaskAction.sourceKey to task.source + ) ) - ) - ), - contentAlignment = Alignment.Center - ) { - Image( - provider = ImageProvider(org.terst.doot.widget.R.drawable.ic_checkbox_empty), - contentDescription = "Complete ${task.title}", - colorFilter = ColorFilter.tint(ColorProvider(palette.textSecondary)), - modifier = GlanceModifier.size(14.dp) - ) + ), + contentAlignment = Alignment.Center + ) { + Image( + provider = ImageProvider(org.terst.doot.widget.R.drawable.ic_checkbox_empty), + contentDescription = "Complete ${task.title}", + colorFilter = ColorFilter.tint(ColorProvider(palette.textSecondary)), + modifier = GlanceModifier.size(14.dp) + ) + } + } else { + Box( + modifier = GlanceModifier + .size(8.dp) + .background(palette.textMuted) + ) {} } - } else { - Box( - modifier = GlanceModifier - .size(8.dp) - .background(palette.textMuted) - ) {} } } + if (gutterWidth != null) { + Box(modifier = GlanceModifier.width(gutterWidth), contentAlignment = Alignment.CenterStart) { + leadingContent() + } + } else { + leadingContent() + } if (task.projectColor != null) { Box( @@ -375,7 +408,7 @@ fun TaskRow(task: WidgetItem, textSize: WidgetTextSize, palette: WidgetPalette, ShadowedText( text = task.title, style = TextStyle( - color = ColorProvider(palette.textPrimary), + color = ColorProvider(titleColor), fontSize = textSize.scaledContentSize(14), fontWeight = textSize.scaledContentWeight(FontWeight.Normal) ), @@ -457,12 +490,22 @@ fun TomorrowSection( if (item.type == "event") { TimeLabeledEventRow(item, zone, textSize, palette, titleColor = palette.textSecondary) } else { - TaskRow(item, textSize, palette, hideCheckboxes) + TaskRow( + item, textSize, palette, hideCheckboxes, + titleColor = palette.textSecondary, + gutterWidth = 32.dp + ) } } fragments.forEach { frag -> - frag.slots.forEach { slot -> TaskRow(slot.task, textSize, palette, hideCheckboxes) } + frag.slots.forEach { slot -> + TaskRow( + slot.task, textSize, palette, hideCheckboxes, + titleColor = palette.textSecondary, + gutterWidth = 32.dp + ) + } } } } -- cgit v1.2.3