- [`expo-av`](https://docs.expo.dev/versions/latest/sdk/av/) for Video and Audio playback, recording and async audio messages support.
+- [`expo-image-picker`](https://docs.expo.dev/versions/latest/sdk/imagepicker/) to capture images to attach them in the message.
- [`expo-sharing`](https://docs.expo.dev/versions/latest/sdk/sharing/) for Attachments sharing support.
- [`expo-haptics`](https://docs.expo.dev/versions/latest/sdk/haptics/) for user haptics support.
- [`expo-clipboard`](https://docs.expo.dev/versions/latest/sdk/clipboard/) for Copy message support.
diff --git a/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_camera_picker.mdx b/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_camera_picker.mdx
new file mode 100644
index 0000000000..5896a258d5
--- /dev/null
+++ b/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_camera_picker.mdx
@@ -0,0 +1,5 @@
+Enable the file picker on the [`MessageInput`](../../../../ui-components/message-input.mdx) component.
+
+| Type | Default |
+| ------- | ------- |
+| Boolean | `true` |
diff --git a/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_file_picker.mdx b/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_file_picker.mdx
index a3b9425550..5896a258d5 100644
--- a/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_file_picker.mdx
+++ b/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_file_picker.mdx
@@ -2,4 +2,4 @@ Enable the file picker on the [`MessageInput`](../../../../ui-components/message
| Type | Default |
| ------- | ------- |
-| boolean | true |
+| Boolean | `true` |
diff --git a/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_image_picker.mdx b/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_image_picker.mdx
index e9689e1787..999c8f1ce5 100644
--- a/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_image_picker.mdx
+++ b/docusaurus/docs/reactnative/common-content/ui-components/channel/props/has_image_picker.mdx
@@ -2,4 +2,4 @@ Enable the image picker on the [`MessageInput`](../../../../ui-components/messag
| Type | Default |
| ------- | ------- |
-| boolean | true |
+| Boolean | `true` |
diff --git a/docusaurus/docs/reactnative/contexts/message-input-context.mdx b/docusaurus/docs/reactnative/contexts/message-input-context.mdx
index dba4f6f94d..0b1b4d3111 100644
--- a/docusaurus/docs/reactnative/contexts/message-input-context.mdx
+++ b/docusaurus/docs/reactnative/contexts/message-input-context.mdx
@@ -26,6 +26,7 @@ import DoDocUploadRequest from '../common-content/ui-components/channel/props/do
import DoImageUploadRequest from '../common-content/ui-components/channel/props/do_image_upload_request.mdx';
import EmojiSearchIndex from '../common-content/ui-components/channel/props/emoji_search_index.mdx';
import FileUploadPreview from '../common-content/ui-components/channel/props/file_upload_preview.mdx';
+import HasCameraPicker from '../common-content/ui-components/channel/props/has_camera_picker.mdx';
import HasCommands from '../common-content/ui-components/channel/props/has_commands.mdx';
import HasFilePicker from '../common-content/ui-components/channel/props/has_file_picker.mdx';
import HasImagePicker from '../common-content/ui-components/channel/props/has_image_picker.mdx';
@@ -182,15 +183,19 @@ const { sendMessage, toggleAttachmentPicker } = useMessageInputContext();
+### _forwarded from [Channel](../../core-components/channel#hascamerapicker)_ props
`hasCameraPicker` {#hascamerapicker}
+
+
+
### _forwarded from [Channel](../../core-components/channel#hascommands)_ props
`hasCommands` {#hascommands}
-### _forwarded from [Channel](../../core-components/channel#hasfilepicker)_ props
hasFilePicker {#hasfilepicker}
+### _forwarded from [Channel](../../core-components/channel#hasfilepicker)_ props
`hasFilePicker` {#hasfilepicker}
-### _forwarded from [Channel](../../core-components/channel#hasimagepicker)_ props
hasImagePicker {#hasimagepicker}
+### _forwarded from [Channel](../../core-components/channel#hasimagepicker)_ props
`hasImagePicker` {#hasimagepicker}
diff --git a/docusaurus/docs/reactnative/core-components/channel.mdx b/docusaurus/docs/reactnative/core-components/channel.mdx
index 9352e0f8f4..87fadbd253 100644
--- a/docusaurus/docs/reactnative/core-components/channel.mdx
+++ b/docusaurus/docs/reactnative/core-components/channel.mdx
@@ -74,6 +74,7 @@ import HandleQuotedReply from '../common-content/ui-components/channel/props/han
import HandleReaction from '../common-content/ui-components/channel/props/handle_reaction.mdx';
import HandleRetry from '../common-content/ui-components/channel/props/handle_retry.mdx';
import HandleThreadReply from '../common-content/ui-components/channel/props/handle_thread_reply.mdx';
+import HasCameraPicker from '../common-content/ui-components/channel/props/has_camera_picker.mdx';
import HasCommands from '../common-content/ui-components/channel/props/has_commands.mdx';
import HasFilePicker from '../common-content/ui-components/channel/props/has_file_picker.mdx';
import HasImagePicker from '../common-content/ui-components/channel/props/has_image_picker.mdx';
@@ -524,6 +525,10 @@ The max allowable is 255, which when reached displays as `255+`.
+### `hasCameraPicker`
+
+
+
### `hasCommands`
diff --git a/examples/SampleApp/ios/Podfile.lock b/examples/SampleApp/ios/Podfile.lock
index 4beb2a4589..0ecce10855 100644
--- a/examples/SampleApp/ios/Podfile.lock
+++ b/examples/SampleApp/ios/Podfile.lock
@@ -1240,15 +1240,15 @@ PODS:
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- - RNImageCropPicker (0.39.0):
+ - RNImageCropPicker (0.41.2):
- React-Core
- React-RCTImage
- - RNImageCropPicker/QBImagePickerController (= 0.39.0)
- - TOCropViewController
- - RNImageCropPicker/QBImagePickerController (0.39.0):
+ - RNImageCropPicker/QBImagePickerController (= 0.41.2)
+ - TOCropViewController (~> 2.7.4)
+ - RNImageCropPicker/QBImagePickerController (0.41.2):
- React-Core
- React-RCTImage
- - TOCropViewController
+ - TOCropViewController (~> 2.7.4)
- RNNotifee (7.8.2):
- React-Core
- RNNotifee/NotifeeCore (= 7.8.2)
@@ -1276,7 +1276,7 @@ PODS:
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.10)
- SocketRocket (0.6.1)
- - TOCropViewController (2.6.1)
+ - TOCropViewController (2.7.4)
- Yoga (1.14.0)
DEPENDENCIES:
@@ -1608,7 +1608,7 @@ SPEC CHECKSUMS:
RNFBMessaging: 9b16c72d001787aca05e2fb997e5c979b821dbb4
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 2e3251b41d462552997c61afd680220d019fea65
- RNImageCropPicker: 14fe1c29298fb4018f3186f455c475ab107da332
+ RNImageCropPicker: 771e2ca319d2cf92e04ebf334ece892ee9a6728f
RNNotifee: 8e2d3df3f0e9ce8f5d1fe4c967431138190b6175
RNReactNativeHapticFeedback: afa5bf2794aecbb2dba2525329253da0d66656df
RNReanimated: 440ca83ef0a79a3376455663fc4a01300e131240
@@ -1618,7 +1618,7 @@ SPEC CHECKSUMS:
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
- TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
+ TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
Yoga: 9e6a04eacbd94f97d94577017e9f23b3ab41cf6c
PODFILE CHECKSUM: 751ee2c534898a790da0a7dba7d623f1f21ae757
diff --git a/examples/SampleApp/package.json b/examples/SampleApp/package.json
index b008442742..07f2f72b5a 100644
--- a/examples/SampleApp/package.json
+++ b/examples/SampleApp/package.json
@@ -42,7 +42,7 @@
"react-native-fs": "^2.18.0",
"react-native-gesture-handler": "^2.14.0",
"react-native-haptic-feedback": "2.0.3",
- "react-native-image-crop-picker": "0.39.0",
+ "react-native-image-crop-picker": "^0.41.2",
"react-native-image-resizer": "1.4.5",
"react-native-markdown-package": "1.8.2",
"react-native-quick-sqlite": "8.0.2",
diff --git a/examples/SampleApp/yarn.lock b/examples/SampleApp/yarn.lock
index 11d050a942..0c77c13a81 100644
--- a/examples/SampleApp/yarn.lock
+++ b/examples/SampleApp/yarn.lock
@@ -6203,10 +6203,10 @@ react-native-haptic-feedback@2.0.3:
resolved "https://registry.yarnpkg.com/react-native-haptic-feedback/-/react-native-haptic-feedback-2.0.3.tgz#09133b2175503831c04798cb0dc63ae91e3959c1"
integrity sha512-7+qvcxXZts/hA+HOOIFyM1x9m9fn/TJVSTgXaoQ8uT4gLc97IMvqHQ559tDmnlth+hHMzd3HRMpmRLWoKPL0DA==
-react-native-image-crop-picker@0.39.0:
- version "0.39.0"
- resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.39.0.tgz#9cb8e8ffb0e8ab06f7b3227cadf077169e225eba"
- integrity sha512-4aANbQMrmU6zN/4b0rVBA7SbaZ3aa5JESm3Xk751sINybZMt1yz/9h95LkO7U0pbslHDo3ofXjG75PmQRP6a/w==
+react-native-image-crop-picker@^0.41.2:
+ version "0.41.2"
+ resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.41.2.tgz#824fa8fee8391fbb3e0b5ae2973221a2dff0cafb"
+ integrity sha512-GcDu/adXU/1y/MrxsbOfqcGRGWC2pTttt5VGy/jyRJ6GXfoC29fTQf8SG5kGtc5schSR6K+mKYO4uW6eJPljlQ==
react-native-image-resizer@1.4.5:
version "1.4.5"
diff --git a/examples/TypeScriptMessaging/ios/Podfile.lock b/examples/TypeScriptMessaging/ios/Podfile.lock
index a425bc4bab..f12cb8d8c9 100644
--- a/examples/TypeScriptMessaging/ios/Podfile.lock
+++ b/examples/TypeScriptMessaging/ios/Podfile.lock
@@ -1148,15 +1148,15 @@ PODS:
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- - RNImageCropPicker (0.39.0):
+ - RNImageCropPicker (0.41.2):
- React-Core
- React-RCTImage
- - RNImageCropPicker/QBImagePickerController (= 0.39.0)
- - TOCropViewController
- - RNImageCropPicker/QBImagePickerController (0.39.0):
+ - RNImageCropPicker/QBImagePickerController (= 0.41.2)
+ - TOCropViewController (~> 2.7.4)
+ - RNImageCropPicker/QBImagePickerController (0.41.2):
- React-Core
- React-RCTImage
- - TOCropViewController
+ - TOCropViewController (~> 2.7.4)
- RNReactNativeHapticFeedback (2.0.3):
- React-Core
- RNReanimated (3.7.1):
@@ -1173,7 +1173,7 @@ PODS:
- RNSVG (14.1.0):
- React-Core
- SocketRocket (0.6.1)
- - TOCropViewController (2.6.1)
+ - TOCropViewController (2.7.4)
- Yoga (1.14.0)
DEPENDENCIES:
@@ -1497,14 +1497,14 @@ SPEC CHECKSUMS:
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 67fb54b3e6ca338a8044e85cd6f340265aa41091
- RNImageCropPicker: 14fe1c29298fb4018f3186f455c475ab107da332
+ RNImageCropPicker: 771e2ca319d2cf92e04ebf334ece892ee9a6728f
RNReactNativeHapticFeedback: afa5bf2794aecbb2dba2525329253da0d66656df
RNReanimated: 15a855719335a6b655a214531e86d806edfd49da
RNScreens: 17e2f657f1b09a71ec3c821368a04acbb7ebcb46
RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c
RNSVG: ba3e7232f45e34b7b47e74472386cf4e1a676d0a
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
- TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
+ TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
Yoga: d17d2cc8105eed528474683b42e2ea310e1daf61
PODFILE CHECKSUM: 90406e1e85c82b37484f5d746afa45c0637bb4b3
diff --git a/examples/TypeScriptMessaging/package.json b/examples/TypeScriptMessaging/package.json
index 144f1b3f1a..fa2978a261 100644
--- a/examples/TypeScriptMessaging/package.json
+++ b/examples/TypeScriptMessaging/package.json
@@ -26,7 +26,7 @@
"react-native-fs": "^2.18.0",
"react-native-gesture-handler": "^2.14.0",
"react-native-haptic-feedback": "^2.0.3",
- "react-native-image-crop-picker": "^0.39.0",
+ "react-native-image-crop-picker": "^0.41.2",
"react-native-image-resizer": "^1.4.5",
"react-native-quick-sqlite": "^8.0.2",
"react-native-reanimated": "^3.7.0",
diff --git a/examples/TypeScriptMessaging/yarn.lock b/examples/TypeScriptMessaging/yarn.lock
index 2ee4fc7e48..5101e89ff9 100644
--- a/examples/TypeScriptMessaging/yarn.lock
+++ b/examples/TypeScriptMessaging/yarn.lock
@@ -6325,10 +6325,10 @@ react-native-haptic-feedback@^2.0.3:
resolved "https://registry.yarnpkg.com/react-native-haptic-feedback/-/react-native-haptic-feedback-2.0.3.tgz#09133b2175503831c04798cb0dc63ae91e3959c1"
integrity sha512-7+qvcxXZts/hA+HOOIFyM1x9m9fn/TJVSTgXaoQ8uT4gLc97IMvqHQ559tDmnlth+hHMzd3HRMpmRLWoKPL0DA==
-react-native-image-crop-picker@^0.39.0:
- version "0.39.0"
- resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.39.0.tgz#9cb8e8ffb0e8ab06f7b3227cadf077169e225eba"
- integrity sha512-4aANbQMrmU6zN/4b0rVBA7SbaZ3aa5JESm3Xk751sINybZMt1yz/9h95LkO7U0pbslHDo3ofXjG75PmQRP6a/w==
+react-native-image-crop-picker@^0.41.2:
+ version "0.41.2"
+ resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.41.2.tgz#824fa8fee8391fbb3e0b5ae2973221a2dff0cafb"
+ integrity sha512-GcDu/adXU/1y/MrxsbOfqcGRGWC2pTttt5VGy/jyRJ6GXfoC29fTQf8SG5kGtc5schSR6K+mKYO4uW6eJPljlQ==
react-native-image-resizer@^1.4.5:
version "1.4.5"
diff --git a/package/expo-package/package.json b/package/expo-package/package.json
index b67e3908df..47ba406119 100644
--- a/package/expo-package/package.json
+++ b/package/expo-package/package.json
@@ -21,7 +21,7 @@
"expo-file-system": "*",
"expo-haptics": "*",
"expo-image-manipulator": "*",
- "expo-image-picker": ">=14.1.0",
+ "expo-image-picker": "*",
"expo-media-library": "*",
"expo-sharing": "*"
},
@@ -35,6 +35,9 @@
"expo-document-picker": {
"optional": true
},
+ "expo-image-picker": {
+ "optional": true
+ },
"expo-sharing": {
"optional": true
},
@@ -47,7 +50,6 @@
"expo": "^44.0.0",
"expo-file-system": "^11.0.2",
"expo-image-manipulator": "^9.1.0",
- "expo-image-picker": "^14.1.1",
"expo-media-library": "~15.2.3"
},
"scripts": {
diff --git a/package/expo-package/src/handlers/index.ts b/package/expo-package/src/handlers/index.ts
index 2518c330db..6f43860e50 100644
--- a/package/expo-package/src/handlers/index.ts
+++ b/package/expo-package/src/handlers/index.ts
@@ -8,5 +8,4 @@ export * from './NetInfo';
export * from './oniOS14GalleryLibrarySelectionChange';
export * from './saveFile';
export * from './Sound';
-export * from './takePhoto';
export * from './Video';
diff --git a/package/expo-package/src/handlers/takePhoto.ts b/package/expo-package/src/handlers/takePhoto.ts
deleted file mode 100644
index b30d351ef5..0000000000
--- a/package/expo-package/src/handlers/takePhoto.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { Image, Platform } from 'react-native';
-
-import * as ImagePicker from 'expo-image-picker';
-
-type Size = {
- height?: number;
- width?: number;
-};
-
-export const takePhoto = async ({ compressImageQuality = 1 }) => {
- try {
- const permissionCheck = await ImagePicker.getCameraPermissionsAsync();
- const canRequest = permissionCheck.canAskAgain;
- let permissionGranted = permissionCheck.granted;
- if (!permissionGranted) {
- if (canRequest) {
- const response = await ImagePicker.requestCameraPermissionsAsync();
- permissionGranted = response.granted;
- } else {
- return { askToOpenSettings: true, cancelled: true };
- }
- }
-
- if (permissionGranted) {
- const imagePickerSuccessResult = await ImagePicker.launchCameraAsync({
- quality: Math.min(Math.max(0, compressImageQuality), 1),
- });
- const canceled = imagePickerSuccessResult.canceled;
- const assets = imagePickerSuccessResult.assets;
- // since we only support single photo upload for now we will only be focusing on 0'th element.
- const photo = assets && assets[0];
-
- if (canceled === false && photo && photo.height && photo.width && photo.uri) {
- let size: Size = {};
- if (Platform.OS === 'android') {
- // Height and width returned by ImagePicker are incorrect on Android.
- // The issue is described in following github issue:
- // https://github.com/ivpusic/react-native-image-crop-picker/issues/901
- // This we can't rely on them as it is, and we need to use Image.getSize
- // to get accurate size.
- const getSize = (): Promise =>
- new Promise((resolve) => {
- Image.getSize(photo.uri, (width, height) => {
- resolve({ height, width });
- });
- });
-
- try {
- const { height, width } = await getSize();
- size.height = height;
- size.width = width;
- } catch (e) {
- console.warn('Error get image size of picture caputred from camera ', e);
- }
- } else {
- size = {
- height: photo.height,
- width: photo.width,
- };
- }
-
- return {
- cancelled: false,
- source: 'camera',
- uri: photo.uri,
- ...size,
- };
- }
- }
- } catch (error) {
- console.log(error);
- }
- return { cancelled: true };
-};
diff --git a/package/expo-package/src/index.js b/package/expo-package/src/index.js
index 818c0a53a6..a2c609b186 100644
--- a/package/expo-package/src/index.js
+++ b/package/expo-package/src/index.js
@@ -13,7 +13,6 @@ import {
oniOS14GalleryLibrarySelectionChange,
saveFile,
Sound,
- takePhoto,
Video,
} from './handlers';
@@ -21,6 +20,7 @@ import {
pickDocument,
setClipboardString,
shareImage,
+ takePhoto,
triggerHaptic,
} from './optionalDependencies';
diff --git a/package/expo-package/src/optionalDependencies/index.ts b/package/expo-package/src/optionalDependencies/index.ts
index 1dcd987add..d2114a319a 100644
--- a/package/expo-package/src/optionalDependencies/index.ts
+++ b/package/expo-package/src/optionalDependencies/index.ts
@@ -3,3 +3,4 @@ export * from './shareImage';
export * from './pickDocument';
export * from './triggerHaptic';
export * from './Video';
+export * from './takePhoto';
diff --git a/package/expo-package/src/optionalDependencies/takePhoto.ts b/package/expo-package/src/optionalDependencies/takePhoto.ts
new file mode 100644
index 0000000000..2fed2c85fa
--- /dev/null
+++ b/package/expo-package/src/optionalDependencies/takePhoto.ts
@@ -0,0 +1,88 @@
+import { Image, Platform } from 'react-native';
+
+let ImagePicker;
+
+try {
+ ImagePicker = require('expo-image-picker');
+} catch (e) {
+ // do nothing
+}
+
+if (!ImagePicker) {
+ console.log(
+ 'expo-image-picker is not installed. Installing this package will enable campturing photos through the app, and thereby send it.',
+ );
+}
+
+type Size = {
+ height?: number;
+ width?: number;
+};
+
+export const takePhoto = ImagePicker
+ ? async ({ compressImageQuality = 1 }) => {
+ try {
+ const permissionCheck = await ImagePicker.getCameraPermissionsAsync();
+ const canRequest = permissionCheck.canAskAgain;
+ let permissionGranted = permissionCheck.granted;
+ if (!permissionGranted) {
+ if (canRequest) {
+ const response = await ImagePicker.requestCameraPermissionsAsync();
+ permissionGranted = response.granted;
+ } else {
+ return { askToOpenSettings: true, cancelled: true };
+ }
+ }
+
+ if (permissionGranted) {
+ const imagePickerSuccessResult = await ImagePicker.launchCameraAsync({
+ quality: Math.min(Math.max(0, compressImageQuality), 1),
+ });
+ const canceled = imagePickerSuccessResult.canceled;
+ const assets = imagePickerSuccessResult.assets;
+ // since we only support single photo upload for now we will only be focusing on 0'th element.
+ const photo = assets && assets[0];
+
+ if (canceled === false && photo && photo.height && photo.width && photo.uri) {
+ let size: Size = {};
+ if (Platform.OS === 'android') {
+ // Height and width returned by ImagePicker are incorrect on Android.
+ // The issue is described in following github issue:
+ // https://github.com/ivpusic/react-native-image-crop-picker/issues/901
+ // This we can't rely on them as it is, and we need to use Image.getSize
+ // to get accurate size.
+ const getSize = (): Promise =>
+ new Promise((resolve) => {
+ Image.getSize(photo.uri, (width, height) => {
+ resolve({ height, width });
+ });
+ });
+
+ try {
+ const { height, width } = await getSize();
+ size.height = height;
+ size.width = width;
+ } catch (e) {
+ console.warn('Error get image size of picture caputred from camera ', e);
+ }
+ } else {
+ size = {
+ height: photo.height,
+ width: photo.width,
+ };
+ }
+
+ return {
+ cancelled: false,
+ source: 'camera',
+ uri: photo.uri,
+ ...size,
+ };
+ }
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ return { cancelled: true };
+ }
+ : null;
diff --git a/package/expo-package/yarn.lock b/package/expo-package/yarn.lock
index 1678f99bc7..95eb408586 100644
--- a/package/expo-package/yarn.lock
+++ b/package/expo-package/yarn.lock
@@ -1895,11 +1895,6 @@ expo-font@~10.0.5:
dependencies:
fontfaceobserver "^2.1.0"
-expo-image-loader@~4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/expo-image-loader/-/expo-image-loader-4.1.1.tgz#efadbb17de1861106864820194900f336dd641b6"
- integrity sha512-ciEHVokU0f6w0eTxdRxLCio6tskMsjxWIoV92+/ZD37qePUJYMfEphPhu1sruyvMBNR8/j5iyOvPFVGTfO8oxA==
-
expo-image-manipulator@^9.1.0:
version "9.2.2"
resolved "https://registry.yarnpkg.com/expo-image-manipulator/-/expo-image-manipulator-9.2.2.tgz#0fc7d2032972961c0a5fb49511d230fe0788fa6f"
@@ -1907,13 +1902,6 @@ expo-image-manipulator@^9.1.0:
dependencies:
expo-modules-core "~0.2.0"
-expo-image-picker@^14.1.1:
- version "14.1.1"
- resolved "https://registry.yarnpkg.com/expo-image-picker/-/expo-image-picker-14.1.1.tgz#181f1348ba6a43df7b87cee4a601d45c79b7c2d7"
- integrity sha512-SvWtnkLW7jp5Ntvk3lVcRQmhFYja8psmiR7O6P/+7S6f4llt3vaFwb4I3+pUXqJxxpi7BHc2+95qOLf0SFOIag==
- dependencies:
- expo-image-loader "~4.1.0"
-
expo-keep-awake@~10.0.2:
version "10.0.2"
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-10.0.2.tgz#706bda839782bb3e8ad4cbe43bde471a56368813"
@@ -2946,10 +2934,10 @@ stream-buffers@2.2.x:
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==
-stream-chat-react-native-core@5.33.0:
- version "5.33.0"
- resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-5.33.0.tgz#14f04de90cbc8db011bab8db3fa84abe2dc2eaec"
- integrity sha512-V9OJA9MrHzaCw5q16ZRbEktA1HamITbXPOkVZOjpDbb0OBcmedmOnD9C2NFIprc770lhllS/1MKBDr0GdQ9NXQ==
+stream-chat-react-native-core@5.33.1:
+ version "5.33.1"
+ resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-5.33.1.tgz#d9e7847469d3ffb6e7fd35fbb7b720f2e25d172e"
+ integrity sha512-TCDmChJe07cYyL3sErc6qycRFMA+HbflCKRGrFvVvpU0RdWJljaqiOo3avFSauciSnQxx9WxzTkMism8YsFHcQ==
dependencies:
"@gorhom/bottom-sheet" "4.4.8"
dayjs "1.10.5"
diff --git a/package/native-package/package.json b/package/native-package/package.json
index 22f17ea81f..05d391dc61 100644
--- a/package/native-package/package.json
+++ b/package/native-package/package.json
@@ -15,17 +15,17 @@
},
"peerDependencies": {
"@react-native-camera-roll/camera-roll": ">=5.0.0",
- "@react-native-community/netinfo": ">=2.0.7",
"@react-native-clipboard/clipboard": "^1.11.1",
+ "@react-native-community/netinfo": ">=2.0.7",
"@stream-io/flat-list-mvcp": "^0.10.3",
"react-native": ">=0.60.0",
+ "react-native-audio-recorder-player": ">=3.6.4",
"react-native-document-picker": ">=9.0.1",
"react-native-fs": ">=2.16.6",
"react-native-haptic-feedback": ">=1.11.0",
"react-native-image-crop-picker": ">=0.33.2",
"react-native-image-resizer": ">=1.4.2",
"react-native-share": ">=4.1.0",
- "react-native-audio-recorder-player": ">=3.6.4",
"react-native-video": ">=6.4.2"
},
"peerDependenciesMeta": {
@@ -41,6 +41,9 @@
"react-native-haptic-feedback": {
"optional": true
},
+ "react-native-image-crop-picker": {
+ "optional": true
+ },
"react-native-audio-recorder-player": {
"optional": true
},
@@ -58,7 +61,6 @@
"@stream-io/flat-list-mvcp": "0.10.3",
"react-native": ">=0.60.0",
"react-native-fs": ">=2.16.6",
- "react-native-image-crop-picker": "^0.38.0",
"react-native-image-resizer": ">=1.4.2"
}
}
diff --git a/package/native-package/src/handlers/index.ts b/package/native-package/src/handlers/index.ts
index 9c0e249db7..7d999e46f5 100644
--- a/package/native-package/src/handlers/index.ts
+++ b/package/native-package/src/handlers/index.ts
@@ -4,7 +4,6 @@ export * from './getLocalAssetUri';
export * from './getPhotos';
export * from './NetInfo';
export * from './saveFile';
-export * from './takePhoto';
export * from './Sound';
export * from './Video';
export * from './oniOS14GalleryLibrarySelectionChange';
diff --git a/package/native-package/src/handlers/takePhoto.ts b/package/native-package/src/handlers/takePhoto.ts
deleted file mode 100644
index 344b215291..0000000000
--- a/package/native-package/src/handlers/takePhoto.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { AppState, Image, PermissionsAndroid, Platform } from 'react-native';
-import ImagePicker from 'react-native-image-crop-picker';
-
-export const takePhoto = async ({ compressImageQuality = Platform.OS === 'ios' ? 0.8 : 1 }) => {
- if (Platform.OS === 'android') {
- const cameraPermissions = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.CAMERA);
- if (!cameraPermissions) {
- const androidPermissionStatus = await PermissionsAndroid.request(
- PermissionsAndroid.PERMISSIONS.CAMERA,
- );
- if (androidPermissionStatus === PermissionsAndroid.RESULTS.DENIED) {
- return { cancelled: true };
- } else if (androidPermissionStatus === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
- return { askToOpenSettings: true, cancelled: true };
- }
- }
- }
- try {
- const photo = await ImagePicker.openCamera({
- compressImageQuality: Math.min(Math.max(0, compressImageQuality), 1),
- });
- if (photo.height && photo.width && photo.path) {
- let size: { height?: number; width?: number } = {};
- if (Platform.OS === 'android') {
- // Height and width returned by ImagePicker are incorrect on Android.
- // The issue is described in following github issue:
- // https://github.com/ivpusic/react-native-image-crop-picker/issues/901
- // This we can't rely on them as it is, and we need to use Image.getSize
- // to get accurate size.
- const getSize = (): Promise<{ height: number; width: number }> =>
- new Promise((resolve) => {
- Image.getSize(photo.path, (width, height) => {
- resolve({ height, width });
- });
- });
-
- try {
- const { height, width } = await getSize();
- size.height = height;
- size.width = width;
- } catch (e) {
- // do nothing
- console.warn('Error get image size of picture caputred from camera ', e);
- }
- } else {
- size = {
- height: photo.height,
- width: photo.width,
- };
- }
- return {
- cancelled: false,
- source: 'camera',
- uri: photo.path,
- ...size,
- };
- }
- } catch (e: unknown) {
- if (e instanceof Error) {
- // on iOS: if it was in inactive state, then the user had just denied the permissions
- if (Platform.OS === 'ios' && AppState.currentState === 'active') {
- const cameraPermissionDeniedMsg = 'User did not grant camera permission.';
- // Open settings when the user did not allow camera permissions
- if (e.message === cameraPermissionDeniedMsg) {
- return { askToOpenSettings: true, cancelled: true };
- }
- }
- }
- }
-
- return { cancelled: true };
-};
diff --git a/package/native-package/src/index.js b/package/native-package/src/index.js
index 1c10124c3e..5dd66d0ca4 100644
--- a/package/native-package/src/index.js
+++ b/package/native-package/src/index.js
@@ -13,7 +13,6 @@ import {
oniOS14GalleryLibrarySelectionChange,
saveFile,
Sound,
- takePhoto,
Video,
} from './handlers';
@@ -22,6 +21,7 @@ import {
pickDocument,
setClipboardString,
shareImage,
+ takePhoto,
triggerHaptic,
} from './optionalDependencies';
diff --git a/package/native-package/src/optionalDependencies/index.ts b/package/native-package/src/optionalDependencies/index.ts
index fbb2228b1f..c4bf0a1242 100644
--- a/package/native-package/src/optionalDependencies/index.ts
+++ b/package/native-package/src/optionalDependencies/index.ts
@@ -4,3 +4,4 @@ export * from './Video';
export * from './triggerHaptic';
export * from './setClipboardString';
export * from './pickDocument';
+export * from './takePhoto';
diff --git a/package/native-package/src/optionalDependencies/takePhoto.ts b/package/native-package/src/optionalDependencies/takePhoto.ts
new file mode 100644
index 0000000000..33b2e694b8
--- /dev/null
+++ b/package/native-package/src/optionalDependencies/takePhoto.ts
@@ -0,0 +1,83 @@
+import { AppState, Image, PermissionsAndroid, Platform } from 'react-native';
+
+let ImagePicker;
+
+try {
+ ImagePicker = require('react-native-image-crop-picker').default;
+} catch (e) {
+ console.log('react-native-image-crop-picker is not installed');
+}
+
+export const takePhoto = ImagePicker
+ ? async ({ compressImageQuality = Platform.OS === 'ios' ? 0.8 : 1 }) => {
+ if (Platform.OS === 'android') {
+ const cameraPermissions = await PermissionsAndroid.check(
+ PermissionsAndroid.PERMISSIONS.CAMERA,
+ );
+ if (!cameraPermissions) {
+ const androidPermissionStatus = await PermissionsAndroid.request(
+ PermissionsAndroid.PERMISSIONS.CAMERA,
+ );
+ if (androidPermissionStatus === PermissionsAndroid.RESULTS.DENIED) {
+ return { cancelled: true };
+ } else if (androidPermissionStatus === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
+ return { askToOpenSettings: true, cancelled: true };
+ }
+ }
+ }
+ try {
+ const photo = await ImagePicker.openCamera({
+ compressImageQuality: Math.min(Math.max(0, compressImageQuality), 1),
+ });
+ if (photo.height && photo.width && photo.path) {
+ let size: { height?: number; width?: number } = {};
+ if (Platform.OS === 'android') {
+ // Height and width returned by ImagePicker are incorrect on Android.
+ // The issue is described in following github issue:
+ // https://github.com/ivpusic/react-native-image-crop-picker/issues/901
+ // This we can't rely on them as it is, and we need to use Image.getSize
+ // to get accurate size.
+ const getSize = (): Promise<{ height: number; width: number }> =>
+ new Promise((resolve) => {
+ Image.getSize(photo.path, (width, height) => {
+ resolve({ height, width });
+ });
+ });
+
+ try {
+ const { height, width } = await getSize();
+ size.height = height;
+ size.width = width;
+ } catch (e) {
+ // do nothing
+ console.warn('Error get image size of picture caputred from camera ', e);
+ }
+ } else {
+ size = {
+ height: photo.height,
+ width: photo.width,
+ };
+ }
+ return {
+ cancelled: false,
+ source: 'camera',
+ uri: photo.path,
+ ...size,
+ };
+ }
+ } catch (e: unknown) {
+ if (e instanceof Error) {
+ // on iOS: if it was in inactive state, then the user had just denied the permissions
+ if (Platform.OS === 'ios' && AppState.currentState === 'active') {
+ const cameraPermissionDeniedMsg = 'User did not grant camera permission.';
+ // Open settings when the user did not allow camera permissions
+ if (e.message === cameraPermissionDeniedMsg) {
+ return { askToOpenSettings: true, cancelled: true };
+ }
+ }
+ }
+ }
+
+ return { cancelled: true };
+ }
+ : null;
diff --git a/package/native-package/yarn.lock b/package/native-package/yarn.lock
index 7dd2c23696..bfe6875815 100644
--- a/package/native-package/yarn.lock
+++ b/package/native-package/yarn.lock
@@ -3743,11 +3743,6 @@ react-native-gradle-plugin@^0.71.18:
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.18.tgz#20ef199bc85be32e45bb6cc069ec2e7dcb1a74a6"
integrity sha512-7F6bD7B8Xsn3JllxcwHhFcsl9aHIig47+3eN4IHFNqfLhZr++3ElDrcqfMzugM+niWbaMi7bJ0kAkAL8eCpdWg==
-react-native-image-crop-picker@^0.38.0:
- version "0.38.1"
- resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.38.1.tgz#5973b4a8b55835b987e6be2064de411e849ac005"
- integrity sha512-cF5UQnWplzHCeiCO+aiGS/0VomWaLmFf3nSsgTMPfY+8+99h8N/eHQvVdSF7RsGw50B8394wGeGyqHjjp8YRWw==
-
react-native-image-resizer@>=1.4.2:
version "1.4.5"
resolved "https://registry.yarnpkg.com/react-native-image-resizer/-/react-native-image-resizer-1.4.5.tgz#5a520aa8baa07638b1894a1d87d4d9a0945c8d58"
diff --git a/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx b/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx
index 12419744ff..c0dff1423a 100644
--- a/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx
+++ b/package/src/components/AttachmentPicker/components/AttachmentPickerSelectionBar.tsx
@@ -32,7 +32,8 @@ export const AttachmentPickerSelectionBar = () => {
} = useAttachmentPickerContext();
const { t } = useTranslationContext();
- const { compressImageQuality, hasFilePicker, imageUploads, pickFile } = useMessageInputContext();
+ const { compressImageQuality, hasCameraPicker, hasFilePicker, imageUploads, pickFile } =
+ useMessageInputContext();
const {
theme: {
@@ -88,7 +89,7 @@ export const AttachmentPickerSelectionBar = () => {
/>
- {hasFilePicker && (
+ {hasFilePicker ? (
{
/>
- )}
-
-
-
-
-
+ ) : null}
+ {hasCameraPicker ? (
+
+
+
+
+
+ ) : null}
);
};
diff --git a/package/src/components/Channel/Channel.tsx b/package/src/components/Channel/Channel.tsx
index e8bebdb225..9ee2f7152f 100644
--- a/package/src/components/Channel/Channel.tsx
+++ b/package/src/components/Channel/Channel.tsx
@@ -75,7 +75,7 @@ import {
ThumbsUpReaction,
WutReaction,
} from '../../icons';
-import { FlatList as FlatListDefault, pickDocument } from '../../native';
+import { FlatList as FlatListDefault, isImagePickerAvailable, pickDocument } from '../../native';
import * as dbApi from '../../store/apis';
import type { DefaultStreamChatGenerics } from '../../types/types';
import { addReactionToLocalState } from '../../utils/addReactionToLocalState';
@@ -491,6 +491,7 @@ const ChannelWithContext = <
handleReaction,
handleRetry,
handleThreadReply,
+ hasCameraPicker = isImagePickerAvailable(),
hasCommands = true,
// If pickDocument isn't available, default to hiding the file picker
hasFilePicker = pickDocument !== null,
@@ -2226,6 +2227,7 @@ const ChannelWithContext = <
editMessage,
emojiSearchIndex,
FileUploadPreview,
+ hasCameraPicker,
hasCommands,
hasFilePicker,
hasImagePicker,
diff --git a/package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts b/package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts
index 73722b706d..39235f0008 100644
--- a/package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts
+++ b/package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts
@@ -34,6 +34,7 @@ export const useCreateInputMessageInputContext = <
editMessage,
emojiSearchIndex,
FileUploadPreview,
+ hasCameraPicker,
hasCommands,
hasFilePicker,
hasImagePicker,
@@ -103,6 +104,7 @@ export const useCreateInputMessageInputContext = <
editMessage,
emojiSearchIndex,
FileUploadPreview,
+ hasCameraPicker,
hasCommands,
hasFilePicker,
hasImagePicker,
diff --git a/package/src/components/MessageInput/InputButtons.tsx b/package/src/components/MessageInput/InputButtons.tsx
index 9d24b12168..f4752e45b4 100644
--- a/package/src/components/MessageInput/InputButtons.tsx
+++ b/package/src/components/MessageInput/InputButtons.tsx
@@ -25,6 +25,7 @@ export type InputButtonsWithContextProps<
| 'AttachButton'
| 'CommandsButton'
| 'giphyActive'
+ | 'hasCameraPicker'
| 'hasCommands'
| 'hasFilePicker'
| 'hasImagePicker'
@@ -46,6 +47,7 @@ export const InputButtonsWithContext = <
AttachButton,
CommandsButton,
giphyActive,
+ hasCameraPicker,
hasCommands,
hasFilePicker,
hasImagePicker,
@@ -69,11 +71,11 @@ export const InputButtonsWithContext = <
return null;
}
- return !showMoreOptions && (hasImagePicker || hasFilePicker) && hasCommands ? (
+ return !showMoreOptions && (hasCameraPicker || hasImagePicker || hasFilePicker) && hasCommands ? (
setShowMoreOptions(true)} />
) : (
<>
- {(hasImagePicker || hasFilePicker) && ownCapabilities.uploadFile && (
+ {(hasCameraPicker || hasImagePicker || hasFilePicker) && ownCapabilities.uploadFile && (
@@ -95,6 +97,7 @@ const areEqual = {
const {
giphyActive: prevGiphyActive,
+ hasCameraPicker: prevHasCameraPicker,
hasCommands: prevHasCommands,
hasFilePicker: prevHasFilePicker,
hasImagePicker: prevHasImagePicker,
@@ -105,6 +108,7 @@ const areEqual = {
return {
isAudioPackageAvailable: jest.fn(() => true),
+ isImagePickerAvailable: jest.fn(() => true),
NetInfo: {
addEventListener: jest.fn(),
fetch: jest.fn(),
diff --git a/package/src/contexts/messageInputContext/MessageInputContext.tsx b/package/src/contexts/messageInputContext/MessageInputContext.tsx
index 385e9146da..a8b1dbd0ee 100644
--- a/package/src/contexts/messageInputContext/MessageInputContext.tsx
+++ b/package/src/contexts/messageInputContext/MessageInputContext.tsx
@@ -307,6 +307,8 @@ export type InputMessageInputContextValue<
*/
FileUploadPreview: React.ComponentType>;
+ /** When false, CameraSelectorIcon will be hidden */
+ hasCameraPicker: boolean;
/** When false, CommandsButton will be hidden */
hasCommands: boolean;
/** When false, FileSelectorIcon will be hidden */
diff --git a/package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts b/package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts
index a09a8737d7..32dc448416 100644
--- a/package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts
+++ b/package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts
@@ -40,6 +40,7 @@ export const useCreateMessageInputContext = <
FileUploadPreview,
fileUploads,
giphyActive,
+ hasCameraPicker,
hasCommands,
hasFilePicker,
hasImagePicker,
@@ -160,6 +161,7 @@ export const useCreateMessageInputContext = <
FileUploadPreview,
fileUploads,
giphyActive,
+ hasCameraPicker,
hasCommands,
hasFilePicker,
hasImagePicker,
diff --git a/package/src/native.ts b/package/src/native.ts
index 44ee874048..27311ce8f3 100644
--- a/package/src/native.ts
+++ b/package/src/native.ts
@@ -360,11 +360,11 @@ export const registerNativeHandlers = (handlers: Handlers) => {
Sound = handlers.Sound;
}
- if (handlers.takePhoto) {
+ if (handlers.takePhoto !== undefined) {
takePhoto = handlers.takePhoto;
}
- if (handlers.triggerHaptic) {
+ if (handlers.triggerHaptic !== undefined) {
triggerHaptic = handlers.triggerHaptic;
}
@@ -377,6 +377,7 @@ export const registerNativeHandlers = (handlers: Handlers) => {
}
};
+export const isImagePickerAvailable = () => !!takePhoto;
export const isVideoPackageAvailable = () => !!Video;
export const isAudioPackageAvailable = () => !!Sound.Player || !!Sound.initializeSound;
export const isRecordingPackageAvailable = () => !!Audio;