# MediaPlayer.v2 필수 수정 사항 **작성일**: 2025-11-10 **발견 사항**: MediaPanel의 실제 사용 컨텍스트 분석 --- ## 🔍 실제 사용 패턴 분석 ### 사용 위치 ``` DetailPanel → ProductAllSection → ProductVideo → startMediaPlayer() → MediaPanel → MediaPlayer (VideoPlayer) ``` ### 동작 플로우 #### 1️⃣ **Modal 모드 시작** (작은 화면) ```javascript // ProductVideo.jsx:174-198 dispatch(startMediaPlayer({ modal: true, // 작은 화면 모드 modalContainerId: 'product-video-player', showUrl: productInfo.prdtMediaUrl, thumbnailUrl: productInfo.thumbnailUrl960, // ... })); ``` **Modal 모드 특징**: - 화면 일부 영역에 fixed position으로 표시 - **오버레이 없음** (controls, slider 모두 숨김) - 클릭만 가능 (전체화면으로 전환) #### 2️⃣ **Fullscreen 모드 전환** (최대화면) ```javascript // ProductVideo.jsx:164-168 if (isCurrentlyPlayingModal) { dispatch(switchMediaToFullscreen()); // modal: false로 변경 } ``` **Fullscreen 모드 특징**: - 전체 화면 표시 - **리모컨 엔터 키 → 오버레이 표시 필수** - ✅ Back 버튼 - ✅ **비디오 진행 바 (MediaSlider)** ← 필수! - ✅ 현재 시간 / 전체 시간 (Times) - ✅ Play/Pause 버튼 (MediaControls) --- ## 🚨 현재 MediaPlayer.v2의 문제점 ### ❌ 제거된 필수 기능 ```javascript // MediaPlayer.v2.jsx - 현재 상태 {controlsVisible && !isModal && (
// Play/Pause만
)} ``` **문제**: 1. ❌ **MediaSlider (seek bar) 없음** - 리모컨으로 진행 위치 조정 불가 2. ❌ **Times 컴포넌트 없음** - 현재 시간/전체 시간 표시 안 됨 3. ❌ **proportionLoaded, proportionPlayed 상태 없음** --- ## ✅ 기존 MediaPlayer.jsx의 올바른 구현 ### Modal vs Fullscreen 조건부 렌더링 ```javascript // MediaPlayer.jsx:2415-2461 {noSlider ? null : (
{/* Times - 전체 시간 */} {this.state.mediaSliderVisible && type ? ( ) : null} {/* Times - 현재 시간 */} {this.state.mediaSliderVisible && type ? ( ) : null} {/* MediaSlider - modal이 아닐 때만 표시 */} {!panelInfo.modal && ( )}
)} ``` **핵심 조건**: ```javascript !panelInfo.modal // Modal이 아닐 때만 MediaSlider 표시 ``` --- ## 📋 MediaPlayer.v2 수정 필요 사항 ### 1. 상태 추가 ```javascript // 현재 (7개) const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [paused, setPaused] = useState(!autoPlay); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [controlsVisible, setControlsVisible] = useState(false); const [sourceUnavailable, setSourceUnavailable] = useState(true); // 추가 필요 (2개) const [proportionLoaded, setProportionLoaded] = useState(0); // 로딩된 비율 const [proportionPlayed, setProportionPlayed] = useState(0); // 재생된 비율 ``` ### 2. Import 추가 ```javascript import { MediaSlider, Times, secondsToTime } from '../MediaPlayer'; import DurationFmt from 'ilib/lib/DurationFmt'; import { memoize } from '@enact/core/util'; ``` ### 3. DurationFmt 헬퍼 추가 ```javascript const memoGetDurFmt = memoize( () => new DurationFmt({ length: 'medium', style: 'clock', useNative: false, }) ); const getDurFmt = () => { if (typeof window === 'undefined') return null; return memoGetDurFmt(); }; ``` ### 4. handleUpdate 수정 (proportionLoaded/Played 계산) ```javascript const handleUpdate = useCallback((ev) => { const el = videoRef.current; if (!el) return; const newCurrentTime = el.currentTime || 0; const newDuration = el.duration || 0; setCurrentTime(newCurrentTime); setDuration(newDuration); setPaused(el.paused); setLoading(el.loading || false); setError(el.error || null); setSourceUnavailable((el.loading && sourceUnavailable) || el.error); // 추가: proportion 계산 setProportionLoaded(el.proportionLoaded || 0); setProportionPlayed(newDuration > 0 ? newCurrentTime / newDuration : 0); // 콜백 호출 if (ev.type === 'timeupdate' && onTimeUpdate) { onTimeUpdate(ev); } // ... }, [onTimeUpdate, sourceUnavailable]); ``` ### 5. Slider 이벤트 핸들러 추가 ```javascript const handleSliderChange = useCallback(({ value }) => { const time = value * duration; seek(time); }, [duration, seek]); const handleKnobMove = useCallback((ev) => { if (!videoRef.current) return; const seconds = Math.floor(ev.proportion * videoRef.current.duration); if (!isNaN(seconds)) { // 스크럽 시 시간 표시 업데이트 등 // 필요시 onScrub 콜백 호출 } }, []); const handleSliderKeyDown = useCallback((ev) => { // Spotlight 키 이벤트 처리 // 위/아래 키로 controls 이동 등 }, []); ``` ### 6. Controls UI 수정 ```javascript {/* Modal이 아닐 때만 전체 controls 표시 */} {controlsVisible && !isModal && (
{/* Slider Section */}
{/* Times - 전체 시간 */} {/* Times - 현재 시간 */} {/* MediaSlider */}
{/* Controls Section */}
{onBackButton && ( )}
)} ``` ### 7. CSS 추가 ```less // VideoPlayer.module.less .controlsContainer { position: absolute; bottom: 0; left: 0; right: 0; padding: 20px; background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent); z-index: 10; } .sliderContainer { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; } .controlsButtons { display: flex; gap: 20px; justify-content: center; } ``` --- ## 📊 수정 전/후 비교 ### 현재 MediaPlayer.v2 (문제) ``` Modal 모드 (modal=true): ✅ 오버레이 없음 (정상) ✅ 클릭으로 전환 (정상) Fullscreen 모드 (modal=false): ❌ MediaSlider 없음 (문제!) ❌ Times 없음 (문제!) ✅ Play/Pause 버튼 (정상) ✅ Back 버튼 (정상) ``` ### 수정 후 MediaPlayer.v2 (정상) ``` Modal 모드 (modal=true): ✅ 오버레이 없음 ✅ 클릭으로 전환 Fullscreen 모드 (modal=false): ✅ MediaSlider (seek bar) ✅ Times (현재/전체 시간) ✅ Play/Pause 버튼 ✅ Back 버튼 ``` --- ## 🎯 우선순위 ### High Priority (필수) 1. ✅ **MediaSlider 추가** - 리모컨으로 진행 위치 조정 2. ✅ **Times 컴포넌트 추가** - 시간 표시 3. ✅ **proportionLoaded/Played 상태** - slider 동작 ### Medium Priority (권장) 4. Slider 이벤트 핸들러 세부 구현 5. Spotlight 키 네비게이션 (위/아래로 slider ↔ buttons) 6. CSS 스타일 개선 ### Low Priority (선택) 7. Scrub 시 썸네일 표시 (기존에도 없음) 8. 추가 피드백 UI --- ## 🔧 구현 순서 1. **Phase 1**: 상태 및 import 추가 (10분) 2. **Phase 2**: MediaSlider 렌더링 (20분) 3. **Phase 3**: Times 컴포넌트 추가 (10분) 4. **Phase 4**: 이벤트 핸들러 구현 (20분) 5. **Phase 5**: CSS 스타일 조정 (10분) 6. **Phase 6**: 테스트 및 디버깅 (30분) **총 예상 시간**: 약 1.5시간 --- ## ✅ 체크리스트 - [ ] proportionLoaded, proportionPlayed 상태 추가 - [ ] MediaSlider, Times import - [ ] DurationFmt 헬퍼 추가 - [ ] handleUpdate에서 proportion 계산 - [ ] handleSliderChange 구현 - [ ] handleKnobMove 구현 - [ ] handleSliderKeyDown 구현 - [ ] Controls UI에 slider 추가 - [ ] Times 컴포넌트 추가 - [ ] CSS 스타일 추가 - [ ] Modal 모드에서 slider 숨김 확인 - [ ] Fullscreen 모드에서 slider 표시 확인 - [ ] 리모컨으로 seek 동작 테스트 --- ## 📝 결론 MediaPlayer.v2는 **MediaSlider와 Times가 필수**입니다. 이유: 1. DetailPanel → ProductVideo에서만 사용 2. Fullscreen 모드에서 리모컨 사용자가 비디오 진행 위치를 조정해야 함 3. 현재/전체 시간 표시 필요 **→ "간소화"는 맞지만, "필수 기능 제거"는 아님** **→ MediaSlider는 제거 불가, 단 Modal 모드에서만 조건부 숨김**