From 1a36d96f4820725c86476f3c5eedb2a5d3ecd19e Mon Sep 17 00:00:00 2001 From: Ivan Evans <74743263+Pasithea0@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:33:48 -0600 Subject: [PATCH 1/6] Disable scrolling in player --- src/assets/css/index.css | 8 ++++++++ src/pages/PlayerView.tsx | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/assets/css/index.css b/src/assets/css/index.css index 092499bc4..da78eca2b 100644 --- a/src/assets/css/index.css +++ b/src/assets/css/index.css @@ -10,6 +10,14 @@ body { font-size: 1.0248em; } +/* Disable scroll in player (PWA improvement) */ +html.no-scroll, +body.no-scroll { + overflow: hidden !important; + height: 100% !important; + touch-action: none !important; +} + html[data-full], html[data-full] body { overscroll-behavior-y: none; diff --git a/src/pages/PlayerView.tsx b/src/pages/PlayerView.tsx index 5282d9b38..0656d5c37 100644 --- a/src/pages/PlayerView.tsx +++ b/src/pages/PlayerView.tsx @@ -54,6 +54,13 @@ export function RealPlayerView() { }); useEffect(() => { reset(); + document.documentElement.classList.add("no-scroll"); + document.body.classList.add("no-scroll"); + + return () => { + document.documentElement.classList.remove("no-scroll"); + document.body.classList.remove("no-scroll"); + }; }, [paramsData, reset]); const metaChange = useCallback( From 05c4988066e37b9e951861fab8f67f78b11fcc96 Mon Sep 17 00:00:00 2001 From: Ivan Evans <74743263+Pasithea0@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:47:14 -0600 Subject: [PATCH 2/6] Disable PiP and Fullscreen for iOS PWA --- src/pages/parts/player/PlayerPart.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/pages/parts/player/PlayerPart.tsx b/src/pages/parts/player/PlayerPart.tsx index 2d73286ba..9eed5d3f5 100644 --- a/src/pages/parts/player/PlayerPart.tsx +++ b/src/pages/parts/player/PlayerPart.tsx @@ -20,6 +20,11 @@ export function PlayerPart(props: PlayerPartProps) { const { isMobile } = useIsMobile(); const isLoading = usePlayerStore((s) => s.mediaPlaying.isLoading); + // Detect if running as a PWA on iOS + const isIOSPWA = + /iPad|iPhone|iPod/i.test(navigator.userAgent) && + window.matchMedia("(display-mode: standalone)").matches; + return ( {props.children} @@ -122,12 +127,19 @@ export function PlayerPart(props: PlayerPartProps) {
- {status === playerStatus.PLAYING ? : null} + {/* Disable PiP for iOS PWA */} + {!isIOSPWA && + (status === playerStatus.PLAYING ? : null)} {status === playerStatus.PLAYING ? : null}
- + {/* Disable for iOS PWA */} + {!isIOSPWA && ( +
+ +
+ )}
From c748d0c17969fed44105f5b43d7069d80fa2c46b Mon Sep 17 00:00:00 2001 From: Ivan Evans <74743263+Pasithea0@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:51:47 -0600 Subject: [PATCH 3/6] Add info button for iOS PWA* Explains why PiP and Fullscreen are disabled. *Needs translations --- src/components/buttons/IosPwaLimitations.tsx | 23 ++++++++++++++++++++ src/pages/parts/player/PlayerPart.tsx | 7 ++++++ 2 files changed, 30 insertions(+) create mode 100644 src/components/buttons/IosPwaLimitations.tsx diff --git a/src/components/buttons/IosPwaLimitations.tsx b/src/components/buttons/IosPwaLimitations.tsx new file mode 100644 index 000000000..dc0ee9e7c --- /dev/null +++ b/src/components/buttons/IosPwaLimitations.tsx @@ -0,0 +1,23 @@ +/* eslint-disable no-alert */ +import { Icon, Icons } from "../Icon"; + +function IosPwaLimitations() { + const showAlert = () => { + alert( + "Due to Appleā€™s limitations, Picture-in-Picture (PiP) and Fullscreen are disabled on iOS PWAs. Use the browser vertion to re-enable these features.\n" + + "Tip: To hide the iOS home indicator, use guided access within the PWA!", + ); + }; + + return ( + + ); +} + +export default IosPwaLimitations; diff --git a/src/pages/parts/player/PlayerPart.tsx b/src/pages/parts/player/PlayerPart.tsx index 9eed5d3f5..cd82e35ae 100644 --- a/src/pages/parts/player/PlayerPart.tsx +++ b/src/pages/parts/player/PlayerPart.tsx @@ -1,5 +1,6 @@ import { ReactNode } from "react"; +import IosPwaLimitations from "@/components/buttons/IosPwaLimitations"; import { BrandPill } from "@/components/layout/BrandPill"; import { Player } from "@/components/player"; import { useShouldShowControls } from "@/components/player/hooks/useShouldShowControls"; @@ -140,6 +141,12 @@ export function PlayerPart(props: PlayerPartProps) {
)} + {/* Add info for iOS PWA */} + {isIOSPWA && ( +
+ +
+ )} From 2e08ed977130482756a70d6c38a37daf3a525e94 Mon Sep 17 00:00:00 2001 From: Ivan Evans <74743263+Pasithea0@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:06:59 -0600 Subject: [PATCH 4/6] Add Widescreen button* *Primarily adds a Widescreen button to replace a native iOS fullscreen feature. (Due to it being disabled now) Also available by holding shift and pressing the fullscreen button on desktop. --- src/components/Icon.tsx | 4 +++ src/components/player/atoms/Widescreen.tsx | 23 ++++++++++++++ .../player/internals/VideoContainer.tsx | 1 + src/pages/parts/player/PlayerPart.tsx | 30 +++++++++++++++++-- 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/components/player/atoms/Widescreen.tsx diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index dda27f5f1..4bd627a68 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -68,6 +68,8 @@ export enum Icons { BRUSH = "brush", UPLOAD = "upload", WEB = "web", + SHRINK = "shrink", + STRETCH = "stretch", } export interface IconProps { @@ -153,6 +155,8 @@ const iconList: Record = { `, + shrink: ``, + stretch: ``, }; function ChromeCastButton() { diff --git a/src/components/player/atoms/Widescreen.tsx b/src/components/player/atoms/Widescreen.tsx new file mode 100644 index 000000000..ccfb76bb8 --- /dev/null +++ b/src/components/player/atoms/Widescreen.tsx @@ -0,0 +1,23 @@ +import { useState } from "react"; + +import { Icons } from "@/components/Icon"; +import { VideoPlayerButton } from "@/components/player/internals/Button"; + +export function Widescreen() { + // Add widescreen status + const [isWideScreen, setIsWideScreen] = useState(false); + + return ( + { + const videoElement = document.getElementById("video-element"); + if (videoElement) { + videoElement.classList.toggle("object-cover"); + setIsWideScreen(!isWideScreen); + } + }} + /> + ); +} diff --git a/src/components/player/internals/VideoContainer.tsx b/src/components/player/internals/VideoContainer.tsx index ee31d6d98..1147e2a25 100644 --- a/src/components/player/internals/VideoContainer.tsx +++ b/src/components/player/internals/VideoContainer.tsx @@ -101,6 +101,7 @@ function VideoElement() { return (