parent
968428cfe0
commit
c6ef5970a5
|
@ -5,9 +5,13 @@ import kr.co.vividnext.sodalive.audition.applicant.GetAuditionApplicantListRespo
|
|||
import kr.co.vividnext.sodalive.audition.detail.GetAuditionDetailResponse
|
||||
import kr.co.vividnext.sodalive.audition.role.AuditionRoleDetailViewModel
|
||||
import kr.co.vividnext.sodalive.audition.role.GetAuditionRoleDetailResponse
|
||||
import kr.co.vividnext.sodalive.audition.vote.VoteAuditionApplicantRequest
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import kr.co.vividnext.sodalive.live.room.menu.UpdateLiveMenuRequest
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
|
@ -39,4 +43,10 @@ interface AuditionApi {
|
|||
@Query("size") size: Int,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<GetAuditionApplicantListResponse>>
|
||||
|
||||
@POST("/audition/vote")
|
||||
fun voteApplicant(
|
||||
@Body request: VoteAuditionApplicantRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package kr.co.vividnext.sodalive.audition
|
||||
|
||||
import kr.co.vividnext.sodalive.audition.role.AuditionRoleDetailViewModel
|
||||
import kr.co.vividnext.sodalive.audition.vote.VoteAuditionApplicantRequest
|
||||
|
||||
class AuditionRepository(
|
||||
private val api: AuditionApi
|
||||
|
@ -44,4 +45,12 @@ class AuditionRepository(
|
|||
size = size,
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun voteApplicant(
|
||||
request: VoteAuditionApplicantRequest,
|
||||
token: String
|
||||
) = api.voteApplicant(
|
||||
request = request,
|
||||
authHeader = token
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package kr.co.vividnext.sodalive.audition.applicant
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
|
@ -11,29 +11,26 @@ import kr.co.vividnext.sodalive.R
|
|||
import kr.co.vividnext.sodalive.databinding.ItemAuditionApplicantBinding
|
||||
|
||||
class AuditionApplicantListAdapter(
|
||||
private var itemList: List<GetAuditionRoleApplicantItem>,
|
||||
private val onClickVote: (Int) -> Unit,
|
||||
private val onClickPlayOrPause: (Int) -> Unit
|
||||
) : RecyclerView.Adapter<AuditionApplicantListAdapter.ViewHolder>() {
|
||||
) : ListAdapter<GetAuditionRoleApplicantItem, AuditionApplicantListAdapter.ViewHolder>(DiffCallback()) {
|
||||
|
||||
private var currentPlayingIndex: Int = -1
|
||||
|
||||
inner class DiffCallback(
|
||||
private val oldList: List<GetAuditionRoleApplicantItem>,
|
||||
private val newList: List<GetAuditionRoleApplicantItem>
|
||||
) : DiffUtil.Callback() {
|
||||
override fun getOldListSize() = oldList.size
|
||||
override fun getNewListSize() = newList.size
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<GetAuditionRoleApplicantItem>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItemPosition: Int,
|
||||
newItemPosition: Int
|
||||
) = oldList[oldItemPosition].applicantId == newList[newItemPosition].applicantId
|
||||
oldItem: GetAuditionRoleApplicantItem,
|
||||
newItem: GetAuditionRoleApplicantItem
|
||||
): Boolean {
|
||||
return oldItem.applicantId == newItem.applicantId
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItemPosition: Int,
|
||||
newItemPosition: Int
|
||||
) = oldList[oldItemPosition] == newList[newItemPosition]
|
||||
oldItem: GetAuditionRoleApplicantItem,
|
||||
newItem: GetAuditionRoleApplicantItem
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
|
||||
inner class ViewHolder(
|
||||
|
@ -68,16 +65,8 @@ class AuditionApplicantListAdapter(
|
|||
)
|
||||
)
|
||||
|
||||
override fun getItemCount() = itemList.size
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(itemList[position], position)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun updateData(newData: List<GetAuditionRoleApplicantItem>) {
|
||||
itemList = newData
|
||||
notifyDataSetChanged()
|
||||
holder.bind(getItem(position), position)
|
||||
}
|
||||
|
||||
fun updatePlayingIndex(newIndex: Int) {
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package kr.co.vividnext.sodalive.audition.role
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
@ -72,7 +76,72 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
|||
}
|
||||
}
|
||||
|
||||
binding.tvSortNewest.setOnClickListener {
|
||||
viewModel.setSortType(AuditionRoleDetailViewModel.AuditionApplicantSortType.NEWEST)
|
||||
}
|
||||
|
||||
binding.tvSortLikes.setOnClickListener {
|
||||
viewModel.setSortType(AuditionRoleDetailViewModel.AuditionApplicantSortType.LIKES)
|
||||
}
|
||||
|
||||
adapter = AuditionApplicantListAdapter(
|
||||
onClickPlayOrPause = {},
|
||||
onClickVote = { viewModel.voteApplicant(it) }
|
||||
)
|
||||
|
||||
val recyclerView = binding.rvApplicant
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
applicationContext,
|
||||
LinearLayoutManager.VERTICAL,
|
||||
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.top = 0
|
||||
outRect.bottom = 2.7f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
adapter.itemCount - 1 -> {
|
||||
outRect.top = 2.7f.dpToPx().toInt()
|
||||
outRect.bottom = 0
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.top = 2.7f.dpToPx().toInt()
|
||||
outRect.bottom = 2.7f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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.getAuditionApplicantList()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
|
@ -127,6 +196,26 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
|||
}
|
||||
|
||||
viewModel.applicantListLiveData.observe(this) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
viewModel.sortTypeLiveData.observe(this) {
|
||||
binding.tvSortNewest.setTextColor(
|
||||
ContextCompat.getColor(applicationContext, R.color.color_bbbbbb)
|
||||
)
|
||||
binding.tvSortLikes.setTextColor(
|
||||
ContextCompat.getColor(applicationContext, R.color.color_bbbbbb)
|
||||
)
|
||||
|
||||
if (it == AuditionRoleDetailViewModel.AuditionApplicantSortType.NEWEST) {
|
||||
binding.tvSortNewest.setTextColor(
|
||||
ContextCompat.getColor(applicationContext, R.color.color_3bb9f1)
|
||||
)
|
||||
} else if (it == AuditionRoleDetailViewModel.AuditionApplicantSortType.LIKES) {
|
||||
binding.tvSortLikes.setTextColor(
|
||||
ContextCompat.getColor(applicationContext, R.color.color_3bb9f1)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,10 @@ import io.reactivex.rxjava3.core.Observable
|
|||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audition.AuditionRepository
|
||||
import kr.co.vividnext.sodalive.audition.applicant.GetAuditionRoleApplicantItem
|
||||
import kr.co.vividnext.sodalive.audition.vote.VoteAuditionApplicantRequest
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import java.util.TimeZone
|
||||
|
||||
class AuditionRoleDetailViewModel(private val repository: AuditionRepository) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
|
@ -91,8 +93,13 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
|||
val data = applicantListResponse.data
|
||||
|
||||
_totalCountLiveData.value = data.totalCount
|
||||
_applicantListLiveData.value = data.items
|
||||
page += 1
|
||||
addApplicantList(data.items)
|
||||
|
||||
if (data.items.isEmpty()) {
|
||||
isLast = true
|
||||
} else {
|
||||
page += 1
|
||||
}
|
||||
} else {
|
||||
if (applicantListResponse.message != null) {
|
||||
_toastLiveData.value = applicantListResponse.message
|
||||
|
@ -138,8 +145,13 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
|||
val data = it.data
|
||||
|
||||
_totalCountLiveData.value = data.totalCount
|
||||
_applicantListLiveData.value = data.items
|
||||
page += 1
|
||||
addApplicantList(data.items)
|
||||
|
||||
if (data.items.isEmpty()) {
|
||||
isLast = true
|
||||
} else {
|
||||
page += 1
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
|
@ -170,6 +182,56 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
|||
}
|
||||
}
|
||||
|
||||
fun voteApplicant(position: Int) {
|
||||
val updatedList = _applicantListLiveData.value?.toMutableList()
|
||||
val applicantId = updatedList?.get(position)?.applicantId
|
||||
|
||||
if (applicantId != null) {
|
||||
_isLoading.value = false
|
||||
val request = VoteAuditionApplicantRequest(
|
||||
applicantId = applicantId,
|
||||
timezone = TimeZone.getDefault().id
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.voteApplicant(
|
||||
request = request,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success) {
|
||||
updatedList[position].voteCount += 1
|
||||
_applicantListLiveData.value = updatedList!!
|
||||
} 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.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addApplicantList(itemList: List<GetAuditionRoleApplicantItem>) {
|
||||
val updatedList = _applicantListLiveData.value?.toMutableList() ?: mutableListOf()
|
||||
updatedList.addAll(itemList)
|
||||
_applicantListLiveData.value = updatedList
|
||||
}
|
||||
|
||||
enum class AuditionApplicantSortType {
|
||||
@SerializedName("NEWEST")
|
||||
NEWEST,
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package kr.co.vividnext.sodalive.audition.vote
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
data class VoteAuditionApplicantRequest(
|
||||
@SerializedName("applicantId") val applicantId: Long,
|
||||
@SerializedName("timezone") val timezone: String,
|
||||
@SerializedName("container") val container: String = "aos"
|
||||
)
|
|
@ -166,7 +166,8 @@
|
|||
android:textColor="@color/color_bbbbbb"
|
||||
android:textSize="10.7sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/ll_applicant_count" />
|
||||
app:layout_constraintTop_toTopOf="@+id/ll_applicant_count"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_sort_newest"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="18.7dp"
|
||||
android:paddingTop="18.7dp"
|
||||
tools:background="@color/black">
|
||||
|
||||
<ImageView
|
||||
|
@ -67,4 +67,13 @@
|
|||
android:textSize="12sp"
|
||||
tools:text="777" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:background="@color/color_555555"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/iv_profile" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
Loading…
Reference in New Issue