feat(character list): 캐릭터 탭
- 배너 리스트 추가 - 배너, 캐릭터 클릭시 캐릭터 상세 페이지로 이동
This commit is contained in:
@@ -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<CharacterBannerResponse>() {
|
||||
override fun bindData(
|
||||
holder: BaseViewHolder<CharacterBannerResponse>,
|
||||
data: CharacterBannerResponse,
|
||||
position: Int,
|
||||
pageSize: Int
|
||||
) {
|
||||
val ivBanner = holder.findViewById<ImageView>(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<Bitmap>() {
|
||||
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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<GetAudioContentBannerResponse>,
|
||||
@SerializedName("banners") val banners: List<CharacterBannerResponse>,
|
||||
@SerializedName("recentCharacters") val recentCharacters: List<RecentCharacter>,
|
||||
@SerializedName("popularCharacters") val popularCharacters: List<Character>,
|
||||
@SerializedName("newCharacters") val newCharacters: List<Character>,
|
||||
@SerializedName("curationSections") val curationSections: List<CurationSection>
|
||||
)
|
||||
|
||||
@Keep
|
||||
data class CharacterBannerResponse(
|
||||
@SerializedName("characterId") val characterId: Long,
|
||||
@SerializedName("imageUrl") val imageUrl: String
|
||||
)
|
||||
|
||||
@@ -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<FragmentCharacterTabBinding>(
|
||||
) {
|
||||
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<FragmentCharacterTabBinding>(
|
||||
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<FragmentCharacterTabBinding>(
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ class CharacterTabViewModel(
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _bannerListLiveData = MutableLiveData<List<GetAudioContentBannerResponse>>()
|
||||
val bannerListLiveData: LiveData<List<GetAudioContentBannerResponse>>
|
||||
private var _bannerListLiveData = MutableLiveData<List<CharacterBannerResponse>>()
|
||||
val bannerListLiveData: LiveData<List<CharacterBannerResponse>>
|
||||
get() = _bannerListLiveData
|
||||
|
||||
// 최근 대화한 캐릭터 LiveData
|
||||
|
||||
@@ -40,10 +40,10 @@ class CharacterDetailActivity : BaseActivity<ActivityCharacterDetailBinding>(
|
||||
// 더미 데이터 로드 (추후 Intent/Repository 연동)
|
||||
val characterId = intent.getLongExtra(EXTRA_CHARACTER_ID, 0)
|
||||
|
||||
// if (characterId <= 0) {
|
||||
// showToast("잘못된 접근 입니다.")
|
||||
// finish()
|
||||
// }
|
||||
if (characterId <= 0) {
|
||||
showToast("잘못된 접근 입니다.")
|
||||
finish()
|
||||
}
|
||||
|
||||
viewModel.loadMock(characterId)
|
||||
bindObservers()
|
||||
|
||||
@@ -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">
|
||||
|
||||
<com.zhpan.bannerview.BannerViewPager
|
||||
@@ -40,7 +40,7 @@
|
||||
android:id="@+id/ll_latest_characters"
|
||||
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" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 캐릭터 카드 리스트 -->
|
||||
@@ -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" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user