From 9cc8ee749085706f509fb201f92cebd92e9e3d47 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sat, 26 Jul 2025 00:38:56 +0200 Subject: [PATCH] Keep controls open in menues or hover --- .../ui/player/controls/bottom-controls.tsx | 32 +++++-- front/src/ui/player/controls/index.tsx | 91 ++++++++++++------- front/src/ui/player/controls/touch.tsx | 7 +- front/src/ui/player/index.tsx | 8 +- 4 files changed, 93 insertions(+), 45 deletions(-) diff --git a/front/src/ui/player/controls/bottom-controls.tsx b/front/src/ui/player/controls/bottom-controls.tsx index 343c8f1c..8bc0e9bb 100644 --- a/front/src/ui/player/controls/bottom-controls.tsx +++ b/front/src/ui/player/controls/bottom-controls.tsx @@ -1,5 +1,6 @@ import SkipNext from "@material-symbols/svg-400/rounded/skip_next-fill.svg"; import SkipPrevious from "@material-symbols/svg-400/rounded/skip_previous-fill.svg"; +import type { ComponentProps } from "react"; import { useTranslation } from "react-i18next"; import { Platform, View, type ViewProps } from "react-native"; import type { VideoPlayer } from "react-native-video"; @@ -9,6 +10,7 @@ import { H2, IconButton, Link, + type Menu, noTouch, Poster, tooltip, @@ -23,12 +25,18 @@ export const BottomControls = ({ poster, name, chapters, + previous, + next, + setMenu, ...props }: { player: VideoPlayer; poster: KImage; name: string; chapters: Chapter[]; + previous: string | null; + next: string | null; + setMenu: (isOpen: boolean) => void; } & ViewProps) => { const { css } = useYoshiki(); @@ -69,7 +77,12 @@ export const BottomControls = ({ name - + ); @@ -79,16 +92,23 @@ const ControlButtons = ({ player, previous, next, + setMenu, ...props }: { player: VideoPlayer; - previous: string; - next: string; + previous: string | null; + next: string | null; + setMenu: (isOpen: boolean) => void; }) => { const { css } = useYoshiki(); const { t } = useTranslation(); const spacing = css({ marginHorizontal: ts(1) }); + const menuProps = { + onMenuOpen: () => setMenu(true), + onMenuClose: () => setMenu(false), + ...spacing, + } satisfies Partial>; return ( - - - + + + {Platform.OS === "web" && } diff --git a/front/src/ui/player/controls/index.tsx b/front/src/ui/player/controls/index.tsx index 9ab306cd..4bdd9a95 100644 --- a/front/src/ui/player/controls/index.tsx +++ b/front/src/ui/player/controls/index.tsx @@ -1,6 +1,8 @@ +import { useState } from "react"; +import type { ViewProps } from "react-native"; import type { VideoPlayer } from "react-native-video"; import { useYoshiki } from "yoshiki/native"; -import type { KImage } from "~/models"; +import type { Chapter, KImage } from "~/models"; import { Back } from "./back"; import { BottomControls } from "./bottom-controls"; import { TouchControls } from "./touch"; @@ -8,54 +10,75 @@ import { TouchControls } from "./touch"; export const Controls = ({ player, title, + subTitle, poster, + chapters, + previous, + next, }: { player: VideoPlayer; title: string; - description: string | null; - poster: KImage | null; + subTitle: string; + poster: KImage; + chapters: Chapter[]; + previous: string | null; + next: string | null; }) => { const { css } = useYoshiki(); + const [hover, setHover] = useState(false); + const [menuOpenned, setMenu] = useState(false); + // + + const hoverControls = { + onPointerEnter: (e) => { + if (e.nativeEvent.pointerType === "mouse") setHover(true); + }, + onPointerLeave: (e) => { + if (e.nativeEvent.pointerType === "mouse") setHover(false); + }, + } satisfies ViewProps; + return ( - { - // if (e.nativeEvent.pointerType === "mouse") - // setHover((x) => ({ ...x, mouseHover: true })); - // }} - // onPointerLeave={(e) => { - // if (e.nativeEvent.pointerType === "mouse") - // setHover((x) => ({ ...x, mouseHover: false })); - // }} - > + theme.darkOverlay, - })} + {...css( + { + // pointerEvents: "auto", + position: "absolute", + top: 0, + left: 0, + right: 0, + bg: (theme) => theme.darkOverlay, + }, + hoverControls, + )} /> theme.darkOverlay, - })} + name={subTitle} + poster={poster} + chapters={chapters} + previous={previous} + next={next} + setMenu={setMenu} + {...css( + { + // Fixed is used because firefox android make the hover disapear under the navigation bar in absolute + // position: Platform.OS === "web" ? ("fixed" as any) : "absolute", + position: "absolute", + bottom: 0, + left: 0, + right: 0, + bg: (theme) => theme.darkOverlay, + }, + hoverControls, + )} /> ); }; + +export { LoadingIndicator } from "./misc"; diff --git a/front/src/ui/player/controls/touch.tsx b/front/src/ui/player/controls/touch.tsx index 54d46969..a330c2a6 100644 --- a/front/src/ui/player/controls/touch.tsx +++ b/front/src/ui/player/controls/touch.tsx @@ -12,13 +12,15 @@ import { useIsTouch } from "~/primitives"; export const TouchControls = ({ player, children, + forceShow = false, ...props -}: { player: VideoPlayer } & PressableProps) => { +}: { player: VideoPlayer; forceShow?: boolean } & PressableProps) => { const { css } = useYoshiki(); const isTouch = useIsTouch(); - const [shouldShow, setShow] = useState(true); + const [_show, setShow] = useState(true); const hideTimeout = useRef(null); + const shouldShow = forceShow || _show; const show = useCallback((val: boolean = true) => { setShow(val); if (hideTimeout.current) clearTimeout(hideTimeout.current); @@ -27,7 +29,6 @@ export const TouchControls = ({ setShow(false); }, 2500); }, []); - // TODO: handle mouse hover & seek // On mouse move useEffect(() => { diff --git a/front/src/ui/player/index.tsx b/front/src/ui/player/index.tsx index bef34123..c9c9749b 100644 --- a/front/src/ui/player/index.tsx +++ b/front/src/ui/player/index.tsx @@ -8,7 +8,7 @@ import { useToken } from "~/providers/account-context"; import { useLocalSetting } from "~/providers/settings"; import { type QueryIdentifier, useFetch } from "~/query"; import { useQueryState } from "~/utils"; -import { LoadingIndicator } from "./controls"; +import { Controls, LoadingIndicator } from "./controls"; const mapMetadata = (item: FullVideo | undefined) => { if (!item) return null; @@ -134,7 +134,11 @@ export const Player = () => { /> - + );