Media Viewer: Various fixes (#2075)
This commit is contained in:
parent
eb69f55f29
commit
5de819826e
@ -130,6 +130,7 @@ const MediaViewerContent: FC<OwnProps & StateProps> = (props) => {
|
||||
noPlay={!isActive}
|
||||
onClose={onClose}
|
||||
isMuted
|
||||
shouldCloseOnClick
|
||||
volume={0}
|
||||
playbackRate={1}
|
||||
/>
|
||||
|
||||
@ -20,6 +20,7 @@ import usePrevious from '../../hooks/usePrevious';
|
||||
import useTimeout from '../../hooks/useTimeout';
|
||||
import useWindowSize from '../../hooks/useWindowSize';
|
||||
import useHistoryBack from '../../hooks/useHistoryBack';
|
||||
import { useFullscreenStatus } from '../../hooks/useFullscreen';
|
||||
|
||||
import MediaViewerContent from './MediaViewerContent';
|
||||
|
||||
@ -101,6 +102,7 @@ const MediaViewerSlides: FC<OwnProps> = ({
|
||||
const hasZoomChanged = prevZoomLevelChange !== undefined && prevZoomLevelChange !== zoomLevelChange;
|
||||
const forceUpdate = useForceUpdate();
|
||||
const [areControlsVisible, setControlsVisible] = useState(false);
|
||||
const isFullscreen = useFullscreenStatus();
|
||||
const [isMouseDown, setIsMouseDown] = useState(false);
|
||||
const { height: windowHeight, width: windowWidth, isResizing } = useWindowSize();
|
||||
const { onClose } = rest;
|
||||
@ -145,7 +147,7 @@ const MediaViewerSlides: FC<OwnProps> = ({
|
||||
}, [mediaId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current || activeMediaId === undefined || isHidden) {
|
||||
if (!containerRef.current || activeMediaId === undefined || isHidden || isFullscreen) {
|
||||
return undefined;
|
||||
}
|
||||
let lastTransform = lastTransformRef.current;
|
||||
@ -631,10 +633,11 @@ const MediaViewerSlides: FC<OwnProps> = ({
|
||||
animationLevel,
|
||||
setIsMouseDown,
|
||||
isHidden,
|
||||
isFullscreen,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current || !hasZoomChanged || isHidden) return;
|
||||
if (!containerRef.current || !hasZoomChanged || isHidden || isFullscreen) return;
|
||||
const { scale } = transformRef.current;
|
||||
const dir = zoomLevelChange > 0 ? -1 : +1;
|
||||
const minZoom = MIN_ZOOM * 0.6;
|
||||
@ -662,7 +665,7 @@ const MediaViewerSlides: FC<OwnProps> = ({
|
||||
containerRef.current.dispatchEvent(wheelEvent);
|
||||
},
|
||||
});
|
||||
}, [zoomLevelChange, hasZoomChanged, isHidden]);
|
||||
}, [zoomLevelChange, hasZoomChanged, isHidden, isFullscreen]);
|
||||
|
||||
if (activeMediaId === undefined) return undefined;
|
||||
|
||||
|
||||
@ -7,11 +7,13 @@ import { getActions } from '../../global';
|
||||
import type { ApiDimensions } from '../../api/types';
|
||||
|
||||
import useBuffering from '../../hooks/useBuffering';
|
||||
import useFullscreenStatus from '../../hooks/useFullscreen';
|
||||
import useFullscreen from '../../hooks/useFullscreen';
|
||||
import usePictureInPicture from '../../hooks/usePictureInPicture';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import useVideoCleanup from '../../hooks/useVideoCleanup';
|
||||
import { IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../util/environment';
|
||||
import {
|
||||
IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV, IS_YA_BROWSER,
|
||||
} from '../../util/environment';
|
||||
import safePlay from '../../util/safePlay';
|
||||
import stopEvent from '../../util/stopEvent';
|
||||
|
||||
@ -36,6 +38,7 @@ type OwnProps = {
|
||||
playbackRate: number;
|
||||
isProtected?: boolean;
|
||||
areControlsVisible: boolean;
|
||||
shouldCloseOnClick?: boolean;
|
||||
toggleControls: (isVisible: boolean) => void;
|
||||
onClose: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
||||
};
|
||||
@ -58,6 +61,7 @@ const VideoPlayer: FC<OwnProps> = ({
|
||||
onClose,
|
||||
toggleControls,
|
||||
areControlsVisible,
|
||||
shouldCloseOnClick,
|
||||
isProtected,
|
||||
}) => {
|
||||
const {
|
||||
@ -70,10 +74,18 @@ const VideoPlayer: FC<OwnProps> = ({
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const [isPlaying, setIsPlaying] = useState(!IS_TOUCH_ENV || !IS_IOS);
|
||||
const [currentTime, setCurrentTime] = useState(0);
|
||||
const [isFullscreen, setFullscreen, exitFullscreen] = useFullscreenStatus(videoRef, setIsPlaying);
|
||||
const [isFullscreen, setFullscreen, exitFullscreen] = useFullscreen(videoRef, setIsPlaying);
|
||||
|
||||
const handleEnterFullscreen = useCallback(() => setMediaViewerHidden(true), [setMediaViewerHidden]);
|
||||
const handleLeaveFullscreen = useCallback(() => setMediaViewerHidden(false), [setMediaViewerHidden]);
|
||||
const handleEnterFullscreen = useCallback(() => {
|
||||
// Yandex browser doesn't support PIP when video is hidden
|
||||
if (IS_YA_BROWSER) return;
|
||||
setMediaViewerHidden(true);
|
||||
}, [setMediaViewerHidden]);
|
||||
|
||||
const handleLeaveFullscreen = useCallback(() => {
|
||||
if (IS_YA_BROWSER) return;
|
||||
setMediaViewerHidden(false);
|
||||
}, [setMediaViewerHidden]);
|
||||
|
||||
const [
|
||||
isPictureInPictureSupported,
|
||||
@ -143,6 +155,14 @@ const VideoPlayer: FC<OwnProps> = ({
|
||||
}
|
||||
}, [isPlaying]);
|
||||
|
||||
const handleClick = useCallback((e: React.MouseEvent<HTMLVideoElement, MouseEvent>) => {
|
||||
if (shouldCloseOnClick) {
|
||||
onClose(e);
|
||||
} else {
|
||||
togglePlayState(e);
|
||||
}
|
||||
}, [onClose, shouldCloseOnClick, togglePlayState]);
|
||||
|
||||
useVideoCleanup(videoRef, []);
|
||||
|
||||
const handleTimeUpdate = useCallback((e: React.SyntheticEvent<HTMLVideoElement>) => {
|
||||
@ -231,7 +251,7 @@ const VideoPlayer: FC<OwnProps> = ({
|
||||
style={videoStyle}
|
||||
onPlay={() => setIsPlaying(true)}
|
||||
onEnded={handleEnded}
|
||||
onClick={!IS_SINGLE_COLUMN_LAYOUT ? togglePlayState : undefined}
|
||||
onClick={!IS_SINGLE_COLUMN_LAYOUT ? handleClick : undefined}
|
||||
onDoubleClick={!IS_TOUCH_ENV ? handleFullscreenChange : undefined}
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...bufferingHandlers}
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
}
|
||||
|
||||
.player-time {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@ -149,12 +150,23 @@
|
||||
}
|
||||
|
||||
.playback-rate-menu {
|
||||
color: var(--color-text);
|
||||
.bubble {
|
||||
min-width: 3.5rem;
|
||||
margin-right: 3.5rem;
|
||||
bottom: 4.1875rem
|
||||
margin-right: 5.8125rem;
|
||||
bottom: 4.1875rem;
|
||||
@media (max-width: 600px) {
|
||||
bottom: 4.6875rem;
|
||||
}
|
||||
}
|
||||
&.no-fullscreen {
|
||||
|
||||
&.no-fullscreen, &.no-pip {
|
||||
.bubble {
|
||||
margin-right: 3.3125rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.no-fullscreen.no-pip {
|
||||
.bubble {
|
||||
margin-right: 0.8125rem;
|
||||
}
|
||||
|
||||
@ -235,7 +235,11 @@ const VideoPlayerControls: FC<OwnProps> = ({
|
||||
</div>
|
||||
<Menu
|
||||
isOpen={isPlaybackMenuOpen}
|
||||
className={buildClassName('playback-rate-menu', !isFullscreenSupported && 'no-fullscreen')}
|
||||
className={buildClassName(
|
||||
'playback-rate-menu',
|
||||
!isFullscreenSupported && 'no-fullscreen',
|
||||
!isPictureInPictureSupported && 'no-pip',
|
||||
)}
|
||||
positionX="right"
|
||||
positionY="bottom"
|
||||
autoClose
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useLayoutEffect, useState } from '../lib/teact/teact';
|
||||
import { useLayoutEffect, useState, useEffect } from '../lib/teact/teact';
|
||||
import { IS_IOS } from '../util/environment';
|
||||
|
||||
type RefType = {
|
||||
@ -10,7 +10,7 @@ type CallbackType = (isPlayed: boolean) => void;
|
||||
|
||||
const prop = getBrowserFullscreenElementProp();
|
||||
|
||||
export default function useFullscreenStatus(elRef: RefType, setIsPlayed: CallbackType): ReturnType {
|
||||
export default function useFullscreen(elRef: RefType, setIsPlayed: CallbackType): ReturnType {
|
||||
const [isFullscreen, setIsFullscreen] = useState(Boolean(prop && document[prop]));
|
||||
|
||||
const setFullscreen = () => {
|
||||
@ -30,13 +30,18 @@ export default function useFullscreenStatus(elRef: RefType, setIsPlayed: Callbac
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const listener = () => { setIsFullscreen(Boolean(prop && document[prop])); };
|
||||
const video = elRef.current;
|
||||
const listener = () => {
|
||||
const isEnabled = Boolean(prop && document[prop]);
|
||||
setIsFullscreen(isEnabled);
|
||||
// In Firefox fullscreen video controls are not visible by default, so we force them manually
|
||||
video!.controls = isEnabled;
|
||||
};
|
||||
const listenerEnter = () => { setIsFullscreen(true); };
|
||||
const listenerExit = () => {
|
||||
setIsFullscreen(false);
|
||||
setIsPlayed(false);
|
||||
};
|
||||
const video = elRef.current;
|
||||
|
||||
document.addEventListener('fullscreenchange', listener, false);
|
||||
document.addEventListener('webkitfullscreenchange', listener, false);
|
||||
@ -66,6 +71,28 @@ export default function useFullscreenStatus(elRef: RefType, setIsPlayed: Callbac
|
||||
return [isFullscreen, setFullscreen, exitFullscreen];
|
||||
}
|
||||
|
||||
export const useFullscreenStatus = () => {
|
||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = () => {
|
||||
setIsFullscreen(checkIfFullscreen());
|
||||
};
|
||||
|
||||
document.addEventListener('fullscreenchange', listener, false);
|
||||
document.addEventListener('webkitfullscreenchange', listener, false);
|
||||
document.addEventListener('mozfullscreenchange', listener, false);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('fullscreenchange', listener, false);
|
||||
document.removeEventListener('webkitfullscreenchange', listener, false);
|
||||
document.removeEventListener('mozfullscreenchange', listener, false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return isFullscreen;
|
||||
};
|
||||
|
||||
function getBrowserFullscreenElementProp() {
|
||||
if (typeof document.fullscreenElement !== 'undefined') {
|
||||
return 'fullscreenElement';
|
||||
@ -74,10 +101,14 @@ function getBrowserFullscreenElementProp() {
|
||||
} else if (typeof document.webkitFullscreenElement !== 'undefined') {
|
||||
return 'webkitFullscreenElement';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
export function checkIfFullscreen() {
|
||||
const fullscreenProp = getBrowserFullscreenElementProp();
|
||||
return Boolean(fullscreenProp && document[fullscreenProp]);
|
||||
}
|
||||
|
||||
export function safeRequestFullscreen(video: HTMLVideoElement) {
|
||||
if (video.requestFullscreen) {
|
||||
video.requestFullscreen();
|
||||
|
||||
@ -44,6 +44,8 @@ export const IS_MAC_OS = PLATFORM_ENV === 'macOS';
|
||||
export const IS_IOS = PLATFORM_ENV === 'iOS';
|
||||
export const IS_ANDROID = PLATFORM_ENV === 'Android';
|
||||
export const IS_SAFARI = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||
export const IS_YA_BROWSER = navigator.userAgent.includes('YaBrowser');
|
||||
|
||||
export const IS_PWA = (
|
||||
window.matchMedia('(display-mode: standalone)').matches
|
||||
|| (window.navigator as any).standalone
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user