Update duration display on selection change
This commit is contained in:
parent
f386e12f72
commit
a4e9ebca3b
|
@ -17,8 +17,9 @@ import { firstValueFrom, from, Observable } from 'rxjs';
|
|||
import { first, map } from 'rxjs/operators';
|
||||
import millisFromDuration from './helpers/millisFromDuration';
|
||||
import { zoomViewportIn, zoomViewportOut } from './helpers/zoom';
|
||||
|
||||
import { ExternalLinkIcon } from '@heroicons/react/solid';
|
||||
import toHHMMSS from './helpers/toHHMMSS';
|
||||
import framesToDuration from './helpers/framesToDuration';
|
||||
import { ClockIcon, ExternalLinkIcon } from '@heroicons/react/solid';
|
||||
|
||||
// ported from backend, where should they live?
|
||||
const thumbnailWidth = 177; // height 100
|
||||
|
@ -330,8 +331,6 @@ function App(): JSX.Element {
|
|||
})();
|
||||
};
|
||||
|
||||
const zoomMultiplier = 1.777;
|
||||
|
||||
const handleZoomIn = () => {
|
||||
if (mediaSet == null) {
|
||||
return;
|
||||
|
@ -392,6 +391,26 @@ function App(): JSX.Element {
|
|||
[mediaSet]
|
||||
);
|
||||
|
||||
const durationString = useCallback((): string => {
|
||||
if (!mediaSet || !mediaSet.videoDuration) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const totalDur = toHHMMSS(mediaSet.videoDuration);
|
||||
if (selection.start == selection.end) {
|
||||
return totalDur;
|
||||
}
|
||||
|
||||
const clipDur = toHHMMSS(
|
||||
framesToDuration(
|
||||
selection.end - selection.start,
|
||||
mediaSet.audioSampleRate
|
||||
)
|
||||
);
|
||||
|
||||
return `Selected ${clipDur} of ${totalDur}`;
|
||||
}, [mediaSet, selection]);
|
||||
|
||||
// render component
|
||||
|
||||
const offsetPixels = Math.floor(thumbnailWidth / 2);
|
||||
|
@ -408,7 +427,7 @@ function App(): JSX.Element {
|
|||
<header className="bg-green-900 h-16 grow-0 flex items-center mb-12 px-[88px]">
|
||||
<h1 className="text-3xl font-bold">Clipper</h1>
|
||||
</header>
|
||||
<div className="flex flex-col grow-1 bg-gray-800 w-full h-full mx-auto">
|
||||
<div className="flex flex-col grow bg-gray-800 w-full h-full mx-auto">
|
||||
<div className={`flex flex-col grow ${marginClass}`}>
|
||||
<div className="flex grow-0 h-8 pt-4 pb-2 items-center space-x-2 text-white">
|
||||
<span className="text-gray-300">{mediaSet.author}</span>
|
||||
|
@ -422,6 +441,10 @@ function App(): JSX.Element {
|
|||
>
|
||||
<ExternalLinkIcon className="h-6 w-6 text-gray-500 hover:text-gray-200" />
|
||||
</a>
|
||||
<span className="flex grow justify-end text-gray-500">
|
||||
<ClockIcon className="h-5 w-5 mr-1 mt-0.5" />
|
||||
{durationString()}
|
||||
</span>
|
||||
</div>
|
||||
<ControlBar
|
||||
playState={playState}
|
||||
|
@ -429,8 +452,10 @@ function App(): JSX.Element {
|
|||
onClip={handleClip}
|
||||
onZoomIn={handleZoomIn}
|
||||
onZoomOut={handleZoomOut}
|
||||
downloadClipEnabled={selection.start != selection.end}
|
||||
/>
|
||||
|
||||
<div className="w-full bg-gray-600 h-6"></div>
|
||||
<Overview
|
||||
peaks={overviewPeaks}
|
||||
mediaSet={mediaSet}
|
||||
|
|
|
@ -16,16 +16,18 @@ interface Props {
|
|||
onClip: () => void;
|
||||
onZoomIn: () => void;
|
||||
onZoomOut: () => void;
|
||||
downloadClipEnabled: boolean;
|
||||
}
|
||||
|
||||
const ControlBar: React.FC<Props> = React.memo((props: Props) => {
|
||||
const buttonStyle =
|
||||
'bg-gray-700 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded';
|
||||
|
||||
const largeButtonStyle =
|
||||
'bg-green-700 hover:bg-green-600 text-white font-bold py-2 px-4 rounded absolute right-0';
|
||||
const downloadButtonStyle = props.downloadClipEnabled
|
||||
? 'bg-green-700 hover:bg-green-600 text-white font-bold py-2 px-4 rounded absolute right-0'
|
||||
: 'bg-gray-700 hover:cursor-not-allowed text-gray-500 font-bold py-2 px-4 rounded absolute right-0';
|
||||
|
||||
const iconStyle = 'inline h-6 w-6 text-white-500';
|
||||
const iconStyle = 'inline h-7 w-7 text-white-500';
|
||||
|
||||
const playPauseComponent =
|
||||
props.playState == PlayState.Playing ? (
|
||||
|
@ -34,6 +36,12 @@ const ControlBar: React.FC<Props> = React.memo((props: Props) => {
|
|||
<PlayIcon className={iconStyle} />
|
||||
);
|
||||
|
||||
const handleClip = () => {
|
||||
if (props.downloadClipEnabled) {
|
||||
props.onClip();
|
||||
}
|
||||
};
|
||||
|
||||
// Detect if the space bar has been used to trigger this event, and ignore
|
||||
// it if so. This conflicts with the player interface.
|
||||
const filterMouseEvent = (evt: React.MouseEvent, cb: () => void) => {
|
||||
|
@ -71,11 +79,11 @@ const ControlBar: React.FC<Props> = React.memo((props: Props) => {
|
|||
<ZoomOutIcon className={iconStyle} />
|
||||
</button>
|
||||
<button
|
||||
className={largeButtonStyle}
|
||||
onClick={(evt) => filterMouseEvent(evt, props.onClip)}
|
||||
className={downloadButtonStyle}
|
||||
onClick={(evt) => filterMouseEvent(evt, handleClip)}
|
||||
>
|
||||
<CloudDownloadIcon className={`${iconStyle} mr-2`} />
|
||||
Download clip
|
||||
Download clip as MP3
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -136,8 +136,8 @@ export const HudCanvas: React.FC<Props> = ({
|
|||
ctx.strokeStyle = positionStrokeStyle;
|
||||
ctx.lineWidth = positionLineWidth;
|
||||
ctx.moveTo(position, 0);
|
||||
ctx.lineWidth = 4;
|
||||
ctx.lineTo(position, canvas.height - 4);
|
||||
ctx.lineWidth = position == 0 ? 8 : 4;
|
||||
ctx.lineTo(position, canvas.height);
|
||||
ctx.stroke();
|
||||
});
|
||||
}, [selection, newSelection, position]);
|
||||
|
|
|
@ -77,7 +77,7 @@ export const Overview: React.FC<Props> = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className={`relative grow-0 h-[80px]`}>
|
||||
<div className={`relative grow-0 h-16`}>
|
||||
<WaveformCanvas
|
||||
peaks={peaks}
|
||||
channels={mediaSet.audioChannels}
|
||||
|
|
|
@ -45,7 +45,7 @@ export const SeekBar: React.FC<Props> = ({
|
|||
canvas.width = canvas.height * (canvas.clientWidth / canvas.clientHeight);
|
||||
|
||||
// background
|
||||
ctx.fillStyle = '#444444';
|
||||
ctx.fillStyle = 'transparent';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// seek bar
|
||||
|
@ -119,7 +119,7 @@ export const SeekBar: React.FC<Props> = ({
|
|||
return (
|
||||
<>
|
||||
<canvas
|
||||
className={`w-full h-[30px] mx-0 my-auto ${cursor}`}
|
||||
className={`w-full bg-gray-700 h-10 mx-0 my-auto ${cursor}`}
|
||||
ref={canvasRef}
|
||||
width={LogicalWidth}
|
||||
height={LogicalHeight}
|
||||
|
|
Loading…
Reference in New Issue