Files
shoptime/.docs/MediaPlayer-v2-Required-Changes.md
Claude 64d1e553ed docs: Add MediaPlayer.v2 required changes analysis
MediaPanel 실제 사용 컨텍스트 분석 및 필수 수정 사항 문서화

주요 발견사항:
- DetailPanel → ProductVideo → MediaPanel 사용 패턴 분석
- Modal 모드: 오버레이 없음 (정상)
- Fullscreen 모드: MediaSlider 필수 (누락됨)

필수 수정 사항:
- MediaSlider 추가 (리모컨으로 진행 위치 조정)
- Times 컴포넌트 추가 (현재/전체 시간 표시)
- proportionLoaded/Played 상태 추가
- Slider 이벤트 핸들러 구현

조건부 렌더링:
- Modal 모드 (modal=true): Slider 숨김
- Fullscreen 모드 (modal=false): Slider 표시

예상 작업 시간: 1.5시간
2025-11-10 08:14:53 +00:00

405 lines
9.7 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 && (
<div className={css.simpleControls}>
<button onClick={...}>{paused ? '▶' : '⏸'}</button> // Play/Pause만
<button onClick={onBackButton}> Back</button>
</div>
)}
```
**문제**:
1.**MediaSlider (seek bar) 없음** - 리모컨으로 진행 위치 조정 불가
2.**Times 컴포넌트 없음** - 현재 시간/전체 시간 표시 안 됨
3.**proportionLoaded, proportionPlayed 상태 없음**
---
## ✅ 기존 MediaPlayer.jsx의 올바른 구현
### Modal vs Fullscreen 조건부 렌더링
```javascript
// MediaPlayer.jsx:2415-2461
{noSlider ? null : (
<div className={css.sliderContainer}>
{/* Times - 전체 시간 */}
{this.state.mediaSliderVisible && type ? (
<Times
noCurrentTime
total={this.state.duration}
formatter={durFmt}
type={type}
/>
) : null}
{/* Times - 현재 시간 */}
{this.state.mediaSliderVisible && type ? (
<Times
noTotalTime
current={this.state.currentTime}
formatter={durFmt}
/>
) : null}
{/* MediaSlider - modal이 아닐 때만 표시 */}
{!panelInfo.modal && (
<MediaSlider
backgroundProgress={this.state.proportionLoaded}
disabled={disabled || this.state.sourceUnavailable}
value={this.state.proportionPlayed}
visible={this.state.mediaSliderVisible}
spotlightDisabled={
spotlightDisabled || !this.state.mediaControlsVisible
}
onChange={this.onSliderChange}
onKnobMove={this.handleKnobMove}
onKeyDown={this.handleSliderKeyDown}
// ...
/>
)}
</div>
)}
```
**핵심 조건**:
```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 && (
<div className={css.controlsContainer}>
{/* Slider Section */}
<div className={css.sliderContainer}>
{/* Times - 전체 시간 */}
<Times
noCurrentTime
total={duration}
formatter={getDurFmt()}
type={type}
/>
{/* Times - 현재 시간 */}
<Times
noTotalTime
current={currentTime}
formatter={getDurFmt()}
/>
{/* MediaSlider */}
<MediaSlider
backgroundProgress={proportionLoaded}
disabled={disabled || sourceUnavailable}
value={proportionPlayed}
visible={controlsVisible}
spotlightDisabled={spotlightDisabled}
onChange={handleSliderChange}
onKnobMove={handleKnobMove}
onKeyDown={handleSliderKeyDown}
spotlightId="media-slider-v2"
/>
</div>
{/* Controls Section */}
<div className={css.controlsButtons}>
<button className={css.playPauseBtn} onClick={...}>
{paused ? '▶' : '⏸'}
</button>
{onBackButton && (
<button className={css.backBtn} onClick={onBackButton}>
Back
</button>
)}
</div>
</div>
)}
```
### 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 모드에서만 조건부 숨김**