diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3774155..1f76c4f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -147,6 +147,7 @@
+
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/AudioContentPlaylistRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/AudioContentPlaylistRepository.kt
index 62115c0..3da0f79 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/AudioContentPlaylistRepository.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/AudioContentPlaylistRepository.kt
@@ -1,6 +1,7 @@
package kr.co.vividnext.sodalive.audio_content.playlist
import kr.co.vividnext.sodalive.audio_content.playlist.create.CreatePlaylistRequest
+import kr.co.vividnext.sodalive.audio_content.playlist.modify.UpdatePlaylistRequest
class AudioContentPlaylistRepository(private val api: PlaylistApi) {
fun getPlaylistList(token: String) = api.getPlaylistList(authHeader = token)
@@ -25,4 +26,14 @@ class AudioContentPlaylistRepository(private val api: PlaylistApi) {
id = playlistId,
authHeader = token
)
+
+ fun updatePlaylist(
+ playlistId: Long,
+ request: UpdatePlaylistRequest,
+ token: String
+ ) = api.updatePlaylist(
+ id = playlistId,
+ request = request,
+ authHeader = token
+ )
}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/PlaylistApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/PlaylistApi.kt
index 25f969c..6228866 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/PlaylistApi.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/PlaylistApi.kt
@@ -3,12 +3,14 @@ package kr.co.vividnext.sodalive.audio_content.playlist
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.audio_content.playlist.create.CreatePlaylistRequest
import kr.co.vividnext.sodalive.audio_content.playlist.detail.GetPlaylistDetailResponse
+import kr.co.vividnext.sodalive.audio_content.playlist.modify.UpdatePlaylistRequest
import kr.co.vividnext.sodalive.common.ApiResponse
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
+import retrofit2.http.PUT
import retrofit2.http.Path
interface PlaylistApi {
@@ -34,4 +36,11 @@ interface PlaylistApi {
@Path("id") id: Long,
@Header("Authorization") authHeader: String
): Single>
+
+ @PUT("/audio-content/playlist/{id}")
+ fun updatePlaylist(
+ @Path("id") id: Long,
+ @Body request: UpdatePlaylistRequest,
+ @Header("Authorization") authHeader: String
+ ): Single>
}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateActivity.kt
index 58b6e5c..5ef4ffe 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateActivity.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateActivity.kt
@@ -12,6 +12,7 @@ import com.jakewharton.rxbinding4.widget.textChanges
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.audio_content.playlist.create.add_content.PlaylistAddContentDialogFragment
+import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentPlaylistCreateBinding
@@ -29,15 +30,33 @@ class AudioContentPlaylistCreateActivity : BaseActivity
+ PlaylistAddContentDialogFragment(screenWidth, viewModel.contentList) { item, isChecked ->
when {
isChecked -> {
- viewModel.addContentId(item)
+ viewModel.addContentId(
+ AudioContentPlaylistContent(
+ id = item.contentId,
+ title = item.title,
+ category = item.themeStr,
+ coverUrl = item.coverImageUrl,
+ duration = item.duration ?: "00:00:00",
+ creatorNickname = item.creatorNickname
+ )
+ )
return@PlaylistAddContentDialogFragment true
}
!isChecked -> {
- viewModel.removeContentId(item)
+ viewModel.removeContentId(
+ AudioContentPlaylistContent(
+ id = item.contentId,
+ title = item.title,
+ category = item.themeStr,
+ coverUrl = item.coverImageUrl,
+ duration = item.duration ?: "00:00:00",
+ creatorNickname = item.creatorNickname
+ )
+ )
return@PlaylistAddContentDialogFragment true
}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateContentAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateContentAdapter.kt
index 11a74ea..8340a84 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateContentAdapter.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateContentAdapter.kt
@@ -7,26 +7,26 @@ import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
-import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListItem
+import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
import kr.co.vividnext.sodalive.databinding.ItemPlaylistCreateContentBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class AudioContentPlaylistCreateContentAdapter :
RecyclerView.Adapter() {
- private val items = mutableListOf()
+ private val items = mutableListOf()
inner class ViewHolder(
private val binding: ItemPlaylistCreateContentBinding
) : RecyclerView.ViewHolder(binding.root) {
- fun bind(item: GetAudioContentOrderListItem) {
- binding.ivCover.load(item.coverImageUrl) {
+ fun bind(item: AudioContentPlaylistContent) {
+ binding.ivCover.load(item.coverUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(5.3f.dpToPx()))
}
binding.tvTitle.text = item.title
- binding.tvTheme.text = item.themeStr
+ binding.tvTheme.text = item.category
binding.tvDuration.text = item.duration
}
}
@@ -46,7 +46,7 @@ class AudioContentPlaylistCreateContentAdapter :
override fun getItemCount() = items.size
@SuppressLint("NotifyDataSetChanged")
- fun updateItems(items: List) {
+ fun updateItems(items: List) {
this.items.clear()
this.items.addAll(items)
notifyDataSetChanged()
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateViewModel.kt
index f4919ac..1e17246 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateViewModel.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/AudioContentPlaylistCreateViewModel.kt
@@ -6,6 +6,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListItem
import kr.co.vividnext.sodalive.audio_content.playlist.AudioContentPlaylistRepository
+import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
@@ -16,25 +17,25 @@ class AudioContentPlaylistCreateViewModel(
val toastLiveData: LiveData
get() = _toastLiveData
- private val _contentListLiveData = MutableLiveData>()
- val contentListLiveData: LiveData>
+ private val _contentListLiveData = MutableLiveData>()
+ val contentListLiveData: LiveData>
get() = _contentListLiveData
private var _isLoading = MutableLiveData(false)
val isLoading: LiveData
get() = _isLoading
- val contentList = mutableListOf()
+ val contentList = mutableListOf()
var title: String = ""
var desc: String = ""
- fun addContentId(item: GetAudioContentOrderListItem) {
+ fun addContentId(item: AudioContentPlaylistContent) {
contentList.add(item)
_contentListLiveData.value = contentList
}
- fun removeContentId(item: GetAudioContentOrderListItem) {
+ fun removeContentId(item: AudioContentPlaylistContent) {
contentList.remove(item)
_contentListLiveData.value = contentList
}
@@ -43,7 +44,7 @@ class AudioContentPlaylistCreateViewModel(
if (validate()) {
_isLoading.value = true
val contentIdAndOrderList = contentList.mapIndexed { index, item ->
- PlaylistContentIdAndOrder(item.contentId, index + 1)
+ PlaylistContentIdAndOrder(item.id, index + 1)
}
compositeDisposable.add(
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/add_content/PlaylistAddContentDialogFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/add_content/PlaylistAddContentDialogFragment.kt
index 2ca42cd..9ffc9b6 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/add_content/PlaylistAddContentDialogFragment.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/create/add_content/PlaylistAddContentDialogFragment.kt
@@ -18,14 +18,15 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListItem
import kr.co.vividnext.sodalive.audio_content.order.OrderType
-import kr.co.vividnext.sodalive.audio_content.playlist.create.AudioContentPlaylistCreateActivity
+import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.FragmentPlaylistAddContentBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject
class PlaylistAddContentDialogFragment(
- private val selectedContentIdList: List,
+ private val screenWidth: Int,
+ private val selectedContentList: List,
private val onItemClick: (GetAudioContentOrderListItem, Boolean) -> Boolean
) : BottomSheetDialogFragment() {
@@ -86,7 +87,7 @@ class PlaylistAddContentDialogFragment(
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
adapter = PlaylistAddContentAdapter(
- selectedContentIdList.map { it.contentId }.toSet(),
+ selectedContentList.map { it.id }.toSet(),
onItemClick
)
@@ -157,7 +158,7 @@ class PlaylistAddContentDialogFragment(
viewModel.isLoading.observe(viewLifecycleOwner) {
if (it) {
loadingDialog.show(
- (requireActivity() as AudioContentPlaylistCreateActivity).screenWidth,
+ screenWidth,
""
)
} else {
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/detail/AudioContentPlaylistDetailActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/detail/AudioContentPlaylistDetailActivity.kt
index eaec1bc..384a2e6 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/detail/AudioContentPlaylistDetailActivity.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/detail/AudioContentPlaylistDetailActivity.kt
@@ -1,14 +1,17 @@
package kr.co.vividnext.sodalive.audio_content.playlist.detail
import android.annotation.SuppressLint
+import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import coil.load
+import kr.co.vividnext.sodalive.audio_content.playlist.modify.AudioContentPlaylistModifyActivity
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants
@@ -28,6 +31,14 @@ class AudioContentPlaylistDetailActivity : BaseActivity
+ if (result.resultCode == RESULT_OK) {
+ viewModel.getPlaylistDetail(playlistId)
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
playlistId = intent.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_PLAYLIST_ID, 0)
super.onCreate(savedInstanceState)
@@ -87,7 +98,19 @@ class AudioContentPlaylistDetailActivity : BaseActivity(
+ ActivityAudioContentPlaylistModifyBinding::inflate
+) {
+
+ private val viewModel: AudioContentPlaylistModifyViewModel by inject()
+
+ private lateinit var imm: InputMethodManager
+ private lateinit var loadingDialog: LoadingDialog
+ private lateinit var adapter: AudioContentPlaylistModifyContentAdapter
+
+ private var playlistId: Long = 0
+ private val handler = Handler(Looper.getMainLooper())
+
+ private val addContentDialogFragment: PlaylistAddContentDialogFragment by lazy {
+ PlaylistAddContentDialogFragment(screenWidth, viewModel.contentList) { item, isChecked ->
+ when {
+ isChecked -> {
+ viewModel.addContentId(
+ AudioContentPlaylistContent(
+ id = item.contentId,
+ title = item.title,
+ category = item.themeStr,
+ coverUrl = item.coverImageUrl,
+ duration = item.duration ?: "00:00:00",
+ creatorNickname = item.creatorNickname
+ )
+ )
+ return@PlaylistAddContentDialogFragment true
+ }
+
+ !isChecked -> {
+ viewModel.removeContentId(
+ AudioContentPlaylistContent(
+ id = item.contentId,
+ title = item.title,
+ category = item.themeStr,
+ coverUrl = item.coverImageUrl,
+ duration = item.duration ?: "00:00:00",
+ creatorNickname = item.creatorNickname
+ )
+ )
+ return@PlaylistAddContentDialogFragment true
+ }
+
+ else -> {
+ return@PlaylistAddContentDialogFragment false
+ }
+ }
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ playlistId = intent.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_PLAYLIST_ID, 0)
+ super.onCreate(savedInstanceState)
+
+ if (playlistId <= 0) {
+ showToast("잘못된 요청입니다.")
+ finish()
+ }
+
+ imm = getSystemService(
+ Service.INPUT_METHOD_SERVICE
+ ) as InputMethodManager
+
+ bindData()
+ viewModel.getPlaylistDetail(playlistId)
+ }
+
+ override fun setupView() {
+ binding.tvBack.text = "재생목록 수정"
+ binding.tvBack.setOnClickListener { finish() }
+
+ loadingDialog = LoadingDialog(this, layoutInflater)
+
+ binding.tvAddContent.setOnClickListener {
+ hideKeyboard()
+ if (addContentDialogFragment.isAdded) return@setOnClickListener
+ addContentDialogFragment.show(supportFragmentManager, addContentDialogFragment.tag)
+ }
+
+ binding.tvModify.setOnClickListener {
+ hideKeyboard()
+ viewModel.modifyPlaylist {
+ setResult(RESULT_OK)
+ finish()
+ }
+ }
+
+ adapter = AudioContentPlaylistModifyContentAdapter()
+
+ val recyclerView = binding.rvPlaylistContent
+ recyclerView.setHasFixedSize(true)
+ recyclerView.layoutManager = LinearLayoutManager(
+ this,
+ 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)
+
+ outRect.left = 13.3f.dpToPx().toInt()
+ outRect.right = 13.3f.dpToPx().toInt()
+
+ when (parent.getChildAdapterPosition(view)) {
+ 0 -> {
+ outRect.top = 13.3f.dpToPx().toInt()
+ outRect.bottom = 6.7f.dpToPx().toInt()
+ }
+
+ adapter.itemCount - 1 -> {
+ outRect.top = 6.7f.dpToPx().toInt()
+ outRect.bottom = 13.3f.dpToPx().toInt()
+ }
+
+ else -> {
+ outRect.top = 6.7f.dpToPx().toInt()
+ outRect.bottom = 6.7f.dpToPx().toInt()
+ }
+ }
+ }
+ })
+
+ recyclerView.adapter = adapter
+ }
+
+ private fun bindData() {
+ viewModel.toastLiveData.observe(this) {
+ it?.let { showToast(it) }
+ }
+
+ viewModel.isLoading.observe(this) {
+ if (it) {
+ loadingDialog.show(screenWidth, "")
+ } else {
+ loadingDialog.dismiss()
+ }
+ }
+
+ viewModel.contentListLiveData.observe(this) {
+ adapter.updateItems(it)
+ }
+
+ viewModel.detailResponseLiveData.observe(this) {
+ binding.etTitle.setText(it.title)
+ binding.etDesc.setText(it.desc)
+ adapter.updateItems(it.contentList)
+ }
+
+ compositeDisposable.add(
+ binding.etTitle.textChanges()
+ .map { it.toString() }
+ .distinctUntilChanged()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe {
+ if (it.length > 30) {
+ val truncated = it.take(30)
+ binding.etTitle.setText(truncated)
+ binding.etTitle.setSelection(truncated.length)
+ setTitle(truncated)
+ } else {
+ setTitle(it)
+ }
+ }
+ )
+
+ compositeDisposable.add(
+ binding.etDesc.textChanges()
+ .map { it.toString() }
+ .distinctUntilChanged()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe {
+ if (it.length > 40) {
+ val truncated = it.take(40)
+ binding.etDesc.setText(truncated)
+ binding.etDesc.setSelection(truncated.length)
+ setDesc(truncated)
+ } else {
+ setDesc(it)
+ }
+ }
+ )
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun setTitle(title: String) {
+ binding.tvTitleLength.text = "${title.length}/30"
+ viewModel.title = title
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun setDesc(desc: String) {
+ binding.tvDescLength.text = "${desc.length}/40"
+ viewModel.desc = desc
+ }
+
+ private fun hideKeyboard() {
+ handler.postDelayed({
+ imm.hideSoftInputFromWindow(
+ window.decorView.applicationWindowToken,
+ InputMethodManager.HIDE_NOT_ALWAYS
+ )
+ }, 100)
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/AudioContentPlaylistModifyContentAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/AudioContentPlaylistModifyContentAdapter.kt
new file mode 100644
index 0000000..4f9d8ab
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/AudioContentPlaylistModifyContentAdapter.kt
@@ -0,0 +1,57 @@
+package kr.co.vividnext.sodalive.audio_content.playlist.modify
+
+import android.annotation.SuppressLint
+import android.view.LayoutInflater
+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.audio_content.playlist.detail.AudioContentPlaylistContent
+import kr.co.vividnext.sodalive.databinding.ItemPlaylistCreateContentBinding
+import kr.co.vividnext.sodalive.extensions.dpToPx
+
+class AudioContentPlaylistModifyContentAdapter :
+ RecyclerView.Adapter() {
+ private val items = mutableListOf()
+
+ inner class ViewHolder(
+ private val binding: ItemPlaylistCreateContentBinding
+ ) : RecyclerView.ViewHolder(binding.root) {
+ fun bind(item: AudioContentPlaylistContent) {
+ binding.ivCover.load(item.coverUrl) {
+ crossfade(true)
+ placeholder(R.drawable.bg_placeholder)
+ transformations(RoundedCornersTransformation(5.3f.dpToPx()))
+ }
+
+ binding.tvTitle.text = item.title
+ binding.tvTheme.text = item.category
+ binding.tvDuration.text = item.duration
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
+ ItemPlaylistCreateContentBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ )
+
+ override fun onBindViewHolder(
+ holder: ViewHolder,
+ position: Int
+ ) {
+ holder.bind(items[position])
+ }
+
+ override fun getItemCount() = items.size
+
+ @SuppressLint("NotifyDataSetChanged")
+ fun updateItems(items: List) {
+ this.items.clear()
+ this.items.addAll(items)
+ notifyDataSetChanged()
+ }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/AudioContentPlaylistModifyViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/AudioContentPlaylistModifyViewModel.kt
new file mode 100644
index 0000000..333abf3
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/AudioContentPlaylistModifyViewModel.kt
@@ -0,0 +1,154 @@
+package kr.co.vividnext.sodalive.audio_content.playlist.modify
+
+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.playlist.AudioContentPlaylistRepository
+import kr.co.vividnext.sodalive.audio_content.playlist.create.PlaylistContentIdAndOrder
+import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
+import kr.co.vividnext.sodalive.audio_content.playlist.detail.GetPlaylistDetailResponse
+import kr.co.vividnext.sodalive.base.BaseViewModel
+import kr.co.vividnext.sodalive.common.SharedPreferenceManager
+
+class AudioContentPlaylistModifyViewModel(
+ private val repository: AudioContentPlaylistRepository
+) : BaseViewModel() {
+ private val _toastLiveData = MutableLiveData()
+ val toastLiveData: LiveData
+ get() = _toastLiveData
+
+ private val _contentListLiveData = MutableLiveData>()
+ val contentListLiveData: LiveData>
+ get() = _contentListLiveData
+
+ private var _isLoading = MutableLiveData(false)
+ val isLoading: LiveData
+ get() = _isLoading
+
+ private val _detailResponseLiveData = MutableLiveData()
+ val detailResponseLiveData: LiveData
+ get() = _detailResponseLiveData
+
+ val contentList = mutableListOf()
+
+ var title: String = ""
+ var desc: String = ""
+ private var playlistId: Long = 0
+
+ fun addContentId(item: AudioContentPlaylistContent) {
+ contentList.add(item)
+ _contentListLiveData.value = contentList
+ }
+
+ fun removeContentId(item: AudioContentPlaylistContent) {
+ contentList.remove(item)
+ _contentListLiveData.value = contentList
+ }
+
+ fun modifyPlaylist(onSuccess: () -> Unit) {
+ if (validate()) {
+ _isLoading.value = true
+ val contentIdAndOrderList = contentList.mapIndexed { index, item ->
+ PlaylistContentIdAndOrder(item.id, index + 1)
+ }
+
+ val request = UpdatePlaylistRequest(
+ title = if (_detailResponseLiveData.value!!.title != title) {
+ title
+ } else {
+ null
+ },
+ desc = if (_detailResponseLiveData.value!!.desc != desc) {
+ desc
+ } else {
+ null
+ },
+ contentIdAndOrderList = contentIdAndOrderList
+ )
+
+ compositeDisposable.add(
+ repository.updatePlaylist(
+ playlistId = playlistId,
+ request = request,
+ token = "Bearer ${SharedPreferenceManager.token}"
+ )
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ {
+ _isLoading.value = false
+ if (it.success) {
+ onSuccess()
+ } else {
+ if (it.message != null) {
+ _toastLiveData.value = it.message
+ } else {
+ _toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+ }
+ }
+ },
+ {
+ _isLoading.value = false
+ if (it.message != null) {
+ _toastLiveData.value = it.message
+ } else {
+ _toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+ }
+ }
+ )
+ )
+ }
+ }
+
+ private fun validate(): Boolean {
+ if (title.isBlank() || title.length < 3) {
+ _toastLiveData.value = "제목을 3자 이상 입력하세요"
+ return false
+ }
+
+ if (contentList.isEmpty()) {
+ _toastLiveData.value = "콘텐츠를 1개 이상 추가하세요"
+ return false
+ }
+
+ return true
+ }
+
+ fun getPlaylistDetail(playlistId: Long) {
+ this.playlistId = playlistId
+ _isLoading.value = true
+ compositeDisposable.add(
+ repository.getPlaylistDetail(
+ playlistId = playlistId,
+ token = "Bearer ${SharedPreferenceManager.token}"
+ )
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ {
+ if (it.success && it.data != null) {
+ val data = it.data
+ _detailResponseLiveData.value = data!!
+ this.contentList.addAll(data.contentList)
+ } else {
+ if (it.message != null) {
+ _toastLiveData.postValue(it.message)
+ } else {
+ _toastLiveData.postValue(
+ "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+ )
+ }
+ }
+ _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/audio_content/playlist/modify/UpdatePlaylistRequest.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/UpdatePlaylistRequest.kt
new file mode 100644
index 0000000..d90cd47
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/UpdatePlaylistRequest.kt
@@ -0,0 +1,10 @@
+package kr.co.vividnext.sodalive.audio_content.playlist.modify
+
+import com.google.gson.annotations.SerializedName
+import kr.co.vividnext.sodalive.audio_content.playlist.create.PlaylistContentIdAndOrder
+
+data class UpdatePlaylistRequest(
+ @SerializedName("title") val title: String? = null,
+ @SerializedName("desc") val desc: String? = null,
+ @SerializedName("contentIdAndOrderList") val contentIdAndOrderList: List = emptyList()
+)
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 d7a58dc..371acf1 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
@@ -29,6 +29,7 @@ import kr.co.vividnext.sodalive.audio_content.playlist.AudioContentPlaylistListV
import kr.co.vividnext.sodalive.audio_content.playlist.PlaylistApi
import kr.co.vividnext.sodalive.audio_content.playlist.create.AudioContentPlaylistCreateViewModel
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistDetailViewModel
+import kr.co.vividnext.sodalive.audio_content.playlist.modify.AudioContentPlaylistModifyViewModel
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
@@ -274,6 +275,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { AudioContentPlaylistListViewModel(get()) }
viewModel { AudioContentPlaylistDetailViewModel(get()) }
viewModel { AudioContentPlaylistCreateViewModel(get()) }
+ viewModel { AudioContentPlaylistModifyViewModel(get()) }
}
private val repositoryModule = module {
diff --git a/app/src/main/res/layout/activity_audio_content_playlist_create.xml b/app/src/main/res/layout/activity_audio_content_playlist_create.xml
index 83d71ce..78c59cd 100644
--- a/app/src/main/res/layout/activity_audio_content_playlist_create.xml
+++ b/app/src/main/res/layout/activity_audio_content_playlist_create.xml
@@ -148,7 +148,7 @@
android:drawablePadding="3.5dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center_vertical"
- android:text="새로운 콘텐츠 추가"
+ android:text="새로운 콘텐츠 추가/제거"
android:textColor="@color/color_3bb9f1"
app:layout_constraintStart_toStartOf="@+id/et_desc"
app:layout_constraintTop_toBottomOf="@+id/et_desc" />
diff --git a/app/src/main/res/layout/activity_audio_content_playlist_modify.xml b/app/src/main/res/layout/activity_audio_content_playlist_modify.xml
new file mode 100644
index 0000000..8e57dfd
--- /dev/null
+++ b/app/src/main/res/layout/activity_audio_content_playlist_modify.xml
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_playlist_add_content.xml b/app/src/main/res/layout/fragment_playlist_add_content.xml
index 71edb53..c978552 100644
--- a/app/src/main/res/layout/fragment_playlist_add_content.xml
+++ b/app/src/main/res/layout/fragment_playlist_add_content.xml
@@ -17,7 +17,7 @@
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:fontFamily="@font/gmarket_sans_bold"
- android:text="새로운 콘텐츠 추가"
+ android:text="새로운 콘텐츠 추가/제거"
android:textColor="@color/color_eeeeee"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/item_playlist_add_content.xml b/app/src/main/res/layout/item_playlist_add_content.xml
index 7bd0e4e..ec72e16 100644
--- a/app/src/main/res/layout/item_playlist_add_content.xml
+++ b/app/src/main/res/layout/item_playlist_add_content.xml
@@ -67,6 +67,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
+ android:padding="8dp"
android:src="@drawable/ic_playlist_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/item_playlist_modify_content.xml b/app/src/main/res/layout/item_playlist_modify_content.xml
new file mode 100644
index 0000000..fdeaf50
--- /dev/null
+++ b/app/src/main/res/layout/item_playlist_modify_content.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+