diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index e4740a04..69dfa5da 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -2281,11 +2281,21 @@ function App() { focusWindow(); - await userOpenFiles(filePaths); + userOpenFiles(filePaths); + } + const element = videoContainerRef.current; + element?.addEventListener('drop', onDrop); + return () => element?.removeEventListener('drop', onDrop); + }, [userOpenFiles, videoContainerRef]); + + useEffect(() => { + function onDrop(ev: DragEvent) { + // default drop handler to prevent new electron window from popping up https://github.com/electron/electron/issues/39839 + ev.preventDefault(); } document.body.addEventListener('drop', onDrop); return () => document.body.removeEventListener('drop', onDrop); - }, [userOpenFiles]); + }, []); const renderOutFmt = useCallback((style: CSSProperties) => ( diff --git a/src/renderer/src/NoFileLoaded.tsx b/src/renderer/src/NoFileLoaded.tsx index 760e5d6d..a36570de 100644 --- a/src/renderer/src/NoFileLoaded.tsx +++ b/src/renderer/src/NoFileLoaded.tsx @@ -5,11 +5,15 @@ import { useTranslation, Trans } from 'react-i18next'; import SetCutpointButton from './components/SetCutpointButton'; import SimpleModeButton from './components/SimpleModeButton'; import useUserSettings from './hooks/useUserSettings'; +import { StateSegment } from './types'; const electron = window.require('electron'); function NoFileLoaded({ mifiLink, currentCutSeg, onClick, darkMode }: { - mifiLink: unknown, currentCutSeg, onClick: () => void, darkMode?: boolean, + mifiLink: unknown, + currentCutSeg: StateSegment, + onClick: () => void, + darkMode?: boolean, }) { const { t } = useTranslation(); const { simpleMode } = useUserSettings(); diff --git a/src/renderer/src/TopMenu.tsx b/src/renderer/src/TopMenu.tsx index 9f0fca64..fa905b4c 100644 --- a/src/renderer/src/TopMenu.tsx +++ b/src/renderer/src/TopMenu.tsx @@ -1,4 +1,4 @@ -import { CSSProperties, ReactNode, memo, useCallback } from 'react'; +import { CSSProperties, ReactNode, memo, useCallback, useEffect, useRef } from 'react'; import { IoIosSettings } from 'react-icons/io'; import { FaLock, FaUnlock } from 'react-icons/fa'; import { CrossIcon, ListIcon, VolumeUpIcon, VolumeOffIcon } from 'evergreen-ui'; @@ -13,6 +13,8 @@ import useUserSettings from './hooks/useUserSettings'; import { InverseCutSegment } from './types'; +const { stat } = window.require('fs/promises'); + const outFmtStyle = { height: 20, maxWidth: 100 }; const exportModeStyle = { flexGrow: 0, flexBasis: 140 }; @@ -44,7 +46,8 @@ function TopMenu({ clearOutDir: () => void, }) { const { t } = useTranslation(); - const { customOutDir, changeOutDir, simpleMode, outFormatLocked, setOutFormatLocked } = useUserSettings(); + const { customOutDir, changeOutDir, setCustomOutDir, simpleMode, outFormatLocked, setOutFormatLocked } = useUserSettings(); + const workingDirButtonRef = useRef(null); const onOutFormatLockedClick = useCallback(() => setOutFormatLocked((v) => (v ? undefined : fileFormat)), [fileFormat, setOutFormatLocked]); @@ -55,6 +58,22 @@ function TopMenu({ return ; } + // Convenience for drag and drop: https://github.com/mifi/lossless-cut/issues/2147 + useEffect(() => { + async function onDrop(ev: DragEvent) { + ev.preventDefault(); + if (!ev.dataTransfer) return; + const paths = [...ev.dataTransfer.files].map((f) => f.path); + const [firstPath] = paths; + if (paths.length === 1 && firstPath && (await stat(firstPath)).isDirectory()) { + setCustomOutDir(firstPath); + } + } + const element = workingDirButtonRef.current; + element?.addEventListener('drop', onDrop); + return () => element?.removeEventListener('drop', onDrop); + }, [setCustomOutDir]); + return (
) { - return ( - // eslint-disable-next-line react/jsx-props-no-spreading, react/button-has-type -