Skip to content

fix(mobile): enlarge icon-only controls to a reliable tap target - #6338

Closed
iscekic wants to merge 1 commit into
mainfrom
kwf/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c
Closed

iscekic wants to merge 1 commit into
mainfrom
kwf/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c

Conversation

@iscekic

@iscekic iscekic commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Changelog for users

  • The Filter sessions, Rename organization, and Invite member icon controls now expose a tappable area at least 28dp on a side.
  • The active-filter count badge on Filter sessions still appears when filters are applied.
  • Pressing each control still opens the filter sheet, the rename sheet, or the invite screen as before.

Changelog for maintainers

  • New shared IconButton renders icon-only controls in a 32×32pt box with 8pt hitSlop, giving a 48pt effective target over the 28dp accessibility minimum and the 44pt DESIGN.md minimum.
  • SessionFilterButton, the organization hub rename pencil, and the members Invite member control now render through IconButton, with the icon centered in a 20pt inner box.
  • Previously these controls sized their accessibility node to the bare icon (20pt, 16pt, 22pt), which the accessibility check flagged as too small to tap.
  • Review apps/mobile/src/components/ui/icon-button.tsx first: confirm caller className merges after the default box and that any caller hitSlop override stays adequate.
  • Tests pin the box and tap-target minimums through a shared helper, and mounted tests cover each migrated control.
  • No schema, configuration, or translation changes.

E2E proof

[e2] Profile -> Organization: tap the pencil 'Rename organization' beside the organization name -> the rename sheet opens and saving a new name updates the row. — android (emulator-5604). One scripted scene from the personal Profile switched to the org ([seed:w4c-org-pair] e2e-org-owner-...), opened Manage organization, tapped the pencil, typed into 'Enter organization name' and tapped Save; e2-scene.log line 1 is 'SCENE e2 OK' and its post-save digest shows the hub header row 'android.view.View e2e-org-renamed tappable [111,167][1044,232]' where the seeded name was before (the DB row cd41b3f7-... became 'e2e-org-renamed', then I restored the 107-char seeded name in e2-restore.log so other shards are unaffected). Screenshot e2.png captured for the…

[e2] Profile -> Organization: tap the pencil 'Rename organization' beside the organization name -> the rename sheet opens and saving a new name updates the row. — prior/e2.png

Re-run the explorer's control-size scan on Agents, Organization (both entries) and Organization Members: no control under 28dp on a side is reported (previously Filter sessions 52x52px, Rename… — e5-org-members.png

