feat(creator): empty state 문구와 버튼 정책을 정리한다
This commit is contained in:
+3
-4
@@ -102,12 +102,11 @@ class CreatorChannelDonationAdapter(
|
||||
private val onEmptyDonationClick: () -> Unit
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
init {
|
||||
binding.btnCreatorChannelDonationEmptyWrite.setOnClickListener { onEmptyDonationClick() }
|
||||
}
|
||||
|
||||
fun bind(isOwner: Boolean) = with(binding) {
|
||||
btnCreatorChannelDonationEmptyWrite.isVisible = !isOwner
|
||||
btnCreatorChannelDonationEmptyWrite.setOnClickListener(
|
||||
if (!isOwner) View.OnClickListener { onEmptyDonationClick() } else null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -80,7 +80,6 @@ class CreatorChannelFanTalkFragment : BaseFragment<FragmentCreatorChannelFantalk
|
||||
viewModel.retryFanTalks()
|
||||
}
|
||||
btnCreatorChannelFantalkWrite.setOnClickListener { host.onCreatorChannelFanTalkWriteClicked() }
|
||||
layoutCreatorChannelFantalkEmptyWriteButton.setOnClickListener { host.onCreatorChannelFanTalkWriteClicked() }
|
||||
}
|
||||
|
||||
private fun observeViewModel() {
|
||||
@@ -113,6 +112,10 @@ class CreatorChannelFanTalkFragment : BaseFragment<FragmentCreatorChannelFantalk
|
||||
tvCreatorChannelFantalkErrorMessage.isVisible = false
|
||||
btnCreatorChannelFantalkRetry.isVisible = false
|
||||
btnCreatorChannelFantalkWrite.isVisible = false
|
||||
layoutCreatorChannelFantalkEmptyWriteButton.isVisible = !host.isCreatorChannelOwner()
|
||||
layoutCreatorChannelFantalkEmptyWriteButton.setOnClickListener(
|
||||
if (!host.isCreatorChannelOwner()) View.OnClickListener { host.onCreatorChannelFanTalkWriteClicked() } else null
|
||||
)
|
||||
host.onCreatorChannelFanTalkFloatingButtonVisibilityChanged(false)
|
||||
host.onCreatorChannelFanTalkContentChanged()
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ fun CreatorChannelHomeResponse.toUiContent(currentMemberId: Long): CreatorChanne
|
||||
series.takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.Series(it)) }
|
||||
communities.takeIf { it.isNotEmpty() }
|
||||
?.let { add(CreatorChannelHomeSection.Communities(it, currentMemberId)) }
|
||||
add(CreatorChannelHomeSection.FanTalk(fanTalk))
|
||||
add(CreatorChannelHomeSection.FanTalk(fanTalk, isOwner))
|
||||
introduce.takeIf { it.isNotBlank() }?.let { add(CreatorChannelHomeSection.Introduce(it)) }
|
||||
add(CreatorChannelHomeSection.Activity(activity))
|
||||
sns.toUiItems().takeIf { it.isNotEmpty() }?.let { add(CreatorChannelHomeSection.Sns(it)) }
|
||||
|
||||
+4
-1
@@ -61,7 +61,10 @@ sealed interface CreatorChannelHomeSection {
|
||||
val communities: List<CreatorChannelCommunityPostResponse>,
|
||||
val currentMemberId: Long
|
||||
) : CreatorChannelHomeSection
|
||||
data class FanTalk(val fanTalk: CreatorChannelFanTalkSummaryResponse) : CreatorChannelHomeSection
|
||||
data class FanTalk(
|
||||
val fanTalk: CreatorChannelFanTalkSummaryResponse,
|
||||
val isOwner: Boolean
|
||||
) : CreatorChannelHomeSection
|
||||
data class Introduce(val introduce: String) : CreatorChannelHomeSection
|
||||
data class Activity(val activity: CreatorChannelActivityResponse) : CreatorChannelHomeSection
|
||||
data class Sns(val items: List<CreatorChannelSnsUiItem>) : CreatorChannelHomeSection
|
||||
|
||||
+7
-7
@@ -113,6 +113,7 @@ class CreatorChannelHomeSectionAdapter(
|
||||
private val fanTalkTotalRow: View? = view.findViewById(R.id.layout_fantalk_total_row)
|
||||
private val fanTalkLatestRow: View? = view.findViewById(R.id.layout_fantalk_latest_row)
|
||||
private val fanTalkEmpty: View? = view.findViewById(R.id.layout_fantalk_empty)
|
||||
private val fanTalkSupportButton: View? = view.findViewById(R.id.layout_fantalk_support_button)
|
||||
private val fanTalkTotalCount: TextView? = view.findViewById(R.id.tv_fantalk_total_count)
|
||||
private val fanTalkProfile: ImageView? = view.findViewById(R.id.iv_fantalk_profile)
|
||||
private val fanTalkContent: TextView? = view.findViewById(R.id.tv_fantalk_content)
|
||||
@@ -184,13 +185,7 @@ class CreatorChannelHomeSectionAdapter(
|
||||
val isDonationEmptyButtonVisible = !item.isOwner
|
||||
donationButton?.isVisible = isDonationButtonVisible
|
||||
donationEmptyButton?.isVisible = isDonationEmptyButtonVisible
|
||||
donationEmptyTitle?.setText(
|
||||
if (item.isOwner) {
|
||||
R.string.creator_channel_donation_empty_owner_title
|
||||
} else {
|
||||
R.string.creator_channel_donation_empty_title
|
||||
}
|
||||
)
|
||||
donationEmptyTitle?.setText(R.string.creator_channel_home_donation_empty_title)
|
||||
donationButton?.setOnClickListener(
|
||||
if (isDonationButtonVisible) View.OnClickListener { onDonationClick() } else null
|
||||
)
|
||||
@@ -417,6 +412,11 @@ class CreatorChannelHomeSectionAdapter(
|
||||
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 (showSupportButton) View.OnClickListener { onSectionChevronClick(CreatorChannelTab.FanTalk) } else null
|
||||
)
|
||||
if (fanTalk != null) {
|
||||
fanTalkContent?.text = fanTalk.content
|
||||
fanTalkProfile?.loadUrl(fanTalk.profileImageUrl) {
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="true"
|
||||
android:text="@string/creator_channel_donation_empty_title"
|
||||
android:text="@string/creator_channel_home_donation_empty_title"
|
||||
android:textColor="@color/white" />
|
||||
|
||||
<LinearLayout
|
||||
@@ -57,7 +57,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginTop="42dp"
|
||||
android:background="@drawable/bg_creator_channel_donation_empty_button"
|
||||
android:background="@drawable/bg_round_corner_999_white"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
|
||||
@@ -77,10 +77,11 @@
|
||||
tools:text="팬이 쓴 응원이 보이는 부분입니다. 두 줄까지만 보여주고 초과 시 말줄임 처리." />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_fantalk_empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="169dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
@@ -89,7 +90,6 @@
|
||||
style="@style/Typography.Heading1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|start"
|
||||
android:layout_marginStart="@dimen/spacing_6"
|
||||
android:layout_marginTop="@dimen/spacing_6"
|
||||
android:includeFontPadding="false"
|
||||
@@ -100,8 +100,7 @@
|
||||
android:id="@+id/layout_fantalk_support_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:layout_marginBottom="@dimen/spacing_6"
|
||||
android:layout_marginTop="@dimen/spacing_14"
|
||||
android:background="@drawable/bg_round_corner_999_white"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
@@ -122,6 +121,6 @@
|
||||
android:text="@string/creator_channel_fantalk_support_action"
|
||||
android:textColor="@color/black" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</kr.co.vividnext.sodalive.v2.creator.channel.ui.CreatorChannelFanTalkCardView>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -375,9 +375,9 @@
|
||||
<string name="creator_channel_community_invalid_post">Could not load the post.</string>
|
||||
<string name="creator_channel_community_purchased_badge">Purchased</string>
|
||||
<string name="creator_channel_fantalk_summary">%1$s · Total %2$d</string>
|
||||
<string name="creator_channel_fantalk_empty_title">Be the first\nto cheer them on!</string>
|
||||
<string name="creator_channel_fantalk_support_action">Leave support</string>
|
||||
<string name="creator_channel_fantalk_empty_message">No cheers yet.\nBe the first to cheer for the creator!</string>
|
||||
<string name="creator_channel_fantalk_empty_title">We\'re waiting for your\nfirst fan letter!</string>
|
||||
<string name="creator_channel_fantalk_support_action">Send fan letter</string>
|
||||
<string name="creator_channel_fantalk_empty_message">No fan letters yet.\nSend the first fan letter!</string>
|
||||
<string name="creator_channel_fantalk_error_message">Could not load Fan Letter.</string>
|
||||
<string name="creator_channel_fantalk_retry">Retry</string>
|
||||
<string name="creator_channel_fantalk_all_label">All</string>
|
||||
@@ -404,7 +404,8 @@
|
||||
<string name="creator_channel_donation_action">Support</string>
|
||||
<string name="creator_channel_donation_error_message">Could not load donation history.</string>
|
||||
<string name="creator_channel_donation_retry">Retry</string>
|
||||
<string name="creator_channel_donation_empty_title">Be the first to\nsupport this creator!</string>
|
||||
<string name="creator_channel_home_donation_empty_title">Be the first to\nsupport this creator!</string>
|
||||
<string name="creator_channel_donation_empty_title">No support yet.\nBe the first to support this creator!</string>
|
||||
<string name="creator_channel_donation_empty_owner_title">No donation history yet.</string>
|
||||
<string name="creator_channel_donation_can_format">%1$s cans</string>
|
||||
<string name="creator_channel_donation_fallback_message">Supported with %1$d cans.</string>
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
<string name="creator_channel_community_invalid_post">投稿を読み込めません。</string>
|
||||
<string name="creator_channel_community_purchased_badge">購入済み</string>
|
||||
<string name="creator_channel_fantalk_summary">%1$s · 全体 %2$d</string>
|
||||
<string name="creator_channel_fantalk_empty_title">最初の応援を\n待っています!</string>
|
||||
<string name="creator_channel_fantalk_empty_title">あなたの最初のファンレターを待っています!</string>
|
||||
<string name="creator_channel_fantalk_support_action">ファンレターを送る</string>
|
||||
<string name="creator_channel_fantalk_empty_message">まだファンレターがありません。\n最初のファンレターを送ってみましょう!</string>
|
||||
<string name="creator_channel_fantalk_error_message">ファンレターを読み込めませんでした。</string>
|
||||
@@ -404,6 +404,7 @@
|
||||
<string name="creator_channel_donation_action">サポートする</string>
|
||||
<string name="creator_channel_donation_error_message">応援履歴を読み込めませんでした。</string>
|
||||
<string name="creator_channel_donation_retry">再試行</string>
|
||||
<string name="creator_channel_home_donation_empty_title">最初のサポートをしてみましょう!</string>
|
||||
<string name="creator_channel_donation_empty_title">まだサポートがありません。\n最初のサポートをしてみましょう!</string>
|
||||
<string name="creator_channel_donation_empty_owner_title">応援履歴がありません</string>
|
||||
<string name="creator_channel_donation_can_format">%1$sCAN</string>
|
||||
|
||||
@@ -403,6 +403,7 @@
|
||||
<string name="creator_channel_donation_action">후원하기</string>
|
||||
<string name="creator_channel_donation_error_message">후원 내역을 불러오지 못했습니다.</string>
|
||||
<string name="creator_channel_donation_retry">다시 시도</string>
|
||||
<string name="creator_channel_home_donation_empty_title">처음으로 크리에이터를\n후원해 보세요!</string>
|
||||
<string name="creator_channel_donation_empty_title">아직 후원이 없습니다.\n처음으로 크리에이터를 후원해 보세요!</string>
|
||||
<string name="creator_channel_donation_empty_owner_title">후원 내역이 없습니다</string>
|
||||
<string name="creator_channel_donation_can_format">%1$s캔</string>
|
||||
|
||||
+28
-10
@@ -1113,7 +1113,12 @@ class CreatorChannelActivitySourceTest {
|
||||
assertTrue(donationLayout.contains("@+id/ll_donation_items"))
|
||||
assertTrue(donationLayout.contains("@+id/layout_donation_empty"))
|
||||
assertTrue(donationLayout.contains("@+id/tv_donation_empty_title"))
|
||||
assertTrue(donationLayout.contains("@string/creator_channel_donation_empty_title"))
|
||||
assertTrue(donationLayout.contains("@string/creator_channel_home_donation_empty_title"))
|
||||
val donationEmptyButtonBlock = donationLayout
|
||||
.substringAfter("android:id=\"@+id/layout_donation_empty_button\"")
|
||||
.substringBefore("</LinearLayout>")
|
||||
assertTrue(donationEmptyButtonBlock.contains("android:background=\"@drawable/bg_round_corner_999_white\""))
|
||||
assertTrue(donationEmptyButtonBlock.contains("android:textColor=\"@color/black\""))
|
||||
assertTrue(donationLayout.contains("android:layout_width=\"match_parent\""))
|
||||
assertTrue(donationLayout.contains("android:layout_height=\"wrap_content\""))
|
||||
assertTrue(donationLayout.contains("@+id/layout_donation_button"))
|
||||
@@ -1308,13 +1313,15 @@ class CreatorChannelActivitySourceTest {
|
||||
val en = projectFile("app/src/main/res/values-en/strings.xml").readText()
|
||||
val ja = projectFile("app/src/main/res/values-ja/strings.xml").readText()
|
||||
|
||||
assertTrue(
|
||||
ko.contains(
|
||||
"name=\"creator_channel_donation_empty_title\">아직 후원이 없습니다.\\n처음으로 크리에이터를 후원해 보세요!"
|
||||
)
|
||||
)
|
||||
assertTrue(en.contains("creator_channel_donation_empty_title"))
|
||||
assertTrue(ja.contains("creator_channel_donation_empty_title"))
|
||||
assertTrue(ko.contains("name=\"creator_channel_home_donation_empty_title\">처음으로 크리에이터를\\n후원해 보세요!"))
|
||||
assertTrue(en.contains("name=\"creator_channel_home_donation_empty_title\">Be the first to\\nsupport this creator!"))
|
||||
assertTrue(ja.contains("name=\"creator_channel_home_donation_empty_title\">最初のサポートをしてみましょう!"))
|
||||
assertTrue(ko.contains("name=\"creator_channel_donation_empty_title\">아직 후원이 없습니다.\\n처음으로 크리에이터를 후원해 보세요!"))
|
||||
assertTrue(en.contains("name=\"creator_channel_donation_empty_title\">No support yet.\\nBe the first to support this creator!"))
|
||||
assertTrue(ja.contains("name=\"creator_channel_donation_empty_title\">まだサポートがありません。\\n最初のサポートをしてみましょう!"))
|
||||
assertTrue(ko.contains("name=\"creator_channel_donation_action\">후원하기"))
|
||||
assertTrue(en.contains("name=\"creator_channel_donation_action\">Support"))
|
||||
assertTrue(ja.contains("name=\"creator_channel_donation_action\">サポートする"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2136,10 +2143,17 @@ class CreatorChannelActivitySourceTest {
|
||||
assertTrue(fanTalkLayout.contains("@+id/layout_fantalk_support_button"))
|
||||
assertTrue(fanTalkLayout.contains("@string/creator_channel_fantalk_empty_title"))
|
||||
assertTrue(fanTalkLayout.contains("@string/creator_channel_fantalk_support_action"))
|
||||
val fanTalkSupportButtonBlock = fanTalkLayout
|
||||
.substringAfter("android:id=\"@+id/layout_fantalk_support_button\"")
|
||||
.substringBefore("</LinearLayout>")
|
||||
assertTrue(fanTalkSupportButtonBlock.contains("android:background=\"@drawable/bg_round_corner_999_white\""))
|
||||
assertTrue(fanTalkSupportButtonBlock.contains("android:textColor=\"@color/black\""))
|
||||
assertTrue(fanTalkLayout.contains("@drawable/ic_new_fantalk_plus"))
|
||||
assertTrue(fanTalkLayout.contains("android:layout_width=\"match_parent\""))
|
||||
assertTrue(fanTalkLayout.contains("android:layout_height=\"169dp\""))
|
||||
assertTrue(fanTalkLayout.contains("android:layout_marginBottom=\"@dimen/spacing_6\""))
|
||||
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\""))
|
||||
assertFalse(fanTalkLayout.contains("@+id/ll_section_items"))
|
||||
assertFalse(fanTalkLayout.contains("android:clipToOutline"))
|
||||
assertTrue(fanTalkCardView.contains("clipToOutline = true"))
|
||||
@@ -2153,10 +2167,14 @@ class CreatorChannelActivitySourceTest {
|
||||
assertTrue(adapter.contains("private val fanTalkTotalRow: View?"))
|
||||
assertTrue(adapter.contains("private val fanTalkLatestRow: View?"))
|
||||
assertTrue(adapter.contains("private val fanTalkEmpty: View?"))
|
||||
assertTrue(adapter.contains("private val fanTalkSupportButton: View?"))
|
||||
assertTrue(adapter.contains("fanTalkTotalCount?.text = item.fanTalk.totalCount.toString()"))
|
||||
assertTrue(adapter.contains("fanTalkTotalRow?.isVisible = fanTalk != null"))
|
||||
assertTrue(adapter.contains("fanTalkLatestRow?.isVisible = fanTalk != null"))
|
||||
assertTrue(adapter.contains("fanTalkEmpty?.isVisible = fanTalk == null"))
|
||||
assertTrue(adapter.contains("val showSupportButton = (fanTalk == null || item.fanTalk.totalCount <= 0) && !item.isOwner"))
|
||||
assertTrue(adapter.contains("fanTalkSupportButton?.isVisible = showSupportButton"))
|
||||
assertTrue(adapter.contains("fanTalkSupportButton?.setOnClickListener"))
|
||||
assertTrue(adapter.contains("fanTalkContent?.text = fanTalk.content"))
|
||||
assertTrue(adapter.contains("fanTalkProfile?.loadUrl(fanTalk.profileImageUrl)"))
|
||||
assertTrue(adapter.contains("fanTalkContent?.text = \"\""))
|
||||
|
||||
+3
-1
@@ -53,12 +53,14 @@ class CreatorChannelHomeMapperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `본인 채널 여부를 후원 section에도 매핑한다`() {
|
||||
fun `본인 채널 여부를 후원과 팬Talk section에도 매핑한다`() {
|
||||
val ownerContent = response().toUiContent(currentMemberId = 100L)
|
||||
val visitorContent = response().toUiContent(currentMemberId = 1L)
|
||||
|
||||
assertTrue(ownerContent.sections.filterIsInstance<CreatorChannelHomeSection.Donations>().single().isOwner)
|
||||
assertFalse(visitorContent.sections.filterIsInstance<CreatorChannelHomeSection.Donations>().single().isOwner)
|
||||
assertTrue(ownerContent.sections.filterIsInstance<CreatorChannelHomeSection.FanTalk>().single().isOwner)
|
||||
assertFalse(visitorContent.sections.filterIsInstance<CreatorChannelHomeSection.FanTalk>().single().isOwner)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ class CreatorChannelDonationActionTest {
|
||||
assertTrue(adapter.contains("onEmptyDonationClick"))
|
||||
assertTrue(adapter.contains("btnCreatorChannelDonationRankingAll.setOnClickListener"))
|
||||
assertTrue(adapter.contains("btnCreatorChannelDonationEmptyWrite.isVisible = !isOwner"))
|
||||
assertTrue(adapter.contains("btnCreatorChannelDonationEmptyWrite.setOnClickListener"))
|
||||
assertTrue(adapter.contains("if (!isOwner) View.OnClickListener { onEmptyDonationClick() } else null"))
|
||||
assertTrue(adapter.contains("bindCreatorChannelDonationCard("))
|
||||
assertTrue(adapter.contains("headerColorResId = item.headerColorResId"))
|
||||
assertTrue(adapter.contains("createdAtText = item.createdAtText"))
|
||||
|
||||
+1
@@ -57,6 +57,7 @@ class CreatorChannelDonationFragmentLayoutTest {
|
||||
assertTrue(layout.contains("android:text=\"@string/creator_channel_donation_empty_title\""))
|
||||
assertTrue(layout.contains("android:text=\"@string/creator_channel_donation_action\""))
|
||||
assertTrue(layout.contains("android:background=\"@drawable/bg_creator_channel_donation_empty_button\""))
|
||||
assertTrue(layout.contains("android:textColor=\"@color/white\""))
|
||||
assertTrue(layout.contains("android:layout_marginTop=\"@dimen/spacing_14\""))
|
||||
assertTrue(layout.contains("android:src=\"@drawable/ic_new_donation\""))
|
||||
assertTrue(layout.contains("android:paddingTop=\"@dimen/spacing_48\""))
|
||||
|
||||
+13
-5
@@ -81,9 +81,15 @@ class CreatorChannelFanTalkFragmentLayoutTest {
|
||||
.readText()
|
||||
.contains("@color/gray_800")
|
||||
)
|
||||
assertLocaleString("values/strings.xml", "아직 응원이 없습니다.\\n처음으로 크리에이터를 응원해 보세요!")
|
||||
assertLocaleString("values-en/strings.xml", "No cheers yet.\\nBe the first to cheer for the creator!")
|
||||
assertLocaleString("values-ja/strings.xml", "まだファンレターがありません。\\n最初のファンレターを送ってみましょう!")
|
||||
assertLocaleString("values/strings.xml", "creator_channel_fantalk_empty_title", "당신의 첫 응원을\\n기다리고 있어요!")
|
||||
assertLocaleString("values-en/strings.xml", "creator_channel_fantalk_empty_title", "We\\'re waiting for your\\nfirst fan letter!")
|
||||
assertLocaleString("values-ja/strings.xml", "creator_channel_fantalk_empty_title", "あなたの最初のファンレターを待っています!")
|
||||
assertLocaleString("values/strings.xml", "creator_channel_fantalk_empty_message", "아직 응원이 없습니다.\\n처음으로 크리에이터를 응원해 보세요!")
|
||||
assertLocaleString("values-en/strings.xml", "creator_channel_fantalk_empty_message", "No fan letters yet.\\nSend the first fan letter!")
|
||||
assertLocaleString("values-ja/strings.xml", "creator_channel_fantalk_empty_message", "まだファンレターがありません。\\n最初のファンレターを送ってみましょう!")
|
||||
assertLocaleString("values/strings.xml", "creator_channel_fantalk_support_action", "응원남기기")
|
||||
assertLocaleString("values-en/strings.xml", "creator_channel_fantalk_support_action", "Send fan letter")
|
||||
assertLocaleString("values-ja/strings.xml", "creator_channel_fantalk_support_action", "ファンレターを送る")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -209,10 +215,12 @@ class CreatorChannelFanTalkFragmentLayoutTest {
|
||||
assertTrue(fragment.contains("fun onCreatorChannelFanTalkWriteClicked()"))
|
||||
assertTrue(fragment.contains("fun onCreatorChannelFanTalkFloatingButtonVisibilityChanged(isVisible: Boolean)"))
|
||||
assertTrue(fragment.contains("layoutCreatorChannelFantalkEmptyWriteButton.setOnClickListener"))
|
||||
assertTrue(fragment.contains("layoutCreatorChannelFantalkEmptyWriteButton.isVisible = !host.isCreatorChannelOwner()"))
|
||||
assertTrue(fragment.contains("host.onCreatorChannelFanTalkWriteClicked()"))
|
||||
assertTrue(fragment.contains("host.onCreatorChannelFanTalkFloatingButtonVisibilityChanged(true)"))
|
||||
assertTrue(fragment.contains("host.onCreatorChannelFanTalkFloatingButtonVisibilityChanged(false)"))
|
||||
assertFalse(fragment.contains("btnCreatorChannelFantalkWrite.setOnClickListener { }"))
|
||||
assertFalse(fragment.contains("layoutCreatorChannelFantalkEmptyWriteButton.setOnClickListener { host.onCreatorChannelFanTalkWriteClicked() }"))
|
||||
assertFalse(fragment.contains("btnCreatorChannelFantalkWrite.isVisible = true"))
|
||||
assertTrue(layout.contains("@+id/layout_creator_channel_fantalk_empty_write_button"))
|
||||
assertTrue(layout.contains("android:id=\"@+id/btn_creator_channel_fantalk_write\""))
|
||||
@@ -227,9 +235,9 @@ class CreatorChannelFanTalkFragmentLayoutTest {
|
||||
|
||||
private fun projectFile(path: String): File = File(projectRoot(), path)
|
||||
|
||||
private fun assertLocaleString(path: String, expectedValue: String) {
|
||||
private fun assertLocaleString(path: String, name: String, expectedValue: String) {
|
||||
val strings = projectFile("app/src/main/res/$path").readText()
|
||||
assertTrue(strings.contains("<string name=\"creator_channel_fantalk_empty_message\">$expectedValue</string>"))
|
||||
assertTrue(strings.contains("<string name=\"$name\">$expectedValue</string>"))
|
||||
}
|
||||
|
||||
private fun projectRoot(): File {
|
||||
|
||||
@@ -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`가 통과했다.
|
||||
|
||||
Reference in New Issue
Block a user