Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
[![NPM](https://img.shields.io/npm/v/stream-chat-react-native.svg)](https://www.npmjs.com/package/stream-chat-react-native)
[![Build Status](https://github.com/GetStream/stream-chat-react-native/actions/workflows/release.yml/badge.svg)](https://github.com/GetStream/stream-chat-react-native/actions)
[![Component Reference](https://img.shields.io/badge/docs-component%20reference-blue.svg)](https://getstream.io/chat/docs/sdk/reactnative)
![JS Bundle Size](https://img.shields.io/badge/js_bundle_size-466%20KB-blue)
![JS Bundle Size](https://img.shields.io/badge/js_bundle_size-467%20KB-blue)

<img align="right" src="https://getstream.imgix.net/images/ios-chat-tutorial/iphone_chat_art@3x.png?auto=format,enhance" width="50%" />

Expand Down Expand Up @@ -48,9 +48,9 @@ For complete pricing details visit our [Chat Pricing Page](https://getstream.io/

This repo includes 3 example apps. One made with Expo, two in TypeScript. One TypeScript app is a simple implementation for reference, the other is a more full featured app example.

- [Expo example](./examples/ExpoMessaging)
- [Typescript example](./examples/TypeScriptMessaging)
- [Fully featured messaging application](./examples/SampleApp)
- [Expo example](https://github.com/GetStream/stream-chat-react-native/tree/develop/examples/ExpoMessaging)
- [Typescript example](https://github.com/GetStream/stream-chat-react-native/tree/develop/examples/TypeScriptMessaging)
- [Fully featured messaging application](https://github.com/GetStream/stream-chat-react-native/tree/develop/examples/SampleApp)

Besides, our team maintains a dedicated repository for fully-fledged sample applications and demos at [GetStream/react-native-samples](https://github.com/GetStream/react-native-samples). Please consider checking following sample applications:

Expand Down
8 changes: 4 additions & 4 deletions package/expo-package/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4733,10 +4733,10 @@ stream-buffers@2.2.x, stream-buffers@~2.2.0:
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==

stream-chat-react-native-core@6.6.7:
version "6.6.7"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.7.tgz#d887234af18890c3396f1b8b5f169d9b28a793ab"
integrity sha512-Xc/S92nUBSwfVPZqNjt/zNs/DJcRV1aRa/+yCSBCqjCwo0EuiWEP9yKy3xGxBkehNe4vaIDvkeREduA4dRUGpA==
stream-chat-react-native-core@6.6.8:
version "6.6.8"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.8.tgz#483ade63ba051426480ab2dfd8ab3b248b90ae88"
integrity sha512-F8S70DHaiit6BEdKOkSMHq2bjMONhrouvJ+szBQuE430EJDgUlc2VErHk3yJCzqIt5lwfVZktjHuqSIOGVg5LQ==
dependencies:
"@gorhom/bottom-sheet" "^5.1.1"
dayjs "1.10.5"
Expand Down
3 changes: 1 addition & 2 deletions package/native-package/src/optionalDependencies/FlatList.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { FlatList as DefaultFlatList, Platform } from 'react-native';
let FlatList;


if (Platform.constants.reactNativeVersion.minor < 72) {
const upgradeLog =
"'@stream-io/flat-list-mvcp' is deprecated, please upgrade your react-native version to >0.71 to get same the benefits on the default FlatList and uninstall the package.";
"'@stream-io/flat-list-mvcp' is deprecated, please upgrade your react-native version to >0.71 to get same the benefits on the default FlatList and uninstall the package.";
try {
FlatList = require('@stream-io/flat-list-mvcp').FlatList;
console.log(upgradeLog);
Expand Down
8 changes: 4 additions & 4 deletions package/native-package/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3409,10 +3409,10 @@ statuses@~1.5.0:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==

stream-chat-react-native-core@6.6.7:
version "6.6.7"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.7.tgz#d887234af18890c3396f1b8b5f169d9b28a793ab"
integrity sha512-Xc/S92nUBSwfVPZqNjt/zNs/DJcRV1aRa/+yCSBCqjCwo0EuiWEP9yKy3xGxBkehNe4vaIDvkeREduA4dRUGpA==
stream-chat-react-native-core@6.6.8:
version "6.6.8"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.8.tgz#483ade63ba051426480ab2dfd8ab3b248b90ae88"
integrity sha512-F8S70DHaiit6BEdKOkSMHq2bjMONhrouvJ+szBQuE430EJDgUlc2VErHk3yJCzqIt5lwfVZktjHuqSIOGVg5LQ==
dependencies:
"@gorhom/bottom-sheet" "^5.1.1"
dayjs "1.10.5"
Expand Down
15 changes: 7 additions & 8 deletions package/src/components/Attachment/AudioAttachment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import { useTheme } from '../../contexts';
import { useAudioPlayer } from '../../hooks/useAudioPlayer';
import { Audio, Pause, Play } from '../../icons';
import {
NativeHandlers,
PlaybackStatus,
SDK,
Sound,
SoundReturnType,
VideoPayloadData,
VideoProgressData,
Expand Down Expand Up @@ -51,7 +50,7 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
testID,
} = props;
const { changeAudioSpeed, pauseAudio, playAudio, seekAudio } = useAudioPlayer({ soundRef });
const isExpoCLI = SDK === 'stream-chat-expo';
const isExpoCLI = NativeHandlers.SDK === 'stream-chat-expo';
const isVoiceRecording = item.type === FileTypes.VoiceRecording;

/** This is for Native CLI Apps */
Expand Down Expand Up @@ -181,8 +180,8 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
useEffect(() => {
if (isExpoCLI) {
const initiateSound = async () => {
if (item && item.file && item.file.uri) {
soundRef.current = await Sound.initializeSound(
if (item && item.file && item.file.uri && NativeHandlers.Sound?.initializeSound) {
soundRef.current = await NativeHandlers.Sound.initializeSound(
{ uri: item.file.uri },
{
progressUpdateIntervalMillis: 100,
Expand Down Expand Up @@ -216,7 +215,7 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
}
};
// For expo CLI
if (!Sound.Player) {
if (!NativeHandlers.Sound?.Player) {
initalPlayPause();
}
}, [item.paused, isExpoCLI, pauseAudio, playAudio]);
Expand Down Expand Up @@ -344,8 +343,8 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
</View>
)}
</View>
{Sound.Player && (
<Sound.Player
{NativeHandlers.Sound?.Player && (
<NativeHandlers.Sound.Player
onEnd={handleEnd}
onLoad={handleLoad}
onProgress={handleProgress}
Expand Down
11 changes: 6 additions & 5 deletions package/src/components/AttachmentPicker/AttachmentPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from '../../contexts/attachmentPickerContext/AttachmentPickerContext';
import { useTheme } from '../../contexts/themeContext/ThemeContext';
import { useScreenDimensions } from '../../hooks/useScreenDimensions';
import { getPhotos, oniOS14GalleryLibrarySelectionChange } from '../../native';
import { NativeHandlers } from '../../native';
import type { Asset } from '../../types/types';
import { BottomSheet } from '../BottomSheetCompatibility/BottomSheet';
import { BottomSheetFlatList } from '../BottomSheetCompatibility/BottomSheetFlatList';
Expand Down Expand Up @@ -122,11 +122,12 @@ export const AttachmentPicker = React.forwardRef(
setLoadingPhotos(true);
const endCursor = endCursorRef.current;
try {
if (!getPhotos) {
if (!NativeHandlers.getPhotos) {
setPhotos([]);
setIosLimited(false);
return;
}
const results = await getPhotos({
const results = await NativeHandlers.getPhotos({
after: endCursor,
first: numberOfAttachmentImagesToLoadPerCall ?? 60,
});
Expand All @@ -153,11 +154,11 @@ export const AttachmentPicker = React.forwardRef(
return;
}

if (!oniOS14GalleryLibrarySelectionChange) {
if (!NativeHandlers.oniOS14GalleryLibrarySelectionChange) {
return;
}
// ios 14 library selection change event is fired when user reselects the images that are permitted to be readable by the app
const { unsubscribe } = oniOS14GalleryLibrarySelectionChange(() => {
const { unsubscribe } = NativeHandlers.oniOS14GalleryLibrarySelectionChange(() => {
// we reset the cursor and has next page to true to facilitate fetching of the first page of photos again
hasNextPageRef.current = true;
endCursorRef.current = undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Pressable, StyleSheet, Text } from 'react-native';

import { useTheme } from '../../../contexts/themeContext/ThemeContext';
import { useTranslationContext } from '../../../contexts/translationContext/TranslationContext';
import { iOS14RefreshGallerySelection } from '../../../native';
import { NativeHandlers } from '../../../native';

export const AttachmentPickerIOSSelectMorePhotos = () => {
const { t } = useTranslationContext();
Expand All @@ -13,13 +13,13 @@ export const AttachmentPickerIOSSelectMorePhotos = () => {
},
} = useTheme();

if (!iOS14RefreshGallerySelection) {
if (!NativeHandlers.iOS14RefreshGallerySelection) {
return null;
}

return (
<Pressable
onPress={iOS14RefreshGallerySelection}
onPress={NativeHandlers.iOS14RefreshGallerySelection}
style={[styles.container, { backgroundColor: white }]}
>
<Text style={[styles.text, { color: accent_blue }]}>{t<string>('Select More Photos')}</Text>
Expand Down
4 changes: 2 additions & 2 deletions package/src/components/Channel/Channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ import {
WutReaction,
} from '../../icons';
import {
FlatList as FlatListDefault,
isDocumentPickerAvailable,
isImageMediaLibraryAvailable,
isImagePickerAvailable,
NativeHandlers,
} from '../../native';
import * as dbApi from '../../store/apis';
import { ChannelUnreadState, DefaultStreamChatGenerics, FileTypes } from '../../types/types';
Expand Down Expand Up @@ -538,7 +538,7 @@ const ChannelWithContext = <
FileAttachmentGroup = FileAttachmentGroupDefault,
FileAttachmentIcon = FileIconDefault,
FileUploadPreview = FileUploadPreviewDefault,
FlatList = FlatListDefault,
FlatList = NativeHandlers.FlatList,
forceAlignMessages,
Gallery = GalleryDefault,
getMessagesGroupStyles,
Expand Down
8 changes: 4 additions & 4 deletions package/src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
import { useStreami18n } from '../../hooks/useStreami18n';
import init from '../../init';

import { SDK } from '../../native';
import { NativeHandlers } from '../../native';
import { SqliteClient } from '../../store/SqliteClient';
import type { DefaultStreamChatGenerics } from '../../types/types';
import { DBSyncManager } from '../../utils/DBSyncManager';
Expand Down Expand Up @@ -187,9 +187,9 @@ const ChatWithContext = <

useEffect(() => {
if (client) {
const sdkName = (SDK ? SDK.replace('stream-chat-', '') : 'react-native') as
| 'react-native'
| 'expo';
const sdkName = (
NativeHandlers.SDK ? NativeHandlers.SDK.replace('stream-chat-', '') : 'react-native'
) as 'react-native' | 'expo';
client.sdkIdentifier = {
name: sdkName,
version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ jest.mock('../../../native.ts', () => {
isImageMediaLibraryAvailable: jest.fn(() => true),
isShareImageAvailable: jest.fn(() => true),
isVideoPlayerAvailable: jest.fn(() => true),
Video: View,
NativeHandlers: {
Video: View,
},
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@ import {
} from '../../../mock-builders/generator/attachment';
import { generateMessage } from '../../../mock-builders/generator/message';
import { getTestClientWithUser } from '../../../mock-builders/mock';
import * as NativeUtils from '../../../native';
import { NativeHandlers } from '../../../native';
import type { DefaultStreamChatGenerics } from '../../../types/types';
import type { MessageType } from '../../MessageList/hooks/useMessageList';
import { ImageGallery, ImageGalleryCustomComponents } from '../ImageGallery';

jest.mock('../../../native.ts', () => {
const View = require('react-native/Libraries/Components/View/View');
return {
deleteFile: jest.fn(),
isFileSystemAvailable: jest.fn(() => true),
isImageMediaLibraryAvailable: jest.fn(() => true),
isShareImageAvailable: jest.fn(() => true),
isVideoPlayerAvailable: jest.fn(() => true),
saveFile: jest.fn(),
shareImage: jest.fn(),
Video: View,
NativeHandlers: {
deleteFile: jest.fn(),
saveFile: jest.fn(),
shareImage: jest.fn(),
Video: View,
},
};
});

Expand Down Expand Up @@ -160,9 +162,9 @@ describe('ImageGalleryFooter', () => {
it('should trigger the share button onPress Handler', async () => {
const user = userEvent.setup();
const chatClient = await getTestClientWithUser({ id: 'testID' });
const saveFileMock = jest.spyOn(NativeUtils, 'saveFile');
const shareImageMock = jest.spyOn(NativeUtils, 'shareImage');
const deleteFileMock = jest.spyOn(NativeUtils, 'deleteFile');
const saveFileMock = jest.spyOn(NativeHandlers, 'saveFile');
const shareImageMock = jest.spyOn(NativeHandlers, 'shareImage');
const deleteFileMock = jest.spyOn(NativeHandlers, 'deleteFile');

render(
<OverlayProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ jest.mock('../../../native.ts', () => {
isImageMediaLibraryAvailable: jest.fn(() => true),
isShareImageAvailable: jest.fn(() => true),
isVideoPlayerAvailable: jest.fn(() => true),
Video: View,
NativeHandlers: {
Video: View,
},
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import Animated, { SharedValue } from 'react-native-reanimated';

import {
isVideoPlayerAvailable,
NativeHandlers,
PlaybackStatus,
Video,
VideoPayloadData,
VideoProgressData,
VideoType,
Expand Down Expand Up @@ -156,8 +156,8 @@ export const AnimatedGalleryVideo = React.memo(

return (
<Animated.View accessibilityLabel='Image Gallery Video' style={[...animatedStyles, style]}>
{isVideoPlayerAvailable() ? (
<Video
{isVideoPlayerAvailable() && NativeHandlers.Video ? (
<NativeHandlers.Video
onBuffer={onBuffer}
onEnd={onEnd}
onLoad={onLoad}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ import { useTheme } from '../../../contexts/themeContext/ThemeContext';
import { useTranslationContext } from '../../../contexts/translationContext/TranslationContext';
import { Grid as GridIconDefault, Share as ShareIconDefault } from '../../../icons';
import {
deleteFile,
isFileSystemAvailable,
isShareImageAvailable,
saveFile,
shareImage,
NativeHandlers,
VideoType,
} from '../../../native';

Expand Down Expand Up @@ -138,19 +136,19 @@ export const ImageGalleryFooterWithContext = <
const share = async () => {
setShareMenuOpen(true);
try {
if (!shareImage || !deleteFile) {
if (!NativeHandlers.shareImage || !NativeHandlers.deleteFile) {
return;
}
const extension = photo.mime_type?.split('/')[1] || 'jpg';
const localFile = await saveFile({
const localFile = await NativeHandlers.saveFile({
fileName: `${photo.user?.id || 'ChatPhoto'}-${
photo.messageId
}-${selectedIndex}.${extension}`,
fromUrl: photo.uri,
});
// `image/jpeg` is added for the case where the mime_type isn't available for a file/image
await shareImage({ type: photo.mime_type || 'image/jpeg', url: localFile });
await deleteFile({ uri: localFile });
await NativeHandlers.shareImage({ type: photo.mime_type || 'image/jpeg', url: localFile });
await NativeHandlers.deleteFile({ uri: localFile });
} catch (error) {
console.log(error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {

import { useImageGalleryContext } from '../../../contexts/imageGalleryContext/ImageGalleryContext';
import { useOverlayContext } from '../../../contexts/overlayContext/OverlayContext';
import { triggerHaptic } from '../../../native';
import { NativeHandlers } from '../../../native';

export enum HasPinched {
FALSE = 0,
Expand Down Expand Up @@ -453,6 +453,8 @@ export const useImageGalleryGestures = ({
.simultaneousWithExternalGesture(pinchRef)
.withRef(panRef);

const triggerHaptic = NativeHandlers.triggerHaptic;

/**
* On pinch is run when two or more fingers touch the screen, it then takes over
* all touch handling even if the number of fingers is reduced to one until the
Expand Down
4 changes: 2 additions & 2 deletions package/src/components/Message/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
useTranslationContext,
} from '../../contexts/translationContext/TranslationContext';

import { isVideoPlayerAvailable, triggerHaptic } from '../../native';
import { isVideoPlayerAvailable, NativeHandlers } from '../../native';
import { DefaultStreamChatGenerics, FileTypes } from '../../types/types';
import {
hasOnlyEmojis,
Expand Down Expand Up @@ -623,7 +623,7 @@ const MessageWithContext = <
setIsBounceDialogOpen(true);
return;
}
triggerHaptic('impactMedium');
NativeHandlers.triggerHaptic('impactMedium');
showMessageOverlay();
};

Expand Down
Loading
Loading