mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-19 00:56:19 +00:00
Init skip button
This commit is contained in:
parent
1737b1c2b2
commit
5f7650dfdd
2 changed files with 97 additions and 18 deletions
92
src/components/player/atoms/SkipIntroButton.tsx
Normal file
92
src/components/player/atoms/SkipIntroButton.tsx
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import classNames from "classnames";
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { Transition } from "@/components/utils/Transition";
|
||||
import { usePlayerStore } from "@/stores/player/store";
|
||||
|
||||
function shouldShowSkipButton(
|
||||
currentTime: number,
|
||||
skipTime?: number | null,
|
||||
): "always" | "hover" | "none" {
|
||||
if (typeof skipTime !== "number") return "none";
|
||||
|
||||
// Show button from beginning until the skip point
|
||||
if (currentTime >= 0 && currentTime < skipTime) {
|
||||
return "always";
|
||||
}
|
||||
|
||||
return "none";
|
||||
}
|
||||
|
||||
function Button(props: {
|
||||
className: string;
|
||||
onClick?: () => void;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
className={classNames(
|
||||
"font-bold rounded h-10 w-40 scale-95 hover:scale-100 transition-all duration-200",
|
||||
props.className,
|
||||
)}
|
||||
type="button"
|
||||
onClick={props.onClick}
|
||||
>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export function SkipIntroButton(props: {
|
||||
controlsShowing: boolean;
|
||||
skipTime?: number | null;
|
||||
}) {
|
||||
const time = usePlayerStore((s) => s.progress.time);
|
||||
const status = usePlayerStore((s) => s.status);
|
||||
const display = usePlayerStore((s) => s.display);
|
||||
|
||||
const showingState = shouldShowSkipButton(time, props.skipTime);
|
||||
|
||||
let show = false;
|
||||
if (showingState === "always") show = true;
|
||||
else if (showingState === "hover" && props.controlsShowing) show = true;
|
||||
if (status !== "playing") show = false;
|
||||
|
||||
const animation = showingState === "hover" ? "slide-up" : "fade";
|
||||
let bottom = "bottom-[calc(6rem+env(safe-area-inset-bottom))]";
|
||||
if (showingState === "always") {
|
||||
bottom = props.controlsShowing
|
||||
? bottom
|
||||
: "bottom-[calc(3rem+env(safe-area-inset-bottom))]";
|
||||
}
|
||||
|
||||
const handleSkip = useCallback(() => {
|
||||
if (typeof props.skipTime === "number" && display) {
|
||||
display.setTime(props.skipTime);
|
||||
}
|
||||
}, [props.skipTime, display]);
|
||||
|
||||
return (
|
||||
<Transition
|
||||
animation={animation}
|
||||
show={show}
|
||||
className="absolute right-[calc(3rem+env(safe-area-inset-right))] bottom-0"
|
||||
>
|
||||
<div
|
||||
className={classNames([
|
||||
"absolute bottom-0 right-0 transition-[bottom] duration-200 flex items-center space-x-3",
|
||||
bottom,
|
||||
])}
|
||||
>
|
||||
<Button
|
||||
onClick={handleSkip}
|
||||
className="bg-buttons-primary hover:bg-buttons-primaryHover text-buttons-primaryText flex justify-center items-center"
|
||||
>
|
||||
<Icon className="text-xl mr-1" icon={Icons.SKIP_EPISODE} />
|
||||
Skip Intro
|
||||
</Button>
|
||||
</div>
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
import { ReactNode, useCallback, useEffect, useState } from "react";
|
||||
import { ReactNode, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
import IosPwaLimitations from "@/components/buttons/IosPwaLimitations";
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { BrandPill } from "@/components/layout/BrandPill";
|
||||
import { Player } from "@/components/player";
|
||||
import { SkipIntroButton } from "@/components/player/atoms/SkipIntroButton";
|
||||
import { Widescreen } from "@/components/player/atoms/Widescreen";
|
||||
import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta";
|
||||
import { useShouldShowControls } from "@/components/player/hooks/useShouldShowControls";
|
||||
|
|
@ -33,7 +34,6 @@ export function PlayerPart(props: PlayerPartProps) {
|
|||
const { isMobile } = useIsMobile();
|
||||
const isLoading = usePlayerStore((s) => s.mediaPlaying.isLoading);
|
||||
const { playerMeta: meta } = usePlayerMeta();
|
||||
const display = usePlayerStore((s) => s.display);
|
||||
|
||||
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
||||
const isIOSPWA =
|
||||
|
|
@ -54,22 +54,7 @@ export function PlayerPart(props: PlayerPartProps) {
|
|||
}
|
||||
});
|
||||
|
||||
// Fullscreen on rotation horizontal
|
||||
const onRotate = useCallback(() => {
|
||||
if (window.orientation === 90 || window.orientation === -90) {
|
||||
if (!document.fullscreenElement && status === playerStatus.PLAYING) {
|
||||
display?.toggleFullscreen();
|
||||
}
|
||||
} else if (document.fullscreenElement && status === playerStatus.PLAYING) {
|
||||
display?.toggleFullscreen();
|
||||
}
|
||||
}, [display, status]);
|
||||
useEffect(() => {
|
||||
window.addEventListener("orientationchange", onRotate);
|
||||
return () => {
|
||||
window.removeEventListener("orientationchange", onRotate);
|
||||
};
|
||||
}, [onRotate]);
|
||||
const skiptime = null;
|
||||
|
||||
return (
|
||||
<Player.Container onLoad={props.onLoad} showingControls={showTargets}>
|
||||
|
|
@ -237,6 +222,8 @@ export function PlayerPart(props: PlayerPartProps) {
|
|||
controlsShowing={showTargets}
|
||||
onChange={props.onMetaChange}
|
||||
/>
|
||||
|
||||
<SkipIntroButton controlsShowing={showTargets} skipTime={skiptime} />
|
||||
</Player.Container>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue