feat(series-main): 시리즈 전체보기 페이지 추가
- 홈, 요일별, 장르별 탭 추가 - 홈 리스트 UI 및 데이터 - 요일별 UI 및 데이터
This commit is contained in:
@@ -86,13 +86,15 @@
|
||||
<data android:scheme="${URISCHEME}" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- PayVerse 리다이렉트에 등록할 커스텀 스킴/호스트 -->
|
||||
<data android:scheme="${URISCHEME}"
|
||||
<data
|
||||
android:host="payverse"
|
||||
android:path="/result"/>
|
||||
android:path="/result"
|
||||
android:scheme="${URISCHEME}" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
@@ -196,6 +198,7 @@
|
||||
</activity>
|
||||
<activity android:name=".chat.character.newcharacters.NewCharactersAllActivity" />
|
||||
<activity android:name=".chat.original.detail.OriginalWorkDetailActivity" />
|
||||
<activity android:name=".audio_content.series.main.SeriesMainActivity" />
|
||||
|
||||
<activity
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main
|
||||
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.by_genre.SeriesMainByGenreFragment
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.day_of_week.SeriesMainDayOfWeekFragment
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.home.SeriesMainHomeFragment
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.databinding.ActivitySeriesMainBinding
|
||||
|
||||
class SeriesMainActivity : BaseActivity<ActivitySeriesMainBinding>(
|
||||
ActivitySeriesMainBinding::inflate
|
||||
) {
|
||||
private var currentTab = 0
|
||||
|
||||
override fun setupView() {
|
||||
binding.toolbar.tvBack.text = "시리즈 전체보기"
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
setupTabs()
|
||||
}
|
||||
|
||||
private fun setupTabs() {
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("홈"))
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("요일별"))
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("장르별"))
|
||||
|
||||
// 탭 선택 리스너 설정
|
||||
binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
currentTab = tab.position
|
||||
showTabContent(currentTab)
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab) {
|
||||
// 필요한 경우 구현
|
||||
}
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab) {
|
||||
// 필요한 경우 구현
|
||||
}
|
||||
})
|
||||
|
||||
// 초기 탭 선택
|
||||
showTabContent(currentTab)
|
||||
}
|
||||
|
||||
private fun showTabContent(position: Int) {
|
||||
val fragmentTransaction = supportFragmentManager.beginTransaction()
|
||||
|
||||
// 기존 프래그먼트 제거
|
||||
supportFragmentManager.fragments.forEach {
|
||||
fragmentTransaction.remove(it)
|
||||
}
|
||||
|
||||
// 선택된 탭에 따라 프래그먼트 표시
|
||||
val fragment = when (position) {
|
||||
1 -> SeriesMainDayOfWeekFragment()
|
||||
2 -> SeriesMainByGenreFragment()
|
||||
else -> SeriesMainHomeFragment()
|
||||
}
|
||||
|
||||
fragmentTransaction.add(R.id.fl_container, fragment)
|
||||
fragmentTransaction.commit()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main
|
||||
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.by_genre.GetSeriesGenreListResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.home.SeriesHomeResponse
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import kr.co.vividnext.sodalive.home.SeriesPublishedDaysOfWeek
|
||||
import kr.co.vividnext.sodalive.settings.ContentType
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface SeriesMainApi {
|
||||
@GET("/audio-content/series/main")
|
||||
fun fetchHome(
|
||||
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
|
||||
@Query("contentType") contentType: ContentType,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<SeriesHomeResponse>>
|
||||
|
||||
@GET("/audio-content/series/main/recommend")
|
||||
fun getRecommendSeriesList(
|
||||
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
|
||||
@Query("contentType") contentType: ContentType,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<List<GetSeriesListResponse.SeriesListItem>>>
|
||||
|
||||
@GET("/audio-content/series/main/day-of-week")
|
||||
fun getDayOfWeekSeriesList(
|
||||
@Query("dayOfWeek") dayOfWeek: SeriesPublishedDaysOfWeek,
|
||||
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
|
||||
@Query("contentType") contentType: ContentType,
|
||||
@Query("page") page: Int,
|
||||
@Query("size") size: Int,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<List<GetSeriesListResponse.SeriesListItem>>>
|
||||
|
||||
@GET("/audio-content/series/main/genre-list")
|
||||
fun getGenreList(
|
||||
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
|
||||
@Query("contentType") contentType: ContentType,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<List<GetSeriesGenreListResponse>>>
|
||||
|
||||
@GET("/audio-content/series/main/list-by-genre")
|
||||
fun getSeriesListByGenre(
|
||||
@Query("genreId") genreId: Long,
|
||||
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
|
||||
@Query("contentType") contentType: ContentType,
|
||||
@Query("page") page: Int,
|
||||
@Query("size") size: Int,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<GetSeriesListResponse>>
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.home.SeriesPublishedDaysOfWeek
|
||||
import kr.co.vividnext.sodalive.settings.ContentType
|
||||
|
||||
class SeriesMainRepository(
|
||||
private val api: SeriesMainApi
|
||||
) {
|
||||
fun fetchData(token: String) = api.fetchHome(
|
||||
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
|
||||
contentType = ContentType.entries[SharedPreferenceManager.contentPreference],
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun getRecommendSeriesList(token: String) = api.getRecommendSeriesList(
|
||||
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
|
||||
contentType = ContentType.entries[SharedPreferenceManager.contentPreference],
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun getDayOfWeekSeriesList(
|
||||
dayOfWeek: SeriesPublishedDaysOfWeek,
|
||||
page: Int,
|
||||
size: Int,
|
||||
token: String
|
||||
) = api.getDayOfWeekSeriesList(
|
||||
dayOfWeek = dayOfWeek,
|
||||
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
|
||||
contentType = ContentType.entries[SharedPreferenceManager.contentPreference],
|
||||
page = page - 1,
|
||||
size = size,
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun getGenreList(token: String) = api.getGenreList(
|
||||
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
|
||||
contentType = ContentType.entries[SharedPreferenceManager.contentPreference],
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun getSeriesListByGenre(
|
||||
genreId: Long,
|
||||
page: Int,
|
||||
size: Int,
|
||||
token: String
|
||||
) = api.getSeriesListByGenre(
|
||||
genreId = genreId,
|
||||
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
|
||||
contentType = ContentType.entries[SharedPreferenceManager.contentPreference],
|
||||
page = page - 1,
|
||||
size = size,
|
||||
authHeader = token
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.by_genre
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
data class GetSeriesGenreListResponse(
|
||||
@SerializedName("id") val id: Long,
|
||||
@SerializedName("genre") val genre: String
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.by_genre
|
||||
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentSeriesMainByGenreBinding
|
||||
|
||||
class SeriesMainByGenreFragment : BaseFragment<FragmentSeriesMainByGenreBinding>(
|
||||
FragmentSeriesMainByGenreBinding::inflate
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.by_genre
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
|
||||
class SeriesMainByGenreViewModel(
|
||||
private val repository: SeriesMainRepository
|
||||
) : BaseViewModel() {
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.day_of_week
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAdapter
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.GridSpacingItemDecoration
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentSeriesMainDayOfWeekBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.home.DayOfWeekAdapter
|
||||
import kr.co.vividnext.sodalive.home.SeriesPublishedDaysOfWeek
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.Calendar
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class SeriesMainDayOfWeekFragment : BaseFragment<FragmentSeriesMainDayOfWeekBinding>(
|
||||
FragmentSeriesMainDayOfWeekBinding::inflate
|
||||
) {
|
||||
private val viewModel: SeriesMainDayOfWeekViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var adapter: SeriesListAdapter
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupView()
|
||||
observeViewModel()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||
|
||||
setupDayOfWeekDay()
|
||||
setupSeriesView()
|
||||
|
||||
val dayOfWeeks = listOf(
|
||||
SeriesPublishedDaysOfWeek.RANDOM,
|
||||
SeriesPublishedDaysOfWeek.SUN,
|
||||
SeriesPublishedDaysOfWeek.MON,
|
||||
SeriesPublishedDaysOfWeek.TUE,
|
||||
SeriesPublishedDaysOfWeek.WED,
|
||||
SeriesPublishedDaysOfWeek.THU,
|
||||
SeriesPublishedDaysOfWeek.FRI,
|
||||
SeriesPublishedDaysOfWeek.SAT
|
||||
)
|
||||
|
||||
val calendar = Calendar.getInstance()
|
||||
val dayIndex = calendar.get(Calendar.DAY_OF_WEEK)
|
||||
|
||||
viewModel.dayOfWeek = dayOfWeeks[dayIndex]
|
||||
}
|
||||
|
||||
private fun setupDayOfWeekDay() {
|
||||
val dayOfWeekAdapter = DayOfWeekAdapter(screenWidth = screenWidth) {
|
||||
adapter.clear()
|
||||
viewModel.dayOfWeek = it
|
||||
}
|
||||
|
||||
val rvDayOfWeek = binding.rvSeriesDayOfWeekDay
|
||||
val layoutManager = object : LinearLayoutManager(
|
||||
context,
|
||||
HORIZONTAL,
|
||||
false
|
||||
) {
|
||||
override fun canScrollVertically() = false
|
||||
override fun canScrollHorizontally() = false
|
||||
}
|
||||
rvDayOfWeek.layoutManager = layoutManager
|
||||
|
||||
rvDayOfWeek.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 = 2.5f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
dayOfWeekAdapter.itemCount - 1 -> {
|
||||
outRect.left = 2.5f.dpToPx().toInt()
|
||||
outRect.right = 0
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.left = 2.5f.dpToPx().toInt()
|
||||
outRect.right = 2.5f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
rvDayOfWeek.adapter = dayOfWeekAdapter
|
||||
}
|
||||
|
||||
private fun setupSeriesView() {
|
||||
adapter = SeriesListAdapter(
|
||||
itemWidth = ((screenWidth - 24f.dpToPx() * 2 - 16f.dpToPx()) / 2f).roundToInt(),
|
||||
onClickItem = {
|
||||
startActivity(
|
||||
Intent(
|
||||
requireContext(),
|
||||
SeriesDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.EXTRA_SERIES_ID, it)
|
||||
}
|
||||
)
|
||||
},
|
||||
onClickCreator = {},
|
||||
isVisibleCreator = false
|
||||
)
|
||||
|
||||
val spanCount = 2
|
||||
val spacingPx = 16f.dpToPx().toInt()
|
||||
val recyclerView = binding.rvSeriesDayOfWeek
|
||||
recyclerView.layoutManager = GridLayoutManager(requireContext(), spanCount)
|
||||
|
||||
recyclerView.addItemDecoration(
|
||||
GridSpacingItemDecoration(spanCount, spacingPx, false)
|
||||
)
|
||||
|
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
|
||||
.findLastCompletelyVisibleItemPosition()
|
||||
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
|
||||
|
||||
// 스크롤이 끝에 도달했는지 확인
|
||||
if (!recyclerView.canScrollVertically(1) &&
|
||||
lastVisibleItemPosition == itemTotalCount
|
||||
) {
|
||||
viewModel.getSeriesList()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.adapter = adapter
|
||||
|
||||
viewModel.seriesListLiveData.observe(viewLifecycleOwner) {
|
||||
adapter.addItems(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeViewModel() {
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.day_of_week
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.home.SeriesPublishedDaysOfWeek
|
||||
|
||||
class SeriesMainDayOfWeekViewModel(
|
||||
private val repository: SeriesMainRepository
|
||||
) : BaseViewModel() {
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private val _seriesListLiveData = MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
|
||||
val seriesListLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
|
||||
get() = _seriesListLiveData
|
||||
|
||||
private var page = 1
|
||||
private var isLast = false
|
||||
private val pageSize = 20
|
||||
|
||||
var dayOfWeek = SeriesPublishedDaysOfWeek.RANDOM
|
||||
set(newValue) {
|
||||
if (field != newValue) {
|
||||
page = 1
|
||||
isLast = false
|
||||
field = newValue
|
||||
getSeriesList()
|
||||
}
|
||||
}
|
||||
|
||||
fun getSeriesList() {
|
||||
if (isLast) return
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.getDayOfWeekSeriesList(
|
||||
dayOfWeek = dayOfWeek,
|
||||
page = page,
|
||||
size = pageSize,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
|
||||
val data = it.data
|
||||
if (it.success && data != null) {
|
||||
page += 1
|
||||
|
||||
if (data.isNotEmpty()) {
|
||||
_seriesListLiveData.value = data
|
||||
} else {
|
||||
isLast = true
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.home
|
||||
|
||||
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
|
||||
|
||||
class SeriesBannerAdapter(
|
||||
private val context: Context,
|
||||
private val itemWidth: Int,
|
||||
private val itemHeight: Int,
|
||||
private val onClick: (SeriesBannerResponse) -> Unit
|
||||
) : BaseBannerAdapter<SeriesBannerResponse>() {
|
||||
override fun bindData(
|
||||
holder: BaseViewHolder<SeriesBannerResponse?>,
|
||||
data: SeriesBannerResponse,
|
||||
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.imagePath)
|
||||
.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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.home
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
|
||||
@Keep
|
||||
data class SeriesHomeResponse(
|
||||
@SerializedName("banners")
|
||||
val banners: List<SeriesBannerResponse>,
|
||||
|
||||
@SerializedName("completedSeriesList")
|
||||
val completedSeriesList: List<GetSeriesListResponse.SeriesListItem>,
|
||||
|
||||
@SerializedName("recommendSeriesList")
|
||||
val recommendSeriesList: List<GetSeriesListResponse.SeriesListItem>
|
||||
)
|
||||
|
||||
@Keep
|
||||
data class SeriesBannerResponse(
|
||||
@SerializedName("seriesId") val seriesId: Long,
|
||||
@SerializedName("imagePath") val imagePath: String
|
||||
)
|
||||
@@ -0,0 +1,233 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.series.SeriesListAdapter
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.GridSpacingItemDecoration
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentSeriesMainHomeBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.home.HomeSeriesAdapter
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
import org.koin.android.ext.android.inject
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class SeriesMainHomeFragment : BaseFragment<FragmentSeriesMainHomeBinding>(
|
||||
FragmentSeriesMainHomeBinding::inflate
|
||||
) {
|
||||
private val viewModel: SeriesMainHomeViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
|
||||
private lateinit var bannerAdapter: SeriesBannerAdapter
|
||||
private lateinit var completedAdapter: HomeSeriesAdapter
|
||||
private lateinit var recommendAdapter: SeriesListAdapter
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupView()
|
||||
observeViewModel()
|
||||
|
||||
viewModel.fetchData()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||
|
||||
setupBanner()
|
||||
setupCompletedSeriesView()
|
||||
setupRecommendSeriesView()
|
||||
}
|
||||
|
||||
private fun setupBanner() {
|
||||
val layoutParams = binding
|
||||
.bannerSlider
|
||||
.layoutParams as LinearLayout.LayoutParams
|
||||
|
||||
val pagerWidth = screenWidth
|
||||
val pagerHeight = pagerWidth * 198 / 352
|
||||
layoutParams.width = pagerWidth
|
||||
layoutParams.height = pagerHeight
|
||||
|
||||
bannerAdapter = SeriesBannerAdapter(
|
||||
requireContext(),
|
||||
pagerWidth,
|
||||
pagerHeight
|
||||
) {
|
||||
startActivity(
|
||||
Intent(
|
||||
requireContext(),
|
||||
SeriesDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.EXTRA_SERIES_ID, it.seriesId)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
binding
|
||||
.bannerSlider
|
||||
.layoutParams = layoutParams
|
||||
|
||||
binding.bannerSlider.apply {
|
||||
adapter = bannerAdapter as BaseBannerAdapter<Any>
|
||||
|
||||
setLifecycleRegistry(lifecycle)
|
||||
setScrollDuration(1000)
|
||||
setInterval(4 * 1000)
|
||||
}.create()
|
||||
|
||||
binding
|
||||
.bannerSlider
|
||||
.setIndicatorView(binding.indicatorBanner)
|
||||
.setIndicatorStyle(IndicatorStyle.ROUND_RECT)
|
||||
.setIndicatorSlideMode(IndicatorSlideMode.SMOOTH)
|
||||
.setIndicatorVisibility(View.GONE)
|
||||
.setIndicatorSliderColor(
|
||||
ContextCompat.getColor(requireContext(), R.color.color_909090),
|
||||
ContextCompat.getColor(requireContext(), R.color.color_3bb9f1)
|
||||
)
|
||||
.setIndicatorSliderWidth(10f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
||||
.setIndicatorHeight(10f.dpToPx().toInt())
|
||||
|
||||
viewModel.bannerListLiveData.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.llBanner.visibility = View.VISIBLE
|
||||
binding.bannerSlider.refreshData(it)
|
||||
} else {
|
||||
binding.llBanner.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCompletedSeriesView() {
|
||||
completedAdapter = HomeSeriesAdapter {
|
||||
if (SharedPreferenceManager.token.isNotBlank()) {
|
||||
startActivity(
|
||||
Intent(requireContext(), SeriesDetailActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_SERIES_ID, it)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
(requireActivity() as MainActivity).showLoginActivity()
|
||||
}
|
||||
}
|
||||
|
||||
val recyclerView = binding.rvCompletedSeries
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
context,
|
||||
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()
|
||||
}
|
||||
|
||||
completedAdapter.itemCount - 1 -> {
|
||||
outRect.left = 8f.dpToPx().toInt()
|
||||
outRect.right = 0
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.left = 8f.dpToPx().toInt()
|
||||
outRect.right = 8f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
recyclerView.adapter = completedAdapter
|
||||
|
||||
viewModel.completedSeriesLiveData.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.llCompletedSeries.visibility = View.VISIBLE
|
||||
completedAdapter.addItems(it)
|
||||
} else {
|
||||
binding.llCompletedSeries.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRecommendSeriesView() {
|
||||
recommendAdapter = SeriesListAdapter(
|
||||
itemWidth = ((screenWidth - 24f.dpToPx() * 2 - 16f.dpToPx()) / 2f).roundToInt(),
|
||||
onClickItem = {
|
||||
startActivity(
|
||||
Intent(
|
||||
requireContext(),
|
||||
SeriesDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.EXTRA_SERIES_ID, it)
|
||||
}
|
||||
)
|
||||
},
|
||||
onClickCreator = {},
|
||||
isVisibleCreator = false
|
||||
)
|
||||
|
||||
val spanCount = 2
|
||||
val spacingPx = 16f.dpToPx().toInt()
|
||||
val recyclerView = binding.rvRecommendSeries
|
||||
recyclerView.layoutManager = GridLayoutManager(requireContext(), spanCount)
|
||||
|
||||
recyclerView.addItemDecoration(
|
||||
GridSpacingItemDecoration(spanCount, spacingPx, false)
|
||||
)
|
||||
|
||||
recyclerView.adapter = recommendAdapter
|
||||
|
||||
binding.ivRecommendRefresh.setOnClickListener {
|
||||
viewModel.getRecommendSeriesList()
|
||||
}
|
||||
|
||||
viewModel.recommendSeriesLiveData.observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.llRecommendSeries.visibility = View.VISIBLE
|
||||
recommendAdapter.clear()
|
||||
recommendAdapter.addItems(it)
|
||||
} else {
|
||||
binding.llRecommendSeries.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeViewModel() {
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.series.main.home
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
|
||||
class SeriesMainHomeViewModel(
|
||||
private val repository: SeriesMainRepository
|
||||
) : BaseViewModel() {
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _bannerListLiveData = MutableLiveData<List<SeriesBannerResponse>>()
|
||||
val bannerListLiveData: LiveData<List<SeriesBannerResponse>>
|
||||
get() = _bannerListLiveData
|
||||
|
||||
private var _completedSeriesLiveData =
|
||||
MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
|
||||
val completedSeriesLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
|
||||
get() = _completedSeriesLiveData
|
||||
|
||||
private var _recommendSeriesLiveData =
|
||||
MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
|
||||
val recommendSeriesLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
|
||||
get() = _recommendSeriesLiveData
|
||||
|
||||
fun fetchData() {
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.fetchData(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
|
||||
val data = it.data
|
||||
if (it.success && data != null) {
|
||||
_bannerListLiveData.value = data.banners
|
||||
_completedSeriesLiveData.value = data.completedSeriesList
|
||||
_recommendSeriesLiveData.value = data.recommendSeriesList
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun getRecommendSeriesList() {
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.getRecommendSeriesList(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
if (it.success && it.data != null) {
|
||||
_recommendSeriesLiveData.value = it.data
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,11 @@ import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.series.content.SeriesContentAllViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainApi
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.by_genre.SeriesMainByGenreViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.day_of_week.SeriesMainDayOfWeekViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.home.SeriesMainHomeViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.upload.theme.AudioContentThemeViewModel
|
||||
import kr.co.vividnext.sodalive.audition.AuditionApi
|
||||
@@ -224,6 +229,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||
single { ApiBuilder().build(get(), TermsApi::class.java) }
|
||||
single { ApiBuilder().build(get(), EventApi::class.java) }
|
||||
single { ApiBuilder().build(get(), SeriesApi::class.java) }
|
||||
single { ApiBuilder().build(get(), SeriesMainApi::class.java) }
|
||||
single { ApiBuilder().build(get(), ReportApi::class.java) }
|
||||
single { ApiBuilder().build(get(), LiveRecommendApi::class.java) }
|
||||
single { ApiBuilder().build(get(), ExplorerApi::class.java) }
|
||||
@@ -333,6 +339,9 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||
viewModel { NewCharactersAllViewModel(get()) }
|
||||
viewModel { OriginalWorkViewModel(get()) }
|
||||
viewModel { OriginalWorkDetailViewModel(get()) }
|
||||
viewModel { SeriesMainHomeViewModel(get()) }
|
||||
viewModel { SeriesMainByGenreViewModel(get()) }
|
||||
viewModel { SeriesMainDayOfWeekViewModel(get()) }
|
||||
}
|
||||
|
||||
private val repositoryModule = module {
|
||||
@@ -376,6 +385,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||
factory { CharacterCommentRepository(get()) }
|
||||
factory { NewCharactersRepository(get()) }
|
||||
factory { OriginalWorkRepository(get()) }
|
||||
factory { SeriesMainRepository(get()) }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,13 +26,16 @@ 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.AudioContentPlayService
|
||||
import kr.co.vividnext.sodalive.audio_content.all.AudioContentAllActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.box.AudioContentBoxActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||
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.player.AudioContentPlayerService
|
||||
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
|
||||
import kr.co.vividnext.sodalive.audition.AuditionActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
@@ -646,7 +649,10 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
// ‘오직 보이스온에서만’ 전체보기: isOriginal=true로 시리즈 전체보기 화면 진입
|
||||
if (SharedPreferenceManager.token.isNotBlank()) {
|
||||
startActivity(
|
||||
Intent(requireContext(), kr.co.vividnext.sodalive.audio_content.series.SeriesListAllActivity::class.java).apply {
|
||||
Intent(
|
||||
requireContext(),
|
||||
SeriesListAllActivity::class.java
|
||||
).apply {
|
||||
putExtra(kr.co.vividnext.sodalive.common.Constants.EXTRA_IS_ORIGINAL, true)
|
||||
}
|
||||
)
|
||||
@@ -791,7 +797,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
outRect.right = 2.5f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
seriesDayOfWeekAdapter.itemCount - 1 -> {
|
||||
dayOfWeekAdapter.itemCount - 1 -> {
|
||||
outRect.left = 2.5f.dpToPx().toInt()
|
||||
outRect.right = 0
|
||||
}
|
||||
@@ -804,6 +810,21 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
}
|
||||
})
|
||||
rvDayOfWeek.adapter = dayOfWeekAdapter
|
||||
|
||||
binding.tvSeriesDayOfWeekAll.setOnClickListener {
|
||||
if (SharedPreferenceManager.token.isNotBlank()) {
|
||||
startActivity(
|
||||
Intent(
|
||||
requireContext(),
|
||||
SeriesMainActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_FREE, true)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
(requireActivity() as MainActivity).showLoginActivity()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPopularCharacters() {
|
||||
@@ -1127,7 +1148,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
binding.tvFreeContentAll.setOnClickListener {
|
||||
if (SharedPreferenceManager.token.isNotBlank()) {
|
||||
startActivity(
|
||||
Intent(requireContext(), kr.co.vividnext.sodalive.audio_content.all.AudioContentAllActivity::class.java).apply {
|
||||
Intent(requireContext(), AudioContentAllActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_FREE, true)
|
||||
}
|
||||
)
|
||||
@@ -1211,7 +1232,10 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
binding.tvPointContentAll.setOnClickListener {
|
||||
if (SharedPreferenceManager.token.isNotBlank()) {
|
||||
startActivity(
|
||||
Intent(requireContext(), kr.co.vividnext.sodalive.audio_content.all.AudioContentAllActivity::class.java).apply {
|
||||
Intent(
|
||||
requireContext(),
|
||||
AudioContentAllActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_POINT_ONLY, true)
|
||||
}
|
||||
)
|
||||
@@ -1229,7 +1253,10 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
||||
recommendContentAdapter = HomeContentAdapter(onClickItem = {
|
||||
if (SharedPreferenceManager.token.isNotBlank()) {
|
||||
startActivity(
|
||||
Intent(requireContext(), AudioContentDetailActivity::class.java).apply {
|
||||
Intent(
|
||||
requireContext(),
|
||||
AudioContentDetailActivity::class.java
|
||||
).apply {
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
|
||||
}
|
||||
)
|
||||
|
||||
30
app/src/main/res/layout/activity_series_main.xml
Normal file
30
app/src/main/res/layout/activity_series_main.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/color_131313"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/detail_toolbar" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/color_131313"
|
||||
app:tabIndicatorColor="@color/color_3bb9f1"
|
||||
app:tabIndicatorFullWidth="true"
|
||||
app:tabIndicatorHeight="4dp"
|
||||
app:tabSelectedTextColor="@color/color_3bb9f1"
|
||||
app:tabTextAppearance="@style/tabText"
|
||||
app:tabTextColor="@color/color_b0bec5" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -253,15 +253,32 @@
|
||||
android:layout_marginBottom="48dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_series_day_of_week"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:fontFamily="@font/pretendard_bold"
|
||||
android:text="요일별 시리즈"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="24sp" />
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_series_day_of_week"
|
||||
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_series_day_of_week_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_series_day_of_week_day"
|
||||
|
||||
23
app/src/main/res/layout/fragment_series_main_by_genre.xml
Normal file
23
app/src/main/res/layout/fragment_series_main_by_genre.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_genre"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:paddingHorizontal="24dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_series_by_genre"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="24dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="24dp" />
|
||||
</LinearLayout>
|
||||
23
app/src/main/res/layout/fragment_series_main_day_of_week.xml
Normal file
23
app/src/main/res/layout/fragment_series_main_day_of_week.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_series_day_of_week_day"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:paddingHorizontal="24dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_series_day_of_week"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="24dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="24dp" />
|
||||
</LinearLayout>
|
||||
111
app/src/main/res/layout/fragment_series_main_home.xml
Normal file
111
app/src/main/res/layout/fragment_series_main_home.xml
Normal file
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/color_131313"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingVertical="24dp">
|
||||
|
||||
<!-- 배너 섹션 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_banner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.zhpan.bannerview.BannerViewPager
|
||||
android:id="@+id/banner_slider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false" />
|
||||
|
||||
<com.zhpan.indicator.IndicatorView
|
||||
android:id="@+id/indicator_banner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="16dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 완결 시리즈 섹션 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_completed_series"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_completed_series"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:fontFamily="@font/pretendard_bold"
|
||||
android:text="완결 시리즈"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="24sp" />
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_completed_series"
|
||||
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_recommend_series"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<!-- 제목과 새로고침 -->
|
||||
<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" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_recommend_refresh"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_refresh" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 2단 Grid 리스트 -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_recommend_series"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
Reference in New Issue
Block a user