feat(creator): empty state 문구와 버튼 정책을 정리한다

This commit is contained in:
2026-08-14 18:30:03 +09:00
parent 5d43f367e3
commit 60df86f899
17 changed files with 305 additions and 94 deletions
@@ -12,11 +12,11 @@
| 문서 항목 | 내용 |
|---|---|
| 상태 | 계획 작성 중 |
| 상태 | 후속 색상 수정 완료 |
| 작성일 | `2026-08-14` |
| 요구사항 기준 | `docs/20260814_크리에이터_채널_empty_state_다국어_문구_정리/prd.md` |
| API 기준 | 없음 |
| 현재 Phase | Phase 1 대기 |
| 현재 Phase | Phase 1 후속 색상 수정 완료 |
| 현재 활성 Goal | 없음 |
## 목표
@@ -27,7 +27,7 @@
| Phase | 상태 | 완료 Task | 활성/다음 Goal | 차단 또는 남은 조건 |
|---:|---|---:|---|---|
| 1 | 대기 | `0/4` | `P1-T1` | 사용자 승인 후 구현 시작 |
| 1 | 완료 | `6/6` | 없음 | 없음 |
## 범위
@@ -36,7 +36,7 @@
- 한국어/영어/일본어 string resource 값 정리
- 홈 전용 후원 empty title resource 추가
- 홈 후원 empty, 홈 팬레터 empty, 팬레터 탭 empty, 후원 탭 empty의 내 채널 action 버튼 숨김 정책
- 홈 탭 팬레터 empty UI 표시와 기존 홈 후원 empty UI 구조 재사용
- 기존 홈 탭 팬레터 empty UI의 문구와 내 채널 action 버튼 정책 보강
- `app/src/test` 기반 resource/source/layout 회귀 테스트
### 제외
@@ -63,7 +63,7 @@
**선행조건:** PRD `CREATOR-EMPTY-I18N-001~005`, `CREATOR-EMPTY-UI-001~005` 확정.
**Phase 완료 조건:** `P1-T1`~`P1-T3` `P1-GATE` 완료, 검증 기록 누적.
**Phase 완료 조건:** `P1-T1`~`P1-T5` `P1-GATE` 완료, 검증 기록 누적.
### 구현 항목
@@ -89,7 +89,7 @@
- Consumes: 기존 `R.string.creator_channel_fantalk_empty_title`, `R.string.creator_channel_fantalk_empty_message`, `R.string.creator_channel_fantalk_support_action`, `R.string.creator_channel_donation_empty_title`, `R.string.creator_channel_donation_action`
- Produces: 신규 `R.string.creator_channel_home_donation_empty_title`
- [ ] **RED:** resource 값 검증 테스트에 아래 기대값을 추가하거나 갱신한다.
- [x] **RED:** resource 값 검증 테스트에 아래 기대값을 추가하거나 갱신한다.
```kotlin
val expectedKo = mapOf(
@@ -118,7 +118,7 @@
)
```
- [ ] **RED 확인:** focused resource/source test를 실행해 신규 홈 후원 key 누락 또는 기존 값 불일치로 실패함을 확인한다.
- [x] **RED 확인:** focused resource/source test를 실행해 신규 홈 후원 key 누락 또는 기존 값 불일치로 실패함을 확인한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
@@ -126,7 +126,7 @@
Expected: `creator_channel_home_donation_empty_title` 누락 또는 기존 팬레터/후원 문구 불일치 assertion 실패.
- [ ] **GREEN:** 세 locale resource에 아래 값을 반영한다.
- [x] **GREEN:** 세 locale resource에 아래 값을 반영한다.
```xml
<string name="creator_channel_home_donation_empty_title">처음으로 크리에이터를\n후원해 보세요!</string>
@@ -155,7 +155,7 @@
<string name="creator_channel_donation_action">サポートする</string>
```
- [ ] **GREEN 확인:** focused resource/source test와 resource merge를 실행한다.
- [x] **GREEN 확인:** focused resource/source test와 resource merge를 실행한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
@@ -164,14 +164,14 @@
Expected: 두 명령 모두 `BUILD SUCCESSFUL`.
- [ ] **REFACTOR:** resource key 순서와 테스트 중복만 정리하고 같은 명령을 재실행해 결과를 Progress에 기록한다.
- [x] **REFACTOR:** resource key 순서와 테스트 중복만 정리하고 같은 명령을 재실행해 결과를 Progress에 기록한다.
#### Task 1.2 홈 탭 empty UI와 내 채널 버튼 정책
**Goal 실행 `P1-T2`:** 홈 후원/팬레터 empty UI가 화면별 문구를 사용하고 내 채널에서는 action 버튼을 숨긴다.
- **시작 조건:** `P1-T1` 완료.
- **완료 증거:** 홈 후원 empty가 홈 전용 string을 사용하고, 홈 팬레터 empty는 빈 데이터에서 표시되며, `isOwner == true`에서 두 empty action 버튼이 숨겨진다.
- **완료 증거:** 홈 후원 empty가 홈 전용 string을 사용하고, 기존 홈 팬레터 empty 표시 분기는 유지되며, `isOwner == true`에서 두 empty action 버튼이 숨겨진다.
- **범위 밖:** 상세 팬레터/후원 탭 Fragment 변경.
**Files:**
@@ -187,7 +187,7 @@
- Consumes: `CreatorChannelHomeSection.Donations.isOwner`, `CreatorChannelHomeSection.FanTalk`, 신규 `R.string.creator_channel_home_donation_empty_title`
- Produces: 홈 empty button visibility와 click listener owner 분기
- [ ] **RED:** 홈 후원 layout이 홈 전용 string을 참조하는지 테스트한다.
- [x] **RED:** 홈 후원 layout이 홈 전용 string을 참조하는지 테스트한다.
```kotlin
val donationLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_donation.xml").readText()
@@ -195,18 +195,19 @@
assertFalse(donationLayout.contains("@string/creator_channel_donation_empty_title"))
```
- [ ] **RED:** 홈 팬레터 empty가 빈 요약 상태에서 표시되고 owner일 때 action button을 숨기는 source test를 추가한다.
- [x] **RED:** 홈 팬레터 empty 버튼이 owner일 때 숨겨지고 click listener가 제거되는 source test를 추가한다.
```kotlin
val adapterSource = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
).readText()
assertTrue(adapterSource.contains("fantalkEmpty?.isVisible ="))
assertTrue(adapterSource.contains("fantalkSupportButton?.isVisible ="))
assertTrue(adapterSource.contains("private val fanTalkSupportButton"))
assertTrue(adapterSource.contains("fanTalkSupportButton?.isVisible ="))
assertTrue(adapterSource.contains("!item.isOwner"))
assertTrue(adapterSource.contains("fanTalkSupportButton?.setOnClickListener"))
```
- [ ] **RED 확인:** focused tests를 실행해 아직 홈 전용 string 참조와 팬레터 owner 분기가 없어 실패함을 확인한다.
- [x] **RED 확인:** focused tests를 실행해 아직 홈 전용 string 참조와 팬레터 owner 분기가 없어 실패함을 확인한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
@@ -214,33 +215,39 @@
Expected: 홈 후원 layout string 또는 홈 팬레터 owner 분기 assertion 실패.
- [ ] **GREEN:** `item_creator_channel_home_donation.xml`의 empty title 참조를 홈 전용 key로 변경한다.
- [x] **GREEN:** `item_creator_channel_home_donation.xml`의 empty title 참조를 홈 전용 key로 변경한다.
```xml
android:text="@string/creator_channel_home_donation_empty_title"
```
- [ ] **GREEN:** `CreatorChannelHomeSectionAdapter.bindDonations()`에서 owner용 별도 empty title 변경을 제거하고 홈 전용 문구를 유지한다.
- [x] **GREEN:** `CreatorChannelHomeSectionAdapter.bindDonations()`에서 owner용 별도 empty title 변경을 제거하고 홈 전용 문구를 유지한다.
```kotlin
donationEmptyTitle?.setText(R.string.creator_channel_home_donation_empty_title)
```
- [ ] **GREEN:** 홈 팬레터 empty 바인딩에서 빈 데이터와 owner 버튼 숨김을 분기한다.
- [x] **GREEN:** 홈 팬레터 empty action button을 ViewHolder에 연결한다.
```kotlin
val hasFanTalk = item.latestFanTalk != null
fantalkTotalRow?.isVisible = hasFanTalk
fantalkLatestRow?.isVisible = hasFanTalk
fantalkEmpty?.isVisible = !hasFanTalk
val isFanTalkSupportButtonVisible = !hasFanTalk && !item.isOwner
fantalkSupportButton?.isVisible = isFanTalkSupportButtonVisible
private val fanTalkSupportButton: View? = view.findViewById(R.id.layout_fantalk_support_button)
```
- [x] **GREEN:** 홈 팬레터 empty 바인딩에서 기존 empty 표시 분기를 유지하고 owner 버튼 숨김을 추가한다.
```kotlin
val fanTalk = item.fanTalk.latestFanTalk
fanTalkTotalRow?.isVisible = fanTalk != null && item.fanTalk.totalCount > 0
fanTalkLatestRow?.isVisible = fanTalk != null && item.fanTalk.totalCount > 0
fanTalkEmpty?.isVisible = fanTalk == null || item.fanTalk.totalCount <= 0
val showSupportButton = (fanTalk == null || item.fanTalk.totalCount <= 0) && !item.isOwner
fanTalkSupportButton?.isVisible = showSupportButton
fantalkSupportButton?.setOnClickListener(
if (isFanTalkSupportButtonVisible) View.OnClickListener { onFanTalkClick() } else null
if (showSupportButton) View.OnClickListener { onSectionChevronClick(CreatorChannelTab.FanTalk) } else null
)
```
- [ ] **GREEN 확인:** 홈 관련 focused tests를 실행한다.
- [x] **GREEN 확인:** 홈 관련 focused tests를 실행한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"
@@ -248,7 +255,7 @@
Expected: `BUILD SUCCESSFUL`.
- [ ] **REFACTOR:** 이번 Task에서 만든 중복만 정리하고 focused tests와 `:app:mergeDebugResources` 결과를 Progress에 기록한다.
- [x] **REFACTOR:** 이번 Task에서 만든 중복만 정리하고 focused tests와 `:app:mergeDebugResources` 결과를 Progress에 기록한다.
#### Task 1.3 팬레터/후원 탭 empty action owner 정책
@@ -260,7 +267,6 @@
**Files:**
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/fantalk/CreatorChannelFanTalkViewModel.kt`
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/fantalk/CreatorChannelFanTalkFragment.kt`
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/ui/CreatorChannelDonationAdapter.kt`
- Test: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/fantalk/CreatorChannelFanTalkViewModelTest.kt`
@@ -273,7 +279,7 @@
- Consumes: `host.isCreatorChannelOwner()`, `CreatorChannelDonationUiState.Empty.isOwner`
- Produces: 팬레터 empty state owner 정보 또는 Fragment owner 분기, 후원 empty adapter owner visibility 분기
- [ ] **RED:** 팬레터 empty state가 owner 여부를 전달하거나 Fragment가 host owner 값을 사용해 empty write button을 숨기는 테스트를 추가한다.
- [x] **RED:** 팬레터 empty state가 owner 여부를 전달하거나 Fragment가 host owner 값을 사용해 empty write button을 숨기는 테스트를 추가한다.
```kotlin
val fragmentSource = projectFile(
@@ -283,16 +289,16 @@
assertTrue(fragmentSource.contains("layoutCreatorChannelFantalkEmptyWriteButton.setOnClickListener"))
```
- [ ] **RED:** 후원 empty adapter가 owner일 때 `btn_creator_channel_donation_empty_write`를 숨기는 테스트를 추가한다.
- [x] **RED:** 후원 empty adapter가 owner일 때 `btn_creator_channel_donation_empty_write`를 숨기는 테스트를 추가한다.
```kotlin
val adapterSource = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/ui/CreatorChannelDonationAdapter.kt"
).readText()
assertTrue(adapterSource.contains("btnCreatorChannelDonationEmptyWrite.isVisible = !isOwner"))
assertTrue(adapterSource.contains("if (!isOwner) View.OnClickListener { onEmptyDonationClick() } else null"))
```
- [ ] **RED 확인:** focused layout/source tests를 실행해 owner empty action 분기 누락으로 실패함을 확인한다.
- [x] **RED 확인:** focused layout/source tests를 실행해 owner empty action 분기 누락으로 실패함을 확인한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationFragmentLayoutTest"
@@ -300,7 +306,7 @@
Expected: owner empty action visibility 관련 assertion 실패.
- [ ] **GREEN:** `CreatorChannelFanTalkFragment.bindEmpty()`에서 내 채널 action button을 숨기고 listener를 제거한다.
- [x] **GREEN:** `CreatorChannelFanTalkFragment.bindEmpty()`에서 내 채널 action button을 숨기고 listener를 제거한다.
```kotlin
val showWriteButton = !host.isCreatorChannelOwner()
@@ -310,13 +316,13 @@
)
```
- [ ] **GREEN:** `setupClickListeners()`에서 empty write button의 고정 click listener를 제거하고 일반 floating write button listener만 유지한다.
- [x] **GREEN:** `setupClickListeners()`에서 empty write button의 고정 click listener를 제거하고 일반 floating write button listener만 유지한다.
```kotlin
btnCreatorChannelFantalkWrite.setOnClickListener { host.onCreatorChannelFanTalkWriteClicked() }
```
- [ ] **GREEN:** `CreatorChannelDonationAdapter` empty ViewHolder에서 `isOwner`에 따라 버튼 visibility와 click listener를 설정한다.
- [x] **GREEN:** `CreatorChannelDonationAdapter` empty ViewHolder에서 `isOwner`에 따라 버튼 visibility와 click listener를 설정한다.
```kotlin
binding.btnCreatorChannelDonationEmptyWrite.isVisible = !isOwner
@@ -325,7 +331,7 @@
)
```
- [ ] **GREEN 확인:** 팬레터/후원 탭 focused tests를 실행한다.
- [x] **GREEN 확인:** 팬레터/후원 탭 focused tests를 실행한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkViewModelTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationViewModelTest"
@@ -333,7 +339,85 @@
Expected: `BUILD SUCCESSFUL`.
- [ ] **REFACTOR:** owner 버튼 분기 중복만 정리하고 focused tests 결과를 Progress에 기록한다.
- [x] **REFACTOR:** owner 버튼 분기 중복만 정리하고 focused tests 결과를 Progress에 기록한다.
#### Task 1.4 홈 팬레터 empty 버튼 영역 회귀 수정
**Goal 실행 `P1-T4`:** 홈 팬레터 empty에서 내 채널이라 action 버튼이 숨겨질 때 버튼 영역도 레이아웃 높이에 남지 않게 한다.
- **시작 조건:** `P1-T2` 완료.
- **완료 증거:** 홈 팬레터 empty root가 fixed height를 쓰지 않고, action button이 숨겨지면 해당 button view/margin이 레이아웃 높이에 기여하지 않는다.
- **범위 밖:** 상세 팬레터/후원 탭, API, adapter 데이터 정책 변경.
**Files:**
- Modify: `app/src/main/res/layout/item_creator_channel_home_fantalk.xml`
- Test: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt`
**Interfaces:**
- Consumes: `CreatorChannelHomeSectionAdapter.bindFanTalk()`의 기존 `fanTalkSupportButton?.isVisible = showSupportButton`
- Produces: button `GONE` 시 button 영역 제거가 가능한 홈 팬레터 empty layout 구조
- [x] **RED:** 홈 팬레터 empty layout이 fixed `169dp` 높이와 button bottom margin을 쓰지 않도록 source/layout test를 추가한다.
```kotlin
assertTrue(fanTalkLayout.contains("android:layout_height=\"wrap_content\""))
assertTrue(fanTalkLayout.contains("android:layout_marginTop=\"@dimen/spacing_14\""))
assertFalse(fanTalkLayout.contains("android:layout_height=\"169dp\""))
assertFalse(fanTalkLayout.contains("android:layout_marginBottom=\"@dimen/spacing_6\""))
```
- [x] **RED 확인:** focused source/layout test를 실행해 기존 fixed height로 실패함을 확인한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
```
- [x] **GREEN:** `layout_fantalk_empty`를 `LinearLayout` `wrap_content` 구조로 변경하고, support button은 `marginTop`만 갖는 sibling으로 둔다.
- [x] **GREEN 확인:** focused source/layout test와 resource merge를 실행한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
./gradlew :app:mergeDebugResources
```
- [x] **REFACTOR:** 불필요한 변경이 없음을 확인하고 공백 검사를 실행해 Progress에 기록한다.
#### Task 1.5 Empty action 버튼 색상 정리
**Goal 실행 `P1-T5`:** 홈/팬레터/후원 empty action 버튼 색상을 화면별 확정값과 일치시킨다.
- **시작 조건:** 사용자 색상 요구사항 확정.
- **완료 증거:** 홈 후원/홈 팬레터 버튼은 white 배경과 black 글자색, 팬레터 탭 버튼은 gray 800 배경과 white 글자색, 후원 탭 버튼은 soda 400 배경과 white 글자색을 source/layout test로 검증한다.
- **범위 밖:** 문구, 노출 정책, click listener, API, 신규 drawable/dependency 변경.
**Files:**
- Modify: `app/src/main/res/layout/item_creator_channel_home_donation.xml`
- Test: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt`
- Test: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/fantalk/CreatorChannelFanTalkFragmentLayoutTest.kt`
- Test: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/CreatorChannelDonationFragmentLayoutTest.kt`
**Interfaces:**
- Consumes: 기존 `bg_round_corner_999_white`, `bg_creator_channel_fantalk_empty_button`, `bg_creator_channel_donation_empty_button`, `@color/black`, `@color/white`
- Produces: 화면별 empty action button 색상 계약
- [x] **RED:** 홈/팬레터/후원 empty action button 색상 source/layout test를 추가한다.
- [x] **RED 확인:** focused tests를 실행해 홈 후원 empty button 배경 mismatch로 실패함을 확인한다.
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationFragmentLayoutTest"
```
- [x] **GREEN:** 홈 후원 empty `layout_donation_empty_button` 배경을 기존 white capsule drawable로 변경한다.
- [x] **GREEN 확인:** focused tests와 `:app:mergeDebugResources`를 실행한다.
- [x] **REFACTOR:** 신규 drawable 없이 기존 resource 재사용만 남았는지 확인하고 공백 검사를 실행한다.
### 검증 방법
@@ -361,10 +445,14 @@ git diff --check
| 2 | `P1-T2` | `P1-T1` | 예, `P1-T3`와 파일 비중복 시 가능 | 홈 section adapter/layout 범위 재확인 |
| 3 | `P1-T3` | `P1-T1` | 예, `P1-T2`와 파일 비중복 시 가능 | Fragment/adapter owner 전달 경로 재확인 |
| 4 | `P1-GATE` | `P1-T2`, `P1-T3` | 아니요 | 실패 소유 Task에 회귀 수정 Task 추가 |
| 5 | `P1-T4` | `P1-T2` | 아니요 | 홈 팬레터 empty layout 구조 재확인 |
| 6 | `P1-T5` | 사용자 색상 요구사항 확정 | 아니요 | 기존 drawable/color resource 재확인 |
```text
P1-T1 -> P1-T2 -> P1-GATE
-> P1-T3 -> P1-GATE
P1-T2 -> P1-T4
색상 요구사항 -> P1-T5
```
## 변경 금지 항목
@@ -383,6 +471,7 @@ P1-T1 -> P1-T2 -> P1-GATE
| 2026-08-14 | `DEC-001` | 확정 | 내 채널에서는 대상 empty state action 버튼을 모두 숨긴다. | 사용자 A안 선택 | `P1-T2`, `P1-T3`, `prd.md` |
| 2026-08-14 | `DEC-002` | 확정 | 영어 resource도 이번 범위에 포함하고 제공되지 않은 영문은 번역 초안을 사용한다. | 사용자 직접 지시 | `P1-T1`, `prd.md` |
| 2026-08-14 | `DEC-003` | 확정 | 홈 후원 empty 전용 string key를 추가한다. | 홈/후원 탭 문구가 서로 다름 | `P1-T1`, `P1-T2`, `prd.md` |
| 2026-08-14 | `DEC-004` | 확정 | empty action 버튼 색상은 홈 탭 white/black, 팬레터 탭 gray 800/white, 후원 탭 soda 400/white로 구분한다. | 사용자 직접 지시 | `P1-T5`, `prd.md` |
## 발견된 문제
@@ -406,6 +495,83 @@ P1-T1 -> P1-T2 -> P1-GATE
- 남은 항목: 사용자 승인 후 `P1-T1` 구현 시작.
- 다음 행동: 구현 요청이 들어오면 `P1-T1`부터 실행한다.
### `P1-T1` 1차 실행 — 2026-08-14
- 상태: 완료
- 무엇을: 한국어/영어/일본어 resource 테스트를 먼저 갱신하고, 홈 전용 후원 empty key와 팬레터/후원 empty 문구를 반영했다.
- 왜: 홈/팬레터/후원 empty state 문구가 PRD 문구 표와 일치해야 하기 때문이다.
- 어떻게:
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkFragmentLayoutTest"` — RED에서 `CreatorChannelActivitySourceTest.kt:1311`, `CreatorChannelFanTalkFragmentLayoutTest.kt:238` assertion 실패를 확인했다.
- 같은 focused test 재실행 — `BUILD SUCCESSFUL`.
- `./gradlew :app:mergeDebugResources` — `BUILD SUCCESSFUL`.
- 남은 항목: 없음.
- 다음 행동: `P1-T2` 실행.
### `P1-T2` 1차 실행 — 2026-08-14
- 상태: 완료
- 무엇을: 홈 후원 empty가 홈 전용 string을 사용하도록 변경하고, `FanTalk` section에 기존 owner 판정값을 전달해 홈 팬레터 empty action 버튼을 owner일 때 숨기도록 했다.
- 왜: 사용자가 지적한 대로 이미 알고 있는 내 채널 여부를 홈 팬레터 empty 버튼 정책에 활용하기 위해서다.
- 어떻게:
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"` — RED에서 `CreatorChannelHomeMapperTest.kt:62`, `:63`의 `FanTalk.isOwner` 미존재 컴파일 실패를 확인했다.
- 같은 focused test 재실행 — `BUILD SUCCESSFUL`.
- 남은 항목: 없음.
- 다음 행동: `P1-T3` 실행.
### `P1-T3` 1차 실행 — 2026-08-14
- 상태: 완료
- 무엇을: 팬레터 탭 empty 버튼은 내 채널에서 숨기고 click listener를 제거했다. 후원 탭 empty 버튼은 기존 visibility 분기를 유지하면서 owner일 때 listener도 제거하도록 보강했다.
- 왜: 내 채널에서는 본인에게 후원하거나 팬레터를 남기는 action을 표시하거나 실행하지 않아야 하기 때문이다.
- 어떻게:
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationActionTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationFragmentLayoutTest"` — RED에서 `CreatorChannelDonationActionTest.kt:94`, `CreatorChannelFanTalkFragmentLayoutTest.kt:218` assertion 실패를 확인했다.
- 같은 focused test 재실행 — `BUILD SUCCESSFUL`.
- 남은 항목: 없음.
- 다음 행동: `P1-GATE` 실행.
### `P1-GATE` 1차 실행 — 2026-08-14
- 상태: 완료
- 무엇을: focused regression, resource merge, 전체 unit suite, 공백 검사와 reviewer gate를 완료했다.
- 왜: 문구/resource merge, owner 버튼 정책, 인접 회귀를 최종 판정하기 위해서다.
- 어떻게:
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkViewModelTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkActionTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationViewModelTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationActionTest"` — `BUILD SUCCESSFUL`.
- `./gradlew :app:mergeDebugResources` — `BUILD SUCCESSFUL`.
- `./gradlew :app:testDebugUnitTest` — 최초 전체 실행은 `CreatorChannelHomeViewModelTest`의 can 차감 assertion 1건이 실패했으나, 해당 테스트 단독 재실행은 `BUILD SUCCESSFUL`이었고 전체 suite 재실행도 `BUILD SUCCESSFUL`이었다.
- `git diff --check` — 출력 없음.
- reviewer gate — `APPROVE`, 차단 발견 없음.
- 남은 항목: 없음.
- 다음 행동: 없음.
### `P1-T4` 1차 실행 — 2026-08-14
- 상태: 완료
- 무엇을: 홈 팬레터 empty root의 fixed `169dp` 높이를 제거하고 `LinearLayout` `wrap_content` 구조로 바꿨다. `응원남기기` 버튼은 title 아래 sibling으로 두고 `marginTop`만 갖게 해 `GONE`일 때 버튼과 간격이 함께 제거되도록 했다.
- 왜: 내 채널에서 버튼을 숨겨도 기존 `FrameLayout` fixed height 때문에 버튼 영역이 남았기 때문이다.
- 어떻게:
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"` — RED에서 `CreatorChannelActivitySourceTest.kt:2145` assertion 실패를 확인했다.
- 같은 focused test 재실행 — `BUILD SUCCESSFUL`.
- `./gradlew :app:mergeDebugResources` — `BUILD SUCCESSFUL`.
- `git diff --check` — 출력 없음.
- 남은 항목: 없음.
- 다음 행동: 없음.
### `P1-T5` 1차 실행 — 2026-08-14
- 상태: 완료
- 무엇을: 홈 후원/홈 팬레터/팬레터 탭/후원 탭 empty action button 색상 계약을 source/layout test로 고정하고, 홈 후원 empty button 배경만 기존 white capsule drawable로 변경했다.
- 왜: 홈 탭 action button은 white 배경과 black 글자색이어야 하고, 후원 탭 action button은 기존 soda 400 배경과 white 글자색을 유지해야 하기 때문이다.
- 어떻게:
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkFragmentLayoutTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.donation.CreatorChannelDonationFragmentLayoutTest"` — RED에서 `CreatorChannelActivitySourceTest.kt:1120` assertion 실패를 확인했다.
- 같은 focused test 재실행 — `BUILD SUCCESSFUL`.
- `./gradlew :app:mergeDebugResources` — `BUILD SUCCESSFUL`.
- `git diff --check` — 출력 없음.
- 남은 항목: 없음.
- 다음 행동: 없음.
## Verification Log
- 2026-08-14: 문서 생성 단계에서는 production resource, Kotlin, XML layout을 수정하지 않았다.
- 2026-08-14: Phase 1 구현 후 focused regression, resource merge, 전체 unit suite 재실행, 공백 검사와 reviewer gate가 통과했다.
- 2026-08-14: `P1-T4` 후속 회귀 수정에서 홈 팬레터 empty fixed height 제거 후 focused source/layout test, resource merge, 공백 검사가 통과했다.
- 2026-08-14: `P1-T5` 후속 색상 수정에서 홈 후원 empty button 배경을 white capsule로 변경한 뒤 focused source/layout test, resource merge, 공백 검사가 통과했다.
@@ -4,7 +4,7 @@
| 항목 | 내용 |
|---|---|
| 문서 상태 | 구현 기준 확정 |
| 문서 상태 | 후속 색상 수정 완료 |
| 작성일 | `2026-08-14` |
| 최종 수정일 | `2026-08-14` |
| 대상 제품 | 크리에이터 채널 홈/팬레터/후원 empty state |
@@ -21,13 +21,13 @@
- 크리에이터 채널 일부 empty state 문구가 화면별 의도와 다르게 재사용되어 홈 탭과 상세 탭의 안내 문구를 동시에 만족하지 못한다.
- 팬레터/후원 empty state 일부 문구와 action label이 한국어, 영어, 일본어에서 일관되게 다국어 처리되어야 한다.
- 홈 탭에는 팬레터가 없을 때 후원 empty state와 동일한 카드형 empty UI가 필요하다.
- 홈 탭 팬레터 empty state는 레이아웃과 표시 분기가 이미 존재하므로, 확정 문구와 내 채널 action 버튼 숨김 정책을 보강해야 한다.
- 내 채널에서는 사용자가 본인에게 후원하거나 본인 채널에 팬레터를 남기는 action 버튼을 보지 않아야 한다.
## 3. Goals
- 홈 탭 후원 empty 안내 문구를 한국어/영어/일본어 resource로 분리해 표시한다.
- 홈 탭 팬레터 empty 안내 문구를 한국어/영어/일본어 resource로 표시하고, 후원 empty UI와 동일한 카드형 UI를 제공하도록 요구사항을 확정한다.
- 홈 탭 팬레터 empty 안내 문구를 한국어/영어/일본어 resource로 표시하고, 기존 카드형 empty UI의 action 버튼 노출 정책을 확정한다.
- 팬레터 탭 empty 안내 문구와 `응원남기기` action label을 한국어/영어/일본어 resource로 표시한다.
- 후원 탭 empty 안내 문구와 `후원하기` action label을 한국어/영어/일본어 resource로 표시한다.
- 내 채널의 홈/팬레터/후원 empty state에서 `후원하기``응원남기기` 버튼을 모두 숨기는 정책을 확정한다.
@@ -75,11 +75,14 @@
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|---|---|---|---|---|
| `CREATOR-EMPTY-UI-001` | 확정 | 홈 탭에서 팬레터가 없을 때 empty state UI를 표시한다. | 홈 팬레터 empty UI는 홈 후원 empty UI와 동일한 카드형 구조와 action button 위치를 사용하고, 문구 팬레터 전용 값으로 표시한다. | `P1-T2` |
| `CREATOR-EMPTY-UI-001` | 확정 | 홈 탭 팬레터 empty UI의 기존 표시 분기를 보존하고 확정 문구를 적용한다. | `item_creator_channel_home_fantalk.xml``layout_fantalk_empty``CreatorChannelHomeSectionAdapter.bindFanTalk()` empty 표시 분기를 유지하며, 문구 팬레터 전용 값으로 표시한다. | `P1-T2` |
| `CREATOR-EMPTY-UI-002` | 확정 | 내 채널 홈 후원 empty에서는 `후원하기` 버튼을 숨긴다. | `isOwner == true`이면 `layout_donation_empty_button`이 보이지 않고 click listener가 연결되지 않는다. | `P1-T2` |
| `CREATOR-EMPTY-UI-003` | 확정 | 내 채널 홈 팬레터 empty에서는 `응원남기기` 버튼을 숨긴다. | `isOwner == true`이면 `layout_fantalk_support_button`이 보이지 않고 click listener가 연결되지 않는다. | `P1-T2` |
| `CREATOR-EMPTY-UI-004` | 확정 | 내 채널 팬레터 탭 empty에서는 `응원남기기` 버튼을 숨긴다. | `isOwner == true`이면 `layout_creator_channel_fantalk_empty_write_button`이 보이지 않고 click listener가 연결되지 않는다. | `P1-T3` |
| `CREATOR-EMPTY-UI-005` | 확정 | 내 채널 후원 탭 empty에서는 `후원하기` 버튼을 숨긴다. | `CreatorChannelDonationUiState.Empty.isOwner == true`이면 `btn_creator_channel_donation_empty_write`가 보이지 않고 click listener가 연결되지 않는다. | `P1-T3` |
| `CREATOR-EMPTY-UI-006` | 확정 | 홈 탭 후원 empty와 홈 탭 팬레터 empty action 버튼은 white 배경과 black 글자색을 사용한다. | `layout_donation_empty_button`, `layout_fantalk_support_button`은 white capsule 배경을 사용하고 label text color는 black이다. | `P1-T5` |
| `CREATOR-EMPTY-UI-007` | 확정 | 팬레터 탭 empty `응원남기기` 버튼은 gray 800 배경과 white 글자색을 사용한다. | `layout_creator_channel_fantalk_empty_write_button``gray_800` 배경 drawable을 사용하고 label text color는 white이다. | `P1-T5` |
| `CREATOR-EMPTY-UI-008` | 확정 | 후원 탭 empty `후원하기` 버튼은 soda 400 배경과 white 글자색을 사용한다. | `btn_creator_channel_donation_empty_write``soda_400` 배경 drawable을 사용하고 label text color는 white이다. | `P1-T5` |
## 8. 문구 표
@@ -106,10 +109,11 @@
## 9. UI/UX Expectations
- 홈 탭 팬레터 empty UI는 기존 홈 후원 empty 카드와 같은 시각 구조를 사용한다.
- 홈 탭 팬레터 empty UI는 기존 `layout_fantalk_empty` 카드 구조를 유지한다.
- 홈 탭 후원 empty와 팬레터 empty는 타인 채널에서 action 버튼을 표시하고 내 채널에서 action 버튼을 숨긴다.
- 팬레터 탭과 후원 탭 empty 상태는 타인 채널에서 문구 아래 action 버튼을 표시하고 내 채널에서 action 버튼을 숨긴다.
- action 버튼이 숨겨져도 empty 문구 정렬과 상하 여백이 어색하게 무너지면 안 된다.
- 홈 탭 empty action 버튼은 white 배경/black 글자색, 팬레터 탭 empty action 버튼은 gray 800 배경/white 글자색, 후원 탭 empty action 버튼은 soda 400 배경/white 글자색을 사용한다.
- 후원 탭 floating `후원하기` 버튼은 기존처럼 내 채널에서 숨긴다.
## 10. 기술적 제약
@@ -123,12 +127,13 @@
## 11. 성공 기준
- [ ] 문구 표의 모든 한국어/영어/일본어 resource 값이 실제 resource와 일치한다.
- [ ] 홈 후원 empty는 `creator_channel_home_donation_empty_title`, 후원 탭 empty는 `creator_channel_donation_empty_title`을 사용한다.
- [ ] 홈 팬레터 empty UI가 팬레터 데이터 없음 상태에서 표시된다.
- [ ] 내 채널의 홈 후원, 홈 팬레터, 팬레터 탭, 후원 탭 empty action 버튼이 모두 숨겨진다.
- [ ] 타인 채널의 empty action 버튼은 기존 후원/팬레터 진입 동작을 유지한다.
- [ ] `./gradlew :app:mergeDebugResources`와 관련 local unit/source/layout test가 통과한다.
- [x] 문구 표의 모든 한국어/영어/일본어 resource 값이 실제 resource와 일치한다.
- [x] 홈 후원 empty는 `creator_channel_home_donation_empty_title`, 후원 탭 empty는 `creator_channel_donation_empty_title`을 사용한다.
- [x] 홈 팬레터 empty UI가 팬레터 데이터 없음 상태에서 표시된다.
- [x] 내 채널의 홈 후원, 홈 팬레터, 팬레터 탭, 후원 탭 empty action 버튼이 모두 숨겨진다.
- [x] 타인 채널의 empty action 버튼은 기존 후원/팬레터 진입 동작을 유지한다.
- [x] 홈/팬레터/후원 empty action 버튼 색상이 화면별 확정 색상과 일치한다.
- [x] `./gradlew :app:mergeDebugResources`와 관련 local unit/source/layout test가 통과한다.
## 12. Open Questions
@@ -151,9 +156,13 @@
| 2026-08-14 | `DEC-001` | 확정 | 내 채널에서는 홈 탭 후원 empty, 홈 탭 팬레터 empty, 팬레터 탭 empty, 후원 탭 empty의 `후원하기`/`응원남기기` 버튼을 모두 숨긴다. | 사용자 A안 선택 | `CREATOR-EMPTY-UI-002~005`, `P1-T2`, `P1-T3` |
| 2026-08-14 | `DEC-002` | 확정 | 영어 resource도 이번 범위에 포함하고, 제공되지 않은 영문 문구는 한국어/일본어 의미에 맞춰 번역 초안을 사용한다. | 사용자 A안 선택 및 직접 지시 | `CREATOR-EMPTY-I18N-001~004`, `P1-T1` |
| 2026-08-14 | `DEC-003` | 확정 | 홈 후원 empty와 후원 탭 empty 문구가 다르므로 홈 전용 후원 empty string을 추가한다. | 기존 `creator_channel_donation_empty_title` 단일 key로 두 화면 문구를 동시에 만족할 수 없음 | `CREATOR-EMPTY-I18N-001`, `P1-T1`, `P1-T2` |
| 2026-08-14 | `DEC-004` | 확정 | empty action 버튼 색상은 홈 탭 white/black, 팬레터 탭 gray 800/white, 후원 탭 soda 400/white로 구분한다. | 사용자 직접 지시 | `CREATOR-EMPTY-UI-006~008`, `P1-T5` |
## 15. Verification Log
- 2026-08-14: `docs/sample/sample-prd.md`, `docs/sample/sample-plan-task.md`를 확인해 신규 문서 구조를 맞췄다.
- 2026-08-14: 기존 관련 문서 `docs/20260611_크리에이터_채널_홈_탭/prd.md`, `docs/20260622_크리에이터_채널_후원_탭/prd.md`, `docs/20260814_팬Talk_팬레터_resource_문구_변경/prd.md`를 확인했다.
- 2026-08-14: 현재 resource와 layout 사용처를 확인해 홈 후원 empty와 후원 탭 empty가 같은 string key를 공유한다는 제약을 문서화했다.
- 2026-08-14: 홈 팬레터 empty UI는 `item_creator_channel_home_fantalk.xml``layout_fantalk_empty``CreatorChannelHomeSectionAdapter.bindFanTalk()` 표시 분기가 이미 있어, 신규 UI 추가가 아니라 문구와 내 채널 action 버튼 정책 보강 범위로 정정했다.
- 2026-08-14: 구현 후 focused regression, `:app:mergeDebugResources`, 전체 `:app:testDebugUnitTest`, `git diff --check`가 통과했고 reviewer gate가 `APPROVE`했다.
- 2026-08-14: 후속 색상 수정에서 홈 후원 empty button 배경만 white capsule로 변경하고, 홈/팬레터/후원 empty action button 색상 source/layout test와 `:app:mergeDebugResources`가 통과했다.