stream-chat-expo 5.4.4-beta.1 → 5.5.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +15 -2
- package/src/handlers/NetInfo.ts +43 -0
- package/src/handlers/Sound.ts +20 -0
- package/src/handlers/Video.tsx +16 -0
- package/src/handlers/compressImage.ts +14 -0
- package/src/handlers/deleteFile.ts +11 -0
- package/src/handlers/getLocalAssetUri.ts +10 -0
- package/src/handlers/getPhotos.ts +32 -0
- package/src/handlers/index.ts +13 -0
- package/src/handlers/pickDocument.ts +20 -0
- package/src/handlers/saveFile.ts +11 -0
- package/src/handlers/setClipboardString.ts +11 -0
- package/src/handlers/shareImage.ts +10 -0
- package/src/handlers/takePhoto.ts +63 -0
- package/src/handlers/triggerHaptic.ts +34 -0
- package/src/index.js +29 -244
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stream-chat-expo",
|
|
3
3
|
"description": "The official Expo SDK for Stream Chat, a service for building chat applications",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.5.0-beta.2",
|
|
5
5
|
"author": {
|
|
6
6
|
"company": "Stream.io Inc",
|
|
7
7
|
"name": "Stream.io Inc"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"main": "src/index.js",
|
|
11
11
|
"types": "types/index.d.ts",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"stream-chat-react-native-core": "5.
|
|
13
|
+
"stream-chat-react-native-core": "5.5.0-beta.2"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"@react-native-community/netinfo": "^6.0.0",
|
|
@@ -23,6 +23,19 @@
|
|
|
23
23
|
"expo-media-library": "^12.0.2",
|
|
24
24
|
"expo-sharing": "^9.1.2"
|
|
25
25
|
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@react-native-community/netinfo": "^6.0.0",
|
|
28
|
+
"expo": ">=44.0.0",
|
|
29
|
+
"expo-av": "^12.0.4",
|
|
30
|
+
"expo-clipboard": "^3.1.0",
|
|
31
|
+
"expo-document-picker": "^9.1.2",
|
|
32
|
+
"expo-file-system": "^11.0.2",
|
|
33
|
+
"expo-haptics": "^10.0.0",
|
|
34
|
+
"expo-image-manipulator": "^9.1.0",
|
|
35
|
+
"expo-image-picker": "^10.1.4",
|
|
36
|
+
"expo-media-library": "^12.0.2",
|
|
37
|
+
"expo-sharing": "^9.1.2"
|
|
38
|
+
},
|
|
26
39
|
"scripts": {
|
|
27
40
|
"prepack": " cp ../../README.md .",
|
|
28
41
|
"postpack": "rm README.md"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { default as OriginalNetInfo, NetInfoState } from '@react-native-community/netinfo';
|
|
2
|
+
|
|
3
|
+
export const NetInfo = {
|
|
4
|
+
addEventListener(listener) {
|
|
5
|
+
let unsubscribe;
|
|
6
|
+
// For NetInfo >= 3.x.x
|
|
7
|
+
if (OriginalNetInfo.fetch && typeof OriginalNetInfo.fetch === 'function') {
|
|
8
|
+
unsubscribe = OriginalNetInfo.addEventListener(({ isConnected, isInternetReachable }) => {
|
|
9
|
+
// Initialize with truthy value when internetReachable is still loading
|
|
10
|
+
// if it resolves to false, listener is triggered with false value and network
|
|
11
|
+
// status is updated
|
|
12
|
+
listener(isInternetReachable === null ? isConnected : isConnected && isInternetReachable);
|
|
13
|
+
});
|
|
14
|
+
return unsubscribe;
|
|
15
|
+
} else {
|
|
16
|
+
// For NetInfo < 3.x.x
|
|
17
|
+
unsubscribe = OriginalNetInfo.addEventListener('connectionChange', () => {
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
OriginalNetInfo.isConnected.fetch().then((isConnected: NetInfoState) => {
|
|
20
|
+
listener(isConnected);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return unsubscribe.remove;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
fetch() {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
// For NetInfo >= 3.x.x
|
|
30
|
+
if (OriginalNetInfo.fetch && typeof OriginalNetInfo.fetch === 'function') {
|
|
31
|
+
OriginalNetInfo.fetch().then(({ isConnected }) => {
|
|
32
|
+
resolve(isConnected);
|
|
33
|
+
}, reject);
|
|
34
|
+
} else {
|
|
35
|
+
// For NetInfo < 3.x.x
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
OriginalNetInfo.isConnected.fetch().then((isConnected: NetInfoState) => {
|
|
38
|
+
resolve(isConnected);
|
|
39
|
+
}, reject);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AudioComponent } from '../optionalDependencies/Video';
|
|
2
|
+
import type { AVPlaybackSource, AVPlaybackStatus, AVPlaybackStatusToSet } from 'expo-av';
|
|
3
|
+
|
|
4
|
+
export const Sound = {
|
|
5
|
+
initializeSound: AudioComponent
|
|
6
|
+
? async (
|
|
7
|
+
source: AVPlaybackSource,
|
|
8
|
+
initialStatus: AVPlaybackStatusToSet,
|
|
9
|
+
onPlaybackStatusUpdate: (playbackStatus: AVPlaybackStatus) => void,
|
|
10
|
+
) => {
|
|
11
|
+
const { sound } = await AudioComponent.Sound.createAsync(
|
|
12
|
+
source,
|
|
13
|
+
initialStatus,
|
|
14
|
+
onPlaybackStatusUpdate,
|
|
15
|
+
);
|
|
16
|
+
return sound;
|
|
17
|
+
}
|
|
18
|
+
: null,
|
|
19
|
+
Player: null,
|
|
20
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { VideoComponent } from '../optionalDependencies/Video';
|
|
2
|
+
|
|
3
|
+
export const Video = VideoComponent
|
|
4
|
+
? ({ onPlaybackStatusUpdate, paused, style, uri, videoRef }) => (
|
|
5
|
+
<VideoComponent
|
|
6
|
+
onPlaybackStatusUpdate={onPlaybackStatusUpdate}
|
|
7
|
+
ref={videoRef}
|
|
8
|
+
resizeMode='contain'
|
|
9
|
+
shouldPlay={!paused}
|
|
10
|
+
source={{
|
|
11
|
+
uri,
|
|
12
|
+
}}
|
|
13
|
+
style={[style]}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
: null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as ImageManipulator from 'expo-image-manipulator';
|
|
2
|
+
|
|
3
|
+
export const compressImage = async ({
|
|
4
|
+
compressImageQuality = 1,
|
|
5
|
+
uri,
|
|
6
|
+
}: {
|
|
7
|
+
compressImageQuality?: number;
|
|
8
|
+
uri: string;
|
|
9
|
+
}) => {
|
|
10
|
+
const { uri: compressedUri } = await ImageManipulator.manipulateAsync(uri, [], {
|
|
11
|
+
compress: Math.min(Math.max(0, compressImageQuality), 1),
|
|
12
|
+
});
|
|
13
|
+
return compressedUri;
|
|
14
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as FileSystem from 'expo-file-system';
|
|
2
|
+
|
|
3
|
+
export const deleteFile = async ({ uri }: { uri: string }) => {
|
|
4
|
+
try {
|
|
5
|
+
await FileSystem.deleteAsync(uri, { idempotent: true });
|
|
6
|
+
return true;
|
|
7
|
+
} catch (error) {
|
|
8
|
+
console.log('File deletion failed...');
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as MediaLibrary from 'expo-media-library';
|
|
2
|
+
|
|
3
|
+
export const getLocalAssetUri = async (assetId: string): Promise<string> => {
|
|
4
|
+
try {
|
|
5
|
+
const { localUri } = await MediaLibrary.getAssetInfoAsync(assetId);
|
|
6
|
+
return localUri;
|
|
7
|
+
} catch {
|
|
8
|
+
throw new Error('getLocalAssetUri Error');
|
|
9
|
+
}
|
|
10
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as MediaLibrary from 'expo-media-library';
|
|
2
|
+
|
|
3
|
+
export const getPhotos = async ({ after, first }: MediaLibrary.AssetsOptions) => {
|
|
4
|
+
try {
|
|
5
|
+
const { status } = await MediaLibrary.requestPermissionsAsync();
|
|
6
|
+
if (status !== 'granted') {
|
|
7
|
+
throw new Error('getPhotos Error');
|
|
8
|
+
}
|
|
9
|
+
const results = await MediaLibrary.getAssetsAsync({
|
|
10
|
+
after,
|
|
11
|
+
first,
|
|
12
|
+
mediaType: [MediaLibrary.MediaType.photo, MediaLibrary.MediaType.video],
|
|
13
|
+
sortBy: [MediaLibrary.SortBy.modificationTime],
|
|
14
|
+
});
|
|
15
|
+
const assets = results.assets.map((asset) => ({
|
|
16
|
+
duration: asset.duration,
|
|
17
|
+
filename: asset.filename,
|
|
18
|
+
height: asset.height,
|
|
19
|
+
id: asset.id,
|
|
20
|
+
source: 'picker',
|
|
21
|
+
type: asset.mediaType,
|
|
22
|
+
uri: asset.uri,
|
|
23
|
+
width: asset.width,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const hasNextPage = results.hasNextPage;
|
|
27
|
+
const endCursor = results.endCursor;
|
|
28
|
+
return { assets, endCursor, hasNextPage };
|
|
29
|
+
} catch {
|
|
30
|
+
throw new Error('getPhotos Error');
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './compressImage';
|
|
2
|
+
export * from './deleteFile';
|
|
3
|
+
export * from './getLocalAssetUri';
|
|
4
|
+
export * from './getPhotos';
|
|
5
|
+
export * from './NetInfo';
|
|
6
|
+
export * from './pickDocument';
|
|
7
|
+
export * from './saveFile';
|
|
8
|
+
export * from './setClipboardString';
|
|
9
|
+
export * from './shareImage';
|
|
10
|
+
export * from './Sound';
|
|
11
|
+
export * from './takePhoto';
|
|
12
|
+
export * from './triggerHaptic';
|
|
13
|
+
export * from './Video';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as DocumentPicker from 'expo-document-picker';
|
|
2
|
+
|
|
3
|
+
export const pickDocument = async () => {
|
|
4
|
+
try {
|
|
5
|
+
const { type, ...rest } = await DocumentPicker.getDocumentAsync();
|
|
6
|
+
if (type === 'cancel') {
|
|
7
|
+
return {
|
|
8
|
+
cancelled: true,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
cancelled: false,
|
|
13
|
+
docs: [rest],
|
|
14
|
+
};
|
|
15
|
+
} catch (err) {
|
|
16
|
+
return {
|
|
17
|
+
cancelled: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as FileSystem from 'expo-file-system';
|
|
2
|
+
|
|
3
|
+
export const saveFile = async ({ fileName, fromUrl }: { fileName: string; fromUrl: string }) => {
|
|
4
|
+
try {
|
|
5
|
+
const path = FileSystem.cacheDirectory + encodeURIComponent(fileName);
|
|
6
|
+
const downloadedImage = await FileSystem.downloadAsync(fromUrl, path);
|
|
7
|
+
return downloadedImage.uri;
|
|
8
|
+
} catch (error) {
|
|
9
|
+
throw new Error('Downloading image failed...');
|
|
10
|
+
}
|
|
11
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
let Clipboard: { setString: (string: string) => void } | undefined;
|
|
2
|
+
|
|
3
|
+
try {
|
|
4
|
+
Clipboard = require('expo-clipboard');
|
|
5
|
+
console.log({ Clipboard });
|
|
6
|
+
} catch (e) {
|
|
7
|
+
// do nothing
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const setClipboardString =
|
|
11
|
+
Clipboard !== undefined ? (string: string) => Clipboard.setString(string) : null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as Sharing from 'expo-sharing';
|
|
2
|
+
|
|
3
|
+
export const shareImage = async ({ type, url }: { type: string; url: string }) => {
|
|
4
|
+
try {
|
|
5
|
+
await Sharing.shareAsync(url, { mimeType: type, UTI: type });
|
|
6
|
+
return true;
|
|
7
|
+
} catch (error) {
|
|
8
|
+
console.warn('Sharing failed or cancelled...');
|
|
9
|
+
}
|
|
10
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Image, Platform } from 'react-native';
|
|
2
|
+
import * as ImagePicker from 'expo-image-picker';
|
|
3
|
+
|
|
4
|
+
type Size = {
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const takePhoto = async ({ compressImageQuality = 1 }) => {
|
|
10
|
+
try {
|
|
11
|
+
const permissionCheck = await ImagePicker.getCameraPermissionsAsync();
|
|
12
|
+
const permissionGranted =
|
|
13
|
+
permissionCheck?.status === 'granted'
|
|
14
|
+
? permissionCheck
|
|
15
|
+
: await ImagePicker.requestCameraPermissionsAsync();
|
|
16
|
+
|
|
17
|
+
if (permissionGranted?.status === 'granted' || permissionGranted?.granted === true) {
|
|
18
|
+
const photo = await ImagePicker.launchCameraAsync({
|
|
19
|
+
quality: Math.min(Math.max(0, compressImageQuality), 1),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (photo.cancelled === false && photo.height && photo.width && photo.uri) {
|
|
23
|
+
let size: Size = {};
|
|
24
|
+
if (Platform.OS === 'android') {
|
|
25
|
+
// Height and width returned by ImagePicker are incorrect on Android.
|
|
26
|
+
// The issue is described in following github issue:
|
|
27
|
+
// https://github.com/ivpusic/react-native-image-crop-picker/issues/901
|
|
28
|
+
// This we can't rely on them as it is, and we need to use Image.getSize
|
|
29
|
+
// to get accurate size.
|
|
30
|
+
const getSize = (): Promise<Size> =>
|
|
31
|
+
new Promise((resolve) => {
|
|
32
|
+
Image.getSize(photo.uri, (width, height) => {
|
|
33
|
+
resolve({ height, width });
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const { height, width } = await getSize();
|
|
39
|
+
size.height = height;
|
|
40
|
+
size.width = width;
|
|
41
|
+
} catch (e) {
|
|
42
|
+
console.warn('Error get image size of picture caputred from camera ', e);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
size = {
|
|
46
|
+
height: photo.height,
|
|
47
|
+
width: photo.width,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
cancelled: false,
|
|
53
|
+
source: 'camera',
|
|
54
|
+
uri: photo.uri,
|
|
55
|
+
...size,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.log(error);
|
|
61
|
+
}
|
|
62
|
+
return { cancelled: true };
|
|
63
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as Haptics from 'expo-haptics';
|
|
2
|
+
|
|
3
|
+
type HapticFeedbackTypes =
|
|
4
|
+
| 'impactHeavy'
|
|
5
|
+
| 'impactLight'
|
|
6
|
+
| 'impactMedium'
|
|
7
|
+
| 'notificationError'
|
|
8
|
+
| 'notificationSuccess'
|
|
9
|
+
| 'notificationWarning';
|
|
10
|
+
|
|
11
|
+
export const triggerHaptic = (method: HapticFeedbackTypes) => {
|
|
12
|
+
switch (method) {
|
|
13
|
+
case 'impactHeavy':
|
|
14
|
+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
|
|
15
|
+
break;
|
|
16
|
+
case 'impactLight':
|
|
17
|
+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
|
18
|
+
break;
|
|
19
|
+
case 'impactMedium':
|
|
20
|
+
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
|
|
21
|
+
break;
|
|
22
|
+
case 'notificationError':
|
|
23
|
+
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
|
|
24
|
+
break;
|
|
25
|
+
case 'notificationSuccess':
|
|
26
|
+
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
|
27
|
+
break;
|
|
28
|
+
case 'notificationWarning':
|
|
29
|
+
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
|
|
30
|
+
break;
|
|
31
|
+
default:
|
|
32
|
+
Haptics.selectionAsync();
|
|
33
|
+
}
|
|
34
|
+
};
|
package/src/index.js
CHANGED
|
@@ -1,254 +1,39 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FlatList } from 'react-native';
|
|
2
2
|
|
|
3
|
-
import { FlatList, Image, Platform } from 'react-native';
|
|
4
|
-
|
|
5
|
-
import NetInfo from '@react-native-community/netinfo';
|
|
6
|
-
import * as DocumentPicker from 'expo-document-picker';
|
|
7
|
-
import * as FileSystem from 'expo-file-system';
|
|
8
|
-
import * as Haptics from 'expo-haptics';
|
|
9
|
-
import * as ImageManipulator from 'expo-image-manipulator';
|
|
10
|
-
import * as ImagePicker from 'expo-image-picker';
|
|
11
|
-
import * as MediaLibrary from 'expo-media-library';
|
|
12
|
-
import * as Sharing from 'expo-sharing';
|
|
13
3
|
import { registerNativeHandlers } from 'stream-chat-react-native-core';
|
|
14
4
|
|
|
15
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
compressImage,
|
|
7
|
+
deleteFile,
|
|
8
|
+
getLocalAssetUri,
|
|
9
|
+
getPhotos,
|
|
10
|
+
NetInfo,
|
|
11
|
+
pickDocument,
|
|
12
|
+
saveFile,
|
|
13
|
+
setClipboardString,
|
|
14
|
+
shareImage,
|
|
15
|
+
Sound,
|
|
16
|
+
takePhoto,
|
|
17
|
+
triggerHaptic,
|
|
18
|
+
Video,
|
|
19
|
+
} from './handlers';
|
|
16
20
|
|
|
17
21
|
registerNativeHandlers({
|
|
18
|
-
compressImage
|
|
19
|
-
|
|
20
|
-
compress: Math.min(Math.max(0, compressImageQuality), 1),
|
|
21
|
-
});
|
|
22
|
-
return compressedUri;
|
|
23
|
-
},
|
|
24
|
-
deleteFile: async ({ uri }) => {
|
|
25
|
-
try {
|
|
26
|
-
await FileSystem.deleteAsync(uri, { idempotent: true });
|
|
27
|
-
return true;
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.log('File deletion failed...');
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
},
|
|
22
|
+
compressImage,
|
|
23
|
+
deleteFile,
|
|
33
24
|
FlatList,
|
|
34
|
-
getLocalAssetUri
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
getPhotos: async ({ after, first }) => {
|
|
43
|
-
try {
|
|
44
|
-
const { status } = await MediaLibrary.requestPermissionsAsync();
|
|
45
|
-
if (status !== 'granted') {
|
|
46
|
-
throw new Error('getPhotos Error');
|
|
47
|
-
}
|
|
48
|
-
const results = await MediaLibrary.getAssetsAsync({
|
|
49
|
-
after,
|
|
50
|
-
first,
|
|
51
|
-
mediaType: [MediaLibrary.MediaType.photo, MediaLibrary.MediaType.video],
|
|
52
|
-
sortBy: [MediaLibrary.SortBy.modificationTime],
|
|
53
|
-
});
|
|
54
|
-
const assets = results.assets.map((asset) => ({
|
|
55
|
-
duration: asset.duration,
|
|
56
|
-
filename: asset.filename,
|
|
57
|
-
height: asset.height,
|
|
58
|
-
id: asset.id,
|
|
59
|
-
source: 'picker',
|
|
60
|
-
type: asset.mediaType,
|
|
61
|
-
uri: asset.uri,
|
|
62
|
-
width: asset.width,
|
|
63
|
-
}));
|
|
64
|
-
|
|
65
|
-
const hasNextPage = results.hasNextPage;
|
|
66
|
-
const endCursor = results.endCursor;
|
|
67
|
-
return { assets, endCursor, hasNextPage };
|
|
68
|
-
} catch {
|
|
69
|
-
throw new Error('getPhotos Error');
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
NetInfo: {
|
|
73
|
-
addEventListener(listener) {
|
|
74
|
-
let unsubscribe;
|
|
75
|
-
// For NetInfo >= 3.x.x
|
|
76
|
-
if (NetInfo.fetch && typeof NetInfo.fetch === 'function') {
|
|
77
|
-
unsubscribe = NetInfo.addEventListener(({ isConnected }) => {
|
|
78
|
-
listener(isConnected);
|
|
79
|
-
});
|
|
80
|
-
return unsubscribe;
|
|
81
|
-
} else {
|
|
82
|
-
// For NetInfo < 3.x.x
|
|
83
|
-
unsubscribe = NetInfo.addEventListener('connectionChange', () => {
|
|
84
|
-
NetInfo.isConnected.fetch().then((isConnected) => {
|
|
85
|
-
listener(isConnected);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
return unsubscribe.remove;
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
fetch() {
|
|
94
|
-
return new Promise((resolve, reject) => {
|
|
95
|
-
// For NetInfo >= 3.x.x
|
|
96
|
-
if (NetInfo.fetch && typeof NetInfo.fetch === 'function') {
|
|
97
|
-
NetInfo.fetch().then(({ isConnected }) => {
|
|
98
|
-
resolve(isConnected);
|
|
99
|
-
}, reject);
|
|
100
|
-
} else {
|
|
101
|
-
// For NetInfo < 3.x.x
|
|
102
|
-
NetInfo.isConnected.fetch().then((isConnected) => {
|
|
103
|
-
resolve(isConnected);
|
|
104
|
-
}, reject);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
pickDocument: async ({ maxNumberOfFiles }) => {
|
|
110
|
-
try {
|
|
111
|
-
const { type, ...rest } = await DocumentPicker.getDocumentAsync();
|
|
112
|
-
if (type === 'cancel') {
|
|
113
|
-
return {
|
|
114
|
-
cancelled: true,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
return {
|
|
118
|
-
cancelled: false,
|
|
119
|
-
docs: [rest],
|
|
120
|
-
};
|
|
121
|
-
} catch (err) {
|
|
122
|
-
return {
|
|
123
|
-
cancelled: true,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
saveFile: async ({ fileName, fromUrl }) => {
|
|
128
|
-
try {
|
|
129
|
-
const path = FileSystem.cacheDirectory + encodeURIComponent(fileName);
|
|
130
|
-
const downloadedImage = await FileSystem.downloadAsync(fromUrl, path);
|
|
131
|
-
return downloadedImage.uri;
|
|
132
|
-
} catch (error) {
|
|
133
|
-
throw new Error('Downloading image failed...');
|
|
134
|
-
}
|
|
135
|
-
},
|
|
25
|
+
getLocalAssetUri,
|
|
26
|
+
getPhotos,
|
|
27
|
+
NetInfo,
|
|
28
|
+
pickDocument,
|
|
29
|
+
saveFile,
|
|
30
|
+
setClipboardString,
|
|
136
31
|
SDK: 'stream-chat-expo',
|
|
137
|
-
shareImage
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
throw new Error('Sharing failed or cancelled...');
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
Sound: {
|
|
146
|
-
initializeSound: AudioComponent
|
|
147
|
-
? async (source, initialStatus, onPlaybackStatusUpdate) => {
|
|
148
|
-
const { sound } = await AudioComponent.Sound.createAsync(
|
|
149
|
-
source,
|
|
150
|
-
initialStatus,
|
|
151
|
-
onPlaybackStatusUpdate,
|
|
152
|
-
);
|
|
153
|
-
return sound;
|
|
154
|
-
}
|
|
155
|
-
: null,
|
|
156
|
-
Player: null,
|
|
157
|
-
},
|
|
158
|
-
takePhoto: async ({ compressImageQuality = 1 }) => {
|
|
159
|
-
try {
|
|
160
|
-
const permissionCheck = await ImagePicker.getCameraPermissionsAsync();
|
|
161
|
-
const permissionGranted =
|
|
162
|
-
permissionCheck?.status === 'granted'
|
|
163
|
-
? permissionCheck
|
|
164
|
-
: await ImagePicker.requestCameraPermissionsAsync();
|
|
165
|
-
|
|
166
|
-
if (permissionGranted?.status === 'granted' || permissionGranted?.granted === true) {
|
|
167
|
-
const photo = await ImagePicker.launchCameraAsync({
|
|
168
|
-
quality: Math.min(Math.max(0, compressImageQuality), 1),
|
|
169
|
-
});
|
|
170
|
-
if (photo.height && photo.width && photo.uri) {
|
|
171
|
-
let size = {};
|
|
172
|
-
if (Platform.OS === 'android') {
|
|
173
|
-
// Height and width returned by ImagePicker are incorrect on Android.
|
|
174
|
-
// The issue is described in following github issue:
|
|
175
|
-
// https://github.com/ivpusic/react-native-image-crop-picker/issues/901
|
|
176
|
-
// This we can't rely on them as it is, and we need to use Image.getSize
|
|
177
|
-
// to get accurate size.
|
|
178
|
-
const getSize = () =>
|
|
179
|
-
new Promise((resolve) => {
|
|
180
|
-
Image.getSize(photo.uri, (width, height) => {
|
|
181
|
-
resolve({ height, width });
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
const { height, width } = await getSize();
|
|
187
|
-
size.height = height;
|
|
188
|
-
size.width = width;
|
|
189
|
-
} catch (e) {
|
|
190
|
-
// do nothing
|
|
191
|
-
console.warning('Error get image size of picture caputred from camera ', e);
|
|
192
|
-
}
|
|
193
|
-
} else {
|
|
194
|
-
size = {
|
|
195
|
-
height: photo.height,
|
|
196
|
-
width: photo.width,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return {
|
|
201
|
-
cancelled: false,
|
|
202
|
-
source: 'camera',
|
|
203
|
-
uri: photo.uri,
|
|
204
|
-
...size,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
} catch (error) {
|
|
209
|
-
console.log(error);
|
|
210
|
-
}
|
|
211
|
-
return { cancelled: true };
|
|
212
|
-
},
|
|
213
|
-
triggerHaptic: (method) => {
|
|
214
|
-
switch (method) {
|
|
215
|
-
case 'impactHeavy':
|
|
216
|
-
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
|
|
217
|
-
break;
|
|
218
|
-
case 'impactLight':
|
|
219
|
-
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
|
220
|
-
break;
|
|
221
|
-
case 'impactMedium':
|
|
222
|
-
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
|
|
223
|
-
break;
|
|
224
|
-
case 'notificationError':
|
|
225
|
-
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
|
|
226
|
-
break;
|
|
227
|
-
case 'notificationSuccess':
|
|
228
|
-
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
|
229
|
-
break;
|
|
230
|
-
case 'notificationWarning':
|
|
231
|
-
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
|
|
232
|
-
break;
|
|
233
|
-
default:
|
|
234
|
-
Haptics.selectionAsync();
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
// eslint-disable-next-line react/display-name
|
|
238
|
-
Video: VideoComponent
|
|
239
|
-
? ({ onPlaybackStatusUpdate, paused, style, uri, videoRef }) => (
|
|
240
|
-
<VideoComponent
|
|
241
|
-
onPlaybackStatusUpdate={onPlaybackStatusUpdate}
|
|
242
|
-
ref={videoRef}
|
|
243
|
-
resizeMode='contain'
|
|
244
|
-
shouldPlay={!paused}
|
|
245
|
-
source={{
|
|
246
|
-
uri,
|
|
247
|
-
}}
|
|
248
|
-
style={[style]}
|
|
249
|
-
/>
|
|
250
|
-
)
|
|
251
|
-
: null,
|
|
32
|
+
shareImage,
|
|
33
|
+
Sound,
|
|
34
|
+
takePhoto,
|
|
35
|
+
triggerHaptic,
|
|
36
|
+
Video,
|
|
252
37
|
});
|
|
253
38
|
|
|
254
39
|
export * from 'stream-chat-react-native-core';
|