mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-22 10:22:31 +01:00
improve batch list selection
https://github.com/mifi/lossless-cut/issues/89#issuecomment-1049831536
This commit is contained in:
parent
7c28d66025
commit
bdb050492f
@ -52,6 +52,8 @@ const defaultKeyBindings = [
|
||||
{ keys: 'command+down', action: 'timelineZoomOut' },
|
||||
{ keys: 'shift+down', action: 'batchNextFile' },
|
||||
|
||||
{ keys: 'shift+enter', action: 'batchOpenSelectedFile' },
|
||||
|
||||
// https://github.com/mifi/lossless-cut/issues/610
|
||||
{ keys: 'ctrl+z', action: 'undo' },
|
||||
{ keys: 'command+z', action: 'undo' },
|
||||
|
37
src/App.jsx
37
src/App.jsx
@ -153,6 +153,7 @@ const App = memo(() => {
|
||||
|
||||
// Batch state / concat files
|
||||
const [batchFiles, setBatchFiles] = useState([]);
|
||||
const [selectedBatchFiles, setSelectedBatchFiles] = useState([]);
|
||||
|
||||
// Segment related state
|
||||
const segCounterRef = useRef(0);
|
||||
@ -1055,9 +1056,13 @@ const App = memo(() => {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (askBeforeClose && !window.confirm(i18n.t('Are you sure you want to close the loaded batch of files?'))) return;
|
||||
setBatchFiles([]);
|
||||
setSelectedBatchFiles([]);
|
||||
}, [askBeforeClose]);
|
||||
|
||||
const batchRemoveFile = useCallback((path) => setBatchFiles((existingBatch) => existingBatch.filter((existingFile) => existingFile.path !== path)), []);
|
||||
const batchRemoveFile = useCallback((path) => {
|
||||
setBatchFiles((existingBatch) => existingBatch.filter((existingFile) => existingFile.path !== path));
|
||||
setSelectedBatchFiles([]);
|
||||
}, []);
|
||||
|
||||
const cleanupFilesDialog = useCallback(async () => {
|
||||
if (!isFileOpened) return;
|
||||
@ -1565,12 +1570,28 @@ const App = memo(() => {
|
||||
}, [userOpenSingleFile, setWorking, filePath]);
|
||||
|
||||
const batchFileJump = useCallback((direction) => {
|
||||
const pathIndex = batchFiles.findIndex(({ path }) => path === filePath);
|
||||
if (batchFiles.length === 0) return;
|
||||
if (selectedBatchFiles.length === 0) {
|
||||
setSelectedBatchFiles([batchFiles[0].path]);
|
||||
return;
|
||||
}
|
||||
const selectedFilePath = selectedBatchFiles[direction > 0 ? selectedBatchFiles.length - 1 : 0];
|
||||
const pathIndex = batchFiles.findIndex(({ path }) => path === selectedFilePath);
|
||||
if (pathIndex === -1) return;
|
||||
const nextFile = batchFiles[pathIndex + direction];
|
||||
if (!nextFile) return;
|
||||
batchOpenSingleFile(nextFile.path);
|
||||
}, [filePath, batchFiles, batchOpenSingleFile]);
|
||||
setSelectedBatchFiles([nextFile.path]);
|
||||
}, [batchFiles, selectedBatchFiles]);
|
||||
|
||||
const batchOpenSelectedFile = useCallback(() => {
|
||||
if (selectedBatchFiles.length === 0) return;
|
||||
batchOpenSingleFile(selectedBatchFiles[0]);
|
||||
}, [batchOpenSingleFile, selectedBatchFiles]);
|
||||
|
||||
const onBatchFileSelect = useCallback((path) => {
|
||||
if (selectedBatchFiles.includes(path)) batchOpenSingleFile(path);
|
||||
else setSelectedBatchFiles([path]);
|
||||
}, [batchOpenSingleFile, selectedBatchFiles]);
|
||||
|
||||
const goToTimecode = useCallback(async () => {
|
||||
if (!filePath) return;
|
||||
@ -1727,6 +1748,7 @@ const App = memo(() => {
|
||||
timelineZoomOut: () => { zoomRel(-1); return false; },
|
||||
batchPreviousFile: () => batchFileJump(-1),
|
||||
batchNextFile: () => batchFileJump(1),
|
||||
batchOpenSelectedFile,
|
||||
closeBatch,
|
||||
removeCurrentSegment: () => removeCutSegment(currentSegIndexSafe),
|
||||
undo: () => cutSegmentsHistory.back(),
|
||||
@ -1796,7 +1818,7 @@ const App = memo(() => {
|
||||
if (match) return bubble;
|
||||
|
||||
return true; // bubble the event
|
||||
}, [addCutSegment, askSetStartTimeOffset, batchFileJump, captureSnapshot, changePlaybackRate, cleanupFilesDialog, clearSegments, closeBatch, closeExportConfirm, concatCurrentBatch, concatDialogVisible, convertFormatBatch, createFixedDurationSegments, createNumSegments, currentSegIndexSafe, cutSegmentsHistory, disableAllSegments, enableAllSegments, enableOnlyCurrentSegment, exportConfirmVisible, extractAllStreams, goToTimecode, increaseRotation, invertAllCutSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, keyboardShortcutsVisible, onExportConfirm, onExportPress, onLabelSegmentPress, pause, play, removeCutSegment, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, setCutEnd, setCutStart, shortStep, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentEnabled, toggleHelp, toggleKeyboardShortcuts, toggleKeyframeCut, togglePlay, toggleSegmentsList, toggleStreamsSelector, toggleStripAudio, userHtml5ifyCurrentFile, zoomRel]);
|
||||
}, [addCutSegment, askSetStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, changePlaybackRate, cleanupFilesDialog, clearSegments, closeBatch, closeExportConfirm, concatCurrentBatch, concatDialogVisible, convertFormatBatch, createFixedDurationSegments, createNumSegments, currentSegIndexSafe, cutSegmentsHistory, disableAllSegments, enableAllSegments, enableOnlyCurrentSegment, exportConfirmVisible, extractAllStreams, goToTimecode, increaseRotation, invertAllCutSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, keyboardShortcutsVisible, onExportConfirm, onExportPress, onLabelSegmentPress, pause, play, removeCutSegment, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, setCutEnd, setCutStart, shortStep, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentEnabled, toggleHelp, toggleKeyboardShortcuts, toggleKeyframeCut, togglePlay, toggleSegmentsList, toggleStreamsSelector, toggleStripAudio, userHtml5ifyCurrentFile, zoomRel]);
|
||||
|
||||
useKeyboard({ keyBindings, onKeyPress });
|
||||
|
||||
@ -1843,8 +1865,10 @@ const App = memo(() => {
|
||||
const mapPathsToFiles = (paths) => paths.map((path) => ({ path, name: basename(path) }));
|
||||
if (append) {
|
||||
const newUniquePaths = newPaths.filter((newPath) => !existingFiles.some(({ path: existingPath }) => newPath === existingPath));
|
||||
setSelectedBatchFiles([newUniquePaths[0]]);
|
||||
return [...existingFiles, ...mapPathsToFiles(newUniquePaths)];
|
||||
}
|
||||
setSelectedBatchFiles([newPaths[0]]);
|
||||
return mapPathsToFiles(newPaths);
|
||||
});
|
||||
}, []);
|
||||
@ -2196,10 +2220,11 @@ const App = memo(() => {
|
||||
<AnimatePresence>
|
||||
{showLeftBar && (
|
||||
<BatchFilesList
|
||||
selectedBatchFiles={selectedBatchFiles}
|
||||
filePath={filePath}
|
||||
width={leftBarWidth}
|
||||
batchFiles={batchFiles}
|
||||
batchOpenSingleFile={batchOpenSingleFile}
|
||||
onBatchFileSelect={onBatchFileSelect}
|
||||
batchRemoveFile={batchRemoveFile}
|
||||
closeBatch={closeBatch}
|
||||
onMergeFilesClick={concatCurrentBatch}
|
||||
|
@ -5,7 +5,7 @@ import { FaAngleRight, FaFile } from 'react-icons/fa';
|
||||
import useContextMenu from '../hooks/useContextMenu';
|
||||
import { primaryTextColor } from '../colors';
|
||||
|
||||
const BatchFile = memo(({ path, filePath, name, onOpen, onDelete }) => {
|
||||
const BatchFile = memo(({ path, isOpen, isSelected, name, onSelect, onDelete }) => {
|
||||
const ref = useRef();
|
||||
|
||||
const { t } = useTranslation();
|
||||
@ -14,15 +14,14 @@ const BatchFile = memo(({ path, filePath, name, onOpen, onDelete }) => {
|
||||
], [t, onDelete, path]);
|
||||
|
||||
useContextMenu(ref, contextMenuTemplate);
|
||||
const isCurrent = path === filePath;
|
||||
|
||||
return (
|
||||
<div ref={ref} role="button" style={{ background: isCurrent ? 'rgba(255,255,255,0.15)' : undefined, fontSize: 13, padding: '3px 6px', display: 'flex', alignItems: 'center', alignContent: 'flex-start' }} title={path} onClick={() => onOpen(path)}>
|
||||
<div ref={ref} role="button" style={{ background: isSelected ? 'rgba(255,255,255,0.15)' : undefined, fontSize: 13, padding: '3px 6px', display: 'flex', alignItems: 'center', alignContent: 'flex-start' }} title={path} onClick={() => onSelect(path)}>
|
||||
<FaFile size={14} style={{ color: primaryTextColor, flexShrink: 0 }} />
|
||||
<div style={{ flexBasis: 4, flexShrink: 0 }} />
|
||||
<div style={{ whiteSpace: 'nowrap', cursor: 'pointer', overflow: 'hidden' }}>{name}</div>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
{isCurrent && <FaAngleRight size={14} style={{ color: 'white', marginRight: -5, flexShrink: 0 }} />}
|
||||
{isOpen && <FaAngleRight size={14} style={{ color: 'white', marginRight: -5, flexShrink: 0 }} />}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -16,7 +16,7 @@ const iconStyle = {
|
||||
padding: '3px 5px',
|
||||
};
|
||||
|
||||
const BatchFilesList = memo(({ filePath, width, batchFiles, batchOpenSingleFile, batchRemoveFile, closeBatch, onMergeFilesClick, onBatchConvertToSupportedFormatClick }) => {
|
||||
const BatchFilesList = memo(({ selectedBatchFiles, filePath, width, batchFiles, onBatchFileSelect, batchRemoveFile, closeBatch, onMergeFilesClick, onBatchConvertToSupportedFormatClick }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -37,7 +37,7 @@ const BatchFilesList = memo(({ filePath, width, batchFiles, batchOpenSingleFile,
|
||||
|
||||
<div style={{ overflowX: 'hidden', overflowY: 'auto' }}>
|
||||
{batchFiles.map(({ path, name }) => (
|
||||
<BatchFile key={path} path={path} name={name} filePath={filePath} onOpen={batchOpenSingleFile} onDelete={batchRemoveFile} />
|
||||
<BatchFile key={path} path={path} name={name} isSelected={selectedBatchFiles.includes(path)} isOpen={filePath === path} onSelect={onBatchFileSelect} onDelete={batchRemoveFile} />
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
@ -365,6 +365,10 @@ const KeyboardShortcuts = memo(({
|
||||
name: t('Next file'),
|
||||
category: batchFilesCategory,
|
||||
},
|
||||
batchOpenSelectedFile: {
|
||||
name: t('Open selected file'),
|
||||
category: batchFilesCategory,
|
||||
},
|
||||
closeBatch: {
|
||||
name: t('Close batch'),
|
||||
category: batchFilesCategory,
|
||||
|
Loading…
Reference in New Issue
Block a user