Skip to content

PrezelPlayer 디자인 시스템 구현#129

Merged
HamBeomJoon merged 15 commits into
developfrom
feat/#125-ds-player
May 11, 2026
Merged

PrezelPlayer 디자인 시스템 구현#129
HamBeomJoon merged 15 commits into
developfrom
feat/#125-ds-player

Conversation

@HamBeomJoon
Copy link
Copy Markdown
Contributor

@HamBeomJoon HamBeomJoon commented May 7, 2026

📌 작업 내용

  • 디자인시스템에 PrezelPlayer 컴포넌트 추가
  • 재생/일시정지, 이전/다음 이동, 탭/드래그 seek 지원
  • 외부에서 재생 상태, 현재 위치, 전체 길이, seek 이벤트를 제어하는 controlled state 구조 적용
  • 드래그 중 외부 currentMillis 업데이트로 핸들이 스냅백되지 않도록 상태 동기화 보정

타임라인/리소스 트랙

  • 현재 시간/전체 시간 라벨 표시
  • idle 상태 및 드래그 핸들 노출 상태 지원
  • PrezelPlayerItem을 Segment/Marker sealed 모델로 구성
  • 모든 item은 이전/다음 이동 대상이며, Marker만 타임라인 마커로 표시

마커/리소스

  • GOOD, WARNING, NEUTRAL 마커 타입 및 표시 UI 추가
  • 뒤로/앞으로 이동 아이콘 drawable 추가
  • PrezelIcons에 SkipBackward, SkipForward 등록

🧩 관련 이슈


📸 스크린샷

스크린샷 2026-05-07 15 55 09 스크린샷 2026-05-07 15 56 18 스크린샷 2026-05-07 15 56 09
  • 영상
2026-05-07.22.25.20.mov

Summary by CodeRabbit

  • 새로운 기능
    • 재생/일시정지, 이전/다음 버튼을 포함한 새로운 플레이어 UI 추가
    • 드래그 가능한 타임라인과 핸들, 진행률 표시 및 마커/세그먼트 시각화 지원
    • 플레이어 상태 관리(재생 상태, 위치, 항목 목록) 및 저장/복원 지원 추가
    • 이전/다음 아이콘과 플레이어 관련 접근성 문자열(한국어) 추가
    • 미리보기(Preview) UI로 재생 동작 및 마커 표시 예시 제공

Review Change Stack

* **feat: `PrezelPlayer` 및 관련 컴포넌트 추가**
    * 재생/일시정지, 전/후 이동 제어 및 프로그레스 바를 포함한 `PrezelPlayer` 컴포넌트를 구현했습니다.
    * `PrezelPlayerResourceTrack`: 재생 진행 상태, 시간 표시, 마커(Marker) 표시 및 탐색(Seek) 기능을 지원하는 트랙 컴포넌트를 추가했습니다.
    * `PrezelPlayerResourceMarker`: 트랙 위에 표시될 상태 마커(`GOOD`, `WARNING`, `NEUTRAL`) 컴포넌트를 추가했습니다.

* **feat: 플레이어 제어용 아이콘 및 데이터 모델 추가**
    * `PrezelIcons`: `SkipBackward`, `SkipForward` 아이콘 리소스를 추가하고 등록했습니다.
    * `PrezelPlayerResourceMarkerItem`: 트랙의 마커 데이터를 정의하기 위한 sealed 구조의 모델과 팩토리 메서드(`speech`, `scriptMatch`)를 추가했습니다.
    * `PrezelPlayerResourceTrackType`: 음성(`SPEECH`) 및 대본 일치(`SCRIPT_MATCH`) 트랙 타입을 정의하는 열거형을 추가했습니다.

* **refactor: 플레이어 UI 스타일 및 인터랙션 구현**
    * 터치 및 드래그 제스처를 통한 재생 위치 탐색(Seek) 로직을 적용했습니다.
    * `playing` 상태에 따라 재생/일시정지 버튼의 색상 및 아이콘이 동적으로 변경되도록 구현했습니다.
    * 밀리초(Long) 단위를 `mm:ss` 형식으로 변환하는 `formatPlayerTime` 확장 함수를 추가했습니다.
* **feat: `PrezelPlayer` 및 관련 컴포넌트 추가**
    * 재생/일시정지, 전/후 이동 제어 및 프로그레스 바를 포함한 `PrezelPlayer` 컴포넌트를 구현했습니다.
    * `PrezelPlayerResourceTrack`: 재생 진행 상태, 시간 표시, 마커(Marker) 표시 및 탐색(Seek) 기능을 지원하는 트랙 컴포넌트를 추가했습니다.
    * `PrezelPlayerResourceMarker`: 트랙 위에 표시될 상태 마커(`GOOD`, `WARNING`, `NEUTRAL`) 컴포넌트를 추가했습니다.

