Repository navigation
Next Release - #3904
Merged
Merged
Next Release#3904
Conversation
β¦ations (#3895) Ticket: https://linear.app/stream/issue/RN-468 ## π― Goal Android (GetStream/stream-chat-android#6848, GetStream/stream-chat-android#6849, GetStream/stream-chat-android#6851), iOS (GetStream/stream-chat-swift#4338) and web (GetStream/stream-chat-react#3339) added two voice-agent visualizations to their AI components. This brings them to `stream-chat-react-native/ai-components` (and `stream-chat-expo/ai-components`) with the same motion, so the platforms look and move alike, and shows them in a new voice mode in `ExpoChatGPTSample`. ## π Implementation details **Public API** (from the `ai-components` entry point): - `VoiceWave`: a single string carrying a wave packet that erupts with speech, its colors flowing along it. - `VoiceGlow`: a soft globe whose color masses orbit inside it and swell with speech. - `useDictationAudioLevel()`: the microphone's live level while dictation listens, as a Reanimated `SharedValue<number | null>`. - Types `VoiceAgentState`, `VoiceVisualizationProps`, `VoiceWaveProps`, `VoiceGlowProps`, `DictationLevel`; `useDictationState` and `useDictationTranscript` are now exported too. - An optional `voiceVisualization` theme key: `colors` (default palette, the accent color) and `backdropColor` (light or dark look; the system color scheme when unset). Both components take `state` (`idle | connecting | listening | thinking | speaking`), `colors` (one to five colors), `expressivity` (0 to 2) and `audioLevel` (a `SharedValue`, read once a frame on the UI thread; `null` animates speech on its own). Other `View` props go to the root. **How it's built:** - One motion driver, ported from Android's `VoiceVisualizationDriver` (per-state motion table, frame-rate-independent easing, reduced motion at 0.07x, tap bounce, HSV palette, and the `Steady`/`Smooth` level responses for glow and wave). It's plain objects and worklets, advanced in a Reanimated `useFrameCallback`, so the motion runs on the UI thread and keeps going while JS is busy streaming a reply. - `VoiceGlow` is a Skia `RuntimeEffect`: Android's AGSL shader is SkSL, so it's ported nearly verbatim and runs on every Android version. Every glow shares one compiled effect. There is no Canvas/CSS fallback and no `rendering` prop. - `VoiceWave` is a Skia path with a 13-stop gradient, as Android draws it; its speech envelope uses the shader's float32 simplex noise (as on iOS and the web). - Drawn at most 2x for the glow and 3x for the wave, as on iOS. - Touches are only observed on a hit area the size of the shape, so a parent `Pressable` still fires and touches beside the shape pass through. Hover ripples with a mouse or pen. - Accessibility follows native: "Voice agent" as the label and the state as the value; Reduce Motion is honoured. - Where native and web differ, this follows native (e.g. no web-only wave smoothing). **Native dictation:** - New `AIDictationOnLevel` event (no codegen spec change; it goes through the existing `NativeEventEmitter`). Android maps the recognizer's `onRmsChanged`; iOS measures the audio tap in dBFS, throttled to ~30 Hz, tuned on an iPhone for `.measurement` mode (-60 to -35 dBFS). - Fix: iOS dictation now remembers the `AVAudioSession` configuration it found and restores it when dictation ends. It used to leave the session in the `.record` category, which muted all playback in the app after the first dictation and kept other apps' audio ducked. **Sample:** `ExpoChatGPTSample` gets a full-screen voice mode (`VoiceGlow` for the agent, `VoiceWave` on the microphone level). It listens with dictation, sends the transcript, follows the agent's AI state, reads the reply aloud with `expo-speech` and listens again. The send path moved into a shared `useSendAIMessage`, and the demo backend is now called with `platform: 'openai'`, as in the React example (its Anthropic key currently fails `/summarize`). **Entry isolation:** everything lives under `src/ai-components`; `validate-entry-isolation` passes. ## π¨ UI Changes Voice mode in `ExpoChatGPTSample`, on a physical iPhone 15 Pro Max and the iOS simulator. Screenshots and a recording to be added. ## π§ͺ Testing - Unit tests: Android's 22 driver tests and the bounce tests ported; palette, input clamping, simplex noise against GPU readback values, hit areas, wave geometry, rendering, accessibility label and value, theme fallbacks, reduced motion, and the dictation level hook. `yarn test:unit`, `yarn lint`, `yarn typecheck` and `yarn build` pass. - The SkSL shader compiles and renders under CanvasKit, matching Android's Paparazzi snapshot. - iOS simulator: both visualizations render and animate, and the voice-mode loop runs (listening, thinking, speaking, back to listening). Speech recognition itself fails on iOS 27 simulators ("Failed to initialize recognizer"), so transcription was faked there. - Physical iPhone: dictation, the mic level driving the wave, the spoken reply and the full voice loop work. - Not yet tested: Android on a device (the Android level mapping is untuned), SampleApp. ## βοΈ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated (AI components README; the React Native v9 AI integration docs are in a separate getstream.io PR) - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android (iOS done, Android pending)
Pulls in the following fixes from stream-chat-js: - poll crash when the last vote on an option is removed - message pagination after message_limit 0 queries and disconnected latest pages - custom attachments dropped when editing a message The poll preview label test now expects the emptied option to be removed from latest_votes_by_option instead of left as an empty array, which is how the LLC handles it now.
fix: bump stream-chat to 9.54.2
fix: adjusted message composer bottom offset calculation
## π― Goal E2E test automation for the SDK, on par with the native iOS/Android and Flutter suites, running on PRs. Linear: [RN-450](https://linear.app/stream/issue/RN-450), [RN-451](https://linear.app/stream/issue/RN-451), [RN-452](https://linear.app/stream/issue/RN-452), [RN-453](https://linear.app/stream/issue/RN-453), [RN-454](https://linear.app/stream/issue/RN-454), [RN-455](https://linear.app/stream/issue/RN-455), [RN-457](https://linear.app/stream/issue/RN-457) (parent [RN-449](https://linear.app/stream/issue/RN-449)) ## π Implementation details **Dedicated app: `examples/E2ETestApp`.** A new bare RN 0.88 workspace with only the SDK and its required peer dependencies (no Firebase, maps, video or navigation library), like the native SDKs' `StreamChatUITestsApp`. It has three screens: a user selector, the channel list, and a channel stacked over the list. It reads a `MOCK_SERVER_URL` launch argument (`react-native-launch-arguments`), never persists a login and runs without offline storage, so every test starts clean. A clean Release build takes ~2 min on an M-series Mac; the SampleApp took ~15 min on Android. **The SampleApp app is unchanged**; only its Fastfile gains the e2e lanes. **Framework ([RN-450](https://linear.app/stream/issue/RN-450)):** Detox 20 + Jest 30 in `examples/E2ETestApp/e2e/`, with `ios.sim.*`, `android.emu.*` and `android.att.*` configs (debug and release). **Mock server ([RN-451](https://linear.app/stream/issue/RN-451)):** the shared [`stream-chat-test-mock-server`](https://github.com/GetStream/stream-chat-test-mock-server), one server per test through its driver (port 4569). **Page objects ([RN-452](https://linear.app/stream/issue/RN-452)) and robots ([RN-453](https://linear.app/stream/issue/RN-453), [RN-454](https://linear.app/stream/issue/RN-454), [RN-455](https://linear.app/stream/issue/RN-455)):** structure and naming follow the native suites: - `BackendRobot` / `ParticipantRobot`: 1:1 ports of the Android robots - `UserRobot` + `UserRobot*Asserts`: assert extensions, like Android's - `LoginPage` / `ChannelListPage` / `MessageListPage` - `setUpStreamTestCase()`, `step()`, and uiautomator-style element helpers Robots chain fluently like the native ones: `await userRobot.login().openChannel().assertMessage('Hi')`. **Smoke suite:** 6 tests (MessageList Γ3, ChannelList Γ3), named after their Android counterparts and keeping the native expectations. **SDK (additive testIDs only):** `channel-preview-title`, `channel-preview-message`, `channel-preview-sender`, and `message-status-{read,delivered,sending,sent}`, with a unit test. **CI ([RN-457](https://linear.app/stream/issue/RN-457)):** `.github/workflows/e2e-test.yml`. - **Android** runs on PRs: `ubuntu-latest`, KVM, API 36 AOSP emulator, `pixel` profile (the native Android SDK's setup). - **iOS** runs only on demand (`workflow_dispatch` with `ios: true`), not on PRs, to save CI time and macOS runners: `macos-15`, Xcode 26.2, iPhone 17 Pro. - Gated like the iOS SDK: a cheap `Check E2E Required` job runs `is_check_required` over the e2e sources (Fastfile `impact_analysis`), and `test_e2e` checks it too. - **`Test E2E Result` is the check to require in branch protection.** It covers Android (it doesn't wait for iOS) and passes when the Android job passes or is skipped as not required. - Caching: - the built `.app` / `.apk`, keyed on the app and SDK sources but not on `e2e/`, so a test-only change skips the native build - `node_modules` of `yarn workspaces focus e2etestapp` - CocoaPods, ccache (with `CCACHE_BINARY` exported, without which RN's ccache wrappers silently skip ccache), the Detox framework, Gradle (`cache-read-only: false`, since `setup-gradle` otherwise only writes on the default branch), and the mock server's gems - each PR fills its own caches (the workflow doesn't run on `develop`): its first run builds cold, and later pushes reuse them - On failure, uploads the mock server logs, Detox's logs and screenshots, and the emulator's crash data. **Fastlane** (in `examples/SampleApp/fastlane`, next to the repo's other lanes): `start_mock_server`, `stop_mock_server`, `e2e_pod_install`, `test_e2e`, `e2e_check_required`. **Notable findings**, documented in `examples/E2ETestApp/e2e/README.md`: - Fabric mounts some testID'd views (`message-list-item-*`, `message-text-container`) empty, with their content as siblings, so page objects scope to `message-content-wrapper` or the list instead. - iOS runs without Detox's idle synchronization, which can wedge on RN's UIManager shadow queue. Robots wait explicitly, and taps retry while the target isn't hittable yet. - `launchApp({ permissions })` makes Detox restart SpringBoard once per permission on every launch. On CI that cost 1.5β3 min per test, so the suite doesn't pass any. - Android sets the composer text directly (as the native suite does). Typing through Gboard left the text in a composing state that the composer didn't send. How to run and extend the suite: `examples/E2ETestApp/e2e/README.md`. ## π¨ UI Changes None (testIDs only). ## π§ͺ Testing - Locally (release builds): iOS simulator 6/6, 31s for the whole suite; Android emulator 6/6. - CI: green on [39459700744](https://github.com/GetStream/stream-chat-react-native/actions/runs/39459700744) and [39467760315](https://github.com/GetStream/stream-chat-react-native/actions/runs/39467760315). On the latter the iOS test step took 3m 12s (31 min before the launch-permission fix), and Android 3m 12s. - `e2e_check_required` against real PRs: no PR β `true`, #3870 (docs only) β `false`, #3879 (`package/`) β `true`. - `yarn build`, `yarn lint`, `yarn typecheck` (now including `e2etestapp`), `cd package && yarn test:typecheck`, `yarn test:unit` green. Not covered yet: Allure TestOps reporting, full suite ports, and iOS on PRs (manual runs only, to save CI time and macOS runners). ## βοΈ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android
Next releasesv9.11.09.11.0 (2026-10-28)Bug Fixes
Features
sampleapp@v4.16.34.16.3 (2026-10-28)Bug Fixes |
Contributor
SDK Size
|
Contributor
|
π This PR is included in version 9.11.0 π The release is available on:
Your semantic-release bot π¦π |
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.
π― Goal
π Implementation details
π¨ UI Changes
iOS
Android
π§ͺ Testing
βοΈ Checklist
developbranch