Skip to content

Commit

Permalink
tag improvements
Browse files Browse the repository at this point in the history
- add keyboard shortcut
- save when pressing add another
- add warning about duplicate keybinding

closes #1829
  • Loading branch information
mifi committed Dec 29, 2023
1 parent 9ab8ba3 commit d2b0974
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 19 deletions.
21 changes: 19 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ import { askForHtml5ifySpeed } from './dialogs/html5ify';
import { askForOutDir, askForImportChapters, promptTimeOffset, askForFileOpenAction, confirmExtractAllStreamsDialog, showCleanupFilesDialog, showDiskFull, showExportFailedDialog, showConcatFailedDialog, openYouTubeChaptersDialog, showRefuseToOverwrite, openDirToast, openExportFinishedToast, openConcatFinishedToast, showOpenDialog } from './dialogs';
import { openSendReportDialog } from './reporting';
import { fallbackLng } from './i18n';
import { createSegment, getCleanCutSegments, findSegmentsAtCursor, sortSegments, convertSegmentsToChapters, hasAnySegmentOverlap, isDurationValid, playOnlyCurrentSegment } from './segments';
import { createSegment, getCleanCutSegments, findSegmentsAtCursor, sortSegments, convertSegmentsToChapters, hasAnySegmentOverlap, isDurationValid, playOnlyCurrentSegment, getSegmentTags } from './segments';
import { generateOutSegFileNames as generateOutSegFileNamesRaw, defaultOutSegTemplate } from './util/outputNameTemplate';
import { rightBarWidth, leftBarWidth, ffmpegExtractWindow, zoomMax } from './util/constants';
import BigWaveform from './components/BigWaveform';
Expand Down Expand Up @@ -156,6 +156,8 @@ const App = memo(() => {
const [keyboardShortcutsVisible, setKeyboardShortcutsVisible] = useState(false);
const [mifiLink, setMifiLink] = useState();
const [alwaysConcatMultipleFiles, setAlwaysConcatMultipleFiles] = useState(false);
const [editingSegmentTagsSegmentIndex, setEditingSegmentTagsSegmentIndex] = useState();
const [editingSegmentTags, setEditingSegmentTags] = useState();

// Batch state / concat files
const [batchFiles, setBatchFiles] = useState([]);
Expand Down Expand Up @@ -1933,6 +1935,15 @@ const App = memo(() => {
}
}, []);

const onEditSegmentTags = useCallback((index) => {
setEditingSegmentTagsSegmentIndex(index);
setEditingSegmentTags(getSegmentTags(apparentCutSegments[index]));
}, [apparentCutSegments]);

const editCurrentSegmentTags = useCallback(() => {
onEditSegmentTags(currentSegIndexSafe);
}, [currentSegIndexSafe, onEditSegmentTags]);

const mainActions = useMemo(() => {
async function exportYouTube() {
if (!checkFileOpened()) return;
Expand Down Expand Up @@ -2036,6 +2047,7 @@ const App = memo(() => {
deselectAllSegments,
selectAllSegments,
selectOnlyCurrentSegment,
editCurrentSegmentTags,
toggleCurrentSegmentSelected,
invertSelectedSegments,
removeSelectedSegments,
Expand Down Expand Up @@ -2064,7 +2076,7 @@ const App = memo(() => {
showIncludeExternalStreamsDialog,
toggleFullscreenVideo,
};
}, [addSegment, alignSegmentTimesToKeyframes, apparentCutSegments, askStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, checkFileOpened, cleanupFilesDialog, clearSegments, closeBatch, closeFileWithConfirm, combineOverlappingSegments, combineSelectedSegments, concatBatch, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, createSegmentsFromKeyframes, currentSegIndexSafe, cutSegmentsHistory, deselectAllSegments, detectBlackScenes, detectSceneChanges, detectSilentScenes, duplicateCurrentSegment, extractAllStreams, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, fillSegmentsGaps, goToTimecode, handleShowStreamsSelectorClick, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, onExportPress, onLabelSegment, openFilesDialog, openSendReportDialogWithState, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, showIncludeExternalStreamsDialog, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleFullscreenVideo, toggleKeyboardShortcuts, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleSettings, toggleShowKeyframes, toggleShowThumbnails, toggleStreamsSelector, toggleStripAudio, toggleWaveformMode, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]);
}, [addSegment, alignSegmentTimesToKeyframes, apparentCutSegments, askStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, checkFileOpened, cleanupFilesDialog, clearSegments, closeBatch, closeFileWithConfirm, combineOverlappingSegments, combineSelectedSegments, concatBatch, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, createSegmentsFromKeyframes, currentSegIndexSafe, cutSegmentsHistory, deselectAllSegments, detectBlackScenes, detectSceneChanges, detectSilentScenes, duplicateCurrentSegment, editCurrentSegmentTags, extractAllStreams, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, fillSegmentsGaps, goToTimecode, handleShowStreamsSelectorClick, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, onExportPress, onLabelSegment, openFilesDialog, openSendReportDialogWithState, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, showIncludeExternalStreamsDialog, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleFullscreenVideo, toggleKeyboardShortcuts, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleSettings, toggleShowKeyframes, toggleShowThumbnails, toggleStreamsSelector, toggleStripAudio, toggleWaveformMode, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]);

const getKeyboardAction = useCallback((action) => mainActions[action], [mainActions]);

Expand Down Expand Up @@ -2455,6 +2467,11 @@ const App = memo(() => {
onSelectSegmentsByTag={onSelectSegmentsByTag}
onLabelSelectedSegments={onLabelSelectedSegments}
updateSegAtIndex={updateSegAtIndex}
editingSegmentTags={editingSegmentTags}
editingSegmentTagsSegmentIndex={editingSegmentTagsSegmentIndex}
setEditingSegmentTags={setEditingSegmentTags}
setEditingSegmentTagsSegmentIndex={setEditingSegmentTagsSegmentIndex}
onEditSegmentTags={onEditSegmentTags}
/>
)}
</AnimatePresence>
Expand Down
14 changes: 4 additions & 10 deletions src/SegmentList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ const SegmentList = memo(({
onLabelSegment, currentCutSeg, segmentAtCursor, toggleSegmentsList, splitCurrentSegment,
selectedSegments, isSegmentSelected, onSelectSingleSegment, onToggleSegmentSelected, onDeselectAllSegments, onSelectAllSegments, onSelectSegmentsByLabel, onSelectSegmentsByTag, onExtractSegmentFramesAsImages, onLabelSelectedSegments, onInvertSelectedSegments, onDuplicateSegmentClick,
jumpSegStart, jumpSegEnd, updateSegAtIndex,
editingSegmentTags, editingSegmentTagsSegmentIndex, setEditingSegmentTags, setEditingSegmentTagsSegmentIndex, onEditSegmentTags,
}) => {
const { t } = useTranslation();
const { getSegColor } = useSegColors();
Expand Down Expand Up @@ -271,26 +272,19 @@ const SegmentList = memo(({
);
}

const [editingSegmentTagsSegmentIndex, setEditingSegmentTagsSegmentIndex] = useState();
const [editingSegmentTags, setEditingSegmentTags] = useState();
const [editingTag, setEditingTag] = useState();

const onTagChange = useCallback((tag, value) => setEditingSegmentTags((existingTags) => ({
...existingTags,
[tag]: value,
})), []);
})), [setEditingSegmentTags]);

const onTagReset = useCallback((tag) => setEditingSegmentTags(({ [tag]: deleted, ...rest }) => rest), []);

const onEditSegmentTags = useCallback((index) => {
setEditingSegmentTagsSegmentIndex(index);
setEditingSegmentTags(getSegmentTags(apparentCutSegments[index]));
}, [apparentCutSegments]);
const onTagReset = useCallback((tag) => setEditingSegmentTags(({ [tag]: deleted, ...rest }) => rest), [setEditingSegmentTags]);

const onSegmentTagsCloseComplete = useCallback(() => {
setEditingSegmentTagsSegmentIndex();
setEditingSegmentTags();
}, []);
}, [setEditingSegmentTags, setEditingSegmentTagsSegmentIndex]);

