From c54e01b8e0ea7aaa8630bb4556f28fe4e1e13e43 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Wed, 17 Aug 2022 10:38:18 +0200 Subject: [PATCH] Media Viewer: Fix video controls (#1997) --- .../mediaViewer/MediaViewerContent.tsx | 28 ++++++------------- .../mediaViewer/MediaViewerSlides.tsx | 20 ++++++------- src/components/mediaViewer/VideoPlayer.tsx | 17 +++++++++-- .../mediaViewer/VideoPlayerControls.tsx | 5 ++-- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/components/mediaViewer/MediaViewerContent.tsx b/src/components/mediaViewer/MediaViewerContent.tsx index 1b574a1a7..2c33db1b2 100644 --- a/src/components/mediaViewer/MediaViewerContent.tsx +++ b/src/components/mediaViewer/MediaViewerContent.tsx @@ -33,8 +33,8 @@ type OwnProps = { animationLevel: 0 | 1 | 2; onClose: () => void; onFooterClick: () => void; - setIsFooterHidden?: (isHidden: boolean) => void; - isFooterHidden?: boolean; + setControlsVisible?: (isVisible: boolean) => void; + areControlsVisible: boolean; }; type StateProps = { @@ -62,14 +62,14 @@ const MediaViewerContent: FC = (props) => { message, origin, animationLevel, - isFooterHidden, + areControlsVisible, isProtected, volume, playbackRate, isMuted, onClose, onFooterClick, - setIsFooterHidden, + setControlsVisible, } = props; const isGhostAnimation = animationLevel === 2; @@ -94,16 +94,8 @@ const MediaViewerContent: FC = (props) => { const isOpen = Boolean(avatarOwner || mediaId); const toggleControls = useCallback((isVisible) => { - setIsFooterHidden?.(!isVisible); - }, [setIsFooterHidden]); - - const handleMouseMove = useCallback(() => { - toggleControls(true); - }, [toggleControls]); - - const handleMouseOut = useCallback(() => { - toggleControls(false); - }, [toggleControls]); + setControlsVisible?.(isVisible); + }, [setControlsVisible]); if (avatarOwner) { if (!isVideoAvatar) { @@ -129,7 +121,7 @@ const MediaViewerContent: FC = (props) => { loadProgress={loadProgress} fileSize={videoSize!} isMediaViewerOpen={isOpen && isActive} - areControlsVisible={!isFooterHidden} + areControlsVisible={areControlsVisible} toggleControls={toggleControls} isProtected={isProtected} noPlay={!isActive} @@ -150,8 +142,6 @@ const MediaViewerContent: FC = (props) => { return (
{isPhoto && renderPhoto( localBlobUrl || fullMediaBlobUrl || previewBlobUrl || pictogramBlobUrl, @@ -173,8 +163,8 @@ const MediaViewerContent: FC = (props) => { posterSize={message && calculateMediaViewerDimensions(dimensions!, hasFooter, true)} loadProgress={loadProgress} fileSize={videoSize!} + areControlsVisible={areControlsVisible} isMediaViewerOpen={isOpen && isActive} - areControlsVisible={!isFooterHidden} toggleControls={toggleControls} noPlay={!isActive} onClose={onClose} @@ -189,7 +179,7 @@ const MediaViewerContent: FC = (props) => { text={textParts} onClick={onFooterClick} isProtected={isProtected} - isHidden={isFooterHidden} + isHidden={IS_TOUCH_ENV ? !areControlsVisible : false} isForVideo={isVideo && !isGif} /> )} diff --git a/src/components/mediaViewer/MediaViewerSlides.tsx b/src/components/mediaViewer/MediaViewerSlides.tsx index e088708c2..705fcd694 100644 --- a/src/components/mediaViewer/MediaViewerSlides.tsx +++ b/src/components/mediaViewer/MediaViewerSlides.tsx @@ -97,7 +97,7 @@ const MediaViewerSlides: FC = ({ const prevZoomLevelChange = usePrevious(zoomLevelChange); const hasZoomChanged = prevZoomLevelChange !== undefined && prevZoomLevelChange !== zoomLevelChange; const forceUpdate = useForceUpdate(); - const [isFooterHidden, setIsFooterHidden] = useState(true); + const [areControlsVisible, setControlsVisible] = useState(false); const [isMouseDown, setIsMouseDown] = useState(false); const { height: windowHeight, width: windowWidth, isResizing } = useWindowSize(); const { onClose } = rest; @@ -121,15 +121,15 @@ const MediaViewerSlides: FC = ({ const shouldCloseOnVideo = isGif && !IS_IOS; const clickXThreshold = IS_TOUCH_ENV ? 40 : windowWidth / 10; - const handleToggleFooterVisibility = useCallback((e: React.MouseEvent) => { + const handleControlsVisibility = useCallback((e: React.MouseEvent) => { if (!IS_TOUCH_ENV) return; const isFooter = windowHeight - e.pageY < CLICK_Y_THRESHOLD; if (!isFooter && e.pageX < clickXThreshold) return; if (!isFooter && e.pageX > windowWidth - clickXThreshold) return; - setIsFooterHidden(!isFooterHidden); - }, [clickXThreshold, isFooterHidden, windowHeight, windowWidth]); + setControlsVisible(!areControlsVisible); + }, [clickXThreshold, areControlsVisible, windowHeight, windowWidth]); - useTimeout(() => setIsFooterHidden(false), ANIMATION_DURATION - 150); + useTimeout(() => setControlsVisible(true), ANIMATION_DURATION + 100); useEffect(() => { if (!containerRef.current || activeMediaId === undefined) { @@ -665,7 +665,7 @@ const MediaViewerSlides: FC = ({ /* eslint-disable-next-line react/jsx-props-no-spreading */ {...rest} animationLevel={animationLevel} - isFooterHidden={isFooterHidden} + areControlsVisible={areControlsVisible} mediaId={prevMediaId} />
@@ -676,7 +676,7 @@ const MediaViewerSlides: FC = ({ 'MediaViewerSlide--active', isMouseDown && scale > 1 && 'MediaViewerSlide--moving', )} - onClick={handleToggleFooterVisibility} + onClick={handleControlsVisibility} ref={activeSlideRef} style={getAnimationStyle(offsetX, offsetY, scale)} > @@ -686,8 +686,8 @@ const MediaViewerSlides: FC = ({ mediaId={activeMediaId} animationLevel={animationLevel} isActive={isActiveRef.current} - setIsFooterHidden={setIsFooterHidden} - isFooterHidden={isFooterHidden || scale !== 1} + setControlsVisible={setControlsVisible} + areControlsVisible={areControlsVisible && scale === 1} /> {hasNext && scale === 1 && !isResizing && ( @@ -696,7 +696,7 @@ const MediaViewerSlides: FC = ({ /* eslint-disable-next-line react/jsx-props-no-spreading */ {...rest} animationLevel={animationLevel} - isFooterHidden={isFooterHidden} + areControlsVisible={areControlsVisible} mediaId={nextMediaId} /> diff --git a/src/components/mediaViewer/VideoPlayer.tsx b/src/components/mediaViewer/VideoPlayer.tsx index 5bf1325ba..52d61b34c 100644 --- a/src/components/mediaViewer/VideoPlayer.tsx +++ b/src/components/mediaViewer/VideoPlayer.tsx @@ -29,11 +29,11 @@ type OwnProps = { fileSize: number; isMediaViewerOpen?: boolean; noPlay?: boolean; - areControlsVisible: boolean; volume: number; isMuted: boolean; playbackRate: number; isProtected?: boolean; + areControlsVisible: boolean; toggleControls: (isVisible: boolean) => void; onClose: (e: React.MouseEvent) => void; }; @@ -66,9 +66,20 @@ const VideoPlayer: FC = ({ const videoRef = useRef(null); const [isPlayed, setIsPlayed] = useState(!IS_TOUCH_ENV || !IS_IOS); const [currentTime, setCurrentTime] = useState(0); - const [isFullscreen, setFullscreen, exitFullscreen] = useFullscreenStatus(videoRef, setIsPlayed); + const handleVideoMove = useCallback(() => { + toggleControls(true); + }, [toggleControls]); + + const handleVideoLeave = useCallback((e) => { + const bounds = videoRef.current?.getBoundingClientRect(); + if (!bounds) return; + if (e.clientX < bounds.left || e.clientX > bounds.right || e.clientY < bounds.top || e.clientY > bounds.bottom) { + toggleControls(false); + } + }, [toggleControls]); + const { isBuffered, bufferedRanges, bufferingHandlers, bufferedProgress, } = useBuffering(); @@ -178,6 +189,8 @@ const VideoPlayer: FC = ({ return (
= ({ bufferedRanges, @@ -86,6 +86,7 @@ const VideoPlayerControls: FC = ({ const isSeeking = isSeekingRef.current; useEffect(() => { + if (!IS_TOUCH_ENV) return undefined; let timeout: number | undefined; if (!isVisible || !isPlayed || isSeeking || isPlaybackMenuOpen) { if (timeout) window.clearTimeout(timeout);