116 lines
6.6 KiB
Markdown
116 lines
6.6 KiB
Markdown
# iris: known problems and things still to build
|
|
|
|
Iris's own list for the library, recorded 2026-09-04 in her words where it
|
|
matters, so the work in RUST.md picks these up in a sensible order rather
|
|
than rediscovering them. Each item says where it sits in the order and
|
|
what "done" looks like.
|
|
|
|
**Only open items live here.** An item is deleted when it lands, not
|
|
ticked: a list of finished work is context every future session pays for,
|
|
and what a change did belongs at the code it changed. Fifty closed items
|
|
and six phone-report sections went on 2026-09-08 for that reason.
|
|
|
|
## Fix
|
|
|
|
- [ ] **Colours are not in a defined colour space. Fix this before a
|
|
styling pass.** Both render backends prefer an sRGB surface
|
|
(`default/render.rs` and `android/render.rs`), while `fs_main` returns
|
|
`unpack4x8unorm` palette and image bytes unchanged. An sRGB attachment
|
|
treats those values as linear and encodes them again: Mocha Crust
|
|
(17,17,27) became (73,73,91) in a desktop screenshot measured on
|
|
2026-09-06.
|
|
|
|
The earlier entry called this desktop-only because the Android picture
|
|
looked right. That was not a measurement: neither the startup line nor
|
|
the diagnostics report records the selected surface format, and the
|
|
Android backend contains the identical preference and shader path. A
|
|
device exposing only a non-sRGB surface can happen to hide the bug; it
|
|
does not make the pipeline correct.
|
|
|
|
Done means defining one convention for palette bytes, decoded images,
|
|
colour emoji and the clear colour, then converting exactly once for the
|
|
selected target. Record the selected format in diagnostics, and add a GPU
|
|
test that draws known non-black, non-white pixels into an sRGB target and
|
|
reads the stored bytes back; screenshots from desktop and Android then
|
|
confirm the same Catppuccin values rather than serving as the definition.
|
|
## Build (for the port)
|
|
|
|
Widgets `RUST.md`'s "The port, in order (decided 2026-09-05)" needs and
|
|
iris does not have yet, one entry per gap, named against the P-step that
|
|
first needs it. Move an entry up to "Fix" if it becomes a current defect;
|
|
delete it once built rather than duplicating it there.
|
|
|
|
- [ ] **Selectable, read-only text.** P0's report and P1's transcript rows
|
|
use `TextEdit` because `Selectable` is implemented only for it. That
|
|
makes prose focusable and opens the IME over text that cannot be edited.
|
|
A display widget needs the same selection geometry and clipboard path
|
|
without a text-input accessibility role or keyboard focus.
|
|
- [ ] **Overflow ellipsis with an explicit retained end.** `TextAttrs` can
|
|
only wrap or clip, so a tool summary is cut with no mark. Parley has no
|
|
ellipsis primitive; use its line breaker to find the cut, but keep source
|
|
and displayed strings distinct with one byte mapping shared by spans,
|
|
links, selection and editing. Replace `wrap: bool` with an enum that can
|
|
say wrap, clip, head ellipsis and tail ellipsis—the caller must choose
|
|
because a command is identified by its head and a path by its tail.
|
|
- [ ] **Expose the distance from a `LazySpan` viewport to its unloaded
|
|
edge.** (**P1**.) `viewport_len` and the visible extents are already
|
|
measured internally, but a paging caller cannot ask whether it is within
|
|
the Compose app's six-viewport `HISTORY_SCREENS` cushion. The API should
|
|
answer in pixels or viewport multiples, never rows: a row ranges from one
|
|
line to a screen, so a fixed row count is not a distance.
|
|
- [ ] **Let an image fit a bounded box while preserving its aspect ratio.**
|
|
(**P1**.) `Image` currently always reports and draws the decoded texture's
|
|
natural pixel size. Decoding and fetching a server-produced attachment
|
|
belong in `app-rust`; iris only owes the generic fit/scale widget used to
|
|
draw its thumbnail.
|
|
- [ ] **Per-range backgrounds for rich text.** (**P1**.) Inline code is
|
|
already monospace and coloured, but matching Compose's chip also needs
|
|
the glyph run's boxes so a surface can be drawn behind exactly that byte
|
|
range. `TextEdit` already computes the same geometry internally for its
|
|
selection highlight; expose one shared primitive rather than giving the
|
|
app a second text-layout path.
|
|
- [ ] **A modal/dialog primitive.** (**P1**, reused by **P3** and
|
|
**P5**.) Needed for the session settings dialog, `UsageDialog`'s
|
|
equivalent, and the delete-with-`deleteForeign` confirmation with its
|
|
toggle switch. Build once, wherever it is first needed, rather than
|
|
once per screen that wants one.
|
|
- [ ] **A horizontal gauge/bar widget.** (**P1**.) For
|
|
`SessionUsageBar`'s equivalent — a bounded fill reflecting a fraction,
|
|
nothing fancier.
|
|
- [ ] **A toggle switch.** (**P3**.) For the delete dialog's
|
|
`deleteForeign` control; iris has no switch/checkbox widget yet as far
|
|
as this pass found.
|
|
|
|
## Later
|
|
|
|
- [ ] **Property/content animations.** Cosmetic, so after correctness and
|
|
parity. Keep them modular, like input; scrolling already animates through
|
|
`Widget::tick` and `UiData::animate`. A widget that does not opt in must
|
|
pay nothing and import nothing for them.
|
|
|
|
- [ ] **Remove `WidgetView` unless a real composite adopts it first.** The
|
|
layout change this decision was waiting for has landed. Every composite
|
|
in `app-rust/src/ui` now uses ordinary child handles plus a returned root;
|
|
`WidgetView` and its derive are used only by `iris/examples/view.rs`.
|
|
Today it demonstrates itself rather than shortening production code, so
|
|
deletion is the concrete default—not another parallel composition style.
|
|
|
|
- [ ] **A `Stack` that chooses its mask the way it chooses its size
|
|
(Iris, 2026-09-08).** She asked whether `masked_by` deserves to exist:
|
|
"a method that just does 2 separate things you can already easily do
|
|
does not deserve to exist." For a square-cornered surface it is indeed
|
|
redundant -- `.background(rect(BAR_FILL)).masked()` was measured
|
|
against `.masked_by(rect(BAR_FILL))` on the composer at the phone's own
|
|
size and density and the two are identical to the pixel. What the pair
|
|
cannot express is a clip that is not a box: `Painter::set_mask` writes
|
|
a `RectPrimitive::color(Color::NONE)` at the widget's own region, with
|
|
no radius, so `.background(rect(fill).radius(r)).masked()` draws a
|
|
rounded panel and then cuts its content square. Both other call sites
|
|
(`row.rs`'s fence, `tool.rs`'s raw output) are rounded, which is why
|
|
the method stands for now.
|
|
Let `Stack` name the mask child the way `StackSize::Child(n)` names the
|
|
sizing child. Then `.background(x)` remains the one way to add a surface
|
|
and clipping to it is a stack property; the named mask child must have
|
|
drawn before any child that uses it. Once that exists, delete
|
|
`masked_by` and `Masked::shape` rather than retaining two APIs.
|