feat(a11y): Physical Keyboard Navigation#7010
feat(a11y): Physical Keyboard Navigation#7010OtavioStasiak wants to merge 126 commits intodevelopfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR introduces keyboard and external input navigation improvements for Android and iOS, including inverted scroll view focus handling, external keyboard detection, imperative focus management via refs, and comprehensive Maestro test flows validating keyboard navigation across the app's UI components. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App as React App
participant RoomHeader
participant RoomView
participant InteractionManager
User->>App: Navigation Focus (isMasterDetail=true)
App->>RoomView: componentDidMount (focus listener registered)
RoomView->>InteractionManager: runAfterInteractions()
InteractionManager->>RoomView: Execute callback
RoomView->>RoomHeader: roomHeaderRef.current?.focus()
RoomHeader->>RoomHeader: useImperativeHandle (expose focus)
RoomHeader->>RoomHeader: findNodeHandle(headerRef)
RoomHeader->>App: AccessibilityInfo.setAccessibilityFocus(nodeHandle)
sequenceDiagram
participant KeyEvent as KeyEvent (Tab/DPAD)
participant InvertedScrollView
participant ScrollChild as Current Focused Child
participant AdjacentChild as Adjacent Cell
participant Composer as Message Composer
KeyEvent->>InvertedScrollView: dispatchKeyEvent(KEYCODE_TAB / DPAD_DOWN)
InvertedScrollView->>InvertedScrollView: Resolve focused child cell
InvertedScrollView->>AdjacentChild: requestFocus(direction)
alt Focus Accepted
AdjacentChild->>InvertedScrollView: return true
else Boundary Reached (end of list)
InvertedScrollView->>InvertedScrollView: Lookup exit focus via nativeID
InvertedScrollView->>Composer: ReactFindViewUtil.findView(exitFocusNativeId)
Composer->>Composer: requestFocus()
end
sequenceDiagram
participant ComposerInput as ComposerInput Component
participant ExternalInput as ExternalInput Module
participant Native as Android/iOS Native Layer
participant Context as MessageComposer Context
ComposerInput->>ComposerInput: onBlur triggered
ComposerInput->>ExternalInput: isExternalKeyboardConnected()
ExternalInput->>Native: Query Configuration/GCKeyboard
Native->>ExternalInput: Return keyboard status
alt External Keyboard Connected
ComposerInput->>Context: Skip blur (keep focus state)
else No External Keyboard
ComposerInput->>Context: setFocused(false) with 150ms delay
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Android Build Available Rocket.Chat Experimental 4.70.0.108314 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNSHg7TdML4PFPLPaD3vbMSQN1kCdTXPzueVdh4N44q6GZfR1wk0ZNlhk_GdG11POn-I-qGjSYJWmIjmQQKs |
|
Android Build Available Rocket.Chat Experimental 4.70.0.108317 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNRigBMM3Bes80dsLl0Wof7_pwq8w6zFWBUUGsRGp2rRCO4FnN6K1TeJ4P-FQhppg3r60B8pyKQNdZQTh6Zy |
|
Android Build Available Rocket.Chat Experimental 4.70.0.108318 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNQfUhHNuTEb7FEFekyzv7gX_VAjowLUgqhtyPgrwQ7XZI58MKTI6S0_cS2vJpxejQfVdMxEh288m2qGEJxg |
|
iOS Build Available Rocket.Chat Experimental 4.72.0.108566 |
|
iOS Build Available Rocket.Chat Experimental 4.72.0.108585 |
|
Android Build Available Rocket.Chat Experimental 4.72.0.108584 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNSB6GJHRG1Aaz0kNPmsRIVqmj1oEOGbdAajcQ5orWR04pihZm2Rcqj6QhureSsRyHuBYyTEW_FFOnSIBPJ9 |
|
Android Build Available Rocket.Chat Experimental 4.72.0.108646 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNQUTi2MCvyEpF0vL6eF6QWxyD-deHE4bTzn8xXLE1law4FQE9pQuNevSf6qUqddhYoOadSk1w_SiTxQNhgX |
|
Android Build Available Rocket.Chat Experimental 4.72.0.108651 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNSjFcQLtGYLfn2ilMBlQRTHbxbSlP6cuXa9MhArSwXlOsyEvuW4XRUzS-smnsgJF_b3C_I2a4jueKnmrcZw |
Proposed changes
Users should be able to navigate through the app using an external keyboard.
Issue(s)
https://rocketchat.atlassian.net/browse/MA-266
How to test or reproduce
What we should ensure:
1 - The RoomView message list must work as expected on both platforms;
2 - In master-detail, we must be able to focus on items inside the modal (Android issue);
3 - ActionSheet navigation must work as expected on both platforms.
What is not covered here:
1 - Keyboard navigation for room swipe actions.
PS: Must be tested on android, iOS, iPad and Android tablet.
Navigation tips:
On iOS, keyboard navigation is more hierarchical. You typically use the Tab key to move between elements, such as entering a list, and then use the arrow keys to navigate within that element (for example, moving between items inside the list).
On Android, keyboard navigation is more flexible. You can use both the Tab key and the arrow keys to move between and within elements, allowing for a more fluid navigation experience without needing to switch modes.
Screenshots
Types of changes
Checklist
Further comments
Summary by CodeRabbit
New Features
Accessibility