Skip to content

Commit

Permalink
Merge pull request #2815 from GetStream/fix/asset-library-issues
Browse files Browse the repository at this point in the history
fix: asset library issues
  • Loading branch information
isekovanic authored Dec 5, 2024
2 parents f310076 + 45488c1 commit a1090cb
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 63 deletions.
11 changes: 11 additions & 0 deletions examples/ExpoMessaging/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@
{
"microphonePermission": "$(PRODUCT_NAME) would like to use your microphone for voice recording."
}
],
[
"expo-build-properties",
{
"android": {
"newArchEnabled": true
},
"ios": {
"newArchEnabled": true
}
}
]
]
}
Expand Down
25 changes: 25 additions & 0 deletions examples/SampleApp/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,27 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-cameraroll (7.8.4):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-document-picker (9.3.1):
- DoubleConversion
- glog
Expand Down Expand Up @@ -2233,6 +2254,7 @@ DEPENDENCIES:
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
- react-native-blob-util (from `../node_modules/react-native-blob-util`)
- "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)"
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
Expand Down Expand Up @@ -2381,6 +2403,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
react-native-blob-util:
:path: "../node_modules/react-native-blob-util"
react-native-cameraroll:
:path: "../node_modules/@react-native-camera-roll/camera-roll"
react-native-document-picker:
:path: "../node_modules/react-native-document-picker"
react-native-image-picker:
Expand Down Expand Up @@ -2531,6 +2555,7 @@ SPEC CHECKSUMS:
React-Mapbuffer: 858e7be7b51da78fd6a12b2461d92ea44e88c0f2
React-microtasksnativemodule: a221789bbd16b09f083a60a4bec8623e2dfbb59f
react-native-blob-util: 356047c561b3506396852bc0d7988243f74dd77d
react-native-cameraroll: 55de4896c31042eedcb0629a58ef5ff0d5a2c428
react-native-document-picker: 1e082836a633ca9e7c75758036ff42535baaf36b
react-native-image-picker: df6597d4b1878a443796be11eb2b7286ed10ece6
react-native-netinfo: 076df4f9b07f6670acf4ce9a75aac8d34c2e2ccc
Expand Down
2 changes: 1 addition & 1 deletion examples/SampleApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@notifee/react-native": "^9.1.2",
"@op-engineering/op-sqlite": "^9.3.0",
"@react-native-async-storage/async-storage": "^1.21.0",
"@react-native-camera-roll/camera-roll": "^7.8.4",
"@react-native-community/netinfo": "^11.3.2",
"@react-native-firebase/app": "^19.3.0",
"@react-native-firebase/messaging": "^19.3.0",
Expand All @@ -40,7 +41,6 @@
"react-native-fast-image": "^8.6.3",
"react-native-gesture-handler": "^2.18.1",
"react-native-haptic-feedback": "^2.3.3",
"react-native-image-picker": "^7.1.2",
"react-native-reanimated": "^3.16.0",
"react-native-safe-area-context": "^4.14.0",
"react-native-screens": "^3.34.0",
Expand Down
10 changes: 5 additions & 5 deletions examples/SampleApp/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1882,6 +1882,11 @@
dependencies:
merge-options "^3.0.4"

"@react-native-camera-roll/camera-roll@^7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@react-native-camera-roll/camera-roll/-/camera-roll-7.8.4.tgz#2422ad5ca4e55fa2973e8c03255e3dc7b330925c"
integrity sha512-CraoJLSOpiPnPsuzbJoydKrtCJY6rPAqHn7fzN/4uCOqoah4IlauMcNVSvr4N9qbemIztPrHBnDgLJtYDlgo+A==

"@react-native-community/[email protected]":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-15.0.0.tgz#10c7cfde8379aaa7a60eaf4bd3920542d4af1b81"
Expand Down Expand Up @@ -6688,11 +6693,6 @@ react-native-haptic-feedback@^2.3.3:
resolved "https://registry.yarnpkg.com/react-native-haptic-feedback/-/react-native-haptic-feedback-2.3.3.tgz#88b6876e91399a69bd1b551fe1681b2f3dc1214e"
integrity sha512-svS4D5PxfNv8o68m9ahWfwje5NqukM3qLS48+WTdhbDkNUkOhP9rDfDSRHzlhk4zq+ISjyw95EhLeh8NkKX5vQ==

react-native-image-picker@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/react-native-image-picker/-/react-native-image-picker-7.1.2.tgz#383849d1953caf4578874a1f5e5dd11c737bd5cd"
integrity sha512-b5y5nP60RIPxlAXlptn2QwlIuZWCUDWa/YPUVjgHc0Ih60mRiOg1PSzf0IjHSLeOZShCpirpvSPGnDExIpTRUg==

react-native-lightbox@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/react-native-lightbox/-/react-native-lightbox-0.7.0.tgz#e52b4d7fcc141f59d7b23f0180de535e35b20ec9"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Platform } from 'react-native';

