Files
Copilot ca986f1e8e Fix widget todo list time display for sub-hour due dates (#4359)
## Summary

Widget todo items due within 1 hour displayed as "in 1 hour" due to
`RelativeDateTimeFormatter` rounding. Now shows minute precision ("in 15
minutes", "in 30 minutes") for better time awareness with full
localization support.

**Implementation:**
- Added `DateComponentsFormatter` for minute-level formatting
- Enhanced `dueDisplay` to detect `abs(timeInterval) < 3600`
- Checks `abs(timeInterval) < 60` directly for "Now" threshold before
calculating minutes
- Uses `ceil()` for future times and `floor()` for past times to avoid
rounding boundary issues
- Displays localized strings via `L10n.Widgets.TodoList.DueDate.now`,
`.inFormat()`, and `.agoFormat()`
- Preserves existing formatter for ≥1 hour durations

**Localization:**
- Added 3 new localization strings to all 34 locale files (English
placeholders for translation team)
- Updated `Strings.swift` with corresponding L10n accessor functions
- All time displays now properly localized via `L10n` infrastructure

**Code Quality:**
- Made `dueDisplay` internal (not private) for testability via
`@testable import`
- Restored family-based widget row spacing logic that was accidentally
removed
- Fixed accessibility issues by replacing `.hidden()` and `.overlay()`
patterns with proper conditional rendering
- Tests made locale-agnostic using helper methods that generate expected
strings with same formatter

**Testing:**
- Added `WidgetTodoListViewTests.swift` with comprehensive coverage for
all time ranges
- Tests validate behavior for items due in 15, 30, 45 minutes, 1 minute,
<1 minute, overdue items, and >1 hour items
- Tests use same `DateComponentsFormatter` and L10n functions as
implementation for locale independence

## Screenshots
N/A - Text-only change

## Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#

## Any other notes
Uses `DateComponentsFormatter.allowedUnits = [.minute]` for proper
localization. English placeholder strings have been added to all 34
locale files for the translation team to localize. The implementation
ensures consistent formatting across all supported languages using the
iOS localization system.

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> The widget To-Do List shows items with due dates less than 1 hour as
"in 1 hour" where it should display the time in minutes (e.g., "in x
minutes"). The issue lies in the `dueDisplay` method in the
`WidgetTodoListView` struct (file path:
`Sources/Extensions/Widgets/TodoList/WidgetTodoListView.swift`).
Specifically, this function uses the `numericRelativeFormatter` but does
not account for cases where the remaining due time is less than 1 hour.
> 
> The `numericRelativeFormatter` is currently used in the following
block:
> ```swift
> if item.hasDueTime {
> let text = Self.numericRelativeFormatter.localizedString(for: due,
relativeTo: now)
> return DueDisplay(text: capitalizeLeadingCharacter(in: text),
isPastDateOnly: false)
> }
> ```
> This produces a generic "in 1 hour" string for times under an hour. To
fix this, we need to enhance the logic to check if the remaining time is
less than 1 hour. If so, explicitly calculate and display the remaining
minutes using custom logic.
> 
> ### Proposed Fix:
> 1. Modify the `dueDisplay` method to check if the due time difference
is less than 1 hour.
> 2. If the remaining time is below one hour, calculate the difference
in minutes and format it as "in x minutes."
> 3. Otherwise, use the `numericRelativeFormatter` as before.
> 
> ### Resources for the Fix:
> - `DateComponentsFormatter` for better control over minute formatting.
> - Update the logic in the `dueDisplay` method to handle the special
case explicitly.
> 
> ### Testing
> - Add unit tests or predefined timelines with entries for due dates at
15, 30, and 45 minutes to confirm the enhanced functionality is applied
correctly.


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/home-assistant/iOS/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-17 16:16:13 +01:00
..