[251116] feat: videoPlayIntentRef
🕐 커밋 시간: 2025. 11. 16. 19:59:28 📊 변경 통계: • 총 파일: 4개 • 추가: +149줄 • 삭제: -16줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/playActions.js ~ com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx ~ com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx ~ com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/views/HomePanel/HomeBanner/HomeBanner.jsx (javascript): 🔄 Modified: Spottable() 📄 com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx (javascript): ✅ Added: SpotlightContainerDecorator() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선
This commit is contained in:
@@ -161,11 +161,12 @@ export const startVideoPlayerNew =
|
|||||||
panelWorkingAction = updatePanel;
|
panelWorkingAction = updatePanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// playerState 업데이트: 기존 playerState와 새 데이터 병합
|
// 중복 실행 방지: 현재 PlayerPanel이 같은 배너를 재생 중이면 skip
|
||||||
const currentPlayerState = topPanel?.panelInfo?.playerState || {};
|
const currentPlayerState = topPanel?.panelInfo?.playerState || {};
|
||||||
|
if (currentPlayerState?.currentBannerId === bannerId) {
|
||||||
// ✅ 정확한 비교: 같은 배너 + 같은 modal 상태 + 같은 위치일 때만 skip
|
console.log('[playActions] startVideoPlayerNew: 동일 배너 재생 중이라 중복 실행 SKIP', {
|
||||||
if (shouldSkipVideoPlayback(topPanel?.panelInfo, modal, modalContainerId, bannerId)) {
|
bannerId,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,13 @@ const SpottableComponent = Spottable('div');
|
|||||||
const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
||||||
const ContainerBasic = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
const ContainerBasic = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
||||||
|
|
||||||
export default function HomeBanner({ firstSpot, spotlightId, handleItemFocus, handleShelfFocus }) {
|
export default function HomeBanner({
|
||||||
|
firstSpot,
|
||||||
|
spotlightId,
|
||||||
|
handleItemFocus,
|
||||||
|
handleShelfFocus,
|
||||||
|
videoPlayIntentRef,
|
||||||
|
}) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(justForYou());
|
dispatch(justForYou());
|
||||||
@@ -453,6 +459,7 @@ export default function HomeBanner({ firstSpot, spotlightId, handleItemFocus, ha
|
|||||||
handleItemFocus={_handleItemFocus}
|
handleItemFocus={_handleItemFocus}
|
||||||
randomNumber={data.randomIndex}
|
randomNumber={data.randomIndex}
|
||||||
videoPlayerable={videoPlayerable}
|
videoPlayerable={videoPlayerable}
|
||||||
|
videoPlayIntentRef={videoPlayIntentRef}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<SpottableComponent spotlightId={'banner' + index}>
|
<SpottableComponent spotlightId={'banner' + index}>
|
||||||
@@ -472,7 +479,7 @@ export default function HomeBanner({ firstSpot, spotlightId, handleItemFocus, ha
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[_handleItemFocus, _handleShelfFocus, bannerDataList]
|
[_handleItemFocus, _handleShelfFocus, bannerDataList, videoPlayIntentRef]
|
||||||
);
|
);
|
||||||
|
|
||||||
// 0번째 배너(영구 재생)를 위한 렌더링 함수
|
// 0번째 배너(영구 재생)를 위한 렌더링 함수
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export default function RandomUnit({
|
|||||||
handleItemFocus,
|
handleItemFocus,
|
||||||
randomNumber,
|
randomNumber,
|
||||||
videoPlayerable = false,
|
videoPlayerable = false,
|
||||||
|
videoPlayIntentRef,
|
||||||
}) {
|
}) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
@@ -83,13 +84,16 @@ export default function RandomUnit({
|
|||||||
const [isFocused, setIsFocused] = useState(false);
|
const [isFocused, setIsFocused] = useState(false);
|
||||||
const [videoError, setVideoError] = useState(false);
|
const [videoError, setVideoError] = useState(false);
|
||||||
const [liveIndicies, setLiveIndicies] = useState([]);
|
const [liveIndicies, setLiveIndicies] = useState([]);
|
||||||
|
const [videoIntentVersion, setVideoIntentVersion] = useState(0);
|
||||||
const defaultFocus = useSelector((state) => state.home.defaultFocus);
|
const defaultFocus = useSelector((state) => state.home.defaultFocus);
|
||||||
const isVideoTransitionLocked = useSelector((state) => state.home.videoTransitionLocked);
|
const isVideoTransitionLocked = useSelector((state) => state.home.videoTransitionLocked);
|
||||||
|
|
||||||
const timerRef = useRef();
|
const timerRef = useRef();
|
||||||
const hasAutoPlayStartedRef = useRef(false);
|
const hasAutoPlayStartedRef = useRef(false);
|
||||||
const hasPlaybackStartedRef = useRef(false);
|
const hasPlaybackStartedRef = useRef(false);
|
||||||
|
const videoIntentTimerRef = useRef(null);
|
||||||
const isDefaultAutoPlayTarget = defaultFocus === spotlightId;
|
const isDefaultAutoPlayTarget = defaultFocus === spotlightId;
|
||||||
|
const lastProcessedIntentVersionRef = useRef(-1);
|
||||||
const bannerDataRef = useRef(bannerData);
|
const bannerDataRef = useRef(bannerData);
|
||||||
const randomDataRef = useRef(
|
const randomDataRef = useRef(
|
||||||
bannerDetailInfos && randomNumber !== undefined && bannerDetailInfos.length > 0
|
bannerDetailInfos && randomNumber !== undefined && bannerDetailInfos.length > 0
|
||||||
@@ -273,19 +277,45 @@ export default function RandomUnit({
|
|||||||
lastUpdate: videoPlayState.lastUpdate,
|
lastUpdate: videoPlayState.lastUpdate,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('[RandomUnit] onFocus called', {
|
console.log('[RandomUnit] onFocus - 비디오 재생 의도 저장', {
|
||||||
spotlightId,
|
bannerId: spotlightId,
|
||||||
videoPlayerable,
|
videoPlayerable,
|
||||||
|
currentIntent: videoPlayIntentRef.current?.bannerId,
|
||||||
currentVideoBannerId,
|
currentVideoBannerId,
|
||||||
randomData: randomData?.showId || 'no-show-id',
|
randomData: randomData?.showId || 'no-show-id',
|
||||||
});
|
});
|
||||||
|
|
||||||
setIsFocused(true);
|
setIsFocused(true);
|
||||||
|
|
||||||
// video가 플레이 가능한 경우: 다른 배너에서 비디오 재생 중이면 종료
|
// 🔽 [251116] 수정: 재생 의도만 저장, 즉시 실행 ❌
|
||||||
if (videoPlayerable && currentVideoBannerId && currentVideoBannerId !== spotlightId) {
|
if (videoPlayerable) {
|
||||||
console.log('[RandomUnit] videoPlayerable=true and different banner, finishing video');
|
videoPlayIntentRef.current = {
|
||||||
dispatch(finishVideoPreview());
|
bannerId: spotlightId,
|
||||||
|
videoProps: {
|
||||||
|
bannerId: spotlightId,
|
||||||
|
showUrl: randomData.showUrl,
|
||||||
|
patnrId: randomData.patnrId,
|
||||||
|
showId: randomData.showId,
|
||||||
|
shptmBanrTpNm: randomData.shptmBanrTpNm,
|
||||||
|
lgCatCd: randomData.lgCatCd,
|
||||||
|
chanId: randomData.brdcChnlId,
|
||||||
|
modal: true,
|
||||||
|
modalContainerId: spotlightId,
|
||||||
|
},
|
||||||
|
timestamp: Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('[RandomUnit] 비디오 재생 의도 저장됨', {
|
||||||
|
intentBannerId: spotlightId,
|
||||||
|
videoUrl: randomData.showUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
setVideoIntentVersion((version) => version + 1);
|
||||||
|
|
||||||
|
// 기존 finishVideoPreview 호출 제거!
|
||||||
|
// if (videoPlayerable && currentVideoBannerId && currentVideoBannerId !== spotlightId) {
|
||||||
|
// dispatch(finishVideoPreview());
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// video가 플레이 불가능한 경우: 재생 중인 비디오를 1px로 축소
|
// video가 플레이 불가능한 경우: 재생 중인 비디오를 1px로 축소
|
||||||
@@ -618,6 +648,15 @@ export default function RandomUnit({
|
|||||||
}
|
}
|
||||||
}, [randomData]);
|
}, [randomData]);
|
||||||
|
|
||||||
|
// 🔽 [251116] 기존 로직 단순화 - videoPlayIntentRef가 모든 비디오 제어를 담당
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isFocused) {
|
||||||
|
setVideoError(false);
|
||||||
|
}
|
||||||
|
}, [isFocused]);
|
||||||
|
|
||||||
|
// 🔽 [251116] 기존 복잡한 비디오 시작 로직 비활성화
|
||||||
|
/*
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isFocused && !videoError && !hasPlaybackStartedRef.current) {
|
if (isFocused && !videoError && !hasPlaybackStartedRef.current) {
|
||||||
if (timerRef.current) {
|
if (timerRef.current) {
|
||||||
@@ -665,6 +704,89 @@ export default function RandomUnit({
|
|||||||
spotlightId,
|
spotlightId,
|
||||||
handleStartVideo,
|
handleStartVideo,
|
||||||
]);
|
]);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 🔽 [251116] 신규: videoPlayIntentRef 기반 비디오 제어
|
||||||
|
useEffect(() => {
|
||||||
|
if (!videoPlayIntentRef.current) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (lastProcessedIntentVersionRef.current === videoIntentVersion) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
lastProcessedIntentVersionRef.current = videoIntentVersion;
|
||||||
|
|
||||||
|
const intent = videoPlayIntentRef.current;
|
||||||
|
const currentVideoId = videoPlayState.videoId;
|
||||||
|
const activeBannerId = currentVideoBannerId;
|
||||||
|
|
||||||
|
console.log('[RandomUnit] videoPlayIntent useEffect', {
|
||||||
|
intentBannerId: intent.bannerId,
|
||||||
|
currentVideoId,
|
||||||
|
activeBannerId,
|
||||||
|
currentPlayback: videoPlayState.playback,
|
||||||
|
currentDisplay: videoPlayState.display,
|
||||||
|
loadingProgress: videoPlayState.loadingProgress,
|
||||||
|
shouldStart: intent.bannerId !== activeBannerId,
|
||||||
|
isVideoTransitionLocked,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (intent.bannerId === activeBannerId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoIntentTimerRef.current) {
|
||||||
|
clearTimeout(videoIntentTimerRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
videoIntentTimerRef.current = setTimeout(() => {
|
||||||
|
if (videoPlayIntentRef.current?.bannerId !== intent.bannerId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[RandomUnit] 비디오 변경 실행', {
|
||||||
|
from: currentVideoId,
|
||||||
|
to: intent.bannerId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (activeBannerId) {
|
||||||
|
dispatch(finishVideoPreview());
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
dispatch(setVideoTransitionLock(true));
|
||||||
|
dispatch(startVideoPlayerNew(intent.videoProps));
|
||||||
|
hasPlaybackStartedRef.current = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
dispatch(setVideoTransitionLock(false));
|
||||||
|
}, 2000);
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
dispatch(setVideoTransitionLock(true));
|
||||||
|
dispatch(startVideoPlayerNew(intent.videoProps));
|
||||||
|
hasPlaybackStartedRef.current = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
dispatch(setVideoTransitionLock(false));
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}, 300); // 안정화 시간
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (videoIntentTimerRef.current) {
|
||||||
|
clearTimeout(videoIntentTimerRef.current);
|
||||||
|
videoIntentTimerRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
videoPlayState.videoId,
|
||||||
|
dispatch,
|
||||||
|
videoPlayIntentRef,
|
||||||
|
videoIntentVersion,
|
||||||
|
isVideoTransitionLocked,
|
||||||
|
currentVideoBannerId,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isFocused && broadcast?.type === 'videoError') {
|
if (isFocused && broadcast?.type === 'videoError') {
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ const HomePanel = ({ isOnTop }) => {
|
|||||||
enableLogging: true,
|
enableLogging: true,
|
||||||
logPrefix: '[HomePanel-VideoPlay]',
|
logPrefix: '[HomePanel-VideoPlay]',
|
||||||
});
|
});
|
||||||
|
// 🔽 비디오 재생 의도 공유 ref
|
||||||
|
const videoPlayIntentRef = useRef(null);
|
||||||
|
|
||||||
// 🔽 useVideoMove - 포커스 전환 기반 동영상 제어
|
// 🔽 useVideoMove - 포커스 전환 기반 동영상 제어
|
||||||
// [COMMENTED OUT] useVideoMove 미사용 - cleanup() 호출되지 않음
|
// [COMMENTED OUT] useVideoMove 미사용 - cleanup() 호출되지 않음
|
||||||
@@ -314,6 +316,7 @@ const HomePanel = ({ isOnTop }) => {
|
|||||||
el.shptmApphmDspyOptNm
|
el.shptmApphmDspyOptNm
|
||||||
)}
|
)}
|
||||||
handleItemFocus={handleItemFocus(el.shptmApphmDspyOptCd)}
|
handleItemFocus={handleItemFocus(el.shptmApphmDspyOptCd)}
|
||||||
|
videoPlayIntentRef={videoPlayIntentRef}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user