Voice notes drafts
This commit is contained in:
parent
356fb301e1
commit
99015d7b96
48 changed files with 2113 additions and 909 deletions
123
ts/components/conversation/WaveformScrubber.tsx
Normal file
123
ts/components/conversation/WaveformScrubber.tsx
Normal file
|
@ -0,0 +1,123 @@
|
|||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import { useRefMerger } from '../../hooks/useRefMerger';
|
||||
import type { LocalizerType } from '../../types/Util';
|
||||
import { durationToPlaybackText } from '../../util/durationToPlaybackText';
|
||||
import { Waveform } from './Waveform';
|
||||
|
||||
type Props = Readonly<{
|
||||
i18n: LocalizerType;
|
||||
peaks: ReadonlyArray<number>;
|
||||
currentTime: number;
|
||||
duration: number | undefined;
|
||||
barMinHeight: number;
|
||||
barMaxHeight: number;
|
||||
onClick: (positionAsRatio: number) => void;
|
||||
onScrub: (positionAsRatio: number) => void;
|
||||
}>;
|
||||
|
||||
const BAR_COUNT = 47;
|
||||
|
||||
const REWIND_BAR_COUNT = 2;
|
||||
|
||||
// Increments for keyboard audio seek (in seconds)\
|
||||
const SMALL_INCREMENT = 1;
|
||||
const BIG_INCREMENT = 5;
|
||||
|
||||
export const WaveformScrubber = React.forwardRef(function WaveformScrubber(
|
||||
{
|
||||
i18n,
|
||||
peaks,
|
||||
barMinHeight,
|
||||
barMaxHeight,
|
||||
currentTime,
|
||||
duration,
|
||||
onClick,
|
||||
onScrub,
|
||||
}: Props,
|
||||
ref
|
||||
): JSX.Element {
|
||||
const refMerger = useRefMerger();
|
||||
|
||||
const waveformRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// Clicking waveform moves playback head position and starts playback.
|
||||
const handleClick = useCallback(
|
||||
(event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (!waveformRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const boundingRect = waveformRef.current.getBoundingClientRect();
|
||||
let progress = (event.pageX - boundingRect.left) / boundingRect.width;
|
||||
|
||||
if (progress <= REWIND_BAR_COUNT / BAR_COUNT) {
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
onClick(progress);
|
||||
},
|
||||
[waveformRef, onClick]
|
||||
);
|
||||
|
||||
// Keyboard navigation for waveform. Pressing keys moves playback head
|
||||
// forward/backwards.
|
||||
const handleKeyDown = (event: React.KeyboardEvent) => {
|
||||
if (!duration) {
|
||||
return;
|
||||
}
|
||||
|
||||
let increment: number;
|
||||
if (event.key === 'ArrowRight' || event.key === 'ArrowUp') {
|
||||
increment = +SMALL_INCREMENT;
|
||||
} else if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') {
|
||||
increment = -SMALL_INCREMENT;
|
||||
} else if (event.key === 'PageUp') {
|
||||
increment = +BIG_INCREMENT;
|
||||
} else if (event.key === 'PageDown') {
|
||||
increment = -BIG_INCREMENT;
|
||||
} else {
|
||||
// We don't handle other keys
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const currentPosition = currentTime / duration;
|
||||
const positionIncrement = increment / duration;
|
||||
const newPosition = currentPosition + positionIncrement;
|
||||
|
||||
onScrub(newPosition);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={refMerger(waveformRef, ref)}
|
||||
className="WaveformScrubber"
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
tabIndex={0}
|
||||
role="slider"
|
||||
aria-label={i18n('MessageAudio--slider')}
|
||||
aria-orientation="horizontal"
|
||||
aria-valuenow={currentTime}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={duration}
|
||||
aria-valuetext={durationToPlaybackText(currentTime)}
|
||||
>
|
||||
<Waveform
|
||||
peaks={peaks}
|
||||
barMinHeight={barMinHeight}
|
||||
barMaxHeight={barMaxHeight}
|
||||
currentTime={currentTime}
|
||||
duration={duration}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue