Skip to content

Commit 40757b4

Browse files
committed
feat: video update
1 parent 3aee6e5 commit 40757b4

File tree

2 files changed

+100
-3
lines changed

2 files changed

+100
-3
lines changed

src/components/stateless/SmartVideoPlayer/index.jsx

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ const SmartVideoPlayer = ({
7676
const settingsPanelRef = useRef(null)
7777
const userPausedRef = useRef(false)
7878
const autoPausedRef = useRef(false)
79+
const isPiPRef = useRef(false)
7980
const inViewRef = useRef(true)
8081
const fullyOutRef = useRef(false)
8182
const miniDismissedRef = useRef(false)
@@ -188,6 +189,33 @@ const SmartVideoPlayer = ({
188189
configRef.current = config
189190
}, [config])
190191

192+
useEffect(() => {
193+
const videoEl = useVideoRef.current
194+
if (!videoEl) return
195+
196+
const onPause = () => {
197+
// Ignore pauses we triggered for lazy-play
198+
if (autoPausedRef.current) return
199+
// Ignore natural end
200+
if (videoEl.ended) return
201+
// Treat any other pause (e.g. PiP native controls / media keys) as user intent
202+
userPausedRef.current = true
203+
}
204+
205+
const onPlay = () => {
206+
// When playback resumes (including PiP native controls), clear both flags.
207+
userPausedRef.current = false
208+
autoPausedRef.current = false
209+
}
210+
211+
videoEl.addEventListener('pause', onPause)
212+
videoEl.addEventListener('play', onPlay)
213+
return () => {
214+
videoEl.removeEventListener('pause', onPause)
215+
videoEl.removeEventListener('play', onPlay)
216+
}
217+
}, [src])
218+
191219
useEffect(() => {
192220
const videoEl = useVideoRef.current
193221
if (!videoEl) return
@@ -328,8 +356,14 @@ const SmartVideoPlayer = ({
328356
if (!videoEl) return
329357
if (!('requestPictureInPicture' in videoEl)) return
330358

331-
const onEnter = () => setIsPiP(true)
332-
const onLeave = () => setIsPiP(false)
359+
const onEnter = () => {
360+
isPiPRef.current = true
361+
setIsPiP(true)
362+
}
363+
const onLeave = () => {
364+
isPiPRef.current = false
365+
setIsPiP(false)
366+
}
333367

334368
videoEl.addEventListener('enterpictureinpicture', onEnter)
335369
videoEl.addEventListener('leavepictureinpicture', onLeave)
@@ -393,6 +427,10 @@ const SmartVideoPlayer = ({
393427
setInView(nextInView)
394428
}
395429

430+
// In PiP, user expects playback to be independent from viewport visibility.
431+
// Avoid IO-driven pause/play fighting with PiP native controls.
432+
if (isPiPRef.current) return
433+
396434
const shouldMini = Boolean(config.miniPlayer && nextFullyOut && !isPiP && !miniDismissedRef.current)
397435

398436
if (!nextInView) {
@@ -436,11 +474,15 @@ const SmartVideoPlayer = ({
436474

437475
useEffect(() => {
438476
if (!config.autoPlay) return
477+
// Keep current playback state when entering PiP; avoid any autoPlay race.
478+
if (isPiPRef.current) return
439479
if (!inView) return
440480
if (userPausedRef.current) return
441481
if (!isPaused) return
482+
const videoEl = useVideoRef.current
483+
if (videoEl?.ended) return
442484
safePlay()
443-
}, [config.autoPlay, inView, isPaused, safePlay])
485+
}, [config.autoPlay, inView, isPaused, isPiP, safePlay])
444486

445487
const handleTogglePause = useCallback(() => {
446488
const videoEl = useVideoRef.current
@@ -635,6 +677,20 @@ const SmartVideoPlayer = ({
635677
Your browser does not support the video tag.
636678
</video>
637679

680+
<div className={`${styles.centerToggle} ${isPaused ? styles.centerToggleVisible : ''}`} aria-hidden={false}>
681+
<button
682+
type="button"
683+
className={styles.centerToggleButton}
684+
aria-label={isPaused ? '播放' : '暂停'}
685+
onClick={(e) => {
686+
e.stopPropagation()
687+
handleTogglePause()
688+
}}
689+
>
690+
{isPaused ? <Play size={34} /> : <Pause size={34} />}
691+
</button>
692+
</div>
693+
638694
<div className={styles.videoControls} aria-label="视频控制条">
639695
<div className={styles.controlsTop} role="group" aria-label="播放与工具">
640696
{!isMini ? <IconButton Icon={SkipBack} label="后退 10 秒" onClick={() => back(10)} /> : null}

src/components/stateless/SmartVideoPlayer/index.module.css

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,47 @@
1919
overflow: hidden;
2020
}
2121

22+
.centerToggle {
23+
position: absolute;
24+
inset: 0;
25+
display: flex;
26+
align-items: center;
27+
justify-content: center;
28+
pointer-events: none;
29+
}
30+
31+
.centerToggleButton {
32+
pointer-events: none;
33+
width: 64px;
34+
height: 64px;
35+
border-radius: 999px;
36+
border: 1px solid rgba(255, 255, 255, 0.16);
37+
background: rgba(0, 0, 0, 0.42);
38+
color: rgba(255, 255, 255, 0.92);
39+
display: inline-flex;
40+
align-items: center;
41+
justify-content: center;
42+
opacity: 0;
43+
transform: scale(1);
44+
transition:
45+
opacity 0.15s ease,
46+
transform 0.1s ease;
47+
}
48+
49+
.centerToggleVisible .centerToggleButton {
50+
pointer-events: auto;
51+
opacity: 0.72;
52+
}
53+
54+
.centerToggleButton:active {
55+
transform: scale(0.96);
56+
}
57+
58+
.mini .centerToggleButton {
59+
width: 54px;
60+
height: 54px;
61+
}
62+
2263
.controlsPinnedWrap .videoControls {
2364
opacity: 1;
2465
transform: translateY(0);

0 commit comments

Comments
 (0)