feat(home): 인기 캐릭터 색션 추가
This commit is contained in:
@@ -20,6 +20,7 @@ data class GetHomeResponse(
|
||||
@SerializedName("eventBannerList") val eventBannerList: GetEventResponse,
|
||||
@SerializedName("originalAudioDramaList") val originalAudioDramaList: List<GetSeriesListResponse.SeriesListItem>,
|
||||
@SerializedName("dayOfWeekSeriesList") val dayOfWeekSeriesList: List<GetSeriesListResponse.SeriesListItem>,
|
||||
@SerializedName("popularCharacters") val popularCharacters: List<Character>,
|
||||
@SerializedName("contentRanking") val contentRanking: List<GetAudioContentRankingItem>,
|
||||
@SerializedName("recommendChannelList") val recommendChannelList: List<RecommendChannelResponse>,
|
||||
@SerializedName("freeContentList") val freeContentList: List<AudioContentMainItem>,
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.os.Looper
|
||||
import android.text.SpannableString
|
||||
import android.text.Spanned
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
@@ -19,6 +20,7 @@ import androidx.media3.common.util.UnstableApi
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.gson.Gson
|
||||
import com.zhpan.bannerview.BaseBannerAdapter
|
||||
import com.zhpan.indicator.enums.IndicatorSlideMode
|
||||
import com.zhpan.indicator.enums.IndicatorStyle
|
||||
@@ -34,6 +36,10 @@ import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
|
||||
import kr.co.vividnext.sodalive.audition.AuditionActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||
import kr.co.vividnext.sodalive.chat.character.CharacterAdapter
|
||||
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.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
@@ -46,10 +52,15 @@ import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
|
||||
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
|
||||
import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import kr.co.vividnext.sodalive.mypage.MyPageViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.auth.Auth
|
||||
import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
|
||||
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||
import kr.co.vividnext.sodalive.search.SearchActivity
|
||||
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
|
||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||
import kr.co.vividnext.sodalive.splash.SplashActivity
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
@@ -59,6 +70,7 @@ import java.util.Locale
|
||||
class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::inflate) {
|
||||
private val viewModel: HomeViewModel by inject()
|
||||
private val liveViewModel: LiveViewModel by inject()
|
||||
private val myPageViewModel: MyPageViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
|
||||
@@ -70,6 +82,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
private lateinit var contentBannerAdapter: AudioContentMainBannerAdapter
|
||||
private lateinit var originalSeriesAdapter: HomeSeriesAdapter
|
||||
private lateinit var seriesDayOfWeekAdapter: HomeSeriesAdapter
|
||||
private lateinit var popularCharacterAdapter: CharacterAdapter
|
||||
private lateinit var weelyChartAdapter: HomeWeeklyChartAdapter
|
||||
private lateinit var recommendChannelAdapter: HomeRecommendChannelAdapter
|
||||
private lateinit var homeFreeContentAdapter: HomeContentAdapter
|
||||
@@ -173,6 +186,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
setupOriginalSeries()
|
||||
setupAudition()
|
||||
setupSeriesDayOfWeek()
|
||||
setupPopularCharacters()
|
||||
setupWeelyChart()
|
||||
setupRecommendChannel()
|
||||
setupFreeContent()
|
||||
@@ -777,6 +791,67 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
rvDayOfWeek.adapter = dayOfWeekAdapter
|
||||
}
|
||||
|
||||
private fun setupPopularCharacters() {
|
||||
// 인기 캐릭터 RecyclerView 설정 (순위 표시)
|
||||
popularCharacterAdapter = CharacterAdapter(
|
||||
showRanking = true
|
||||
) {
|
||||
onCharacterClick(it)
|
||||
}
|
||||
|
||||
val recyclerView = binding.rvPopularCharacters
|
||||
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
requireContext(),
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
|
||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
|
||||
when (parent.getChildAdapterPosition(view)) {
|
||||
0 -> {
|
||||
outRect.left = 0
|
||||
outRect.right = 8f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
popularCharacterAdapter.itemCount - 1 -> {
|
||||
outRect.left = 8f.dpToPx().toInt()
|
||||
outRect.right = 0
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.left = 8f.dpToPx().toInt()
|
||||
outRect.right = 8f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.adapter = popularCharacterAdapter
|
||||
|
||||
binding.tvPopularCharacterAll.setOnClickListener {
|
||||
(requireActivity() as MainActivity).openChatTab()
|
||||
}
|
||||
|
||||
// 인기 캐릭터 LiveData 구독
|
||||
viewModel.popularCharacters.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.llPopularCharacters.visibility = View.VISIBLE
|
||||
popularCharacterAdapter.updateCharacters(it)
|
||||
} else {
|
||||
binding.llPopularCharacters.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupWeelyChart() {
|
||||
val spSectionTitle = SpannableString(binding.tvWeeklyChart.text)
|
||||
spSectionTitle.setSpan(
|
||||
@@ -1196,4 +1271,65 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ensureLoginAndAuth(onAuthed: () -> Unit) {
|
||||
if (SharedPreferenceManager.token.isBlank()) {
|
||||
(requireActivity() as MainActivity).showLoginActivity()
|
||||
return
|
||||
}
|
||||
|
||||
if (!SharedPreferenceManager.isAuth) {
|
||||
SodaDialog(
|
||||
activity = requireActivity(),
|
||||
layoutInflater = layoutInflater,
|
||||
title = "본인인증",
|
||||
desc = "보이스온의 오픈월드 캐릭터톡은\n청소년 보호를 위해 본인인증한\n성인만 이용이 가능합니다.\n" +
|
||||
"캐릭터톡 서비스를 이용하시려면\n본인인증을 하고 이용해주세요.",
|
||||
confirmButtonTitle = "본인인증 하러가기",
|
||||
confirmButtonClick = { startAuthFlow() },
|
||||
cancelButtonTitle = "취소",
|
||||
cancelButtonClick = {},
|
||||
descGravity = Gravity.CENTER
|
||||
).show(screenWidth)
|
||||
return
|
||||
}
|
||||
|
||||
onAuthed()
|
||||
}
|
||||
|
||||
private fun startAuthFlow() {
|
||||
Auth.auth(requireActivity(), requireContext()) { json ->
|
||||
val bootpayResponse = Gson().fromJson(
|
||||
json,
|
||||
BootpayResponse::class.java
|
||||
)
|
||||
val request = AuthVerifyRequest(receiptId = bootpayResponse.data.receiptId)
|
||||
requireActivity().runOnUiThread {
|
||||
myPageViewModel.authVerify(request) {
|
||||
startActivity(
|
||||
Intent(
|
||||
requireContext(),
|
||||
SplashActivity::class.java
|
||||
).apply {
|
||||
addFlags(
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
)
|
||||
}
|
||||
)
|
||||
requireActivity().finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCharacterClick(characterId: Long) {
|
||||
ensureLoginAndAuth {
|
||||
startActivity(
|
||||
Intent(requireContext(), CharacterDetailActivity::class.java).apply {
|
||||
putExtra(EXTRA_CHARACTER_ID, characterId)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
|
||||
import kr.co.vividnext.sodalive.audio_content.main.v2.GetContentCurationResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.chat.character.Character
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.explorer.GetExplorerSectionCreatorResponse
|
||||
import kr.co.vividnext.sodalive.live.GetRoomListResponse
|
||||
@@ -58,6 +59,11 @@ class HomeViewModel(
|
||||
val dayOfWeekSeriesListLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
|
||||
get() = _dayOfWeekSeriesListLiveData
|
||||
|
||||
// 인기 캐릭터 LiveData
|
||||
private val _popularCharacters = MutableLiveData<List<Character>>(emptyList())
|
||||
val popularCharacters: LiveData<List<Character>>
|
||||
get() = _popularCharacters
|
||||
|
||||
private var _contentRankingLiveData = MutableLiveData<List<GetAudioContentRankingItem>>()
|
||||
val contentRankingLiveData: LiveData<List<GetAudioContentRankingItem>>
|
||||
get() = _contentRankingLiveData
|
||||
|
||||
@@ -596,6 +596,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
||||
}
|
||||
}
|
||||
|
||||
fun openChatTab() {
|
||||
viewModel.clickTab(MainViewModel.CurrentTab.CHAT)
|
||||
}
|
||||
|
||||
inner class AudioContentReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
val contentId = intent?.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
|
||||
|
||||
@@ -263,6 +263,51 @@
|
||||
android:paddingHorizontal="24dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 인기 캐릭터 섹션 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_popular_characters"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 제목과 전체보기 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/pretendard_bold"
|
||||
android:text="인기 캐릭터"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_popular_character_all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/pretendard_regular"
|
||||
android:text="전체보기"
|
||||
android:textColor="#90A4AE"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 캐릭터 카드 리스트 -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_popular_characters"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="24dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_weekly_chart"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
Reference in New Issue
Block a user