Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
373dac3
feat: track attachment uploads outside of message composer
szuperaz Apr 2, 2026
d85b358
feat: implement native multipart uploads
isekovanic Apr 21, 2026
bf5e0a7
refactor: uploadManager state change
szuperaz Apr 21, 2026
796a708
chore: cleanup
isekovanic Apr 21, 2026
63925be
Merge branch 'track-file-uploads-outside-message-composer' into feat/…
szuperaz Apr 21, 2026
9a6eeef
fix: file picking
isekovanic Apr 21, 2026
8c2b9af
fix: cancellation
isekovanic Apr 21, 2026
eeb0d4f
fix: too fast upload progress ui glitch
isekovanic Apr 21, 2026
878dc6a
fix: upload progress animations
isekovanic Apr 21, 2026
63e1c23
fix: cleanup and edge cases
isekovanic Apr 22, 2026
7f284ea
fix: concurrency issues on ios
isekovanic Apr 23, 2026
8168a19
refactor: video gallery
isekovanic Apr 23, 2026
a1eec02
chore: move adapter to shared code
isekovanic Apr 23, 2026
02557e1
fix: audio attachments
isekovanic Apr 23, 2026
4d1cd3c
perf: shimmer view and fastimage
isekovanic Apr 23, 2026
5b68170
fix: upload progress styles
isekovanic Apr 23, 2026
69cd37f
feat: component overrides
isekovanic Apr 23, 2026
9267be7
chore: make native uploads configurable
isekovanic Apr 23, 2026
1cea748
chore: bump stream-chat-js
isekovanic Apr 23, 2026
e91b028
feat: message composer progress
isekovanic Apr 23, 2026
d2fe291
fix: file upload indicators in composer
isekovanic Apr 23, 2026
603ca1d
fix: lint and tests
isekovanic Apr 23, 2026
e0c0732
fix: make uploads depend solely on allowSendBeforeAttachmentsUpload
isekovanic Apr 24, 2026
06c4ae0
fix: bump stream-chat-js
isekovanic Apr 24, 2026
340c2e0
chore: move multipart upload to native handlers
isekovanic Apr 24, 2026
4d264dd
Merge branch 'develop' into feat/native-multipart-upload
isekovanic Apr 24, 2026
fbf3197
fix: tests from merge
isekovanic Apr 24, 2026
0d2a24a
Merge branch 'develop' into feat/native-multipart-upload
isekovanic Apr 24, 2026
0824549
fix: typescript errors
isekovanic Apr 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/SampleApp/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ const DrawerNavigatorWrapper: React.FC<{
enableOfflineSupport
isMessageAIGenerated={isMessageAIGenerated}
i18nInstance={i18nInstance}
useNativeMultipartUpload
>
<StreamChatProvider>
<AppOverlayProvider>
Expand Down
41 changes: 41 additions & 0 deletions examples/SampleApp/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,34 @@ require Pod::Executable.execute_command('node', ['-p',
{paths: [process.argv[1]]},
)', __dir__]).strip

react_native_path = File.dirname(
Pod::Executable.execute_command('node', ['-p',
'require.resolve(
"react-native/package.json",
{paths: [process.argv[1]]},
)', __dir__]).strip,
)

fmt_podspec_path = File.join(react_native_path, 'third-party-podspecs', 'fmt.podspec')
rct_folly_podspec_path = File.join(react_native_path, 'third-party-podspecs', 'RCT-Folly.podspec')

fmt_podspec = File.read(fmt_podspec_path)
fmt_podspec = fmt_podspec.gsub('spec.version = "11.0.2"', 'spec.version = "12.1.0"')
fmt_podspec = fmt_podspec.gsub(':tag => "11.0.2"', ':tag => "12.1.0"')
fmt_podspec = fmt_podspec.gsub(
'"GCC_WARN_INHIBIT_ALL_WARNINGS" => "YES" # Disable warnings because we don\'t control this library',
"\"GCC_WARN_INHIBIT_ALL_WARNINGS\" => \"YES\", \"OTHER_CPLUSPLUSFLAGS\" => \"$(inherited) -DFMT_USE_CONSTEVAL=0\" # Disable warnings because we don't control this library",
)
File.write(fmt_podspec_path, fmt_podspec)

rct_folly_podspec = File.read(rct_folly_podspec_path)
rct_folly_podspec = rct_folly_podspec.gsub('spec.dependency "fmt", "11.0.2"', 'spec.dependency "fmt", "12.1.0"')
rct_folly_podspec = rct_folly_podspec.gsub(
'"GCC_WARN_INHIBIT_ALL_WARNINGS" => "YES" # Disable warnings because we don\'t control this library',
"\"GCC_WARN_INHIBIT_ALL_WARNINGS\" => \"YES\", \"OTHER_CPLUSPLUSFLAGS\" => \"$(inherited) -DFMT_USE_CONSTEVAL=0\" # Disable warnings because we don't control this library",
)
File.write(rct_folly_podspec_path, rct_folly_podspec)

platform :ios, min_ios_version_supported
prepare_react_native_project!

Expand Down Expand Up @@ -55,5 +83,18 @@ target 'SampleApp' do
:mac_catalyst_enabled => false,
# :ccache_enabled => true
)

installer.pods_project.targets.each do |target|
next unless ['fmt', 'RCT-Folly'].include?(target.name)

target.build_configurations.each do |config|
flags = Array(config.build_settings['OTHER_CPLUSPLUSFLAGS'] || '$(inherited)')
unless flags.include?('-DFMT_USE_CONSTEVAL=0')
flags << '-DFMT_USE_CONSTEVAL=0'
end
config.build_settings['OTHER_CPLUSPLUSFLAGS'] = flags
end
end

end
end
92 changes: 70 additions & 22 deletions examples/SampleApp/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ PODS:
- GoogleUtilities/Reachability (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1)
- nanopb (~> 3.30910.0)
- FirebaseRemoteConfigInterop (11.14.0)
- FirebaseRemoteConfigInterop (11.15.0)
- FirebaseSessions (11.13.0):
- FirebaseCore (~> 11.13.0)
- FirebaseCoreExtension (~> 11.13.0)
Expand All @@ -83,7 +83,7 @@ PODS:
- GoogleUtilities/UserDefaults (~> 8.1)
- nanopb (~> 3.30910.0)
- PromisesSwift (~> 2.1)
- fmt (11.0.2)
- fmt (12.1.0)
- glog (0.3.5)
- GoogleAppMeasurement (11.13.0):
- GoogleAppMeasurement/AdIdSupport (= 11.13.0)
Expand Down Expand Up @@ -138,6 +138,11 @@ PODS:
- hermes-engine (0.81.6):
- hermes-engine/Pre-built (= 0.81.6)
- hermes-engine/Pre-built (0.81.6)
- libavif/core (0.11.1)
- libavif/libdav1d (0.11.1):
- libavif/core
- libdav1d (>= 0.6.0)
- libdav1d (1.2.0)
- libwebp (1.5.0):
- libwebp/demux (= 1.5.0)
- libwebp/mux (= 1.5.0)
Expand Down Expand Up @@ -251,20 +256,20 @@ PODS:
- boost
- DoubleConversion
- fast_float (= 8.0.0)
- fmt (= 11.0.2)
- fmt (= 12.1.0)
- glog
- RCT-Folly/Default (= 2024.11.18.00)
- RCT-Folly/Default (2024.11.18.00):
- boost
- DoubleConversion
- fast_float (= 8.0.0)
- fmt (= 11.0.2)
- fmt (= 12.1.0)
- glog
- RCT-Folly/Fabric (2024.11.18.00):
- boost
- DoubleConversion
- fast_float (= 8.0.0)
- fmt (= 11.0.2)
- fmt (= 12.1.0)
- glog
- RCTDeprecation (0.81.6)
- RCTRequired (0.81.6)
Expand Down Expand Up @@ -2893,10 +2898,40 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- RNFastImage (8.6.3):
- RNFastImage (8.13.0):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- libavif/core (~> 0.11.1)
- libavif/libdav1d (~> 0.11.1)
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- SDWebImage (~> 5.11.1)
- SDWebImageWebPCoder (~> 0.8.4)
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SDWebImage (>= 5.19.1)
- SDWebImageAVIFCoder (~> 0.11.0)
- SDWebImageSVGCoder (~> 1.7.0)
- SDWebImageWebPCoder (~> 0.14)
- SocketRocket
- Yoga
- RNFBApp (22.2.1):
- Firebase/CoreOnly (= 11.13.0)
- React-Core
Expand Down Expand Up @@ -3292,12 +3327,17 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- SDWebImage (5.11.1):
- SDWebImage/Core (= 5.11.1)
- SDWebImage/Core (5.11.1)
- SDWebImageWebPCoder (0.8.5):
- SDWebImage (5.21.7):
- SDWebImage/Core (= 5.21.7)
- SDWebImage/Core (5.21.7)
- SDWebImageAVIFCoder (0.11.1):
- libavif/core (>= 0.11.0)
- SDWebImage (~> 5.10)
- SDWebImageSVGCoder (1.7.0):
- SDWebImage/Core (~> 5.6)
- SDWebImageWebPCoder (0.15.0):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.10)
- SDWebImage/Core (~> 5.17)
- SocketRocket (0.7.1)
- stream-chat-react-native (8.1.0):
- boost
Expand Down Expand Up @@ -3476,7 +3516,7 @@ DEPENDENCIES:
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- RNFastImage (from `../node_modules/react-native-fast-image`)
- "RNFastImage (from `../node_modules/@d11/react-native-fast-image`)"
- "RNFBApp (from `../node_modules/@react-native-firebase/app`)"
- "RNFBMessaging (from `../node_modules/@react-native-firebase/messaging`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
Expand Down Expand Up @@ -3508,11 +3548,15 @@ SPEC REPOS:
- GoogleAppMeasurement
- GoogleDataTransport
- GoogleUtilities
- libavif
- libdav1d
- libwebp
- nanopb
- PromisesObjC
- PromisesSwift
- SDWebImage
- SDWebImageAVIFCoder
- SDWebImageSVGCoder
- SDWebImageWebPCoder
- SocketRocket

Expand Down Expand Up @@ -3689,7 +3733,7 @@ EXTERNAL SOURCES:
RNCClipboard:
:path: "../node_modules/@react-native-clipboard/clipboard"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
:path: "../node_modules/@d11/react-native-fast-image"
RNFBApp:
:path: "../node_modules/@react-native-firebase/app"
RNFBMessaging:
Expand Down Expand Up @@ -3731,22 +3775,24 @@ SPEC CHECKSUMS:
FirebaseCrashlytics: 8281e577b6f85a08ea7aeb8b66f95e1ae430c943
FirebaseInstallations: 0ee9074f2c1e86561ace168ee1470dc67aabaf02
FirebaseMessaging: 195bbdb73e6ca1dbc76cd46e73f3552c084ef6e4
FirebaseRemoteConfigInterop: 7b74ceaa54e28863ed17fa39da8951692725eced
FirebaseRemoteConfigInterop: 1c6135e8a094cc6368949f5faeeca7ee8948b8aa
FirebaseSessions: eaa8ec037e7793769defe4201c20bd4d976f9677
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
fmt: 12a698626610c2fef5e7d8de472b100baf225f93
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
GoogleAppMeasurement: 0dfca1a4b534d123de3945e28f77869d10d0d600
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
hermes-engine: 7219f6e751ad6ec7f3d7ec121830ee34dae40749
libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7
libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
NitroModules: 62786c3090e21b6e28baf91ea69257b1b75fdcfd
NitroSound: ef03d951a0f7bb504f13bdc27ce1271c4c422e22
op-sqlite: 2e58f87227360fa6251d1fe103d189f11ae8c95f
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f
RCT-Folly: 5a8bea092f38495b327c6eff2dc52ee25c10f637
RCTDeprecation: d4ef510f229cea15314176aee5e3ba10064a8496
RCTRequired: 1e41b794629558f6626e2bc39c166ac0ec1c5878
RCTTypeSafety: 62c8105cf08af634c93d38ea1e8ec8a57b7abc2c
Expand Down Expand Up @@ -3821,7 +3867,7 @@ SPEC CHECKSUMS:
ReactCommon: 66eb46e6696f1f4816b250ab2807389018bacd78
RNCAsyncStorage: fd44f4b03e007e642e98df6726737bc66e9ba609
RNCClipboard: e560338bf6cc4656a09ff90610b62ddc0dbdad65
RNFastImage: 462a183c4b0b6b26fdfd639e1ed6ba37536c3b87
RNFastImage: 674d5912e174468a60971d2ba9efc7bb43d116fa
RNFBApp: db9c2e6d36fe579ab19b82c0a4a417ff7569db7e
RNFBMessaging: de62448d205095171915d622ed5fb45c2be5e075
RNGestureHandler: 6bc8f2f56c8a68f3380cd159f3a1ae06defcfabb
Expand All @@ -3832,13 +3878,15 @@ SPEC CHECKSUMS:
RNShare: c0f25f3d0ec275239c35cadbc98c94053118bee7
RNSVG: b1cb00d54dbc3066a3e98732e5418c8361335124
RNWorklets: 68ab13976d7eba39fb2f0844994a51380e76046d
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf
SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57
SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c
SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
stream-chat-react-native: d15df89b47c1a08bc7db90c316d34b8ac4e13900
Teleport: ed828b19e62ca8b9ec101d991bf0594b1c1c8812
Yoga: ff16d80456ce825ffc9400eeccc645a0dfcccdf5

PODFILE CHECKSUM: 4f662370295f8f9cee909f1a4c59a614999a209d
PODFILE CHECKSUM: 84efea5f3e8c9c79671ee6e525f700f244c17388

COCOAPODS: 1.15.2
2 changes: 1 addition & 1 deletion examples/SampleApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"fastlane:ios-deploy": "bundle exec fastlane ios deploy_to_testflight_qa deploy:true"
},
"dependencies": {
"@d11/react-native-fast-image": "^8.13.0",
"@emoji-mart/data": "^1.2.1",
"@notifee/react-native": "^9.1.8",
"@op-engineering/op-sqlite": "^14.0.4",
Expand All @@ -54,7 +55,6 @@
"react": "19.1.4",
"react-native": "0.81.6",
"react-native-blob-util": "^0.22.2",
"react-native-fast-image": "^8.6.3",
"react-native-gesture-handler": "^2.31.0",
"react-native-haptic-feedback": "^2.3.3",
"react-native-image-picker": "^8.2.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
import { Platform, StyleSheet, useColorScheme, View } from 'react-native';
import type { ComponentOverrides } from 'stream-chat-react-native';
import { BlurView } from '@react-native-community/blur';
import FastImage from 'react-native-fast-image';
import FastImage from '@d11/react-native-fast-image';
import {
useTheme,
} from 'stream-chat-react-native';
Expand Down
10 changes: 5 additions & 5 deletions examples/SampleApp/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,11 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==

"@d11/react-native-fast-image@^8.13.0":
version "8.13.0"
resolved "https://registry.yarnpkg.com/@d11/react-native-fast-image/-/react-native-fast-image-8.13.0.tgz#ae73d61fdc54b6c0b97cb97860773fb9f8db2b7f"
integrity sha512-zfsBtYNttiZVV/NwEnN/PzgW3PGlGYqn0/6DUOQ/tCv1lO0gO7+S0GiANmNDl35oVmh8o0DK81lF8xAhYz/aNA==

"@egjs/hammerjs@^2.0.17":
version "2.0.17"
resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124"
Expand Down Expand Up @@ -7574,11 +7579,6 @@ react-native-drawer-layout@^4.1.10:
dependencies:
use-latest-callback "^0.2.3"

react-native-fast-image@^8.6.3:
version "8.6.3"
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.6.3.tgz#6edc3f9190092a909d636d93eecbcc54a8822255"
integrity sha512-Sdw4ESidXCXOmQ9EcYguNY2swyoWmx53kym2zRsvi+VeFCHEdkO+WG1DK+6W81juot40bbfLNhkc63QnWtesNg==

react-native-gesture-handler@^2.31.0:
version "2.31.0"
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.31.0.tgz#7963b37b5566134bb6006024ec6a20d215a5b1a0"
Expand Down
9 changes: 5 additions & 4 deletions package/expo-package/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ if (isNewArchitectureEnabled()) {
def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["StreamChatExpo_" + name]).toInteger()
}
def canonicalProjectDir = projectDir.getCanonicalFile()
def localSharedNativeRootDir = new File(projectDir, "src/main/java/com/streamchatreactnative/shared")
def sharedNativeRootDir = new File(projectDir, "../../shared-native/android")
def sharedNativeRootDir = new File(canonicalProjectDir, "../../shared-native/android")
def hasNativeSources = { File dir ->
dir.exists() && !fileTree(dir).matching { include "**/*.kt"; include "**/*.java" }.files.isEmpty()
}
Expand Down Expand Up @@ -88,10 +89,10 @@ tasks.register("syncSharedShimmerSources") {
outputs.upToDateWhen { false }
doLast {
def sourceRootDir = null
if (hasNativeSources(localSharedNativeRootDir)) {
sourceRootDir = localSharedNativeRootDir
} else if (hasNativeSources(sharedNativeRootDir)) {
if (hasNativeSources(sharedNativeRootDir)) {
sourceRootDir = sharedNativeRootDir
} else if (hasNativeSources(localSharedNativeRootDir)) {
sourceRootDir = localSharedNativeRootDir
}

if (sourceRootDir == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@
import java.util.Map;

public class StreamChatExpoPackage extends TurboReactPackage {
private static final String STREAM_MULTIPART_UPLOADER_MODULE = "StreamMultipartUploader";
private static final String STREAM_VIDEO_THUMBNAIL_MODULE = "StreamVideoThumbnail";

@Nullable
@Override
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
if (name.equals(STREAM_VIDEO_THUMBNAIL_MODULE) && BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
if (name.equals(STREAM_MULTIPART_UPLOADER_MODULE)) {
return createNewArchModule("com.streamchatexpo.StreamMultipartUploaderModule", reactContext);
}

if (name.equals(STREAM_VIDEO_THUMBNAIL_MODULE)) {
return createNewArchModule("com.streamchatexpo.StreamVideoThumbnailModule", reactContext);
}

Expand All @@ -30,7 +35,17 @@ public NativeModule getModule(String name, ReactApplicationContext reactContext)
public ReactModuleInfoProvider getReactModuleInfoProvider() {
return () -> {
final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
moduleInfos.put(
STREAM_MULTIPART_UPLOADER_MODULE,
new ReactModuleInfo(
STREAM_MULTIPART_UPLOADER_MODULE,
STREAM_MULTIPART_UPLOADER_MODULE,
false, // canOverrideExistingModule
false, // needsEagerInit
false, // hasConstants
false, // isCxxModule
true // isTurboModule
));
moduleInfos.put(
STREAM_VIDEO_THUMBNAIL_MODULE,
new ReactModuleInfo(
Expand All @@ -40,7 +55,7 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() {
false, // needsEagerInit
false, // hasConstants
false, // isCxxModule
isTurboModule // isTurboModule
true // isTurboModule
));
return moduleInfos;
};
Expand Down
Loading
Loading