* **feat: 플레이어 제어용 아이콘 및 데이터 모델 추가**
    * `PrezelIcons`: `SkipBackward`, `SkipForward` 아이콘 리소스를 추가하고 등록했습니다.
    * `PrezelPlayerResourceMarkerItem`: 트랙의 마커 데이터를 정의하기 위한 sealed 구조의 모델과 팩토리 메서드(`speech`, `scriptMatch`)를 추가했습니다.
    * `PrezelPlayerResourceTrackType`: 음성(`SPEECH`) 및 대본 일치(`SCRIPT_MATCH`) 트랙 타입을 정의하는 열거형을 추가했습니다.

* **refactor: 플레이어 UI 스타일 및 인터랙션 구현**
    * 터치 및 드래그 제스처를 통한 재생 위치 탐색(Seek) 로직을 적용했습니다.
    * `playing` 상태에 따라 재생/일시정지 버튼의 색상 및 아이콘이 동적으로 변경되도록 구현했습니다.
    * 밀리초(Long) 단위를 `mm:ss` 형식으로 변환하는 `formatPlayerTime` 확장 함수를 추가했습니다.
-ds-player

# Conflicts:
#	Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayer.kt
#	Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceTrack.kt
*   **feat: 플레이어 데이터 모델 및 마커 인터페이스 정의**
    *   `PrezelPlayerResourceMarkerItem` sealed interface를 추가하여 `Speech`와 `ScriptMatch` 트랙 마커를 구분하고, `timeSeconds` 기반으로 위치를 계산하도록 개선했습니다.
    *   마커 타입(`GOOD`, `WARNING`, `NEUTRAL`) 및 트랙 타입(`SPEECH`, `SCRIPT_MATCH`)을 정의하는 Enum 클래스들을 추가했습니다.

*   **refactor: `PrezelPlayer` 및 관련 컴포넌트 구조 개선**
    *   `PrezelPlayerResourceTrack`: 외부에서 `progress`를 주입받는 대신 `currentMillis`와 `durationMillis`를 통해 내부에서 계산하도록 로직을 변경했습니다.
    *   `PrezelPlayerTimeline`: 타임라인 로직을 별도 컴포넌트로 분리하고, 드래그/탭 제스처를 통한 탐색(Seek) 및 마커 렌더링 로직을 통합했습니다.
    *   컴포넌트 내부에 흩어져 있던 Preview 코드들을 `PrezelPlayerPreview.kt`로 분리하여 관리 효율성을 높였습니다.

*   **feat: 접근성(Accessibility) 및 다국어 지원 추가**
    *   재생, 일시정지, 앞/뒤로 이동 버튼 및 각 트랙 타임라인에 대한 `contentDescription`을 추가했습니다.
    *   `strings.xml`에 플레이어 조작 및 트랙 설명 관련 리소스를 정의했습니다.

*   **fix: 플레이어 로직 안정화**
    *   시간 표시 포맷팅 로직(`formatPlayerTime`) 및 재생 시간 제한(`coercePlayerMillis`) 유틸리티 함수를 추가했습니다.
    *   `progress` 계산 시 0으로 나누기(Division by zero) 방지 로직을 적용했습니다.
@HamBeomJoon HamBeomJoon self-assigned this May 7, 2026
@HamBeomJoon HamBeomJoon requested a review from moondev03 as a code owner May 7, 2026 06:57
@HamBeomJoon HamBeomJoon added the ✨ feat 새로운 기능 추가 또는 기존 기능 확장 label May 7, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Warning

Rate limit exceeded

@HamBeomJoon has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 40 minutes and 25 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4b9af873-fd7f-40a9-9339-5831fd5ddfff

📥 Commits

Reviewing files that changed from the base of the PR and between 1e8a5b3 and 4722cfb.

📒 Files selected for processing (2)
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayer.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt
📝 Walkthrough

Walkthrough

플레이어 디자인 시스템을 구현합니다. 데이터 모델(Segment, Marker), 마커 렌더링, 타임라인(탭/드래그/접근성), 트랙 UI, Compose 상태(PrezelPlayerState), 공개 PrezelPlayer 컴포저블 및 관련 리소스를 추가합니다.

플레이어 디자인 시스템

