VoiceChrome, VoiceChromeWave DS 컴포넌트 구현#138
Conversation
- `VoiceChromeStatus` (IDLE, LISTENING, WAITING)에 따른 UI 상태 정의 - 음성 인식 강도 표현을 위한 `VoiceChromeGradient` 애니메이션 로직 추가 - 상태별 하단 라인 표시 및 텍스트 브러시 효과 적용 - "듣고 있어요", "일시정지됨" 등 관련 시스템 문자열 추가
- 음성 입력 상태(IDLE, LISTENING, WAITING)에 따른 웨이브 애니메이션 UI 추가 - 입력 볼륨 크기에 따라 막대 높이가 동적으로 변하는 시각화 로직 구현 - 기준선 표시 여부 및 커스텀 스타일(브러시, 색상, 간격) 설정 기능 제공 - 컴포넌트 동작 확인을 위한 프리뷰 및 애니메이션 샘플 추가
- `PrezelVoiceChromeComponentPreview`를 상태별(Status, Gradient, Title) 세션으로 분리하여 가독성 향상 - `PreviewSurface`, `PreviewColumn` 등 공통 미리보기 컴포넌트 적용 - 미리보기용 보조 컴포넌트(`VoiceChromePreviewSection`, `VoiceChromePreviewItem`) 추가 - 애니메이션 미리보기(`PrezelVoiceChromeAnimatedPreview`)에 레이블 및 배경 스타일 적용
- `VoiceChromeStatus.LISTENING` 상태일 때 그라데이션이 자동으로 움직이는 무한 애니메이션 추가 - 상태 변경 시 라인 컬러 및 타이틀 텍스트 컬러가 부드럽게 전환되도록 `animateColorAsState` 적용 - `VoiceChromeStatus.IDLE`에서 다른 상태로 전환될 때 라인이 중앙에서 양옆으로 확장되는 애니메이션 구현 - `VoiceChromeGradient`에 따른 애니메이션 시작/종료 지점 계산 로직 추가 - 컴포넌트 동작 확인을 위한 클릭 토글 프리뷰 추가 및 기존 프리뷰 구조 정리
- `activationProgress`와 `volumeProgress`를 도입하여 상태 전환 시 부드러운 애니메이션 효과 추가 - `drawVoiceChromeWaveContent`를 통해 IDLE에서 LISTENING 상태로 전환 시 가로 스크롤 연출 구현 - `volumeToBarHeight` 계산 로직에 `progress` 파라미터를 추가하여 가변적인 높이 조절 지원 - `PreviewVolumePattern` 상수를 정의하고 애니메이션 프리뷰 로직을 상태 기반으로 리팩터링 - 불필요한 `rememberInfiniteTransition` 및 `sin` 함수 기반의 볼륨 샘플링 제거
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthrough음성 상태 열거형과 두 컴포저블(PrezelVoiceChrome, PrezelVoiceChromeWave)을 추가해 그라디언트 기반 크롬과 파형 기반 웨이브로 IDLE/LISTENING/WAITING 상태를 시각화합니다. Changes음성 UI 컴포넌트 추가
요약음성 입력/출력 상태를 시각화하는 두 가지 UI 컴포넌트를 설계 시스템에 추가했습니다. VoiceChrome은 그라디언트 애니메이션으로, VoiceChromeWave는 파형 바로 음성 상태(IDLE/LISTENING/WAITING)를 표현하며, 각각 상태별 애니메이션과 프리뷰를 포함합니다. 변경 사항음성 UI 컴포넌트 추가
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/voice/PrezelVoiceChrome.kt (3)
258-261: 💤 Low value매직 넘버 추출 고려
scaleY = 0.45f는 타원형 그라디언트 효과를 만드는 중요한 값이지만, 코드만으로는 의도를 파악하기 어렵습니다. 파일 상단에 상수로 추출하고 의미 있는 이름과 주석을 추가하는 것을 고려해보세요.♻️ 상수 추출 제안
파일 상단에:
private const val VOICE_CHROME_GRADIENT_SCALE_Y = 0.45f // 타원형 그라디언트를 위한 수직 스케일사용 시:
- scaleY = 0.45f, + scaleY = VOICE_CHROME_GRADIENT_SCALE_Y,🤖 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/voice/PrezelVoiceChrome.kt` around lines 258 - 261, Extract the magic literal 0.45f used in the scale(...) call (scaleY = 0.45f) into a top-level constant (e.g. VOICE_CHROME_GRADIENT_SCALE_Y) with a clear name and a short comment explaining it creates the vertical compression for the elliptical gradient; then replace the literal in PrezelVoiceChrome's scale(...) invocation with that constant so the intent is obvious (reference: scale(...), scaleY, PrezelVoiceChrome).
276-281: 💤 Low value그라디언트 스톱 값 문서화 권장
0.28f와0.44f값들은 시각적 효과를 결정하는 중요한 상수이지만, 어떻게 결정되었는지 알기 어렵습니다. 디자인 명세나 시각적 효과를 설명하는 주석을 추가하는 것을 권장합니다.📝 문서화 제안
private val VoiceChromeGradient.stop: Float get() = when (this) { - VoiceChromeGradient.NONE -> 0f - VoiceChromeGradient.MIN -> 0.28f - VoiceChromeGradient.MAX -> 0.44f + VoiceChromeGradient.NONE -> 0f // 그라디언트 없음 + VoiceChromeGradient.MIN -> 0.28f // 최소 그라디언트 확산 (디자인 명세 기준) + VoiceChromeGradient.MAX -> 0.44f // 최대 그라디언트 확산 (디자인 명세 기준) }🤖 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/voice/PrezelVoiceChrome.kt` around lines 276 - 281, VoiceChromeGradient.stop의 하드코딩된 값들(VoiceChromeGradient.MIN -> 0.28f, VoiceChromeGradient.MAX -> 0.44f)은 시각적 비율/픽셀 기준 또는 디자인 스펙에 따라 결정된 중요한 상수이므로, 이 getter(VoiceChromeGradient.stop) 바로 위에 각 값의 근거(디자인 명세에서 온 비율인지, 시뮬레이션/시각적 테스트 결과인지, 어떤 화면 해상도/비율을 기준으로 했는지)와 단위(비율인지 픽셀인지) 및 기대 효과(예: 페이드 시작/종료 위치, 대비 조정 등)를 간단히 주석으로 추가해 주세요; 또한 가능하면 참조한 디자인 문서나 스크린샷/토큰 이름을 주석에 링크/명시해 주세요.
67-85: ⚡ Quick win불필요한 애니메이션 실행으로 인한 리소스 낭비 가능성
rememberInfiniteTransition이 항상 실행되지만,status가LISTENING이 아니거나gradient가NONE일 때는 애니메이션 값이 사용되지 않습니다. 상태에 따라 조건부로 애니메이션을 시작/중지하는 것을 고려해보세요.♻️ 조건부 애니메이션 제안
`@Composable` fun PrezelVoiceChrome( titleText: String, modifier: Modifier = Modifier, status: VoiceChromeStatus = VoiceChromeStatus.IDLE, gradient: VoiceChromeGradient = VoiceChromeGradient.NONE, ) { + val shouldAnimate = status == VoiceChromeStatus.LISTENING && gradient != VoiceChromeGradient.NONE + val transition = rememberInfiniteTransition(label = "VoiceChromeGradientTransition") val animatedGradientStop by transition.animateFloat( initialValue = gradient.initialAnimatedStop, - targetValue = gradient.targetAnimatedStop, + targetValue = if (shouldAnimate) gradient.targetAnimatedStop else gradient.initialAnimatedStop, animationSpec = infiniteRepeatable( animation = tween( durationMillis = 2400, delayMillis = 160, easing = LinearEasing, ), repeatMode = RepeatMode.Reverse, ), label = "VoiceChromeGradientStop", ) - val gradientStop = when { - status != VoiceChromeStatus.LISTENING -> VoiceChromeGradient.NONE.stop - gradient == VoiceChromeGradient.NONE -> VoiceChromeGradient.NONE.stop - else -> animatedGradientStop - } + val gradientStop = if (shouldAnimate) animatedGradientStop else VoiceChromeGradient.NONE.stop🤖 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/voice/PrezelVoiceChrome.kt` around lines 67 - 85, The infinite transition is always created via rememberInfiniteTransition and animateFloat (animatedGradientStop) even when not used; change this so the transition and animateFloat are only created when status == VoiceChromeStatus.LISTENING and gradient != VoiceChromeGradient.NONE (e.g., wrap the rememberInfiniteTransition/animateFloat block in that conditional), and otherwise set gradientStop directly to VoiceChromeGradient.NONE.stop; ensure references to rememberInfiniteTransition, animateFloat/animatedGradientStop, gradientStop, VoiceChromeGradient and VoiceChromeStatus.LISTENING are adjusted so no animation objects are created when not needed.
🤖 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/voice/PrezelVoiceChromeWave.kt`:
- Around line 239-251: The baseline is being drawn as a vertical line in
drawVoiceChromeWaveBaseline (visible parameter) but should be a horizontal
center line; update the drawLine call in drawVoiceChromeWaveBaseline so the
start Offset is at x = 0f, y = size.height / 2f and the end Offset is at x =
size.width, y = size.height / 2f (keep color and strokeWidth), ensuring the
baseline aligns with the waveform's central axis.
---
Nitpick comments:
In
`@Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/voice/PrezelVoiceChrome.kt`:
- Around line 258-261: Extract the magic literal 0.45f used in the scale(...)
call (scaleY = 0.45f) into a top-level constant (e.g.
VOICE_CHROME_GRADIENT_SCALE_Y) with a clear name and a short comment explaining
it creates the vertical compression for the elliptical gradient; then replace
the literal in PrezelVoiceChrome's scale(...) invocation with that constant so
the intent is obvious (reference: scale(...), scaleY, PrezelVoiceChrome).
- Around line 276-281: VoiceChromeGradient.stop의 하드코딩된
값들(VoiceChromeGradient.MIN -> 0.28f, VoiceChromeGradient.MAX -> 0.44f)은 시각적
비율/픽셀 기준 또는 디자인 스펙에 따라 결정된 중요한 상수이므로, 이 getter(VoiceChromeGradient.stop) 바로 위에 각
값의 근거(디자인 명세에서 온 비율인지, 시뮬레이션/시각적 테스트 결과인지, 어떤 화면 해상도/비율을 기준으로 했는지)와 단위(비율인지
픽셀인지) 및 기대 효과(예: 페이드 시작/종료 위치, 대비 조정 등)를 간단히 주석으로 추가해 주세요; 또한 가능하면 참조한 디자인 문서나
스크린샷/토큰 이름을 주석에 링크/명시해 주세요.
- Around line 67-85: The infinite transition is always created via
rememberInfiniteTransition and animateFloat (animatedGradientStop) even when not
used; change this so the transition and animateFloat are only created when
status == VoiceChromeStatus.LISTENING and gradient != VoiceChromeGradient.NONE
(e.g., wrap the rememberInfiniteTransition/animateFloat block in that
conditional), and otherwise set gradientStop directly to
VoiceChromeGradient.NONE.stop; ensure references to rememberInfiniteTransition,
animateFloat/animatedGradientStop, gradientStop, VoiceChromeGradient and
VoiceChromeStatus.LISTENING are adjusted so no animation objects are created
when not needed.
🪄 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: ed8db0f0-b6b4-4448-a63e-bfbb4015deef
📒 Files selected for processing (3)
Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/voice/PrezelVoiceChrome.ktPrezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/voice/PrezelVoiceChromeWave.ktPrezel/core/designsystem/src/main/res/values/strings.xml
- `PrezelVoiceChrome`의 그라데이션 애니메이션 로직을 상태(`status`)에 따라 조건부로 실행되도록 최적화 - 하단 그라데이션 영역의 너비를 고정값(360.dp)에서 `fillMaxWidth()`로 변경 - 보이스 크롬의 `radialGradient` 컬러 스톱을 세분화하여 더욱 부드러운 효과 구현 - `PrezelVoiceChromeWave`에서 라인이 그려지는 방향을 수직에서 수평으로 수정 (그려지는 좌표 계산 로직 변경)
📌 작업 내용
PrezelVoiceChrome디자인 시스템 컴포넌트를 추가했습니다.PrezelVoiceChromeWave컴포넌트를 추가했습니다.IDLE,LISTENING,WAITING상태별 UI 표현을 분리했습니다.🧩 관련 이슈
📸 스크린샷
📢 논의하고 싶은 내용
Summary by CodeRabbit
Summary by CodeRabbit
릴리스 노트