feat: combine iOS native list, swipe, Liquid Glass and markdown PRs - #7723
diegolmello wants to merge 175 commits into
Conversation
* chore: upgrade dependencies and patches to RN 0.86 / Expo 57 * chore: align upgrade toolchain floors and CI checks * chore: update Jest toolchain for RN 0.86 and Expo 57
* fix: adapt app code to React Native 0.86 and Expo 57 * test: await scheduled gesture and floating date callbacks
* fix(ios): support React Native 0.86 and Expo 57 * test: fix jest failures under Node 22 Resolve Expo's lazy fetch global in jest setup so suites that fully mock react-native no longer crash when jest enumerates globals at teardown. Restore real timers only after Testing Library unmounts, so immediates scheduled with fake timers are cancelled with the same clock. * fix(android): adopt Expo 57 autolinking plugin and drop jcenter from patched libraries Expo 57 removed scripts/autolinking.gradle in favour of the expo-autolinking-settings and expo-root-project Gradle plugins. Gradle 9 removed jcenter(), which @react-native-cookies/cookies and react-native-math-view still declared. Bump the iOS Pods cache key so runners stop restoring Local Podspecs generated for the previous React Native version. * fix(android): build with React Native 0.86 codegen and Expo 57 prebuilt modules Bump @react-native/codegen, babel-preset and typescript-config to 0.86.3 so libraries stop resolving the stale 0.80 codegen. Build the four patched Expo packages from source, since Expo 57 ships prebuilt Android artifacts that ignore patch-package changes. Patch camera-roll to drop string literal unions from its spec, keyboard-controller for the non-null onConfigurationChanged signature, math-view to drop the removed UIManagerModuleListener import, and expo-font for the nullable loadedFonts field. Declare androidx.localbroadcastmanager explicitly and resolve the WRITE_EXTERNAL_STORAGE maxSdkVersion manifest conflict. * fix: drop undefined request headers rejected by Expo fetch Expo 57 installs its native fetch as the global and rejects header entries whose value is undefined. getServerInfo sent X-Auth-Token and X-User-Id as undefined before login, so every deep link login fell back to the Add workspace screen and all E2E flows failed. * test(e2e): wait for LoginView transition before keyboard navigation * fix(login): keep focus on the password field when submitting with a hardware keyboard * fix(ios): compile the release bundle with the hermesc matching the bundled Hermes runtime * fix(ios): expose room header testIDs to accessibility tree An accessible wrapper around the room header hides its children from XCUITest on React Native 0.86, so Maestro could not find the header title or the header button. Move the accessibility label and role to the pressable header, which already exposes its children. * fix(ios): expose rooms list header testIDs to accessibility tree Same cause as the room header: an accessible wrapper inside the native stack header hides its children from XCUITest, so Maestro could not find the servers list button. * fix(ios): bump react-native-linear-gradient to 2.8.3 to stop zero-size layer crash on mention autocomplete * fix(ios): address upgrade review feedback * fix(ios): exclude Android keyboard flow change
* fix: update Android build for React Native 0.86 * fix: restore Android Gradle 9 compatibility * fix: align React Native codegen version * fix: resolve Android storage permission merge * fix: patch Android modules for React Native 0.86 * fix: restore Android local broadcast dependency * fix: build patched Expo modules from source * fix: raise iOS deployment target to 16.4 for Expo 57 * fix: materialize expo fetch global before jest mocks * fix: keep setImmediate real under jest fake timers * fix: key iOS pods cache by Podfile.lock hash * fix: allow non-modular React includes in framework modules * fix: drop undefined header values before fetch expo/fetch, installed as the global fetch on native by Expo 57, forwards header entries to the native request verbatim, so an undefined value fails the Kotlin cast to Pair<String, String> and rejects the whole request. * fix: build React-Core from source instead of prebuilt * fix: match Expo import access level with generated provider * fix: adopt Expo 57 AppDelegate contract * fix: compile Hermes bytecode with the legacy compiler * fix: expose header test ids on iOS * fix: expose team channels header test id * fix: remove iOS changes from Android upgrade
Removed the three Podfile opt-outs (RCT_USE_PREBUILT_RNCORE, RCT_USE_RN_DEP, RCT_HERMES_V1_ENABLED) and the HERMES_CLI_PATH post_install override, letting React Native 0.86 use its prebuilt React-Core/ReactNativeDependencies tarball and Hermes V1 (250829098.0.17) instead of building from source. Dropped the RCTViewManager accessibility-role patch: it only touched the Paper renderer, the app runs on Fabric, and the file no longer compiles under prebuilt Core. VoiceOver role-update behavior is covered by manual smoke testing, not this patch. RNFB pods forced to static libraries in the pre_install hook to avoid a non-modular-include failure on RNFB 21.x; the fix ships in react-native-firebase >= 26.3.0, so this can be dropped on that bump. SocketRocket now ships vendored inside the ReactNativeDependencies xcframework under a namespaced header path, so SSLPinning.mm's import changed from a flat "SRWebSocket.h" to <SocketRocket/SRWebSocket.h>. Copy Pods Resources phases regenerated by pod install, dropping the boost/glog/RCT-Folly privacy bundles that no longer exist as separate pods.
* fix(e2e): reach login email field by focus instead of Dpad count The keyboard navigation onboarding flow walked to the email field with four blind Remote Dpad Down presses. Removing the decorative OR separator from the accessibility focus chain shortened the chain by one, so the email was typed into the password field and the password into the email field, and login was never submitted. Press Down until login-view-email reports focused, bounded by times: 10, and assert focus before typing. Maestro returns normally when a repeat bound is exhausted, so without the assertion an over-long chain would fail later at the rooms-list-view wait with an unrelated error. The separator only renders when totalServices > 0, so the chain length depends on server config and no fixed count is correct. * fix(e2e): reach password and submit by focus, hide keyboard first Anchoring the email field exposed two more blind steps in the same flow. The hop to the password field assumed Enter moves focus, and the submit assumed Enter on the password field logs in. Neither had been exercised before, because the flow failed earlier. Press Down until each target reports focused, bounded and asserted like the email field. The submit loop needs the soft keyboard hidden first: with the keyboard up the Dpad presses go to the input method and never reach the login screen, so the submit button is never focused.
* chore(deps): bump reanimated to 4.6.0 and worklets to 0.12.2 Reanimated 4.6.0 requires react-native-worklets 0.12.x, so both move together. Worklets drops its caret to match reanimated's exact pin. Reanimated 4.6.0 initializes CSS event handling at import time, which the JS-only fallback used by Jest does not implement, so the mock entry point throws on load. Stubbing setCSSEventHandler at its source keeps the rest of the proxy module real. * chore(ios): update Podfile.lock for reanimated and worklets CocoaPods preserves versions already in Podfile.lock, so pod install would not have picked these up on its own. * chore(ios): bump ffi to 1.17.4 for Xcode 27 compatibility
iOS 27 SDK requires scene-based app lifecycle. The app now uses Expo's ExpoAppSceneDelegate via a new SceneDelegate, with startReactNative and boot splash initialization moved out of the app delegate into the scene delegate.
Disable code-highlight and math native assets to avoid network-dependent postinstall downloads and a known iOS static-linkage conflict with LaTeX. Patch the package's jest.d.ts, which points at raw unbuilt TS source instead of its compiled declarations, breaking typecheck for any project using the official jest mock.
Serialize the message-parser AST into CommonMark/GFM per top-level block and render each block with EnrichedMarkdownText instead of one React component per AST node type. Mentions, channels, timestamps and custom emoji encode as scheme links (user://, channel://, timestamp://) or inline images, resolved through a single onLinkPress dispatcher. Block LaTeX keeps rendering through the existing KaTeX component; inline LaTeX and the preview/plain-text path are unchanged.
…pshots Regenerate snapshots for stories that render through the new markdown component tree.
…-pad The RN 0.86 gesture-handler bump added an Android-only onKeyUp override that intercepts DPAD_CENTER/ENTER/SPACE and activates whichever button currently holds native view focus, bypassing the default performClick() path. Every composer and header icon button is a BorderlessButton, so this silently fired the wrong button (e.g. the header drawer button) on hardware Enter/D-pad and swallowed the key event elsewhere. Removed the hunk; the iOS press-handling hunk is untouched.
Derive the open side from the resting offset instead of a separate row state, release and register the row inside the gesture worklet, fire the threshold haptic from the pan update, and flip gesture input and output once for right-to-left layouts. Drop the duplicate long-press gesture and skip the snapshot rebuild on the record's initial emission.
…de-10' into combo-13-recreate
…pe' into combo-13-recreate
…t' into combo-13-recreate # Conflicts: # app/containers/BackgroundContainer/__snapshots__/index.test.tsx.snap # app/containers/BackgroundContainer/index.tsx # app/containers/Button/index.tsx # app/containers/DirectoryItem/__snapshots__/DirectoryItem.test.tsx.snap # app/containers/List/__snapshots__/List.test.tsx.snap # app/containers/MessageComposer/components/SendThreadToChannel.tsx # app/containers/RoomHeader/RoomHeader.tsx # app/containers/RoomHeader/__snapshots__/RoomHeader.test.tsx.snap # app/containers/RoomItem/__snapshots__/RoomItem.test.tsx.snap # app/containers/ServerItem/__snapshots__/ServerItem.test.tsx.snap # app/containers/markdown/__snapshots__/Markdown.test.tsx.snap # app/views/AccessibilityAndAppearanceView/components/ListPicker.tsx # app/views/MediaAutoDownloadView/ListPicker.tsx # app/views/NewMessageView/Item.test.tsx # app/views/NewMessageView/Item.tsx # app/views/NewMessageView/__snapshots__/Item.test.tsx.snap # app/views/NewServerView/components/ServersHistoryItem/__snapshots__/ServersHistoryItem.test.tsx.snap # app/views/RoomInfoView/components/BaseButton.tsx # app/views/RoomMembersView/index.tsx # app/views/RoomView/components/Banner.tsx # app/views/RoomsListView/components/Header.tsx # app/views/RoomsListView/components/SectionHeader.tsx # app/views/SelectedUsersView/Header.tsx
(cherry picked from commit bf2c80f)
(cherry picked from commit 30b8d39)
(cherry picked from commit 63e41dd)
(cherry picked from commit e5f5c75)
(cherry picked from commit 7bda226)
(cherry picked from commit 3c59091)
|
Verified 96ec202 on an iOS 27 simulator (iPhone 17 Pro, debug build). Steps shown in the video:
Outcome: the swipe, open-row, tap and long-press behaviour works, and so does the missing-attachment guard. One issue in the share list, unrelated to the merge (the merge changes only the attachment guard in that screen): the list begins under the native header and search bar. The "Chats" section header and the first two rooms sit behind the bar and can't be scrolled into view. When a search has results, they render behind the bar too: "Legend" matches one room, and the visible list stays empty (1:10–1:13). 96ec2024ff.mp4 |
…c theme (cherry picked from commit 332e2ce)
332e2ce to
14d846b
Compare
|
iOS Build Available Rocket.Chat 4.77.0.109816 |
|
Android Build Available Rocket.Chat 4.77.0.109815 Internal App Sharing: https://play.google.com/apps/test/RQQ8k09hlnQ/ahAO29uNQQ2m5Kb2AezBUp1RWOtTcOtHgEFDYkqv9tvpvDfT8K_EMbAOD32AJVTBmVNneXuTBZIre66NAqVLxvf4Xg |
Proposed changes
Combines seven open UI PRs on top of the React Native 0.86 upgrade branch:
UILabel/TextView.#7707, #7718, #7719 and #7727 are merged in. #7724, #7740 and #7739 are cherry-picked, since their branches also carry commits that are already here in another form (the unsquashed #7721 commits, and the previous version of this branch).
Conflicts resolved:
TexttoPlainTextswap was applied on top of the Liquid Glass and Expo UI List versions of the same files.RoomMessageActions.LoadMorekeeps the gesture handler v3disabledprop, and the room screen passeslistRefto the messages list.PlainTextexposes.Also includes the iOS theme fix that resets the color scheme override before resolving the automatic theme.
Issue(s)
https://rocketchat.atlassian.net/browse/NATIVE-1576
How to test or reproduce
Screenshots
Types of changes
Checklist
Further comments
Epic: https://rocketchat.atlassian.net/browse/NATIVE-1561
Summary by CodeRabbit
New Features
Bug Fixes