feat: fraction colour for two-tone amounts - #6
Draft
IgnacioNavarro wants to merge 1 commit into
Draft
Conversation
A balance is commonly drawn with its decimals dimmed so the figure that matters reads first. `fractionColor` colours the fraction span — the decimal separator, the digits after it, and any trailing affix — leaving the rest in the `style` colour. Omitted, nothing changes. The span is read from the formatted string rather than from the value, so it lands on the separator the locale actually drew, and a format with no fraction digits dims only a trailing affix if there is one. Both renderers keep the transition intact rather than working around it: Android draws the line into one white raster and tints it at composite time, so a colour is a property of the draw and not of the bitmap. The second colour is a second PorterDuffColorFilter chosen per keyed slice. Settled and transitioning frames share one draw path, so both pick it up, and the fraction colour joins the RenderNode cache key because the tint is recorded into the display list. iOS concatenates two Text runs. `.numericText()` is closed, but `Text + Text` is still one Text, so its raster simply carries two coloured runs and the transition is untouched. Two sibling views would not survive: each would rasterise and transition on its own and they would drift apart on any change that moves the decimal point. The key predicate moves to TransitionLogic, next to the encoding it reads, with unit tests over the span it selects.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A balance is commonly drawn with its decimals dimmed, so the figure that matters reads first. This adds
fractionColor, a second colour for the fraction span — the decimal separator, the digits after it, and any trailing affix.Omit the prop and the number is one colour, exactly as before. No existing behaviour changes.
The span
Read from the formatted string rather than from the value, so it lands on the separator the locale actually drew —
1.234,56 €dims,56 €. A format with no fraction digits dims only a trailing affix, if there is one. The two platforms are deliberately given the same rule.Android
The line is rasterised white and tinted at composite time, so a colour is a property of the draw rather than of the bitmap — which means a second one costs nothing but choosing a different
PorterDuffColorFilterper keyed slice. BecauseonDrawroutes everything throughdrawRolling, settled and transitioning frames pick it up alike, so there is no second code path to keep in sync.The fraction colour joins the
RenderNodecache key, since the tint is recorded into the display list.isFractionKeymoved toTransitionLogic— it reads the key encodinglayoutKeyedSlotsassigns, so it belongs beside it, and that makes it directly testable.FractionSpanTestcovers the span it selects (separator + decimals, integer left alone, trailing affix included, leading currency symbol excluded) plus the predicate itself.iOS
Two concatenated
Textruns.Your own comments establish that
.numericText()is closed — SwiftUI rasterises once per value and animates the raster, with no CALayer per digit and nothing per glyph to reach into. That rules out the obvious approaches, but not this one:Text + Textis still oneText, so the raster it produces simply carries two coloured runs and the transition is unaffected.Two sibling views would not survive — each would rasterise and transition independently, and they would drift apart on any change that moves the decimal point. The concatenation is what keeps it a single transition.
foregroundStyleon 17+,foregroundColorbelow, so the colour still applies where the transition itself does not.Verification
Honest about this: I've run neither the example app nor the native test suites here — the change came out of using the library, and I can't currently build both platforms. What I have done is follow the existing structure closely and keep the diff narrow.
The Android mechanism is in production use via a local patch of this same change, on a real balance screen, so the per-slice tint and the cache-key interaction are exercised. The iOS concatenation is the approach I'm already using in a hand-rolled SwiftUI numeric text in the same app, so the "concatenation survives numericText" claim is from observation rather than theory — but not in this codebase, which is why this is a draft.
Happy to adjust naming (
fractionColorvsfractionStyle), the span definition, or anything else that doesn't fit how you'd like this to work.