[e5] Re-run the explorer's control-size scan on Agents, Organization (both entries) and Organization Members: no control under 28dp on a side is reported (previously Filter sessions 52x52px, Rename… — android (emulator-5604, density 2.625 -> 28dp = 73.5px). Scan of the four screens' a11y hierarchies (e5-agents.xml, e5-org-index.xml, e5-org-deeplink.xml, e5-org-members.xml) reports 'Filter sessions <-- scanned control 28dp-OK', 'Rename organization <-- scanned control 28dp-OK' (hub via profile entry and via the organization/ deep link) and 'Invite member <-- scanned control 28dp-OK', all measured 84x84px = 32.0x32.0dp, up from 52/42/57px; no icon control under 28dp. Screenshots e5-agents.png, e5-org-index.png, e5-org-deeplink.png, e5-org-members.png captured for the visual reviewer (not…

[e5] Re-run the explorer's control-size scan on Agents, Organization (both entries) and Organization Members: no control under 28dp on a side is reported (previously Filter sessions 52x52px, Rename… — prior/e5-org-index.png

[e5] Re-run the explorer's control-size scan on Agents, Organization (both entries) and Organization Members: no control under 28dp on a side is reported (previously Filter sessions 52x52px, Rename…

[e5] Re-run the explorer's control-size scan on Agents, Organization (both entries) and Organization Members: no control under 28dp on a side is reported (previously Filter sessions 52x52px, Rename… — prior/e5-org-deeplink.png

E2E proof — log excerpts

[e1] Open the organization deep-link entry (/(app)/(tabs)/(3_profile)/organizati -> pass :: Android emulator-5554: signed in as the org owner and switched context in Profile > account selector, opened the deep-link route and one script call reported 'SCENE e1 OK' with the rename sheet digest (Rename organization / Enter organization name / Cancel / Save) in e1-script.log; the control node content-desc="Rename organization" bounds="[914,372][998,456]" is 84x84px (32dp, above the 28dp minimum, up from the explorer's 42x42px) in e1-owner3-hierarchy.xml and e1-hub.log, the org-manage entry renders the same control at the same bounds in e1b-manage-hub.log, and the members Invite member control is 84x84px in e1-members.log; no UX defects observed.
/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c/e2e-mobile-app/e1-script.log
SCENE e1 OK
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.view.ViewGroup Rename organization tappable [55,270][1025,711]
android.widget.TextView Rename organization tappable [100,315][978,371]
android.widget.EditText Enter organization name tappable [100,408][978,513]
android.widget.Button Cancel tappable [625,550][806,665]
android.widget.TextView Cancel tappable [664,584][766,630]
android.widget.Button Save [833,550][979,665]
android.widget.TextView Save tappable [869,584][941,630]
/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c/e2e-mobile-app/e1-hub.log
android.widget.TextView Requests tappable [581,1069][998,1106]
android.widget.TextView 0 tappable [82,1189][499,1254]
android.widget.TextView Input Tokens tappable [82,1263][499,1300]
android.widget.TextView 0 tappable [581,1189][998,1254]
android.widget.TextView Output Tokens tappable [581,1263][998,1300]
android.widget.Button Members tappable [83,1383][997,1518]
android.widget.TextView Members tappable [189,1427][933,1473]
android.widget.Button Credit activity tappable [83,1518][997,1654]
android.widget.TextView Credit activity tappable [189,1562][933,1608]
android.widget.Button Invoices tappable [83,1653][997,1788]
android.widget.TextView Invoices tappable [189,1697][933,1743]
android.widget.Button Kilo Pass. Not subscribed tappable [83,1789][997,1933]
android.widget.TextView Kilo Pass tappable [189,1817][933,1863]
android.widget.TextView Not subscribed tappable [189,1867][933,1904]
android.widget.Button Low balance alert, Off tappable [83,1933][997,2075]
android.widget.TextView Low balance alert tappable [189,1961][933,2007]
android.widget.TextView Off tappable [189,2011][933,2048]
android.view.View Home, tab, 1 of 3 tappable [0,2195][360,2337]
android.widget.TextView HOME tappable [13,2281][347,2320]
android.view.View Agents, tab, 2 of 3 tappable [360,2195][720,2337]
android.widget.TextView AGENTS tappable [373,2281][707,2320]
android.view.View Profile, tab, 3 of 3 tappable [720,2195][1080,2337]
android.widget.TextView PROFILE tappable [733,2281][1067,2320]
/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c/e2e-mobile-app/e1b-manage-hub.log
android.widget.TextView 0 tappable [581,995][998,1060]
android.widget.TextView Requests tappable [581,1069][998,1106]
android.widget.TextView 0 tappable [82,1189][499,1254]
android.widget.TextView Input Tokens tappable [82,1263][499,1300]
android.widget.TextView 0 tappable [581,1189][998,1254]
android.widget.TextView Output Tokens tappable [581,1263][998,1300]
android.widget.Button Members tappable [83,1383][997,1518]
android.widget.TextView Members tappable [189,1427][933,1473]
android.widget.Button Credit activity tappable [83,1518][997,1654]
android.widget.TextView Credit activity tappable [189,1562][933,1608]
android.widget.Button Invoices tappable [83,1653][997,1788]
android.widget.TextView Invoices tappable [189,1697][933,1743]
android.widget.Button Kilo Pass. Not subscribed tappable [83,1789][997,1933]
android.widget.TextView Kilo Pass tappable [189,1817][933,1863]
android.widget.TextView Not subscribed tappable [189,1867][933,1904]
android.widget.Button Low balance alert, Off tappable [83,1933][997,2075]
android.widget.TextView Low balance alert tappable [189,1961][933,2007]
android.widget.TextView Off tappable [189,2011][933,2048]
android.view.View Home, tab, 1 of 3 tappable [0,2195][360,2337]
android.widget.TextView HOME tappable [13,2281][347,2320]
android.view.View Agents, tab, 2 of 3 tappable [360,2195][720,2337]
android.widget.TextView AGENTS tappable [373,2281][707,2320]
android.view.View Profile, tab, 3 of 3 tappable [720,2195][1080,2337]
android.widget.TextView PROFILE tappable [733,2281][1067,2320]
/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c/e2e-mobile-app/e1-members.log
SCENE e1m OK
android.widget.LinearLayout com.kilocode.kiloapp:id/action_bar_root tappable [0,0][1080,2400]
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.Button Go back tappable [0,149][101,250]
android.view.View Members tappable [111,167][933,232]
android.widget.Button Invite member tappable [960,158][1044,242]
android.widget.TextView MEMBERS tappable [55,356][1025,393]
android.widget.TextView E2E Org Owner tappable [83,440][850,486]
android.widget.TextView e2e-org-owner-explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c@example.com tappable [83,490][850,527]
android.widget.TextView Owner tappable [895,463][979,502]
android.widget.Button Manage e2e-mobile-explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c-android tappable [55,556][1025,698]
android.widget.TextView e2e-mobile-explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c-android tappable [83,584][825,630]
android.widget.TextView e2e-mobile-explorer-a-control-is-too-small-to-tap-reliably-6790f7d4-3a6c-android@example.com tappable [83,634][825,671]
android.widget.TextView Member tappable [870,607][979,646]
android.view.View Home, tab, 1 of 3 tappable [0,2195][360,2337]
android.widget.TextView HOME tappable [13,2281][347,2320]
android.view.View Agents, tab, 2 of 3 tappable [360,2195][720,2337]
android.widget.TextView AGENTS tappable [373,2281][707,2320]
android.view.View Profile, tab, 3 of 3 tappable [720,2195][1080,2337]
android.widget.TextView PROFILE tappable [733,2281][1067,2320]
Owner request

Explorer finding: a control is too small to tap reliably

The user-agent explorer found this while using the app like a user.
One finding per item; the explorer never edits product code.

Flow: accessibility
Found on revision: fd04ca1

Repro:

  1. open the app on emulator-5554
  2. reach the screen the capture names (the screen the capture names)
  3. the capture shows the defect named below

Observed: controls below 28dp on a side: agents: 1 small control(s): Filter sessions (52x52px) org-manage: 1 small control(s): Rename organization (42x42px) org-members: 1 small control(s): Invite member (57x57px) profile-org: 1 small control(s): Rename organization (42x42px)
Expected: every control is at least 28dp on a side

Evidence (from the device run):

Follow-ups (not changed here)

  • not proved live: Agents tab: tap the sliders 'Filter sessions' control in the header -> the filter sheet opens; with a filter applied the control shows the count badge and tapping it re-opens the sheet. (no capture cited it)
  • not proved live: Open the organization deep-link entry (/(app)/(tabs)/(3_profile)/organization/) -> its Rename organization control opens the same sheet (the profile-org and org-manage entries share the control). (no capture cited it)
  • not proved live: Organization -> Members: tap the 'Invite member' icon in the header -> the invite-member sheet opens. (no capture cited it)

Open findings (not fixed here)

  • not proved live: agents.png is no longer on the host that took it, so no publish can carry it
  • not proved live: e1h.png is no longer on the host that took it, so no publish can carry it
  • not proved live: e1m.png is no longer on the host that took it, so no publish can carry it
  • not proved live: home-ar.png is no longer on the host that took it, so no publish can carry it
  • not proved live: home-dark.png is no longer on the host that took it, so no publish can carry it
  • not proved live: home.png is no longer on the host that took it, so no publish can carry it

e5-agents

Explorer finding: a control is too small to tap reliably

The user-agent explorer found this while using the app like a user.
One finding per item; the explorer never edits product code.

Flow: accessibility
Found on revision: fd04ca1

Repro:
1. open the app on emulator-5554
2. reach the screen the capture names (the screen the capture names)
3. the capture shows the defect named below

Observed: controls below 28dp on a side: agents: 1 small control(s): Filter sessions (52x52px) org-manage: 1 small control(s): Rename organization (42x42px) org-members: 1 small control(s): Invite member (57x57px) profile-org: 1 small control(s): Rename organization (42x42px)
Expected: every control is at least 28dp on a side

Evidence (from the device run):
- ~/.local/share/kwf/findings/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4/agents.png
- ~/.local/share/kwf/findings/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4/home-ar.png
- ~/.local/share/kwf/findings/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4/home-dark.png
- ~/.local/share/kwf/findings/explorer-a-control-is-too-small-to-tap-reliably-6790f7d4/home.png
@kilo-code-bot

kilo-code-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Reviewed the new shared IconButton and its migration of the filter, rename, and invite controls plus the accompanying tests; no security, correctness, or regression issues found in the changed lines.

Files Reviewed (10 files)
  • apps/mobile/src/components/ui/icon-button.tsx
  • apps/mobile/src/test/touch-target.test-helpers.ts
  • apps/mobile/src/components/agents/session-filter-button.tsx
  • apps/mobile/src/components/organization/hub-screen.tsx
  • apps/mobile/src/components/organization/members-screen.tsx
  • apps/mobile/src/components/ui/icon-button.mounted.test.tsx
  • apps/mobile/src/components/agents/session-filter-button.mounted.test.tsx
  • apps/mobile/src/components/organization/hub-screen.mounted.test.tsx
  • apps/mobile/src/components/organization/members-screen.mounted.test.tsx
  • apps/mobile/src/components/agents/session-list-screen.mounted.test.tsx

Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

@iscekic

iscekic commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

This description names a scenario the proof did not capture:

  • not proved live: Agents tab: tap the sliders 'Filter sessions' control in the header -> the filter sheet opens; with a filter applied the control shows the count badge and tapping it re-opens the sheet. (no capture cited it)

A repeated proof run rebuilds the same evidence, so no proof run is dispatched for a named gap. Merging with this gap open is your decision.

@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 19, 2026
@iscekic iscekic self-assigned this Sep 19, 2026
@iscekic

iscekic commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator Author

Closing as a duplicate of #6395.

This PR and ten others came from the same explorer finding, a-control-is-too-small-to-tap-reliably. Nine of the eleven edit apps/mobile/src/components/agents/session-filter-button.tsx, so they could never all merge — the first to land would conflict the rest.

#6395 is kept because it is the broadest of the group (14 files of the 34 the group touches).

Any screen still below the tap-target bar after #6395 merges will be found again by the same scan, and will now arrive as one finding: the intake refuses a finding whose slug already has an open PR or a live section (kwf 07c842fd).

@iscekic iscekic closed this Sep 20, 2026
@iscekic iscekic reopened this Sep 20, 2026
@iscekic

iscekic commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator Author

Reopened — I closed this in error.

I closed it as a duplicate of #6395 on the grounds that eleven PRs shared one explorer finding. That was right about the finding and wrong about this PR: it is not a subset of #6395. It changes files #6395 does not touch, so closing it discarded real work rather than removing a copy.

Checked properly: of the ten I closed, only #6365 and #6363 are true subsets of #6395. The other eight, including this one, each fix a screen or a helper the keeper leaves alone.

What remains true: these PRs overlap on apps/mobile/src/components/agents/session-filter-button.tsx, so they will conflict with each other and cannot all merge as they stand. That is a sequencing problem to resolve, not a reason to throw the work away.

Apologies for the churn.

@iscekic

iscekic commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator Author

Closing so this defect has one PR instead of nine.

All nine came from the same explorer finding, a-control-is-too-small-to-tap-reliably, on different screens. Nine of them edit apps/mobile/src/components/agents/session-filter-button.tsx, so the first to merge conflicts the rest — they were never all mergeable.

#6395 is kept as the broadest (14 files).

I reopened this PR earlier today after closing it, because it is not a subset of #6395 and I did not want to pretend otherwise. The work it carries is not being dropped: the six source files across this group that #6395 does not touch are now one queued item, tap targets on the screens the first pass did not cover, which names each component and the PR it came from —

  • components/agents/session-list-header-actions.tsx
  • components/login/idle-auth.tsx
  • components/organization/hub-screen.tsx
  • components/organization/members-screen.tsx
  • components/ui/icon-button.tsx
  • lib/a11y/tap-target.ts (the shared helper)

One change through the shared helper is a better answer than nine screen-by-screen edits that conflict.

Cause, now fixed: each finding was dispatched the moment it was found. The explorer pools findings for an hour and dispatches one item per defect (kwf d25ae7de), and the intake refuses a slug that already has open work (kwf 07c842fd).

@iscekic iscekic closed this Sep 20, 2026
@iscekic iscekic removed the human-ready The PR is ready for human review. label Sep 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant