mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Make video touch nicer to use on mobile
This commit is contained in:
parent
be499b3085
commit
2c49848dd7
@ -35,7 +35,7 @@ import {
|
|||||||
} from "@kyoo/primitives";
|
} from "@kyoo/primitives";
|
||||||
import { Chapter, Font, Track, WatchItem } from "@kyoo/models";
|
import { Chapter, Font, Track, WatchItem } from "@kyoo/models";
|
||||||
import { useAtomValue, useSetAtom, useAtom } from "jotai";
|
import { useAtomValue, useSetAtom, useAtom } from "jotai";
|
||||||
import { Platform, View, ViewProps } from "react-native";
|
import { Platform, Pressable, View, ViewProps } from "react-native";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { percent, rem, useYoshiki } from "yoshiki/native";
|
import { percent, rem, useYoshiki } from "yoshiki/native";
|
||||||
import { useRouter } from "solito/router";
|
import { useRouter } from "solito/router";
|
||||||
@ -59,6 +59,7 @@ export const Hover = ({
|
|||||||
onMenuOpen,
|
onMenuOpen,
|
||||||
onMenuClose,
|
onMenuClose,
|
||||||
show,
|
show,
|
||||||
|
onPointerDown,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
@ -83,7 +84,10 @@ export const Hover = ({
|
|||||||
{({ css }) => (
|
{({ css }) => (
|
||||||
<>
|
<>
|
||||||
<Back isLoading={isLoading} name={showName} href={href} {...css(opacity, props)} />
|
<Back isLoading={isLoading} name={showName} href={href} {...css(opacity, props)} />
|
||||||
<View
|
<Pressable
|
||||||
|
focusable={false}
|
||||||
|
onPointerDown={onPointerDown}
|
||||||
|
onPress={Platform.OS !== "web" ? () => onPointerDown?.({} as any): undefined}
|
||||||
{...css(
|
{...css(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -128,7 +132,7 @@ export const Hover = ({
|
|||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</Pressable>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ContrastArea>
|
</ContrastArea>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
import { QueryIdentifier, QueryPage, WatchItem, WatchItemP, useFetch } from "@kyoo/models";
|
import { QueryIdentifier, QueryPage, WatchItem, WatchItemP, useFetch } from "@kyoo/models";
|
||||||
import { Head } from "@kyoo/primitives";
|
import { Head } from "@kyoo/primitives";
|
||||||
import { useState, useEffect, ComponentProps } from "react";
|
import { useState, useEffect, ComponentProps } from "react";
|
||||||
import { Platform, Pressable, PressableProps, StyleSheet, View } from "react-native";
|
import { Platform, Pressable, PressableProps, StyleSheet, View, PointerEvent as NativePointerEvent } from "react-native";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useRouter } from "solito/router";
|
import { useRouter } from "solito/router";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
@ -127,6 +127,24 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
|||||||
};
|
};
|
||||||
}, [setFullscreen]);
|
}, [setFullscreen]);
|
||||||
|
|
||||||
|
const onPointerDown = (e: NativePointerEvent) => {
|
||||||
|
if (Platform.OS === "web") e.preventDefault();
|
||||||
|
if (Platform.OS !== "web" || e.nativeEvent.pointerType !== "mouse") {
|
||||||
|
displayControls ? setMouseMoved(false) : show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
touchCount++;
|
||||||
|
if (touchCount == 2) {
|
||||||
|
touchCount = 0;
|
||||||
|
setFullscreen(!isFullscreen);
|
||||||
|
clearTimeout(touchTimeout);
|
||||||
|
} else
|
||||||
|
touchTimeout = setTimeout(() => {
|
||||||
|
touchCount = 0;
|
||||||
|
}, 400);
|
||||||
|
setPlay(!isPlaying);
|
||||||
|
};
|
||||||
|
|
||||||
if (error || playbackError)
|
if (error || playbackError)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -159,29 +177,7 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
|||||||
next={next}
|
next={next}
|
||||||
previous={previous}
|
previous={previous}
|
||||||
/>
|
/>
|
||||||
<PressView
|
<View
|
||||||
focusable={false}
|
|
||||||
onMobilePress={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
displayControls ? setMouseMoved(false) : show();
|
|
||||||
}}
|
|
||||||
onPointerDown={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.nativeEvent.pointerType !== "mouse") {
|
|
||||||
displayControls ? setMouseMoved(false) : show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
touchCount++;
|
|
||||||
if (touchCount == 2) {
|
|
||||||
touchCount = 0;
|
|
||||||
setFullscreen(!isFullscreen);
|
|
||||||
clearTimeout(touchTimeout);
|
|
||||||
} else
|
|
||||||
touchTimeout = setTimeout(() => {
|
|
||||||
touchCount = 0;
|
|
||||||
}, 400);
|
|
||||||
setPlay(!isPlaying);
|
|
||||||
}}
|
|
||||||
onPointerLeave={(e) => {
|
onPointerLeave={(e) => {
|
||||||
if (e.nativeEvent.pointerType === "mouse") setMouseMoved(false);
|
if (e.nativeEvent.pointerType === "mouse") setMouseMoved(false);
|
||||||
}}
|
}}
|
||||||
@ -198,6 +194,7 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
|||||||
subtitles={data?.subtitles}
|
subtitles={data?.subtitles}
|
||||||
setError={setPlaybackError}
|
setError={setPlaybackError}
|
||||||
fonts={data?.fonts}
|
fonts={data?.fonts}
|
||||||
|
onPointerDown={(e) => onPointerDown(e)}
|
||||||
onEnd={() => {
|
onEnd={() => {
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
if (data.isMovie)
|
if (data.isMovie)
|
||||||
@ -217,15 +214,14 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
|||||||
<Hover
|
<Hover
|
||||||
{...mapData(data, previous, next)}
|
{...mapData(data, previous, next)}
|
||||||
onPointerEnter={(e) => {
|
onPointerEnter={(e) => {
|
||||||
if (e.nativeEvent.pointerType === "mouse") setHover(true);
|
if (Platform.OS !== "web" || e.nativeEvent.pointerType === "mouse") setHover(true);
|
||||||
}}
|
}}
|
||||||
onPointerLeave={(e) => {
|
onPointerLeave={(e) => {
|
||||||
if (e.nativeEvent.pointerType === "mouse") setHover(false);
|
if (e.nativeEvent.pointerType === "mouse") setHover(false);
|
||||||
}}
|
}}
|
||||||
onPointerDown={(e) => {
|
onPointerDown={(e) => {
|
||||||
// Prevent clicks on the hover to play/pause.
|
if (!displayControls) onPointerDown(e);
|
||||||
e.preventDefault();
|
if (Platform.OS === "web") e.preventDefault();
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
}}
|
||||||
onMenuOpen={() => setMenuOpen(true)}
|
onMenuOpen={() => setMenuOpen(true)}
|
||||||
onMenuClose={() => {
|
onMenuClose={() => {
|
||||||
@ -235,7 +231,7 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
|
|||||||
}}
|
}}
|
||||||
show={displayControls}
|
show={displayControls}
|
||||||
/>
|
/>
|
||||||
</PressView>
|
</View>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -39,6 +39,8 @@ import NativeVideo, { OnLoadData, VideoProps } from "react-native-video";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { PlayMode, playModeAtom } from "./state";
|
import { PlayMode, playModeAtom } from "./state";
|
||||||
import uuid from "react-native-uuid";
|
import uuid from "react-native-uuid";
|
||||||
|
import { Pressable } from "react-native";
|
||||||
|
import { useYoshiki } from "yoshiki/native";
|
||||||
|
|
||||||
const infoAtom = atom<OnLoadData | null>(null);
|
const infoAtom = atom<OnLoadData | null>(null);
|
||||||
const videoAtom = atom(0);
|
const videoAtom = atom(0);
|
||||||
@ -47,9 +49,10 @@ const audioAtom = atom(0);
|
|||||||
const clientId = uuid.v4() as string;
|
const clientId = uuid.v4() as string;
|
||||||
|
|
||||||
const Video = forwardRef<NativeVideo, VideoProps>(function _NativeVideo(
|
const Video = forwardRef<NativeVideo, VideoProps>(function _NativeVideo(
|
||||||
{ onLoad, source, ...props },
|
{ onLoad, source, onPointerDown, ...props },
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
|
const { css } = useYoshiki();
|
||||||
const token = useRef<string | null>(null);
|
const token = useRef<string | null>(null);
|
||||||
const setInfo = useSetAtom(infoAtom);
|
const setInfo = useSetAtom(infoAtom);
|
||||||
const video = useAtomValue(videoAtom);
|
const video = useAtomValue(videoAtom);
|
||||||
@ -66,23 +69,28 @@ const Video = forwardRef<NativeVideo, VideoProps>(function _NativeVideo(
|
|||||||
}, [source]);
|
}, [source]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NativeVideo
|
<Pressable
|
||||||
ref={ref}
|
focusable={false}
|
||||||
source={{
|
onPress={() => onPointerDown?.({ nativeEvent: { pointerType: "pointer" } } as any)}
|
||||||
...source,
|
{...css({ flexGrow: 1, flexShrink: 1 })}
|
||||||
headers: {
|
>
|
||||||
Authorization: `Bearer: ${token.current}`,
|
<NativeVideo
|
||||||
"X-CLIENT-ID": clientId,
|
ref={ref}
|
||||||
}
|
source={{
|
||||||
}}
|
...source,
|
||||||
onLoad={(info) => {
|
headers: {
|
||||||
setInfo(info);
|
Authorization: `Bearer: ${token.current}`,
|
||||||
onLoad?.(info);
|
"X-CLIENT-ID": clientId,
|
||||||
}}
|
}
|
||||||
selectedVideoTrack={video === -1 ? { type: "auto" } : { type: "resolution", value: video }}
|
}}
|
||||||
selectedAudioTrack={{ type: "index", value: audio }}
|
onLoad={(info) => {
|
||||||
{...props}
|
setInfo(info);
|
||||||
/>
|
onLoad?.(info);
|
||||||
|
}}
|
||||||
|
selectedVideoTrack={video === -1 ? { type: "auto" } : { type: "resolution", value: video }}
|
||||||
|
selectedAudioTrack={{ type: "index", value: audio }}
|
||||||
|
{...props}
|
||||||
|
/></Pressable>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function
|
|||||||
onPlayPause,
|
onPlayPause,
|
||||||
onMediaUnsupported,
|
onMediaUnsupported,
|
||||||
fonts,
|
fonts,
|
||||||
|
onPointerDown,
|
||||||
},
|
},
|
||||||
forwaredRef,
|
forwaredRef,
|
||||||
) {
|
) {
|
||||||
@ -191,6 +192,7 @@ const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function
|
|||||||
// onPlay={() => onPlayPause?.call(null, true)}
|
// onPlay={() => onPlayPause?.call(null, true)}
|
||||||
// onPause={() => onPlayPause?.call(null, false)}
|
// onPause={() => onPlayPause?.call(null, false)}
|
||||||
onEnded={onEnd}
|
onEnded={onEnd}
|
||||||
|
onPointerDown={(e) => onPointerDown?.(e as any)}
|
||||||
{...css({ width: "100%", height: "100%", objectFit: "contain" })}
|
{...css({ width: "100%", height: "100%", objectFit: "contain" })}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user