Layer / File(s) Summary
데이터 모델 및 열거형
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerModels.kt
PrezelPlayerMarkerType 열거형과 sealed PrezelPlayerItem, Segment, Marker 불변 데이터 클래스를 추가합니다.
마커 시각화 컴포넌트
Prezel/core/designsystem/src/main/java/com/team/prezel.core/designsystem/component/player/PrezelPlayerResourceMarker.kt
타입별 색상 매핑과 8dp clipped Box를 렌더링하는 내부 PrezelPlayerResourceMarker 컴포저블과 미리보기를 추가합니다.
타임라인 핵심 로직
Prezel/core/designsystem/src/main/java/com/team/prezel.core/designsystem/component/player/PrezelPlayerTimeline.kt
너비 측정, 포인터 X→정규화 progress, 탭/드래그 시크(포인터 소비), 접근성 setProgress, 마커 위치 계산, 진행도 오버레이 및 드래그 핸들 렌더링을 구현합니다.
타임라인 미리보기 및 샘플 데이터
Prezel/core/designsystem/src/main/java/com/team/prezel.core/designsystem/component/player/PrezelPlayerTimeline.kt
여러 구성(played bar, drag handle, overlapping markers) 미리보기와 샘플 아이템 리스트를 제공합니다.
트랙 리소스 컴포넌트
Prezel/core/designsystem/src/main/java/com/team/prezel.core/designsystem/component/player/PrezelPlayerResourceTrack.kt
40dp 높이의 트랙(타임라인 + mm:ss 레이블), idle 기반 표시 제어, onDragStarted/onDragStopped 콜백을 포함한 PrezelPlayerResourceTrack를 추가합니다.
플레이어 상태 홀더
Prezel/core/designsystem/src/main/java/com/team/prezel.core/designsystem/component/player/PrezelPlayerState.kt
Compose 기반 PrezelPlayerStaterememberPrezelPlayerState를 추가하고, 시크/이전-다음 이동/재생 토글/드래그 제어와 Saver를 구현합니다.
플레이어 UI 컴포저블
Prezel/core/designsystem/src/main/java/com/team/prezel.core/designsystem/component/player/PrezelPlayer.kt
공개 PrezelPlayer와 내부 PrezelPlayerContent/TrackSection/Controls/Buttons를 구현하고 상태의 값과 콜백을 연결하며 미리보기를 포함합니다.
아이콘 및 리소스
Prezel/core/designsystem/src/main/java/com/team/prezel.core/designsystem/icon/PrezelIcons.kt, Prezel/core/designsystem/src/main/res/drawable/core_designsystem_ic_backward.xml, Prezel/core/designsystem/src/main/res/drawable/core_designsystem_ic_forward.xml, Prezel/core/designsystem/src/main/res/values/strings.xml
PrezelIconsSkipBackward/SkipForward를 추가하고 두 벡터 드로어블과 플레이어 접근성 문자열 6개를 추가합니다.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목 'PrezelPlayer 디자인 시스템 구현'은 변경사항의 주요 내용을 명확하고 간결하게 요약하고 있습니다.
Description check ✅ Passed PR 설명에서 작업 내용, 관련 이슈, 스크린샷과 영상이 포함되어 있으며 템플릿의 주요 섹션을 충족하고 있습니다.
Linked Issues check ✅ Passed 코드 변경사항이 #125의 요구사항을 모두 충족합니다: PrezelPlayer 컴포넌트 구현, 재생/일시정지/이전/다음 제어, 외부 제어 가능한 상태, 타임라인 리소스 마커, 탭/드래그 seek, 현재/전체 시간 라벨, idle 상태 및 드래그 핸들 지원이 모두 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #125 요구사항의 범위 내에 있습니다: 아이콘 리소스, 문자열 리소스, 마커 타입과 모델은 모두 구현의 필수 부분입니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@HamBeomJoon HamBeomJoon changed the title Feat/#125 ds player PrezelPlayer 디자인 시스템 구현 May 7, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerModels.kt (1)

5-21: 💤 Low value

enum class@Immutable 적용은 불필요합니다.

Compose 컴파일러는 enum 클래스를 별도 어노테이션 없이 이미 안정적(stable)으로 추론합니다. sealed class/interface 및 그 구현체(data class)에 대한 @Immutable 적용은 의미가 있지만, enum에 적용하는 것은 불필요한 noise입니다.

♻️ 제안: enum의 불필요한 어노테이션 제거
-@Immutable
 enum class PrezelPlayerResourceTrackType {
     SPEECH,
     SCRIPT_MATCH,
 }

-@Immutable
 enum class PrezelSpeechMarkerType {
     GOOD,
     WARNING,
 }

