diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index 8d80a0a1..7de705f2 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -1248,12 +1248,12 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props return () => { // 패널이 2개 존재할때만 popPanel 진행 // 현재 스택의 top이 PlayerPanel일 때만 pop 수행 (다른 패널이 올라온 상태에서 오작동 방지) - console.log('[PP-TRACE] cleanup start', { - modal: panelInfo.modal, - isOnTop, - topPanel: panels[panels.length - 1]?.name, - stack: panels.map((p) => p.name), - }); + // console.log('[PP-TRACE] cleanup start', { + // modal: panelInfo.modal, + // isOnTop, + // topPanel: panels[panels.length - 1]?.name, + // stack: panels.map((p) => p.name), + // }); // 🔽 [251221] PlayerPanel unmount 시 DeepLink 플래그 리셋 dispatch( @@ -1272,7 +1272,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props topPanelName === panel_names.PLAYER_PANEL && panels.length === 1 // 다른 패널 존재 시 pop 금지 (DetailPanel 제거 방지) ) { - console.log('[PP-TRACE] popPanel - useEffect cleanup (top is PlayerPanel)'); + // console.log('[PP-TRACE] popPanel - useEffect cleanup (top is PlayerPanel)'); dispatch(PanelActions.popPanel()); } else { Spotlight.focus('tbody'); @@ -2536,14 +2536,105 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ); const onKeyDown = (ev) => { - if (ev.keyCode === 34) { + // tabIndex === 1 (LiveChannelContents 표시)이고 비디오 배너에 포커스가 있는 경우 + const currentFocused = Spotlight.getCurrent(); + const spotlightId = currentFocused?.getAttribute('data-spotlight-id'); + const isVideoItemFocused = spotlightId?.startsWith('tabChannel-video'); + + // LiveChannelContents의 비디오 배너에 포커스가 있는 경우: PageUp/PageDown을 좌우 이동으로 변환 + if (tabIndexV2 === 1 && isVideoItemFocused) { + // DOM에서 실제로 렌더링된 모든 비디오 배너 찾기 (가상화 대응) + const allVideoBanners = Array.from( + document.querySelectorAll('[data-spotlight-id^="tabChannel-video-"]') + ); + + if (allVideoBanners.length > 0) { + // 현재 포커스된 배너의 인덱스 찾기 + const currentBannerIndex = allVideoBanners.findIndex( + (el) => el === currentFocused + ); + + if (currentBannerIndex !== -1) { + if (ev.keyCode === 34) { // PageDown -> 오른쪽 배너로 포커스 이동 + ev.stopPropagation(); + ev.preventDefault(); + + // DOM에 렌더링된 다음 배너로 이동 (마지막이면 무시 또는 첫 번째로) + if (currentBannerIndex < allVideoBanners.length - 1) { + // 다음 배너가 DOM에 있으면 이동 + const nextBanner = allVideoBanners[currentBannerIndex + 1]; + const nextSpotlightId = nextBanner.getAttribute('data-spotlight-id'); + + dlog('[PlayerPanel] 🎯 PageDown (비디오 배너) -> 오른쪽으로 이동', { + current: spotlightId, + next: nextSpotlightId, + currentBannerIndex, + totalVisibleBanners: allVideoBanners.length, + }); + + Spotlight.focus(nextSpotlightId); + } else { + // 마지막 배너면 첫 번째로 이동 시도 (DOM에 있으면) + const firstBanner = allVideoBanners[0]; + const firstSpotlightId = firstBanner.getAttribute('data-spotlight-id'); + + dlog('[PlayerPanel] 🎯 PageDown (마지막 배너) -> 첫 번째 배너로 이동 시도', { + current: spotlightId, + next: firstSpotlightId, + isWrapAround: true, + }); + + Spotlight.focus(firstSpotlightId); + } + return; + } else if (ev.keyCode === 33) { // PageUp -> 왼쪽 배너로 포커스 이동 + ev.stopPropagation(); + ev.preventDefault(); + + // DOM에 렌더링된 이전 배너로 이동 (첫 번째면 무시 또는 마지막으로) + if (currentBannerIndex > 0) { + // 이전 배너가 DOM에 있으면 이동 + const prevBanner = allVideoBanners[currentBannerIndex - 1]; + const prevSpotlightId = prevBanner.getAttribute('data-spotlight-id'); + + dlog('[PlayerPanel] 🎯 PageUp (비디오 배너) -> 왼쪽으로 이동', { + current: spotlightId, + prev: prevSpotlightId, + currentBannerIndex, + totalVisibleBanners: allVideoBanners.length, + }); + + Spotlight.focus(prevSpotlightId); + } else { + // 첫 번째 배너면 마지막으로 이동 시도 (DOM에 있으면) + const lastBanner = allVideoBanners[allVideoBanners.length - 1]; + const lastSpotlightId = lastBanner.getAttribute('data-spotlight-id'); + + dlog('[PlayerPanel] 🎯 PageUp (첫 번째 배너) -> 마지막 배너로 이동 시도', { + current: spotlightId, + prev: lastSpotlightId, + isWrapAround: true, + }); + + Spotlight.focus(lastSpotlightId); + } + return; + } + } + } + } + + // 기존 로직: LiveChannelButton 또는 다른 경우에는 상/하 이동 + if (ev.keyCode === 34) { // PageDown handleIndicatorDownClick(); ev.stopPropagation(); ev.preventDefault(); - } else if (ev.keyCode === 33) { + dlog('[PlayerPanel] 📺 PageDown (버튼 또는 다른 경우) -> 다음 비디오'); + } else if (ev.keyCode === 33) { // PageUp handleIndicatorUpClick(); ev.stopPropagation(); ev.preventDefault(); + dlog('[PlayerPanel] 📺 PageUp (버튼 또는 다른 경우) -> 이전 비디오'); } };