diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.js b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.js index 4c2c2ca5..b1bda180 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.js +++ b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.js @@ -561,7 +561,7 @@ const VideoPlayerBase = class extends React.Component { /** * Disables seek function. * - * Note that jump by arrow keys will also be disabled when `true`. + * Note that jump by arrow keys will also be disabled when `true`. * * @type {Boolean} * @public @@ -2314,6 +2314,10 @@ const VideoPlayerBase = class extends React.Component { mediaProps.height = height; mediaProps.videoRef = this.setVideoRef; mediaProps.config = reactPlayerConfig; + // 웹/TV 전체화면에서 ReactPlayer(YouTube) iframe이 자체 컨트롤을 활성화하지 않도록 포인터 이벤트 차단 + if (!panelInfo.modal) { + mediaProps.style = { ...(mediaProps.style || {}), pointerEvents: 'none' }; + } delete mediaProps.mediaComponent; delete mediaProps.ref; // mediaProps.isYoutube = isYoutube; diff --git a/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx b/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx index 8e9c7613..da0e1510 100644 --- a/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx +++ b/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx @@ -211,6 +211,7 @@ const MediaPanel = React.forwardRef( }); const videoPlayer = useRef(null); + const focusReturnRef = useRef(null); const isTransitioningToFullscreen = useRef(false); const [playListInfo, setPlayListInfo] = USE_STATE('playListInfo', ''); const [shopNowInfo, setShopNowInfo] = USE_STATE('shopNowInfo'); @@ -2004,42 +2005,79 @@ const MediaPanel = React.forwardRef( }; }, []); - const onEnded = useCallback((e) => { - if (panelInfoRef.current.shptmBanrTpNm === 'MEDIA') { - // ⚠️ 배경 설정 복원 취소 - DetailPanel 업데이트 없이 바로 패널 제거 - // dispatch( - // updatePanel({ - // name: panel_names.DETAIL_PANEL, - // panelInfo: { - // launchedFromPlayer: true, - // isPlayerFinished: true, - // }, - // }) - // ); - console.log('[MediaPanel] 🚫 Skipping background restoration for ended media'); - Spotlight.pause(); - setTimeout(() => { - Spotlight.resume(); - dispatch(PanelActions.popPanel()); - }, VIDEO_END_ACTION_DELAY); + const focusBackToPanel = useCallback(() => { + if (focusReturnRef.current) { + focusReturnRef.current.focus(); + return true; + } + return false; + }, []); + + const focusBackButtonOrFallback = useCallback(() => { + if (Spotlight.focus('player-back-button')) { + return true; + } + return focusBackToPanel(); + }, [focusBackToPanel]); + + const stopExternalPlayer = useCallback(() => { + const playerInstance = videoPlayer.current; + const media = playerInstance?.video; + + if (!media) { return; } - if (panelInfoRef.current.shptmBanrTpNm === 'VOD') { - Spotlight.pause(); - setTimeout(() => { - Spotlight.resume(); - if (panelInfoRef.current.modal) { - videoPlayer.current.play(); - } else { - dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL)); - } - }, VIDEO_END_ACTION_DELAY); - e?.stopPropagation(); - e?.preventDefault(); - return; + + if (typeof media.stopVideo === 'function') { + media.stopVideo(); + } + if (typeof media.seekTo === 'function') { + media.seekTo(0); + } + if (typeof media.pause === 'function') { + media.pause(); } }, []); + const onEnded = useCallback( + (e) => { + const currentInfo = panelInfoRef.current; + + // MEDIA: 기존 동작 유지 (배경 복원 없이 즉시 pop) + if (currentInfo.shptmBanrTpNm === 'MEDIA') { + console.log('[MediaPanel] 🚫 Skipping background restoration for ended media'); + Spotlight.pause(); + setTimeout(() => { + Spotlight.resume(); + dispatch(PanelActions.popPanel()); + }, VIDEO_END_ACTION_DELAY); + return; + } + + // VOD: modal 여부에 따라 동작 분리 + if (currentInfo.shptmBanrTpNm === 'VOD') { + Spotlight.pause(); + setTimeout(() => { + stopExternalPlayer(); + if (currentInfo.modal) { + // 모달: 화면 유지 + Back 포커스 회수 + videoPlayer.current?.showControls?.(); + Spotlight.resume(); + focusBackButtonOrFallback(); + } else { + // 전체화면: 바로 종료(pop)하여 포커스가 VOD 컨트롤로 남지 않게 함 + Spotlight.resume(); + dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL)); + } + }, VIDEO_END_ACTION_DELAY); + e?.stopPropagation(); + e?.preventDefault(); + return; + } + }, + [dispatch, focusBackButtonOrFallback, stopExternalPlayer] + ); + const onKeyDown = (ev) => { if (ev.keyCode === 34) { handleIndicatorDownClick(); @@ -2263,14 +2301,17 @@ const MediaPanel = React.forwardRef( > { - // if (!panelInfo?.modal && isOnTop && panelInfo?.shptmBanrTpNm !== 'MEDIA') { - // setBelowContentsVisible((prev) => !prev); - // } - // }} > +