diff --git a/front/apps/mobile/package.json b/front/apps/mobile/package.json index d46a9112..6de8d41f 100644 --- a/front/apps/mobile/package.json +++ b/front/apps/mobile/package.json @@ -15,7 +15,7 @@ "@tanstack/react-query": "^4.19.1", "babel-plugin-transform-inline-environment-variables": "^0.4.4", "expo": "^47.0.0", - "expo-av": "~13.0.2", + "expo-av": "file:///home/anonymus-raccoon/projects/expo/packages/expo-av/", "expo-constants": "~14.0.2", "expo-linear-gradient": "~12.0.1", "expo-linking": "~3.2.3", diff --git a/front/apps/web/package.json b/front/apps/web/package.json index c14a62e1..cab06450 100644 --- a/front/apps/web/package.json +++ b/front/apps/web/package.json @@ -23,7 +23,7 @@ "@tanstack/react-query": "^4.19.1", "clsx": "^1.2.1", "csstype": "^3.1.1", - "expo-av": "^13.0.2", + "expo-av": "file:///home/anonymus-raccoon/projects/expo/packages/expo-av/", "expo-linear-gradient": "^12.0.1", "hls.js": "^1.2.8", "i18next": "^22.0.6", diff --git a/front/packages/primitives/src/index.ts b/front/packages/primitives/src/index.ts index 22cb1ad4..ce833c42 100644 --- a/front/packages/primitives/src/index.ts +++ b/front/packages/primitives/src/index.ts @@ -30,6 +30,7 @@ export * from "./tooltip"; export * from "./container"; export * from "./divider"; export * from "./progress"; +export * from "./slider"; export * from "./animated"; export * from "./utils"; diff --git a/front/packages/primitives/src/slider.tsx b/front/packages/primitives/src/slider.tsx new file mode 100644 index 00000000..fc7d2c49 --- /dev/null +++ b/front/packages/primitives/src/slider.tsx @@ -0,0 +1,127 @@ +/* + * Kyoo - A portable and vast media library solution. + * Copyright (c) Kyoo. + * + * See AUTHORS.md and LICENSE file in the project root for full license information. + * + * Kyoo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Kyoo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kyoo. If not, see . + */ + +import { useState } from "react"; +import { Platform, Pressable, View } from "react-native"; +import { percent, Stylable, useYoshiki } from "yoshiki/native"; +import { ts } from "./utils"; + +const calc = + Platform.OS === "web" + ? (first: number, operator: "+" | "-" | "*" | "/", second: number): number => + `calc(${first} ${operator} ${second})` as unknown as number + : (first: number, operator: "+" | "-" | "*" | "/", second: number): number => { + switch (operator) { + case "+": + return first + second; + case "-": + return first - second; + case "*": + return first * second; + case "/": + return first / second; + } + }; + +export const Slider = ({ + progress, + subtleProgress, + max = 100, + markers, + ...props +}: { progress: number; max?: number; subtleProgress?: number; markers?: number[] } & Stylable) => { + const { css } = useYoshiki(); + const [isSeeking, setSeek] = useState(false); + + return ( + { + // // prevent drag and drop of the UI. + // event.preventDefault(); + setSeek(true); + }} + {...css( + { + paddingVertical: ts(1), + }, + props, + )} + > + theme.overlay0, + })} + > + {subtleProgress && ( + theme.overlay1, + position: "absolute", + top: 0, + bottom: 0, + left: 0, + width: percent((subtleProgress / max) * 100), + })} + /> + )} + theme.accent, + position: "absolute", + top: 0, + bottom: 0, + left: 0, + width: percent((progress / max) * 100), + })} + /> + {markers?.map((x) => ( + theme.accent, + width: ts(1), + height: ts(1), + borderRadius: ts(0.5), + })} + /> + ))} + + theme.accent, + width: ts(2), + height: ts(2), + borderRadius: ts(1), + })} + /> + + ); +}; diff --git a/front/packages/ui/src/player/components/left-buttons.tsx b/front/packages/ui/src/player/components/left-buttons.tsx index a687826c..c073b218 100644 --- a/front/packages/ui/src/player/components/left-buttons.tsx +++ b/front/packages/ui/src/player/components/left-buttons.tsx @@ -59,7 +59,7 @@ export const LeftButtons = ({ )} setPlay(!isPlaying)} + onPress={() => setPlay(!isPlaying)} {...tooltip(isPlaying ? t("player.pause") : t("player.play"))} {...spacing} /> @@ -139,8 +139,9 @@ const ProgressText = () => { ); }; -const toTimerString = (timer: number, duration?: number) => { +const toTimerString = (timer?: number, duration?: number) => { + if (timer === undefined) return "??:??"; if (!duration) duration = timer; - if (duration >= 3600) return new Date(timer * 1000).toISOString().substring(11, 19); - return new Date(timer * 1000).toISOString().substring(14, 19); + if (duration >= 3600) return new Date(timer).toISOString().substring(11, 19); + return new Date(timer).toISOString().substring(14, 19); }; diff --git a/front/packages/ui/src/player/components/progress-bar.tsx b/front/packages/ui/src/player/components/progress-bar.tsx index b5bb7c24..ff0b3444 100644 --- a/front/packages/ui/src/player/components/progress-bar.tsx +++ b/front/packages/ui/src/player/components/progress-bar.tsx @@ -19,7 +19,7 @@ */ import { Chapter } from "@kyoo/models"; -import { ts } from "@kyoo/primitives"; +import { ts, Slider } from "@kyoo/primitives"; import { useAtom, useAtomValue } from "jotai"; import { useEffect, useRef, useState } from "react"; import { NativeTouchEvent, Pressable, Touchable, View } from "react-native"; @@ -27,14 +27,22 @@ import { useYoshiki, px, percent } from "yoshiki/native"; import { bufferedAtom, durationAtom, progressAtom } from "../state"; export const ProgressBar = ({ chapters }: { chapters?: Chapter[] }) => { - return null; - const { css } = useYoshiki(); - const ref = useRef(null); - const [isSeeking, setSeek] = useState(false); const [progress, setProgress] = useAtom(progressAtom); const buffered = useAtomValue(bufferedAtom); const duration = useAtomValue(durationAtom); + return ( + x.startTime)} + /> + ); + const { css } = useYoshiki(); + const ref = useRef(null); + const [isSeeking, setSeek] = useState(false); + const updateProgress = (event: NativeTouchEvent, skipSeek?: boolean) => { if (!(isSeeking || skipSeek) || !ref?.current) return; const pageX: number = "pageX" in event ? event.pageX : event.changedTouches[0].pageX; diff --git a/front/packages/ui/src/player/index.tsx b/front/packages/ui/src/player/index.tsx index 614c9f3d..429fad81 100644 --- a/front/packages/ui/src/player/index.tsx +++ b/front/packages/ui/src/player/index.tsx @@ -21,13 +21,12 @@ import { QueryIdentifier, QueryPage, WatchItem, WatchItemP, useFetch } from "@kyoo/models"; import { Head } from "@kyoo/primitives"; import { useState, useEffect, PointerEvent as ReactPointerEvent, ComponentProps } from "react"; -import { StyleSheet, View } from "react-native"; +import { PointerEvent, StyleSheet, View } from "react-native"; import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { useRouter } from "solito/router"; -import { Video } from "expo-av"; import { percent, useYoshiki } from "yoshiki/native"; import { Hover, LoadingIndicator } from "./components/hover"; -import { fullscreenAtom, playAtom, useSubtitleController, useVideoController } from "./state"; +import { fullscreenAtom, playAtom, Video } from "./state"; import { episodeDisplayNumber } from "../details/episode"; import { useVideoKeyboard } from "./keyboard"; import { MediaSessionManager } from "./media-session"; @@ -44,7 +43,7 @@ const query = (slug: string): QueryIdentifier => ({ const mapData = ( data: WatchItem | undefined, - previousSlug: string, + previousSlug?: string, nextSlug?: string, ): Partial> => { if (!data) return {}; @@ -61,6 +60,7 @@ const mapData = ( }; }; + export const Player: QueryPage<{ slug: string }> = ({ slug }) => { const { css } = useYoshiki(); @@ -152,17 +152,17 @@ export const Player: QueryPage<{ slug: string }> = ({ slug }) => { })} >