feat: show global audio player when scrolled

This commit is contained in:
jinhojang6 2023-08-18 22:34:52 +09:00
parent 1454e5ae97
commit 7d9aedf8e5
2 changed files with 68 additions and 20 deletions

View File

@ -8,6 +8,7 @@ import { LogosCircleIcon } from '@/components/Icons/LogosCircleIcon'
import { useHookstate } from '@hookstate/core'
import { playerState } from '@/components/GlobalAudioPlayer/globalAudioPlayer.state'
import EpisodeChannels from './Episode.Channels'
import { useEffect, useRef } from 'react'
export type EpisodeHeaderProps = LPE.Podcast.Document & {
url: string
@ -26,25 +27,58 @@ const EpisodeHeader = ({
const date = new Date(publishedAt)
const state = useHookstate(playerState)
const playerContainerRef = useRef<HTMLDivElement>(null)
const playerRef = useRef<ReactPlayer>(null)
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
state.set((prev) => ({
...prev,
isEnabled: false,
}))
} else {
const offset = 0.5 // offset for episode player
playerRef.current?.seekTo(state.value.playedSeconds + offset, 'seconds')
state.set((prev) => ({
...prev,
playedSeconds: state.value.playedSeconds + offset,
isEnabled: true,
}))
}
})
observer.observe(playerContainerRef.current as any)
return () => {
observer.disconnect()
state.set((prev) => ({
...prev,
isEnabled: true,
}))
}
}, [])
return (
<EpisodeHeaderContainer>
<PlayerContainer>
<PlayerContainer ref={playerContainerRef}>
<ReactPlayer
ref={playerRef}
url={url}
controls={true}
playing={state.value.playing}
volume={state.value.volume}
muted={state.value.isEnabled ? true : false}
onProgress={(newState: { playedSeconds: number }) => {
onProgress={(newState) => {
state.set((prev) => ({
...prev,
playedSeconds: newState.playedSeconds,
played: newState.played,
loaded: newState.loaded,
}))
}}
onPlay={() =>
state.set((prev) => ({
...prev,
playing: true,
isEnabled: true,
}))
}
onPlay={() => {
state.set((prev) => ({ ...prev, playing: true }))
}}
onPause={() => state.set((prev) => ({ ...prev, playing: false }))}
onDuration={(duration) =>
state.set((prev) => ({ ...prev, duration }))

View File

@ -25,6 +25,7 @@ export default function GlobalAudioPlayer() {
const epState = useHookstate(episodeState)
const ref = useRef<ReactPlayer>(null)
const [episode, setEpisode] = useState<EpisodeProps>({
title: '',
podcast: '',
@ -54,7 +55,12 @@ export default function GlobalAudioPlayer() {
// }
const handlePlay = () => {
state.set((prev) => ({ ...prev, playing: true }))
ref.current?.seekTo(state.value.playedSeconds, 'seconds')
state.set((prev) => ({
...prev,
playing: true,
playedSeconds: state.value.playedSeconds,
}))
}
const handlePlayPause = () => {
@ -85,9 +91,7 @@ export default function GlobalAudioPlayer() {
state.set((prev) => ({ ...prev, playing: false }))
}
const handleSeekMouseDown = (
e: React.MouseEvent<HTMLInputElement, MouseEvent>,
) => {
const handleSeekMouseDown = () => {
state.set((prev) => ({ ...prev, seeking: true }))
}
@ -113,12 +117,21 @@ export default function GlobalAudioPlayer() {
state.set((prev) => ({ ...prev, playbackRate: parseFloat(e.target.value) }))
}
const handleProgress = (newState: { playedSeconds: number }) => {
state.set((prev) => ({ ...prev, playedSeconds: newState.playedSeconds }))
const handleProgress = (newState: {
playedSeconds: number
played: number
loaded: number
}) => {
state.set((prev) => ({
...prev,
playedSeconds: newState.playedSeconds,
played: newState.played,
loaded: newState.loaded,
}))
}
return state.value.isEnabled ? (
<Container>
return (
<Container visible={state.value.isEnabled}>
<AudioPlayer>
<Buttons>
<Row>
@ -182,7 +195,7 @@ export default function GlobalAudioPlayer() {
loop={state.value.loop}
playbackRate={state.value.playbackRate}
volume={state.value.volume}
muted={state.value.muted}
muted={state.value.isEnabled ? false : true}
onReady={() => console.log('onReady')}
onStart={() => console.log('onStart')}
onPlay={handlePlay}
@ -208,10 +221,10 @@ export default function GlobalAudioPlayer() {
</EpisodeData>
</RightMenu>
</Container>
) : null
)
}
const Container = styled.div`
const Container = styled.div<{ visible: boolean }>`
width: 100vw;
height: 80px;
padding: 22px 16px;
@ -224,6 +237,7 @@ const Container = styled.div`
left: 0;
border-top: 1px solid rgb(var(--lsd-border-primary));
box-sizing: border-box;
visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
`
const Buttons = styled.div`