[251217] fix: PlayerPanel activity check 추가
🕐 커밋 시간: 2025. 12. 17. 13:43:33 📊 변경 통계: • 총 파일: 1개 • 추가: +133줄 • 삭제: -6줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx 🔧 주요 변경 내용: • 중간 규모 기능 개선
This commit is contained in:
@@ -1845,6 +1845,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
if (watchIntervalLive.current) clearInterval(watchIntervalLive.current);
|
||||
if (watchIntervalVod.current) clearInterval(watchIntervalVod.current);
|
||||
if (watchIntervalMedia.current) clearInterval(watchIntervalMedia.current);
|
||||
if (activityCheckIntervalRef.current) clearInterval(activityCheckIntervalRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -2345,7 +2346,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
setPrevChannelIndex(selectedIndex);
|
||||
}
|
||||
setSideContentsVisible(true);
|
||||
}, [dispatch, playListInfo, selectedIndex, sideContentsVisible, initialEnter]);
|
||||
}, [dispatch, playListInfo, selectedIndex, sideContentsVisible, initialEnter, tabContainerVersion, tabIndexV2]);
|
||||
|
||||
const handleIndicatorUpClick = useCallback(() => {
|
||||
if (!initialEnter) {
|
||||
@@ -2393,7 +2394,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
setPrevChannelIndex(selectedIndex);
|
||||
}
|
||||
setSideContentsVisible(true);
|
||||
}, [dispatch, playListInfo, selectedIndex, sideContentsVisible, initialEnter]);
|
||||
}, [dispatch, playListInfo, selectedIndex, sideContentsVisible, initialEnter, tabContainerVersion, tabIndexV2]);
|
||||
|
||||
useEffect(() => {
|
||||
if (panelInfo.shptmBanrTpNm === 'VOD' && panelInfo.patnrId && panelInfo.showId) {
|
||||
@@ -2553,6 +2554,11 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
const timerIdTabAutoAdvance = useRef(null);
|
||||
const prevTabIndexV2 = useRef(null);
|
||||
|
||||
// Activity Check for tabIndex auto-advance
|
||||
const lastActivityTimeRef = useRef(Date.now());
|
||||
const activityCheckIntervalRef = useRef(null);
|
||||
const ACTIVITY_TIMEOUT = 1000; // 1초 동안 활동이 없으면 타이머 진행
|
||||
|
||||
const showSideContents = useMemo(() => {
|
||||
return (
|
||||
sideContentsVisible &&
|
||||
@@ -2664,17 +2670,62 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
timerIdTabAutoAdvance.current = null;
|
||||
}, []);
|
||||
|
||||
// Activity 감지 함수
|
||||
const onActivityDetected = useCallback(() => {
|
||||
lastActivityTimeRef.current = Date.now();
|
||||
dlog('[PlayerPanel] 🎯 Activity detected - timer will be delayed', {
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Activity 여부를 확인하는 함수 (1초 타임아웃 체크)
|
||||
const isInactive = useCallback(() => {
|
||||
const now = Date.now();
|
||||
const timeSinceLastActivity = now - lastActivityTimeRef.current;
|
||||
return timeSinceLastActivity > ACTIVITY_TIMEOUT;
|
||||
}, []);
|
||||
|
||||
const resetTimerTabAutoAdvance = useCallback(
|
||||
(timeout) => {
|
||||
if (timerIdTabAutoAdvance.current) {
|
||||
clearTimerTabAutoAdvance();
|
||||
}
|
||||
|
||||
timerIdTabAutoAdvance.current = setTimeout(() => {
|
||||
// Activity check interval 설정 (매 100ms마다 체크)
|
||||
if (activityCheckIntervalRef.current) {
|
||||
clearInterval(activityCheckIntervalRef.current);
|
||||
}
|
||||
|
||||
let elapsedTime = 0;
|
||||
|
||||
activityCheckIntervalRef.current = setInterval(() => {
|
||||
// 활동이 없을 때만 경과 시간 증가
|
||||
if (isInactive()) {
|
||||
elapsedTime += 100;
|
||||
dlog('[PlayerPanel] ⏱️ TabIndex auto-advance: inactive', {
|
||||
elapsedTime,
|
||||
requiredTime: timeout,
|
||||
});
|
||||
|
||||
// 필요한 시간만큼 경과했으면 타이머 실행
|
||||
if (elapsedTime >= timeout) {
|
||||
dlog('[PlayerPanel] ✅ TabIndex auto-advance executing - setTabIndexV2(2)', {
|
||||
totalElapsed: elapsedTime,
|
||||
timeout,
|
||||
});
|
||||
clearInterval(activityCheckIntervalRef.current);
|
||||
setTabIndexV2(2);
|
||||
}, timeout);
|
||||
}
|
||||
} else {
|
||||
// 활동이 감지되면 경과 시간 리셋
|
||||
dlog('[PlayerPanel] 🔄 Activity detected - resetting elapsed time', {
|
||||
previousElapsed: elapsedTime,
|
||||
});
|
||||
elapsedTime = 0;
|
||||
}
|
||||
}, 100);
|
||||
},
|
||||
[clearTimerTabAutoAdvance]
|
||||
[clearTimerTabAutoAdvance, isInactive]
|
||||
);
|
||||
|
||||
// Redux로 오버레이 숨김
|
||||
@@ -2699,6 +2750,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
if (timerIdTabAutoAdvance.current) {
|
||||
clearTimerTabAutoAdvance();
|
||||
}
|
||||
if (activityCheckIntervalRef.current) {
|
||||
clearInterval(activityCheckIntervalRef.current);
|
||||
activityCheckIntervalRef.current = null;
|
||||
}
|
||||
|
||||
dispatch(resetPlayerOverlays());
|
||||
}
|
||||
@@ -2913,6 +2968,53 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
panelInfo?.modal,
|
||||
]);
|
||||
|
||||
// PageUp/PageDown으로 비디오 변경 시 현재 재생 배너로 포커스 이동
|
||||
useEffect(() => {
|
||||
if (tabContainerVersion === 2 &&
|
||||
tabIndexV2 === 1 &&
|
||||
panelInfo?.isIndicatorByClick &&
|
||||
selectedIndex !== null &&
|
||||
selectedIndex >= 0) {
|
||||
|
||||
dlog('[PlayerPanel] 🎯 PageUp/PageDown 후 포커스 이동 준비', {
|
||||
selectedIndex,
|
||||
tabContainerVersion,
|
||||
tabIndexV2,
|
||||
isIndicatorByClick: panelInfo.isIndicatorByClick
|
||||
});
|
||||
|
||||
const bannerSpotlightId = `banner${selectedIndex}`;
|
||||
|
||||
setTimeout(() => {
|
||||
dlog('[PlayerPanel] 🔍 포커스 이동 시도:', bannerSpotlightId);
|
||||
|
||||
const bannerElement = document.querySelector(`[data-spotlight-id="${bannerSpotlightId}"]`);
|
||||
|
||||
if (bannerElement) {
|
||||
dlog('[PlayerPanel] ✅ 배너 요소 찾음, 포커스 이동 실행');
|
||||
Spotlight.focus(bannerElement);
|
||||
} else {
|
||||
dlog('[PlayerPanel] ⚠️ 배너 요소 찾지 못함:', bannerSpotlightId);
|
||||
// 모든 배너 요소 목록 출력
|
||||
const allBanners = document.querySelectorAll('[data-spotlight-id^="banner"]');
|
||||
dlog('[PlayerPanel] 🔍 사용 가능한 배너 목록:',
|
||||
Array.from(allBanners).map(el => el.getAttribute('data-spotlight-id'))
|
||||
);
|
||||
}
|
||||
|
||||
// 플래그 리셋
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.PLAYER_PANEL,
|
||||
panelInfo: {
|
||||
isIndicatorByClick: false
|
||||
},
|
||||
})
|
||||
);
|
||||
}, 200); // DOM 업데이트 대기
|
||||
}
|
||||
}, [selectedIndex, tabContainerVersion, tabIndexV2, panelInfo?.isIndicatorByClick, dispatch]);
|
||||
|
||||
// TabIndex 1 자동 다음 단계로 이동
|
||||
useEffect(() => {
|
||||
// tabIndex === 1일 때만 실행
|
||||
@@ -2939,6 +3041,31 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
clearTimerTabAutoAdvance,
|
||||
]);
|
||||
|
||||
// Activity detection for tabIndex auto-advance (mousemove, keydown, click)
|
||||
useEffect(() => {
|
||||
// tabIndex === 1일 때만 Activity 감지 활성화
|
||||
if (tabIndexV2 !== 1 || !belowContentsVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
dlog('[PlayerPanel] 🎙️ Activity listener registered for tabIndex=1');
|
||||
|
||||
const handleMouseMove = onActivityDetected;
|
||||
const handleKeyDown = onActivityDetected;
|
||||
const handleClick = onActivityDetected;
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
document.addEventListener('click', handleClick);
|
||||
|
||||
return () => {
|
||||
dlog('[PlayerPanel] 🎙️ Activity listener unregistered');
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
document.removeEventListener('click', handleClick);
|
||||
};
|
||||
}, [tabIndexV2, belowContentsVisible, onActivityDetected]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const videoContainer = document.querySelector(`.${css.videoContainer}`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user