-@Immutable
 enum class PrezelScriptMatchMarkerType {
     GOOD,
     NEUTRAL,
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerModels.kt`
around lines 5 - 21, Remove unnecessary `@Immutable` annotations from enum
classes: PrezelPlayerResourceTrackType, PrezelSpeechMarkerType, and
PrezelScriptMatchMarkerType; the Compose compiler treats enums as stable so
simply delete the `@Immutable` annotation usages on those enum class declarations
(leave sealed/interface implementations and data classes untouched).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerTimeline.kt`:
- Around line 51-53: 현재 ::seekTo 로컬 함수 참조와 onDragStarted/onDragStopped 같은 인라인
람다가 재컴포지션마다 새 객체가 되어 pointerInput 키 변경 시 코루틴이 취소되는 문제가 있습니다; 고정된 키(Unit)를 사용하도록
playerTimelineModifier 안의 pointerInput 호출을 변경하고 PrezelPlayerTimeline 내부에서
seekTo, onDragStarted, onDragStopped, onHorizontalDrag 등 외부 콜백들을
rememberUpdatedState로 래핑한 최신 상태 참조로 만든 뒤 그 래핑된 값들을 modifier에 전달해 pointerInput
코루틴이 재시작되지 않도록 수정하세요 (참조 심볼: seekTo, onSeek, onDragStarted, onDragStopped,
onHorizontalDrag, playerTimelineModifier, pointerInput, rememberUpdatedState).

---

Nitpick comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerModels.kt`:
- Around line 5-21: Remove unnecessary `@Immutable` annotations from enum classes:
PrezelPlayerResourceTrackType, PrezelSpeechMarkerType, and
PrezelScriptMatchMarkerType; the Compose compiler treats enums as stable so
simply delete the `@Immutable` annotation usages on those enum class declarations
(leave sealed/interface implementations and data classes untouched).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 39035c60-099f-45c1-bbcc-3082381543dd

📥 Commits

Reviewing files that changed from the base of the PR and between 5f473d7 and c4713e0.

📒 Files selected for processing (9)
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayer.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerModels.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceMarker.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceTrack.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerTimeline.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/icon/PrezelIcons.kt
  • Prezel/core/designsystem/src/main/res/drawable/core_designsystem_ic_backward.xml
  • Prezel/core/designsystem/src/main/res/drawable/core_designsystem_ic_forward.xml
  • Prezel/core/designsystem/src/main/res/values/strings.xml

* **refactor: 불필요한 `@Immutable` 어노테이션 제거**
    * `enum class`는 기본적으로 불변(Immutable)으로 취급되므로, `PrezelPlayerResourceMarkerType`, `PrezelPlayerResourceTrackType`, `PrezelSpeechMarkerType`, `PrezelScriptMatchMarkerType`에 선언된 중복 어노테이션을 삭제했습니다.

* **fix: `PrezelPlayerTimeline` 드래그 및 탭 이벤트 핸들링 개선**
    * `pointerInput` 내에서 외부 상태 참조 시 람다 캡처로 인한 부작용을 방지하기 위해 `rememberUpdatedState`를 적용했습니다.
    * `pointerInput`의 key를 `Unit`으로 설정하여 불필요한 코루틴 재실행을 방지하고, 최신 콜백(`onSeekTo`, `onDragStarted`, `onDragStopped`)을 안전하게 호출하도록 수정했습니다.
    * `playerTimelineModifier` 확장 함수에 `@Composable` 어노테이션을 추가했습니다.
* **feat: PrezelPlayerState 및 Hoisting 로직 추가**
    * 재생 상태(`playing`), 재생 시간(`currentMillis`), 전체 길이(`durationMillis`), 아이템 목록(`items`) 등을 통합 관리하는 `PrezelPlayerState` 클래스를 추가했습니다.
    * `rememberPrezelPlayerState`를 통해 Compose 생기주기에 맞게 상태를 보존하고, `SideEffect`를 사용하여 외부 상태 변화를 동기화합니다.
    * 드래그 상태 관리(`dragging`) 및 이전/다음 아이템 이동 가능 여부(`previousEnabled`, `nextEnabled`) 판단 로직을 포함합니다.

* **refactor: 플레이어 컨트롤러 및 네비게이션 로직 개선**
    * 단순히 앞/뒤로 이동하던 로직을 `PrezelPlayerItem` 기반의 '이전/다음 아이템' 이동 로직으로 고도화했습니다.
    * `PrezelPlayer` 컴포넌트가 `PrezelPlayerState`를 주입받아 동작하도록 구조를 변경했습니다.
    * `PrezelIconButton`에 `enabled` 상태를 적용하여 이동 가능 여부에 따라 버튼 활성화 상태가 시각적으로 표시되도록 개선했습니다.

* **refactor: 데이터 모델 단순화 및 마커 시스템 개편**
    * `PrezelPlayerResourceMarkerItem`을 `sealed interface`에서 단일 `data class`로 통합하여 관리 효율성을 높였습니다.
    * `PrezelSpeechMarkerType`, `PrezelScriptMatchMarkerType`으로 분리되어 있던 마커 타입을 `PrezelPlayerResourceMarkerType`으로 단일화했습니다.

* **docs: Preview 및 리소스 문자열 업데이트**
    * `BasicPreview` 어노테이션을 적용하고, 상태 기반의 플레이어 동작을 확인할 수 있도록 Preview 코드를 보강했습니다.
    * 플레이어 컨트롤러 관련 접근성 설명(Content Description)을 '뒤로/앞으로'에서 '이전/다음 아이템'으로 수정했습니다.
인증 관련 도메인 레이어의 구성 요소들을 삭제했습니다. (기존 로직의 위치 이동 또는 구조 재설계로 인한 정리)

*   **`AuthRepository` 인터페이스 삭제**
    *   로그인 상태 확인(`loginStatus`), 로그인/로그아웃 및 회원 탈퇴 메서드 정의가 포함된 인터페이스를 제거했습니다.

*   **인증 관련 UseCase 클래스 삭제**
    *   `CheckLoginStatusUseCase`: 로그인 상태 구독 로직 제거
    *   `LoginUseCase`: ID 토큰 기반 서버 로그인 호출 로직 제거
    *   `LogoutUseCase`: 로그아웃 요청 처리 로직 제거
    *   `WithdrawUseCase`: 회원 탈퇴 요청 처리 로직 제거
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceTrack.kt`:
- Around line 42-58: The Column is using a fixed height(40.dp) which can
compress PrezelPlayerTimeline when system font scale increases; update the
Column modifier (around where PrezelPlayerTimeline and PlayerTrackTimeLabels are
composed) to either use wrapContentHeight() or heightIn(min = 40.dp) so the
timeline gets a guaranteed tappable height (or alternately make the time label
use a non-scale font size), ensuring PrezelPlayerTimeline and its drag handle
(and PlayerTrackTimeLabels) are not reduced to ~0dp.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt`:
- Around line 123-133: update() unconditionally overwrites this.currentMillis on
every SideEffect call which causes the seek handle to snap back while the user
is dragging; change PrezelPlayerState.update to avoid updating
this.currentMillis when dragging is true (i.e., only set this.currentMillis =
currentMillis.coercePlayerMillis(this.durationMillis) if the instance's dragging
flag is false), while still updating playing, durationMillis (coerced), and
items as before so external updates don't disturb the UI during a drag.

In
`@Prezel/core/domain/src/main/java/com/team/prezel/core/domain/repository/auth/AuthRepository.kt`:
- Around line 7-15: There are two conflicting AuthRepository interfaces (one
defines loginStatus, login, logout, withdraw in AuthRepository.kt and the other
defines hasJwtToken() and clearSession() in the Kotlin version); pick a single
canonical API and eliminate the duplicate: either delete the Java AuthRepository
file and keep the Kotlin interface, or merge the APIs into one AuthRepository
that includes all required members (loginStatus, login(idToken), logout(),
withdraw(reason), hasJwtToken(), clearSession()) and remove the other file;
update all call sites to the unified interface so only one AuthRepository type
remains in the codebase.

In
`@Prezel/core/domain/src/main/java/com/team/prezel/core/domain/usecase/auth/CheckLoginStatusUseCase.kt`:
- Around line 17-21: There is a redeclaration conflict for the class
CheckLoginStatusUseCase — locate the existing declaration(s) of
CheckLoginStatusUseCase (and other auth usecases) in the module (the validation
script used in the LogoutUseCase review can help identify duplicate file
locations) and either remove the older/duplicate file or replace it with this
new implementation so only one CheckLoginStatusUseCase class exists; ensure your
fix resolves the Redeclaration error and run the build/validation script to
confirm duplicates are gone.

In
`@Prezel/core/domain/src/main/java/com/team/prezel/core/domain/usecase/auth/LoginUseCase.kt`:
- Around line 15-19: LoginUseCase is declared more than once causing a
Redeclaration build error; locate all duplicate declarations (e.g.,
LoginUseCase, similar to previously flagged WithdrawUseCase and LogoutUseCase
duplicates) and remove or consolidate them so only a single LoginUseCase class
remains, ensuring any required logic from duplicates is merged into that one
declaration and imports/DI bindings are updated accordingly.

In
`@Prezel/core/domain/src/main/java/com/team/prezel/core/domain/usecase/auth/LogoutUseCase.kt`:
- Around line 14-18: There are duplicate class declarations (LogoutUseCase,
LoginUseCase, CheckLoginStatusUseCase, WithdrawUseCase) present in both the java
and kotlin source trees; remove the redundant copies so each use-case class is
defined only once and keep the implementation in a single source directory
(either the Java file under core/domain/src/main/java or the Kotlin file under
core/domain/src/main/kotlin), then verify no remaining references/imports point
to the deleted path and run a build to ensure the single remaining classes
(e.g., LogoutUseCase, LoginUseCase, CheckLoginStatusUseCase, WithdrawUseCase)
compile cleanly.

In
`@Prezel/core/domain/src/main/java/com/team/prezel/core/domain/usecase/auth/WithdrawUseCase.kt`:
- Around line 15-19: There is a redeclaration of WithdrawUseCase causing CI
Redeclaration errors; locate all occurrences of the class named WithdrawUseCase
(same pattern as LogoutUseCase, LoginUseCase, CheckLoginStatusUseCase) and
remove or consolidate duplicates so only a single declaration remains, ensuring
the remaining class keeps the same constructor signature (`@Inject`
constructor(private val authRepository: AuthRepository)) and operator fun
invoke(reason: WithdrawReason): Result<Unit> signature; if the duplicate came
from a copy-paste file, delete the extra file or rename the duplicate class to a
unique name and update any callers accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b46907e2-cc6a-4947-ae77-30b25d769fd8

📥 Commits

Reviewing files that changed from the base of the PR and between c4713e0 and a4e030d.

📒 Files selected for processing (12)
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayer.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerModels.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceMarker.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceTrack.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerTimeline.kt
  • Prezel/core/designsystem/src/main/res/values/strings.xml
  • Prezel/core/domain/src/main/java/com/team/prezel/core/domain/repository/auth/AuthRepository.kt
  • Prezel/core/domain/src/main/java/com/team/prezel/core/domain/usecase/auth/CheckLoginStatusUseCase.kt
  • Prezel/core/domain/src/main/java/com/team/prezel/core/domain/usecase/auth/LoginUseCase.kt
  • Prezel/core/domain/src/main/java/com/team/prezel/core/domain/usecase/auth/LogoutUseCase.kt
  • Prezel/core/domain/src/main/java/com/team/prezel/core/domain/usecase/auth/WithdrawUseCase.kt
✅ Files skipped from review due to trivial changes (1)
  • Prezel/core/designsystem/src/main/res/values/strings.xml
🚧 Files skipped from review as they are similar to previous changes (3)
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceMarker.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerModels.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayer.kt

@Team-Prezel Team-Prezel deleted a comment from coderabbitai Bot May 7, 2026
@Team-Prezel Team-Prezel deleted a comment from coderabbitai Bot May 7, 2026
@Team-Prezel Team-Prezel deleted a comment from coderabbitai Bot May 7, 2026
@Team-Prezel Team-Prezel deleted a comment from coderabbitai Bot May 7, 2026
@Team-Prezel Team-Prezel deleted a comment from coderabbitai Bot May 7, 2026
* **feat: `PrezelPlayerItem` Sealed Interface 도입 및 모델 통합**
    * 기존의 `PrezelPlayerItem`과 `PrezelPlayerResourceMarkerItem`으로 분리되어 있던 모델을 `PrezelPlayerItem` 인터페이스 아래 `Segment`와 `Marker`로 통합했습니다.
    * 마커 타입을 정의하던 `PrezelPlayerResourceMarkerType`을 `PrezelPlayerMarkerType`으로 변경했습니다.
    * 기존 `PrezelPlayerResourceTrackType`에 의존하던 로직을 제거하고, `trackContentDescription`을 외부에서 주입받도록 유연하게 개선했습니다.

* **refactor: 플레이어 상태 관리 및 탐색 로직 개선**
    * `PrezelPlayerState`: 드래그 중일 때 `currentMillis` 업데이트 방식을 수정하여 탐색 중 화면 끊김 현상을 개선했습니다.
    * `PrezelPlayerState`: `currentItemIndex` 계산 시 `startMillis` 대신 통합된 `timeMillis` 필드를 사용하도록 변경했습니다.
    * `PrezelPlayerTimeline`: 마커 표시 로직에서 `PrezelPlayerItem.Marker` 타입만 필터링하여 렌더링하도록 수정했습니다.

* **ui: 디자인 시스템 컴포넌트 레이아웃 조정**
    * `PrezelPlayerResourceTrack`: 고정 높이(`height`) 대신 `heightIn(min = 40.dp)`을 사용하여 유연성을 높였습니다.
    * `PrezelPlayerTimeline`: 타임라인 내 Played Bar와 Drag Handle의 z-index 및 배치 로직을 최적화했습니다.

* **test: 미리보기(Preview) 데이터 및 컴포넌트 업데이트**
    * 변경된 `PrezelPlayerItem` 구조에 맞춰 `previewSpeechItems`, `previewScriptMatchItems` 등 테스트 데이터를 갱신했습니다.
    * `PrezelPlayerTimelinePreview`를 추가하여 타임라인 단독 컴포넌트의 시각적 검증을 강화했습니다.
* **refactor: `PrezelPlayerState` 호이스팅 및 업데이트 로직 변경**
    * `rememberPrezelPlayerState`에서 외부 콜백(`onPlayPauseClick`, `onSeekToMillis`) 및 `SideEffect`를 통한 자동 업데이트 로직을 제거했습니다.
    * 상태 객체 내부에서 직접 상태를 변경할 수 있도록 `updatePlaying`, `updateCurrentMillis`, `togglePlaying` 메서드를 추가했습니다.
    * `currentMillis` 및 `durationMillis` 설정 시 사용되던 `coercePlayerMillis` 유틸리티와 불필요한 제약 로직을 제거했습니다.

* **refactor: `PrezelPlayer` 컴포넌트 내부 리팩터링**
    * 플레이어 제어 콜백을 `state` 객체의 메서드(`togglePlaying`, `seekToProgress` 등)를 직접 호출하도록 변경했습니다.
    * `PrezelPlayer` 레이아웃 구성 시 `Arrangement.spacedBy` 대신 명시적인 `Spacer`를 사용하도록 수정했습니다.
    * 프리뷰(Preview) 코드에서 외부 변수로 관리하던 재생 상태를 `playerState` 내부 상태를 사용하도록 업데이트했습니다.

* **refactor: `PrezelPlayerResourceTrack` 최적화**
    * 시간 포맷팅 및 진행률 계산 시 불필요하게 호출되던 범위를 제한하는 로직(`coercePlayerMillis`)을 제거하고 원본 값을 사용하도록 단순화했습니다.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt (1)

89-103: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

드래그 중 외부 시간 업데이트가 시크 위치를 다시 덮어쓸 수 있습니다.

updateCurrentMillis가 드래그 중에도 항상 값을 반영해서, 재생 ticker 업데이트가 들어오면 핸들이 스냅백될 수 있습니다. 또한 내부 시간 보정이 없어 범위를 벗어난 값이 그대로 상태에 들어갑니다. 과거에 같은 성격의 이슈가 있었던 만큼, 여기서도 방어해두는 편이 안전합니다.

🐛 제안 수정
 fun updateCurrentMillis(currentMillis: Long) {
-    this.currentMillis = currentMillis
+    if (!dragging) {
+        seekToMillis(currentMillis)
+    }
 }
@@
 private fun seekToMillis(targetMillis: Long) {
-    currentMillis = targetMillis
+    currentMillis = targetMillis.coerceIn(0L, durationMillis)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt`
around lines 89 - 103, updateCurrentMillis currently overwrites the position
even while dragging and allows out-of-range values; change it to ignore external
updates when dragging (use the dragging flag set by startDrag/stopDrag) and
validate/clamp incoming currentMillis to the valid range before assigning (reuse
seekToMillis logic or centralize clamping there), e.g., only assign
currentMillis = targetMillis when not dragging and always clamp targetMillis
into [0, durationOrMaxMillis] to prevent invalid state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt`:
- Around line 89-103: updateCurrentMillis currently overwrites the position even
while dragging and allows out-of-range values; change it to ignore external
updates when dragging (use the dragging flag set by startDrag/stopDrag) and
validate/clamp incoming currentMillis to the valid range before assigning (reuse
seekToMillis logic or centralize clamping there), e.g., only assign
currentMillis = targetMillis when not dragging and always clamp targetMillis
into [0, durationOrMaxMillis] to prevent invalid state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9cb3a4af-670d-49a4-8740-9b4d7c194704

📥 Commits

Reviewing files that changed from the base of the PR and between a4e030d and 215e9cf.

📒 Files selected for processing (6)
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayer.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerModels.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceMarker.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerResourceTrack.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerTimeline.kt

# Conflicts:
#	Prezel/core/designsystem/src/main/res/values/strings.xml
* **feat: PrezelPlayerState 상태 보존 로직 추가**
    * 구성 변경(화면 회전 등) 시에도 플레이어의 상태가 유지되도록 `remember`를 `rememberSaveable`로 변경했습니다.
    * `PrezelPlayerState`를 저장하고 복원하기 위한 `Saver`를 companion object에 구현했습니다.

* **refactor: PrezelPlayerItem 직렬화 로직 구현**
    * `PrezelPlayerItem`의 하위 타입인 `Segment`와 `Marker`를 `List` 형태로 변환하여 저장하고 복구하는 매핑 로직(`toSaveable`, `toPrezelPlayerItem`)을 추가했습니다.
    * 플레이어 상태 값(`playing`, `durationMillis`, `currentMillis`)과 아이템 리스트를 모두 `Saver`를 통해 관리하도록 개선했습니다.
*   **refactor: PrezelPlayerState 재생/일시정지 로직 고도화**
    *   `updatePlaying(Boolean)` 대신 명시적인 `play()`, `pause()` 메서드를 도입했습니다.
    *   `play()` 호출 시 재생이 이미 종료된 상태(`playbackEnded`)라면 처음(0ms)부터 다시 재생하도록 개선했습니다.
    *   `togglePlaying()`에서 위에서 정의된 `play`/`pause` 로직을 사용하도록 변경했습니다.

*   **refactor: 이전/다음 아이템 이동 및 탐색(Seek) 로직 개선**
    *   `previousEnabled`: 현재 재생 위치가 현재 아이템의 시작점보다 뒤에 있는 경우에도 이전 버튼을 활성화하도록 조건을 확장했습니다.
    *   `moveToPreviousItem`: 현재 재생 위치에 따라 현재 아이템의 시작점으로 돌아가거나, 진짜 이전 아이템으로 이동하도록 로직을 세분화했습니다.
    *   `seekToMillis` 및 `updateCurrentMillis`: 입력값이 0과 전체 재생 시간(`durationMillis`) 범위를 벗어나지 않도록 `coerceIn`을 적용했습니다.

*   **refactor: PrezelPlayer 재생 종료 처리 수정**
    *   재생 시간이 끝에 도달했을 때 직접 상태를 변경하던 로직을 `playerState.pause()` 호출로 변경하여 일관성을 유지했습니다.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt`:
- Around line 141-151: The restore lambda for PrezelPlayerState should validate
the saved data before unsafe casts: check the incoming saved value is a List<*>
with size >= 4, verify values[0] is Boolean, values[1]/values[2] are Long (or
convertible), and values[3] is a List<*> whose elements are List<*> acceptable
to toPrezelPlayerItem; if any check fails return null so rememberSaveable will
use the initializer instead of throwing; implement these checks inside the
restore block (referencing restore, PrezelPlayerState, and toPrezelPlayerItem)
and only construct PrezelPlayerState after all validations pass.
- Around line 177-180: PrezelPlayerItem.Marker 생성 시
PrezelPlayerMarkerType.valueOf(...) 호출이 잘못된 문자열에서 IllegalArgumentException을 던질 수
있으므로 안전하게 파싱하도록 변경하세요: PrezelPlayerMarkerType.valueOf(this[2] as String) 대신 안전한
검색(e.g. enumValues<PrezelPlayerMarkerType>().firstOrNull { it.name == storedName
} ?: FALLBACK) 또는 try/catch/ runCatching을 사용해 유효하지 않은 값일 경우 기존의 "unknown type"
처리와 동일한 폴백 값(예: PrezelPlayerMarkerType.Unknown 또는 기존 처리 로직으로 리다이렉트)으로 대체하도록
수정하고, 관련 심볼은 PrezelPlayerState, PrezelPlayerItem.Marker,
PrezelPlayerMarkerType.valueOf/enumValues 등을 참고하세요.
- Around line 14-30: The rememberPrezelPlayerState usage lacks synchronization
with external props; add an internal fun update(playing: Boolean,
durationMillis: Long, currentMillis: Long, items:
ImmutableList<PrezelPlayerItem>) to PrezelPlayerState that updates its private
properties, keep the Saver unchanged, and then call this update from the caller
(e.g., SideEffect { playerState.update(playing, durationMillis, currentMillis,
initialItems) }) so external changes to durationMillis/initialItems/playing are
reflected; alternatively, if you prefer recreate-on-change, add inputs =
arrayOf(durationMillis, initialItems, playing, currentMillis) to the
rememberSaveable call in rememberPrezelPlayerState so the state is recreated
when those props change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ed28aebb-16a7-481f-b468-7bafc8582c2f

📥 Commits

Reviewing files that changed from the base of the PR and between 215e9cf and 1e8a5b3.

📒 Files selected for processing (3)
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayer.kt
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayerState.kt
  • Prezel/core/designsystem/src/main/res/values/strings.xml
✅ Files skipped from review due to trivial changes (1)
  • Prezel/core/designsystem/src/main/res/values/strings.xml
🚧 Files skipped from review as they are similar to previous changes (1)
  • Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/player/PrezelPlayer.kt

* refactor: PrezelPlayerState 내 재생 상태 관리 및 초기화 로직 개선

`rememberSaveable`의 갱신 기준을 강화하고, 재생 종료에 따른 상태 변경 로직을 상태 클래스 내부로 캡슐화했습니다.
*   `rememberSaveable`의 `inputs` 파라미터에 `durationMillis`와 `initialItems`를 추가하여 데이터 변경 시 상태가 올바르게 재설정되도록 수정
*   `updateCurrentMillis` 메서드 내에 재생 종료(`playbackEnded`) 시 자동으로 일시정지(`pause()`)하는 로직을 추가하여 상태 일관성 확보

* refactor: PrezelPlayer 컴포넌트 코드 정리 및 책임 분리

UI 레이어에 존재하던 비즈니스 로직을 상태 클래스로 이관하고 코드를 간결하게 수정했습니다.
*   `onSeek` 콜백 함수를 메서드 참조(`state::seekToProgress`) 방식으로 변경
*   매 초마다 현재 시간을 업데이트할 때 수행하던 재생 종료 체크 로직을 `PrezelPlayerState` 내부로 이동하여 UI 컴포넌트의 복잡도 감소
@HamBeomJoon HamBeomJoon merged commit 2d696bc into develop May 11, 2026
2 checks passed
@HamBeomJoon HamBeomJoon deleted the feat/#125-ds-player branch May 11, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feat 새로운 기능 추가 또는 기존 기능 확장

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Player, PlayerResourceTrack 구현

2 participants