add modal that lets you pick photo or video
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M2 5a1 1 0 0 1 1-1h13a1 1 0 0 1 1 1v2.523l3.629-1.451A1 1 0 0 1 22 7v10a1 1 0 0 1-1.371.928L17 16.477V19a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5Zm2 1v12h11v-3a1 1 0 0 1 1.371-.928L20 15.523V8.477l-3.629 1.451A1 1 0 0 1 15 9V6H4Zm5.5 4.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3ZM6 12a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0Z" clip-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 449 B |
@@ -0,0 +1,5 @@
|
|||||||
|
import {createSinglePathSVG} from './TEMPLATE'
|
||||||
|
|
||||||
|
export const FilmCamera_Stroke2_Corner0_Rounded = createSinglePathSVG({
|
||||||
|
path: 'M2 5a1 1 0 0 1 1-1h13a1 1 0 0 1 1 1v2.523l3.629-1.451A1 1 0 0 1 22 7v10a1 1 0 0 1-1.371.928L17 16.477V19a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5Zm2 1v12h11v-3a1 1 0 0 1 1.371-.928L20 15.523V8.477l-3.629 1.451A1 1 0 0 1 15 9V6H4Zm5.5 4.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3ZM6 12a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0Z',
|
||||||
|
})
|
||||||
@@ -807,7 +807,11 @@ export const ComposePost = observer(function ComposePost({
|
|||||||
disabled={!canSelectImages}
|
disabled={!canSelectImages}
|
||||||
setError={setError}
|
setError={setError}
|
||||||
/>
|
/>
|
||||||
<OpenCameraBtn gallery={gallery} disabled={!canSelectImages} />
|
<OpenCameraBtn
|
||||||
|
gallery={gallery}
|
||||||
|
disabled={!canSelectImages}
|
||||||
|
selectVideo={selectVideo}
|
||||||
|
/>
|
||||||
<SelectGifBtn
|
<SelectGifBtn
|
||||||
onClose={focusTextInput}
|
onClose={focusTextInput}
|
||||||
onSelectGif={onSelectGif}
|
onSelectGif={onSelectGif}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import React, {useCallback} from 'react'
|
import React, {useCallback} from 'react'
|
||||||
|
import {Keyboard} from 'react-native'
|
||||||
|
import {
|
||||||
|
ImagePickerAsset,
|
||||||
|
launchCameraAsync,
|
||||||
|
MediaTypeOptions,
|
||||||
|
UIImagePickerPresentationStyle,
|
||||||
|
} from 'expo-image-picker'
|
||||||
import * as MediaLibrary from 'expo-media-library'
|
import * as MediaLibrary from 'expo-media-library'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||||
@@ -11,21 +18,27 @@ import {logger} from '#/logger'
|
|||||||
import {isMobileWeb, isNative} from '#/platform/detection'
|
import {isMobileWeb, isNative} from '#/platform/detection'
|
||||||
import {GalleryModel} from '#/state/models/media/gallery'
|
import {GalleryModel} from '#/state/models/media/gallery'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
|
import * as Dialog from '#/components/Dialog'
|
||||||
import {Camera_Stroke2_Corner0_Rounded as Camera} from '#/components/icons/Camera'
|
import {Camera_Stroke2_Corner0_Rounded as Camera} from '#/components/icons/Camera'
|
||||||
|
import {FilmCamera_Stroke2_Corner0_Rounded as FilmCamera} from '#/components/icons/FilmCamera'
|
||||||
|
|
||||||
|
const VIDEO_MAX_DURATION = 60
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
gallery: GalleryModel
|
gallery: GalleryModel
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
|
selectVideo: (video: ImagePickerAsset) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenCameraBtn({gallery, disabled}: Props) {
|
export function OpenCameraBtn({gallery, disabled, selectVideo}: Props) {
|
||||||
const {track} = useAnalytics()
|
const {track} = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {requestCameraAccessIfNeeded} = useCameraPermission()
|
const {requestCameraAccessIfNeeded} = useCameraPermission()
|
||||||
const [mediaPermissionRes, requestMediaPermission] =
|
const [mediaPermissionRes, requestMediaPermission] =
|
||||||
MediaLibrary.usePermissions({granularPermissions: ['photo']})
|
MediaLibrary.usePermissions({granularPermissions: ['photo']})
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const control = Dialog.useDialogControl()
|
||||||
|
|
||||||
const onPressTakePicture = useCallback(async () => {
|
const onPressTakePicture = useCallback(async () => {
|
||||||
track('Composer:CameraOpened')
|
track('Composer:CameraOpened')
|
||||||
@@ -49,7 +62,7 @@ export function OpenCameraBtn({gallery, disabled}: Props) {
|
|||||||
await MediaLibrary.createAssetAsync(img.path)
|
await MediaLibrary.createAssetAsync(img.path)
|
||||||
}
|
}
|
||||||
gallery.add(img)
|
gallery.add(img)
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
// ignore
|
// ignore
|
||||||
logger.warn('Error using camera', {error: err})
|
logger.warn('Error using camera', {error: err})
|
||||||
}
|
}
|
||||||
@@ -61,23 +74,101 @@ export function OpenCameraBtn({gallery, disabled}: Props) {
|
|||||||
requestMediaPermission,
|
requestMediaPermission,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const onPressTakeVideo = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const response = await launchCameraAsync({
|
||||||
|
mediaTypes: MediaTypeOptions.Videos,
|
||||||
|
quality: 0.8,
|
||||||
|
videoMaxDuration: VIDEO_MAX_DURATION,
|
||||||
|
exif: false,
|
||||||
|
presentationStyle: UIImagePickerPresentationStyle.PAGE_SHEET,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.canceled && response.assets[0]) {
|
||||||
|
selectVideo(response.assets[0])
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// ignore
|
||||||
|
logger.warn('Error using camera', {error: err})
|
||||||
|
}
|
||||||
|
}, [selectVideo])
|
||||||
|
|
||||||
const shouldShowCameraButton = isNative || isMobileWeb
|
const shouldShowCameraButton = isNative || isMobileWeb
|
||||||
if (!shouldShowCameraButton) {
|
if (!shouldShowCameraButton) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isMobileWeb) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
testID="openCameraButton"
|
||||||
|
onPress={onPressTakePicture}
|
||||||
|
label={_(msg`Camera`)}
|
||||||
|
accessibilityHint={_(msg`Opens camera on device`)}
|
||||||
|
style={a.p_sm}
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
color="primary"
|
||||||
|
disabled={disabled}>
|
||||||
|
<Camera size="lg" style={disabled && t.atoms.text_contrast_low} />
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<>
|
||||||
testID="openCameraButton"
|
<Button
|
||||||
onPress={onPressTakePicture}
|
testID="openCameraButton"
|
||||||
label={_(msg`Camera`)}
|
onPress={() => {
|
||||||
accessibilityHint={_(msg`Opens camera on device`)}
|
Keyboard.dismiss()
|
||||||
style={a.p_sm}
|
control.open()
|
||||||
variant="ghost"
|
}}
|
||||||
shape="round"
|
label={_(msg`Camera`)}
|
||||||
color="primary"
|
accessibilityHint={_(msg`Take a photo or video with your camera`)}
|
||||||
disabled={disabled}>
|
style={a.p_sm}
|
||||||
<Camera size="lg" style={disabled && t.atoms.text_contrast_low} />
|
variant="ghost"
|
||||||
</Button>
|
shape="round"
|
||||||
|
color="primary"
|
||||||
|
disabled={disabled}>
|
||||||
|
<Camera size="lg" style={disabled && t.atoms.text_contrast_low} />
|
||||||
|
</Button>
|
||||||
|
<Dialog.Outer control={control} testID="selectCameraModeDialog">
|
||||||
|
<Dialog.Handle />
|
||||||
|
<Dialog.Inner label={_(msg`Camera Mode`)} style={a.gap_md}>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Take a photo`)}
|
||||||
|
variant="solid"
|
||||||
|
color="secondary"
|
||||||
|
size="large"
|
||||||
|
onPress={() => control.close(onPressTakePicture)}>
|
||||||
|
<ButtonIcon icon={Camera} />
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Photo</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Take a video`)}
|
||||||
|
variant="solid"
|
||||||
|
color="secondary"
|
||||||
|
size="large"
|
||||||
|
onPress={() => control.close(onPressTakeVideo)}>
|
||||||
|
<ButtonIcon icon={FilmCamera} />
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Video</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Cancel`)}
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
size="medium"
|
||||||
|
onPress={() => control.close()}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Cancel</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</Dialog.Inner>
|
||||||
|
</Dialog.Outer>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user