From a18c61380c26998cfc4c260035804278416e8ba0 Mon Sep 17 00:00:00 2001 From: optrader Date: Sun, 16 Nov 2025 21:32:12 +0900 Subject: [PATCH] [251116] feat: PlayerPanel FullScreen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 11. 16. 21:32:12 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 5๊ฐœ โ€ข ์ถ”๊ฐ€: +81์ค„ โ€ข ์‚ญ์ œ: -20์ค„ ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/actions/playActions.js ~ com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js ~ com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js ~ com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx ~ com.twin.app.shoptime/src/views/MainView/MainView.jsx ๐Ÿ”ง ํ•จ์ˆ˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ: ๐Ÿ“„ com.twin.app.shoptime/src/actions/playActions.js (javascript): ๐Ÿ”„ Modified: resumeFullscreenVideo() ๐Ÿ”ง ์ฃผ์š” ๋ณ€๊ฒฝ ๋‚ด์šฉ: โ€ข ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฐœ์„  --- .../src/actions/playActions.js | 31 +++- .../src/hooks/useVideoPlay/useVideoPlay.js | 11 +- .../src/middleware/panelHistoryMiddleware.js | 164 +++++++++++++----- .../src/views/HomePanel/HomePanel.jsx | 29 ++++ .../src/views/MainView/MainView.jsx | 19 +- 5 files changed, 197 insertions(+), 57 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/playActions.js b/com.twin.app.shoptime/src/actions/playActions.js index fecf1154..fef433c7 100644 --- a/com.twin.app.shoptime/src/actions/playActions.js +++ b/com.twin.app.shoptime/src/actions/playActions.js @@ -161,11 +161,18 @@ export const startVideoPlayerNew = panelWorkingAction = updatePanel; } - // ์ค‘๋ณต ์‹คํ–‰ ๋ฐฉ์ง€: ํ˜„์žฌ PlayerPanel์ด ๊ฐ™์€ ๋ฐฐ๋„ˆ๋ฅผ ์žฌ์ƒ ์ค‘์ด๋ฉด skip - const currentPlayerState = topPanel?.panelInfo?.playerState || {}; - if (currentPlayerState?.currentBannerId === bannerId) { - console.log('[playActions] startVideoPlayerNew: ๋™์ผ ๋ฐฐ๋„ˆ ์žฌ์ƒ ์ค‘์ด๋ผ ์ค‘๋ณต ์‹คํ–‰ SKIP', { + // ์ค‘๋ณต ์‹คํ–‰ ๋ฐฉ์ง€: ๊ฐ™์€ ๋ฐฐ๋„ˆ + ๊ฐ™์€ modal ์ƒํƒœ/์ปจํ…Œ์ด๋„ˆ๋ฉด skip + const currentPanelInfo = topPanel?.panelInfo || {}; + const currentPlayerState = currentPanelInfo.playerState || {}; + const isSameBanner = currentPlayerState.currentBannerId === bannerId; + const isSameModalType = currentPanelInfo.modal === modal; + const isSameContainer = currentPanelInfo.modalContainerId === modalContainerId; + + if (isSameBanner && isSameModalType && isSameContainer) { + console.log('[playActions] startVideoPlayerNew: ๋™์ผํ•œ ์š”์ฒญ์ด๋ฏ€๋กœ ์Šคํ‚ต', { bannerId, + modal, + modalContainerId, }); return; } @@ -397,7 +404,13 @@ export const shrinkVideoTo1px = () => (dispatch, getState) => { }) ); } else { - console.log('[HomePanel] shrinkVideoTo1px: No modal PlayerPanel found'); + console.log('[HomePanel] shrinkVideoTo1px: No modal PlayerPanel found', { + panels: panels.map((p) => ({ + name: p.name, + modal: p.panelInfo?.modal, + shouldShrinkTo1px: p.panelInfo?.shouldShrinkTo1px, + })), + }); } }; @@ -445,7 +458,13 @@ export const expandVideoFrom1px = () => (dispatch, getState) => { }) ); } else { - console.log('[HomePanel] expandVideoFrom1px: No shrunk modal PlayerPanel found'); + console.log('[HomePanel] expandVideoFrom1px: No shrunk modal PlayerPanel found', { + panels: panels.map((p) => ({ + name: p.name, + modal: p.panelInfo?.modal, + shouldShrinkTo1px: p.panelInfo?.shouldShrinkTo1px, + })), + }); } }; diff --git a/com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js b/com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js index 0a235f91..7157402b 100644 --- a/com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js +++ b/com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js @@ -3,7 +3,7 @@ import { useCallback, useRef, useState, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { - startBannerVideo, + startVideoPlayerNew, stopBannerVideo, stopAndHideVideo, hidePlayerVideo, @@ -143,7 +143,14 @@ export const useVideoPlay = (options = {}) => { videoState.setCurrentPlaying(bannerId); // Redux ์•ก์…˜ dispatch - bannerId๋ฅผ modalContainerId๋กœ ์‚ฌ์šฉ - dispatch(startBannerVideo(bannerId, { modalContainerId: bannerId, force })); + dispatch( + startVideoPlayerNew({ + bannerId, + modal: true, + modalContainerId: bannerId, + force, + }) + ); // ์„ฑ๊ณต ์ƒํƒœ ์—…๋ฐ์ดํŠธ setErrorCount(0); // ์„ฑ๊ณต ์‹œ ์˜ค๋ฅ˜ ์นด์šดํŠธ ์ดˆ๊ธฐํ™” diff --git a/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js b/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js index 0e0b261b..81ca099f 100644 --- a/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js +++ b/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js @@ -22,10 +22,11 @@ const DEBUG_MODE = true; */ export const panelHistoryMiddleware = (store) => (next) => (action) => { // ๋ชจ๋“  PANEL ๊ด€๋ จ ์•ก์…˜ ๋กœ๊น… - if (DEBUG_MODE && action.type && ( - action.type.includes('PANEL') || - action.type === 'CLEAR_PANEL_HISTORY' - )) { + if ( + DEBUG_MODE && + action.type && + (action.type.includes('PANEL') || action.type === 'CLEAR_PANEL_HISTORY') + ) { const caller = new Error().stack.split('\n')[1]?.trim(); console.log(`[PANEL DEBUG] ${action.type} from: ${caller}`); console.log(' Payload:', action.payload); @@ -38,8 +39,7 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { const stackLines = stack.split('\n'); for (const line of stackLines) { - if (line.includes('TabLayout.jsx') || - line.includes('TIconButton.jsx')) { + if (line.includes('TabLayout.jsx') || line.includes('TIconButton.jsx')) { return true; } } @@ -75,15 +75,36 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { if (panelName) { const isGNB = isGNBCall(); const isOnTop = calculateIsOnTop(panelName); // ๐ŸŽฏ isOnTop ๊ณ„์‚ฐ - if (DEBUG_MODE) console.log('[PANEL] PUSH_PANEL:', { panelName, panelInfo, isGNB, isOnTop, timestamp: new Date().toISOString() }); - store.dispatch(enqueuePanelHistory(panelName, panelInfo, 'PUSH', new Date().toISOString(), isGNB, false, isOnTop)); + if (DEBUG_MODE) + console.log('[PANEL] PUSH_PANEL:', { + panelName, + panelInfo, + isGNB, + isOnTop, + timestamp: new Date().toISOString(), + }); + store.dispatch( + enqueuePanelHistory( + panelName, + panelInfo, + 'PUSH', + new Date().toISOString(), + isGNB, + false, + isOnTop + ) + ); // PanelHistory ์ƒํƒœ ๋กœ๊ทธ (state ์—…๋ฐ์ดํŠธ ํ›„) const logPanelHistoryAfter = () => { if (DEBUG_MODE) { const stateAfter = store.getState(); const panelHistoryAfter = stateAfter.panelHistory; - console.log('[PANEL_HISTORY] After PUSH_PANEL:', panelHistoryAfter); + const panelsAfter = stateAfter.panels.panels; + console.log('[PANEL_HISTORY] After PUSH_PANEL:', { + panelHistory: panelHistoryAfter, + panels: panelsAfter, + }); } }; @@ -102,15 +123,36 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { if (topPanel && topPanel.name) { const isGNB = isGNBCall(); const isOnTop = calculateIsOnTop(topPanel.name); // ๐ŸŽฏ isOnTop ๊ณ„์‚ฐ - if (DEBUG_MODE) console.log('[PANEL] POP_PANEL:', { panelName: topPanel.name, panelInfo: topPanel.panelInfo || {}, isGNB, isOnTop, timestamp: new Date().toISOString() }); - store.dispatch(enqueuePanelHistory(topPanel.name, topPanel.panelInfo || {}, 'POP', new Date().toISOString(), isGNB, false, isOnTop)); + if (DEBUG_MODE) + console.log('[PANEL] POP_PANEL:', { + panelName: topPanel.name, + panelInfo: topPanel.panelInfo || {}, + isGNB, + isOnTop, + timestamp: new Date().toISOString(), + }); + store.dispatch( + enqueuePanelHistory( + topPanel.name, + topPanel.panelInfo || {}, + 'POP', + new Date().toISOString(), + isGNB, + false, + isOnTop + ) + ); // PanelHistory ์ƒํƒœ ๋กœ๊ทธ (state ์—…๋ฐ์ดํŠธ ํ›„) const logPanelHistoryAfter = () => { if (DEBUG_MODE) { const stateAfter = store.getState(); const panelHistoryAfter = stateAfter.panelHistory; - console.log('[PANEL_HISTORY] After POP_PANEL:', panelHistoryAfter); + const panelsAfter = stateAfter.panels.panels; + console.log('[PANEL_HISTORY] After POP_PANEL:', { + panelHistory: panelHistoryAfter, + panels: panelsAfter, + }); } }; @@ -129,15 +171,36 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { if (panelName) { const isGNB = isGNBCall(); const isOnTop = calculateIsOnTop(panelName); // ๐ŸŽฏ isOnTop ๊ณ„์‚ฐ - if (DEBUG_MODE) console.log('[PANEL] UPDATE_PANEL:', { panelName, panelInfo, isGNB, isOnTop, timestamp: new Date().toISOString() }); - store.dispatch(enqueuePanelHistory(panelName, panelInfo, 'UPDATE', new Date().toISOString(), isGNB, false, isOnTop)); + if (DEBUG_MODE) + console.log('[PANEL] UPDATE_PANEL:', { + panelName, + panelInfo, + isGNB, + isOnTop, + timestamp: new Date().toISOString(), + }); + store.dispatch( + enqueuePanelHistory( + panelName, + panelInfo, + 'UPDATE', + new Date().toISOString(), + isGNB, + false, + isOnTop + ) + ); // PanelHistory ์ƒํƒœ ๋กœ๊ทธ (state ์—…๋ฐ์ดํŠธ ํ›„) const logPanelHistoryAfter = () => { if (DEBUG_MODE) { const stateAfter = store.getState(); const panelHistoryAfter = stateAfter.panelHistory; - console.log('[PANEL_HISTORY] After UPDATE_PANEL:', panelHistoryAfter); + const panelsAfter = stateAfter.panels.panels; + console.log('[PANEL_HISTORY] After UPDATE_PANEL:', { + panelHistory: panelHistoryAfter, + panels: panelsAfter, + }); } }; @@ -150,11 +213,13 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { // RESET_PANELS: GNB ๋„ค๋น„๊ฒŒ์ด์…˜ ๋˜๋Š” ์™„์ „ ์ดˆ๊ธฐํ™” case types.RESET_PANELS: { - if (DEBUG_MODE) console.log('[PANEL] RESET_PANELS:', { - payload: action.payload, - timestamp: new Date().toISOString() - }); - if (DEBUG_MODE) console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory); + if (DEBUG_MODE) + console.log('[PANEL] RESET_PANELS:', { + payload: action.payload, + timestamp: new Date().toISOString(), + }); + if (DEBUG_MODE) + console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory); // ๋ชจ๋“  RESET_PANELS๋ฅผ ๊ธฐ๋ก const isGNB = isGNBCall(); @@ -164,35 +229,48 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { const firstPanel = action.payload[0]; if (firstPanel && firstPanel.name) { const isOnTop = calculateIsOnTop(firstPanel.name); // ๐ŸŽฏ isOnTop ๊ณ„์‚ฐ - if (DEBUG_MODE) console.log('[PANEL_DEBUG] RESET_PANELS to:', firstPanel.name, { isGNB, isOnTop, fromResetPanel: true }); + if (DEBUG_MODE) + console.log('[PANEL_DEBUG] RESET_PANELS to:', firstPanel.name, { + isGNB, + isOnTop, + fromResetPanel: true, + }); // RESET ์ด๋™์„ ํžˆ์Šคํ† ๋ฆฌ์— ๊ธฐ๋ก - store.dispatch(enqueuePanelHistory( - firstPanel.name, - firstPanel.panelInfo || {}, - 'RESET', - new Date().toISOString(), - isGNB, // TabLayout/TIconButton์ด๋ฉด true - true, // fromResetPanel: ํ•ญ์ƒ true - isOnTop // ๐ŸŽฏ isOnTop ์ •๋ณด ์ถ”๊ฐ€ - )); + store.dispatch( + enqueuePanelHistory( + firstPanel.name, + firstPanel.panelInfo || {}, + 'RESET', + new Date().toISOString(), + isGNB, // TabLayout/TIconButton์ด๋ฉด true + true, // fromResetPanel: ํ•ญ์ƒ true + isOnTop // ๐ŸŽฏ isOnTop ์ •๋ณด ์ถ”๊ฐ€ + ) + ); } } else { // ์™„์ „ ์ดˆ๊ธฐํ™” (payload๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ - HomePanel, ์•ฑ ์ดˆ๊ธฐํ™” ๋“ฑ) - if (DEBUG_MODE) console.log('[PANEL_DEBUG] Complete panel history reset (payload empty)', { isGNB, fromResetPanel: true }); + if (DEBUG_MODE) + console.log('[PANEL_DEBUG] Complete panel history reset (payload empty)', { + isGNB, + fromResetPanel: true, + }); store.dispatch(clearPanelHistory()); // HomePanel ์ดˆ๊ธฐํ™” ๊ธฐ๋ก (์•ฑ ์‹œ์ž‘ ์‹œ) if (DEBUG_MODE) console.log('[PANEL_DEBUG] Recording initial HomePanel'); const isOnTop = calculateIsOnTop('homepanel'); // ๐ŸŽฏ isOnTop ๊ณ„์‚ฐ - store.dispatch(enqueuePanelHistory( - 'homepanel', - {}, - 'APP_INITIALIZE', - new Date().toISOString(), - isGNB, // TIconButton Home ๋ฒ„ํŠผ์ด๋ฉด true - true, // fromResetPanel: true - isOnTop // ๐ŸŽฏ isOnTop ์ •๋ณด ์ถ”๊ฐ€ - )); + store.dispatch( + enqueuePanelHistory( + 'homepanel', + {}, + 'APP_INITIALIZE', + new Date().toISOString(), + isGNB, // TIconButton Home ๋ฒ„ํŠผ์ด๋ฉด true + true, // fromResetPanel: true + isOnTop // ๐ŸŽฏ isOnTop ์ •๋ณด ์ถ”๊ฐ€ + ) + ); } // PanelHistory ์ƒํƒœ ๋กœ๊ทธ (์ดˆ๊ธฐํ™” ํ›„) @@ -200,7 +278,11 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { if (DEBUG_MODE) { const stateAfter = store.getState(); const panelHistoryAfter = stateAfter.panelHistory; - console.log('[PANEL_HISTORY] After RESET_PANELS:', panelHistoryAfter); + const panelsAfter = stateAfter.panels.panels; + console.log('[PANEL_HISTORY] After RESET_PANELS:', { + panelHistory: panelHistoryAfter, + panels: panelsAfter, + }); } }; diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx index f03becbc..5870f1be 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx @@ -599,6 +599,13 @@ const HomePanel = ({ isOnTop }) => { if (isInitialRender.current) { isInitialRender.current = false; + // โœ… ๋งˆ์šดํŠธ ์‹œ banner0 ์ž๋™ ์žฌ์ƒ ์„ค์ • + console.log('[HomePanel] ๋งˆ์šดํŠธ - banner0 ์žฌ์ƒ ์‹œ๋„', videoPlay); + videoPlayIntentRef.current = { bannerId: 'banner0' }; + console.log('[HomePanel] videoPlayIntentRef ์„ค์ •:', videoPlayIntentRef.current); + videoPlay.playVideo('banner0', { reason: 'mount-init' }); + console.log('[HomePanel] playVideo ํ˜ธ์ถœ ์™„๋ฃŒ'); + if (isDeepLink || (!panels.length && !panelInfo.focusedContainerId)) { dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } })); dispatch(getHomeMainContents()); @@ -684,6 +691,28 @@ const HomePanel = ({ isOnTop }) => { } }, [isOnTop]); + // โœ… HomePanel ํ™œ์„ฑํ™” ์กฐ๊ฑด: ์ตœ์ƒ๋‹จ ํŒจ๋„ ๋˜๋Š” PlayerPanel ์•„๋ž˜์˜ ๋‘ ๋ฒˆ์งธ ํŒจ๋„ + // ๋น„๋””์˜ค๊ฐ€ ์žฌ์ƒ์ด ์•„๋‹ˆ๋ฉด videoPlayIntentRef์˜ bannerId๋กœ ๋น„๋””์˜ค ์žฌ์ƒ + useEffect(() => { + const isHomePanelActive = + panels[0]?.name === panel_names.HOME_PANEL || + (panels.length >= 2 && + panels[0]?.name === panel_names.PLAYER_PANEL && + panels[1]?.name === panel_names.HOME_PANEL); + + if (isHomePanelActive && videoPlayIntentRef.current?.bannerId) { + const bannerId = videoPlayIntentRef.current.bannerId; + const currentPlaying = videoPlay.getCurrentPlayingBanner(); + + // ์ด๋ฏธ ์žฌ์ƒ ์ค‘์ธ ๋ฐฐ๋„ˆ๊ฐ€ ๋‹ค๋ฅด๋ฉด ์ƒˆ๋กœ ์žฌ์ƒ + if (currentPlaying !== bannerId) { + videoPlay.playVideo(bannerId, { + reason: 'homePanel-active', + }); + } + } + }, [panels]); + useEffect(() => { return () => { const c = Spotlight.getCurrent(); diff --git a/com.twin.app.shoptime/src/views/MainView/MainView.jsx b/com.twin.app.shoptime/src/views/MainView/MainView.jsx index fae595f7..1a34875a 100644 --- a/com.twin.app.shoptime/src/views/MainView/MainView.jsx +++ b/com.twin.app.shoptime/src/views/MainView/MainView.jsx @@ -6,11 +6,10 @@ import { useDispatch, useSelector } from 'react-redux'; import platform from '@enact/core/platform'; import Spotlight from '@enact/spotlight'; - import defaultWatchItem from '../../../assets/images/img-alert-banner-st@3x.png'; // ํ…Œ์ŠคํŠธ์šฉ - TODO: ๋ฉ”์ธ ํ™ˆ ํ™”๋ฉด์— ๋‚˜์™€์•ผ ํ•˜๋Š” ์ด๋ฏธ์ง€๋“ค ์ถ”๊ฐ€ ํ›„ preloadImages์— ์ถ”๊ฐ€ -import testImage from '../../../assets/images/img-banner-myinfo-login@3x.png'; -import defaultImageItem from '../../../assets/images/img-thumb-empty-product@3x.png'; +// import testImage from '../../../assets/images/img-banner-myinfo-login@3x.png'; +// import defaultImageItem from '../../../assets/images/img-thumb-empty-product@3x.png'; import LoadingPreloadImage from '../../../assets/images/intro/splash_02_stop.webp'; import LoadingAnimation from '../../../assets/images/intro/splash_03_end.webp'; import LoadingCompleteImage from '../../../assets/images/intro/splash_04_end.webp'; @@ -80,7 +79,7 @@ import WelcomeEventPanel from '../WelcomeEventPanel/WelcomeEventPanel'; import css from './MainView.module.less'; // DEBUG_MODE ์ƒ์ˆ˜ - true์ผ ๋•Œ๋งŒ console.log ์ถœ๋ ฅ -const DEBUG_MODE = false; +const DEBUG_MODE = true; const preloadImages = [ LoadingPreloadImage, @@ -209,11 +208,14 @@ export default function MainView({ className, initService }) { // ๋‹จ๋… ํŒจ๋„ ์ฒดํฌ - CheckOutPanel, CartPanel ๋“ฑ ๋‹จ๋…์œผ๋กœ ๋ Œ๋”๋ง๋˜์–ด์•ผ ํ•˜๋Š” ํŒจ๋„๋“ค if (DEBUG_MODE) { - console.log(`[MainView] ๐Ÿ” Top panel name: ${topPanel?.name}`); - console.log(`[MainView] ๐Ÿ” isStandalonePanel check:`, isStandalonePanel(topPanel?.name)); - console.log(`[MainView] ๐Ÿ” STANDALONE_PANELS:`, STANDALONE_PANELS); + console.log(`[PANEL_MainView] ๐Ÿ” Top panel name: ${topPanel?.name}`); console.log( - `[MainView] ๐Ÿ” All panels:`, + `[PANEL_MainView] ๐Ÿ” isStandalonePanel check:`, + isStandalonePanel(topPanel?.name) + ); + console.log(`[PANEL_MainView] ๐Ÿ” STANDALONE_PANELS:`, STANDALONE_PANELS); + console.log( + `[PANEL_MainView] ๐Ÿ” All panels:`, panels.map((p) => ({ name: p.name, hasModal: !!p.panelInfo?.modal })) ); } @@ -258,6 +260,7 @@ export default function MainView({ className, initService }) { renderingPanels = panels.slice(-1); } } + return ( <> {(isHomeOnTop ||