diff --git a/com.twin.app.shoptime/src/actions/mediaActions.js b/com.twin.app.shoptime/src/actions/mediaActions.js index 9e50c714..ad053994 100644 --- a/com.twin.app.shoptime/src/actions/mediaActions.js +++ b/com.twin.app.shoptime/src/actions/mediaActions.js @@ -284,6 +284,14 @@ export const minimizeModalMedia = () => (dispatch, getState) => { export const restoreModalMedia = () => (dispatch, getState) => { const panels = getState().panels.panels; + if (typeof window !== 'undefined' && window.detailPanelScrollTop !== 0) { + console.log( + '[restoreModalMedia] Blocked restore because detail panel scroll not zero:', + window.detailPanelScrollTop + ); + return; + } + // console.log('[Restore]] ========== Called =========='); // console.log('[Restore] Total panels:', panels.length); // console.log( diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.module.less b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.module.less index 57000fb7..d3c91ed5 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.module.less +++ b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.module.less @@ -1,17 +1,19 @@ // VideoPlayer.module.less // -@import "~@enact/sandstone/styles/variables.less"; +@import "~@enact/sandstone/styles/variables.less"; @import "~@enact/sandstone/styles/mixins.less"; @import "~@enact/sandstone/styles/skin.less"; @import "../../style/utils.module.less"; @import "../../style/CommonStyle.module.less"; -.videoPlayer { - // Set by counting the IconButtons inside the side components. - --liftDistance: 0px; - - overflow: hidden; - padding: 2px; - box-sizing: border-box; +.fullscreen .videoPlayer, +.videoPlayer { + // Set by counting the IconButtons inside the side components. + --liftDistance: 0px; + + overflow: hidden; + padding: 2px; + margin: 0; + box-sizing: border-box; :focus { outline: none !important; @@ -19,34 +21,51 @@ box-shadow: none !important; } - .video { - height: calc(100% - 4px); - width: calc(100% - 4px); - background: #000; - } + &.fullscreen { + width: 100%; + height: 100%; + } + + .video { + height: 100%; + width: 100%; + background: #000; + max-width: none; + max-height: none; + } - .media { - height: var(--media-height, calc(100% - 4px)); - width: var(--media-width, calc(100% - 4px)); - background: #000; - - &.mediaBackground { - &:after { - width: 560px; - height: 200px; - position: absolute; - left: 0; - bottom: 0; - content: ""; - background: linear-gradient( - to top, - rgba(255, 255, 255, 1), - transparent - ); - opacity: 0.2; - } - } - } + .media { + height: var(--media-height, calc(100% - 4px)); + width: var(--media-width, calc(100% - 4px)); + background: #000; + + &.mediaBackground { + &:after { + width: 560px; + height: 200px; + position: absolute; + left: 0; + bottom: 0; + content: ""; + background: linear-gradient( + to top, + rgba(255, 255, 255, 1), + transparent + ); + opacity: 0.2; + } + } + } + + &.fullscreen { + --media-width: 100vw; + --media-height: 100vh; + } + + .fullscreen .videoPlayer .media { + --media-width: 100vw; + --media-height: 100vh; + } .preloadVideo { display: none; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx index 75c5646c..ee18f332 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx @@ -537,6 +537,29 @@ export default function ProductAllSection({ }, []); const scrollContainerRef = useRef(null); + useEffect(() => { + if (typeof window !== 'undefined') { + window.detailPanelScrollTop = 0; + } + }, []); + useEffect(() => { + const handleScrollReset = () => { + const container = scrollContainerRef.current; + if (!container) return; + if (typeof container.scrollTo === 'function') { + container.scrollTo({ top: 0, behavior: 'auto' }); + } else if (typeof container.scrollTop === 'number') { + container.scrollTop = 0; + } + }; + + if (typeof document === 'undefined') return () => {}; + + document.addEventListener('detailpanel-scroll-reset', handleScrollReset); + return () => { + document.removeEventListener('detailpanel-scroll-reset', handleScrollReset); + }; + }, []); const productDetailRef = useRef(null); //높이값 변경때문 const descriptionRef = useRef(null); const reviewRef = useRef(null); @@ -666,6 +689,9 @@ export default function ProductAllSection({ const handleScroll = useCallback( (e) => { const currentScrollTop = e.scrollTop; + if (typeof window !== 'undefined') { + window.detailPanelScrollTop = Math.max(0, currentScrollTop); + } const prevScrollTop = prevScrollTopRef.current; scrollPositionRef.current = currentScrollTop; 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 1ae72ccc..60718922 100644 --- a/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx +++ b/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx @@ -913,6 +913,7 @@ const MediaPanel = React.forwardRef( if (!panelInfo.modal) { dispatch(PanelActions.popPanel()); dispatch(changeAppStatus({ cursorVisible: false })); + document?.dispatchEvent?.(new CustomEvent('detailpanel-scroll-reset')); //딮링크로 플레이어 진입 후 이전버튼 클릭시 if (panels.length === 1) { @@ -1120,9 +1121,34 @@ const MediaPanel = React.forwardRef( dispatch(minimizeModalMedia()); }, [dispatch]); + const requestDetailScrollReset = useCallback(() => { + if (typeof document !== 'undefined') { + document.dispatchEvent(new CustomEvent('detailpanel-scroll-reset')); + } + }, []); + + const canRestoreFromDetailPanel = useCallback(() => { + if (typeof window === 'undefined') return true; + return window.detailPanelScrollTop === 0; + }, []); + + const restoreWhenScrollZero = useCallback(() => { + let attempts = 0; + const attemptRestore = () => { + if (canRestoreFromDetailPanel()) { + dispatch(restoreModalMedia()); + } else if (attempts < 5) { + attempts += 1; + requestDetailScrollReset(); + setTimeout(attemptRestore, 50); + } + }; + attemptRestore(); + }, [canRestoreFromDetailPanel, dispatch, requestDetailScrollReset]); + const restoreViaRef = useCallback(() => { - dispatch(restoreModalMedia()); - }, [dispatch]); + restoreWhenScrollZero(); + }, [restoreWhenScrollZero]); useImperativeHandle( ref, @@ -1641,7 +1667,9 @@ const MediaPanel = React.forwardRef( setModalStyle({}); setModalScale(1); } else if (isOnTop && !panelInfo.modal && videoPlayer.current) { - console.log('[MediaPanel] Condition 3: Playing fullscreen video'); + console.log( + '[MediaPanel] Condition 3: Playing fullscreen video - enforcing 1920x1080 rendering' + ); if (videoPlayer.current?.getMediaState()?.paused) { videoPlayer.current.play(); } @@ -1652,6 +1680,14 @@ const MediaPanel = React.forwardRef( } }, [panelInfo, isOnTop, dispatch]); + useEffect(() => { + if (!panelInfo.modal) { + console.log('[MediaPanel] modal=false - resetting inline styles for fullscreen'); + setModalStyle({}); + setModalScale(1); + } + }, [panelInfo.modal]); + const smallestOffsetHourIndex = useMemo(() => { if (shopNowInfo) { const filteredVideos = shopNowInfo.filter((video) => video.offsetHour >= currentTime); @@ -2184,6 +2220,7 @@ const MediaPanel = React.forwardRef( const containerClassName = classNames( css.videoContainer, panelInfo.modal && css.modal, + !panelInfo.modal && css.fullscreen, panelInfo.shouldShrinkTo1px && css.shrinkTo1px, // MediaPanel이 최상단 아니고, 최상단이 DetailPanel(from Player)이면 비디오 보이도록 !isOnTop && isTopPanelDetailFromPlayer && css['background-visible'], @@ -2192,12 +2229,23 @@ const MediaPanel = React.forwardRef( !captionEnable && css.hideSubtitle ); + const panelStyleOverride = !panelInfo.modal + ? { + width: '100vw', + height: '100vh', + top: 0, + left: 0, + position: 'fixed', + } + : undefined; + return ( {partnerName} - - {showName} - + {!panelInfo?.modal && ( + + {showName} + + )} {type === 'VOD' && disclaimer && (