Skip to content

Commit 2fd794e

Browse files
committed
feat: add optional support for @react-native-documents/picker
1 parent 6c19b24 commit 2fd794e

File tree

4 files changed

+134
-15
lines changed

4 files changed

+134
-15
lines changed

packages/uikit-react-native/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"@react-native-camera-roll/camera-roll": "^7.8.1",
7272
"@react-native-clipboard/clipboard": "^1.14.1",
7373
"@react-native-community/netinfo": "^11.3.2",
74+
"@react-native-documents/picker": "^10.0.0",
7475
"@react-native-firebase/app": "^14.4.0",
7576
"@react-native-firebase/messaging": "^14.4.0",
7677
"@types/react": "*",
@@ -108,6 +109,7 @@
108109
"@react-native-camera-roll/camera-roll": ">=5.0.0",
109110
"@react-native-clipboard/clipboard": ">=1.8.5",
110111
"@react-native-community/netinfo": ">=9.3.0",
112+
"@react-native-documents/picker": ">=10.0.0",
111113
"@react-native-firebase/messaging": ">=14.4.0",
112114
"@sendbird/chat": "^4.16.0",
113115
"@sendbird/react-native-scrollview-enhancer": "*",
@@ -145,6 +147,9 @@
145147
"@react-native-clipboard/clipboard": {
146148
"optional": true
147149
},
150+
"@react-native-documents/picker": {
151+
"optional": true
152+
},
148153
"@react-native-firebase/messaging": {
149154
"optional": true
150155
},

