show loading indicator for mini waveform

https://github.com/mifi/lossless-cut/issues/260#issuecomment-2546373534
and fix dark mode for mini waveform
pull/2298/head
Mikael Finstad 10 months ago
parent 241211843b
commit cb4155799f
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26

@ -2542,6 +2542,7 @@ function App() {
onWheel={onTimelineWheel}
goToTimecode={goToTimecode}
isSegmentSelected={isSegmentSelected}
darkMode={darkMode}
/>
<BottomBar

@ -15,3 +15,15 @@
color: rgba(255, 255, 255, 0.8);
transition: opacity 0.2s;
}
@keyframes background-animation {
0% {background-position: 0% 50%}
100% {background-position: 100% 50%}
}
.loading-bg {
--c: rgba(255,255,255,0.3);
background: repeating-linear-gradient(45deg, var(--c), var(--c) 1px, transparent 1.5px, transparent 4.4px);
background-size: 50% 100%;
animation: background-animation 3s linear infinite;
}

@ -23,40 +23,41 @@ type CalculateTimelinePercent = (time: number) => string | undefined;
const currentTimeWidth = 1;
// eslint-disable-next-line react/display-name
const Waveform = memo(({ waveform, calculateTimelinePercent, durationSafe }: {
waveform: RenderableWaveform, calculateTimelinePercent: CalculateTimelinePercent, durationSafe: number,
const Waveform = memo(({ waveform, calculateTimelinePercent, durationSafe, darkMode }: {
waveform: RenderableWaveform,
calculateTimelinePercent: CalculateTimelinePercent,
durationSafe: number,
darkMode: boolean,
}) => {
const [style, setStyle] = useState<CSSProperties>({ display: 'none' });
const leftPos = calculateTimelinePercent(waveform.from);
const toTruncated = Math.min(waveform.to, durationSafe);
// Prevents flash
function onLoad() {
setStyle({
position: 'absolute', height: '100%', left: leftPos, width: `${((toTruncated - waveform.from) / durationSafe) * 100}%`,
});
}
const style = useMemo<CSSProperties>(() => ({
position: 'absolute', height: '100%', left: leftPos, width: `${((toTruncated - waveform.from) / durationSafe) * 100}%`, filter: darkMode ? undefined : 'invert(1)',
}), [darkMode, durationSafe, leftPos, toTruncated, waveform.from]);
if (waveform.url == null) return null;
if (waveform.url == null) {
return <div style={{ ...style }} className={styles['loading-bg']} />;
}
return (
<img src={waveform.url} draggable={false} style={style} alt="" onLoad={onLoad} />
<img src={waveform.url} draggable={false} style={style} alt="" />
);
});
// eslint-disable-next-line react/display-name
const Waveforms = memo(({ calculateTimelinePercent, durationSafe, waveforms, zoom, height }: {
const Waveforms = memo(({ calculateTimelinePercent, durationSafe, waveforms, zoom, height, darkMode }: {
calculateTimelinePercent: CalculateTimelinePercent,
durationSafe: number,
waveforms: RenderableWaveform[],
zoom: number,
height: number,
darkMode: boolean,
}) => (
<div style={{ height, width: `${zoom * 100}%`, position: 'relative' }}>
{waveforms.map((waveform) => (
<Waveform key={`${waveform.from}-${waveform.to}`} waveform={waveform} calculateTimelinePercent={calculateTimelinePercent} durationSafe={durationSafe} />
<Waveform key={`${waveform.from}-${waveform.to}`} waveform={waveform} calculateTimelinePercent={calculateTimelinePercent} durationSafe={durationSafe} darkMode={darkMode} />
))}
</div>
));
@ -108,6 +109,7 @@ function Timeline({
commandedTimeRef,
goToTimecode,
isSegmentSelected,
darkMode,
} : {
durationSafe: number,
startTimeOffset: number,
@ -138,6 +140,7 @@ function Timeline({
commandedTimeRef: MutableRefObject<number>,
goToTimecode: () => void,
isSegmentSelected: (a: { segId: string }) => boolean,
darkMode: boolean,
}) {
const { t } = useTranslation();
@ -354,6 +357,7 @@ function Timeline({
waveforms={waveforms}
zoom={zoom}
height={40}
darkMode={darkMode}
/>
)}

@ -1,4 +1,4 @@
import { memo, useEffect, useState, useCallback, useRef, CSSProperties } from 'react';
import { memo, useEffect, useState, useCallback, useRef, CSSProperties, MouseEventHandler, WheelEventHandler } from 'react';
import { Spinner } from 'evergreen-ui';
import { ffmpegExtractWindow } from '../util/constants';
@ -38,9 +38,9 @@ function BigWaveform({ waveforms, relevantTime, playing, durationSafe, zoom, see
e.preventDefault();
}, [relevantTime]);
const scaleToTime = useCallback((v) => (((v) / getRect().width) * windowSize) / zoom, [getRect, windowSize, zoom]);
const scaleToTime = useCallback((v: number) => (((v) / getRect().width) * windowSize) / zoom, [getRect, windowSize, zoom]);
const handleMouseMove = useCallback((e) => {
const handleMouseMove = useCallback<MouseEventHandler<HTMLDivElement>>((e) => {
if (mouseDownRef.current == null) return;
seekRel(-scaleToTime(e.movementX));
@ -48,11 +48,11 @@ function BigWaveform({ waveforms, relevantTime, playing, durationSafe, zoom, see
e.preventDefault();
}, [scaleToTime, seekRel]);
const handleWheel = useCallback((e) => {
const handleWheel = useCallback<WheelEventHandler<HTMLDivElement>>((e) => {
seekRel(scaleToTime(e.deltaX));
}, [scaleToTime, seekRel]);
const handleMouseUp = useCallback((e) => {
const handleMouseUp = useCallback<MouseEventHandler<HTMLDivElement>>((e) => {
if (!mouseDownRef.current) return;
mouseDownRef.current = undefined;
e.preventDefault();
@ -63,7 +63,7 @@ function BigWaveform({ waveforms, relevantTime, playing, durationSafe, zoom, see
const startTime = Date.now();
if (playing) {
let raf;
let raf: number;
// eslint-disable-next-line no-inner-declarations
function render() {
raf = window.requestAnimationFrame(() => {

Loading…
Cancel
Save