fix ui: prevent audioplayer from looping after playing once unless scrolled backwards (#2598)
This commit is contained in:
parent
f5949cc08e
commit
a11c683baf
1 changed files with 29 additions and 10 deletions
|
|
@ -8,7 +8,7 @@ import { Button, InputNumber, Popover } from 'antd';
|
||||||
import { Slider } from 'antd';
|
import { Slider } from 'antd';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||||
|
import cn from 'classnames';
|
||||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||||
|
|
||||||
function DropdownAudioPlayer({
|
function DropdownAudioPlayer({
|
||||||
|
|
@ -24,17 +24,27 @@ function DropdownAudioPlayer({
|
||||||
const [isMuted, setIsMuted] = useState(false);
|
const [isMuted, setIsMuted] = useState(false);
|
||||||
const lastPlayerTime = useRef(0);
|
const lastPlayerTime = useRef(0);
|
||||||
const audioRefs = useRef<Record<string, HTMLAudioElement | null>>({});
|
const audioRefs = useRef<Record<string, HTMLAudioElement | null>>({});
|
||||||
|
const fileLengths = useRef<Record<string, number>>({});
|
||||||
const { time = 0, speed = 1, playing, sessionStart } = store?.get() ?? {};
|
const { time = 0, speed = 1, playing, sessionStart } = store?.get() ?? {};
|
||||||
|
|
||||||
const files = audioEvents.map((pa) => {
|
const files = React.useMemo(() => audioEvents.map((pa) => {
|
||||||
const data = pa.payload;
|
const data = pa.payload;
|
||||||
return {
|
return {
|
||||||
url: data.url,
|
url: data.url,
|
||||||
timestamp: data.timestamp,
|
timestamp: data.timestamp,
|
||||||
start: pa.timestamp - sessionStart,
|
start: pa.timestamp - sessionStart,
|
||||||
};
|
};
|
||||||
});
|
}), [audioEvents, sessionStart])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
Object.entries(audioRefs.current).forEach(([url, audio]) => {
|
||||||
|
if (audio) {
|
||||||
|
audio.addEventListener('loadedmetadata', () => {
|
||||||
|
fileLengths.current[url] = audio.duration;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [audioRefs.current])
|
||||||
|
|
||||||
const toggleMute = () => {
|
const toggleMute = () => {
|
||||||
Object.values(audioRefs.current).forEach((audio) => {
|
Object.values(audioRefs.current).forEach((audio) => {
|
||||||
|
|
@ -114,6 +124,9 @@ function DropdownAudioPlayer({
|
||||||
Object.entries(audioRefs.current).forEach(([url, audio]) => {
|
Object.entries(audioRefs.current).forEach(([url, audio]) => {
|
||||||
if (audio) {
|
if (audio) {
|
||||||
const file = files.find((f) => f.url === url);
|
const file = files.find((f) => f.url === url);
|
||||||
|
if (audio.ended && fileLengths.current[url] < time) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (file && time >= file.start) {
|
if (file && time >= file.start) {
|
||||||
if (audio.paused && playing) {
|
if (audio.paused && playing) {
|
||||||
audio.play();
|
audio.play();
|
||||||
|
|
@ -121,14 +134,19 @@ function DropdownAudioPlayer({
|
||||||
} else {
|
} else {
|
||||||
audio.pause();
|
audio.pause();
|
||||||
}
|
}
|
||||||
if (audio.muted !== isMuted) {
|
|
||||||
audio.muted = isMuted;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
lastPlayerTime.current = time + deltaMs;
|
lastPlayerTime.current = time + deltaMs;
|
||||||
}, [time, delta]);
|
}, [time, delta]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Object.values(audioRefs.current).forEach((audio) => {
|
||||||
|
if (audio) {
|
||||||
|
audio.muted = isMuted;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [isMuted])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
changePlaybackSpeed(speed);
|
changePlaybackSpeed(speed);
|
||||||
}, [speed]);
|
}, [speed]);
|
||||||
|
|
@ -147,12 +165,12 @@ function DropdownAudioPlayer({
|
||||||
setVolume(isMuted ? 0 : volume);
|
setVolume(isMuted ? 0 : volume);
|
||||||
}, [playing]);
|
}, [playing]);
|
||||||
|
|
||||||
|
const buttonIcon = 'px-2 cursor-pointer border border-gray-light hover:border-main hover:text-main hover:z-10 h-fit'
|
||||||
return (
|
return (
|
||||||
<div className={'relative'}>
|
<div className={'relative'}>
|
||||||
<div className={'flex items-center'} style={{ height: 24 }}>
|
<div className={'flex items-center'} style={{ height: 24 }}>
|
||||||
<Popover
|
<Popover
|
||||||
trigger={'click'}
|
trigger={'click'}
|
||||||
className={'h-full'}
|
|
||||||
content={
|
content={
|
||||||
<div
|
<div
|
||||||
className={'flex flex-col gap-2 rounded'}
|
className={'flex flex-col gap-2 rounded'}
|
||||||
|
|
@ -171,7 +189,7 @@ function DropdownAudioPlayer({
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'px-2 h-full cursor-pointer border rounded-l border-gray-light hover:border-main hover:text-main hover:z-10'
|
cn(buttonIcon, 'rounded-l')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{isMuted ? <MutedOutlined /> : <SoundOutlined />}
|
{isMuted ? <MutedOutlined /> : <SoundOutlined />}
|
||||||
|
|
@ -181,7 +199,7 @@ function DropdownAudioPlayer({
|
||||||
onClick={toggleVisible}
|
onClick={toggleVisible}
|
||||||
style={{ marginLeft: -1 }}
|
style={{ marginLeft: -1 }}
|
||||||
className={
|
className={
|
||||||
'px-2 h-full border rounded-r border-gray-light cursor-pointer hover:border-main hover:text-main hover:z-10'
|
cn(buttonIcon, 'rounded-r')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<CaretDownOutlined />
|
<CaretDownOutlined />
|
||||||
|
|
@ -236,6 +254,7 @@ function DropdownAudioPlayer({
|
||||||
<div style={{ display: 'none' }}>
|
<div style={{ display: 'none' }}>
|
||||||
{files.map((file) => (
|
{files.map((file) => (
|
||||||
<audio
|
<audio
|
||||||
|
loop={false}
|
||||||
key={file.url}
|
key={file.url}
|
||||||
ref={(el) => (audioRefs.current[file.url] = el)}
|
ref={(el) => (audioRefs.current[file.url] = el)}
|
||||||
controls
|
controls
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue