Make video touch nicer to use on mobile

This commit is contained in:
Zoe Roux 2023-07-18 17:59:33 +09:00
parent be499b3085
commit 2c49848dd7
4 changed files with 60 additions and 50 deletions

View File

@ -35,7 +35,7 @@ import {
} from "@kyoo/primitives";
import { Chapter, Font, Track, WatchItem } from "@kyoo/models";
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 { percent, rem, useYoshiki } from "yoshiki/native";
import { useRouter } from "solito/router";
@ -59,6 +59,7 @@ export const Hover = ({
onMenuOpen,
onMenuClose,
show,
onPointerDown,
...props
}: {
isLoading: boolean;
@ -83,7 +84,10 @@ export const Hover = ({
{({ css }) => (
<>
<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(
[
{
@ -128,7 +132,7 @@ export const Hover = ({
/>
</View>
</View>
</View>
</Pressable>
</>
)}
</ContrastArea>

View File

@ -21,7 +21,7 @@
import { QueryIdentifier, QueryPage, WatchItem, WatchItemP, useFetch } from "@kyoo/models";
import { Head } from "@kyoo/primitives";
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 { useRouter } from "solito/router";
import { useAtom } from "jotai";
@ -127,6 +127,24 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
};
}, [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)
return (
<>
@ -159,29 +177,7 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
next={next}
previous={previous}
/>
<PressView
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);
}}
<View
onPointerLeave={(e) => {
if (e.nativeEvent.pointerType === "mouse") setMouseMoved(false);
}}
@ -198,6 +194,7 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
subtitles={data?.subtitles}
setError={setPlaybackError}
fonts={data?.fonts}
onPointerDown={(e) => onPointerDown(e)}
onEnd={() => {
if (!data) return;
if (data.isMovie)
@ -217,15 +214,14 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
<Hover
{...mapData(data, previous, next)}
onPointerEnter={(e) => {
if (e.nativeEvent.pointerType === "mouse") setHover(true);
if (Platform.OS !== "web" || e.nativeEvent.pointerType === "mouse") setHover(true);
}}
onPointerLeave={(e) => {
if (e.nativeEvent.pointerType === "mouse") setHover(false);
}}
onPointerDown={(e) => {
// Prevent clicks on the hover to play/pause.
e.preventDefault();
e.stopPropagation();
if (!displayControls) onPointerDown(e);
if (Platform.OS === "web") e.preventDefault();
}}
onMenuOpen={() => setMenuOpen(true)}
onMenuClose={() => {
@ -235,7 +231,7 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => {
}}
show={displayControls}
/>
</PressView>
</View>
</>
);
};

View File

@ -39,6 +39,8 @@ import NativeVideo, { OnLoadData, VideoProps } from "react-native-video";
import { useTranslation } from "react-i18next";
import { PlayMode, playModeAtom } from "./state";
import uuid from "react-native-uuid";
import { Pressable } from "react-native";
import { useYoshiki } from "yoshiki/native";
const infoAtom = atom<OnLoadData | null>(null);
const videoAtom = atom(0);
@ -47,9 +49,10 @@ const audioAtom = atom(0);
const clientId = uuid.v4() as string;
const Video = forwardRef<NativeVideo, VideoProps>(function _NativeVideo(
{ onLoad, source, ...props },
{ onLoad, source, onPointerDown, ...props },
ref,
) {
const { css } = useYoshiki();
const token = useRef<string | null>(null);
const setInfo = useSetAtom(infoAtom);
const video = useAtomValue(videoAtom);
@ -66,23 +69,28 @@ const Video = forwardRef<NativeVideo, VideoProps>(function _NativeVideo(
}, [source]);
return (
<NativeVideo
ref={ref}
source={{
...source,
headers: {
Authorization: `Bearer: ${token.current}`,
"X-CLIENT-ID": clientId,
}
}}
onLoad={(info) => {
setInfo(info);
onLoad?.(info);
}}
selectedVideoTrack={video === -1 ? { type: "auto" } : { type: "resolution", value: video }}
selectedAudioTrack={{ type: "index", value: audio }}
{...props}
/>
<Pressable
focusable={false}
onPress={() => onPointerDown?.({ nativeEvent: { pointerType: "pointer" } } as any)}
{...css({ flexGrow: 1, flexShrink: 1 })}
>
<NativeVideo
ref={ref}
source={{
...source,
headers: {
Authorization: `Bearer: ${token.current}`,
"X-CLIENT-ID": clientId,
}
}}
onLoad={(info) => {
setInfo(info);
onLoad?.(info);
}}
selectedVideoTrack={video === -1 ? { type: "auto" } : { type: "resolution", value: video }}
selectedAudioTrack={{ type: "index", value: audio }}
{...props}
/></Pressable>
);
});

View File

@ -79,6 +79,7 @@ const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function
onPlayPause,
onMediaUnsupported,
fonts,
onPointerDown,
},
forwaredRef,
) {
@ -191,6 +192,7 @@ const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function
// onPlay={() => onPlayPause?.call(null, true)}
// onPause={() => onPlayPause?.call(null, false)}
onEnded={onEnd}
onPointerDown={(e) => onPointerDown?.(e as any)}
{...css({ width: "100%", height: "100%", objectFit: "contain" })}
/>
);