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!!)
 | 
			
		||||
                    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