diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index cd7ef96c..a1c3c83b 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -24,7 +24,7 @@ import useFrameCapture from './hooks/useFrameCapture'; import useSegments from './hooks/useSegments'; 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 MediaSourcePlayer from './MediaSourcePlayer'; @@ -80,7 +80,7 @@ import { adjustRate } from './util/rate-calculator'; 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 { 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 { rightBarWidth, leftBarWidth, ffmpegExtractWindow, zoomMax } from './util/constants'; import BigWaveform from './components/BigWaveform'; @@ -323,7 +323,7 @@ function App() { }, [isFileOpened]); 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 }); const { getEdlFilePath, projectFileSavePath, getProjectFileSavePath } = useSegmentsAutoSave({ autoSaveProjectFile, storeProjectInWorkingDir, filePath, customOutDir, cutSegments }); @@ -463,12 +463,13 @@ function App() { }; }, [allUserSettings, changeOutDir, effectiveExportMode, toggleCaptureFormat, toggleExportConfirmEnabled, toggleKeyframeCut, toggleSafeOutputFileName, toggleSimpleMode]); - const segColorsContext = useMemo(() => ({ + const segColorsContext = useMemo(() => ({ getSegColor: (seg: SegmentColorIndex | undefined) => { const color = getSegColor(seg); 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) => { if (index == null) { diff --git a/src/renderer/src/SegmentList.tsx b/src/renderer/src/SegmentList.tsx index 1435957e..3ef1f8cc 100644 --- a/src/renderer/src/SegmentList.tsx +++ b/src/renderer/src/SegmentList.tsx @@ -16,7 +16,7 @@ import { saveColor, controlsBackground, primaryTextColor, darkModeTransition } f import { useSegColors } from './contexts'; import { getSegmentTags } from './segments'; 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 * as Dialog from './components/Dialog'; import { DialogButton } from './components/Button'; @@ -363,14 +363,15 @@ function SegmentList({ onEditSegmentTags: (index: number) => void, }) { const { t } = useTranslation(); - const { getSegColor } = useSegColors(); + const { getSegColor, nextSegColorIndex } = useSegColors(); const [draggingId, setDraggingId] = useState(); 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 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]); @@ -420,7 +421,7 @@ function SegmentList({
& UserS effectiveExportMode: ExportMode, } -interface SegColorsContextType { - getSegColor: (seg: SegmentColorIndex | undefined) => Color +export interface SegColorsContextType { + getSegColor: (seg: SegmentColorIndex | undefined) => Color, + nextSegColorIndex: number, } export type HandleError = (error: GenericError) => void; diff --git a/src/renderer/src/hooks/useSegments.tsx b/src/renderer/src/hooks/useSegments.tsx index 593db5ad..e09fd9f6 100644 --- a/src/renderer/src/hooks/useSegments.tsx +++ b/src/renderer/src/hooks/useSegments.tsx @@ -62,15 +62,22 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea const { t } = useTranslation(); // Segment related state + const [segColorCounter, setSegColorCounterState] = useState(0); const segColorCounterRef = useRef(0); + const setSegColorCounter = useCallback((v: number) => { + segColorCounterRef.current = v; + setSegColorCounterState(v); + }, []); const createIndexedSegment = useCallback(({ segment, incrementCount }: { segment?: Parameters[0], incrementCount?: boolean, } = {}) => { - if (incrementCount) segColorCounterRef.current += 1; + if (incrementCount) { + setSegColorCounter(segColorCounterRef.current + 1); + } return addSegmentColorIndex(createSegment(segment), segColorCounterRef.current); - }, []); + }, [setSegColorCounter]); const [cutSegments, setCutSegments, cutSegmentsHistory] = useStateWithHistory( [], @@ -95,8 +102,8 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea const clearSegColorCounter = useCallback(() => { // eslint-disable-next-line no-param-reassign - segColorCounterRef.current = 0; - }, [segColorCounterRef]); + setSegColorCounter(0); + }, [setSegColorCounter]); const safeSetCutSegments = useCallback((newSegmentsOrFn: StateSegment[] | ((a: StateSegment[]) => StateSegment[]), clampDuration?: number) => { function clampValue(val: number | undefined) { @@ -1003,6 +1010,7 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea updateSegAtIndex, findSegmentsAtCursor, currentCutSegOrWholeTimeline, + segColorCounter, }; }