[251217] fix: VOD 경과시간 표시
🕐 커밋 시간: 2025. 12. 17. 16:09:01 📊 변경 통계: • 총 파일: 2개 • 추가: +18줄 • 삭제: -205줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js 🔧 주요 변경 내용: • UI 컴포넌트 아키텍처 개선 • 코드 정리 및 최적화 Performance: 코드 최적화로 성능 개선 기대
This commit is contained in:
@@ -840,9 +840,11 @@ const VideoPlayerBase = class extends React.Component {
|
||||
this.state.mediaSliderVisible === nextState.mediaSliderVisible &&
|
||||
this.state.loading === nextState.loading &&
|
||||
this.props.loading === nextProps.loading &&
|
||||
(this.state.currentTime !== nextState.currentTime ||
|
||||
this.state.proportionPlayed !== nextState.proportionPlayed ||
|
||||
this.state.sliderTooltipTime !== nextState.sliderTooltipTime)
|
||||
this.state.currentTime === nextState.currentTime &&
|
||||
this.state.proportionPlayed === nextState.proportionPlayed &&
|
||||
this.state.sliderTooltipTime === nextState.sliderTooltipTime &&
|
||||
this.state.mediaControlsVisible === nextState.mediaControlsVisible &&
|
||||
this.state.bottomControlsRendered === nextState.bottomControlsRendered
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -1279,14 +1281,11 @@ const VideoPlayerBase = class extends React.Component {
|
||||
sourceUnavailable: true,
|
||||
proportionPlayed: 0,
|
||||
proportionLoaded: 0,
|
||||
bottomControlsRendered: true,
|
||||
});
|
||||
|
||||
if (!this.props.noAutoShowMediaControls) {
|
||||
if (!this.state.bottomControlsRendered) {
|
||||
this.renderBottomControl.idle();
|
||||
} else {
|
||||
this.showControls();
|
||||
}
|
||||
this.showControls();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -855,9 +855,11 @@ const VideoPlayerBase = class extends React.Component {
|
||||
this.state.mediaSliderVisible === nextState.mediaSliderVisible &&
|
||||
this.state.loading === nextState.loading &&
|
||||
this.props.loading === nextProps.loading &&
|
||||
(this.state.currentTime !== nextState.currentTime ||
|
||||
this.state.proportionPlayed !== nextState.proportionPlayed ||
|
||||
this.state.sliderTooltipTime !== nextState.sliderTooltipTime)
|
||||
this.state.currentTime === nextState.currentTime &&
|
||||
this.state.proportionPlayed === nextState.proportionPlayed &&
|
||||
this.state.sliderTooltipTime === nextState.sliderTooltipTime &&
|
||||
this.state.mediaControlsVisible === nextState.mediaControlsVisible &&
|
||||
this.state.bottomControlsRendered === nextState.bottomControlsRendered
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -1423,14 +1425,11 @@ const VideoPlayerBase = class extends React.Component {
|
||||
sourceUnavailable: true,
|
||||
proportionPlayed: 0,
|
||||
proportionLoaded: 0,
|
||||
bottomControlsRendered: true,
|
||||
});
|
||||
|
||||
if (!this.props.noAutoShowMediaControls) {
|
||||
if (!this.state.bottomControlsRendered) {
|
||||
this.renderBottomControl.idle();
|
||||
} else {
|
||||
this.showControls();
|
||||
}
|
||||
this.showControls();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1636,103 +1635,6 @@ const VideoPlayerBase = class extends React.Component {
|
||||
updatedState.thumbnailUrl = null;
|
||||
}
|
||||
this.setState(updatedState);
|
||||
|
||||
// Redux에 비디오 재생 상태 업데이트 (기존 로직 유지)
|
||||
if (this.props.dispatch) {
|
||||
// 🔥 onProgress 이벤트는 Redux 업데이트하지 않음 (빈번한 이벤트)
|
||||
const shouldUpdateRedux = !['onProgress'].includes(ev.type);
|
||||
|
||||
if (shouldUpdateRedux) {
|
||||
const updateState = {
|
||||
isPlaying: !updatedState.paused,
|
||||
isPaused: updatedState.paused,
|
||||
currentTime: updatedState.currentTime,
|
||||
duration: updatedState.duration,
|
||||
playbackRate: updatedState.playbackRate,
|
||||
};
|
||||
|
||||
// 가장 중요한 이벤트만 로그
|
||||
const shouldLogEvent = ['play', 'pause', 'ended'].includes(ev.type);
|
||||
if (shouldLogEvent) {
|
||||
dlog('🔄 [PlayerPanel][VideoPlayer] Event-driven Redux update', {
|
||||
eventType: ev.type,
|
||||
videoState: updatedState,
|
||||
updateState,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
// 🔍 Redux dispatch 확인
|
||||
dlog('📤 [PlayerPanel][VideoPlayer] Dispatching Redux update', {
|
||||
eventType: ev.type,
|
||||
updateState,
|
||||
hasDispatch: !!this.props.dispatch,
|
||||
propsVideoPlayState: this.props.videoPlayState,
|
||||
});
|
||||
|
||||
this.props.dispatch(updateVideoPlayState(updateState));
|
||||
}
|
||||
} else {
|
||||
derror('❌ [PlayerPanel][VideoPlayer] No dispatch prop available', {
|
||||
props: Object.keys(this.props),
|
||||
hasDispatch: !!this.props.dispatch,
|
||||
hasVideoPlayState: !!this.props.videoPlayState,
|
||||
});
|
||||
}
|
||||
|
||||
// 🔹 [강화] 내부 상태와 Redux 상태 동기화
|
||||
// Redux 상태를 우선적으로 사용하여 내부 상태 일관성 확보
|
||||
if (this.props.videoPlayState && typeof this.props.videoPlayState === 'object') {
|
||||
// Redux 상태 디버깅 (최소한의 중요 이벤트만)
|
||||
if (ev.type === 'play' || ev.type === 'pause') {
|
||||
dlog('🔍 [PlayerPanel][VideoPlayer] Redux state debug', {
|
||||
videoPlayState: this.props.videoPlayState,
|
||||
isPaused: this.props.videoPlayState?.isPaused,
|
||||
isPlaying: this.props.videoPlayState?.isPlaying,
|
||||
currentTime: this.props.videoPlayState?.currentTime,
|
||||
eventType: ev.type,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
const { currentTime, paused, playbackRate } = this.props.videoPlayState;
|
||||
|
||||
// Redux 상태와 현재 내부 상태가 크게 다를 경우 내부 상태 업데이트
|
||||
const timeDiff = Math.abs(currentTime - this.state.currentTime);
|
||||
const shouldUpdateTime = timeDiff > 0.5; // 0.5초 이상 차이 시 업데이트
|
||||
|
||||
// 빈번한 이벤트는 로그에서 제외
|
||||
const isFrequentEvent = [
|
||||
'onProgress',
|
||||
'onBuffer',
|
||||
'onBufferEnd',
|
||||
'onReady',
|
||||
'onDuration',
|
||||
'onStart',
|
||||
].includes(ev.type);
|
||||
const hasSignificantChange =
|
||||
shouldUpdateTime || (paused !== this.state.paused && !isFrequentEvent);
|
||||
|
||||
// 중요한 상태 변화가 있고 빈번한 이벤트가 아닐 때만 로그
|
||||
if (hasSignificantChange && !isFrequentEvent) {
|
||||
dlog('🔄 [PlayerPanel][VideoPlayer] Syncing internal state with Redux', {
|
||||
timeDiff,
|
||||
shouldUpdateTime,
|
||||
pausedDiff: paused !== this.state.paused,
|
||||
reduxPaused: paused,
|
||||
internalPaused: this.state.paused,
|
||||
eventType: ev.type,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
if (hasSignificantChange) {
|
||||
this.setState({
|
||||
currentTime: shouldUpdateTime ? currentTime : this.state.currentTime,
|
||||
paused: paused !== undefined ? paused : this.state.paused,
|
||||
playbackRate: playbackRate !== undefined ? playbackRate : this.state.playbackRate,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
renderBottomControl = new Job(() => {
|
||||
@@ -1744,7 +1646,6 @@ const VideoPlayerBase = class extends React.Component {
|
||||
/**
|
||||
* Returns an object with the current state of the media including `currentTime`, `duration`,
|
||||
* `paused`, `playbackRate`, `proportionLoaded`, and `proportionPlayed`.
|
||||
* Redux 상태와 내부 상태를 우선적으로 사용하여 일관성 보장
|
||||
*
|
||||
* @function
|
||||
* @memberof sandstone/VideoPlayer.VideoPlayerBase.prototype
|
||||
@@ -1752,19 +1653,13 @@ const VideoPlayerBase = class extends React.Component {
|
||||
* @public
|
||||
*/
|
||||
getMediaState = () => {
|
||||
// Redux 상태를 우선적으로 사용하여 일관성 보장
|
||||
// Redux 상태가 없으면 내부 상태 사용 (fallback)
|
||||
const reduxState = this.props.videoPlayState;
|
||||
|
||||
return {
|
||||
currentTime: reduxState?.currentTime ?? this.state.currentTime,
|
||||
duration: reduxState?.duration ?? this.state.duration,
|
||||
paused: reduxState?.isPaused ?? this.state.paused,
|
||||
playbackRate: reduxState?.playbackRate ?? this.video?.playbackRate ?? this.state.playbackRate,
|
||||
currentTime: this.state.currentTime,
|
||||
duration: this.state.duration,
|
||||
paused: this.state.paused,
|
||||
playbackRate: this.video?.playbackRate,
|
||||
proportionLoaded: this.state.proportionLoaded,
|
||||
proportionPlayed: this.state.proportionPlayed,
|
||||
// Redux 상태 정보도 포함
|
||||
isPlaying: reduxState?.isPlaying ?? !this.state.paused,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1793,16 +1688,7 @@ const VideoPlayerBase = class extends React.Component {
|
||||
* @public
|
||||
*/
|
||||
play = () => {
|
||||
dlog('🟢 [PlayerPanel][VideoPlayer] play() called', {
|
||||
currentTime: this.state.currentTime,
|
||||
duration: this.state.duration,
|
||||
paused: this.state.paused,
|
||||
sourceUnavailable: this.state.sourceUnavailable,
|
||||
prevCommand: this.prevCommand,
|
||||
});
|
||||
|
||||
if (this.state.sourceUnavailable) {
|
||||
dwarn('⚠️ [PlayerPanel][VideoPlayer] play() aborted - source unavailable');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1814,19 +1700,6 @@ const VideoPlayerBase = class extends React.Component {
|
||||
this.send('play');
|
||||
this.announce($L('Play'));
|
||||
this.startDelayedMiniFeedbackHide(5000);
|
||||
|
||||
// Redux 상태 업데이트 - 재생 상태로 변경
|
||||
if (this.props.dispatch) {
|
||||
this.props.dispatch(
|
||||
updateVideoPlayState({
|
||||
isPlaying: true,
|
||||
isPaused: false,
|
||||
currentTime: this.state.currentTime,
|
||||
duration: this.state.duration,
|
||||
playbackRate: 1,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1837,16 +1710,7 @@ const VideoPlayerBase = class extends React.Component {
|
||||
* @public
|
||||
*/
|
||||
pause = () => {
|
||||
dlog('🔴 [VideoPlayer] pause() called', {
|
||||
currentTime: this.state.currentTime,
|
||||
duration: this.state.duration,
|
||||
paused: this.state.paused,
|
||||
sourceUnavailable: this.state.sourceUnavailable,
|
||||
prevCommand: this.prevCommand,
|
||||
});
|
||||
|
||||
if (this.state.sourceUnavailable) {
|
||||
dwarn('⚠️ [VideoPlayer] pause() aborted - source unavailable');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1858,22 +1722,6 @@ const VideoPlayerBase = class extends React.Component {
|
||||
this.send('pause');
|
||||
this.announce($L('Pause'));
|
||||
this.stopDelayedMiniFeedbackHide();
|
||||
|
||||
// Redux 상태 업데이트 - 일시정지 상태로 변경
|
||||
if (this.props.dispatch) {
|
||||
const pauseState = {
|
||||
isPlaying: false,
|
||||
isPaused: true,
|
||||
currentTime: this.state.currentTime,
|
||||
duration: this.state.duration,
|
||||
playbackRate: 1,
|
||||
};
|
||||
|
||||
dlog('📤 [VideoPlayer] Dispatching pause state', pauseState);
|
||||
this.props.dispatch(updateVideoPlayState(pauseState));
|
||||
} else {
|
||||
dwarn('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1885,15 +1733,6 @@ const VideoPlayerBase = class extends React.Component {
|
||||
* @public
|
||||
*/
|
||||
seek = (timeIndex) => {
|
||||
dlog('⏩ [VideoPlayer] seek() called', {
|
||||
timeIndex,
|
||||
currentTime: this.state.currentTime,
|
||||
duration: this.state.duration,
|
||||
videoDuration: this.video?.duration,
|
||||
seekDisabled: this.props.seekDisabled,
|
||||
sourceUnavailable: this.state.sourceUnavailable,
|
||||
});
|
||||
|
||||
if (this.video) {
|
||||
if (
|
||||
!this.props.seekDisabled &&
|
||||
@@ -1904,34 +1743,9 @@ const VideoPlayerBase = class extends React.Component {
|
||||
const actualSeekTime =
|
||||
timeIndex >= this.video.duration ? this.video.duration - 1 : timeIndex;
|
||||
this.video.currentTime = actualSeekTime;
|
||||
|
||||
dlog('⏩ [VideoPlayer] Video seek completed', {
|
||||
requestedTime: timeIndex,
|
||||
actualTime: actualSeekTime,
|
||||
videoDuration: this.video.duration,
|
||||
});
|
||||
|
||||
// Redux 상태 업데이트 - 시간 이동 상태 반영
|
||||
if (this.props.dispatch) {
|
||||
const seekState = {
|
||||
isPlaying: !this.state.paused,
|
||||
isPaused: this.state.paused,
|
||||
currentTime: actualSeekTime,
|
||||
duration: this.state.duration,
|
||||
playbackRate: this.state.playbackRate,
|
||||
};
|
||||
|
||||
dlog('📤 [VideoPlayer] Dispatching seek state', seekState);
|
||||
this.props.dispatch(updateVideoPlayState(seekState));
|
||||
} else {
|
||||
dwarn('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated');
|
||||
}
|
||||
} else {
|
||||
derror('❌ [VideoPlayer] seek failed - disabled or source unavailable');
|
||||
forward('onSeekFailed', {}, this.props);
|
||||
}
|
||||
} else {
|
||||
derror('❌ [VideoPlayer] seek failed - no video element');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user