feat: dynamic skip buttons

This commit is contained in:
shinya
2025-07-03 00:31:57 +08:00
parent d5dd131bdb
commit 37aa342d5b

View File

@@ -75,6 +75,56 @@ function PlayPageClient() {
const [reverseEpisodeOrder, setReverseEpisodeOrder] = useState(false);
const shortcutHintTimeoutRef = useRef<NodeJS.Timeout | null>(null);
// NEW STATE: 控制快进/快退按钮是否显示
const [showSkipButtons, setShowSkipButtons] = useState(true);
// 使用 ResizeObserver 根据 MediaPlayer 元素尺寸动态决定按钮显隐
useEffect(() => {
if (
typeof window === 'undefined' ||
typeof ResizeObserver === 'undefined'
) {
return;
}
const updateShowSkipButtons = () => {
const el: HTMLElement | undefined = (playerRef.current as any)?.el;
if (!el) return;
const rect = el.getBoundingClientRect();
// width < 576 或 height < 380 时隐藏
setShowSkipButtons(!(rect.width < 576 || rect.height < 380));
};
// 尝试立即更新一次
updateShowSkipButtons();
const observer = new ResizeObserver(updateShowSkipButtons);
// 有可能此时 el 还未就绪,使用轮询确保绑定
let retryTimer: NodeJS.Timeout | null = null;
const attachObserver = () => {
const el: HTMLElement | undefined = (playerRef.current as any)?.el;
if (el) {
observer.observe(el);
if (retryTimer) clearInterval(retryTimer);
}
};
attachObserver();
if (!(playerRef.current as any)?.el) {
// 如果首次未获取到 el继续重试直至获取
retryTimer = setInterval(attachObserver, 200);
}
// orientationchange 也可能影响高/宽
window.addEventListener('orientationchange', updateShowSkipButtons);
return () => {
observer.disconnect();
if (retryTimer) clearInterval(retryTimer);
window.removeEventListener('orientationchange', updateShowSkipButtons);
};
}, []);
// 换源相关状态
const [searchResults, setSearchResults] = useState<SearchResult[]>([]);
const [searchLoading, setSearchLoading] = useState(false);
@@ -1339,31 +1389,33 @@ function PlayPageClient() {
airPlayButton: null, // 隐藏默认 AirPlay 按钮
beforeCurrentTime: (
<>
{/* 快进 10 秒按钮 - 移动端隐藏 */}
<button
className='vds-button hidden md:inline-flex mr-2'
onClick={() => {
if (playerRef.current) {
const p = playerRef.current;
const newTime = Math.min(
(p.currentTime || 0) + 10,
p.duration || 0
);
p.currentTime = newTime;
}
}}
aria-label='Fast Forward 10 Seconds'
>
<svg
className='vds-icon'
viewBox='0 0 32 32'
xmlns='http://www.w3.org/2000/svg'
{/* 快进 10 秒按钮 - 根据播放器尺寸决定显隐 */}
{showSkipButtons && (
<button
className='vds-button mr-2'
onClick={() => {
if (playerRef.current) {
const p = playerRef.current;
const newTime = Math.min(
(p.currentTime || 0) + 10,
p.duration || 0
);
p.currentTime = newTime;
}
}}
aria-label='Fast Forward 10 Seconds'
>
{/* 双三角快进图标 */}
<path d='M6 24l10-8L6 8v16z' fill='currentColor' />
<path d='M18 24l10-8-10-8v16z' fill='currentColor' />
</svg>
</button>
<svg
className='vds-icon'
viewBox='0 0 32 32'
xmlns='http://www.w3.org/2000/svg'
>
{/* 双三角快进图标 */}
<path d='M6 24l10-8L6 8v16z' fill='currentColor' />
<path d='M18 24l10-8-10-8v16z' fill='currentColor' />
</svg>
</button>
)}
{totalEpisodes > 1 && (
// 下一集按钮放在时间显示前
@@ -1411,29 +1463,33 @@ function PlayPageClient() {
</AirPlayButton>
</>
),
// 快退 10 秒按钮(移动端隐藏
// 快退 10 秒按钮(根据播放器尺寸决定显隐
beforePlayButton: (
<button
className='vds-button hidden md:inline-flex mr-2'
onClick={() => {
if (playerRef.current) {
const p = playerRef.current;
const newTime = Math.max(0, (p.currentTime || 0) - 10);
p.currentTime = newTime;
}
}}
aria-label='Rewind 10 Seconds'
>
<svg
className='vds-icon'
viewBox='0 0 32 32'
xmlns='http://www.w3.org/2000/svg'
>
{/* 双三角快退图标 */}
<path d='M26 24l-10-8 10-8v16z' fill='currentColor' />
<path d='M14 24l-10-8 10-8v16z' fill='currentColor' />
</svg>
</button>
<>
{showSkipButtons && (
<button
className='vds-button mr-2'
onClick={() => {
if (playerRef.current) {
const p = playerRef.current;
const newTime = Math.max(0, (p.currentTime || 0) - 10);
p.currentTime = newTime;
}
}}
aria-label='Rewind 10 Seconds'
>
<svg
className='vds-icon'
viewBox='0 0 32 32'
xmlns='http://www.w3.org/2000/svg'
>
{/* 双三角快退图标 */}
<path d='M26 24l-10-8 10-8v16z' fill='currentColor' />
<path d='M14 24l-10-8 10-8v16z' fill='currentColor' />
</svg>
</button>
)}
</>
),
}}
/>