From 968428cfe0c03ad398a42f3b75a0b30f892bbb61 Mon Sep 17 00:00:00 2001 From: klaus Date: Thu, 2 Jan 2025 17:02:15 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B0=B0=EC=97=AD=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 1 + .../sodalive/audition/AuditionApi.kt | 18 ++ .../sodalive/audition/AuditionRepository.kt | 24 ++ .../applicant/AuditionApplicantListAdapter.kt | 89 +++++++ .../GetAuditionApplicantListResponse.kt | 19 ++ .../audition/detail/AuditionDetailActivity.kt | 10 +- .../role/AuditionRoleDetailActivity.kt | 132 ++++++++++ .../role/AuditionRoleDetailViewModel.kt | 180 +++++++++++++ .../role/GetAuditionRoleDetailResponse.kt | 15 ++ .../co/vividnext/sodalive/common/Constants.kt | 1 + .../java/kr/co/vividnext/sodalive/di/AppDI.kt | 2 + .../res/drawable-xxhdpi/ic_audition_pause.png | Bin 0 -> 293 bytes .../res/drawable-xxhdpi/ic_audition_play.png | Bin 0 -> 1413 bytes .../res/drawable-xxhdpi/ic_heart_vote.png | Bin 0 -> 860 bytes .../res/layout/activity_audition_detail.xml | 1 + .../layout/activity_audition_role_detail.xml | 242 ++++++++++++++++++ .../res/layout/item_audition_applicant.xml | 70 +++++ .../main/res/layout/item_audition_role.xml | 4 +- 18 files changed, 805 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audition/applicant/AuditionApplicantListAdapter.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audition/applicant/GetAuditionApplicantListResponse.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audition/role/AuditionRoleDetailActivity.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audition/role/AuditionRoleDetailViewModel.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audition/role/GetAuditionRoleDetailResponse.kt create mode 100644 app/src/main/res/drawable-xxhdpi/ic_audition_pause.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_audition_play.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_heart_vote.png create mode 100644 app/src/main/res/layout/activity_audition_role_detail.xml create mode 100644 app/src/main/res/layout/item_audition_applicant.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c54482e..f602a9b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -150,6 +150,7 @@ + diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audition/AuditionApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/audition/AuditionApi.kt index 4f13957..66ca14c 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audition/AuditionApi.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audition/AuditionApi.kt @@ -1,7 +1,10 @@ package kr.co.vividnext.sodalive.audition import io.reactivex.rxjava3.core.Single +import kr.co.vividnext.sodalive.audition.applicant.GetAuditionApplicantListResponse 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.common.ApiResponse import retrofit2.http.GET import retrofit2.http.Header @@ -21,4 +24,19 @@ interface AuditionApi { @Path("id") id: Long, @Header("Authorization") authHeader: String ): Single> + + @GET("/audition/role/{id}") + fun getAuditionRoleDetail( + @Path("id") id: Long, + @Header("Authorization") authHeader: String + ): Single> + + @GET("/audition/applicant") + fun getAuditionApplicantList( + @Query("auditionRoleId") auditionRoleId: Long, + @Query("sortType") sortType: AuditionRoleDetailViewModel.AuditionApplicantSortType, + @Query("page") page: Int, + @Query("size") size: Int, + @Header("Authorization") authHeader: String + ): Single> } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audition/AuditionRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/audition/AuditionRepository.kt index 11ce2c9..3934cea 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audition/AuditionRepository.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audition/AuditionRepository.kt @@ -1,5 +1,7 @@ package kr.co.vividnext.sodalive.audition +import kr.co.vividnext.sodalive.audition.role.AuditionRoleDetailViewModel + class AuditionRepository( private val api: AuditionApi ) { @@ -20,4 +22,26 @@ class AuditionRepository( id = auditionId, authHeader = token ) + + fun getAuditionRoleDetail( + auditionRoleId: Long, + token: String + ) = api.getAuditionRoleDetail( + id = auditionRoleId, + authHeader = token + ) + + fun getAuditionApplicantList( + auditionRoleId: Long, + sortType: AuditionRoleDetailViewModel.AuditionApplicantSortType, + page: Int, + size: Int, + token: String + ) = api.getAuditionApplicantList( + auditionRoleId = auditionRoleId, + sortType = sortType, + page = page - 1, + size = size, + authHeader = token + ) } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audition/applicant/AuditionApplicantListAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/audition/applicant/AuditionApplicantListAdapter.kt new file mode 100644 index 0000000..263d5bc --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audition/applicant/AuditionApplicantListAdapter.kt @@ -0,0 +1,89 @@ +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.RecyclerView +import coil.load +import coil.transform.CircleCropTransformation +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.databinding.ItemAuditionApplicantBinding + +class AuditionApplicantListAdapter( + private var itemList: List, + private val onClickVote: (Int) -> Unit, + private val onClickPlayOrPause: (Int) -> Unit +) : RecyclerView.Adapter() { + + private var currentPlayingIndex: Int = -1 + + inner class DiffCallback( + private val oldList: List, + private val newList: List + ) : DiffUtil.Callback() { + override fun getOldListSize() = oldList.size + override fun getNewListSize() = newList.size + + override fun areItemsTheSame( + oldItemPosition: Int, + newItemPosition: Int + ) = oldList[oldItemPosition].applicantId == newList[newItemPosition].applicantId + + override fun areContentsTheSame( + oldItemPosition: Int, + newItemPosition: Int + ) = oldList[oldItemPosition] == newList[newItemPosition] + } + + inner class ViewHolder( + private val binding: ItemAuditionApplicantBinding + ) : RecyclerView.ViewHolder(binding.root) { + fun bind(item: GetAuditionRoleApplicantItem, position: Int) { + binding.ivVote.setOnClickListener { onClickVote(position) } + binding.ivPlayOrPause.setOnClickListener { onClickPlayOrPause(position) } + + binding.tvNickname.text = item.nickname + binding.ivProfile.load(item.profileImageUrl) { + crossfade(true) + placeholder(R.drawable.bg_placeholder) + transformations(CircleCropTransformation()) + } + + binding.ivPlayOrPause.setImageResource( + if (position == currentPlayingIndex) { + R.drawable.ic_audition_play + } else { + R.drawable.ic_audition_pause + } + ) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder( + ItemAuditionApplicantBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + + override fun getItemCount() = itemList.size + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(itemList[position], position) + } + + @SuppressLint("NotifyDataSetChanged") + fun updateData(newData: List) { + itemList = newData + notifyDataSetChanged() + } + + fun updatePlayingIndex(newIndex: Int) { + val previousIndex = currentPlayingIndex + currentPlayingIndex = newIndex + notifyItemChanged(previousIndex) + notifyItemChanged(currentPlayingIndex) + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audition/applicant/GetAuditionApplicantListResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/audition/applicant/GetAuditionApplicantListResponse.kt new file mode 100644 index 0000000..4ecedf3 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audition/applicant/GetAuditionApplicantListResponse.kt @@ -0,0 +1,19 @@ +package kr.co.vividnext.sodalive.audition.applicant + +import androidx.annotation.Keep +import com.google.gson.annotations.SerializedName + +@Keep +data class GetAuditionApplicantListResponse( + @SerializedName("totalCount") val totalCount: Int, + @SerializedName("items") val items: List +) + +@Keep +data class GetAuditionRoleApplicantItem( + @SerializedName("applicantId") val applicantId: Long, + @SerializedName("nickname") val nickname: String, + @SerializedName("profileImageUrl") val profileImageUrl: String, + @SerializedName("voiceUrl") val voiceUrl: String, + @SerializedName("voteCount") var voteCount: Long +) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audition/detail/AuditionDetailActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/audition/detail/AuditionDetailActivity.kt index f15f360..37e0edb 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audition/detail/AuditionDetailActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audition/detail/AuditionDetailActivity.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.audition.detail +import android.content.Intent import android.graphics.Rect import android.os.Bundle import android.view.View @@ -9,6 +10,7 @@ import androidx.recyclerview.widget.RecyclerView import coil.load import coil.transform.RoundedCornersTransformation import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.audition.role.AuditionRoleDetailActivity import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.LoadingDialog @@ -72,7 +74,13 @@ class AuditionDetailActivity : BaseActivity( } } - adapter = AuditionDetailRoleAdapter { } + adapter = AuditionDetailRoleAdapter { + startActivity( + Intent(applicationContext, AuditionRoleDetailActivity::class.java).apply { + putExtra(Constants.EXTRA_AUDITION_ROLE_ID, it) + } + ) + } binding.rvRole.layoutManager = LinearLayoutManager( applicationContext, diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audition/role/AuditionRoleDetailActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/audition/role/AuditionRoleDetailActivity.kt new file mode 100644 index 0000000..09e8c88 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audition/role/AuditionRoleDetailActivity.kt @@ -0,0 +1,132 @@ +package kr.co.vividnext.sodalive.audition.role + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.view.View +import android.widget.Toast +import coil.load +import coil.transform.RoundedCornersTransformation +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.audition.applicant.AuditionApplicantListAdapter +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.databinding.ActivityAuditionRoleDetailBinding +import kr.co.vividnext.sodalive.extensions.dpToPx +import org.koin.android.ext.android.inject + +class AuditionRoleDetailActivity : BaseActivity( + ActivityAuditionRoleDetailBinding::inflate +) { + private val viewModel: AuditionRoleDetailViewModel by inject() + + private lateinit var loadingDialog: LoadingDialog + private lateinit var adapter: AuditionApplicantListAdapter + + private var auditionRoleId: Long = 0 + private var isOpenInformation = false + + override fun onCreate(savedInstanceState: Bundle?) { + auditionRoleId = intent.getLongExtra(Constants.EXTRA_AUDITION_ROLE_ID, 0) + + if (auditionRoleId <= 0) { + Toast.makeText( + applicationContext, + "잘못된 요청입니다.\n다시 시도해 주세요.", + Toast.LENGTH_LONG + ).show() + + finish() + } + + super.onCreate(savedInstanceState) + + bindData() + viewModel.getAuditionRoleDetail(auditionRoleId = auditionRoleId) + } + + override fun setupView() { + loadingDialog = LoadingDialog(this, layoutInflater) + binding.toolbar.tvBack.setOnClickListener { finish() } + binding.tvOpen.setOnClickListener { + isOpenInformation = !isOpenInformation + if (isOpenInformation) { + binding.tvInformation.maxLines = Int.MAX_VALUE + binding.tvOpen.text = "접기" + binding.tvOpen.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_live_detail_top, + 0, + 0, + 0 + ) + } else { + binding.tvInformation.maxLines = 3 + binding.tvOpen.text = "펼치기" + binding.tvOpen.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_live_detail_bottom, + 0, + 0, + 0 + ) + } + } + + + } + + 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.auditionRoleDetailLiveData.observe(this) { roleDetail -> + binding.toolbar.tvBack.text = roleDetail.name + + binding.tvAuditionScript.setOnClickListener { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(roleDetail.auditionScriptUrl))) + } + + binding.tvOriginalWork.setOnClickListener { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(roleDetail.originalWorkUrl))) + } + + binding.tvInformation.text = roleDetail.information + + binding.ivCover.load(roleDetail.imageUrl) { + crossfade(true) + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(5f.dpToPx())) + } + + if (roleDetail.isAlreadyApplicant) { + binding.tvApplicant.text = "오디션 재지원" + } else { + binding.tvApplicant.text = "오디션 지원하기" + } + } + + viewModel.totalCountLiveData.observe(this) { + binding.groupApplicant.visibility = View.GONE + binding.groupNoApplicant.visibility = View.GONE + + if (it > 0) { + binding.groupApplicant.visibility = View.VISIBLE + binding.tvApplicantCount.text = "$it" + } else { + binding.groupNoApplicant.visibility = View.VISIBLE + } + } + + viewModel.applicantListLiveData.observe(this) { + } + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audition/role/AuditionRoleDetailViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/audition/role/AuditionRoleDetailViewModel.kt new file mode 100644 index 0000000..6df5b9f --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audition/role/AuditionRoleDetailViewModel.kt @@ -0,0 +1,180 @@ +package kr.co.vividnext.sodalive.audition.role + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.google.gson.annotations.SerializedName +import com.orhanobut.logger.Logger +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +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.base.BaseViewModel +import kr.co.vividnext.sodalive.common.SharedPreferenceManager + +class AuditionRoleDetailViewModel(private val repository: AuditionRepository) : BaseViewModel() { + private val _toastLiveData = MutableLiveData() + val toastLiveData: LiveData + get() = _toastLiveData + + private val _isLoading = MutableLiveData(false) + val isLoading: LiveData + get() = _isLoading + + private val _auditionRoleDetailLiveData = MutableLiveData() + val auditionRoleDetailLiveData: LiveData + get() = _auditionRoleDetailLiveData + + private val _totalCountLiveData = MutableLiveData(0) + val totalCountLiveData: LiveData + get() = _totalCountLiveData + + private val _applicantListLiveData = MutableLiveData>() + val applicantListLiveData: LiveData> + get() = _applicantListLiveData + + private val _sortTypeLiveData = MutableLiveData(AuditionApplicantSortType.NEWEST) + val sortTypeLiveData: LiveData + get() = _sortTypeLiveData + + var page = 1 + var isLast = false + private var auditionRoleId = -1L + private val pageSize = 10 + + fun getAuditionRoleDetail(auditionRoleId: Long, onFailure: (() -> Unit)? = null) { + this.auditionRoleId = auditionRoleId + _isLoading.value = true + + val auditionRoleDetail = repository.getAuditionRoleDetail( + auditionRoleId = auditionRoleId, + token = "Bearer ${SharedPreferenceManager.token}" + ) + + val getApplicantList = repository.getAuditionApplicantList( + auditionRoleId = auditionRoleId, + sortType = _sortTypeLiveData.value!!, + page = page, + size = pageSize, + token = "Bearer ${SharedPreferenceManager.token}" + ) + + compositeDisposable.add( + Observable.combineLatest( + auditionRoleDetail.toObservable(), + getApplicantList.toObservable() + ) { response1, response2 -> + Pair(response1, response2) + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { pair -> + val roleDetailResponse = pair.first + val applicantListResponse = pair.second + + if (roleDetailResponse.success && roleDetailResponse.data != null) { + _auditionRoleDetailLiveData.value = roleDetailResponse.data!! + } else { + if (roleDetailResponse.message != null) { + _toastLiveData.value = roleDetailResponse.message + } else { + _toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + } + + if (onFailure != null) { + onFailure() + } + } + + if (applicantListResponse.success && applicantListResponse.data != null) { + val data = applicantListResponse.data + + _totalCountLiveData.value = data.totalCount + _applicantListLiveData.value = data.items + page += 1 + } else { + if (applicantListResponse.message != null) { + _toastLiveData.value = applicantListResponse.message + } else { + _toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + } + + if (onFailure != null) { + onFailure() + } + } + + _isLoading.value = false + }, + { + _isLoading.value = false + it.message?.let { message -> Logger.e(message) } + _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + if (onFailure != null) { + onFailure() + } + } + ) + ) + } + + fun getAuditionApplicantList() { + _isLoading.value = true + + compositeDisposable.add( + repository.getAuditionApplicantList( + auditionRoleId = auditionRoleId, + sortType = _sortTypeLiveData.value!!, + page = page, + size = pageSize, + token = "Bearer ${SharedPreferenceManager.token}" + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + if (it.success && it.data != null) { + val data = it.data + + _totalCountLiveData.value = data.totalCount + _applicantListLiveData.value = data.items + page += 1 + } 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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + } + ) + ) + } + + fun setSortType(sortType: AuditionApplicantSortType) { + val prevSortType = _sortTypeLiveData.value!! + + if (sortType != prevSortType) { + _sortTypeLiveData.value = sortType + isLast = false + page = 1 + getAuditionApplicantList() + } + } + + enum class AuditionApplicantSortType { + @SerializedName("NEWEST") + NEWEST, + + @SerializedName("LIKES") + LIKES + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audition/role/GetAuditionRoleDetailResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/audition/role/GetAuditionRoleDetailResponse.kt new file mode 100644 index 0000000..eaa8471 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audition/role/GetAuditionRoleDetailResponse.kt @@ -0,0 +1,15 @@ +package kr.co.vividnext.sodalive.audition.role + +import androidx.annotation.Keep +import com.google.gson.annotations.SerializedName + +@Keep +data class GetAuditionRoleDetailResponse( + @SerializedName("auditionRoleId") val auditionRoleId: Long, + @SerializedName("name") val name: String, + @SerializedName("imageUrl") val imageUrl: String, + @SerializedName("information") val information: String, + @SerializedName("originalWorkUrl") val originalWorkUrl: String, + @SerializedName("auditionScriptUrl") val auditionScriptUrl: String, + @SerializedName("isAlreadyApplicant") val isAlreadyApplicant: Boolean +) 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 16aac00..92800c8 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 @@ -40,6 +40,7 @@ object Constants { const val EXTRA_LIVE_TIME_NOW = "extra_live_time_now" const val EXTRA_RESULT_ROULETTE = "extra_result_roulette" const val EXTRA_GO_TO_PREV_PAGE = "extra_go_to_prev_page" + const val EXTRA_AUDITION_ROLE_ID = "extra_audition_role_id" const val EXTRA_SELECT_RECIPIENT = "extra_select_recipient" const val EXTRA_ROOM_CHANNEL_NAME = "extra_room_channel_name" const val EXTRA_LIVE_RESERVATION_RESPONSE = "extra_live_reservation_response" 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 2f6388f..6d2dc12 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 @@ -43,6 +43,7 @@ import kr.co.vividnext.sodalive.audition.AuditionApi import kr.co.vividnext.sodalive.audition.AuditionRepository import kr.co.vividnext.sodalive.audition.AuditionViewModel import kr.co.vividnext.sodalive.audition.detail.AuditionDetailViewModel +import kr.co.vividnext.sodalive.audition.role.AuditionRoleDetailViewModel import kr.co.vividnext.sodalive.common.ApiBuilder import kr.co.vividnext.sodalive.common.ObjectBox import kr.co.vividnext.sodalive.explorer.ExplorerApi @@ -286,6 +287,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) { viewModel { AudioContentPlayerViewModel() } viewModel { AuditionViewModel(get()) } viewModel { AuditionDetailViewModel(get()) } + viewModel { AuditionRoleDetailViewModel(get()) } } private val repositoryModule = module { diff --git a/app/src/main/res/drawable-xxhdpi/ic_audition_pause.png b/app/src/main/res/drawable-xxhdpi/ic_audition_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..7c0758c34901c35d0dcb2a2cd77ae9d38189a07f GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{w_}!$B+ufx3?Vm4k-w@J-jF!qL-5&VB5ql z^MZH6JE_NuxKzHJ|1ESWMNByE`V2;fmZekP86MjrTOPk=$YVeT8Onyw12=}RcZ zCloHdM{W-9=KWe0&;R@}s*Y6N`~CmXyYjoA@7-*At=gU;K_&k;Z$pRMHiIspFBm*s L{an^LB{Ts5eH?H_ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_audition_play.png b/app/src/main/res/drawable-xxhdpi/ic_audition_play.png new file mode 100644 index 0000000000000000000000000000000000000000..542d9472a0a25c2c695e15ee95faf9879418203a GIT binary patch literal 1413 zcmV;01$z34P);m#3OrmDa#YA3@-|=*u*KFf284)W7C?*24#R4zmneUBWAzNCKv==&AjWJg zx{SnE9rZh2d2li?I?NSDyUb&VynC1(SDq7;B&ahECDmrG>5= zpjiydk891-N416qiWui%Wp{W;%+;~W<1X<7Z$qKiTdN&hyi#&4zJkfS8Bma@L|Y^T z++oXxZvc#jwxdpld%Mxa)420^kcV@i2q88&q}h;nN9s@;-~ZVyP*I5^I!Le*?{eH> z>I`8V8NYqu;I1<`_lLiGyg7}mMxq~q1VMuDfFj&s3Xbq~8yhpu|7tV%r-QsnKHQ#? z=psbKQ?NaL?}7pt`j5>~F9(FQUHh>X!7#9N&KA670<-rVVPEj#O4?#_bg<0 zodTHCgLHyvADdSZfG+WyYrcJQ(f`rj`#9*r`~>epJnm7)mqWij<9{w1ZOvq>1rn7f z0h%>tsu~Xe58he{>X#?7sz={f_=R)^U>Hd4ETeLquB;khTlgx(4 z^6jl8Y^{#n@0{C7*AqX%8pv}Lw&EAN8^>M1EQzUFeo4)7GrrzQg=tnJ^PQu^?3SXS zlXvwfC-A-RgAX_Ebr~GFybNwHzrB%!?Dk67W*_=_S+$3sgCvhXPM5kS9(g4*F8=uivnztvLk{+85bYFvN+<#MFwLE{kbUf9%(syqoP!K>Vgch(3}`!t z^6!{~sAGuXl<>JIo_s=iDu618rye{3Y9JC?9za>>I?+KqbkN6D^b^c4ssW3E4k5*I zJd+lkY=DA|z!cCSf>=(_syzHkWj64oV>W6=PL64CUO6G5SvwLV;rm1k#pGRw`Qvch zqgZJsG=0cYM=^WEV%*MpUdAz>-m*cDf5Q^^kQZk^J?UfzD!=3l^st>2p22Jwc(n@C z1jQG4)1-ppTh7@*7jTS|hi?z_Fb|;E#?^5$aG`v6Hi@NN>9+_1TiN_ZV+ZlXR>Qn3A>OR&>JKtXqR1( zyuK$e2n_y}99#I?APXbC56Lz>381E?rlvw5WQ0Do_FxD1x%ifk-prc&!{y(w^KXp( z(O<{`b-gA`UU`7j1cJRq`|toe#O)97Ap@y|snhb{2|vOM_^=3KBV!;shh4Z!8r)R! z^>;3LeCS1=4EG%V2zH-(Y2*_LQt~qr(fn2D@Md^k=>JU<1TH{TSwTM<(L=kF(FGR4fa^vV)<&>D>e?4^@(mmKBn%EmcA~URFrF zdRT7hWU@lq&-@x_uVu?6N{G zVby)1()nbC+`=l1LZtJ{3PywlyV7Q41!Ka39cgp2f>B|?th8BK!MLzsM%uirU`1HS zCv8VouqG^IleQ--SQQr1N!yhbtP2atr0vTJg$N7L(#6OMg$WDmrHhjl3KbTVv}`3p mkd5EHxZSTcH8nLg+r)p`{5Al0>>Dfq0000 diff --git a/app/src/main/res/layout/activity_audition_role_detail.xml b/app/src/main/res/layout/activity_audition_role_detail.xml new file mode 100644 index 0000000..c621903 --- /dev/null +++ b/app/src/main/res/layout/activity_audition_role_detail.xml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_audition_applicant.xml b/app/src/main/res/layout/item_audition_applicant.xml new file mode 100644 index 0000000..ba010a5 --- /dev/null +++ b/app/src/main/res/layout/item_audition_applicant.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_audition_role.xml b/app/src/main/res/layout/item_audition_role.xml index 4d5ceea..ea7bc34 100644 --- a/app/src/main/res/layout/item_audition_role.xml +++ b/app/src/main/res/layout/item_audition_role.xml @@ -3,8 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - tools:background="@color/black" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + tools:background="@color/black">