diff --git a/com.twin.app.shoptime/src/actions/playActions.js b/com.twin.app.shoptime/src/actions/playActions.js index efeb97e5..c8b32235 100644 --- a/com.twin.app.shoptime/src/actions/playActions.js +++ b/com.twin.app.shoptime/src/actions/playActions.js @@ -217,7 +217,7 @@ export const finishVideoPreview = () => (dispatch, getState) => { clearTimeout(startVideoFocusTimer); startVideoFocusTimer = null; } - dispatch(popPanel()); + // dispatch(popPanel()); } }; @@ -235,7 +235,7 @@ export const finishModalVideoForce = () => (dispatch, getState) => { startVideoFocusTimer = null; } // panelName을 지정하면 스택 어디에 있든 해당 패널을 제거 - dispatch(popPanel(panel_names.PLAYER_PANEL)); + // dispatch(popPanel(panel_names.PLAYER_PANEL)); } }; @@ -256,6 +256,123 @@ export const finishAllVideoForce = () => (dispatch, getState) => { } }; +// 🔽 패널은 유지하고 비디오만 중지하는 함수들 + +/** + * 패널을 닫지 않고(popPanel 하지 않고) 비디오만 중지합니다. + * 모달 비디오의 재생을 중지하고 숨김 상태로 만듭니다. + */ +export const stopModalVideoWithoutClosingPanel = () => (dispatch, getState) => { + const panels = getState().panels.panels; + + // modal PlayerPanel 찾기 + const modalPlayerPanel = panels.find( + (panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal + ); + + if (modalPlayerPanel) { + console.log('[stopModalVideoWithoutClosingPanel] Stopping modal video playback'); + + // 타이머 정리 + if (startVideoFocusTimer) { + clearTimeout(startVideoFocusTimer); + startVideoFocusTimer = null; + } + + // 패널은 유지하되, 비디오 중지 상태로 업데이트 + dispatch( + updatePanel({ + name: panel_names.PLAYER_PANEL, + panelInfo: { + ...modalPlayerPanel.panelInfo, + shouldStop: true, // 비디오 중지 플래그 + isPaused: true, // 일시정지 상태 + isHidden: true, // 화면에서 숨김 + }, + }) + ); + + // Redux 상태도 중지로 업데이트 + dispatch(setVideoStopped()); + } +}; + +/** + * 패널을 닫지 않고 전체화면 비디오만 중지합니다. + */ +export const stopFullscreenVideoWithoutClosingPanel = () => (dispatch, getState) => { + const panels = getState().panels.panels; + + // 전체화면 PlayerPanel 찾기 + const fullscreenPlayerPanel = panels.find( + (panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal + ); + + if (fullscreenPlayerPanel) { + console.log('[stopFullscreenVideoWithoutClosingPanel] Stopping fullscreen video playback'); + + // 타이머 정리 + if (startVideoFocusTimer) { + clearTimeout(startVideoFocusTimer); + startVideoFocusTimer = null; + } + + // 패널은 유지하되, 비디오 중지 상태로 업데이트 + dispatch( + updatePanel({ + name: panel_names.PLAYER_PANEL, + panelInfo: { + ...fullscreenPlayerPanel.panelInfo, + shouldStop: true, // 비디오 중지 플래그 + isPaused: true, + isHidden: true, + }, + }) + ); + + // Redux 상태도 중지로 업데이트 + dispatch(setVideoStopped()); + } +}; + +/** + * 모든 비디오(모달+전체화면)를 패널 닫지 않고 중지합니다. + */ +export const stopAllVideosWithoutClosingPanel = () => (dispatch, getState) => { + const panels = getState().panels.panels; + + // 모든 PlayerPanel 찾기 + const playerPanels = panels.filter((panel) => panel.name === panel_names.PLAYER_PANEL); + + if (playerPanels.length > 0) { + console.log('[stopAllVideosWithoutClosingPanel] Stopping all video playback'); + + // 타이머 정리 + if (startVideoFocusTimer) { + clearTimeout(startVideoFocusTimer); + startVideoFocusTimer = null; + } + + // 모든 PlayerPanel을 중지 상태로 업데이트 + playerPanels.forEach((playerPanel) => { + dispatch( + updatePanel({ + name: panel_names.PLAYER_PANEL, + panelInfo: { + ...playerPanel.panelInfo, + shouldStop: true, + isPaused: true, + isHidden: true, + }, + }) + ); + }); + + // Redux 상태도 중지로 업데이트 + dispatch(setVideoStopped()); + } +}; + // 모달 비디오를 일시정지 (패널은 유지) export const pauseModalVideo = () => (dispatch, getState) => { const panels = getState().panels.panels; @@ -358,7 +475,7 @@ export const resumeFullscreenVideo = () => (dispatch, getState) => { }; // 모달 비디오를 1px로 축소 (배너 정보 저장) -export const shrinkVideoTo1px = () => (dispatch, getState) => { +export const hideModalVideo = () => (dispatch, getState) => { const panels = getState().panels.panels; // modal PlayerPanel 찾기 @@ -389,7 +506,7 @@ export const shrinkVideoTo1px = () => (dispatch, getState) => { }, }; - // console.log('[HomePanel] shrinkVideoTo1px: saving shrinkInfo', { + // console.log('[HomePanel] hideModalVideo: saving shrinkInfo', { // shrinkInfo: updatedPlayerState.shrinkInfo, // modalStyle: panelInfo.modalStyle, // }); @@ -405,7 +522,7 @@ export const shrinkVideoTo1px = () => (dispatch, getState) => { }) ); } else { - console.log('[HomePanel] shrinkVideoTo1px: No modal PlayerPanel found', { + console.log('[HomePanel] hideModalVideo: No modal PlayerPanel found', { panels: panels.map((p) => ({ name: p.name, modal: p.panelInfo?.modal, @@ -416,7 +533,7 @@ export const shrinkVideoTo1px = () => (dispatch, getState) => { }; // 축소된 모달 비디오를 원래 크기로 복구 -export const expandVideoFrom1px = () => (dispatch, getState) => { +export const showModalVideo = () => (dispatch, getState) => { const panels = getState().panels.panels; // 축소된 modal PlayerPanel 찾기 @@ -431,7 +548,7 @@ export const expandVideoFrom1px = () => (dispatch, getState) => { const panelInfo = shrunkModalPlayerPanel.panelInfo; const shrinkInfo = panelInfo.playerState?.shrinkInfo; - // console.log('[HomePanel] expandVideoFrom1px: expanding video', { + // console.log('[HomePanel] showModalVideo: expanding video', { // hasShrinkInfo: !!shrinkInfo, // hasModalStyle: !!shrinkInfo?.modalStyle, // hasModalContainerId: !!shrinkInfo?.modalContainerId, @@ -450,7 +567,7 @@ export const expandVideoFrom1px = () => (dispatch, getState) => { }), }; - // console.log('[HomePanel] expandVideoFrom1px: updated panelInfo shouldShrinkTo1px=false, modalStyle restored, skipModalStyleRecalculation=true'); + // console.log('[HomePanel] showModalVideo: updated panelInfo shouldShrinkTo1px=false, modalStyle restored, skipModalStyleRecalculation=true'); dispatch( updatePanel({ @@ -459,7 +576,7 @@ export const expandVideoFrom1px = () => (dispatch, getState) => { }) ); } else { - console.log('[HomePanel] expandVideoFrom1px: No shrunk modal PlayerPanel found', { + console.log('[HomePanel] showModalVideo: No shrunk modal PlayerPanel found', { panels: panels.map((p) => ({ name: p.name, modal: p.panelInfo?.modal, diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx index bea6cd05..24179d29 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx @@ -28,7 +28,6 @@ import { updatePanel, } from '../../actions/panelActions'; import { - finishVideoPreview, pauseFullscreenVideo, resumeFullscreenVideo, } from '../../actions/playActions'; @@ -170,9 +169,9 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { fp.pipe( () => { dispatch(clearAllToasts()); // BuyOption Toast 포함 모든 토스트 제거 - dispatch(pauseFullscreenVideo()); // PLAYER_PANEL 비디오 중지 + // dispatch(pauseFullscreenVideo()); // PLAYER_PANEL 비디오 중지 dispatch(finishModalMediaForce()); // MEDIA_PANEL(ProductVideo) 강제 종료 - dispatch(finishVideoPreview()); + // ✅ [251118] finishVideoPreview() 제거 - PlayerPanel 유지하기 위함 dispatch(popPanel(panel_names.DETAIL_PANEL)); }, () => { diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx index 1730e736..aeedba62 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx @@ -22,7 +22,7 @@ import { finishVideoPreview, startVideoPlayer, startVideoPlayerNew, - shrinkVideoTo1px, + hideModalVideo, } from '../../../actions/playActions'; import CustomImage from '../../../components/CustomImage/CustomImage'; import usePriceInfo from '../../../hooks/usePriceInfo'; @@ -324,7 +324,7 @@ export default function RandomUnit({ videoPlayerable, currentVideoBannerId, }); - dispatch(shrinkVideoTo1px()); + dispatch(hideModalVideo()); } if (handleItemFocus) { @@ -346,7 +346,7 @@ export default function RandomUnit({ // 현재 비디오가 재생 중이면 1px로 축소 (주석: HomePanel 스크롤로 처리) // if (currentVideoBannerId && videoPlayerable) { // console.log('[RandomUnit] onBlur: shrinking video to 1px'); - // dispatch(shrinkVideoTo1px()); + // dispatch(hideModalVideo()); // } // dispatch(finishVideoPreview()); diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx index be432816..e1baa11c 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx @@ -29,9 +29,9 @@ import { getSubCategory, getTop20Show } from '../../actions/mainActions'; import { getHomeOnSaleInfo } from '../../actions/onSaleActions'; import { updatePanel } from '../../actions/panelActions'; import { - expandVideoFrom1px, + showModalVideo, finishVideoPreview, - shrinkVideoTo1px, + hideModalVideo, startVideoPlayerNew, } from '../../actions/playActions'; import { getBestSeller } from '../../actions/productActions'; @@ -497,7 +497,7 @@ const HomePanel = ({ isOnTop }) => { } // console.log('[HomePanel] Expansion attempt', expandAttemptRef.current + 1); - dispatch(expandVideoFrom1px()); + dispatch(showModalVideo()); expandAttemptRef.current++; }, 200); } @@ -514,7 +514,7 @@ const HomePanel = ({ isOnTop }) => { // 아래로 스크롤: 비디오를 1px로 축소 // console.log('[HomePanel] Scrolling down - shrinking video'); if (!isVideoTransitionLocked) { - dispatch(shrinkVideoTo1px()); + dispatch(hideModalVideo()); } // 기존 타이머 취소 if (scrollExpandTimerRef.current) { @@ -533,7 +533,7 @@ const HomePanel = ({ isOnTop }) => { // 1초 후 자동으로 크기 조정 scrollExpandTimerRef.current = setTimeout(() => { // console.log('[HomePanel] 1s passed - auto expanding video'); - dispatch(expandVideoFrom1px()); + dispatch(showModalVideo()); scrollExpandTimerRef.current = null; }, 1000); } @@ -705,6 +705,22 @@ const HomePanel = ({ isOnTop }) => { panels.map((p) => ({ name: p.name, modal: p.panelInfo?.modal })) ); + // ✅ [251118] 현재 재생 중인 비디오 정보 상세 로그 + const playerPanel = panels.find((p) => p.name === panel_names.PLAYER_PANEL); + if (playerPanel) { + console.log('[HomeActive] 🎬 PlayerPanel 정보:', { + modal: playerPanel.panelInfo?.modal, + shouldShrinkTo1px: playerPanel.panelInfo?.shouldShrinkTo1px, + currentBannerId: playerPanel.panelInfo?.playerState?.currentBannerId, + bannerId: playerPanel.panelInfo?.bannerId, + showUrl: playerPanel.panelInfo?.showUrl?.substring(0, 50), + patnrId: playerPanel.panelInfo?.patnrId, + showId: playerPanel.panelInfo?.showId, + }); + } else { + console.log('[HomeActive] ❌ PlayerPanel을 찾을 수 없음'); + } + const isHomePanelActive = isOnTop; console.log('[HomeActive] isHomePanelActive:', isHomePanelActive); @@ -756,7 +772,7 @@ const HomePanel = ({ isOnTop }) => { // 재생 기록 업데이트 lastPlayedBannerIdRef.current = bannerId; console.log('[HomeActive] 재생 기록 업데이트:', bannerId); - }, [isOnTop, dispatch]); + }, [isOnTop, dispatch, panels]); // ✅ [251118] DetailPanel 닫힘 감지 useEffect const detailPanelClosedTime = useSelector( @@ -770,8 +786,99 @@ const HomePanel = ({ isOnTop }) => { console.log('[HomePanel] isOnTop:', isOnTop); console.log('[HomePanel] videoPlayIntentRef.current:', videoPlayIntentRef.current); console.log('[HomePanel] lastPlayedBannerIdRef.current:', lastPlayedBannerIdRef.current); + + // ✅ [핵심] videoPlayIntentRef.current.videoProps가 있으면 비디오 재생 + if (videoPlayIntentRef.current?.videoProps) { + const videoProps = videoPlayIntentRef.current.videoProps; + const bannerId = videoPlayIntentRef.current.bannerId; + + console.log('[HomePanel] 비디오 재생 정보 있음:', { + bannerId, + showUrl: videoProps.showUrl, + patnrId: videoProps.patnrId, + showId: videoProps.showId, + }); + + // ✅ 중복 체크 우회를 위해 ref 초기화 + lastPlayedBannerIdRef.current = null; + + // ✅ scrollTop 상태 확인 (0이면 normal, 아니면 1px로 축소) + const currentScrollTop = prevScrollTopRef.current; + console.log('[HomePanel] 현재 scrollTop:', currentScrollTop); + + // modalContainerId 변경으로 중복 체크 우회 + const modifiedVideoProps = { + ...videoProps, + modalContainerId: 'banner-modal-' + bannerId, + }; + + console.log('[HomePanel] dispatch(startVideoPlayerNew) 호출:', modifiedVideoProps); + dispatch(startVideoPlayerNew(modifiedVideoProps)); + } else { + console.log('[HomePanel] ❌ videoProps가 없어서 비디오 재생 불가'); + } } - }, [detailPanelClosedTime, isOnTop]); + }, [detailPanelClosedTime, isOnTop, dispatch]); + + // ✅ [251118] DetailPanel 복귀 후 비디오 크기 자동 조정 + useEffect(() => { + // ✅ [251118] videoProps가 없으면 PlayerPanel에서 직접 읽기 + const hasVideoInfo = videoPlayIntentRef.current?.videoProps || + (panels.find((p) => p.name === panel_names.PLAYER_PANEL)?.panelInfo?.modal); + + if (detailPanelClosedTime && isOnTop && hasVideoInfo) { + console.log('[HomePanel] 비디오 크기 조정 타이머 시작...'); + console.log('[HomePanel] videoProps 여부:', !!videoPlayIntentRef.current?.videoProps); + + // 약간의 지연 후 비디오 상태 확인 (재생이 완료된 후) + const timer = setTimeout(() => { + const currentScrollTop = prevScrollTopRef.current; + const playerPanelInfo = panels.find((p) => p.name === panel_names.PLAYER_PANEL); + const shouldShrink = playerPanelInfo?.panelInfo?.shouldShrinkTo1px; + + // ✅ [251118] 더 자세한 로그 추가 + console.log('[HomePanel] 비디오 크기 조정 체크:', { + currentScrollTop, + shouldShrink, + bannerId: videoPlayIntentRef.current?.bannerId, + playerPanelExists: !!playerPanelInfo, + }); + + console.log('[HomePanel] 📊 PlayerPanel 전체 정보:', { + hasPlayerPanel: !!playerPanelInfo, + modal: playerPanelInfo?.panelInfo?.modal, + shouldShrinkTo1px: playerPanelInfo?.panelInfo?.shouldShrinkTo1px, + currentBannerId: playerPanelInfo?.panelInfo?.playerState?.currentBannerId, + panelName: playerPanelInfo?.name, + }); + + console.log('[HomePanel] 📍 Ref 정보:', { + prevScrollTopRef: prevScrollTopRef.current, + shouldShrinkRef: shouldShrinkRef.current, + videoPlayIntentRef: videoPlayIntentRef.current?.bannerId, + }); + + if (currentScrollTop <= 1 && shouldShrink) { + // scrollTop = 0이고 현재 1px 상태면 → 확대 + console.log('[HomePanel] ▲ 비디오 확대 (scrollTop <= 1 && shouldShrink)'); + dispatch(showModalVideo()); + } else if (currentScrollTop > 1 && !shouldShrink) { + // scrollTop > 0이고 normal size면 → 축소 + console.log('[HomePanel] ▼ 비디오 축소 (scrollTop > 1 && !shouldShrink)'); + dispatch(hideModalVideo()); + } else { + console.log('[HomePanel] ⚠️ 비디오 크기 조정 불필요', { + reason: currentScrollTop <= 1 && !shouldShrink ? 'scrollTop 최상단이고 이미 normal size' : + currentScrollTop > 1 && shouldShrink ? 'scrollTop > 1이고 이미 1px 상태' : '기타', + condition1: `currentScrollTop <= 1: ${currentScrollTop <= 1}`, + condition2: `shouldShrink: ${shouldShrink}`, + }); + } + }, 500); // 비디오 재생 완료 대기 + + return () => clearTimeout(timer); + } + }, [detailPanelClosedTime, isOnTop, dispatch, panels]); useEffect(() => { return () => {