let MediaLibrary;

try {
Expand All @@ -12,10 +14,14 @@ if (!MediaLibrary) {
);
}

// TODO: The API is different for Expo and RN CLI. We should unify it.
export const getLocalAssetUri = async (assetId: string): Promise<string | undefined> => {
try {
const { localUri } = await MediaLibrary.getAssetInfoAsync(assetId);
return localUri;
if (Platform.OS === 'ios') {
const { localUri } = await MediaLibrary.getAssetInfoAsync(assetId);
return localUri;
}
return null;
} catch {
throw new Error('getLocalAssetUri Error');
}
Expand Down
30 changes: 20 additions & 10 deletions package/expo-package/src/optionalDependencies/getPhotos.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Platform } from 'react-native';

let MediaLibrary;

try {
Expand All @@ -13,6 +15,8 @@ if (!MediaLibrary) {
}
import type { Asset } from 'stream-chat-react-native-core';

import { getLocalAssetUri } from './getLocalAssetUri';

type ReturnType = {
assets: Array<Omit<Asset, 'source'> & { source: 'picker' }>;
endCursor: string | undefined;
Expand Down Expand Up @@ -40,16 +44,22 @@ export const getPhotos = MediaLibrary
mediaType: [MediaLibrary.MediaType.photo, MediaLibrary.MediaType.video],
sortBy: [MediaLibrary.SortBy.modificationTime],
});
const assets = results.assets.map((asset) => ({
duration: asset.duration * 1000,
height: asset.height,
id: asset.id,
name: asset.filename,
source: 'picker' as const,
type: asset.mediaType,
uri: asset.uri,
width: asset.width,
}));
const assets = await Promise.all(
results.assets.map(async (asset) => {
const localUri = await getLocalAssetUri(asset.id);
return {
duration: asset.duration * 1000,
height: asset.height,
id: asset.id,
name: asset.filename,
originalUri: asset.uri,
source: 'picker' as const,
type: asset.mediaType,
uri: localUri || asset.uri,
width: asset.width,
};
}),
);

const hasNextPage = results.hasNextPage;
const endCursor = results.endCursor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Platform } from 'react-native';

let CameraRollDependency;

