Enable the bottom scrubber only on touch

This commit is contained in:
Zoe Roux 2024-01-25 16:32:24 +01:00
parent d026f9b418
commit a56c06ca33
2 changed files with 55 additions and 29 deletions

View File

@ -18,6 +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 { useEffect } from "react";
import { Platform, ViewProps } from "react-native"; import { Platform, ViewProps } from "react-native";
export const TouchOnlyCss = () => { export const TouchOnlyCss = () => {
@ -39,3 +40,10 @@ export const touchOnly: ViewProps = {
export const noTouch: ViewProps = { export const noTouch: ViewProps = {
style: Platform.OS === "web" ? ({ $$css: true, noTouch: "noTouch" } as any) : { display: "none" }, style: Platform.OS === "web" ? ({ $$css: true, noTouch: "noTouch" } as any) : { display: "none" },
}; };
export const useIsTouch = () => {
if (Platform.OS !== "web") return true;
if (typeof window === "undefined") return false;
// TODO: Subscribe to the change.
return document.body.classList.contains("noHover");
};

View File

@ -33,12 +33,13 @@ import {
Tooltip, Tooltip,
tooltip, tooltip,
ts, ts,
useIsTouch,
} from "@kyoo/primitives"; } from "@kyoo/primitives";
import { Chapter, KyooImage, Subtitle, Audio } from "@kyoo/models"; import { Chapter, KyooImage, Subtitle, Audio } from "@kyoo/models";
import { useAtomValue, useSetAtom, useAtom } from "jotai"; import { useAtomValue, useSetAtom, useAtom } from "jotai";
import { ImageStyle, Platform, Pressable, View, ViewProps } from "react-native"; import { ImageStyle, 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, vh } from "yoshiki/native";
import { useRouter } from "solito/router"; import { useRouter } from "solito/router";
import ArrowBack from "@material-symbols/svg-400/rounded/arrow_back-fill.svg"; import ArrowBack from "@material-symbols/svg-400/rounded/arrow_back-fill.svg";
import { LeftButtons, TouchControls } from "./left-buttons"; import { LeftButtons, TouchControls } from "./left-buttons";
@ -63,6 +64,7 @@ const hoverReasonAtom = atom({
export const hoverAtom = atom((get) => export const hoverAtom = atom((get) =>
[!get(playAtom), ...Object.values(get(hoverReasonAtom))].includes(true), [!get(playAtom), ...Object.values(get(hoverReasonAtom))].includes(true),
); );
export const seekingAtom = atom(false);
export const Hover = ({ export const Hover = ({
isLoading, isLoading,
@ -93,6 +95,10 @@ export const Hover = ({
}) => { }) => {
const show = useAtomValue(hoverAtom); const show = useAtomValue(hoverAtom);
const setHover = useSetAtom(hoverReasonAtom); const setHover = useSetAtom(hoverReasonAtom);
const isSeeking = useAtomValue(seekingAtom);
const isTouch = useIsTouch();
const showBottomSeeker = isSeeking && isTouch;
return ( return (
<ContrastArea mode="dark"> <ContrastArea mode="dark">
@ -150,32 +156,37 @@ export const Hover = ({
maxWidth: percent(100), maxWidth: percent(100),
})} })}
> >
<H2 numberOfLines={1} {...css({ paddingBottom: ts(1) })}> {!showBottomSeeker && (
{isLoading ? <Skeleton {...css({ width: rem(15), height: rem(2) })} /> : name} <H2 numberOfLines={1} {...css({ paddingBottom: ts(1) })}>
</H2> {isLoading ? <Skeleton {...css({ width: rem(15), height: rem(2) })} /> : name}
<ProgressBar url={url} chapters={chapters} /> </H2>
<BottomScrubber url={url} /> )}
<View <ProgressBar chapters={chapters} url={url} />
{...css({ {showBottomSeeker ? (
flexDirection: "row", <BottomScrubber url={url} />
flexGrow: 1, ) : (
justifyContent: "space-between", <View
flexWrap: "wrap", {...css({
})} flexDirection: "row",
> flexGrow: 1,
<LeftButtons previousSlug={previousSlug} nextSlug={nextSlug} /> justifyContent: "space-between",
<RightButtons flexWrap: "wrap",
subtitles={subtitles} })}
audios={audios} >
fonts={fonts} <LeftButtons previousSlug={previousSlug} nextSlug={nextSlug} />
qualitiesAvailables={qualitiesAvailables} <RightButtons
onMenuOpen={() => setHover((x) => ({ ...x, menuOpened: true }))} subtitles={subtitles}
onMenuClose={() => { audios={audios}
// Disable hover since the menu overlay makes the mouseout unreliable. fonts={fonts}
setHover((x) => ({ ...x, menuOpened: false, mouseHover: false })); qualitiesAvailables={qualitiesAvailables}
}} onMenuOpen={() => setHover((x) => ({ ...x, menuOpened: true }))}
/> onMenuClose={() => {
</View> // Disable hover since the menu overlay makes the mouseout unreliable.
setHover((x) => ({ ...x, menuOpened: false, mouseHover: false }));
}}
/>
</View>
)}
</View> </View>
</View> </View>
</View> </View>
@ -318,13 +329,20 @@ const ProgressBar = ({ url, chapters }: { url: string; chapters?: Chapter[] }) =
const setPlay = useSetAtom(playAtom); const setPlay = useSetAtom(playAtom);
const [hoverProgress, setHoverProgress] = useState<number | null>(null); const [hoverProgress, setHoverProgress] = useState<number | null>(null);
const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 }); const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 });
const setSeeking = useSetAtom(seekingAtom);
return ( return (
<> <>
<Slider <Slider
progress={progress} progress={progress}
startSeek={() => setPlay(false)} startSeek={() => {
endSeek={() => setTimeout(() => setPlay(true), 10)} setPlay(false);
setSeeking(true);
}}
endSeek={() => {
setSeeking(false);
setTimeout(() => setPlay(true), 10);
}}
onHover={(progress, layout) => { onHover={(progress, layout) => {
setHoverProgress(progress); setHoverProgress(progress);
setLayout(layout); setLayout(layout);