Dashboard live trio no longer wraps large grid-import values onto two lines.
trioValueCompact typography variant (22 pt vs the regular 26 pt) is selected when the numeric value runs past four characters; values under 10 kW are unchanged..lineLimit(1) on the value Text guarantees it can never wrap, even for unexpected widths or custom fonts.Ready to push
A focused, low-risk UI fix. Three parallel review agents (reuse, quality, efficiency) found nothing to consolidate, no efficiency regression, and confirmed the threshold logic matches the intended behaviour. The one nit raised — a comment that under-described the trigger range — was fixed in this review. Build succeeds and the two edited files lint clean.
738d0f3 [bug]: shrink Dashboard trio value font for large grid values The Dashboard shows three little columns at a glance: Solar, House, and Grid. Each shows a number and a unit (like 11.51 kW). When the grid number got big enough to have five characters (anything 10 kW or more), it was too wide for its column and the last digit dropped onto a second line, which looked broken.
It's a visual glitch on the app's main screen — the first thing you see. The fix makes the number a bit smaller only when it's long, so it always stays on one tidy line.
LiveTrioPanel.column(...) formats the wattage via PowerFormatting.split, which returns a (value, unit) pair — e.g. ("11.51", "kW") for ≥ 1 kW, ("950", "W") below 1 kW. The value and unit render as two adjacent Text views in a firstTextBaseline HStack.
The fix selects the font by the formatted value's character count: (parts?.value.count ?? 0) > 4 ? trioValueCompact : trioValue. Because split formats kW with %.2f, anything ≥ 10 kW is exactly five characters, which is the natural boundary for "regular under 10 kW, smaller above." A new FluxTheme.Typography.trioValueCompact mirrors trioValue (same medium weight, monospaced digits) at 22 pt. .lineLimit(1) is a belt-and-braces guard against wrapping.
The threshold is coupled to the formatter's output shape rather than the underlying magnitude. That's acceptable here — both live in tightly-related code and the relationship is documented in a comment — but a magnitude-based predicate would be marginally less brittle if the formatter ever changed precision.
The selection is computed once per render in the view body as a stored function reference (FluxTheme.Typography.trioValueCompact is a (String?) -> Font), then resolved by AppFontModifier against the appFontFamily environment value. AppFontResolver.resolve caches font-availability lookups per family, so switching between the 22 pt and 26 pt variants across the 10 s auto-refresh cycle is a constant-cost cache hit plus a SwiftUI Font construction — no regression versus the prior unconditional trioValue.
abs() is applied upstream (watts.map(PowerFormatting.split) receives abs(pgrid) for the grid column), so no minus sign ever inflates the character count..lineLimit(1) sits only on the value Text; the unit ("kW"/"W", fixed 11 pt) is small enough that the compact value keeps the pair within the column width, so the unit needs no explicit limit.Fully implemented: the requested behaviour (regular < 10 kW, slightly smaller ≥ 10 kW, no wrapping). Partial/missing: none for the stated scope. No spec exists for this panel; this is a standalone visual bugfix.
LiveTrioPanel.swift
Why it matters. User-visible fix on the app's primary screen; prevents the grid value wrapping to two lines at ≥ 10 kW. Applies to all three columns for consistency.
What to look at. LiveTrioPanel.swift:60-65, 79-82
FluxTheme.swift
Why it matters. Adds the 22 pt variant the panel switches to, keeping all sizing in the central typography enum rather than as an inline magic number at the call site.
What to look at. FluxTheme.swift:109-115
The user requested a discrete "regular under 10 kW, smaller above" behaviour. Because PowerFormatting.split formats kW with %.2f, the value is exactly five characters at and above 10 kW, so a length test of > 4 maps cleanly to the requested boundary and reads simply. The coupling to the formatter's output is documented inline.
A ~15% reduction from the regular 26 pt — "a little smaller" as requested — verified to fit "11.51 kW" within the iPhone column width while staying close to the regular size. Same medium weight and monospaced digits as trioValue.
The shared column(...) helper renders Solar, House, and Grid identically, so the rule naturally covers any column crossing 10 kW. This matches the project's data/visual-consistency principle that a value shown in multiple places should behave the same everywhere.
| Severity | Area | Finding | Resolution |
|---|---|---|---|
| minor | LiveTrioPanel.swift / FluxTheme.swift comments | The explanatory comment cited "11.51" as the trigger example, which under-described the actual range — the > 4 rule fires for the whole ≥ 10 kW range (e.g. "10.00" is also 5 chars). | Reworded both comments to state that values ≥ 10 kW render five characters, with "10.00"/"11.51" as examples. |
| minor | code reuse | Considered whether an existing shrink-to-fit mechanism (minimumScaleFactor / ViewThatFits) or a shared renderer (PowerTrioColumns, DashboardHeroPanel) should be reused instead. | None applies: LiveTrioPanel is the only caller of PowerFormatting.split, no length-aware font pattern exists in the app, and the widget trio uses the combined PowerFormatting.format. The localized fix is correct. |
| minor | efficiency | Checked whether per-render font selection on the 10 s refresh hot path adds cost. | No regression — AppFontResolver caches availability per family; the selection is O(1) and the compact path costs the same as the prior unconditional resolve. |
Click to expand.
diff --git a/Flux/Flux/Dashboard/LiveTrioPanel.swift b/Flux/Flux/Dashboard/LiveTrioPanel.swiftindex 0e4e3eb..fcb5bbf 100644--- a/Flux/Flux/Dashboard/LiveTrioPanel.swift+++ b/Flux/Flux/Dashboard/LiveTrioPanel.swift@@ -58,6 +58,13 @@ struct LiveTrioPanel: View { showsLeftDivider: Bool ) -> some View { let parts = watts.map(PowerFormatting.split)+ // Drop to a slightly smaller value font once the numeric portion runs+ // past four characters — values ≥ 10 kW render five characters+ // (e.g. "10.00", "11.51") — so the value plus unit stays on one line+ // instead of wrapping in the column.+ let valueFont = (parts?.value.count ?? 0) > 4+ ? FluxTheme.Typography.trioValueCompact+ : FluxTheme.Typography.trioValue HStack(spacing: 0) { if showsLeftDivider { Rectangle()@@ -71,8 +78,9 @@ struct LiveTrioPanel: View { .foregroundStyle(FluxTheme.Palette.tertiaryText) HStack(alignment: .firstTextBaseline, spacing: 2) { Text(parts?.value ?? "—")- .appFont(FluxTheme.Typography.trioValue)+ .appFont(valueFont) .foregroundStyle(valueColor)+ .lineLimit(1) Text(parts?.unit ?? "kW") .appFont(FluxTheme.Typography.trioUnit) .foregroundStyle(FluxTheme.Palette.tertiaryText)
diff --git a/Flux/Flux/Helpers/FluxTheme.swift b/Flux/Flux/Helpers/FluxTheme.swiftindex 4861365..eba175d 100644--- a/Flux/Flux/Helpers/FluxTheme.swift+++ b/Flux/Flux/Helpers/FluxTheme.swift@@ -106,6 +106,13 @@ enum FluxTheme { nonisolated static func trioValue(family: String?) -> Font { AppFontResolver.resolve(size: 26, weight: .medium, family: family).monospacedDigit() }+ /// Slightly smaller trio value used when the numeric portion runs long+ /// (values ≥ 10 kW render five characters, e.g. "10.00", "11.51"), so+ /// the value plus its unit fits on one line instead of wrapping in the+ /// column.+ nonisolated static func trioValueCompact(family: String?) -> Font {+ AppFontResolver.resolve(size: 22, weight: .medium, family: family).monospacedDigit()+ } nonisolated static func trioUnit(family: String?) -> Font { AppFontResolver.resolve(size: 11, weight: .regular, family: family) }
diff --git a/CHANGELOG.md b/CHANGELOG.mdindex 354ecab..9dd398c 100644--- a/CHANGELOG.md+++ b/CHANGELOG.md@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [Unreleased]++### Fixed++- **Dashboard live trio no longer wraps large grid values.** When grid import (or any Solar/House/Grid column) reached 10 kW or more, the value rendered "11.51 kW" with the trailing digit wrapping onto a second line. The numeric value now drops to a slightly smaller font (22 pt instead of 26 pt) once it runs past four characters, keeping the value and unit on one line; values under 10 kW are unchanged.+ ## [1.4] - 2026-05-31 ### Added
DashboardViewModelTests.refreshSkipsWhenAlreadyLoading failed on one suite run and passed on others. It is a timing-dependent async test (relies on an 80 ms in-flight window) and passes in isolation. Unrelated to this font-only change, but worth de-flaking separately.