# Player — Feature Spec (PO View)

> Spec dành cho Product Owner — mô tả **tính năng Player** của AI Music MV Maker (brand "Melix") **theo đúng những gì đã có trong code hiện tại** (branch `feat/pixelplayer-port-redo`).
>
> Player là **trình phát nhạc thống nhất** cho AI-gen songs + nhạc thư viện thiết bị, dạng sheet overlay xuyên suốt app.
>
> ⚠️ **Quy ước:** tài liệu này CHỈ giữ những gì đã wired-UI và chạy thực tế trong code hiện tại. Các tính năng có code nhưng chưa wire UI (Queue sheet, Sleep timer picker, Song Info, Share, Save Queue, Album art carousel, Multi-select queue, Cast, Lyrics, EQ…) tạm bỏ — đợi PO confirm thứ tự enable trước khi đưa vào spec.

Liên quan: [Unified Player Sheet trong spec.md](./spec.md#unified-player-sheet-mini--full--queue).

---

## 1. Mục tiêu sản phẩm

Player là thanh phát nhạc **always-on** dưới đáy app — user nghe AI song vừa tạo hoặc nhạc thư viện thiết bị, vẫn duyệt được tab Create / Library / Settings mà không gián đoạn. Tận dụng codebase PixelPlayer (MIT) để rút ngắn thời gian build.

### Trong scope hiện tại
- Mini player ngang neo trên bottom-nav.
- Full player full-screen với album art + controls cơ bản.
- Sheet states Hidden / Mini / Full với drag-to-expand + predictive back.
- Favorite toggle (đã wired với Favorites repository).
- Persistent across tab swipes.
- Dynamic theme từ album art (opt-in qua remote config).
- External file open (`ExternalPlayerActivity` — VIEW/SEND intent).
- Notification lock-screen + sleep-timer-fires-pause (chạy ngầm qua service).

### Ngoài scope hiện tại
Queue UI sheet, Sleep timer picker, Song Info sheet, Share button, Save Queue, Cast, Lyrics, EQ, Album art carousel, Multi-select trong queue — code đã có ở holder/scoped state nhưng chưa wire UI trigger trong Full player. Sẽ bổ sung sau khi PO chốt thứ tự enable.

---

## 2. User Story chính

> Là user vừa tạo AI song, tôi muốn một thanh player hiện ngay dưới đáy app để play/pause nhanh và mở rộng xem chi tiết — không bị mất khi tôi chuyển tab.

---

## 3. Trạng thái Player Sheet — minh hoạ

Player có **3 state chính**. Layout đơn giản:

### 3.1 Hidden — chưa có bài nào / user swipe-dismiss

```
 ┌────────────────────────────────────┐
 │                                    │
 │                                    │
 │         Library / Create /         │
 │           Settings tab             │
 │                                    │
 │                                    │
 │                                    │
 ├────────────────────────────────────┤
 │  ⌂ Home    🎵 Library    ⚙ Setting │   ← bottom-nav (không có sheet)
 └────────────────────────────────────┘
```

### 3.2 Mini — bài đang phát, sheet collapsed

```
 ┌────────────────────────────────────┐
 │                                    │
 │         Library / Create /         │
 │           Settings tab             │
 │                                    │
 │                                    │
 │ ┌────────────────────────────────┐ │
 │ │ ▢▢▢  Bài hát đang phát   ▶/⏸ │ │   ← Mini ~72dp, neo trên nav
 │ │      Tên nghệ sĩ              │ │     gradient brand blue fade →
 │ └────────────────────────────────┘ │
 │ ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ │   ← hairline progress 1px
 ├────────────────────────────────────┤
 │  ⌂ Home    🎵 Library    ⚙ Setting │
 └────────────────────────────────────┘

 Tương tác:
   • Tap card → expand Full
   • Kéo dọc lên >40dp → expand
   • Vuốt ngang quá ngưỡng → dismiss (Hidden, nhạc vẫn phát ngầm)
```

### 3.3 Full — full-screen player

```
 ┌────────────────────────────────────┐
 │  ⌄        Playing from album       │   ← TopBar:
 │              [tên album]      ♡    │     ⌄ collapse | album | ♡ favorite
 │                                    │
 │         ╔════════════════╗         │
 │         ║                ║         │
 │         ║                ║         │
 │         ║   Album art    ║         │   ← Hero 280dp (TĨNH, không carousel)
 │         ║   280 x 280    ║         │
 │         ║                ║         │
 │         ║                ║         │
 │         ╚════════════════╝         │
 │                                    │
 │           Tên bài hát              │   ← TitleBlock (marquee 1 dòng)
 │            Tên artist              │
 │                                    │
 │  ∿∿∿∿∿●━━━━━━━━━━━━━━━━━━━━━━━━━  │   ← WavyMusicSlider
 │  01:23                       03:45 │     (sóng khi play, thẳng khi pause)
 │                                    │
 │     ⤨      ⏮      ●▶      ⏭     ↻ │   ← MainControls (5 nút):
 │  Shuffle  Prev  Play/Pause Next Rep│     shuffle / prev / play / next /
 │                                    │     repeat (off → all → one)
 │                                    │
 │ Background: gradient brand blue    │
 │ (radial center top), hoặc dynamic  │
 │ palette từ album art (nếu          │
 │ enable_dynamic_palette = true)     │
 └────────────────────────────────────┘

 Tương tác:
   • Tap ⌄ → collapse Mini
   • Kéo dọc xuống → collapse smooth theo finger
   • Bấm back (Android 14+): preview gesture co dần Full→Mini
   • Tap ♡ → toggle favorite (gọi FavoritesRepository)
   • Drag slider → seek
```

### 3.4 External Player — Activity riêng

```
 ┌────────────────────────────────────┐
 │ (Không có MonetizeD7 splash,       │
 │  không có 3-tab shell)             │
 │                                    │
 │         ╔════════════════╗         │
 │         ║                ║         │
 │         ║   Album art    ║         │
 │         ║                ║         │
 │         ╚════════════════╝         │
 │                                    │
 │       Tên file mp3 vừa mở          │
 │                                    │
 │   ━━━━━━●━━━━━━━━━━━━━━━━━━━━━━   │
 │                                    │
 │       [ Mở trong Melix ]           │
 │       [ Đóng ]                     │
 └────────────────────────────────────┘

 Khi nào hiển thị:
   • User chọn file mp3 từ Files app → "Open with Melix"
   • User Share file mp3 từ app khác → chọn Melix
 Bypass: splash + 3-tab shell. Granted FLAG_GRANT_READ_URI_PERMISSION.
```

---

## 4. Entry points (đã wired)

| Trigger | Hành vi |
|---|---|
| Tap song row trong Library | `openSongById` → build queue từ tất cả AI-gen songs → auto-show Mini |
| Tap nút Play trong VideoResult / AI-gen result | `playItem(item)` → auto-show Mini |
| Tap mini card | Mini → Full |
| Kéo mini dọc lên >40dp | Mini → Full |
| Vuốt ngang mini quá ngưỡng | Dismiss (Hidden, nhạc tiếp tục) |
| Tap ⌄ trong Full | Full → Mini |
| Bấm back (Android 14+) | Predictive back — preview Full→Mini theo gesture |
| Bấm back (Android <14) | Instant collapse Full → Mini |
| Tap ♡ favorite | Toggle FavoritesRepository, icon update |
| Drag slider | Seek (optimistic UI + audio seek) |
| Tap controls (shuffle/prev/play/next/repeat) | Delegate xuống AudioController |
| Vào Create / Preview MV (`stopAndHide()`) | Auto pause + hide. Tap focused song lại → repromote |
| Mở file mp3 từ Files / Share sheet | `ExternalPlayerActivity` overlay (bypass splash) |
| Tap notification (lock-screen) | Mở MainActivity, sheet ở state hiện tại |
| Sleep timer hết giờ (qua service ngầm) | Service auto pause, sheet giữ Mini |

---

## 5. Màn hình chi tiết

### S1 — Hidden
Sheet không render, không chiếm pixel. Bottom-nav sát đáy bình thường.

### S2 — Mini player (~72dp)
- **Layout** (trái → phải): album art vuông 56dp + title (1 dòng, truncate) + artist (1 dòng) + nút play/pause.
- Background card solid `#1A1A1A`.
- Gradient brand blue subtle lan từ phải (alpha fade → 0 khi expand).
- Hairline border 1dp, fade khi expand.
- Hairline progress bar 1px dưới đáy card theo % bài.
- Shadow 3dp (tắt khi queue mở hoặc expand > 18%).
- Corner radius 14dp → 0dp khi expand.
- Tap toàn card → expand. Kéo dọc lên → expand smooth. Vuốt ngang → dismiss.

### S3 — Full player
- **Background**: radial gradient brand blue (center top, fade về `#020202` ở 70%) hoặc dynamic palette từ album art nếu remote config `enable_dynamic_palette = true`.
- **TopBar**: ⌄ collapse (trái) | "Playing from album" + tên album (giữa) | ♡ favorite (phải).
- **Hero**: Album art **TĨNH** 280×280dp với corner 20dp (CHƯA có carousel/HorizontalPager).
- **TitleBlock**: title (subtitle bold, basicMarquee 1 dòng) + artist (caption regular, marquee 1 dòng).
- **SeekRow**: `WavyMusicSlider` (sóng nhấp nhô khi play, thẳng khi pause) + time current / total. Drag = optimistic UI; release = commit seek.
- **MainControls** (5 nút ngang): Shuffle | Previous | Play-Pause (big circle) | Next | Repeat (cycle OFF → ALL → ONE).

### S4 — External Player overlay
- Activity riêng, không qua splash.
- Compact UI: album art + tên file + slider + nút "Open in app" / "Close".

### S5 — Predictive Back (Android 14+)
- User kéo gesture back từ cạnh → sheet co dần Full → Mini theo finger (preview).
- Release qua ngưỡng → commit Mini; dưới ngưỡng → snap về Full.
- Android <14: back = instant collapse.

---

## 6. Scenarios chính

### 6.1 First play in session (Happy)
**Given** chưa phát bài nào (Hidden), **When** tap row đầu Library, **Then** sheet slide-up Hidden → Mini + play.

### 6.2 Expand (Happy)
**Given** Mini visible, **When** tap card / kéo lên >40dp, **Then** animate Mini → Full.

### 6.3 Favorite toggle (Happy)
**Given** Full mở, **When** tap ♡, **Then** Favorites DB cập nhật, icon đổi (outline ↔ filled đỏ).

### 6.4 Seek (Happy)
**Given** Full mở, **When** drag slider thumb, **Then** UI follow finger real-time; release → commit seek.

### 6.5 Skip via button (Happy)
**Given** Full mở, queue ≥2 bài, **When** tap ⏭, **Then** play bài kế.

### 6.6 Shuffle/Repeat (Happy)
**Given** Full mở, **When** tap shuffle / repeat, **Then** mode cycle (off / all / one), AudioController update.

### 6.7 Tab swipe persistence (Happy)
**Given** Mini visible đang phát, **When** vuốt sang tab Create, **Then** Mini vẫn ở đó, nhạc tiếp tục.

### 6.8 Generation flow handover (Happy)
**Given** đang nghe AI song A, **When** vào CreateSong, **Then** auto `pause + hide`. Về Library tap A lại → repromote + resume.

### 6.9 Predictive back (Happy, Android 14+)
**Given** Full mở, **When** kéo gesture back từ cạnh, **Then** sheet co dần theo finger; release qua ngưỡng → Mini.

### 6.10 Mini swipe-dismiss (Happy)
**Given** Mini visible, **When** vuốt ngang quá ngưỡng, **Then** Mini → Hidden, nhạc tiếp tục ngầm.

### 6.11 Re-tap focused song (Edge)
**Given** Mini visible với bài A đang play, **When** tap row A lần nữa, **Then** **no-op** (không restart).

### 6.12 Re-tap khi sheet Hidden (Edge)
**Given** sheet Hidden (vừa swipe-dismiss) nhưng bài A vẫn ở currentItem, **When** tap row A, **Then** repromote sheet → Mini + resume.

### 6.13 External file open (Happy)
**Given** user chọn "Mở bằng Melix" từ Files app, **When** Activity nhận intent, **Then** `ExternalPlayerActivity` overlay compact, play ngay.

### 6.14 Notification controls (Happy)
**Given** đang play, **When** lock màn hình, **Then** notification hiện play/pause/next với artwork. Tap notification → mở MainActivity.

### 6.15 Connectivity error (Edge)
**Given** đang play streaming, mạng yếu, **When** ExoPlayer error, **Then** ConnectivityStateHolder phát hiện offline; (UI surface defer — chỉ holder ready).

### 6.16 Process killed (Edge)
**Given** đang phát, **When** process killed, **Then** service foreground giữ playback; nếu service cũng bị kill → lần mở lại sheet Hidden + queue trống.
