diff --git a/.docs/MediaPlayer-v2-Required-Changes.md b/.docs/MediaPlayer-v2-Required-Changes.md new file mode 100644 index 00000000..b4469eef --- /dev/null +++ b/.docs/MediaPlayer-v2-Required-Changes.md @@ -0,0 +1,404 @@ +# 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 모드에서만 조건부 숨김**