feat(mobile): splash mark, formSheet picker, and catalog guard - #5518
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryIncremental review of the Done-only language apply fix and matching tests found no correctness or runtime issues. Files Reviewed (2 files)
Previous Review Summaries (3 snapshots, latest commit e73796f)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit e73796f)Status: No Issues Found | Recommendation: Merge Executive SummaryIncremental review of same-direction picker apply, profile-tab reset, deep-link Files Reviewed (10 files)
Previous review (commit 62eaddd)Status: No Issues Found | Recommendation: Merge Executive SummaryIncremental review of the hardcoded picker return targets, unused SVG removal, and matching test updates found no correctness or runtime issues. Files Reviewed (8 files)
Previous review (commit 6530600)Status: No Issues Found | Recommendation: Merge Executive SummaryReviewed the splash mark swap, formSheet language picker (routes, bridge, prevent-remove), catalog English-identical guard, and locale updates with high confidence and no correctness, security, or runtime issues on changed lines. Files Reviewed (103 files)
Reviewed by grok-4.6 · Input: 171.7K · Output: 8.2K · Cached: 292.1K Review guidance: REVIEW.md from base branch |
Summary
The language picker is now a native formSheet route instead of an in-screen Modal. The sheet shows a system grabber and a fading backdrop at a half-height and a full detent, and Done applies while Cancel, a swipe down, or back dismisses without applying. The usePreventRemove guard blocks dismissal while an apply is in flight, and a failed RTL reload shows a Retry sheet instead of the list.
Files
apps/mobile/src/components/language-picker-sheet.tsx— replaces the Modal with PickerSheet; renders the list, restarting, and reload-failed states at the top level; adds the usePreventRemove guard, a focus reset, and the search remount epoch; moves the search field into a list header.apps/mobile/src/app/(app)/_layout.tsx— registers the picker as a formSheet with 0.5 and full detents and a visible grabber.apps/mobile/src/app/(auth)/_layout.tsx— replaces the Slot with a Stack, sets login as the initial route, and registers the picker formSheet.Login and Preferences open the picker by pushing its route and pass per-caller work through a new module-level LanguagePickerBridge. The two picker routes inline their returnTarget literal instead of reading a query parameter, so the query round-trip is gone. The bridge is cleared when a picker route loses focus, so a stale caller callback never fires.
Files
apps/mobile/src/components/login-screen.tsx— removes the inline Modal state and LanguagePickerSheet render; pushes the auth picker route and sets the bridge with a draft-flush callback.apps/mobile/src/components/preferences-screen.tsx— removes the inline Modal state and LanguagePickerSheet render; pushes the app picker route and sets the bridge with a push-token reconciliation callback.apps/mobile/src/lib/picker-bridge.ts— adds the LanguagePickerBridge type and its set, get, and clear accessors.apps/mobile/src/app/(app)/language-picker.tsx— new route screen; inlines the preferences returnTarget, reads the bridge, clears it on blur, and backs on close.apps/mobile/src/app/(auth)/language-picker.tsx— new route screen; same shape with the login returnTarget.The native splash and the animated overlay now use a transparent letter mark instead of the square logo. The mark is dark letters on transparency at 100 dp over the unchanged yellow background, so a dropped frame cannot show a yellow or black tile, and the dip, punch, disc, and handover choreography is unchanged. The app icon and the login screen keep the square logo.
Files
apps/mobile/app.config.ts— points the expo-splash-screen plugin at the transparent mark with the unchanged yellow background and width 100.apps/mobile/src/components/animated-splash-overlay.tsx— imports the transparent mark instead of the square logo.Three English-only mobile strings — preferences.prReviewAttribution, preferences.prReviewAttributionSubtitle, and agentChat.newSession.remoteHint — are now translated in all 86 non-English catalogs. The catalog parity check gains an English-identical guard that fails any mobile key whose value equals English in every non-English locale, so an untranslated key can no longer ship silently. The guard carries an allowlist of proper nouns and the two format-only strings that hold no translatable words.
Files
apps/mobile/src/i18n/locales/af.json— translates the three English-only keys.apps/mobile/src/i18n/locales/am.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ar.json— translates the three English-only keys.apps/mobile/src/i18n/locales/az.json— translates the three English-only keys.apps/mobile/src/i18n/locales/be.json— translates the three English-only keys.apps/mobile/src/i18n/locales/bg.json— translates the three English-only keys.apps/mobile/src/i18n/locales/bn.json— translates the three English-only keys.apps/mobile/src/i18n/locales/bs.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ca.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ckb.json— translates the three English-only keys.apps/mobile/src/i18n/locales/cs.json— translates the three English-only keys.apps/mobile/src/i18n/locales/cy.json— translates the three English-only keys.apps/mobile/src/i18n/locales/da.json— translates the three English-only keys.apps/mobile/src/i18n/locales/de.json— translates the three English-only keys.apps/mobile/src/i18n/locales/el.json— translates the three English-only keys.apps/mobile/src/i18n/locales/es.json— translates the three English-only keys.apps/mobile/src/i18n/locales/et.json— translates the three English-only keys.apps/mobile/src/i18n/locales/eu.json— translates the three English-only keys.apps/mobile/src/i18n/locales/fa.json— translates the three English-only keys.apps/mobile/src/i18n/locales/fi.json— translates the three English-only keys.apps/mobile/src/i18n/locales/fil.json— translates the three English-only keys.apps/mobile/src/i18n/locales/fr.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ga.json— translates the three English-only keys.apps/mobile/src/i18n/locales/gl.json— translates the three English-only keys.apps/mobile/src/i18n/locales/gu.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ha.json— translates the three English-only keys.apps/mobile/src/i18n/locales/he.json— translates the three English-only keys.apps/mobile/src/i18n/locales/hi.json— translates the three English-only keys.apps/mobile/src/i18n/locales/hr.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ht.json— translates the three English-only keys.apps/mobile/src/i18n/locales/hu.json— translates the three English-only keys.apps/mobile/src/i18n/locales/hy.json— translates the three English-only keys.apps/mobile/src/i18n/locales/id.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ig.json— translates the three English-only keys.apps/mobile/src/i18n/locales/is.json— translates the three English-only keys.apps/mobile/src/i18n/locales/it.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ja.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ka.json— translates the three English-only keys.apps/mobile/src/i18n/locales/kk.json— translates the three English-only keys.apps/mobile/src/i18n/locales/km.json— translates the three English-only keys.apps/mobile/src/i18n/locales/kn.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ko.json— translates the three English-only keys.apps/mobile/src/i18n/locales/lo.json— translates the three English-only keys.apps/mobile/src/i18n/locales/lt.json— translates the three English-only keys.apps/mobile/src/i18n/locales/lv.json— translates the three English-only keys.apps/mobile/src/i18n/locales/mg.json— translates the three English-only keys.apps/mobile/src/i18n/locales/mi.json— translates the three English-only keys.apps/mobile/src/i18n/locales/mk.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ml.json— translates the three English-only keys.apps/mobile/src/i18n/locales/mn.json— translates the three English-only keys.apps/mobile/src/i18n/locales/mr.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ms.json— translates the three English-only keys.apps/mobile/src/i18n/locales/mt.json— translates the three English-only keys.apps/mobile/src/i18n/locales/my.json— translates the three English-only keys.apps/mobile/src/i18n/locales/nb.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ne.json— translates the three English-only keys.apps/mobile/src/i18n/locales/nl.json— translates the three English-only keys.apps/mobile/src/i18n/locales/om.json— translates the three English-only keys.apps/mobile/src/i18n/locales/or.json— translates the three English-only keys.apps/mobile/src/i18n/locales/pa.json— translates the three English-only keys.apps/mobile/src/i18n/locales/pl.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ps.json— translates the three English-only keys.apps/mobile/src/i18n/locales/pt-BR.json— translates the three English-only keys.apps/mobile/src/i18n/locales/pt.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ro.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ru.json— translates the three English-only keys.apps/mobile/src/i18n/locales/si.json— translates the three English-only keys.apps/mobile/src/i18n/locales/sk.json— translates the three English-only keys.apps/mobile/src/i18n/locales/sl.json— translates the three English-only keys.apps/mobile/src/i18n/locales/so.json— translates the three English-only keys.apps/mobile/src/i18n/locales/sq.json— translates the three English-only keys.apps/mobile/src/i18n/locales/sr.json— translates the three English-only keys.apps/mobile/src/i18n/locales/sv.json— translates the three English-only keys.apps/mobile/src/i18n/locales/sw.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ta.json— translates the three English-only keys.apps/mobile/src/i18n/locales/te.json— translates the three English-only keys.apps/mobile/src/i18n/locales/th.json— translates the three English-only keys.apps/mobile/src/i18n/locales/tr.json— translates the three English-only keys.apps/mobile/src/i18n/locales/uk.json— translates the three English-only keys.apps/mobile/src/i18n/locales/ur.json— translates the three English-only keys.apps/mobile/src/i18n/locales/uz.json— translates the three English-only keys.apps/mobile/src/i18n/locales/vi.json— translates the three English-only keys.apps/mobile/src/i18n/locales/yo.json— translates the three English-only keys.apps/mobile/src/i18n/locales/zh-Hans.json— translates the three English-only keys.apps/mobile/src/i18n/locales/zh-Hant.json— translates the three English-only keys.apps/mobile/src/i18n/locales/zu.json— translates the three English-only keys.tools/i18n/check-catalogs.mjs— adds the English-identical guard; allowlists the proper nouns and the format-only prReview.screen.title and securityAgent.auditReport.periodUtc.Tests: 4 test files updated —
apps/mobile/src/components/animated-splash-overlay.mounted.test.tsx,apps/mobile/src/components/language-picker-sheet.mounted.test.tsx,apps/mobile/src/components/login-screen.test.ts, andapps/mobile/src/components/preferences-screen.mounted.test.tsx.Generated: 1 binary asset added —
apps/mobile/assets/images/logo-mark.png.Verification
Two rounds on iOS ran five cases: round 1 ran s1 to s4, and round 2 ran s5.
No round reproduced a defect on the unfixed build.
Round 1 recorded the cold boot in
/Users/igor/Projects/.scratch/kilo-workflow-mobile-polish-4e1a.SGxkBr/e2e-e2e-r1-ErY3q9/s1-splash.mp4.Visual Changes
Splash screen. The user now sees a full yellow splash with dark KILO letters and no tile around them on cold boot. In the picture, the dark pixel letters sit at the center of the yellow field with no frame around them.
Language picker sheet, login entry. The globe button now opens a sheet with a search field and a language list over the dimmed login screen. In the picture, the white sheet with one grabber and the Cancel, Language, Done header covers the lower half.
Language picker sheet, Preferences entry. The language row now opens the same sheet over the dimmed Preferences screen. In the picture, the sheet with the search field and the language list covers the lower half above the dimmed toggle cards.
Preferences screen in Spanish. After the user applies Spanish, every Preferences row shows translated copy and the language row shows Español. In the picture, the third card reads Añadir atribución de la app a las revisiones de PR, and the account row reads Idioma, Español.
Reviewer Notes
Human steps: none.
Notes: none.