stream-chat-react-native-core
Version:
The official React Native and Expo components for Stream Chat, a service for building chat applications
91 lines (78 loc) • 3.4 kB
text/typescript
import { useCallback } from 'react';
import { Alert, Linking } from 'react-native';
import { useChannelEditDetailsContext } from '../../../contexts/channelEditDetailsContext/ChannelEditDetailsContext';
import { useTranslationContext } from '../../../contexts/translationContext/TranslationContext';
import { NativeHandlers } from '../../../native';
import type { File } from '../../../types/types';
import { compressedImageURI } from '../../../utils/compressImage';
export type UseEditChannelImageResult = {
/**
* Open the device's native image picker and return a single picked image
* with the compression configured on `ChannelDetails` already applied
* to its `uri`. Returns `undefined` if the user cancels or denies access.
*/
pickImageFromNativePicker: () => Promise<File | undefined>;
/**
* Launch the device's camera and return the captured image. Returns
* `undefined` if the user cancels or denies access. The native camera
* handler already honors `compressImageQuality`, so no extra compression
* pass is needed for camera files.
*/
takePhoto: () => Promise<File | undefined>;
};
/**
* Hook that exposes the two image-acquisition flows used by the channel edit
* screen — camera capture and native gallery pick — using the same control
* flow and compression behavior as the message composer (`takeAndUploadImage`
* and `pickAndUploadImageFromNativePicker` in `MessageInputContext`). The
* hook intentionally does NOT upload the picked file; the consumer receives a
* `File` and decides what to do with it.
*
* Reads `compressImageQuality` from `ChannelEditDetailsContext`.
*/
export const useEditChannelImage = (): UseEditChannelImageResult => {
const { compressImageQuality } = useChannelEditDetailsContext();
const { t } = useTranslationContext();
const takePhoto = useCallback(async (): Promise<File | undefined> => {
const file = await NativeHandlers.takePhoto({
compressImageQuality: compressImageQuality ?? 1,
mediaType: 'image',
});
if (file.askToOpenSettings) {
Alert.alert(
t('Allow camera access in device settings'),
t('Device camera is used to take photos or videos.'),
[
{ style: 'cancel', text: t('Cancel') },
{ onPress: () => Linking.openSettings(), style: 'default', text: t('Open Settings') },
],
);
return undefined;
}
if (file.cancelled) {
return undefined;
}
return file;
}, [compressImageQuality, t]);
const pickImageFromNativePicker = useCallback(async (): Promise<File | undefined> => {
const result = await NativeHandlers.pickImage({ maxNumberOfFiles: 1 });
if (result.askToOpenSettings) {
Alert.alert(
t('Allow access to your Gallery'),
t('Device gallery permissions is used to take photos or videos.'),
[
{ style: 'cancel', text: t('Cancel') },
{ onPress: () => Linking.openSettings(), style: 'default', text: t('Open Settings') },
],
);
return undefined;
}
if (result.cancelled || !result.assets?.length) {
return undefined;
}
const asset = result.assets[0];
const compressedUri = await compressedImageURI(asset, compressImageQuality);
return { ...asset, uri: compressedUri };
}, [compressImageQuality, t]);
return { pickImageFromNativePicker, takePhoto };
};