const onSegmentTagsConfirm = useCallback(() => {
updateSegAtIndex(editingSegmentTagsSegmentIndex, { tags: editingSegmentTags });
Expand Down
12 changes: 9 additions & 3 deletions src/components/KeyboardShortcuts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import groupBy from 'lodash/groupBy';
import orderBy from 'lodash/orderBy';
import uniq from 'lodash/uniq';

import Swal from '../swal';
import SetCutpointButton from './SetCutpointButton';
import SegmentCutpointButton from './SegmentCutpointButton';

Expand Down Expand Up @@ -295,6 +296,10 @@ const KeyboardShortcuts = memo(({
name: t('Label current segment'),
category: segmentsAndCutpointsCategory,
},
editCurrentSegmentTags: {
name: t('Edit current segment tags'),
category: segmentsAndCutpointsCategory,
},
splitCurrentSegment: {
name: t('Split segment at cursor'),
category: segmentsAndCutpointsCategory,
Expand Down Expand Up @@ -622,8 +627,9 @@ const KeyboardShortcuts = memo(({
console.log('new key binding', action, keysStr);

setKeyBindings((existingBindings) => {
const haveDuplicate = existingBindings.some((existingBinding) => existingBinding.keys === keysStr);
if (haveDuplicate) {
const duplicate = existingBindings.find((existingBinding) => existingBinding.keys === keysStr);
if (duplicate) {
Swal.fire({ icon: 'error', title: t('Duplicate keyboard combination'), text: t('Combination is already bound to "{{alreadyBoundKey}}"', { alreadyBoundKey: actionsMap[duplicate.action]?.name }) });
console.log('trying to add duplicate');
return existingBindings;
}
Expand All @@ -632,7 +638,7 @@ const KeyboardShortcuts = memo(({
setCreatingBinding();
return [...existingBindings, { action, keys: keysStr }];
});
}, [setKeyBindings]);
}, [actionsMap, setKeyBindings, t]);

const missingActions = Object.keys(mainActions).filter((key) => actionsMap[key] == null);
if (missingActions.length > 0) throw new Error(`Action(s) missing: ${missingActions.join(',')}`);
Expand Down
14 changes: 10 additions & 4 deletions src/components/TagEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editi
setNewTag();
}, [editingTag, onTagReset, setEditingTag]);

function onEditClick(tag) {
const onEditClick = useCallback((tag) => {
if (newTag) {
onTagChange(editingTag, editingTagVal);
setEditingTag();
Expand All @@ -40,7 +40,7 @@ function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editi
setEditingTag(tag);
setEditingTagVal(mergedTags[tag]);
}
}
}, [editingTag, editingTagVal, existingTags, mergedTags, newTag, onResetClick, onTagChange, setEditingTag]);

function onSubmit(e) {
e.preventDefault();
Expand All @@ -50,12 +50,18 @@ function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editi
const onAddPress = useCallback(async (e) => {
e.preventDefault();
e.target.blur();

if (newTag || editingTag != null) {
// save any unsaved edit
onEditClick();
}

const tag = await askForMetadataKey({ title: addTagTitle, text: addTagText });
if (!tag || Object.keys(mergedTags).includes(tag)) return;
setEditingTag(tag);
setEditingTagVal('');
setNewTag(tag);
}, [addTagText, addTagTitle, mergedTags, setEditingTag]);
}, [addTagText, addTagTitle, editingTag, mergedTags, newTag, onEditClick, setEditingTag]);

useEffect(() => {
ref.current?.focus();
Expand Down Expand Up @@ -92,7 +98,7 @@ function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editi
</tbody>
</table>

<Button style={{ marginTop: 10 }} iconBefore={PlusIcon} onClick={onAddPress}>{t('Add metadata')}</Button>
<Button style={{ marginTop: 10 }} iconBefore={PlusIcon} onClick={onAddPress}>{addTagTitle}</Button>
</>
);
}
Expand Down

0 comments on commit d2b0974

Please sign in to comment.