diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7b668b2..626b987 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -134,6 +134,7 @@
+
>
+
+ @GET("/audio-content/series/{id}")
+ fun getSeriesDetail(
+ @Path("id") seriesId: Long,
+ @Header("Authorization") authHeader: String
+ ): Single>
}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/SeriesListAllActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/SeriesListAllActivity.kt
index 400d24c..cd3e7f0 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/SeriesListAllActivity.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/SeriesListAllActivity.kt
@@ -1,10 +1,12 @@
package kr.co.vividnext.sodalive.audio_content.series
+import android.content.Intent
import android.os.Bundle
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.detail.SeriesDetailActivity
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.GridSpacingItemDecoration
@@ -42,7 +44,13 @@ class SeriesListAllActivity : BaseActivity(
binding.toolbar.tvBack.setOnClickListener { finish() }
seriesAdapter = SeriesListAdapter(
- onClickItem = {},
+ onClickItem = {
+ startActivity(
+ Intent(applicationContext, SeriesDetailActivity::class.java).apply {
+ putExtra(Constants.EXTRA_SERIES_ID, it)
+ }
+ )
+ },
onClickCreator = {},
isVisibleCreator = false
)
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/SeriesRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/SeriesRepository.kt
index a9f12cb..332678b 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/SeriesRepository.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/SeriesRepository.kt
@@ -14,4 +14,9 @@ class SeriesRepository(private val api: SeriesApi) {
size = size,
authHeader = token
)
+
+ fun getSeriesDetail(seriesId: Long, token: String) = api.getSeriesDetail(
+ seriesId = seriesId,
+ authHeader = token
+ )
}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/GetSeriesContentListResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/GetSeriesContentListResponse.kt
new file mode 100644
index 0000000..5f04d39
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/GetSeriesContentListResponse.kt
@@ -0,0 +1,22 @@
+package kr.co.vividnext.sodalive.audio_content.series.detail
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+data class GetSeriesContentListResponse(
+ @SerializedName("totalCount") val totalCount: Int,
+ @SerializedName("items") val items: List
+)
+
+@Parcelize
+data class GetSeriesContentListItem(
+ @SerializedName("contentId") val contentId: Long,
+ @SerializedName("title") val title: String,
+ @SerializedName("coverImage") val coverImage: String,
+ @SerializedName("releaseDate") val releaseDate: String,
+ @SerializedName("duration") val duration: String,
+ @SerializedName("price") val price: Int,
+ @SerializedName("isRented") var isRented: Boolean,
+ @SerializedName("isOwned") var isOwned: Boolean
+) : Parcelable
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/GetSeriesDetailResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/GetSeriesDetailResponse.kt
new file mode 100644
index 0000000..2398196
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/GetSeriesDetailResponse.kt
@@ -0,0 +1,36 @@
+package kr.co.vividnext.sodalive.audio_content.series.detail
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class GetSeriesDetailResponse(
+ @SerializedName("seriesId") val seriesId: Long,
+ @SerializedName("title") val title: String,
+ @SerializedName("coverImage") val coverImage: String,
+ @SerializedName("introduction") val introduction: String,
+ @SerializedName("genre") val genre: String,
+ @SerializedName("isAdult") val isAdult: Boolean,
+ @SerializedName("writer") val writer: String?,
+ @SerializedName("studio") val studio: String?,
+ @SerializedName("publishedDate") val publishedDate: String,
+ @SerializedName("creator") val creator: GetSeriesDetailCreator,
+ @SerializedName("rentalMinPrice") var rentalMinPrice: Int,
+ @SerializedName("rentalMaxPrice") var rentalMaxPrice: Int,
+ @SerializedName("rentalPeriod") val rentalPeriod: Int,
+ @SerializedName("minPrice") var minPrice: Int,
+ @SerializedName("maxPrice") var maxPrice: Int,
+ @SerializedName("keywordList") var keywordList: List,
+ @SerializedName("publishedDaysOfWeek") var publishedDaysOfWeek: String,
+ @SerializedName("contentList") val contentList: List,
+ @SerializedName("contentCount") val contentCount: Int
+) : Parcelable {
+ @Parcelize
+ data class GetSeriesDetailCreator(
+ @SerializedName("creatorId") val creatorId: Long,
+ @SerializedName("nickname") val nickname: String,
+ @SerializedName("profileImage") val profileImage: String,
+ @SerializedName("isFollow") var isFollow: Boolean
+ ) : Parcelable
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailActivity.kt
new file mode 100644
index 0000000..78fb1ce
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailActivity.kt
@@ -0,0 +1,201 @@
+package kr.co.vividnext.sodalive.audio_content.series.detail
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.View
+import android.widget.Toast
+import androidx.core.content.ContextCompat
+import androidx.core.content.res.ResourcesCompat
+import coil.load
+import coil.size.Scale
+import coil.transform.BlurTransformation
+import coil.transform.CircleCropTransformation
+import coil.transform.RoundedCornersTransformation
+import com.google.android.material.chip.Chip
+import com.google.android.material.shape.ShapeAppearanceModel
+import com.google.android.material.tabs.TabLayout
+import kr.co.vividnext.sodalive.R
+import kr.co.vividnext.sodalive.base.BaseActivity
+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.ActivitySeriesDetailBinding
+import kr.co.vividnext.sodalive.extensions.dpToPx
+import org.koin.android.ext.android.inject
+
+class SeriesDetailActivity : BaseActivity(
+ ActivitySeriesDetailBinding::inflate
+) {
+ private val viewModel: SeriesDetailViewModel by inject()
+
+ private lateinit var loadingDialog: LoadingDialog
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val seriesId = intent.getLongExtra(Constants.EXTRA_SERIES_ID, 0)
+ if (seriesId <= 0) {
+ Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
+ finish()
+ }
+
+ bindData()
+
+ viewModel.seriesId = seriesId
+ viewModel.getSeriesDetail()
+ }
+
+ override fun setupView() {
+ loadingDialog = LoadingDialog(this, layoutInflater)
+ binding.ivBack.setOnClickListener { finish() }
+
+ setupTab()
+ }
+
+ private fun setupTab() {
+ val tabs = binding.tabs
+ tabs.addTab(tabs.newTab().setText("홈").setTag("home"))
+ tabs.addTab(tabs.newTab().setText("작품소개").setTag("introduction"))
+
+ tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
+ override fun onTabSelected(tab: TabLayout.Tab) {
+ val tag = tab.tag as String
+ changeFragment(tag)
+ }
+
+ override fun onTabUnselected(tab: TabLayout.Tab) {
+ }
+
+ override fun onTabReselected(tab: TabLayout.Tab) {
+ }
+
+ })
+ }
+
+ private fun changeFragment(tag: String) {
+ val fragmentManager = supportFragmentManager
+ val fragmentTransaction = fragmentManager.beginTransaction()
+
+ val fragment = when (tag) {
+ "introduction" -> SeriesDetailIntroductionFragment()
+ else -> SeriesDetailHomeFragment()
+ }
+
+ val bundle = Bundle()
+ bundle.putParcelable(Constants.EXTRA_SERIES, viewModel.seriesDetailResponse)
+ fragment.arguments = bundle
+
+ fragmentTransaction.replace(R.id.container, fragment, tag)
+ fragmentTransaction.setPrimaryNavigationFragment(fragment)
+ fragmentTransaction.setReorderingAllowed(true)
+ fragmentTransaction.commitNow()
+ }
+
+ private fun bindData() {
+ viewModel.toastLiveData.observe(this) {
+ it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
+ }
+
+ viewModel.isLoading.observe(this) {
+ if (it) {
+ loadingDialog.show(screenWidth, "")
+ } else {
+ loadingDialog.dismiss()
+ }
+ }
+
+ viewModel.seriesDetailLiveData.observe(this) {
+ setSeriesBg(it.coverImage)
+ setSeriesInfo(it)
+ setSeriesCreator(it.creator)
+ setSeriesKeywordChipList(it.keywordList)
+
+ changeFragment("home")
+ }
+ }
+
+ private fun setSeriesKeywordChipList(keywordList: List) {
+ binding.chipGroup.isSingleLine = true
+ binding.chipGroup.isHorizontalScrollBarEnabled = false
+
+ for (keyword in keywordList) {
+ val chip = Chip(this)
+ chip.text = keyword
+ chip.isClickable = false
+ chip.isCheckable = false
+ chip.textSize = 14.7f
+ chip.chipStrokeWidth = 0f
+ chip.setChipBackgroundColorResource(R.color.color_222222)
+
+ val shapeAppearanceModel = ShapeAppearanceModel.Builder()
+ .setAllCornerSizes(26.7f.dpToPx())
+ .build()
+ chip.shapeAppearanceModel = shapeAppearanceModel
+
+ chip.setPadding(0, 0, 0, 0)
+ chip.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_d2d2d2))
+ chip.typeface = ResourcesCompat.getFont(applicationContext, R.font.gmarket_sans_medium)
+ binding.chipGroup.addView(chip)
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun setSeriesInfo(seriesDetail: GetSeriesDetailResponse) {
+ binding.ivCover.load(seriesDetail.coverImage) {
+ crossfade(true)
+ placeholder(R.drawable.bg_placeholder)
+ transformations(RoundedCornersTransformation(5f.dpToPx()))
+ }
+
+ binding.tvTitle.text = seriesDetail.title
+ binding.tvGenre.text = seriesDetail.genre
+ binding.tvPublishedDaysOfWeek.text = "${seriesDetail.publishedDaysOfWeek} 연재"
+
+ if (seriesDetail.isAdult) {
+ binding.tvAge19.visibility = View.GONE
+ binding.tvAgeAll.visibility = View.VISIBLE
+ } else {
+ binding.tvAge19.visibility = View.VISIBLE
+ binding.tvAgeAll.visibility = View.GONE
+ }
+ }
+
+ private fun setSeriesCreator(creator: GetSeriesDetailResponse.GetSeriesDetailCreator) {
+ binding.tvNickname.text = creator.nickname
+ binding.ivProfile.load(creator.profileImage) {
+ crossfade(true)
+ placeholder(R.drawable.bg_placeholder)
+ transformations(CircleCropTransformation())
+ }
+
+ if (SharedPreferenceManager.userId != creator.creatorId) {
+ binding.ivFollow.visibility = View.VISIBLE
+ binding.ivFollow.setImageResource(
+ if (creator.isFollow) {
+ R.drawable.btn_following_big
+ } else {
+ R.drawable.btn_follow_big
+ }
+ )
+ } else {
+ binding.ivFollow.visibility = View.GONE
+ }
+
+ binding.ivFollow.setOnClickListener { }
+ binding.ivProfile.setOnClickListener { }
+ binding.tvNickname.setOnClickListener { }
+ }
+
+ private fun setSeriesBg(coverImage: String) {
+ binding.ivBg.load(coverImage) {
+ transformations(
+ BlurTransformation(
+ this@SeriesDetailActivity,
+ 25f,
+ 2.5f
+ )
+ )
+ scale(Scale.FILL)
+ }
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailHomeContentAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailHomeContentAdapter.kt
new file mode 100644
index 0000000..c7eb974
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailHomeContentAdapter.kt
@@ -0,0 +1,81 @@
+package kr.co.vividnext.sodalive.audio_content.series.detail
+
+import android.annotation.SuppressLint
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import coil.load
+import coil.transform.RoundedCornersTransformation
+import kr.co.vividnext.sodalive.R
+import kr.co.vividnext.sodalive.databinding.ItemSeriesContentBinding
+import kr.co.vividnext.sodalive.extensions.dpToPx
+
+class SeriesDetailHomeContentAdapter(
+ private val onClickItem: (Long) -> Unit
+) : RecyclerView.Adapter() {
+
+ val items = mutableListOf()
+
+ inner class ViewHolder(
+ private val binding: ItemSeriesContentBinding
+ ) : RecyclerView.ViewHolder(binding.root) {
+ fun bind(item: GetSeriesContentListItem) {
+ binding.ivCover.load(item.coverImage) {
+ crossfade(true)
+ placeholder(R.drawable.bg_placeholder)
+ transformations(RoundedCornersTransformation(5.3f.dpToPx()))
+ }
+
+ binding.tvTitle.text = item.title
+ binding.tvDate.text = item.releaseDate
+ binding.tvDuration.text = item.duration
+
+ binding.tvPrice.visibility = View.GONE
+ binding.tvOwned.visibility = View.GONE
+ binding.tvRented.visibility = View.GONE
+ binding.tvPriceFree.visibility = View.GONE
+
+ if (item.isOwned) {
+ binding.tvOwned.visibility = View.VISIBLE
+ }
+
+ if (item.isRented) {
+ binding.tvRented.visibility = View.VISIBLE
+ }
+
+ if (item.price > 0) {
+ binding.tvPrice.text = "${item.price}"
+ binding.tvPrice.visibility = View.VISIBLE
+ } else {
+ binding.tvPriceFree.visibility = View.VISIBLE
+ }
+
+ binding.root.setOnClickListener { onClickItem(item.contentId) }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
+ ItemSeriesContentBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ )
+
+ override fun getItemCount() = items.size
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ holder.bind(items[position])
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ fun addItems(items: List) {
+ this.items.addAll(items)
+ notifyDataSetChanged()
+ }
+
+ fun clear() {
+ this.items.clear()
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailHomeFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailHomeFragment.kt
new file mode 100644
index 0000000..734ccd5
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailHomeFragment.kt
@@ -0,0 +1,66 @@
+package kr.co.vividnext.sodalive.audio_content.series.detail
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import kr.co.vividnext.sodalive.base.BaseFragment
+import kr.co.vividnext.sodalive.common.Constants
+import kr.co.vividnext.sodalive.databinding.FragmentSeriesDetailHomeBinding
+
+class SeriesDetailHomeFragment : BaseFragment(
+ FragmentSeriesDetailHomeBinding::inflate
+) {
+ private var seriesDetailResponse: GetSeriesDetailResponse? = null
+
+ private lateinit var adapter: SeriesDetailHomeContentAdapter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (arguments != null) {
+ seriesDetailResponse = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ requireArguments().getParcelable(
+ Constants.EXTRA_SERIES,
+ GetSeriesDetailResponse::class.java
+ )
+ } else {
+ requireArguments().getParcelable(Constants.EXTRA_SERIES)
+ }
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ if (seriesDetailResponse != null) {
+ setContent()
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun setContent() {
+ binding.tvTotalCount.text = "(${seriesDetailResponse!!.contentCount})"
+ binding.llContentAll.setOnClickListener {}
+
+ adapter = SeriesDetailHomeContentAdapter { }
+
+ binding.rvContent.layoutManager = LinearLayoutManager(
+ requireContext(),
+ LinearLayoutManager.VERTICAL,
+ false
+ )
+
+ binding.rvContent.addItemDecoration(
+ DividerItemDecoration(
+ requireContext(),
+ DividerItemDecoration.VERTICAL
+ )
+ )
+
+ binding.rvContent.adapter = adapter
+ adapter.addItems(seriesDetailResponse!!.contentList)
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailIntroductionFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailIntroductionFragment.kt
new file mode 100644
index 0000000..9e99981
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailIntroductionFragment.kt
@@ -0,0 +1,140 @@
+package kr.co.vividnext.sodalive.audio_content.series.detail
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.core.content.res.ResourcesCompat
+import com.google.android.material.chip.Chip
+import com.google.android.material.shape.ShapeAppearanceModel
+import kr.co.vividnext.sodalive.R
+import kr.co.vividnext.sodalive.base.BaseFragment
+import kr.co.vividnext.sodalive.common.Constants
+import kr.co.vividnext.sodalive.databinding.FragmentSeriesDetailIntroductionBinding
+import kr.co.vividnext.sodalive.extensions.dpToPx
+
+class SeriesDetailIntroductionFragment : BaseFragment(
+ FragmentSeriesDetailIntroductionBinding::inflate
+) {
+ private var seriesDetailResponse: GetSeriesDetailResponse? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (arguments != null) {
+ seriesDetailResponse = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ requireArguments().getParcelable(
+ Constants.EXTRA_SERIES,
+ GetSeriesDetailResponse::class.java
+ )
+ } else {
+ requireArguments().getParcelable(Constants.EXTRA_SERIES)
+ }
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ if (seriesDetailResponse != null) {
+ setSeriesKeywordChipList(seriesDetailResponse!!.keywordList)
+ setSeriesIntroduction(seriesDetailResponse!!.introduction)
+ setSeriesPrice()
+ setSeriesInfo()
+ }
+ }
+
+ private fun setSeriesPrice() {
+ val rentalMinPrice = seriesDetailResponse!!.rentalMinPrice
+ val rentalMaxPrice = seriesDetailResponse!!.rentalMaxPrice
+ val minPrice = seriesDetailResponse!!.minPrice
+ val maxPrice = seriesDetailResponse!!.maxPrice
+
+ binding.tvRentalPrice.text = if (rentalMinPrice == rentalMaxPrice) {
+ if (rentalMaxPrice == 0) {
+ "무료(15일)"
+ } else {
+ "$rentalMaxPrice(15일)"
+ }
+ } else {
+ "$rentalMinPrice ~ ${rentalMaxPrice}캔 (15일)"
+ }
+
+ binding.tvPrice.text = if (minPrice == maxPrice) {
+ if (maxPrice == 0) {
+ "무료(15일)"
+ } else {
+ "$maxPrice(15일)"
+ }
+ } else {
+ "${if (minPrice == 0) "무료" else minPrice} ~ ${maxPrice}캔"
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun setSeriesInfo() {
+ binding.tvGenre.text = seriesDetailResponse!!.genre
+ binding.tvIsAdult.text = if (seriesDetailResponse!!.isAdult) {
+ "19세 이상"
+ } else {
+ "전체연령가"
+ }
+
+ binding.tvPublishedDate.text = seriesDetailResponse!!.publishedDate
+ binding.tvPublishedDaysOfWeek.text =
+ if (seriesDetailResponse!!.publishedDaysOfWeek == "랜덤") {
+ seriesDetailResponse!!.publishedDaysOfWeek
+ } else {
+ "${seriesDetailResponse!!.publishedDaysOfWeek}요일"
+ }
+
+ if (seriesDetailResponse!!.writer != null) {
+ binding.tvWriter.visibility = View.VISIBLE
+ binding.tvWriterLabel.visibility = View.VISIBLE
+
+ binding.tvWriter.text = seriesDetailResponse!!.writer
+ } else {
+ binding.tvWriter.visibility = View.GONE
+ binding.tvWriterLabel.visibility = View.GONE
+ }
+
+ if (seriesDetailResponse!!.studio != null) {
+ binding.tvStudio.visibility = View.VISIBLE
+ binding.tvStudioLabel.visibility = View.VISIBLE
+
+ binding.tvStudio.text = seriesDetailResponse!!.studio
+ } else {
+ binding.tvStudio.visibility = View.GONE
+ binding.tvStudioLabel.visibility = View.GONE
+ }
+ }
+
+ private fun setSeriesIntroduction(introduction: String) {
+ binding.tvIntroduce.text = introduction
+ }
+
+ private fun setSeriesKeywordChipList(keywordList: List) {
+ binding.chipGroup.isHorizontalScrollBarEnabled = false
+
+ for (keyword in keywordList) {
+ val chip = Chip(requireActivity())
+ chip.text = keyword
+ chip.isClickable = false
+ chip.isCheckable = false
+ chip.textSize = 14.7f
+ chip.chipStrokeWidth = 0f
+ chip.setChipBackgroundColorResource(R.color.color_222222)
+
+ val shapeAppearanceModel = ShapeAppearanceModel.Builder()
+ .setAllCornerSizes(26.7f.dpToPx())
+ .build()
+ chip.shapeAppearanceModel = shapeAppearanceModel
+
+ chip.setPadding(0, 0, 0, 0)
+ chip.setTextColor(ContextCompat.getColor(requireContext(), R.color.color_d2d2d2))
+ chip.typeface = ResourcesCompat.getFont(requireContext(), R.font.gmarket_sans_medium)
+ binding.chipGroup.addView(chip)
+ }
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailViewModel.kt
new file mode 100644
index 0000000..f448452
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailViewModel.kt
@@ -0,0 +1,59 @@
+package kr.co.vividnext.sodalive.audio_content.series.detail
+
+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.SeriesRepository
+import kr.co.vividnext.sodalive.base.BaseViewModel
+import kr.co.vividnext.sodalive.common.SharedPreferenceManager
+
+class SeriesDetailViewModel(private val repository: SeriesRepository) : BaseViewModel() {
+ private val _toastLiveData = MutableLiveData()
+ val toastLiveData: LiveData
+ get() = _toastLiveData
+
+ private var _isLoading = MutableLiveData(false)
+ val isLoading: LiveData
+ get() = _isLoading
+
+ private var _seriesDetailLiveData = MutableLiveData()
+ val seriesDetailLiveData: LiveData
+ get() = _seriesDetailLiveData
+
+ var seriesId = 0L
+
+ lateinit var seriesDetailResponse: GetSeriesDetailResponse
+
+ fun getSeriesDetail() {
+ compositeDisposable.add(
+ repository.getSeriesDetail(
+ seriesId = seriesId,
+ token = "Bearer ${SharedPreferenceManager.token}"
+ )
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ {
+ if (it.success && it.data != null) {
+ seriesDetailResponse = it.data
+ _seriesDetailLiveData.value = seriesDetailResponse
+ } else {
+ if (it.message != null) {
+ _toastLiveData.value = it.message
+ } else {
+ _toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+ }
+ }
+ _isLoading.value = false
+ },
+ {
+ _isLoading.value = false
+ it.message?.let { message -> Logger.e(message) }
+ _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
+ }
+ )
+ )
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/common/Constants.kt b/app/src/main/java/kr/co/vividnext/sodalive/common/Constants.kt
index 752831f..232b368 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/common/Constants.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/common/Constants.kt
@@ -20,10 +20,12 @@ object Constants {
const val EXTRA_DATA = "extra_data"
const val EXTRA_TERMS = "extra_terms"
const val EXTRA_EVENT = "extra_event"
+ const val EXTRA_SERIES = "extra_series"
const val EXTRA_NOTICE = "extra_notice"
const val EXTRA_ROOM_ID = "extra_room_id"
const val EXTRA_USER_ID = "extra_user_id"
const val EXTRA_THEME_ID = "extra_theme_id"
+ const val EXTRA_SERIES_ID = "extra_series_id"
const val EXTRA_NICKNAME = "extra_nickname"
const val EXTRA_MESSAGE_ID = "extra_message_id"
const val EXTRA_ROOM_DETAIL = "extra_room_detail"
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
index b64b5c6..257d645 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
@@ -27,6 +27,7 @@ import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewMod
import kr.co.vividnext.sodalive.audio_content.series.SeriesApi
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.detail.SeriesDetailViewModel
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadViewModel
import kr.co.vividnext.sodalive.audio_content.upload.theme.AudioContentThemeViewModel
import kr.co.vividnext.sodalive.common.ApiBuilder
@@ -208,6 +209,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { EventViewModel(get()) }
viewModel { NotificationSettingsViewModel(get()) }
viewModel { SettingsViewModel(get()) }
+ viewModel { SeriesDetailViewModel(get()) }
viewModel { SeriesListAllViewModel(get()) }
viewModel { TextMessageDetailViewModel(get()) }
viewModel { LiveReservationStatusViewModel(get()) }
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt
index 949ec2a..62604c9 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt
@@ -27,6 +27,9 @@ import kr.co.vividnext.sodalive.audio_content.AudioContentActivity
import kr.co.vividnext.sodalive.audio_content.AudioContentAdapter
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
+import kr.co.vividnext.sodalive.audio_content.series.SeriesListAdapter
+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.upload.AudioContentUploadActivity
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
@@ -43,8 +46,6 @@ import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAda
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity
-import kr.co.vividnext.sodalive.audio_content.series.SeriesListAdapter
-import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllActivity
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.loadUrl
import kr.co.vividnext.sodalive.extensions.moneyFormat
@@ -437,7 +438,13 @@ class UserProfileActivity : BaseActivity(
)
seriesAdapter = SeriesListAdapter(
- onClickItem = {},
+ onClickItem = {
+ startActivity(
+ Intent(applicationContext, SeriesDetailActivity::class.java).apply {
+ putExtra(Constants.EXTRA_SERIES_ID, it)
+ }
+ )
+ },
onClickCreator = {},
isVisibleCreator = false
)
diff --git a/app/src/main/res/drawable/bg_round_corner_26_7_222222.xml b/app/src/main/res/drawable/bg_round_corner_26_7_222222.xml
new file mode 100644
index 0000000..942fed5
--- /dev/null
+++ b/app/src/main/res/drawable/bg_round_corner_26_7_222222.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bg_round_corner_2_6_312827.xml b/app/src/main/res/drawable/bg_round_corner_2_6_312827.xml
new file mode 100644
index 0000000..4655baf
--- /dev/null
+++ b/app/src/main/res/drawable/bg_round_corner_2_6_312827.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bg_top_round_corner_21_3_111111.xml b/app/src/main/res/drawable/bg_top_round_corner_21_3_111111.xml
new file mode 100644
index 0000000..b4e26eb
--- /dev/null
+++ b/app/src/main/res/drawable/bg_top_round_corner_21_3_111111.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_series_detail.xml b/app/src/main/res/layout/activity_series_detail.xml
new file mode 100644
index 0000000..6cceae7
--- /dev/null
+++ b/app/src/main/res/layout/activity_series_detail.xml
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_series_detail_home.xml b/app/src/main/res/layout/fragment_series_detail_home.xml
new file mode 100644
index 0000000..1e2718d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_series_detail_home.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_series_detail_introduction.xml b/app/src/main/res/layout/fragment_series_detail_introduction.xml
new file mode 100644
index 0000000..a88f782
--- /dev/null
+++ b/app/src/main/res/layout/fragment_series_detail_introduction.xml
@@ -0,0 +1,268 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_series_content.xml b/app/src/main/res/layout/item_series_content.xml
new file mode 100644
index 0000000..14f9f08
--- /dev/null
+++ b/app/src/main/res/layout/item_series_content.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index e908790..e683e70 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -116,4 +116,6 @@
#14262D
#EC6033
#002ABD
+ #312827
+ #F1291C