color add segment button with next seg color

closes #2609
pull/2640/head
Mikael Finstad 9 months ago
parent 25111307d7
commit 251113d617
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26

@ -24,7 +24,7 @@ import useFrameCapture from './hooks/useFrameCapture';
import useSegments from './hooks/useSegments'; import useSegments from './hooks/useSegments';
import useDirectoryAccess from './hooks/useDirectoryAccess'; import useDirectoryAccess from './hooks/useDirectoryAccess';
import { UserSettingsContext, SegColorsContext, UserSettingsContextType, AppContext, AppContextType } from './contexts'; import { UserSettingsContext, SegColorsContext, UserSettingsContextType, AppContext, AppContextType, SegColorsContextType } from './contexts';
import NoFileLoaded from './NoFileLoaded'; import NoFileLoaded from './NoFileLoaded';
import MediaSourcePlayer from './MediaSourcePlayer'; import MediaSourcePlayer from './MediaSourcePlayer';
@ -80,7 +80,7 @@ import { adjustRate } from './util/rate-calculator';
import { askExtractFramesAsImages } from './dialogs/extractFrames'; import { askExtractFramesAsImages } from './dialogs/extractFrames';
import { askForOutDir, askForImportChapters, askForFileOpenAction, showDiskFull, showExportFailedDialog, showConcatFailedDialog, openYouTubeChaptersDialog, showRefuseToOverwrite, showOpenDialog, showMuxNotSupported, promptDownloadMediaUrl, CleanupChoicesType, showOutputNotWritable, deleteFiles, mustDisallowVob, toastError } from './dialogs'; import { askForOutDir, askForImportChapters, askForFileOpenAction, showDiskFull, showExportFailedDialog, showConcatFailedDialog, openYouTubeChaptersDialog, showRefuseToOverwrite, showOpenDialog, showMuxNotSupported, promptDownloadMediaUrl, CleanupChoicesType, showOutputNotWritable, deleteFiles, mustDisallowVob, toastError } from './dialogs';
import { openSendReportDialog } from './reporting'; import { openSendReportDialog } from './reporting';
import { sortSegments, convertSegmentsToChaptersWithGaps, hasAnySegmentOverlap, isDurationValid, getPlaybackAction, getSegmentTags, filterNonMarkers } from './segments'; import { sortSegments, convertSegmentsToChaptersWithGaps, hasAnySegmentOverlap, isDurationValid, getPlaybackAction, getSegmentTags, filterNonMarkers, isInitialSegment } from './segments';
import { generateCutFileNames as generateCutFileNamesRaw, generateCutMergedFileNames as generateCutMergedFileNamesRaw, generateMergedFileNames as generateMergedFileNamesRaw, defaultCutFileTemplate, defaultCutMergedFileTemplate, defaultMergedFileTemplate, GenerateMergedOutFileNamesParams, GeneratedOutFileNames } from './util/outputNameTemplate'; import { generateCutFileNames as generateCutFileNamesRaw, generateCutMergedFileNames as generateCutMergedFileNamesRaw, generateMergedFileNames as generateMergedFileNamesRaw, defaultCutFileTemplate, defaultCutMergedFileTemplate, defaultMergedFileTemplate, GenerateMergedOutFileNamesParams, GeneratedOutFileNames } from './util/outputNameTemplate';
import { rightBarWidth, leftBarWidth, ffmpegExtractWindow, zoomMax } from './util/constants'; import { rightBarWidth, leftBarWidth, ffmpegExtractWindow, zoomMax } from './util/constants';
import BigWaveform from './components/BigWaveform'; import BigWaveform from './components/BigWaveform';
@ -323,7 +323,7 @@ function App() {
}, [isFileOpened]); }, [isFileOpened]);
const { const {
cutSegments, cutSegmentsHistory, createSegmentsFromKeyframes, shuffleSegments, detectBlackScenes, detectSilentScenes, detectSceneChanges, removeSegment, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, combineSelectedSegments, shiftAllSegmentTimes, alignSegmentTimesToKeyframes, updateSegOrder, updateSegOrders, reorderSegsByStartTime, addSegment, setCutStart, setCutEnd, labelSegment, splitCurrentSegment, focusSegmentAtCursor, selectSegmentsAtCursor, createNumSegments, createFixedDurationSegments, createFixedByteSizedSegments, createRandomSegments, haveInvalidSegs, currentSegIndexSafe, currentCutSeg, inverseCutSegments, clearSegments, clearSegColorCounter, loadCutSegments, setCutTime, setCurrentSegIndex, labelSelectedSegments, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, toggleCurrentSegmentSelected, invertSelectedSegments, removeSelectedSegments, selectSegmentsByLabel, selectSegmentsByExpr, selectAllMarkers, mutateSegmentsByExpr, toggleSegmentSelected, selectOnlySegment, selectedSegments, segmentsOrInverse, segmentsToExport, duplicateCurrentSegment, duplicateSegment, updateSegAtIndex, findSegmentsAtCursor, maybeCreateFullLengthSegment, currentCutSegOrWholeTimeline, cutSegments, cutSegmentsHistory, createSegmentsFromKeyframes, shuffleSegments, detectBlackScenes, detectSilentScenes, detectSceneChanges, removeSegment, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, combineSelectedSegments, shiftAllSegmentTimes, alignSegmentTimesToKeyframes, updateSegOrder, updateSegOrders, reorderSegsByStartTime, addSegment, setCutStart, setCutEnd, labelSegment, splitCurrentSegment, focusSegmentAtCursor, selectSegmentsAtCursor, createNumSegments, createFixedDurationSegments, createFixedByteSizedSegments, createRandomSegments, haveInvalidSegs, currentSegIndexSafe, currentCutSeg, inverseCutSegments, clearSegments, clearSegColorCounter, loadCutSegments, setCutTime, setCurrentSegIndex, labelSelectedSegments, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, toggleCurrentSegmentSelected, invertSelectedSegments, removeSelectedSegments, selectSegmentsByLabel, selectSegmentsByExpr, selectAllMarkers, mutateSegmentsByExpr, toggleSegmentSelected, selectOnlySegment, selectedSegments, segmentsOrInverse, segmentsToExport, duplicateCurrentSegment, duplicateSegment, updateSegAtIndex, findSegmentsAtCursor, maybeCreateFullLengthSegment, currentCutSegOrWholeTimeline, segColorCounter,
} = useSegments({ filePath, workingRef, setWorking, setProgress, videoStream: activeVideoStream, fileDuration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly, timecodePlaceholder, parseTimecode, appendFfmpegCommandLog, fileDurationNonZero, mainFileMeta, seekAbs, activeVideoStreamIndex, activeAudioStreamIndexes, handleError, showGenericDialog }); } = useSegments({ filePath, workingRef, setWorking, setProgress, videoStream: activeVideoStream, fileDuration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly, timecodePlaceholder, parseTimecode, appendFfmpegCommandLog, fileDurationNonZero, mainFileMeta, seekAbs, activeVideoStreamIndex, activeAudioStreamIndexes, handleError, showGenericDialog });
const { getEdlFilePath, projectFileSavePath, getProjectFileSavePath } = useSegmentsAutoSave({ autoSaveProjectFile, storeProjectInWorkingDir, filePath, customOutDir, cutSegments }); const { getEdlFilePath, projectFileSavePath, getProjectFileSavePath } = useSegmentsAutoSave({ autoSaveProjectFile, storeProjectInWorkingDir, filePath, customOutDir, cutSegments });
@ -463,12 +463,13 @@ function App() {
}; };
}, [allUserSettings, changeOutDir, effectiveExportMode, toggleCaptureFormat, toggleExportConfirmEnabled, toggleKeyframeCut, toggleSafeOutputFileName, toggleSimpleMode]); }, [allUserSettings, changeOutDir, effectiveExportMode, toggleCaptureFormat, toggleExportConfirmEnabled, toggleKeyframeCut, toggleSafeOutputFileName, toggleSimpleMode]);
const segColorsContext = useMemo(() => ({ const segColorsContext = useMemo<SegColorsContextType>(() => ({
getSegColor: (seg: SegmentColorIndex | undefined) => { getSegColor: (seg: SegmentColorIndex | undefined) => {
const color = getSegColor(seg); const color = getSegColor(seg);
return preferStrongColors ? color.desaturate(0.2) : color.desaturate(0.6); return preferStrongColors ? color.desaturate(0.2) : color.desaturate(0.6);
}, },
}), [preferStrongColors]); nextSegColorIndex: isInitialSegment(cutSegments) ? segColorCounter : segColorCounter + 1,
}), [cutSegments, preferStrongColors, segColorCounter]);
const onActiveSubtitleChange = useCallback(async (index?: number) => { const onActiveSubtitleChange = useCallback(async (index?: number) => {
if (index == null) { if (index == null) {

@ -16,7 +16,7 @@ import { saveColor, controlsBackground, primaryTextColor, darkModeTransition } f
import { useSegColors } from './contexts'; import { useSegColors } from './contexts';
import { getSegmentTags } from './segments'; import { getSegmentTags } from './segments';
import TagEditor from './components/TagEditor'; import TagEditor from './components/TagEditor';
import { ContextMenuTemplate, DefiniteSegmentBase, FormatTimecode, GetFrameCount, InverseCutSegment, SegmentBase, SegmentTags, StateSegment } from './types'; import { ContextMenuTemplate, DefiniteSegmentBase, FormatTimecode, GetFrameCount, InverseCutSegment, SegmentBase, SegmentColorIndex, SegmentTags, StateSegment } from './types';
import { UseSegments } from './hooks/useSegments'; import { UseSegments } from './hooks/useSegments';
import * as Dialog from './components/Dialog'; import * as Dialog from './components/Dialog';
import { DialogButton } from './components/Button'; import { DialogButton } from './components/Button';
@ -363,14 +363,15 @@ function SegmentList({
onEditSegmentTags: (index: number) => void, onEditSegmentTags: (index: number) => void,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { getSegColor } = useSegColors(); const { getSegColor, nextSegColorIndex } = useSegColors();
const [draggingId, setDraggingId] = useState<UniqueIdentifier | undefined>(); const [draggingId, setDraggingId] = useState<UniqueIdentifier | undefined>();
const { invertCutSegments, simpleMode, darkMode, springAnimation } = useUserSettings(); const { invertCutSegments, simpleMode, darkMode, springAnimation } = useUserSettings();
const getButtonColor = useCallback((seg: StateSegment | undefined, next?: boolean) => getSegColor(seg ? { segColorIndex: next ? seg.segColorIndex + 1 : seg.segColorIndex } : undefined).desaturate(0.3).lightness(darkMode ? 45 : 55).string(), [darkMode, getSegColor]); const getButtonColor = useCallback((seg: SegmentColorIndex | undefined, next?: boolean) => getSegColor(seg ? { segColorIndex: next ? seg.segColorIndex + 1 : seg.segColorIndex } : undefined).desaturate(0.3).lightness(darkMode ? 45 : 55).string(), [darkMode, getSegColor]);
const currentSegColor = useMemo(() => getButtonColor(currentCutSeg), [currentCutSeg, getButtonColor]); const currentSegColor = useMemo(() => getButtonColor(currentCutSeg), [currentCutSeg, getButtonColor]);
const segAtCursorColor = useMemo(() => getButtonColor(firstSegmentAtCursor), [getButtonColor, firstSegmentAtCursor]); const segAtCursorColor = useMemo(() => getButtonColor(firstSegmentAtCursor), [getButtonColor, firstSegmentAtCursor]);
const nextSegmentColor = useMemo(() => getButtonColor({ segColorIndex: nextSegColorIndex }, false), [getButtonColor, nextSegColorIndex]);
const segmentsTotal = useMemo(() => selectedSegments.reduce((acc, seg) => (seg.end == null ? 0 : seg.end - seg.start) + acc, 0), [selectedSegments]); const segmentsTotal = useMemo(() => selectedSegments.reduce((acc, seg) => (seg.end == null ? 0 : seg.end - seg.start) + acc, 0), [selectedSegments]);
@ -420,7 +421,7 @@ function SegmentList({
<div style={{ display: 'flex', padding: '5px 0', alignItems: 'center', justifyContent: 'center', borderBottom: '1px solid var(--gray-6)' }}> <div style={{ display: 'flex', padding: '5px 0', alignItems: 'center', justifyContent: 'center', borderBottom: '1px solid var(--gray-6)' }}>
<FaPlus <FaPlus
size={24} size={24}
style={{ ...buttonBaseStyle, background: neutralButtonColor }} style={{ ...buttonBaseStyle, background: nextSegmentColor }}
role="button" role="button"
title={t('Add segment')} title={t('Add segment')}
onClick={addSegment} onClick={addSegment}

@ -19,8 +19,9 @@ export type UserSettingsContextType = Omit<UserSettingsRoot, 'settings'> & UserS
effectiveExportMode: ExportMode, effectiveExportMode: ExportMode,
} }
interface SegColorsContextType { export interface SegColorsContextType {
getSegColor: (seg: SegmentColorIndex | undefined) => Color getSegColor: (seg: SegmentColorIndex | undefined) => Color,
nextSegColorIndex: number,
} }
export type HandleError = (error: GenericError) => void; export type HandleError = (error: GenericError) => void;

@ -62,15 +62,22 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea
const { t } = useTranslation(); const { t } = useTranslation();
// Segment related state // Segment related state
const [segColorCounter, setSegColorCounterState] = useState(0);
const segColorCounterRef = useRef(0); const segColorCounterRef = useRef(0);
const setSegColorCounter = useCallback((v: number) => {
segColorCounterRef.current = v;
setSegColorCounterState(v);
}, []);
const createIndexedSegment = useCallback(({ segment, incrementCount }: { const createIndexedSegment = useCallback(({ segment, incrementCount }: {
segment?: Parameters<typeof createSegment>[0], segment?: Parameters<typeof createSegment>[0],
incrementCount?: boolean, incrementCount?: boolean,
} = {}) => { } = {}) => {
if (incrementCount) segColorCounterRef.current += 1; if (incrementCount) {
setSegColorCounter(segColorCounterRef.current + 1);
}
return addSegmentColorIndex(createSegment(segment), segColorCounterRef.current); return addSegmentColorIndex(createSegment(segment), segColorCounterRef.current);
}, []); }, [setSegColorCounter]);
const [cutSegments, setCutSegments, cutSegmentsHistory] = useStateWithHistory<StateSegment[], StateSegment[]>( const [cutSegments, setCutSegments, cutSegmentsHistory] = useStateWithHistory<StateSegment[], StateSegment[]>(
[], [],
@ -95,8 +102,8 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea
const clearSegColorCounter = useCallback(() => { const clearSegColorCounter = useCallback(() => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
segColorCounterRef.current = 0; setSegColorCounter(0);
}, [segColorCounterRef]); }, [setSegColorCounter]);
const safeSetCutSegments = useCallback((newSegmentsOrFn: StateSegment[] | ((a: StateSegment[]) => StateSegment[]), clampDuration?: number) => { const safeSetCutSegments = useCallback((newSegmentsOrFn: StateSegment[] | ((a: StateSegment[]) => StateSegment[]), clampDuration?: number) => {
function clampValue(val: number | undefined) { function clampValue(val: number | undefined) {
@ -1003,6 +1010,7 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea
updateSegAtIndex, updateSegAtIndex,
findSegmentsAtCursor, findSegmentsAtCursor,
currentCutSegOrWholeTimeline, currentCutSegOrWholeTimeline,
segColorCounter,
}; };
} }

Loading…
Cancel
Save