fix(ux): focus regression, keyboard room switching, and a filter that erased itself - #287
Merged
Conversation
#285 gave the base button `color_focus: RBX_FOCUS_TINT`, but that token is an opaque `#0E8C9E` and the shader replaces the fill outright: fill = color_fill.mix(color_fill_focus, self.focus) At focus=1.0 the fill *is* the tint. Buttons that carry their own background were unaffected, which is why this got through review — but the ghost variants, whose `color` is transparent, turned into a solid accent block with a grey icon on it. Inverted, not outlined. Those are the composer tool buttons and the per-message copy button: the two highest-traffic controls in the app. The base now focuses to `RBX_ACCENT_SOFT`, a wash rather than a repaint. The token keeps its opaque value on purpose; making *it* translucent would let the page show through the solid variants instead. The four semantic variants get an explicit `color_focus` equal to their own fill. Left to inherit, a green confirm or a red destructive button would have washed teal on focus and lost the colour that identifies it — they already draw a border, so `border_color_focus` carries the signal for them.
Typing a room name and pressing Enter did nothing. The results list had no concept of a selection — items only responded to `click_button.clicked` — so switching rooms, the highest-frequency action in the client, always ended at the mouse. Arrow keys move a selection, Enter opens it, and the selected row is tinted so the keys are not aiming blind. Keys are claimed in `Event::KeyDown` rather than through a `Hit`: focus stays in the query field while typing, so the list never receives hits of its own. Only Up/Down/Return are taken; every other key still reaches the field. Selection is clamped at the ends instead of wrapping — holding an arrow should come to rest on the first or last result, not cycle — and resets whenever the result set changes, since index 3 of the previous query has nothing to do with index 3 of this one. The highlight is an Animator over a shader instance, not `script_apply_eval!`, which does nothing on widgets built from a FlatList template (pitfall #40). Both animator states are written on every frame: rows are reused by index, so writing only `on` would leave the old row highlighted after the selection moved.
Typing a room name that matched nothing brought the entire room list back while the query was still sitting in the box — the filter looked broken at the moment it was working correctly. `update_displayed_rooms` cleared `display_filter` and regenerated whenever every category came back empty. That also made the "no matching rooms" status unreachable: by the time `update_status` ran, `display_filter` was already None, so the count fell into the unfiltered arm. The fallback dates from "improve people lookup and fallback empty local filters", when the sidebar filter and people search shared a path. They no longer do: the sidebar list is driven by `MainFilterAction`, while people results (`RoomFilterResultTarget::RemoteUser`) are rendered by the quick switcher modal, a separate surface with its own list. Nothing depends on the sidebar staying populated. Note the newly reachable status string is English, like the five siblings it sits with — this file has no i18n at all yet, so the line is no more English than before. Worth its own change.
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.
Three unrelated UX problems, one commit each so they can be judged separately.
1. Keyboard focus repainted ghost buttons solid — regression from #285
#285 gave the base button
color_focus: RBX_FOCUS_TINT, but that token is an opaque#0E8C9Eand the shader replaces the fill outright:At
focus = 1.0the fill is the tint. Buttons carrying their own background were unaffected — which is why it got past review — but the ghost variants, whosecoloris transparent, became a solid accent block with a grey icon on it. Inverted, not outlined. Those are the composer tool buttons and the per-message copy button.The base now focuses to
RBX_ACCENT_SOFT. The token keeps its opaque value deliberately: making it translucent would let the page show through the solid variants instead.The four semantic variants get an explicit
color_focusequal to their own fill — left to inherit, a green confirm or red destructive button would wash teal on focus and lose the colour that identifies it. They already draw a border, soborder_color_focuscarries the signal for them.2. The room quick switcher could not be driven by keyboard
Type a room name, press Enter, nothing happens. The results list had no concept of a selection — items only answered
click_button.clicked— so switching rooms, the most frequent action in the client, always ended at the mouse.Arrow keys move a selection, Enter opens it, and the selected row is tinted so the keys are not aiming blind.
Event::KeyDown, not via aHit: focus stays in the query field while typing, so the list never receives hits of its own. Only Up/Down/Return are taken.script_apply_eval!, which does nothing on FlatList template widgets (pitfall docs: add deployment guide for Robrix + Palpo + Octos #40). Both animator states are written every frame: rows are reused by index, so writing onlyonwould strand the highlight on the old row.3. A filter matching nothing brought the whole list back
Typing a room name that matched nothing restored the entire room list while the query was still in the box — the filter looked broken at the moment it was working.
update_displayed_roomscleareddisplay_filterand regenerated whenever every category came back empty. That also made the "no matching rooms" status unreachable:display_filterwas alreadyNoneby the timeupdate_statusran, so the count fell into the unfiltered arm.Why removing it is safe. The fallback dates from
73a27561 fix(search): improve people lookup and fallback empty local filters, when the sidebar filter and people search shared a path. They no longer do — the sidebar list is driven byMainFilterAction, while people results (RoomFilterResultTarget::RemoteUser) render in the quick switcher modal, a separate surface with its own list. Nothing depends on the sidebar staying populated.One consequence worth naming: the newly reachable status string is English, like the five siblings it sits with. That file has no i18n at all yet, so the line is no more English than before — but it deserves its own change.
Testing
cargo test --lib --features agent_chat— 593 pass.typos src/clean. Ran the app and confirmed no new runtime DSL/shader errors in the log, which is where a mistyped token or shader field surfaces (cargo checkcannot see them).By hand: Tab onto the copy and composer buttons gives a wash, not a block; green and red buttons keep their colour and gain a ring; the switcher moves with arrows, opens on Enter, clamps at both ends, and resets to the first row on a new query; a non-matching filter now leaves the list empty with "No matching rooms found".