From 944c6ed14a28604782026d8da2ea7e02bb60065c Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 10 Jun 2024 17:03:43 +0700 Subject: [PATCH 01/18] fix Hide video playback controls on auto-playing videos --- src/components/FeatureTrainingModal.tsx | 1 + .../VideoPlayer/BaseVideoPlayer.tsx | 29 +++++++++++++++++-- src/components/VideoPlayer/types.ts | 1 + 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx index 88099b6d078b..587e48605828 100644 --- a/src/components/FeatureTrainingModal.tsx +++ b/src/components/FeatureTrainingModal.tsx @@ -135,6 +135,7 @@ function FeatureTrainingModal({ videoPlayerStyle={[styles.onboardingVideoPlayer, {aspectRatio}]} onVideoLoaded={setAspectRatio} controlsStatus={CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW} + canToggleControlOnTap shouldUseControlsBottomMargin={false} shouldPlay isLooping diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index bc7c32729c5a..d193ea88e54e 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -5,6 +5,7 @@ import type {MutableRefObject} from 'react'; import React, {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react'; import type {GestureResponderEvent} from 'react-native'; import {View} from 'react-native'; +import {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import AttachmentOfflineIndicator from '@components/AttachmentOfflineIndicator'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Hoverable from '@components/Hoverable'; @@ -48,6 +49,7 @@ function BaseVideoPlayer({ // eslint-disable-next-line @typescript-eslint/no-unused-vars isVideoHovered = false, isPreview, + canToggleControlOnTap = false, }: VideoPlayerProps) { const styles = useThemeStyles(); const { @@ -73,6 +75,11 @@ function BaseVideoPlayer({ const [sourceURL] = useState(VideoUtils.addSkipTimeTagToURL(url.includes('blob:') || url.includes('file:///') ? url : addEncryptedAuthTokenToURL(url), 0.001)); const [isPopoverVisible, setIsPopoverVisible] = useState(false); const [popoverAnchorPosition, setPopoverAnchorPosition] = useState({horizontal: 0, vertical: 0}); + const [controlStatusState, setControlStatusState] = useState(controlsStatus); + const controlsOpacity = useSharedValue(1); + const controlsAnimatedStyle = useAnimatedStyle(() => ({ + opacity: controlsOpacity.value, + })); const videoPlayerRef = useRef(null); const videoPlayerElementParentRef = useRef(null); @@ -96,6 +103,21 @@ function BaseVideoPlayer({ } }, [isCurrentlyURLSet, isPlaying, pauseVideo, playVideo, updateCurrentlyPlayingURL, url, videoResumeTryNumber]); + const toggleControlStatusState = useCallback(() => { + if (!canToggleControlOnTap) { + return; + } + if (controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { + setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE); + } else { + setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); + controlsOpacity.value = 1; + setTimeout(() => { + controlsOpacity.value = withTiming(0, {duration: 500}, () => setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); + }, 2000); + } + }, [canToggleControlOnTap, controlStatusState]); + const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { videoPopoverMenuPlayerRef.current = videoPlayerRef.current; videoPlayerRef.current?.getStatusAsync().then((status) => { @@ -311,6 +333,7 @@ function BaseVideoPlayer({ return; } togglePlayCurrentVideo(); + toggleControlStatusState(); }} style={[styles.flex1, styles.noSelect]} > @@ -367,7 +390,7 @@ function BaseVideoPlayer({ {((isLoading && !isOffline) || isBuffering) && } {isLoading && !isBuffering && } - {controlsStatus !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE && !isLoading && (isPopoverVisible || isHovered || canUseTouchScreen) && ( + {controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE && !isLoading && (isPopoverVisible || isHovered || canUseTouchScreen) && ( )} diff --git a/src/components/VideoPlayer/types.ts b/src/components/VideoPlayer/types.ts index 3dd3884534ec..7aaa06126122 100644 --- a/src/components/VideoPlayer/types.ts +++ b/src/components/VideoPlayer/types.ts @@ -30,6 +30,7 @@ type VideoPlayerProps = { controlsStatus?: ValueOf; shouldPlay?: boolean; isPreview?: boolean; + canToggleControlOnTap?: boolean; }; export type {VideoPlayerProps, VideoWithOnFullScreenUpdate}; From fe167aa523065af8dacc9de2131dbc4338b70857 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 10 Jun 2024 17:13:20 +0700 Subject: [PATCH 02/18] fix lint --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index d193ea88e54e..560d17067e99 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -116,7 +116,7 @@ function BaseVideoPlayer({ controlsOpacity.value = withTiming(0, {duration: 500}, () => setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); }, 2000); } - }, [canToggleControlOnTap, controlStatusState]); + }, [canToggleControlOnTap, controlStatusState, controlsOpacity]); const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { videoPopoverMenuPlayerRef.current = videoPlayerRef.current; From 9caa203f83ce7de986b3b5e0cd53c7a7dc0a4a97 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 10 Jun 2024 17:41:03 +0700 Subject: [PATCH 03/18] fix update controlsStatus --- src/components/FeatureTrainingModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx index 587e48605828..5825a6fddd58 100644 --- a/src/components/FeatureTrainingModal.tsx +++ b/src/components/FeatureTrainingModal.tsx @@ -134,7 +134,7 @@ function FeatureTrainingModal({ url={videoURL} videoPlayerStyle={[styles.onboardingVideoPlayer, {aspectRatio}]} onVideoLoaded={setAspectRatio} - controlsStatus={CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW} + controlsStatus={CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE} canToggleControlOnTap shouldUseControlsBottomMargin={false} shouldPlay From 8a7993d11fa8feb5bd67df8d441ef12c8f27ca22 Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 11 Jun 2024 09:50:34 +0700 Subject: [PATCH 04/18] fix use runOnJS --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 560d17067e99..be5a842b6b29 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -5,7 +5,7 @@ import type {MutableRefObject} from 'react'; import React, {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react'; import type {GestureResponderEvent} from 'react-native'; import {View} from 'react-native'; -import {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; +import {runOnJS, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import AttachmentOfflineIndicator from '@components/AttachmentOfflineIndicator'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Hoverable from '@components/Hoverable'; @@ -113,7 +113,7 @@ function BaseVideoPlayer({ setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); controlsOpacity.value = 1; setTimeout(() => { - controlsOpacity.value = withTiming(0, {duration: 500}, () => setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); + controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); }, 2000); } }, [canToggleControlOnTap, controlStatusState, controlsOpacity]); From cf99a4cb0a664878cccf1e3efe9447c0664a78e9 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 26 Jun 2024 16:01:07 +0700 Subject: [PATCH 05/18] fix auto hide controls after playing video 2s --- .../VideoPlayer/BaseVideoPlayer.tsx | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index f99d1e36635c..5ab176f20c48 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -1,8 +1,9 @@ /* eslint-disable no-underscore-dangle */ import type {AVPlaybackStatus, VideoFullscreenUpdateEvent} from 'expo-av'; import {ResizeMode, Video, VideoFullscreenUpdate} from 'expo-av'; +import {debounce} from 'lodash'; import type {MutableRefObject} from 'react'; -import React, {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; import type {GestureResponderEvent} from 'react-native'; import {View} from 'react-native'; import {runOnJS, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; @@ -17,6 +18,7 @@ import {useVideoPopoverMenuContext} from '@components/VideoPlayerContexts/VideoP import {useVolumeContext} from '@components/VideoPlayerContexts/VolumeContext'; import VideoPopoverMenu from '@components/VideoPopoverMenu'; import useNetwork from '@hooks/useNetwork'; +import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; @@ -69,6 +71,7 @@ function BaseVideoPlayer({ const [duration, setDuration] = useState(videoDuration * 1000); const [position, setPosition] = useState(0); const [isPlaying, setIsPlaying] = useState(false); + const prevIsPlaying = usePrevious(isPlaying); const [isLoading, setIsLoading] = useState(true); const [isBuffering, setIsBuffering] = useState(true); // we add "#t=0.001" at the end of the URL to skip first milisecond of the video and always be able to show proper video preview when video is paused at the beginning @@ -112,11 +115,21 @@ function BaseVideoPlayer({ } else { setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); controlsOpacity.value = 1; - setTimeout(() => { - controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); - }, 2000); } - }, [canToggleControlOnTap, controlStatusState, controlsOpacity]); + }, [canToggleControlOnTap, controlStatusState]); + + const hideControlWithDelay = useCallback(() => { + setTimeout(() => { + controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); + }, 2000); + }, [controlsOpacity]); + const debouncedHideControlWithDelay = useMemo(() => debounce(hideControlWithDelay, 2000, {leading: true}), [hideControlWithDelay]); + + useEffect(() => { + if (!prevIsPlaying && isPlaying && controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { + debouncedHideControlWithDelay(); + } + }, [isPlaying, prevIsPlaying, debouncedHideControlWithDelay, controlStatusState]); const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { videoPopoverMenuPlayerRef.current = videoPlayerRef.current; From 964a0d2644012881acfde0b545f114703aeb7064 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 26 Jun 2024 16:02:49 +0700 Subject: [PATCH 06/18] fix missing condition --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 5ab176f20c48..84267c3b1ab4 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -126,10 +126,10 @@ function BaseVideoPlayer({ const debouncedHideControlWithDelay = useMemo(() => debounce(hideControlWithDelay, 2000, {leading: true}), [hideControlWithDelay]); useEffect(() => { - if (!prevIsPlaying && isPlaying && controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { + if (canToggleControlOnTap && !prevIsPlaying && isPlaying && controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { debouncedHideControlWithDelay(); } - }, [isPlaying, prevIsPlaying, debouncedHideControlWithDelay, controlStatusState]); + }, [isPlaying, prevIsPlaying, debouncedHideControlWithDelay, controlStatusState, canToggleControlOnTap]); const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { videoPopoverMenuPlayerRef.current = videoPlayerRef.current; From 5daecf088096729488d9e1279876451379a3647f Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 26 Jun 2024 16:26:14 +0700 Subject: [PATCH 07/18] fix lint --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 84267c3b1ab4..16fdde4e1513 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -106,17 +106,16 @@ function BaseVideoPlayer({ } }, [isCurrentlyURLSet, isPlaying, pauseVideo, playVideo, updateCurrentlyPlayingURL, url, videoResumeTryNumber]); - const toggleControlStatusState = useCallback(() => { + const showControl = useCallback(() => { if (!canToggleControlOnTap) { return; } if (controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { - setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE); - } else { - setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); - controlsOpacity.value = 1; + return; } - }, [canToggleControlOnTap, controlStatusState]); + setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); + controlsOpacity.value = 1; + }, [canToggleControlOnTap, controlStatusState, controlsOpacity]); const hideControlWithDelay = useCallback(() => { setTimeout(() => { @@ -346,7 +345,7 @@ function BaseVideoPlayer({ return; } togglePlayCurrentVideo(); - toggleControlStatusState(); + showControl(); }} style={[styles.flex1, styles.noSelect]} > From cfe687ae95c80ad815e14dc65fc8c00b29339b67 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 26 Jun 2024 16:28:00 +0700 Subject: [PATCH 08/18] fix lint --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 16fdde4e1513..3a7582359e44 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -125,9 +125,10 @@ function BaseVideoPlayer({ const debouncedHideControlWithDelay = useMemo(() => debounce(hideControlWithDelay, 2000, {leading: true}), [hideControlWithDelay]); useEffect(() => { - if (canToggleControlOnTap && !prevIsPlaying && isPlaying && controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { - debouncedHideControlWithDelay(); + if (!canToggleControlOnTap || prevIsPlaying || !isPlaying || controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { + return; } + debouncedHideControlWithDelay(); }, [isPlaying, prevIsPlaying, debouncedHideControlWithDelay, controlStatusState, canToggleControlOnTap]); const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { From f1f9bead59220a0ca4fed0dd5a6de973ee87b509 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 27 Jun 2024 15:38:24 +0700 Subject: [PATCH 09/18] fix do not play video on tap --- .../VideoPlayer/BaseVideoPlayer.tsx | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 3a7582359e44..10c707489a01 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -18,7 +18,7 @@ import {useVideoPopoverMenuContext} from '@components/VideoPlayerContexts/VideoP import {useVolumeContext} from '@components/VideoPlayerContexts/VolumeContext'; import VideoPopoverMenu from '@components/VideoPopoverMenu'; import useNetwork from '@hooks/useNetwork'; -import usePrevious from '@hooks/usePrevious'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; @@ -71,7 +71,6 @@ function BaseVideoPlayer({ const [duration, setDuration] = useState(videoDuration * 1000); const [position, setPosition] = useState(0); const [isPlaying, setIsPlaying] = useState(false); - const prevIsPlaying = usePrevious(isPlaying); const [isLoading, setIsLoading] = useState(true); const [isBuffering, setIsBuffering] = useState(true); // we add "#t=0.001" at the end of the URL to skip first milisecond of the video and always be able to show proper video preview when video is paused at the beginning @@ -94,6 +93,7 @@ function BaseVideoPlayer({ const videoStateRef = useRef(null); const {updateVolume} = useVolumeContext(); const {videoPopoverMenuPlayerRef, setCurrentPlaybackSpeed} = useVideoPopoverMenuContext(); + const {isSmallScreenWidth} = useResponsiveLayout(); const togglePlayCurrentVideo = useCallback(() => { videoResumeTryNumber.current = 0; @@ -117,19 +117,23 @@ function BaseVideoPlayer({ controlsOpacity.value = 1; }, [canToggleControlOnTap, controlStatusState, controlsOpacity]); - const hideControlWithDelay = useCallback(() => { - setTimeout(() => { - controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); - }, 2000); - }, [controlsOpacity]); - const debouncedHideControlWithDelay = useMemo(() => debounce(hideControlWithDelay, 2000, {leading: true}), [hideControlWithDelay]); + const hideControl = useCallback( + () => (controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE))), + [controlsOpacity], + ); + const debouncedHideControl = useMemo(() => debounce(hideControl, 2000), [hideControl]); useEffect(() => { - if (!canToggleControlOnTap || prevIsPlaying || !isPlaying || controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { + if (!canToggleControlOnTap || controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { + return; + } + if (!isPlaying) { + debouncedHideControl.cancel(); return; } - debouncedHideControlWithDelay(); - }, [isPlaying, prevIsPlaying, debouncedHideControlWithDelay, controlStatusState, canToggleControlOnTap]); + + debouncedHideControl(); + }, [isPlaying, debouncedHideControl, controlStatusState, canToggleControlOnTap]); const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { videoPopoverMenuPlayerRef.current = videoPlayerRef.current; @@ -345,7 +349,9 @@ function BaseVideoPlayer({ if (isFullScreenRef.current) { return; } - togglePlayCurrentVideo(); + if (!isSmallScreenWidth) { + togglePlayCurrentVideo(); + } showControl(); }} style={[styles.flex1, styles.noSelect]} From 801707f6467711d1788d17501c5d5f9f2b7739f4 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 3 Jul 2024 16:56:21 +0700 Subject: [PATCH 10/18] fix reset the debounce once click on video --- .../VideoPlayer/BaseVideoPlayer.tsx | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 10c707489a01..80bf7472d1e3 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -106,17 +106,6 @@ function BaseVideoPlayer({ } }, [isCurrentlyURLSet, isPlaying, pauseVideo, playVideo, updateCurrentlyPlayingURL, url, videoResumeTryNumber]); - const showControl = useCallback(() => { - if (!canToggleControlOnTap) { - return; - } - if (controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { - return; - } - setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); - controlsOpacity.value = 1; - }, [canToggleControlOnTap, controlStatusState, controlsOpacity]); - const hideControl = useCallback( () => (controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE))), [controlsOpacity], @@ -135,6 +124,18 @@ function BaseVideoPlayer({ debouncedHideControl(); }, [isPlaying, debouncedHideControl, controlStatusState, canToggleControlOnTap]); + const showControl = useCallback(() => { + if (!canToggleControlOnTap) { + return; + } + if (controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { + debouncedHideControl(); + return; + } + setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); + controlsOpacity.value = 1; + }, [canToggleControlOnTap, controlStatusState, controlsOpacity, debouncedHideControl]); + const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { videoPopoverMenuPlayerRef.current = videoPlayerRef.current; videoPlayerRef.current?.getStatusAsync().then((status) => { From 2fc87597d6b2a3bf93e32d18594e6223d919ee57 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 5 Jul 2024 18:49:46 +0700 Subject: [PATCH 11/18] fix do not hide control if popover is opening --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 80bf7472d1e3..fd6976eabffc 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -116,13 +116,13 @@ function BaseVideoPlayer({ if (!canToggleControlOnTap || controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { return; } - if (!isPlaying) { + if (!isPlaying || isPopoverVisible) { debouncedHideControl.cancel(); return; } debouncedHideControl(); - }, [isPlaying, debouncedHideControl, controlStatusState, canToggleControlOnTap]); + }, [isPlaying, debouncedHideControl, controlStatusState, canToggleControlOnTap, isPopoverVisible]); const showControl = useCallback(() => { if (!canToggleControlOnTap) { From 80504a8728130196d01e785c2bb3a57ebf34daee Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 17 Jul 2024 00:40:06 +0700 Subject: [PATCH 12/18] remove canToggleControlOnTap and fix lint --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 17 ++++++----------- src/components/VideoPlayer/types.ts | 1 - 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index cfd234c1f9f5..b93d4e13c78c 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -51,7 +51,6 @@ function BaseVideoPlayer({ // eslint-disable-next-line @typescript-eslint/no-unused-vars isVideoHovered = false, isPreview, - canToggleControlOnTap = false, }: VideoPlayerProps) { const styles = useThemeStyles(); const { @@ -106,14 +105,13 @@ function BaseVideoPlayer({ } }, [isCurrentlyURLSet, isPlaying, pauseVideo, playVideo, updateCurrentlyPlayingURL, url, videoResumeTryNumber]); - const hideControl = useCallback( - () => (controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE))), - [controlsOpacity], - ); + const hideControl = useCallback(() => { + controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); + }, [controlsOpacity]); const debouncedHideControl = useMemo(() => debounce(hideControl, 2000), [hideControl]); useEffect(() => { - if (!canToggleControlOnTap || controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { + if (controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { return; } if (!isPlaying || isPopoverVisible) { @@ -122,19 +120,16 @@ function BaseVideoPlayer({ } debouncedHideControl(); - }, [isPlaying, debouncedHideControl, controlStatusState, canToggleControlOnTap, isPopoverVisible]); + }, [isPlaying, debouncedHideControl, controlStatusState, isPopoverVisible]); const showControl = useCallback(() => { - if (!canToggleControlOnTap) { - return; - } if (controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { debouncedHideControl(); return; } setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); controlsOpacity.value = 1; - }, [canToggleControlOnTap, controlStatusState, controlsOpacity, debouncedHideControl]); + }, [controlStatusState, controlsOpacity, debouncedHideControl]); const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { videoPopoverMenuPlayerRef.current = videoPlayerRef.current; diff --git a/src/components/VideoPlayer/types.ts b/src/components/VideoPlayer/types.ts index 7aaa06126122..3dd3884534ec 100644 --- a/src/components/VideoPlayer/types.ts +++ b/src/components/VideoPlayer/types.ts @@ -30,7 +30,6 @@ type VideoPlayerProps = { controlsStatus?: ValueOf; shouldPlay?: boolean; isPreview?: boolean; - canToggleControlOnTap?: boolean; }; export type {VideoPlayerProps, VideoWithOnFullScreenUpdate}; From 1cb1e811582846ab9d8219960692f0bbd0816a5d Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 17 Jul 2024 00:44:48 +0700 Subject: [PATCH 13/18] fix type --- src/components/FeatureTrainingModal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx index 7df83b423c70..68f9cafe12bb 100644 --- a/src/components/FeatureTrainingModal.tsx +++ b/src/components/FeatureTrainingModal.tsx @@ -139,7 +139,6 @@ function FeatureTrainingModal({ videoPlayerStyle={[styles.onboardingVideoPlayer, {aspectRatio}]} onVideoLoaded={setAspectRatio} controlsStatus={CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE} - canToggleControlOnTap shouldUseControlsBottomMargin={false} shouldPlay isLooping From f73f558d87d4dcf19ba415183303f6147896d007 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 17 Jul 2024 01:05:55 +0700 Subject: [PATCH 14/18] fix lint --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index b93d4e13c78c..89a4753b9f7f 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -106,6 +106,7 @@ function BaseVideoPlayer({ }, [isCurrentlyURLSet, isPlaying, pauseVideo, playVideo, updateCurrentlyPlayingURL, url, videoResumeTryNumber]); const hideControl = useCallback(() => { + // eslint-disable-next-line react-compiler/react-compiler controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); }, [controlsOpacity]); const debouncedHideControl = useMemo(() => debounce(hideControl, 2000), [hideControl]); From b81117fad822455354e99b929cf9c6d5e7e6868f Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 22 Jul 2024 16:06:17 +0700 Subject: [PATCH 15/18] fix hover over video should display control in dekstop --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 89a4753b9f7f..7c5eb5d75541 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -92,7 +92,6 @@ function BaseVideoPlayer({ const videoStateRef = useRef(null); const {updateVolume} = useVolumeContext(); const {videoPopoverMenuPlayerRef, setCurrentPlaybackSpeed} = useVideoPopoverMenuContext(); - const {isSmallScreenWidth} = useResponsiveLayout(); const togglePlayCurrentVideo = useCallback(() => { videoResumeTryNumber.current = 0; @@ -112,6 +111,19 @@ function BaseVideoPlayer({ const debouncedHideControl = useMemo(() => debounce(hideControl, 2000), [hideControl]); useEffect(() => { + if (canUseTouchScreen) { + return; + } + // If the device cannot use touch screen, always set the control status as 'show'. + // Then if user hover over the video, controls is shown. + setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); + }, [canUseTouchScreen]); + + useEffect(() => { + // We only auto hide the control if the device can use touch screen. + if (!canUseTouchScreen) { + return; + } if (controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { return; } @@ -121,7 +133,7 @@ function BaseVideoPlayer({ } debouncedHideControl(); - }, [isPlaying, debouncedHideControl, controlStatusState, isPopoverVisible]); + }, [isPlaying, debouncedHideControl, controlStatusState, isPopoverVisible, canUseTouchScreen]); const showControl = useCallback(() => { if (controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { @@ -347,7 +359,7 @@ function BaseVideoPlayer({ if (isFullScreenRef.current) { return; } - if (!isSmallScreenWidth) { + if (!canUseTouchScreen) { togglePlayCurrentVideo(); } showControl(); From dd15a3d0475009ccea0b8f3cd3d7d29b9e2adca8 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 22 Jul 2024 16:22:16 +0700 Subject: [PATCH 16/18] fix lint --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 7c5eb5d75541..dcd3181f2fd6 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -18,7 +18,6 @@ import {useVideoPopoverMenuContext} from '@components/VideoPlayerContexts/VideoP import {useVolumeContext} from '@components/VideoPlayerContexts/VolumeContext'; import VideoPopoverMenu from '@components/VideoPopoverMenu'; import useNetwork from '@hooks/useNetwork'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; From 53f69d656d333fcc4eec0d20672af0aea986ca4c Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 31 Jul 2024 16:43:17 +0700 Subject: [PATCH 17/18] do not delay hide control & hide control on tap --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index dcd3181f2fd6..176cc84a6dcc 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -134,14 +134,14 @@ function BaseVideoPlayer({ debouncedHideControl(); }, [isPlaying, debouncedHideControl, controlStatusState, isPopoverVisible, canUseTouchScreen]); - const showControl = useCallback(() => { + const toggleControl = useCallback(() => { if (controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) { - debouncedHideControl(); + hideControl(); return; } setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW); controlsOpacity.value = 1; - }, [controlStatusState, controlsOpacity, debouncedHideControl]); + }, [controlStatusState, controlsOpacity, hideControl]); const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => { videoPopoverMenuPlayerRef.current = videoPlayerRef.current; @@ -360,8 +360,9 @@ function BaseVideoPlayer({ } if (!canUseTouchScreen) { togglePlayCurrentVideo(); + return; } - showControl(); + toggleControl(); }} style={[styles.flex1, styles.noSelect]} > From 8f5c197e95c3ac3c87ccf8e7a909baf37a320593 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 1 Aug 2024 14:27:59 +0700 Subject: [PATCH 18/18] reduce hide delay to 1500 --- src/components/VideoPlayer/BaseVideoPlayer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.tsx b/src/components/VideoPlayer/BaseVideoPlayer.tsx index 176cc84a6dcc..6f810b4ec694 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.tsx +++ b/src/components/VideoPlayer/BaseVideoPlayer.tsx @@ -107,7 +107,7 @@ function BaseVideoPlayer({ // eslint-disable-next-line react-compiler/react-compiler controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE)); }, [controlsOpacity]); - const debouncedHideControl = useMemo(() => debounce(hideControl, 2000), [hideControl]); + const debouncedHideControl = useMemo(() => debounce(hideControl, 1500), [hideControl]); useEffect(() => { if (canUseTouchScreen) {