feat: Ability to record videos and capture photos directly in app by selecting + in Files view (#2095)

This commit is contained in:
Aman Harwara
2022-12-13 21:41:41 +05:30
committed by GitHub
parent cd8596b14e
commit d4b63e4ea6
11 changed files with 552 additions and 39 deletions

View File

@@ -302,6 +302,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
isFilesSmartView={isFilesSmartView}
optionsSubtitle={optionsSubtitle}
selectedTag={selectedTag}
filesController={filesController}
/>
)}
<SearchBar itemListController={itemListController} searchOptionsController={searchOptionsController} />

View File

@@ -0,0 +1,127 @@
import PhotoCaptureModal from '@/Components/CameraCaptureModal/PhotoCaptureModal'
import VideoCaptureModal from '@/Components/CameraCaptureModal/VideoCaptureModal'
import Icon from '@/Components/Icon/Icon'
import Menu from '@/Components/Menu/Menu'
import MenuItem from '@/Components/Menu/MenuItem'
import Popover from '@/Components/Popover/Popover'
import { FilesController } from '@/Controllers/FilesController'
import { PhotoRecorder } from '@/Controllers/Moments/PhotoRecorder'
import { classNames } from '@standardnotes/snjs'
import { useEffect, useRef, useState } from 'react'
type Props = {
isDailyEntry: boolean
isInFilesSmartView: boolean
addButtonLabel: string
addNewItem: () => void
filesController: FilesController
}
const AddItemMenuButton = ({
filesController,
isDailyEntry,
addButtonLabel,
isInFilesSmartView,
addNewItem,
}: Props) => {
const addItemButtonRef = useRef<HTMLButtonElement>(null)
const [isMenuOpen, setIsMenuOpen] = useState(false)
const [deviceHasCamera, setDeviceHasCamera] = useState(false)
const [captureType, setCaptureType] = useState<'photo' | 'video'>()
useEffect(() => {
const setCameraSupport = async () => {
setDeviceHasCamera(await PhotoRecorder.isSupported())
}
void setCameraSupport()
}, [])
const canShowMenu = isInFilesSmartView && deviceHasCamera
return (
<>
<button
className={classNames(
'hidden md:flex',
'h-8 w-8 hover:brightness-125',
'z-editor-title-bar ml-3 cursor-pointer items-center',
`justify-center rounded-full border border-solid border-transparent ${
isDailyEntry ? 'bg-danger text-danger-contrast' : 'bg-info text-info-contrast'
}`,
)}
title={addButtonLabel}
aria-label={addButtonLabel}
onClick={() => {
if (canShowMenu) {
setIsMenuOpen((isOpen) => !isOpen)
} else {
addNewItem()
}
}}
ref={addItemButtonRef}
>
<Icon type="add" size="custom" className="h-5 w-5" />
</button>
<Popover
open={canShowMenu && isMenuOpen}
anchorElement={addItemButtonRef.current}
togglePopover={() => {
setIsMenuOpen((isOpen) => !isOpen)
}}
side="bottom"
align="center"
className="py-2"
>
<Menu a11yLabel={'test'} isOpen={isMenuOpen}>
<MenuItem
onClick={() => {
addNewItem()
setIsMenuOpen(false)
}}
>
<Icon type="add" className="mr-2" />
{addButtonLabel}
</MenuItem>
<MenuItem
onClick={async () => {
setCaptureType('photo')
setIsMenuOpen(false)
}}
>
<Icon type="camera" className="mr-2" />
Take photo
</MenuItem>
<MenuItem
onClick={async () => {
setCaptureType('video')
setIsMenuOpen(false)
}}
>
<Icon type="camera" className="mr-2" />
Record video
</MenuItem>
</Menu>
</Popover>
{captureType === 'photo' && (
<PhotoCaptureModal
filesController={filesController}
close={() => {
setCaptureType(undefined)
}}
/>
)}
{captureType === 'video' && (
<VideoCaptureModal
filesController={filesController}
close={() => {
setCaptureType(undefined)
}}
/>
)}
</>
)
}
export default AddItemMenuButton

View File

@@ -9,6 +9,8 @@ import { isTag, VectorIconNameOrEmoji } from '@standardnotes/snjs'
import RoundIconButton from '@/Components/Button/RoundIconButton'
import { AnyTag } from '@/Controllers/Navigation/AnyTagType'
import { MediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
import AddItemMenuButton from './AddItemMenuButton'
import { FilesController } from '@/Controllers/FilesController'
type Props = {
application: WebApplication
@@ -19,6 +21,7 @@ type Props = {
isFilesSmartView: boolean
optionsSubtitle?: string
selectedTag: AnyTag
filesController: FilesController
}
const ContentListHeader = ({
@@ -30,6 +33,7 @@ const ContentListHeader = ({
isFilesSmartView,
optionsSubtitle,
selectedTag,
filesController,
}: Props) => {
const displayOptionsContainerRef = useRef<HTMLDivElement>(null)
const displayOptionsButtonRef = useRef<HTMLButtonElement>(null)
@@ -84,23 +88,15 @@ const ContentListHeader = ({
const AddButton = useMemo(() => {
return (
<button
className={classNames(
'hidden md:flex',
'h-8 w-8 hover:brightness-125',
'z-editor-title-bar ml-3 cursor-pointer items-center',
`justify-center rounded-full border border-solid border-transparent ${
isDailyEntry ? 'bg-danger text-danger-contrast' : 'bg-info text-info-contrast'
}`,
)}
title={addButtonLabel}
aria-label={addButtonLabel}
onClick={addNewItem}
>
<Icon type="add" size="custom" className="h-5 w-5" />
</button>
<AddItemMenuButton
isInFilesSmartView={isFilesSmartView}
isDailyEntry={isDailyEntry}
addButtonLabel={addButtonLabel}
addNewItem={addNewItem}
filesController={filesController}
/>
)
}, [addButtonLabel, addNewItem, isDailyEntry])
}, [addButtonLabel, addNewItem, filesController, isDailyEntry, isFilesSmartView])
const FolderName = useMemo(() => {
return (