try {
Expand All @@ -12,8 +14,11 @@ try {
export const getLocalAssetUri = CameraRollDependency
? async (remoteUri: string) => {
try {
const localUri = await CameraRollDependency.CameraRoll.save(remoteUri);
return localUri;
if (Platform.OS === 'ios') {
const imageData = await CameraRollDependency.CameraRoll.iosGetImageDataById(remoteUri);
return imageData?.node?.image?.filepath;
}
return remoteUri;
} catch {
throw new Error('getLocalAssetUri Error');
}
Expand Down
28 changes: 19 additions & 9 deletions package/native-package/src/optionalDependencies/getPhotos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ try {

import type { Asset } from 'stream-chat-react-native-core';

import { getLocalAssetUri } from './getLocalAssetUri';

type ReturnType = {
assets: Array<Omit<Asset, 'source'> & { source: 'picker' }>;
endCursor: string | undefined;
Expand Down Expand Up @@ -82,15 +84,23 @@ export const getPhotos = CameraRollDependency
first,
include: ['fileSize', 'filename', 'imageSize', 'playableDuration'],
});
const assets = results.edges.map((edge) => ({
...edge.node.image,
duration: edge.node.image.playableDuration * 1000,
// since we include filename, fileSize in the query, we can safely assume it will be defined
name: edge.node.image.filename as string,
size: edge.node.image.fileSize as number,
source: 'picker' as const,
type: edge.node.type,
}));
const assets = await Promise.all(
results.edges.map(async (edge) => {
const originalUri = edge.node?.image?.uri;
const uri = getLocalAssetUri ? await getLocalAssetUri(originalUri) : originalUri;
return {
...edge.node.image,
duration: edge.node.image.playableDuration * 1000,
// since we include filename, fileSize in the query, we can safely assume it will be defined
name: edge.node.image.filename as string,
originalUri,
size: edge.node.image.fileSize as number,
source: 'picker' as const,
type: edge.node.type,
uri,
};
}),
);
const hasNextPage = results.page_info.has_next_page;
const endCursor = results.page_info.end_cursor;
return { assets, endCursor, hasNextPage, iOSLimited: !!results.limited };
Expand Down
8 changes: 6 additions & 2 deletions package/src/components/AttachmentPicker/AttachmentPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,13 @@ export const AttachmentPicker = React.forwardRef(
// `id` is available for Expo MediaLibrary while Cameraroll doesn't share id therefore we use `uri`
selected:
selectedImages.some((image) =>
image.id ? image.id === asset.id : image.uri === asset.uri,
image.id
? image.id === asset.id
: image.uri === asset.uri || image.originalUri === asset.uri,
) ||
selectedFiles.some((file) => (file.id ? file.id === asset.id : file.uri === asset.uri)),
selectedFiles.some((file) =>
file.id ? file.id === asset.id : file.uri === asset.uri || file.originalUri === asset.uri,
),
selectedFiles,
selectedImages,
setSelectedFiles,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

import { Alert, ImageBackground, Platform, StyleSheet, Text, View } from 'react-native';
import { Alert, ImageBackground, StyleSheet, Text, View } from 'react-native';

import { TouchableOpacity } from '@gorhom/bottom-sheet';
import { lookup } from 'mime-types';
Expand All @@ -10,7 +10,6 @@ import { useTheme } from '../../../contexts/themeContext/ThemeContext';
import { useTranslationContext } from '../../../contexts/translationContext/TranslationContext';
import { useViewport } from '../../../hooks/useViewport';
import { Recorder } from '../../../icons';
import { getLocalAssetUri } from '../../../native';
import type { Asset, File } from '../../../types/types';
import { getDurationLabelFromDuration } from '../../../utils/utils';

Expand Down Expand Up @@ -49,18 +48,14 @@ const AttachmentVideo = (props: AttachmentVideoProps) => {
},
} = useTheme();

const { duration: videoDuration, uri } = asset;
const { duration: videoDuration, id: assetId, originalUri, uri } = asset;

const durationLabel = getDurationLabelFromDuration(videoDuration);

const size = vw(100) / (numberOfAttachmentPickerImageColumns || 3) - 2;

/* Patches video files with uri and mimetype */
const patchVideoFile = async (files: File[]) => {
// For the case of Expo CLI where you need to fetch the file uri from file id. Here it is only done for iOS since for android the file.uri is fine.
const localAssetURI =
Platform.OS === 'ios' && asset.id && getLocalAssetUri && (await getLocalAssetUri(asset.id));
const uri = localAssetURI || asset.uri || '';
const patchVideoFile = (files: File[]) => {
// We need a mime-type to upload a video file.
const mimeType = lookup(asset.name) || 'multipart/form-data';
return [
Expand All @@ -70,26 +65,29 @@ const AttachmentVideo = (props: AttachmentVideoProps) => {
id: asset.id,
mimeType,
name: asset.name,
originalUri,
size: asset.size,
uri,
},
];
};

const updateSelectedFiles = async () => {
const updateSelectedFiles = () => {
if (numberOfUploads >= maxNumberOfFiles) {
Alert.alert(t('Maximum number of files reached'));
return;
}
const files = await patchVideoFile(selectedFiles);
const files = patchVideoFile(selectedFiles);
setSelectedFiles(files);
};

const onPressVideo = () => {
if (selected) {
setSelectedFiles((files) =>
// `id` is available for Expo MediaLibrary while Cameraroll doesn't share id therefore we use `uri`
files.filter((file) => (file.id ? file.id !== asset.id : file.uri !== asset.uri)),
files.filter((file) =>
file.id ? file.id !== assetId : file.uri !== uri && file.originalUri !== uri,
),
);
} else {
updateSelectedFiles();
Expand All @@ -99,7 +97,7 @@ const AttachmentVideo = (props: AttachmentVideoProps) => {
return (
<TouchableOpacity onPress={onPressVideo}>
<ImageBackground
source={{ uri }}
source={{ uri: originalUri }}
style={[
{
height: size,
Expand Down Expand Up @@ -149,43 +147,31 @@ const AttachmentImage = (props: AttachmentImageProps) => {

const size = vw(100) / (numberOfAttachmentPickerImageColumns || 3) - 2;

const { uri } = asset;
const { id: assetId, originalUri, uri } = asset;

/* Patches image files with uri */
const patchImageFile = async (images: Asset[]) => {
// For the case of Expo CLI where you need to fetch the file uri from file id. Here it is only done for iOS since for android the file.uri is fine.
const localAssetURI =
Platform.OS === 'ios' && asset.id && getLocalAssetUri && (await getLocalAssetUri(asset.id));
const uri = localAssetURI || asset.uri || '';
return [
...images,
{
...asset,
uri,
},
];
};

const updateSelectedImages = async () => {
const updateSelectedImages = () => {
if (numberOfUploads >= maxNumberOfFiles) {
Alert.alert(t('Maximum number of files reached'));
return;
}
const images = await patchImageFile(selectedImages);
setSelectedImages(images);
setSelectedImages([...selectedImages, asset]);
};

const onPressImage = () => {
if (selected) {
// `id` is available for Expo MediaLibrary while Cameraroll doesn't share id therefore we use `uri`
setSelectedImages((images) =>
images.filter((image) => (image.id ? image.id !== asset.id : image.uri !== asset.uri)),
images.filter((image) =>
assetId ? image.id !== assetId : image.uri !== uri && originalUri !== uri,
),
);
} else {
updateSelectedImages();
}
};

console.log('URIS: IMG: ', uri, originalUri);

return (
<TouchableOpacity onPress={onPressImage}>
<ImageBackground
Expand Down
Loading

0 comments on commit a1090cb

Please sign in to comment.