From ff1e134fe474e0a99f920384507370e38018fcf2 Mon Sep 17 00:00:00 2001 From: klaus Date: Wed, 13 Aug 2025 00:05:39 +0900 Subject: [PATCH] =?UTF-8?q?feat(character=20list):=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=20=ED=83=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 배너 리스트 추가 - 배너, 캐릭터 클릭시 캐릭터 상세 페이지로 이동 --- .../chat/character/CharacterBannerAdapter.kt | 54 ++++++++++++++++++ .../chat/character/CharacterHomeResponse.kt | 9 ++- .../chat/character/CharacterTabFragment.kt | 55 ++++++------------- .../chat/character/CharacterTabViewModel.kt | 4 +- .../detail/CharacterDetailActivity.kt | 8 +-- .../res/layout/fragment_character_tab.xml | 14 +++-- app/src/main/res/layout/item_character.xml | 4 ++ 7 files changed, 96 insertions(+), 52 deletions(-) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterBannerAdapter.kt diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterBannerAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterBannerAdapter.kt new file mode 100644 index 00000000..3b5b700f --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterBannerAdapter.kt @@ -0,0 +1,54 @@ +package kr.co.vividnext.sodalive.chat.character + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.widget.FrameLayout +import android.widget.ImageView +import com.bumptech.glide.Glide +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition +import com.zhpan.bannerview.BaseBannerAdapter +import com.zhpan.bannerview.BaseViewHolder +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse + +class CharacterBannerAdapter( + private val context: Context, + private val itemWidth: Int, + private val itemHeight: Int, + private val onClick: (CharacterBannerResponse) -> Unit +) : BaseBannerAdapter() { + override fun bindData( + holder: BaseViewHolder, + data: CharacterBannerResponse, + position: Int, + pageSize: Int + ) { + val ivBanner = holder.findViewById(R.id.iv_recommend_live) + val layoutParams = ivBanner.layoutParams as FrameLayout.LayoutParams + + layoutParams.width = itemWidth + layoutParams.height = itemHeight + + Glide + .with(context) + .asBitmap() + .load(data.imageUrl) + .into(object : CustomTarget() { + override fun onResourceReady(resource: Bitmap, transition: Transition?) { + ivBanner.setImageBitmap(resource) + ivBanner.layoutParams = layoutParams + } + + override fun onLoadCleared(placeholder: Drawable?) { + } + }) + + ivBanner.setOnClickListener { onClick(data) } + } + + override fun getLayoutId(viewType: Int): Int { + return R.layout.item_recommend_live + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterHomeResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterHomeResponse.kt index 5b552ad2..ea3bce61 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterHomeResponse.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterHomeResponse.kt @@ -2,15 +2,20 @@ package kr.co.vividnext.sodalive.chat.character import androidx.annotation.Keep import com.google.gson.annotations.SerializedName -import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse import kr.co.vividnext.sodalive.chat.character.curation.CurationSection import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacter @Keep data class CharacterHomeResponse( - @SerializedName("banners") val banners: List, + @SerializedName("banners") val banners: List, @SerializedName("recentCharacters") val recentCharacters: List, @SerializedName("popularCharacters") val popularCharacters: List, @SerializedName("newCharacters") val newCharacters: List, @SerializedName("curationSections") val curationSections: List ) + +@Keep +data class CharacterBannerResponse( + @SerializedName("characterId") val characterId: Long, + @SerializedName("imageUrl") val imageUrl: String +) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabFragment.kt index 9e6c8697..0aa06cfd 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabFragment.kt @@ -2,7 +2,6 @@ package kr.co.vividnext.sodalive.chat.character import android.content.Intent import android.graphics.Rect -import android.net.Uri import android.os.Bundle import android.view.View import android.widget.LinearLayout @@ -16,21 +15,17 @@ import com.zhpan.bannerview.BaseBannerAdapter import com.zhpan.indicator.enums.IndicatorSlideMode import com.zhpan.indicator.enums.IndicatorStyle import kr.co.vividnext.sodalive.R -import kr.co.vividnext.sodalive.audio_content.main.AudioContentBannerType -import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerAdapter -import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity import kr.co.vividnext.sodalive.base.BaseFragment import kr.co.vividnext.sodalive.chat.character.curation.CurationSectionAdapter +import kr.co.vividnext.sodalive.chat.character.detail.CharacterDetailActivity +import kr.co.vividnext.sodalive.chat.character.detail.CharacterDetailActivity.Companion.EXTRA_CHARACTER_ID import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacter import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacterAdapter -import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.databinding.FragmentCharacterTabBinding -import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.main.MainActivity -import kr.co.vividnext.sodalive.settings.event.EventDetailActivity import org.koin.android.ext.android.inject // 캐릭터 탭 프래그먼트 @@ -40,7 +35,7 @@ class CharacterTabFragment : BaseFragment( ) { private val viewModel: CharacterTabViewModel by inject() - private lateinit var contentBannerAdapter: AudioContentMainBannerAdapter + private lateinit var contentBannerAdapter: CharacterBannerAdapter private lateinit var recentCharacterAdapter: RecentCharacterAdapter private lateinit var popularCharacterAdapter: CharacterAdapter private lateinit var newCharacterAdapter: CharacterAdapter @@ -75,41 +70,17 @@ class CharacterTabFragment : BaseFragment( layoutParams.width = pagerWidth layoutParams.height = pagerHeight - contentBannerAdapter = AudioContentMainBannerAdapter( + contentBannerAdapter = CharacterBannerAdapter( requireContext(), pagerWidth, pagerHeight ) { if (SharedPreferenceManager.token.isNotBlank()) { - when (it.type) { - AudioContentBannerType.EVENT -> { - startActivity( - Intent(requireContext(), EventDetailActivity::class.java).apply { - putExtra(Constants.EXTRA_EVENT, it.eventItem!!) - } - ) + startActivity( + Intent(requireContext(), CharacterDetailActivity::class.java).apply { + putExtra(EXTRA_CHARACTER_ID, it.characterId) } - - AudioContentBannerType.CREATOR -> { - startActivity( - Intent(requireContext(), UserProfileActivity::class.java).apply { - putExtra(Constants.EXTRA_USER_ID, it.creatorId!!) - } - ) - } - - AudioContentBannerType.SERIES -> { - startActivity( - Intent(requireContext(), SeriesDetailActivity::class.java).apply { - putExtra(Constants.EXTRA_SERIES_ID, it.seriesId!!) - } - ) - } - - AudioContentBannerType.LINK -> { - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(it.link!!))) - } - } + ) } else { (requireActivity() as MainActivity).showLoginActivity() } @@ -401,6 +372,14 @@ class CharacterTabFragment : BaseFragment( } private fun onCharacterClick(character: Character) { - // TODO: 캐릭터 클릭 처리 + if (SharedPreferenceManager.token.isNotBlank()) { + startActivity( + Intent(requireContext(), CharacterDetailActivity::class.java).apply { + putExtra(EXTRA_CHARACTER_ID, character.id) + } + ) + } else { + (requireActivity() as MainActivity).showLoginActivity() + } } } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabViewModel.kt index 92e7137b..52c22286 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/CharacterTabViewModel.kt @@ -22,8 +22,8 @@ class CharacterTabViewModel( val toastLiveData: LiveData get() = _toastLiveData - private var _bannerListLiveData = MutableLiveData>() - val bannerListLiveData: LiveData> + private var _bannerListLiveData = MutableLiveData>() + val bannerListLiveData: LiveData> get() = _bannerListLiveData // 최근 대화한 캐릭터 LiveData diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/CharacterDetailActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/CharacterDetailActivity.kt index 935d0d6f..2496561a 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/CharacterDetailActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/CharacterDetailActivity.kt @@ -40,10 +40,10 @@ class CharacterDetailActivity : BaseActivity( // 더미 데이터 로드 (추후 Intent/Repository 연동) val characterId = intent.getLongExtra(EXTRA_CHARACTER_ID, 0) -// if (characterId <= 0) { -// showToast("잘못된 접근 입니다.") -// finish() -// } + if (characterId <= 0) { + showToast("잘못된 접근 입니다.") + finish() + } viewModel.loadMock(characterId) bindObservers() diff --git a/app/src/main/res/layout/fragment_character_tab.xml b/app/src/main/res/layout/fragment_character_tab.xml index aa4c184a..d7c3e073 100644 --- a/app/src/main/res/layout/fragment_character_tab.xml +++ b/app/src/main/res/layout/fragment_character_tab.xml @@ -17,7 +17,7 @@ android:id="@+id/ll_banner" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="48dp" + android:layout_marginBottom="24dp" android:orientation="vertical"> @@ -87,7 +87,7 @@ android:id="@+id/ll_popular_characters" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="48dp" + android:layout_marginBottom="24dp" android:orientation="vertical"> @@ -114,7 +114,8 @@ android:fontFamily="@font/pretendard_regular" android:text="전체보기" android:textColor="#90A4AE" - android:textSize="14sp" /> + android:textSize="14sp" + android:visibility="gone" /> @@ -132,7 +133,7 @@ android:id="@+id/ll_new_characters" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="48dp" + android:layout_marginBottom="24dp" android:orientation="vertical"> @@ -159,7 +160,8 @@ android:fontFamily="@font/pretendard_regular" android:text="전체보기" android:textColor="#90A4AE" - android:textSize="14sp" /> + android:textSize="14sp" + android:visibility="gone" /> diff --git a/app/src/main/res/layout/item_character.xml b/app/src/main/res/layout/item_character.xml index 697184df..b596d8ff 100644 --- a/app/src/main/res/layout/item_character.xml +++ b/app/src/main/res/layout/item_character.xml @@ -47,7 +47,9 @@ android:id="@+id/tv_character_name" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:ellipsize="end" android:fontFamily="@font/pretendard_regular" + android:maxLines="1" android:textColor="@color/color_b0bec5" android:textSize="18sp" /> @@ -56,7 +58,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="4dp" + android:ellipsize="end" android:fontFamily="@font/pretendard_regular" + android:maxLines="1" android:textColor="#78909C" android:textSize="14sp" />