fix(home): 팔로잉 크리에이터 전체 이동을 연결한다

This commit is contained in:
2026-06-30 17:43:14 +09:00
parent 05cbbdfddc
commit 658b4f0a9d
4 changed files with 111 additions and 9 deletions

View File

@@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
import kr.co.vividnext.sodalive.databinding.FragmentV2MainHomeBinding import kr.co.vividnext.sodalive.databinding.FragmentV2MainHomeBinding
import kr.co.vividnext.sodalive.databinding.ViewSectionTitleBinding import kr.co.vividnext.sodalive.databinding.ViewSectionTitleBinding
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
import kr.co.vividnext.sodalive.following.FollowingCreatorActivity
import kr.co.vividnext.sodalive.chat.talk.room.ChatRoomActivity import kr.co.vividnext.sodalive.chat.talk.room.ChatRoomActivity
import kr.co.vividnext.sodalive.home.pushnotification.PushNotificationListActivity import kr.co.vividnext.sodalive.home.pushnotification.PushNotificationListActivity
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
@@ -96,7 +97,10 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
) )
private val popularCommunityAdapter = HomePopularCommunityAdapter { openPopularCommunityPost(it) } private val popularCommunityAdapter = HomePopularCommunityAdapter { openPopularCommunityPost(it) }
private val creatorRankingAdapter = CreatorRankingAdapter { openCreatorRankingProfile(it) } private val creatorRankingAdapter = CreatorRankingAdapter { openCreatorRankingProfile(it) }
private val followingCreatorAdapter = HomeFollowingCreatorAdapter { openCreatorProfile(it.creatorId) } private val followingCreatorAdapter = HomeFollowingCreatorAdapter(
onClickItem = { openCreatorProfile(it.creatorId) },
onClickAll = { openFollowingCreatorAll() }
)
private val followingLiveAdapter = HomeFollowingLiveAdapter { onFollowingLiveClick(it) } private val followingLiveAdapter = HomeFollowingLiveAdapter { onFollowingLiveClick(it) }
private val followingChatAdapter = HomeFollowingChatAdapter { openFollowingChat(it) } private val followingChatAdapter = HomeFollowingChatAdapter { openFollowingChat(it) }
private val followingScheduleAdapter = HomeFollowingScheduleAdapter { onFollowingScheduleClick(it) } private val followingScheduleAdapter = HomeFollowingScheduleAdapter { onFollowingScheduleClick(it) }
@@ -526,6 +530,12 @@ class HomeMainFragment : BaseFragment<FragmentV2MainHomeBinding>(
private fun onFollowingNewsClick(item: HomeFollowingNewsUiItem) = Unit private fun onFollowingNewsClick(item: HomeFollowingNewsUiItem) = Unit
private fun openFollowingCreatorAll() {
ensureMainV2NavigationAllowed {
startActivity(Intent(requireContext(), FollowingCreatorActivity::class.java))
}
}
private fun openFollowingChat(item: ChatRoomListUiItem) { private fun openFollowingChat(item: ChatRoomListUiItem) {
ensureMainV2NavigationAllowed { ensureMainV2NavigationAllowed {
when (item.chatType) { when (item.chatType) {

View File

@@ -10,8 +10,9 @@ import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingCreatorUiItem import kr.co.vividnext.sodalive.v2.main.home.model.HomeFollowingCreatorUiItem
class HomeFollowingCreatorAdapter( class HomeFollowingCreatorAdapter(
private val onClickItem: (HomeFollowingCreatorUiItem) -> Unit = {} private val onClickItem: (HomeFollowingCreatorUiItem) -> Unit = {},
) : RecyclerView.Adapter<HomeFollowingCreatorAdapter.CreatorViewHolder>() { private val onClickAll: () -> Unit = {}
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var items: List<HomeFollowingCreatorUiItem> = emptyList() private var items: List<HomeFollowingCreatorUiItem> = emptyList()
fun submitItems(items: List<HomeFollowingCreatorUiItem>) { fun submitItems(items: List<HomeFollowingCreatorUiItem>) {
@@ -19,17 +20,29 @@ class HomeFollowingCreatorAdapter(
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CreatorViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_home_following_creator, parent, false) val layoutResId = when (viewType) {
VIEW_TYPE_ALL -> R.layout.item_home_following_creator_all
else -> R.layout.item_home_following_creator
}
val view = LayoutInflater.from(parent.context).inflate(layoutResId, parent, false)
view.layoutParams = recyclerItemLayoutParams(parent) view.layoutParams = recyclerItemLayoutParams(parent)
return CreatorViewHolder(view, onClickItem) return when (viewType) {
VIEW_TYPE_ALL -> AllViewHolder(view, onClickAll)
else -> CreatorViewHolder(view, onClickItem)
}
} }
override fun onBindViewHolder(holder: CreatorViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
holder.bind(items[position]) when (holder) {
is AllViewHolder -> holder.bind()
is CreatorViewHolder -> holder.bind(items[position])
}
} }
override fun getItemCount(): Int = items.size override fun getItemCount(): Int = items.size + if (items.isNotEmpty()) 1 else 0
override fun getItemViewType(position: Int): Int = if (position < items.size) VIEW_TYPE_CREATOR else VIEW_TYPE_ALL
class CreatorViewHolder( class CreatorViewHolder(
itemView: View, itemView: View,
@@ -44,4 +57,18 @@ class HomeFollowingCreatorAdapter(
itemView.setOnClickListener { onClickItem(item) } itemView.setOnClickListener { onClickItem(item) }
} }
} }
class AllViewHolder(
itemView: View,
private val onClickAll: () -> Unit
) : RecyclerView.ViewHolder(itemView) {
fun bind() {
itemView.setOnClickListener { onClickAll() }
}
}
private companion object {
private const val VIEW_TYPE_CREATOR = 0
private const val VIEW_TYPE_ALL = 1
}
} }

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="16dp">
<TextView
android:id="@+id/tv_home_following_creator_all"
style="@style/Typography.Body5"
android:layout_width="wrap_content"
android:layout_height="75dp"
android:gravity="center"
android:includeFontPadding="false"
android:text="@string/screen_home_theme_all"
android:textColor="@color/soda_400" />
<TextView
style="@style/Typography.Body5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_6"
android:includeFontPadding="false"
android:maxLines="1"
android:text="@string/screen_home_theme_all"
android:visibility="invisible" />
</LinearLayout>

View File

@@ -199,6 +199,38 @@ class HomeFollowingFragmentSourceTest {
assertTrue(itemLayout.contains("@style/Typography.Body5")) assertTrue(itemLayout.contains("@style/Typography.Body5"))
} }
@Test
fun `following creators list appends all button as last item`() {
val adapter = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeFollowingCreatorAdapter.kt"
).readText()
val fragment = homeMainFragmentSource()
val allLayoutFile = projectFileOrNull("app/src/main/res/layout/item_home_following_creator_all.xml")
assertTrue(allLayoutFile != null)
val allLayout = allLayoutFile?.readText().orEmpty()
assertTrue(adapter.contains("VIEW_TYPE_CREATOR"))
assertTrue(adapter.contains("VIEW_TYPE_ALL"))
assertTrue(adapter.contains("getItemViewType(position: Int)"))
assertTrue(adapter.contains("if (position < items.size) VIEW_TYPE_CREATOR else VIEW_TYPE_ALL"))
assertTrue(adapter.contains("override fun getItemCount(): Int = items.size + if (items.isNotEmpty()) 1 else 0"))
assertTrue(adapter.contains("R.layout.item_home_following_creator_all"))
assertTrue(adapter.contains("AllViewHolder"))
assertTrue(fragment.contains("import kr.co.vividnext.sodalive.following.FollowingCreatorActivity"))
assertTrue(fragment.contains("HomeFollowingCreatorAdapter("))
assertTrue(fragment.contains("onClickAll = { openFollowingCreatorAll() }"))
assertTrue(fragment.contains("private fun openFollowingCreatorAll()"))
assertTrue(fragment.contains("startActivity(Intent(requireContext(), FollowingCreatorActivity::class.java))"))
assertTrue(allLayout.contains("android:layout_width=\"wrap_content\""))
assertTrue(allLayout.contains("android:layout_height=\"wrap_content\""))
assertTrue(allLayout.contains("android:layout_height=\"75dp\""))
assertTrue(allLayout.contains("android:paddingHorizontal=\"16dp\""))
assertTrue(allLayout.contains("android:textColor=\"@color/soda_400\""))
assertTrue(allLayout.contains("android:visibility=\"invisible\""))
assertTrue(allLayout.contains("@string/screen_home_theme_all"))
}
@Test @Test
fun `following recent chats section is horizontal box list`() { fun `following recent chats section is horizontal box list`() {
val layout = homeMainLayoutSource() val layout = homeMainLayoutSource()
@@ -246,4 +278,9 @@ class HomeFollowingFragmentSourceTest {
val candidates = listOf(File(relativePath), File("../$relativePath")) val candidates = listOf(File(relativePath), File("../$relativePath"))
return candidates.first { it.exists() }.canonicalFile return candidates.first { it.exists() }.canonicalFile
} }
private fun projectFileOrNull(relativePath: String): File? {
val candidates = listOf(File(relativePath), File("../$relativePath"))
return candidates.firstOrNull { it.exists() }?.canonicalFile
}
} }