allow taking videos with camera button
This commit is contained in:
@@ -3,7 +3,7 @@ import {
|
||||
getInfoAsync,
|
||||
readDirectoryAsync,
|
||||
} from 'expo-file-system/legacy'
|
||||
import {type ImagePickerResult} from 'expo-image-picker'
|
||||
import {type ImagePickerAsset, type ImagePickerResult} from 'expo-image-picker'
|
||||
import ExpoImageCropTool, {
|
||||
type OpenCropperOptions,
|
||||
} from '@bsky.app/expo-image-crop-tool'
|
||||
@@ -57,8 +57,20 @@ export async function openUnifiedPicker(): Promise<ImagePickerResult> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function openCamera(): Promise<PickerImage> {
|
||||
return await getFile()
|
||||
export async function openCamera(): Promise<
|
||||
PickerImage & {asset: ImagePickerAsset}
|
||||
> {
|
||||
const file = await getFile()
|
||||
return {
|
||||
...file,
|
||||
asset: {
|
||||
uri: file.path,
|
||||
width: file.width,
|
||||
height: file.height,
|
||||
mimeType: file.mime,
|
||||
type: 'image',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function openCropper(opts: OpenCropperOptions) {
|
||||
|
||||
@@ -29,6 +29,7 @@ export async function openCamera(customOpts: ImagePickerOptions) {
|
||||
size: asset.fileSize ?? 0,
|
||||
width: asset.width,
|
||||
height: asset.height,
|
||||
asset,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import {type ImagePickerAsset, type ImagePickerOptions} from 'expo-image-picker'
|
||||
import {type OpenCropperOptions} from '@bsky.app/expo-image-crop-tool'
|
||||
|
||||
import {type PickerImage} from './picker.shared'
|
||||
import {type CameraOpts} from './types'
|
||||
|
||||
export {openPicker, openUnifiedPicker} from './picker.shared'
|
||||
|
||||
export async function openCamera(_opts: CameraOpts): Promise<PickerImage> {
|
||||
export async function openCamera(
|
||||
_opts: ImagePickerOptions,
|
||||
): Promise<PickerImage & {asset: ImagePickerAsset}> {
|
||||
throw new Error('openCamera is not supported on web')
|
||||
}
|
||||
|
||||
|
||||
@@ -1951,7 +1951,8 @@ function ComposerFooter({
|
||||
/>
|
||||
<OpenCameraBtn
|
||||
disabled={media?.type === 'images' ? isMaxImages : !!media}
|
||||
onAdd={onImageAdd}
|
||||
onAddImage={onImageAdd}
|
||||
onAddVideo={asset => onSelectVideo(post.id, asset)}
|
||||
/>
|
||||
<SelectGifBtn onSelectGif={onSelectGif} disabled={!!media} />
|
||||
{!isMobile ? (
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import {useCallback} from 'react'
|
||||
import {type ImagePickerAsset} from 'expo-image-picker'
|
||||
import * as MediaLibrary from 'expo-media-library'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {POST_IMG_MAX} from '#/lib/constants'
|
||||
import {POST_IMG_MAX, VIDEO_MAX_DURATION_MS} from '#/lib/constants'
|
||||
import {useCameraPermission} from '#/lib/hooks/usePermissions'
|
||||
import {openCamera} from '#/lib/media/picker'
|
||||
import {logger} from '#/logger'
|
||||
@@ -15,14 +16,15 @@ import {IS_NATIVE, IS_WEB_MOBILE} from '#/env'
|
||||
|
||||
type Props = {
|
||||
disabled?: boolean
|
||||
onAdd: (next: ComposerImage[]) => void
|
||||
onAddImage: (next: ComposerImage[]) => void
|
||||
onAddVideo: (asset: ImagePickerAsset) => void
|
||||
}
|
||||
|
||||
export function OpenCameraBtn({disabled, onAdd}: Props) {
|
||||
export function OpenCameraBtn({disabled, onAddImage, onAddVideo}: Props) {
|
||||
const {_} = useLingui()
|
||||
const {requestCameraAccessIfNeeded} = useCameraPermission()
|
||||
const [mediaPermissionRes, requestMediaPermission] =
|
||||
MediaLibrary.usePermissions({granularPermissions: ['photo']})
|
||||
MediaLibrary.usePermissions({granularPermissions: ['photo', 'video']})
|
||||
const t = useTheme()
|
||||
|
||||
const onPressTakePicture = useCallback(async () => {
|
||||
@@ -34,25 +36,31 @@ export function OpenCameraBtn({disabled, onAdd}: Props) {
|
||||
await requestMediaPermission()
|
||||
}
|
||||
|
||||
const img = await openCamera({
|
||||
const result = await openCamera({
|
||||
mediaTypes: ['images', 'videos'],
|
||||
aspect: [POST_IMG_MAX.width, POST_IMG_MAX.height],
|
||||
videoMaxDuration: VIDEO_MAX_DURATION_MS / 1000,
|
||||
})
|
||||
|
||||
// If we don't have permissions it's fine, we just wont save it. The post itself will still have access to
|
||||
// the image even without these permissions
|
||||
if (mediaPermissionRes) {
|
||||
await MediaLibrary.createAssetAsync(img.path)
|
||||
await MediaLibrary.createAssetAsync(result.path)
|
||||
}
|
||||
|
||||
const res = await createComposerImage(img)
|
||||
|
||||
onAdd([res])
|
||||
if (result.mime.startsWith('image')) {
|
||||
const img = await createComposerImage(result)
|
||||
onAddImage([img])
|
||||
} else if (result.mime.startsWith('video')) {
|
||||
onAddVideo(result.asset)
|
||||
}
|
||||
} catch (err: any) {
|
||||
// ignore
|
||||
logger.warn('Error using camera', {error: err})
|
||||
}
|
||||
}, [
|
||||
onAdd,
|
||||
onAddImage,
|
||||
onAddVideo,
|
||||
requestCameraAccessIfNeeded,
|
||||
mediaPermissionRes,
|
||||
requestMediaPermission,
|
||||
|
||||
Reference in New Issue
Block a user