packages/uikit-react-native/src/platform/createFileService.native.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { CameraRoll } from '@react-native-camera-roll/camera-roll';
22
import { Platform } from 'react-native';
3-
import type * as DocumentPicker from 'react-native-document-picker';
43
import type * as FileAccess from 'react-native-file-access';
54
import type * as ImagePicker from 'react-native-image-picker';
65
import type * as Permissions from 'react-native-permissions';
@@ -18,6 +17,7 @@ import {
1817
import SBUError from '../libs/SBUError';
1918
import nativePermissionGranted from '../utils/nativePermissionGranted';
2019
import normalizeFile from '../utils/normalizeFile';
20+
import { DocumentPicker, openDocument } from './openDocument.native';
2121
import type {
2222
FilePickerResponse,
2323
FileServiceInterface,
@@ -52,7 +52,7 @@ const createNativeFileService = ({
5252
fsModule,
5353
}: {
5454
imagePickerModule: typeof ImagePicker;
55-
documentPickerModule: typeof DocumentPicker;
55+
documentPickerModule: DocumentPicker;
5656
permissionModule: typeof Permissions;
5757
mediaLibraryModule: typeof CameraRoll;
5858
fsModule: typeof FileAccess;
@@ -78,17 +78,20 @@ const createNativeFileService = ({
7878
const status = await permissionModule.checkMultiple(requiredPermissions);
7979
return nativePermissionGranted(status);
8080
}
81+
8182
async requestCameraPermission(): Promise<boolean> {
8283
const requiredPermissionsStatus = await permissionModule.requestMultiple(requiredPermissions);
8384
if (!nativePermissionGranted(requiredPermissionsStatus)) return false;
8485

8586
await permissionModule.requestMultiple(optionalPermissions);
8687
return true;
8788
}
89+
8890
async hasMediaLibraryPermission(): Promise<boolean> {
8991
const status = await permissionModule.checkMultiple(mediaLibraryPermissions);
9092
return nativePermissionGranted(status);
9193
}
94+
9295
async requestMediaLibraryPermission(): Promise<boolean> {
9396
const status = await permissionModule.requestMultiple(mediaLibraryPermissions);
9497
return nativePermissionGranted(status);
@@ -129,6 +132,7 @@ const createNativeFileService = ({
129132
const { fileName: name, fileSize: size, type, uri } = response.assets?.[0] ?? {};
130133
return normalizeFile({ uri, size, name, type });
131134
}
135+
132136
async openMediaLibrary(options?: OpenMediaLibraryOptions): Promise<FilePickerResponse[] | null> {
133137
/**
134138
* NOTE: options.selectionLimit {@link https://github.com/react-native-image-picker/react-native-image-picker#options}
@@ -172,17 +176,11 @@ const createNativeFileService = ({
172176
.map(({ fileName: name, fileSize: size, type, uri }) => normalizeFile({ uri, size, name, type })),
173177
);
174178
}
179+
175180
async openDocument(options?: OpenDocumentOptions): Promise<FilePickerResponse> {
176-
try {
177-
const { uri, size, name, type } = await documentPickerModule.pickSingle();
178-
return normalizeFile({ uri, size, name, type });
179-
} catch (e) {
180-
if (!documentPickerModule.isCancel(e) && documentPickerModule.isInProgress(e)) {
181-
options?.onOpenFailure?.(SBUError.UNKNOWN, e);
182-
}
183-
return null;
184-
}
181+
return await openDocument(documentPickerModule, options);
185182
}
183+
186184
async save(options: SaveOptions): Promise<string> {
187185
const hasPermission = await this.hasMediaLibraryPermission();
188186
if (!hasPermission) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type * as NewDocumentsPicker from '@react-native-documents/picker';
2+
import type * as OldDocumentPicker from 'react-native-document-picker';
3+
4+
import type { FilePickerResponse, OpenDocumentOptions } from '@sendbird/uikit-react-native';
5+
import { Logger } from '@sendbird/uikit-utils';
6+
7+
import SBUError from '../libs/SBUError';
8+
import normalizeFile from '../utils/normalizeFile';
9+
10+
export type DocumentPicker = typeof OldDocumentPicker | typeof NewDocumentsPicker;
11+
12+
async function openDocumentByOldDocumentPicker(
13+
documentPickerModule: typeof OldDocumentPicker,
14+
options?: OpenDocumentOptions,
15+
): Promise<FilePickerResponse> {
16+
Logger.log('called openDocumentByOldDocumentPicker');
17+
try {
18+
const { uri, size, name, type } = await documentPickerModule.pickSingle();
19+
return normalizeFile({ uri, size, name, type });
20+
} catch (e) {
21+
if (!documentPickerModule.isCancel(e) && documentPickerModule.isInProgress(e)) {
22+
options?.onOpenFailure?.(SBUError.UNKNOWN, e);
23+
}
24+
return null;
25+
}
26+
}
27+
28+
async function openDocumentByNewDocumentsPicker(
29+
documentPickerModule: typeof NewDocumentsPicker,
30+
options?: OpenDocumentOptions,
31+
): Promise<FilePickerResponse> {
32+
Logger.log('called openDocumentByNewDocumentsPicker');
33+
try {
34+
const results = await documentPickerModule.pick();
35+
const { uri, size, name, type } = results[0];
36+
return normalizeFile({ uri, size, name, type });
37+
} catch (e) {
38+
if (
39+
!documentPickerModule.isErrorWithCode(documentPickerModule.errorCodes.OPERATION_CANCELED) &&
40+
documentPickerModule.isErrorWithCode(documentPickerModule.errorCodes.IN_PROGRESS)
41+
) {
42+
options?.onOpenFailure?.(SBUError.UNKNOWN, e);
43+
}
44+
return null;
45+
}
46+
}
47+
48+
export async function openDocument(
49+
documentPickerModule: DocumentPicker,
50+
options?: OpenDocumentOptions,
51+
): Promise<FilePickerResponse> {
52+
let oldDocumentPicker: typeof OldDocumentPicker | undefined;
53+
let newDocumentsPicker: typeof NewDocumentsPicker | undefined;
54+
55+
try {
56+
oldDocumentPicker = require('react-native-document-picker') as typeof OldDocumentPicker;
57+
} catch {}
58+
59+
try {
60+
newDocumentsPicker = require('@react-native-documents/picker') as typeof NewDocumentsPicker;
61+
} catch {}
62+
63+
if (newDocumentsPicker && documentPickerModule === newDocumentsPicker) {
64+
return await openDocumentByNewDocumentsPicker(documentPickerModule, options);
65+
} else if (oldDocumentPicker && documentPickerModule === oldDocumentPicker) {
66+
return await openDocumentByOldDocumentPicker(documentPickerModule, options);
67+
} else {
68+
const errorMessage =
69+
'Document picker module not found. Please install either react-native-document-picker or @react-native-documents/picker.';
70+
Logger.error(errorMessage);
71+
throw new Error(errorMessage);
72+
}
73+
}

yarn.lock

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,7 +1237,7 @@
12371237
"@babel/parser" "^7.25.9"
12381238
"@babel/types" "^7.25.9"
12391239

1240-
"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3", "@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.20.0", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.4":
1240+
"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3":
12411241
version "7.25.9"
12421242
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
12431243
integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==
@@ -1266,6 +1266,19 @@
12661266
debug "^4.1.0"
12671267
globals "^11.1.0"
12681268

1269+
"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.20.0", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.4":
1270+
version "7.25.9"
1271+
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
1272+
integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==
1273+
dependencies:
1274+
"@babel/code-frame" "^7.25.9"
1275+
"@babel/generator" "^7.25.9"
1276+
"@babel/parser" "^7.25.9"
1277+
"@babel/template" "^7.25.9"
1278+
"@babel/types" "^7.25.9"
1279+
debug "^4.3.1"
1280+
globals "^11.1.0"
1281+
12691282
"@babel/types@7.17.0":
12701283
version "7.17.0"
12711284
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
@@ -3280,6 +3293,11 @@
32803293
resolved "https://registry.yarnpkg.com/@react-native-community/slider/-/slider-4.5.5.tgz#d70fc5870477760033769bbd6625d57e7d7678b2"
32813294
integrity sha512-x2N415pg4ZxIltArOKczPwn7JEYh+1OxQ4+hTnafomnMsqs65HZuEWcX+Ch8c5r8V83DiunuQUf5hWGWlw8hQQ==
32823295

3296+
"@react-native-documents/picker@^10.0.0":
3297+
version "10.1.2"
3298+
resolved "https://registry.yarnpkg.com/@react-native-documents/picker/-/picker-10.1.2.tgz#2ebbf1eccc7e9efa3690e35ab5f0a811411a57b8"
3299+
integrity sha512-JzbFmFp0SmG0FEKt4Q62trewHMFpas2zAX0n5EANwrU9kondnzAEF7/xxz2EA2tfZNwnkHelqG8A7iedGleMRw==
3300+
32833301
"@react-native-firebase/app@^14.4.0", "@react-native-firebase/app@^14.7.0":
32843302
version "14.12.0"
32853303
resolved "https://registry.yarnpkg.com/@react-native-firebase/app/-/app-14.12.0.tgz#d9706973489485d8705ce8344e3b255115b381a8"
@@ -15062,7 +15080,16 @@ string-natural-compare@^3.0.1:
1506215080
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
1506315081
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
1506415082

15065-
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
15083+
"string-width-cjs@npm:string-width@^4.2.0":
15084+
version "4.2.3"
15085+
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
15086+
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
15087+
dependencies:
15088+
emoji-regex "^8.0.0"
15089+
is-fullwidth-code-point "^3.0.0"
15090+
strip-ansi "^6.0.1"
15091+
15092+
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
1506615093
version "4.2.3"
1506715094
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
1506815095
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -15168,7 +15195,7 @@ string_decoder@~1.1.1:
1516815195
dependencies:
1516915196
safe-buffer "~5.1.0"
1517015197

15171-
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
15198+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
1517215199
version "6.0.1"
1517315200
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
1517415201
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -15182,6 +15209,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.2.0:
1518215209
dependencies:
1518315210
ansi-regex "^4.1.0"
1518415211

15212+
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
15213+
version "6.0.1"
15214+
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
15215+
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
15216+
dependencies:
15217+
ansi-regex "^5.0.1"
15218+
1518515219
strip-ansi@^7.0.1:
1518615220
version "7.1.0"
1518715221
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -16374,7 +16408,7 @@ worker-farm@^1.7.0:
1637416408
dependencies:
1637516409
errno "~0.1.7"
1637616410

16377-
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
16411+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
1637816412
version "7.0.0"
1637916413
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
1638016414
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -16392,6 +16426,15 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0:
1639216426
string-width "^4.1.0"
1639316427
strip-ansi "^6.0.0"
1639416428

16429+
wrap-ansi@^7.0.0:
16430+
version "7.0.0"
16431+
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
16432+
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
16433+
dependencies:
16434+
ansi-styles "^4.0.0"
16435+
string-width "^4.1.0"
16436+
strip-ansi "^6.0.0"
16437+
1639516438
wrap-ansi@^8.1.0:
1639616439
version "8.1.0"
1639716440
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"

0 commit comments

Comments
 (0)