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