From e937cd09794c207df774cd0ec774fa80ce3c19bb Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Fri, 30 Dec 2022 12:47:39 +0800 Subject: [PATCH] improvements - make zoom exponential - make segments copyable - fixes #719 --- src/App.jsx | 14 +++++--------- src/SegmentList.jsx | 16 ++++++++-------- src/ffmpeg-parameters.js | 2 +- src/util/constants.js | 8 +++++++- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 96fcddc7..98f7934e 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -75,7 +75,7 @@ import { fallbackLng } from './i18n'; import { createSegment, getCleanCutSegments, getSegApparentStart, findSegmentsAtCursor, sortSegments, invertSegments, getSegmentTags, convertSegmentsToChapters, hasAnySegmentOverlap } from './segments'; import { getOutSegError as getOutSegErrorRaw } from './util/outputNameTemplate'; import * as ffmpegParameters from './ffmpeg-parameters'; -import { maxSegmentsAllowed } from './util/constants'; +import { maxSegmentsAllowed, ffmpegExtractWindow, zoomMax, rightBarWidth, leftBarWidth } from './util/constants'; import isDev from './isDev'; @@ -91,16 +91,10 @@ const { dialog } = remote; const { focusWindow } = remote.require('./electron'); -const ffmpegExtractWindow = 60; const calcShouldShowWaveform = (zoomedDuration) => (zoomedDuration != null && zoomedDuration < ffmpegExtractWindow * 8); const calcShouldShowKeyframes = (zoomedDuration) => (zoomedDuration != null && zoomedDuration < ffmpegExtractWindow * 8); -const zoomMax = 2 ** 14; - -const rightBarWidth = 200; -const leftBarWidth = 240; - const videoStyle = { width: '100%', height: '100%', objectFit: 'contain' }; const bottomMotionStyle = { background: controlsBackground }; @@ -133,7 +127,7 @@ const App = memo(() => { const [copyStreamIdsByFile, setCopyStreamIdsByFile] = useState({}); const [streamsSelectorShown, setStreamsSelectorShown] = useState(false); const [concatDialogVisible, setConcatDialogVisible] = useState(false); - const [zoom, setZoom] = useState(1); + const [zoomUnrounded, setZoom] = useState(1); const [thumbnails, setThumbnails] = useState([]); const [shortestFlag, setShortestFlag] = useState(false); const [zoomWindowStartTime, setZoomWindowStartTime] = useState(0); @@ -198,6 +192,8 @@ const App = memo(() => { setWorkingState(val); }, []); + const zoom = Math.floor(zoomUnrounded); + const durationSafe = isDurationValid(duration) ? duration : 1; const zoomedDuration = isDurationValid(duration) ? duration / zoom : undefined; @@ -325,7 +321,7 @@ const App = memo(() => { const isRotationSet = rotation !== 360; const effectiveRotation = isRotationSet ? rotation : (mainVideoStream && mainVideoStream.tags && mainVideoStream.tags.rotate && parseInt(mainVideoStream.tags.rotate, 10)); - const zoomRel = useCallback((rel) => setZoom(z => Math.min(Math.max(z + rel, 1), zoomMax)), []); + const zoomRel = useCallback((rel) => setZoom((z) => Math.min(Math.max(z + (rel * (1 + (z / 10))), 1), zoomMax)), []); const canvasPlayerRequired = !!(mainVideoStream && usingDummyVideo); const canvasPlayerWanted = !!(mainVideoStream && isRotationSet && !hideCanvasPreview); // Allow user to disable it diff --git a/src/SegmentList.jsx b/src/SegmentList.jsx index 7cdc4883..fd59e422 100644 --- a/src/SegmentList.jsx +++ b/src/SegmentList.jsx @@ -75,11 +75,11 @@ const Segment = memo(({ seg, index, currentSegIndex, formatTimecode, getFrameCou }, 300, [isActive]); function renderNumber() { - if (invertCutSegments) return ; + if (invertCutSegments) return ; const segColor = getSegColor(seg); - return {index + 1}; + return {index + 1}; } const timeStr = useMemo(() => `${formatTimecode({ seconds: seg.start })} - ${formatTimecode({ seconds: seg.end })}`, [seg.start, seg.end, formatTimecode]); @@ -110,16 +110,17 @@ const Segment = memo(({ seg, index, currentSegIndex, formatTimecode, getFrameCou onClick={() => !invertCutSegments && onClick(index)} onDoubleClick={onDoubleClick} positionTransition - style={{ cursor: 'grab', originY: 0, margin: '5px 0', background: 'rgba(0,0,0,0.1)', border: `1px solid rgba(255,255,255,${isActive ? 1 : 0.3})`, padding: 5, borderRadius: 5, position: 'relative', opacity: !enabled && !invertCutSegments ? 0.5 : undefined }} + style={{ originY: 0, margin: '5px 0', background: 'rgba(0,0,0,0.1)', border: `1px solid rgba(255,255,255,${isActive ? 1 : 0.3})`, padding: 5, borderRadius: 5, position: 'relative', opacity: !enabled && !invertCutSegments ? 0.5 : undefined }} initial={{ scaleY: 0 }} animate={{ scaleY: 1 }} exit={{ scaleY: 0 }} className="segment-list-entry" > -
+
{renderNumber()} - {timeStr} + {timeStr}
+
{seg.name}
{t('Duration')} {formatTimecode({ seconds: duration, shorten: true })} @@ -248,13 +249,12 @@ const SegmentList = memo(({ return ( -
+
- + {sortableList.map(({ id, seg }, index) => { const enabled = !invertCutSegments && selectedSegmentsRaw.includes(seg); return ( diff --git a/src/ffmpeg-parameters.js b/src/ffmpeg-parameters.js index 27bd397b..08b2282b 100644 --- a/src/ffmpeg-parameters.js +++ b/src/ffmpeg-parameters.js @@ -22,7 +22,7 @@ export const silencedetect = () => ({ }, duration: { value: '2.0', - hint: i18n.t('Set silence duration until notification (default is 2 seconds).'), + hint: i18n.t('Set minimum silence duration that will be converted into a segment.'), }, }); diff --git a/src/util/constants.js b/src/util/constants.js index d5a35385..22685dd3 100644 --- a/src/util/constants.js +++ b/src/util/constants.js @@ -1,3 +1,9 @@ // anything more than this will probably cause the UI to become unusably slow -// eslint-disable-next-line import/prefer-default-export export const maxSegmentsAllowed = 2000; + +export const ffmpegExtractWindow = 60; + +export const zoomMax = 2 ** 14; + +export const rightBarWidth = 200; +export const leftBarWidth = 240;