mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Add volume slider (keyboard accessible)
Fix tooltip position on the bottom of the screen. Add fullscreen support on the web
This commit is contained in:
parent
b1b8772717
commit
7a1bde1b73
@ -64,6 +64,7 @@ export const IconButton = <AsProps = PressableProps,>({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
|
accessibilityRole="button"
|
||||||
{...(css(
|
{...(css(
|
||||||
{
|
{
|
||||||
p: ts(1),
|
p: ts(1),
|
||||||
|
@ -20,8 +20,7 @@
|
|||||||
|
|
||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import { GestureResponderEvent, Platform, View } from "react-native";
|
import { GestureResponderEvent, Platform, View } from "react-native";
|
||||||
import { percent, Stylable, useYoshiki } from "yoshiki/native";
|
import { px, percent, Stylable, useYoshiki } from "yoshiki/native";
|
||||||
import { ts } from "./utils";
|
|
||||||
|
|
||||||
export const Slider = ({
|
export const Slider = ({
|
||||||
progress,
|
progress,
|
||||||
@ -31,6 +30,7 @@ export const Slider = ({
|
|||||||
setProgress,
|
setProgress,
|
||||||
startSeek,
|
startSeek,
|
||||||
endSeek,
|
endSeek,
|
||||||
|
size = 6,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
progress: number;
|
progress: number;
|
||||||
@ -40,6 +40,7 @@ export const Slider = ({
|
|||||||
setProgress: (progress: number) => void;
|
setProgress: (progress: number) => void;
|
||||||
startSeek?: () => void;
|
startSeek?: () => void;
|
||||||
endSeek?: () => void;
|
endSeek?: () => void;
|
||||||
|
size?: number;
|
||||||
} & Stylable) => {
|
} & Stylable) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
const ref = useRef<View>(null);
|
const ref = useRef<View>(null);
|
||||||
@ -49,6 +50,8 @@ export const Slider = ({
|
|||||||
const [isFocus, setFocus] = useState(false);
|
const [isFocus, setFocus] = useState(false);
|
||||||
const smallBar = !(isSeeking || isHover || isFocus);
|
const smallBar = !(isSeeking || isHover || isFocus);
|
||||||
|
|
||||||
|
const ts = (value: number) => px(value * size);
|
||||||
|
|
||||||
const change = (event: GestureResponderEvent) => {
|
const change = (event: GestureResponderEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const locationX = Platform.select({
|
const locationX = Platform.select({
|
||||||
@ -58,7 +61,6 @@ export const Slider = ({
|
|||||||
setProgress(Math.max(0, Math.min(locationX / layout.width, 1)) * max);
|
setProgress(Math.max(0, Math.min(locationX / layout.width, 1)) * max);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO keyboard handling (left, right, up, down)
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@ -66,8 +68,7 @@ export const Slider = ({
|
|||||||
onMouseEnter={() => setHover(true)}
|
onMouseEnter={() => setHover(true)}
|
||||||
// @ts-ignore Web only
|
// @ts-ignore Web only
|
||||||
onMouseLeave={() => setHover(false)}
|
onMouseLeave={() => setHover(false)}
|
||||||
// TODO: This does not work
|
focusable
|
||||||
tabindex={0}
|
|
||||||
onFocus={() => setFocus(true)}
|
onFocus={() => setFocus(true)}
|
||||||
onBlur={() => setFocus(false)}
|
onBlur={() => setFocus(false)}
|
||||||
onStartShouldSetResponder={() => true}
|
onStartShouldSetResponder={() => true}
|
||||||
@ -84,6 +85,22 @@ export const Slider = ({
|
|||||||
onLayout={() =>
|
onLayout={() =>
|
||||||
ref.current?.measure((_, __, width, ___, pageX) => setLayout({ width: width, x: pageX }))
|
ref.current?.measure((_, __, width, ___, pageX) => setLayout({ width: width, x: pageX }))
|
||||||
}
|
}
|
||||||
|
onKeyDown={(e: KeyboardEvent) => {
|
||||||
|
switch (e.code) {
|
||||||
|
case "ArrowLeft":
|
||||||
|
setProgress(Math.max(progress - 0.05 * max, 0));
|
||||||
|
break;
|
||||||
|
case "ArrowRight":
|
||||||
|
setProgress(Math.min(progress + 0.05 * max, max));
|
||||||
|
break;
|
||||||
|
case "ArrowDown":
|
||||||
|
setProgress(Math.max(progress - 0.1 * max, 0));
|
||||||
|
break;
|
||||||
|
case "ArrowUp":
|
||||||
|
setProgress(Math.min(progress + 0.1 * max, max));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}}
|
||||||
{...css(
|
{...css(
|
||||||
{
|
{
|
||||||
paddingVertical: ts(1),
|
paddingVertical: ts(1),
|
||||||
@ -155,11 +172,12 @@ export const Slider = ({
|
|||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 0,
|
top: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
marginY: ts(0.5),
|
marginY: ts(Platform.OS === "android" ? -0.5 : 0.5),
|
||||||
bg: (theme) => theme.accent,
|
bg: (theme) => theme.accent,
|
||||||
width: ts(2),
|
width: ts(2),
|
||||||
height: ts(2),
|
height: ts(2),
|
||||||
borderRadius: ts(1),
|
borderRadius: ts(1),
|
||||||
|
marginLeft: ts(-1),
|
||||||
},
|
},
|
||||||
smallBar && { opacity: 0 },
|
smallBar && { opacity: 0 },
|
||||||
],
|
],
|
||||||
|
@ -18,13 +18,13 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ToastAndroid, Platform } from "react-native";
|
import { ToastAndroid, Platform, ViewProps, PressableProps } from "react-native";
|
||||||
import { Theme } from "yoshiki/native";
|
import { Theme } from "yoshiki/native";
|
||||||
|
|
||||||
export const tooltip = (tooltip: string) =>
|
export const tooltip = (tooltip: string, up?: boolean) =>
|
||||||
Platform.select({
|
Platform.select({
|
||||||
web: {
|
web: {
|
||||||
dataSet: { tooltip, label: tooltip },
|
dataSet: { tooltip, label: tooltip, tooltipPos: up ? "up" : undefined },
|
||||||
},
|
},
|
||||||
android: {
|
android: {
|
||||||
onLongPress: () => {
|
onLongPress: () => {
|
||||||
@ -66,6 +66,11 @@ export const WebTooltip = ({ theme }: { theme: Theme }) => {
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
transition: opacity 0.3s ease-in-out;
|
transition: opacity 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
[data-tooltip-pos]::after {
|
||||||
|
top: unset;
|
||||||
|
bottom: 100%;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
:where(body:not(.noHover)) [data-tooltip]:hover::after,
|
:where(body:not(.noHover)) [data-tooltip]:hover::after,
|
||||||
[data-tooltip]:focus-visible::after {
|
[data-tooltip]:focus-visible::after {
|
||||||
@ -81,7 +86,6 @@ export const WebTooltip = ({ theme }: { theme: Theme }) => {
|
|||||||
outline: none;
|
outline: none;
|
||||||
transition: box-shadow 0.15s ease-in-out;
|
transition: box-shadow 0.15s ease-in-out;
|
||||||
box-shadow: 0 0 0 2px ${theme.colors.black};
|
box-shadow: 0 0 0 2px ${theme.colors.black};
|
||||||
/* box-shadow: ${theme.accent} 1px; */
|
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
);
|
);
|
||||||
|
@ -26,16 +26,14 @@ import { PersonAvatar } from "./person";
|
|||||||
export const Staff = ({ slug }: { slug: string }) => {
|
export const Staff = ({ slug }: { slug: string }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
// TODO: handle infinite scroll
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteFetch
|
<InfiniteFetch
|
||||||
query={Staff.query(slug)}
|
query={Staff.query(slug)}
|
||||||
horizontal
|
horizontal
|
||||||
layout={{ numColumns: 1, size: PersonAvatar.width }}
|
layout={{ numColumns: 1, size: PersonAvatar.width }}
|
||||||
|
empty={t("show.staff-none")}
|
||||||
placeholderCount={20}
|
placeholderCount={20}
|
||||||
>
|
>
|
||||||
{/* <HorizontalList title={t("show.staff")} noContent={t("show.staff-none")}> */}
|
|
||||||
{(item, key) => (
|
{(item, key) => (
|
||||||
<PersonAvatar
|
<PersonAvatar
|
||||||
key={key}
|
key={key}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IconButton, Link, P, tooltip, ts } from "@kyoo/primitives";
|
import { IconButton, Link, P, Slider, tooltip, ts } from "@kyoo/primitives";
|
||||||
import { useAtom, useAtomValue } from "jotai";
|
import { useAtom, useAtomValue } from "jotai";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
@ -31,7 +31,7 @@ import VolumeMute from "@material-symbols/svg-400/rounded/volume_mute-fill.svg";
|
|||||||
import VolumeDown from "@material-symbols/svg-400/rounded/volume_down-fill.svg";
|
import VolumeDown from "@material-symbols/svg-400/rounded/volume_down-fill.svg";
|
||||||
import VolumeUp from "@material-symbols/svg-400/rounded/volume_up-fill.svg";
|
import VolumeUp from "@material-symbols/svg-400/rounded/volume_up-fill.svg";
|
||||||
import { durationAtom, mutedAtom, playAtom, progressAtom, volumeAtom } from "../state";
|
import { durationAtom, mutedAtom, playAtom, progressAtom, volumeAtom } from "../state";
|
||||||
import { useYoshiki } from "yoshiki/native";
|
import { px, useYoshiki } from "yoshiki/native";
|
||||||
|
|
||||||
export const LeftButtons = ({
|
export const LeftButtons = ({
|
||||||
previousSlug,
|
previousSlug,
|
||||||
@ -53,14 +53,14 @@ export const LeftButtons = ({
|
|||||||
icon={SkipPrevious}
|
icon={SkipPrevious}
|
||||||
as={Link}
|
as={Link}
|
||||||
href={previousSlug}
|
href={previousSlug}
|
||||||
{...tooltip(t("player.previous"))}
|
{...tooltip(t("player.previous"), true)}
|
||||||
{...spacing}
|
{...spacing}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={isPlaying ? Pause : PlayArrow}
|
icon={isPlaying ? Pause : PlayArrow}
|
||||||
onPress={() => setPlay(!isPlaying)}
|
onPress={() => setPlay(!isPlaying)}
|
||||||
{...tooltip(isPlaying ? t("player.pause") : t("player.play"))}
|
{...tooltip(isPlaying ? t("player.pause") : t("player.play"), true)}
|
||||||
{...spacing}
|
{...spacing}
|
||||||
/>
|
/>
|
||||||
{nextSlug && (
|
{nextSlug && (
|
||||||
@ -68,7 +68,7 @@ export const LeftButtons = ({
|
|||||||
icon={SkipNext}
|
icon={SkipNext}
|
||||||
as={Link}
|
as={Link}
|
||||||
href={nextSlug}
|
href={nextSlug}
|
||||||
{...tooltip(t("player.next"))}
|
{...tooltip(t("player.next"), true)}
|
||||||
{...spacing}
|
{...spacing}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -84,13 +84,13 @@ const VolumeSlider = () => {
|
|||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return null;
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
{...css({
|
{...css({
|
||||||
display: { xs: "none", sm: "flex" },
|
display: { xs: "none", sm: "flex" },
|
||||||
p: ts(1),
|
alignItems: "center",
|
||||||
"body.hoverEnabled &:hover .slider": { width: "100px", px: "16px" },
|
flexDirection: "row",
|
||||||
|
paddingRight: ts(1),
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -103,26 +103,16 @@ const VolumeSlider = () => {
|
|||||||
? VolumeDown
|
? VolumeDown
|
||||||
: VolumeUp
|
: VolumeUp
|
||||||
}
|
}
|
||||||
onClick={() => setMuted(!isMuted)}
|
onPress={() => setMuted(!isMuted)}
|
||||||
{...tooltip(t("mute"))}
|
{...tooltip(t("player.mute"), true)}
|
||||||
|
/>
|
||||||
|
<Slider
|
||||||
|
progress={volume}
|
||||||
|
setProgress={setVolume}
|
||||||
|
size={4}
|
||||||
|
{...css({ width: px(100) })}
|
||||||
|
{...tooltip(t("player.volume"), true)}
|
||||||
/>
|
/>
|
||||||
<View
|
|
||||||
className="slider"
|
|
||||||
sx={{
|
|
||||||
width: 0,
|
|
||||||
transition: "width .2s cubic-bezier(0.4,0, 1, 1), padding .2s cubic-bezier(0.4,0, 1, 1)",
|
|
||||||
overflow: "hidden",
|
|
||||||
alignSelf: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Slider
|
|
||||||
value={volume}
|
|
||||||
onChange={(_, value) => setVolume(value as number)}
|
|
||||||
size="small"
|
|
||||||
aria-label={t("volume")}
|
|
||||||
sx={{ alignSelf: "center" }}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -23,7 +23,7 @@ import { IconButton, tooltip } from "@kyoo/primitives";
|
|||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { useRouter } from "solito/router";
|
import { useRouter } from "solito/router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { View } from "react-native";
|
import { Platform, View } from "react-native";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import Fullscreen from "@material-symbols/svg-400/rounded/fullscreen-fill.svg";
|
import Fullscreen from "@material-symbols/svg-400/rounded/fullscreen-fill.svg";
|
||||||
import FullscreenExit from "@material-symbols/svg-400/rounded/fullscreen_exit-fill.svg";
|
import FullscreenExit from "@material-symbols/svg-400/rounded/fullscreen_exit-fill.svg";
|
||||||
@ -72,12 +72,13 @@ export const RightButtons = ({
|
|||||||
{/* </IconButton> */}
|
{/* </IconButton> */}
|
||||||
{/* </Tooltip> */}
|
{/* </Tooltip> */}
|
||||||
{/* )} */}
|
{/* )} */}
|
||||||
<IconButton
|
{Platform.OS === "web" && (
|
||||||
icon={isFullscreen ? FullscreenExit : Fullscreen}
|
<IconButton
|
||||||
onClick={() => setFullscreen(!isFullscreen)}
|
icon={isFullscreen ? FullscreenExit : Fullscreen}
|
||||||
{...tooltip(t("player.fullscreen"))}
|
onPress={() => setFullscreen(!isFullscreen)}
|
||||||
sx={{ color: "white" }}
|
{...tooltip(t("player.fullscreen"), true)}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{/* {subtitleAnchor && ( */}
|
{/* {subtitleAnchor && ( */}
|
||||||
{/* <SubtitleMenu */}
|
{/* <SubtitleMenu */}
|
||||||
{/* subtitles={subtitles!} */}
|
{/* subtitles={subtitles!} */}
|
||||||
|
@ -33,10 +33,6 @@ import { MediaSessionManager } from "./media-session";
|
|||||||
import { ErrorView } from "../fetch";
|
import { ErrorView } from "../fetch";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
// Callback used to hide the controls when the mouse goes iddle. This is stored globally to clear the old timeout
|
|
||||||
// if the mouse moves again (if this is stored as a state, the whole page is redrawn on mouse move)
|
|
||||||
let mouseCallback: NodeJS.Timeout;
|
|
||||||
|
|
||||||
const query = (slug: string): QueryIdentifier<WatchItem> => ({
|
const query = (slug: string): QueryIdentifier<WatchItem> => ({
|
||||||
path: ["watch", slug],
|
path: ["watch", slug],
|
||||||
parser: WatchItemP,
|
parser: WatchItemP,
|
||||||
@ -62,6 +58,14 @@ const mapData = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Callback used to hide the controls when the mouse goes iddle. This is stored globally to clear the old timeout
|
||||||
|
// if the mouse moves again (if this is stored as a state, the whole page is redrawn on mouse move)
|
||||||
|
let mouseCallback: NodeJS.Timeout;
|
||||||
|
// Number of time the video has been pressed. Used to handle double click. Since there is only one player,
|
||||||
|
// this can be global and not in the state.
|
||||||
|
let touchCount = 0;
|
||||||
|
let touchTimeout: NodeJS.Timeout;
|
||||||
|
|
||||||
export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -80,7 +84,7 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
|||||||
// useVideoKeyboard(data?.subtitles, data?.fonts, previous, next);
|
// useVideoKeyboard(data?.subtitles, data?.fonts, previous, next);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const setFullscreen = useSetAtom(fullscreenAtom);
|
const [isFullscreen, setFullscreen] = useAtom(fullscreenAtom);
|
||||||
const [isPlaying, setPlay] = useAtom(playAtom);
|
const [isPlaying, setPlay] = useAtom(playAtom);
|
||||||
const [showHover, setHover] = useState(false);
|
const [showHover, setHover] = useState(false);
|
||||||
const [mouseMoved, setMouseMoved] = useState(false);
|
const [mouseMoved, setMouseMoved] = useState(false);
|
||||||
@ -154,7 +158,23 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
|||||||
{/* `}</style> */}
|
{/* `}</style> */}
|
||||||
<Pressable
|
<Pressable
|
||||||
onHoverOut={() => setMouseMoved(false)}
|
onHoverOut={() => setMouseMoved(false)}
|
||||||
onPress={Platform.OS === "web" ? () => setPlay(!isPlaying) : show}
|
onPress={
|
||||||
|
Platform.OS === "web"
|
||||||
|
? (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
touchCount++;
|
||||||
|
if (touchCount == 2) {
|
||||||
|
touchCount = 0;
|
||||||
|
setFullscreen(!isFullscreen);
|
||||||
|
clearTimeout(touchTimeout);
|
||||||
|
} else
|
||||||
|
touchTimeout = setTimeout(() => {
|
||||||
|
touchCount = 0;
|
||||||
|
}, 400);
|
||||||
|
setPlay(!isPlaying);
|
||||||
|
}
|
||||||
|
: show
|
||||||
|
}
|
||||||
{...css({
|
{...css({
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -36,6 +36,7 @@ const playModeAtom = atom<PlayMode>(PlayMode.Direct);
|
|||||||
|
|
||||||
export const playAtom = atom(true);
|
export const playAtom = atom(true);
|
||||||
export const loadAtom = atom(false);
|
export const loadAtom = atom(false);
|
||||||
|
|
||||||
export const bufferedAtom = atom(0);
|
export const bufferedAtom = atom(0);
|
||||||
export const durationAtom = atom<number | undefined>(undefined);
|
export const durationAtom = atom<number | undefined>(undefined);
|
||||||
|
|
||||||
@ -49,18 +50,9 @@ export const progressAtom = atom<number, number>(
|
|||||||
const privateProgressAtom = atom(0);
|
const privateProgressAtom = atom(0);
|
||||||
const publicProgressAtom = atom(0);
|
const publicProgressAtom = atom(0);
|
||||||
|
|
||||||
export const [_volumeAtom, volumeAtom] = bakedAtom(100, (get, set, value, baker) => {
|
export const volumeAtom = atom(100);
|
||||||
const player = get(playerAtom);
|
export const mutedAtom = atom(false);
|
||||||
if (!player?.current) return;
|
|
||||||
set(baker, value);
|
|
||||||
if (player.current) player.current.volume = Math.max(0, Math.min(value, 100)) / 100;
|
|
||||||
});
|
|
||||||
export const [_mutedAtom, mutedAtom] = bakedAtom(false, (get, set, value, baker) => {
|
|
||||||
const player = get(playerAtom);
|
|
||||||
if (!player?.current) return;
|
|
||||||
set(baker, value);
|
|
||||||
if (player.current) player.current.muted = value;
|
|
||||||
});
|
|
||||||
export const [_, fullscreenAtom] = bakedAtom(false, async (_, set, value, baker) => {
|
export const [_, fullscreenAtom] = bakedAtom(false, async (_, set, value, baker) => {
|
||||||
try {
|
try {
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -82,11 +74,6 @@ export const Video = ({
|
|||||||
setError,
|
setError,
|
||||||
...props
|
...props
|
||||||
}: { links?: WatchItem["link"]; setError: (error: string | undefined) => void } & VideoProps) => {
|
}: { links?: WatchItem["link"]; setError: (error: string | undefined) => void } & VideoProps) => {
|
||||||
// const player = useRef<HTMLVideoElement>(null);
|
|
||||||
// const setPlayer = useSetAtom(playerAtom);
|
|
||||||
// const setVolume = useSetAtom(_volumeAtom);
|
|
||||||
// const setMuted = useSetAtom(_mutedAtom);
|
|
||||||
// const setFullscreen = useSetAtom(fullscreenAtom);
|
|
||||||
// const [playMode, setPlayMode] = useAtom(playModeAtom);
|
// const [playMode, setPlayMode] = useAtom(playModeAtom);
|
||||||
|
|
||||||
const ref = useRef<NativeVideo | null>(null);
|
const ref = useRef<NativeVideo | null>(null);
|
||||||
@ -101,17 +88,12 @@ export const Video = ({
|
|||||||
const setPrivateProgress = useSetAtom(privateProgressAtom);
|
const setPrivateProgress = useSetAtom(privateProgressAtom);
|
||||||
const setBuffered = useSetAtom(bufferedAtom);
|
const setBuffered = useSetAtom(bufferedAtom);
|
||||||
const setDuration = useSetAtom(durationAtom);
|
const setDuration = useSetAtom(durationAtom);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ref.current?.setStatusAsync({ positionMillis: publicProgress });
|
ref.current?.setStatusAsync({ positionMillis: publicProgress });
|
||||||
}, [publicProgress]);
|
}, [publicProgress]);
|
||||||
|
|
||||||
// setPlayer(player);
|
const volume = useAtomValue(volumeAtom);
|
||||||
|
const isMuted = useAtomValue(mutedAtom);
|
||||||
// useEffect(() => {
|
|
||||||
// if (!player.current) return;
|
|
||||||
// setPlay(!player.current.paused);
|
|
||||||
// }, [setPlay]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// setPlayMode(PlayMode.Direct);
|
// setPlayMode(PlayMode.Direct);
|
||||||
@ -150,6 +132,8 @@ export const Video = ({
|
|||||||
{...props}
|
{...props}
|
||||||
source={links ? { uri: links.direct } : undefined}
|
source={links ? { uri: links.direct } : undefined}
|
||||||
shouldPlay={isPlaying}
|
shouldPlay={isPlaying}
|
||||||
|
isMuted={isMuted}
|
||||||
|
volume={volume}
|
||||||
onPlaybackStatusUpdate={(status) => {
|
onPlaybackStatusUpdate={(status) => {
|
||||||
if (!status.isLoaded) {
|
if (!status.isLoaded) {
|
||||||
setLoad(true);
|
setLoad(true);
|
||||||
@ -158,7 +142,6 @@ export const Video = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setLoad(status.isPlaying !== status.shouldPlay);
|
setLoad(status.isPlaying !== status.shouldPlay);
|
||||||
setPlay(status.shouldPlay);
|
|
||||||
setPrivateProgress(status.positionMillis);
|
setPrivateProgress(status.positionMillis);
|
||||||
setBuffered(status.playableDurationMillis ?? 0);
|
setBuffered(status.playableDurationMillis ?? 0);
|
||||||
setDuration(status.durationMillis);
|
setDuration(status.durationMillis);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user