s.display);
const { isPaused } = usePlayerStore((s) => s.mediaPlaying);
@@ -13,6 +13,7 @@ export function Pause() {
return (
diff --git a/src/components/player/atoms/Settings.tsx b/src/components/player/atoms/Settings.tsx
new file mode 100644
index 00000000..7f372767
--- /dev/null
+++ b/src/components/player/atoms/Settings.tsx
@@ -0,0 +1,38 @@
+import { useEffect } from "react";
+
+import { Icons } from "@/components/Icon";
+import { OverlayAnchor } from "@/components/overlays/OverlayAnchor";
+import { Overlay } from "@/components/overlays/OverlayDisplay";
+import { OverlayPage } from "@/components/overlays/OverlayPage";
+import { OverlayRouter } from "@/components/overlays/OverlayRouter";
+import { VideoPlayerButton } from "@/components/player/internals/Button";
+import { useOverlayRouter } from "@/hooks/useOverlayRouter";
+import { usePlayerStore } from "@/stores/player/store";
+
+function SettingsOverlay({ id }: { id: string }) {
+ return (
+
+
+
+ This is settings menu, welcome!
+
+
+
+ );
+}
+
+export function Settings() {
+ const router = useOverlayRouter("settings");
+ const setHasOpenOverlay = usePlayerStore((s) => s.setHasOpenOverlay);
+
+ useEffect(() => {
+ setHasOpenOverlay(router.isRouterActive);
+ }, [setHasOpenOverlay, router.isRouterActive]);
+
+ return (
+
+ router.open()} icon={Icons.GEAR} />
+
+
+ );
+}
diff --git a/src/components/player/atoms/Skips.tsx b/src/components/player/atoms/Skips.tsx
index 82261a5b..455ee2fc 100644
--- a/src/components/player/atoms/Skips.tsx
+++ b/src/components/player/atoms/Skips.tsx
@@ -4,7 +4,7 @@ import { Icons } from "@/components/Icon";
import { VideoPlayerButton } from "@/components/player/internals/Button";
import { usePlayerStore } from "@/stores/player/store";
-export function SkipForward() {
+export function SkipForward(props: { iconSizeClass?: string }) {
const display = usePlayerStore((s) => s.display);
const time = usePlayerStore((s) => s.progress.time);
@@ -12,10 +12,16 @@ export function SkipForward() {
display?.setTime(time + 10);
}, [display, time]);
- return
;
+ return (
+
+ );
}
-export function SkipBackward() {
+export function SkipBackward(props: { iconSizeClass?: string }) {
const display = usePlayerStore((s) => s.display);
const time = usePlayerStore((s) => s.progress.time);
@@ -23,5 +29,11 @@ export function SkipBackward() {
display?.setTime(time - 10);
}, [display, time]);
- return
;
+ return (
+
+ );
}
diff --git a/src/components/player/atoms/Title.tsx b/src/components/player/atoms/Title.tsx
index 1fcf79b0..54453c18 100644
--- a/src/components/player/atoms/Title.tsx
+++ b/src/components/player/atoms/Title.tsx
@@ -2,5 +2,5 @@ import { usePlayerStore } from "@/stores/player/store";
export function Title() {
const title = usePlayerStore((s) => s.meta?.title);
- return
{title || "Beep beep, Richie!"}
;
+ return
{title}
;
}
diff --git a/src/components/player/atoms/Volume.tsx b/src/components/player/atoms/Volume.tsx
index 6e5ddc1a..7a303099 100644
--- a/src/components/player/atoms/Volume.tsx
+++ b/src/components/player/atoms/Volume.tsx
@@ -24,7 +24,6 @@ export function Volume(props: Props) {
const commitVolume = useCallback(
(percentage) => {
- console.log("setting", percentage);
setVolume(percentage);
},
[setVolume]
diff --git a/src/components/player/atoms/index.ts b/src/components/player/atoms/index.ts
index 3487d9de..e54adc08 100644
--- a/src/components/player/atoms/index.ts
+++ b/src/components/player/atoms/index.ts
@@ -8,3 +8,4 @@ export * from "./AutoPlayStart";
export * from "./Volume";
export * from "./Title";
export * from "./EpisodeTitle";
+export * from "./Settings";
diff --git a/src/components/player/base/CenterMobileControls.tsx b/src/components/player/base/CenterMobileControls.tsx
new file mode 100644
index 00000000..3c4d4bbc
--- /dev/null
+++ b/src/components/player/base/CenterMobileControls.tsx
@@ -0,0 +1,26 @@
+import classNames from "classnames";
+
+import { Transition } from "@/components/Transition";
+
+export function CenterMobileControls(props: {
+ children: React.ReactNode;
+ show: boolean;
+ className?: string;
+}) {
+ return (
+
+ *]:pointer-events-auto",
+ props.className,
+ ])}
+ >
+ {props.children}
+
+
+ );
+}
diff --git a/src/components/player/base/LeftSideControls.tsx b/src/components/player/base/LeftSideControls.tsx
index 38401f8e..acbe4754 100644
--- a/src/components/player/base/LeftSideControls.tsx
+++ b/src/components/player/base/LeftSideControls.tsx
@@ -1,8 +1,12 @@
+import classNames from "classnames";
import { useCallback, useEffect } from "react";
import { usePlayerStore } from "@/stores/player/store";
-export function LeftSideControls(props: { children: React.ReactNode }) {
+export function LeftSideControls(props: {
+ children: React.ReactNode;
+ className?: string;
+}) {
const setHoveringLeftControls = usePlayerStore(
(s) => s.setHoveringLeftControls
);
@@ -18,7 +22,10 @@ export function LeftSideControls(props: { children: React.ReactNode }) {
}, [setHoveringLeftControls]);
return (
-
+
{props.children}
);
diff --git a/src/components/player/hooks/useShouldShowControls.tsx b/src/components/player/hooks/useShouldShowControls.tsx
index c0f3af9f..ed74b742 100644
--- a/src/components/player/hooks/useShouldShowControls.tsx
+++ b/src/components/player/hooks/useShouldShowControls.tsx
@@ -1,9 +1,20 @@
import { PlayerHoverState } from "@/stores/player/slices/interface";
import { usePlayerStore } from "@/stores/player/store";
-export function useShouldShowControls() {
- const { hovering } = usePlayerStore((s) => s.interface);
- const { isPaused } = usePlayerStore((s) => s.mediaPlaying);
+export function useShouldShowControls(opts?: { touchOnly: boolean }) {
+ const hovering = usePlayerStore((s) => s.interface.hovering);
+ const lastHoveringState = usePlayerStore(
+ (s) => s.interface.lastHoveringState
+ );
+ const isPaused = usePlayerStore((s) => s.mediaPlaying.isPaused);
+ const hasOpenOverlay = usePlayerStore((s) => s.interface.hasOpenOverlay);
- return hovering !== PlayerHoverState.NOT_HOVERING || isPaused;
+ const showTouchControls =
+ lastHoveringState === PlayerHoverState.MOBILE_TAPPED;
+ const notNotHovering = hovering !== PlayerHoverState.NOT_HOVERING;
+
+ if (opts?.touchOnly)
+ return (showTouchControls && notNotHovering) || isPaused || hasOpenOverlay;
+
+ return notNotHovering || isPaused || hasOpenOverlay;
}
diff --git a/src/components/player/hooks/useVolume.ts b/src/components/player/hooks/useVolume.ts
index 35242a43..06a94515 100644
--- a/src/components/player/hooks/useVolume.ts
+++ b/src/components/player/hooks/useVolume.ts
@@ -1,25 +1,26 @@
-import {
- getStoredVolume,
- setStoredVolume,
-} from "@/_oldvideo/components/hooks/volumeStore";
+import { setStoredVolume } from "@/_oldvideo/components/hooks/volumeStore";
import { usePlayerStore } from "@/stores/player/store";
// TODO use new stored volume
export function useVolume() {
const volume = usePlayerStore((s) => s.mediaPlaying.volume);
+ const lastVolume = usePlayerStore((s) => s.interface.lastVolume);
+ const setLastVolume = usePlayerStore((s) => s.setLastVolume);
const display = usePlayerStore((s) => s.display);
const toggleVolume = (_isKeyboardEvent = false) => {
// TODO use keyboard event
+ let newVolume = 0;
+
if (volume > 0) {
- setStoredVolume(volume);
- display?.setVolume(0);
- } else {
- const storedVolume = getStoredVolume();
- if (storedVolume > 0) display?.setVolume(storedVolume);
- else display?.setVolume(1);
- }
+ newVolume = 0;
+ setLastVolume(volume);
+ } else if (lastVolume > 0) newVolume = lastVolume;
+ else newVolume = 1;
+
+ display?.setVolume(newVolume);
+ setStoredVolume(newVolume);
};
return {
@@ -28,6 +29,7 @@ export function useVolume() {
},
setVolume(vol: number) {
setStoredVolume(vol);
+ setLastVolume(vol);
display?.setVolume(vol);
},
};
diff --git a/src/hooks/useOverlayRouter.ts b/src/hooks/useOverlayRouter.ts
index fbfc3135..046156de 100644
--- a/src/hooks/useOverlayRouter.ts
+++ b/src/hooks/useOverlayRouter.ts
@@ -94,6 +94,7 @@ export function useOverlayRouter(id: string) {
const router = useInternalOverlayRouter(id);
return {
id,
+ isRouterActive: router.isOverlayActive(),
open: router.open,
close: router.close,
navigate: router.navigate,
diff --git a/src/pages/PlayerView.tsx b/src/pages/PlayerView.tsx
index 688458f8..eb7bdaa6 100644
--- a/src/pages/PlayerView.tsx
+++ b/src/pages/PlayerView.tsx
@@ -7,15 +7,21 @@ import { AutoPlayStart } from "@/components/player/atoms";
import { usePlayer } from "@/components/player/hooks/usePlayer";
import { useShouldShowControls } from "@/components/player/hooks/useShouldShowControls";
import { ScrapingPart } from "@/pages/parts/player/ScrapingPart";
+import { PlayerHoverState } from "@/stores/player/slices/interface";
import {
PlayerMeta,
metaToScrapeMedia,
playerStatus,
} from "@/stores/player/slices/source";
+import { usePlayerStore } from "@/stores/player/store";
export function PlayerView() {
const { status, setScrapeStatus, playMedia, setMeta } = usePlayer();
+ const { lastHoveringState } = usePlayerStore((s) => s.interface);
+
const desktopControlsVisible = useShouldShowControls();
+ const touchControlsVisible = useShouldShowControls({ touchOnly: true });
+
const meta = useMemo
(
() => ({
type: "show",
@@ -71,6 +77,15 @@ export function PlayerView() {
+
+
+
+
+
+
@@ -91,14 +106,19 @@ export function PlayerView() {
-
+
-
+
+ {/* Do mobile controls here :) */}
+
+
+
diff --git a/src/pages/developer/TestView.tsx b/src/pages/developer/TestView.tsx
index 81d0c007..6c175eb2 100644
--- a/src/pages/developer/TestView.tsx
+++ b/src/pages/developer/TestView.tsx
@@ -1,5 +1,3 @@
-import { useEffect, useRef } from "react";
-
import { OverlayAnchor } from "@/components/overlays/OverlayAnchor";
import { Overlay, OverlayDisplay } from "@/components/overlays/OverlayDisplay";
import { OverlayPage } from "@/components/overlays/OverlayPage";
@@ -21,9 +19,10 @@ export default function TestView() {
>
Open
-
-
-
+
diff --git a/src/stores/player/slices/interface.ts b/src/stores/player/slices/interface.ts
index 5435fb63..a08b2313 100644
--- a/src/stores/player/slices/interface.ts
+++ b/src/stores/player/slices/interface.ts
@@ -15,7 +15,10 @@ export interface InterfaceSlice {
interface: {
isFullscreen: boolean;
isSeeking: boolean;
+ lastVolume: number;
+ hasOpenOverlay: boolean;
hovering: PlayerHoverState;
+ lastHoveringState: PlayerHoverState;
volumeChangedWithKeybind: boolean; // has the volume recently been adjusted with the up/down arrows recently?
volumeChangedWithKeybindDebounce: NodeJS.Timeout | null; // debounce for the duration of the "volume changed thingamajig"
@@ -27,19 +30,34 @@ export interface InterfaceSlice {
setSeeking(seeking: boolean): void;
setTimeFormat(format: VideoPlayerTimeFormat): void;
setHoveringLeftControls(state: boolean): void;
+ setHasOpenOverlay(state: boolean): void;
+ setLastVolume(state: number): void;
}
export const createInterfaceSlice: MakeSlice = (set, get) => ({
interface: {
+ hasOpenOverlay: false,
isFullscreen: false,
isSeeking: false,
+ lastVolume: 0,
leftControlHovering: false,
hovering: PlayerHoverState.NOT_HOVERING,
+ lastHoveringState: PlayerHoverState.NOT_HOVERING,
volumeChangedWithKeybind: false,
volumeChangedWithKeybindDebounce: null,
timeFormat: VideoPlayerTimeFormat.REGULAR,
},
+ setLastVolume(state) {
+ set((s) => {
+ s.interface.lastVolume = state;
+ });
+ },
+ setHasOpenOverlay(state) {
+ set((s) => {
+ s.interface.hasOpenOverlay = state;
+ });
+ },
setTimeFormat(format) {
set((s) => {
s.interface.timeFormat = format;
@@ -47,6 +65,8 @@ export const createInterfaceSlice: MakeSlice = (set, get) => ({
},
updateInterfaceHovering(newState: PlayerHoverState) {
set((s) => {
+ if (newState !== PlayerHoverState.NOT_HOVERING)
+ s.interface.lastHoveringState = newState;
s.interface.hovering = newState;
});
},