Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions packages/uikit-react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"@react-native-camera-roll/camera-roll": "^7.8.1",
"@react-native-clipboard/clipboard": "^1.14.1",
"@react-native-community/netinfo": "^11.3.2",
"@react-native-documents/picker": "^10.0.0",
"@react-native-firebase/app": "^14.4.0",
"@react-native-firebase/messaging": "^14.4.0",
"@types/react": "*",
Expand Down Expand Up @@ -108,6 +109,7 @@
"@react-native-camera-roll/camera-roll": ">=5.0.0",
"@react-native-clipboard/clipboard": ">=1.8.5",
"@react-native-community/netinfo": ">=9.3.0",
"@react-native-documents/picker": ">=10.0.0",
"@react-native-firebase/messaging": ">=14.4.0",
"@sendbird/chat": "^4.16.0",
"@sendbird/react-native-scrollview-enhancer": "*",
Expand Down Expand Up @@ -145,6 +147,9 @@
"@react-native-clipboard/clipboard": {
"optional": true
},
"@react-native-documents/picker": {
"optional": true
},
"@react-native-firebase/messaging": {
"optional": true
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { CameraRoll } from '@react-native-camera-roll/camera-roll';
import { Platform } from 'react-native';
import type * as DocumentPicker from 'react-native-document-picker';
import type * as FileAccess from 'react-native-file-access';
import type * as ImagePicker from 'react-native-image-picker';
import type * as Permissions from 'react-native-permissions';
Expand All @@ -18,6 +17,7 @@ import {
import SBUError from '../libs/SBUError';
import nativePermissionGranted from '../utils/nativePermissionGranted';
import normalizeFile from '../utils/normalizeFile';
import { DocumentPicker, openDocument } from './openDocument.native';
import type {
FilePickerResponse,
FileServiceInterface,
Expand Down Expand Up @@ -52,7 +52,7 @@ const createNativeFileService = ({
fsModule,
}: {
imagePickerModule: typeof ImagePicker;
documentPickerModule: typeof DocumentPicker;
documentPickerModule: DocumentPicker;
permissionModule: typeof Permissions;
mediaLibraryModule: typeof CameraRoll;
fsModule: typeof FileAccess;
Expand All @@ -78,17 +78,20 @@ const createNativeFileService = ({
const status = await permissionModule.checkMultiple(requiredPermissions);
return nativePermissionGranted(status);
}

async requestCameraPermission(): Promise<boolean> {
const requiredPermissionsStatus = await permissionModule.requestMultiple(requiredPermissions);
if (!nativePermissionGranted(requiredPermissionsStatus)) return false;

await permissionModule.requestMultiple(optionalPermissions);
return true;
}

async hasMediaLibraryPermission(): Promise<boolean> {
const status = await permissionModule.checkMultiple(mediaLibraryPermissions);
return nativePermissionGranted(status);
}

async requestMediaLibraryPermission(): Promise<boolean> {
const status = await permissionModule.requestMultiple(mediaLibraryPermissions);
return nativePermissionGranted(status);
Expand Down Expand Up @@ -129,6 +132,7 @@ const createNativeFileService = ({
const { fileName: name, fileSize: size, type, uri } = response.assets?.[0] ?? {};
return normalizeFile({ uri, size, name, type });
}

async openMediaLibrary(options?: OpenMediaLibraryOptions): Promise<FilePickerResponse[] | null> {
/**
* NOTE: options.selectionLimit {@link https://github.com/react-native-image-picker/react-native-image-picker#options}
Expand Down Expand Up @@ -172,17 +176,11 @@ const createNativeFileService = ({
.map(({ fileName: name, fileSize: size, type, uri }) => normalizeFile({ uri, size, name, type })),
);
}

async openDocument(options?: OpenDocumentOptions): Promise<FilePickerResponse> {
try {
const { uri, size, name, type } = await documentPickerModule.pickSingle();
return normalizeFile({ uri, size, name, type });
} catch (e) {
if (!documentPickerModule.isCancel(e) && documentPickerModule.isInProgress(e)) {
options?.onOpenFailure?.(SBUError.UNKNOWN, e);
}
return null;
}
return await openDocument(documentPickerModule, options);
}

async save(options: SaveOptions): Promise<string> {
const hasPermission = await this.hasMediaLibraryPermission();
if (!hasPermission) {
Expand Down
73 changes: 73 additions & 0 deletions packages/uikit-react-native/src/platform/openDocument.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type * as NewDocumentsPicker from '@react-native-documents/picker';
import type * as OldDocumentPicker from 'react-native-document-picker';

import type { FilePickerResponse, OpenDocumentOptions } from '@sendbird/uikit-react-native';
import { Logger } from '@sendbird/uikit-utils';

import SBUError from '../libs/SBUError';
import normalizeFile from '../utils/normalizeFile';

export type DocumentPicker = typeof OldDocumentPicker | typeof NewDocumentsPicker;

async function openDocumentByOldDocumentPicker(
documentPickerModule: typeof OldDocumentPicker,
options?: OpenDocumentOptions,
): Promise<FilePickerResponse> {
Logger.log('called openDocumentByOldDocumentPicker');
try {
const { uri, size, name, type } = await documentPickerModule.pickSingle();
return normalizeFile({ uri, size, name, type });
} catch (e) {
if (!documentPickerModule.isCancel(e) && documentPickerModule.isInProgress(e)) {
options?.onOpenFailure?.(SBUError.UNKNOWN, e);
}
return null;
}
}

async function openDocumentByNewDocumentsPicker(
documentPickerModule: typeof NewDocumentsPicker,
options?: OpenDocumentOptions,
): Promise<FilePickerResponse> {
Logger.log('called openDocumentByNewDocumentsPicker');
try {
const results = await documentPickerModule.pick();
const { uri, size, name, type } = results[0];
return normalizeFile({ uri, size, name, type });
} catch (e) {
if (
!documentPickerModule.isErrorWithCode(documentPickerModule.errorCodes.OPERATION_CANCELED) &&
documentPickerModule.isErrorWithCode(documentPickerModule.errorCodes.IN_PROGRESS)
) {
options?.onOpenFailure?.(SBUError.UNKNOWN, e);
}
return null;
}
}

export async function openDocument(
documentPickerModule: DocumentPicker,
options?: OpenDocumentOptions,
): Promise<FilePickerResponse> {
let oldDocumentPicker: typeof OldDocumentPicker | undefined;
let newDocumentsPicker: typeof NewDocumentsPicker | undefined;

try {
oldDocumentPicker = require('react-native-document-picker') as typeof OldDocumentPicker;
} catch {}

try {
newDocumentsPicker = require('@react-native-documents/picker') as typeof NewDocumentsPicker;
} catch {}

if (newDocumentsPicker && documentPickerModule === newDocumentsPicker) {
return await openDocumentByNewDocumentsPicker(documentPickerModule, options);
} else if (oldDocumentPicker && documentPickerModule === oldDocumentPicker) {
return await openDocumentByOldDocumentPicker(documentPickerModule, options);
} else {
const errorMessage =
'Document picker module not found. Please install either react-native-document-picker or @react-native-documents/picker.';
Logger.error(errorMessage);
throw new Error(errorMessage);
}
}
51 changes: 47 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1237,7 +1237,7 @@
"@babel/parser" "^7.25.9"
"@babel/types" "^7.25.9"

"@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":
"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==
Expand Down Expand Up @@ -1266,6 +1266,19 @@
debug "^4.1.0"
globals "^11.1.0"

"@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":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84"
integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==
dependencies:
"@babel/code-frame" "^7.25.9"
"@babel/generator" "^7.25.9"
"@babel/parser" "^7.25.9"
"@babel/template" "^7.25.9"
"@babel/types" "^7.25.9"
debug "^4.3.1"
globals "^11.1.0"

"@babel/[email protected]":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
Expand Down Expand Up @@ -3280,6 +3293,11 @@
resolved "https://registry.yarnpkg.com/@react-native-community/slider/-/slider-4.5.5.tgz#d70fc5870477760033769bbd6625d57e7d7678b2"
integrity sha512-x2N415pg4ZxIltArOKczPwn7JEYh+1OxQ4+hTnafomnMsqs65HZuEWcX+Ch8c5r8V83DiunuQUf5hWGWlw8hQQ==

"@react-native-documents/picker@^10.0.0":
version "10.1.2"
resolved "https://registry.yarnpkg.com/@react-native-documents/picker/-/picker-10.1.2.tgz#2ebbf1eccc7e9efa3690e35ab5f0a811411a57b8"
integrity sha512-JzbFmFp0SmG0FEKt4Q62trewHMFpas2zAX0n5EANwrU9kondnzAEF7/xxz2EA2tfZNwnkHelqG8A7iedGleMRw==

"@react-native-firebase/app@^14.4.0", "@react-native-firebase/app@^14.7.0":
version "14.12.0"
resolved "https://registry.yarnpkg.com/@react-native-firebase/app/-/app-14.12.0.tgz#d9706973489485d8705ce8344e3b255115b381a8"
Expand Down Expand Up @@ -15062,7 +15080,16 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==

"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:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -15168,7 +15195,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"

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

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
Expand Down Expand Up @@ -16374,7 +16408,7 @@ worker-farm@^1.7.0:
dependencies:
errno "~0.1.7"

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

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
Expand Down
Loading