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 }) => {
})}
>