@ -3,7 +3,7 @@ import { unstable_batchedUpdates as batchedUpdates } from 'react-dom';
import { FaAngleLeft , FaWindowClose } from 'react-icons/fa' ;
import { MdRotate90DegreesCcw } from 'react-icons/md' ;
import { AnimatePresence , motion } from 'framer-motion' ;
import { Table , SideSheet , Button, Position, ForkIcon , DisableIc on, ThemeProvider } from 'evergreen-ui' ;
import { Table , SideSheet , Position, ThemeProvider } from 'evergreen-ui' ;
import { useStateWithHistory } from 'react-use/lib/useStateWithHistory' ;
import useDebounceOld from 'react-use/lib/useDebounce' ; / / W a n t t o p h a s e o u t t h i s
import { useDebounce } from 'use-debounce' ;
@ -18,13 +18,15 @@ import isEqual from 'lodash/isEqual';
import theme from './theme' ;
import useTimelineScroll from './hooks/useTimelineScroll' ;
import useUser Preferences from './hooks/useUserPreferences ';
import useUser SettingsRoot from './hooks/useUserSettingsRoot ';
import useFfmpegOperations from './hooks/useFfmpegOperations' ;
import useKeyframes from './hooks/useKeyframes' ;
import useWaveform from './hooks/useWaveform' ;
import useKeyboard from './hooks/useKeyboard' ;
import useFileFormatState from './hooks/useFileFormatState' ;
import UserSettingsContext from './contexts/UserSettingsContext' ;
import NoFileLoaded from './NoFileLoaded' ;
import Canvas from './Canvas' ;
import TopMenu from './TopMenu' ;
@ -36,7 +38,7 @@ import Settings from './Settings';
import Timeline from './Timeline' ;
import BottomBar from './BottomBar' ;
import ExportConfirm from './ExportConfirm' ;
import ValueTuner from './components/ValueTuner ';
import ValueTuner s from './components/ValueTuner s ';
import VolumeControl from './components/VolumeControl' ;
import SubtitleControl from './components/SubtitleControl' ;
import BatchFilesList from './components/BatchFilesList' ;
@ -59,7 +61,7 @@ import { shouldCopyStreamByDefault, getAudioStreams, getRealVideoStreams, defaul
import { exportEdlFile , readEdlFile , saveLlcProject , loadLlcProject , askForEdlImport } from './edlStore' ;
import { formatYouTube , getTimeFromFrameNum as getTimeFromFrameNumRaw , getFrameCountRaw } from './edlFormats' ;
import {
getOutPath , toast , errorToast , handleError , setFileNameTitle , getOutDir , getFileDir , withBlur ,
getOutPath , toast , errorToast , handleError , setFileNameTitle , getOutDir , getFileDir ,
checkDirWriteAccess , dirExists , openDirToast , isMasBuild , isStoreBuild , dragPreventer ,
isDurationValid , filenamify , getOutFileExtension , generateSegFileName , defaultOutSegTemplate ,
havePermissionToReadFile , resolvePathIfNeeded , getPathReadAccessError , html5ifiedPrefix , html5dummySuffix , findExistingHtml5FriendlyFile ,
@ -196,7 +198,7 @@ const App = memo(() => {
const {
captureFormat , setCaptureFormat , customOutDir , setCustomOutDir , keyframeCut , setKeyframeCut , preserveMovData , setPreserveMovData , movFastStart , setMovFastStart , avoidNegativeTs , setAvoidNegativeTs , autoMerge , setAutoMerge , timecodeFormat , setTimecodeFormat , invertCutSegments , setInvertCutSegments , autoExportExtraStreams , setAutoExportExtraStreams , askBeforeClose , setAskBeforeClose , enableAskForImportChapters , setEnableAskForImportChapters , enableAskForFileOpenAction , setEnableAskForFileOpenAction , playbackVolume , setPlaybackVolume , autoSaveProjectFile , setAutoSaveProjectFile , wheelSensitivity , setWheelSensitivity , invertTimelineScroll , setInvertTimelineScroll , language , setLanguage , ffmpegExperimental , setFfmpegExperimental , hideNotifications , setHideNotifications , autoLoadTimecode , setAutoLoadTimecode , autoDeleteMergedSegments , setAutoDeleteMergedSegments , exportConfirmEnabled , setExportConfirmEnabled , segmentsToChapters , setSegmentsToChapters , preserveMetadataOnMerge , setPreserveMetadataOnMerge , simpleMode , setSimpleMode , outSegTemplate , setOutSegTemplate , keyboardSeekAccFactor , setKeyboardSeekAccFactor , keyboardNormalSeekSpeed , setKeyboardNormalSeekSpeed , enableTransferTimestamps , setEnableTransferTimestamps , outFormatLocked , setOutFormatLocked , safeOutputFileName , setSafeOutputFileName , enableAutoHtml5ify , setEnableAutoHtml5ify , segmentsToChaptersOnly , setSegmentsToChaptersOnly , keyBindings , setKeyBindings , resetKeyBindings , enableSmartCut , setEnableSmartCut ,
} = useUser Preferences ( ) ;
} = useUser SettingsRoot ( ) ;
const {
concatFiles , html5ifyDummy , cutMultiple , autoConcatCutSegments , html5ify , fixInvalidDuration ,
@ -214,8 +216,6 @@ const App = memo(() => {
const isFileOpened = ! ! filePath ;
const onOutFormatLockedClick = ( ) => setOutFormatLocked ( ( v ) => ( v ? undefined : fileFormat ) ) ;
const onOutputFormatUserChange = useCallback ( ( newFormat ) => {
setFileFormat ( newFormat ) ;
if ( outFormatLocked ) {
@ -740,6 +740,10 @@ const App = memo(() => {
return ! v ;
} ) , [ hideAllNotifications , setSimpleMode ] ) ;
const userSettingsContext = useMemo ( ( ) => ( {
captureFormat , setCaptureFormat , toggleCaptureFormat , customOutDir , setCustomOutDir , changeOutDir , keyframeCut , setKeyframeCut , toggleKeyframeCut , preserveMovData , setPreserveMovData , togglePreserveMovData , movFastStart , setMovFastStart , toggleMovFastStart , avoidNegativeTs , setAvoidNegativeTs , autoMerge , setAutoMerge , timecodeFormat , setTimecodeFormat , invertCutSegments , setInvertCutSegments , autoExportExtraStreams , setAutoExportExtraStreams , askBeforeClose , setAskBeforeClose , enableAskForImportChapters , setEnableAskForImportChapters , enableAskForFileOpenAction , setEnableAskForFileOpenAction , playbackVolume , setPlaybackVolume , autoSaveProjectFile , setAutoSaveProjectFile , wheelSensitivity , setWheelSensitivity , invertTimelineScroll , setInvertTimelineScroll , language , setLanguage , ffmpegExperimental , setFfmpegExperimental , hideNotifications , setHideNotifications , autoLoadTimecode , setAutoLoadTimecode , autoDeleteMergedSegments , setAutoDeleteMergedSegments , exportConfirmEnabled , setExportConfirmEnabled , toggleExportConfirmEnabled , segmentsToChapters , setSegmentsToChapters , toggleSegmentsToChapters , preserveMetadataOnMerge , setPreserveMetadataOnMerge , togglePreserveMetadataOnMerge , simpleMode , setSimpleMode , toggleSimpleMode , outSegTemplate , setOutSegTemplate , keyboardSeekAccFactor , setKeyboardSeekAccFactor , keyboardNormalSeekSpeed , setKeyboardNormalSeekSpeed , enableTransferTimestamps , setEnableTransferTimestamps , outFormatLocked , setOutFormatLocked , safeOutputFileName , setSafeOutputFileName , toggleSafeOutputFileName , enableAutoHtml5ify , setEnableAutoHtml5ify , segmentsToChaptersOnly , setSegmentsToChaptersOnly , keyBindings , setKeyBindings , resetKeyBindings , enableSmartCut , setEnableSmartCut ,
} ) , [ askBeforeClose , autoDeleteMergedSegments , autoExportExtraStreams , autoLoadTimecode , autoMerge , autoSaveProjectFile , avoidNegativeTs , captureFormat , changeOutDir , customOutDir , enableAskForFileOpenAction , enableAskForImportChapters , enableAutoHtml5ify , enableSmartCut , enableTransferTimestamps , exportConfirmEnabled , ffmpegExperimental , hideNotifications , invertCutSegments , invertTimelineScroll , keyBindings , keyboardNormalSeekSpeed , keyboardSeekAccFactor , keyframeCut , language , movFastStart , outFormatLocked , outSegTemplate , playbackVolume , preserveMetadataOnMerge , preserveMovData , resetKeyBindings , safeOutputFileName , segmentsToChapters , segmentsToChaptersOnly , setAskBeforeClose , setAutoDeleteMergedSegments , setAutoExportExtraStreams , setAutoLoadTimecode , setAutoMerge , setAutoSaveProjectFile , setAvoidNegativeTs , setCaptureFormat , setCustomOutDir , setEnableAskForFileOpenAction , setEnableAskForImportChapters , setEnableAutoHtml5ify , setEnableSmartCut , setEnableTransferTimestamps , setExportConfirmEnabled , setFfmpegExperimental , setHideNotifications , setInvertCutSegments , setInvertTimelineScroll , setKeyBindings , setKeyboardNormalSeekSpeed , setKeyboardSeekAccFactor , setKeyframeCut , setLanguage , setMovFastStart , setOutFormatLocked , setOutSegTemplate , setPlaybackVolume , setPreserveMetadataOnMerge , setPreserveMovData , setSafeOutputFileName , setSegmentsToChapters , setSegmentsToChaptersOnly , setSimpleMode , setTimecodeFormat , setWheelSensitivity , simpleMode , timecodeFormat , toggleCaptureFormat , toggleExportConfirmEnabled , toggleKeyframeCut , toggleMovFastStart , togglePreserveMetadataOnMerge , togglePreserveMovData , toggleSafeOutputFileName , toggleSegmentsToChapters , toggleSimpleMode , wheelSensitivity ] ) ;
const isCopyingStreamId = useCallback ( ( path , streamId ) => (
! ! ( copyStreamIdsByFile [ path ] || { } ) [ streamId ]
) , [ copyStreamIdsByFile ] ) ;
@ -2109,23 +2113,6 @@ const App = memo(() => {
< OutputFormatSelect style = { style } detectedFileFormat = { detectedFileFormat } fileFormat = { fileFormat } onOutputFormatUserChange = { onOutputFormatUserChange } / >
) , [ detectedFileFormat , fileFormat , onOutputFormatUserChange ] ) ;
const renderCaptureFormatButton = useCallback ( ( props ) => (
< Button
title = { i18n . t ( 'Capture frame format' ) }
onClick = { withBlur ( toggleCaptureFormat ) }
/ / e s l i n t - d i s a b l e - n e x t - l i n e r e a c t / j s x - p r o p s - n o - s p r e a d i n g
{ ... props }
>
{ captureFormat }
< / Button >
) , [ captureFormat , toggleCaptureFormat ] ) ;
const AutoExportToggler = useCallback ( ( ) => (
< Button intent = { autoExportExtraStreams ? 'success' : 'danger' } iconBefore = { autoExportExtraStreams ? ForkIcon : DisableIcon } onClick = { ( ) => setAutoExportExtraStreams ( ! autoExportExtraStreams ) } >
{ autoExportExtraStreams ? i18n . t ( 'Extract' ) : i18n . t ( 'Discard' ) }
< / Button >
) , [ autoExportExtraStreams , setAutoExportExtraStreams ] ) ;
const onTunerRequested = useCallback ( ( type ) => {
setSettingsVisible ( false ) ;
setTunerVisible ( type ) ;
@ -2163,39 +2150,6 @@ const App = memo(() => {
const { t } = useTranslation ( ) ;
function renderTuner ( type ) {
/ / N O T E d e f a u l t v a l u e s a r e d u p l i c a t e d i n p u b l i c / c o n f i g S t o r e . j s
const types = {
wheelSensitivity : {
title : t ( 'Timeline trackpad/wheel sensitivity' ) ,
value : wheelSensitivity ,
setValue : setWheelSensitivity ,
default : 0.2 ,
} ,
keyboardNormalSeekSpeed : {
title : t ( 'Timeline keyboard seek speed' ) ,
value : keyboardNormalSeekSpeed ,
setValue : setKeyboardNormalSeekSpeed ,
min : 0 ,
max : 100 ,
default : 1 ,
} ,
keyboardSeekAccFactor : {
title : t ( 'Timeline keyboard seek acceleration' ) ,
value : keyboardSeekAccFactor ,
setValue : setKeyboardSeekAccFactor ,
min : 1 ,
max : 2 ,
default : 1.03 ,
} ,
} ;
const { title , value , setValue , min , max , default : defaultValue } = types [ type ] ;
const resetToDefault = ( ) => setValue ( defaultValue ) ;
return < ValueTuner title = { title } value = { value } setValue = { setValue } onFinished = { ( ) => setTunerVisible ( ) } max = { max } min = { min } resetToDefault = { resetToDefault } / > ;
}
function renderSubtitles ( ) {
if ( ! activeSubtitle ) return null ;
return < track default kind = "subtitles" label = { activeSubtitle . lang } srcLang = "en" src = { activeSubtitle . url } / > ;
@ -2204,14 +2158,14 @@ const App = memo(() => {
/ / t h r o w n e w E r r o r ( ' T e s t e r r o r b o u n d a r y ' ) ;
return (
< UserSettingsContext.Provider value = { userSettingsContext } >
< ThemeProvider value = { theme } >
< div style = { { display : 'flex' , flexDirection : 'column' , height : '100vh' } } >
< TopMenu
filePath = { filePath }
fileFormat = { fileFormat }
copyAnyAudioTrack = { copyAnyAudioTrack }
toggleStripAudio = { toggleStripAudio }
customOutDir = { customOutDir }
changeOutDir = { changeOutDir }
clearOutDir = { clearOutDir }
isCustomFormatSelected = { isCustomFormatSelected }
renderOutFmt = { renderOutFmt }
@ -2221,15 +2175,6 @@ const App = memo(() => {
numStreamsTotal = { numStreamsTotal }
setStreamsSelectorShown = { setStreamsSelectorShown }
enabledSegments = { enabledSegments }
autoMerge = { autoMerge }
setAutoMerge = { setAutoMerge }
autoDeleteMergedSegments = { autoDeleteMergedSegments }
setAutoDeleteMergedSegments = { setAutoDeleteMergedSegments }
outFormatLocked = { outFormatLocked }
onOutFormatLockedClick = { onOutFormatLockedClick }
simpleMode = { simpleMode }
segmentsToChaptersOnly = { segmentsToChaptersOnly }
setSegmentsToChaptersOnly = { setSegmentsToChaptersOnly }
/ >
< div style = { { flexGrow : 1 , display : 'flex' , overflowY : 'hidden' } } >
@ -2252,7 +2197,7 @@ const App = memo(() => {
{ /* Middle part: */ }
< div style = { { position : 'relative' , flexGrow : 1 } } >
{ ! isFileOpened && < NoFileLoaded mifiLink = { mifiLink } toggleHelp = { toggleHelp } currentCutSeg = { currentCutSeg } simpleMode = { simpleMode } toggleSimpleMode = { toggleSimpleMode } / > }
{ ! isFileOpened && < NoFileLoaded mifiLink = { mifiLink } toggleHelp = { toggleHelp } currentCutSeg = { currentCutSeg } / > }
< div className = "no-user-select" style = { { position : 'absolute' , top : 0 , left : 0 , right : 0 , bottom : 0 , visibility : ! isFileOpened ? 'hidden' : undefined } } onWheel = { onTimelineWheel } >
{ /* eslint-disable-next-line jsx-a11y/media-has-caption */ }
@ -2303,7 +2248,7 @@ const App = memo(() => {
{ working && < Loading text = { working } cutProgress = { cutProgress } / > }
< / AnimatePresence >
{ tunerVisible && renderTuner ( tunerVisible ) }
{ tunerVisible && < ValueTuners type = { tunerVisible } onFinished = { ( ) => setTunerVisible ( ) } / > }
< / div >
< AnimatePresence >
@ -2316,13 +2261,11 @@ const App = memo(() => {
exit = { { x : rightBarWidth } }
>
< SegmentList
simpleMode = { simpleMode }
currentSegIndex = { currentSegIndexSafe }
apparentCutSegments = { apparentCutSegments }
inverseCutSegments = { inverseCutSegments }
getFrameCount = { getFrameCount }
formatTimecode = { formatTimecode }
invertCutSegments = { invertCutSegments }
onSegClick = { setCurrentSegIndex }
updateSegOrder = { updateSegOrder }
updateSegOrders = { updateSegOrders }
@ -2368,7 +2311,6 @@ const App = memo(() => {
apparentCutSegments = { apparentCutSegments }
setCurrentSegIndex = { setCurrentSegIndex }
currentSegIndexSafe = { currentSegIndexSafe }
invertCutSegments = { invertCutSegments }
inverseCutSegments = { inverseCutSegments }
formatTimecode = { formatTimecode }
onZoomWindowStartTimeChange = { setZoomWindowStartTime }
@ -2381,24 +2323,16 @@ const App = memo(() => {
< BottomBar
zoom = { zoom }
setZoom = { setZoom }
invertCutSegments = { invertCutSegments }
setInvertCutSegments = { setInvertCutSegments }
timelineToggleComfortZoom = { timelineToggleComfortZoom }
simpleMode = { simpleMode }
toggleSimpleMode = { toggleSimpleMode }
hasVideo = { hasVideo }
isRotationSet = { isRotationSet }
rotation = { rotation }
areWeCutting = { areWeCutting }
autoMerge = { autoMerge }
increaseRotation = { increaseRotation }
cleanupFilesDialog = { cleanupFilesDialog }
renderCaptureFormatButton = { renderCaptureFormatButton }
captureSnapshot = { captureSnapshot }
onExportPress = { onExportPress }
enabledSegments = { enabledSegments }
exportConfirmEnabled = { exportConfirmEnabled }
toggleExportConfirmEnabled = { toggleExportConfirmEnabled }
seekAbs = { seekAbs }
currentSegIndexSafe = { currentSegIndexSafe }
cutSegments = { cutSegments }
@ -2455,7 +2389,6 @@ const App = memo(() => {
shortestFlag = { shortestFlag }
setShortestFlag = { setShortestFlag }
nonCopiedExtraStreams = { nonCopiedExtraStreams }
AutoExportToggler = { AutoExportToggler }
customTagsByFile = { customTagsByFile }
setCustomTagsByFile = { setCustomTagsByFile }
customTagsByStreamId = { customTagsByStreamId }
@ -2465,7 +2398,7 @@ const App = memo(() => {
/ >
< / SideSheet >
< ExportConfirm filePath = { filePath } autoMerge = { autoMerge } setAutoMerge = { setAutoMerge } areWeCutting = { areWeCutting } enabledSegments = { enabledSegments } willMerge = { willMerge } visible = { exportConfirmVisible } onClosePress = { closeExportConfirm } onExportConfirm = { onExportConfirm } keyframeCut= { keyframeCut } toggleKeyframeCut = { toggleKeyframeCut } renderOutFmt= { renderOutFmt } preserveMovData= { preserveMovData } togglePreserveMovData = { togglePreserveMovData } movFastStart = { movFastStart } toggleMovFastStart = { toggleMovFastStart } avoidNegativeTs = { avoidNegativeTs } setAvoidNegativeTs = { setAvoidNegativeTs } changeOutDir = { changeOutDir } outputDir= { outputDir } numStreamsTotal = { numStreamsTotal } numStreamsToCopy = { numStreamsToCopy } setStreamsSelectorShown = { setStreamsSelectorShown } exportConfirmEnabled= { exportConfirmEnabled } toggleExportConfirmEnabled = { toggleExportConfirmEnabled } segmentsToChapters = { segmentsToChapters } toggleSegmentsToChapters = { toggleSegmentsToChapters } outFormat= { fileFormat } preserveMetadataOnMerge= { preserveMetadataOnMerge } togglePreserveMetadataOnMerge = { togglePreserveMetadataOnMerge } setOutSegTemplate= { setOutSegTemplate } outSegTemplate = { outSegTemplateOrDefault } generateOutSegFileNames = { generateOutSegFileNames } currentSegIndexSafe = { currentSegIndexSafe } getOutSegError = { getOutSegError } autoDeleteMergedSegments = { autoDeleteMergedSegments } setAutoDeleteMergedSegments = { setAutoDeleteMergedSegments } safeOutputFileName = { safeOutputFileName } toggleSafeOutputFileName = { toggleSafeOutputFileName } segmentsToChaptersOnly = { segmentsToChaptersOnly } setSegmentsToChaptersOnly = { setSegmentsToChaptersOnly } enableSmartCut = { enableSmartCut } setEnableSmartCut = { setEnableSmartCut } / >
< ExportConfirm filePath = { filePath } areWeCutting = { areWeCutting } enabledSegments = { enabledSegments } willMerge = { willMerge } visible = { exportConfirmVisible } onClosePress = { closeExportConfirm } onExportConfirm = { onExportConfirm } renderOutFmt= { renderOutFmt } outputDir= { outputDir } numStreamsTotal = { numStreamsTotal } numStreamsToCopy = { numStreamsToCopy } setStreamsSelectorShown = { setStreamsSelectorShown } outFormat= { fileFormat } setOutSegTemplate= { setOutSegTemplate } outSegTemplate = { outSegTemplateOrDefault } generateOutSegFileNames = { generateOutSegFileNames } currentSegIndexSafe = { currentSegIndexSafe } getOutSegError = { getOutSegError } / >
< HelpSheet
visible = { helpVisible }
@ -2482,38 +2415,6 @@ const App = memo(() => {
< / Table.Head >
< Table.Body >
< Settings
changeOutDir = { changeOutDir }
customOutDir = { customOutDir }
keyframeCut = { keyframeCut }
setKeyframeCut = { setKeyframeCut }
invertCutSegments = { invertCutSegments }
setInvertCutSegments = { setInvertCutSegments }
autoSaveProjectFile = { autoSaveProjectFile }
setAutoSaveProjectFile = { setAutoSaveProjectFile }
timecodeFormat = { timecodeFormat }
setTimecodeFormat = { setTimecodeFormat }
askBeforeClose = { askBeforeClose }
setAskBeforeClose = { setAskBeforeClose }
enableAskForImportChapters = { enableAskForImportChapters }
setEnableAskForImportChapters = { setEnableAskForImportChapters }
enableAskForFileOpenAction = { enableAskForFileOpenAction }
setEnableAskForFileOpenAction = { setEnableAskForFileOpenAction }
ffmpegExperimental = { ffmpegExperimental }
setFfmpegExperimental = { setFfmpegExperimental }
invertTimelineScroll = { invertTimelineScroll }
setInvertTimelineScroll = { setInvertTimelineScroll }
language = { language }
setLanguage = { setLanguage }
hideNotifications = { hideNotifications }
setHideNotifications = { setHideNotifications }
autoLoadTimecode = { autoLoadTimecode }
setAutoLoadTimecode = { setAutoLoadTimecode }
enableTransferTimestamps = { enableTransferTimestamps }
setEnableTransferTimestamps = { setEnableTransferTimestamps }
enableAutoHtml5ify = { enableAutoHtml5ify }
setEnableAutoHtml5ify = { setEnableAutoHtml5ify }
AutoExportToggler = { AutoExportToggler }
renderCaptureFormatButton = { renderCaptureFormatButton }
onTunerRequested = { onTunerRequested }
onKeyboardShortcutsDialogRequested = { onKeyboardShortcutsDialogRequested }
/ >
@ -2521,11 +2422,12 @@ const App = memo(() => {
< / Table >
< / Sheet >
< ConcatDialog isShown = { batchFiles . length > 0 && concatDialogVisible } onHide = { ( ) => setConcatDialogVisible ( false ) } initialPaths = { batchFilePaths } onConcat = { userConcatFiles } se gmentsToChapters= { segmentsToChapters } setSegmentsToChapters = { setSegmentsToChapters } se tAlwaysConcatMultipleFiles= { setAlwaysConcatMultipleFiles } alwaysConcatMultipleFiles = { alwaysConcatMultipleFiles } preserveMetadataOnMerge = { preserveMetadataOnMerge } setPreserveMetadataOnMerge = { setPreserveMetadataOnMerge } preserveMovData = { preserveMovData } setPreserveMovData = { setPreserveMovData } / >
< ConcatDialog isShown = { batchFiles . length > 0 && concatDialogVisible } onHide = { ( ) => setConcatDialogVisible ( false ) } initialPaths = { batchFilePaths } onConcat = { userConcatFiles } se tAlwaysConcatMultipleFiles= { setAlwaysConcatMultipleFiles } alwaysConcatMultipleFiles = { alwaysConcatMultipleFiles } / >
< KeyboardShortcuts isShown = { keyboardShortcutsVisible } onHide = { ( ) => setKeyboardShortcutsVisible ( false ) } keyBindings = { keyBindings } setKeyBindings = { setKeyBindings } currentCutSeg = { currentCutSeg } resetKeyBindings = { resetKeyBindings } / >
< / div >
< / ThemeProvider >
< / UserSettingsContext.Provider >
) ;
} ) ;