새 재생목록 만들기

- 새로운 콘텐츠 추가 페이지 추가
This commit is contained in:
klaus 2024-12-03 23:49:25 +09:00
parent ad5a84c3b8
commit 40335fb7ff
7 changed files with 382 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.audio_content.playlist.create
import android.app.Service
import android.os.Bundle
import android.view.inputmethod.InputMethodManager
import kr.co.vividnext.sodalive.audio_content.playlist.create.add_content.PlaylistAddContentDialogFragment
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentPlaylistCreateBinding
@ -14,6 +15,10 @@ class AudioContentPlaylistCreateActivity : BaseActivity<ActivityAudioContentPlay
private lateinit var imm: InputMethodManager
private lateinit var loadingDialog: LoadingDialog
private val addContentDialogFragment: PlaylistAddContentDialogFragment by lazy {
PlaylistAddContentDialogFragment()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -27,5 +32,10 @@ class AudioContentPlaylistCreateActivity : BaseActivity<ActivityAudioContentPlay
binding.tvBack.setOnClickListener { finish() }
loadingDialog = LoadingDialog(this, layoutInflater)
binding.tvAddContent.setOnClickListener {
if (addContentDialogFragment.isAdded) return@setOnClickListener
addContentDialogFragment.show(supportFragmentManager, addContentDialogFragment.tag)
}
}
}

View File

@ -0,0 +1,62 @@
package kr.co.vividnext.sodalive.audio_content.playlist.create.add_content
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListItem
import kr.co.vividnext.sodalive.databinding.ItemPlaylistAddContentBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class PlaylistAddContentAdapter : RecyclerView.Adapter<PlaylistAddContentAdapter.ViewHolder>() {
var items = mutableListOf<GetAudioContentOrderListItem>()
inner class ViewHolder(
private val context: Context,
private val binding: ItemPlaylistAddContentBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetAudioContentOrderListItem) {
Glide
.with(context)
.load(item.coverImageUrl)
.apply(
RequestOptions().transform(
CenterCrop(),
RoundedCorners(5.3f.dpToPx().toInt())
)
)
.into(binding.ivCover)
binding.tvTitle.text = item.title
binding.tvTheme.text = item.themeStr
binding.tvDuration.text = item.duration
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
parent.context,
ItemPlaylistAddContentBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount() = items.count()
@SuppressLint("NotifyDataSetChanged")
fun clear() {
items.clear()
notifyDataSetChanged()
}
}

View File

@ -0,0 +1,167 @@
package kr.co.vividnext.sodalive.audio_content.playlist.create.add_content
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Rect
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
import kr.co.vividnext.sodalive.audio_content.playlist.create.AudioContentPlaylistCreateActivity
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 : BottomSheetDialogFragment() {
private lateinit var binding: FragmentPlaylistAddContentBinding
private lateinit var adapter: PlaylistAddContentAdapter
private lateinit var loadingDialog: LoadingDialog
private val viewModel: AudioContentOrderListViewModel by inject()
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.setOnShowListener { dialogInterface ->
val d = dialogInterface as BottomSheetDialog
val bottomSheet = d.findViewById<FrameLayout>(
com.google.android.material.R.id.design_bottom_sheet
)
if (bottomSheet != null) {
BottomSheetBehavior.from(bottomSheet).state = BottomSheetBehavior.STATE_EXPANDED
}
bottomSheet?.let {
val behavior = BottomSheetBehavior.from(bottomSheet)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.skipCollapsed = true
it.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
it.requestLayout()
}
}
return dialog
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentPlaylistAddContentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupView()
bindData()
viewModel.getAudioContentOrderList { dismiss() }
}
private fun setupView() {
binding.tvClose.setOnClickListener { dismiss() }
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
adapter = PlaylistAddContentAdapter()
val recyclerView = binding.rvContent
recyclerView.layoutManager = LinearLayoutManager(
requireContext(),
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.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.getAudioContentOrderList {}
}
}
})
recyclerView.adapter = adapter
}
@SuppressLint("SetTextI18n", "NotifyDataSetChanged")
private fun bindData() {
viewModel.toastLiveData.observe(viewLifecycleOwner) {
Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show()
}
viewModel.isLoading.observe(viewLifecycleOwner) {
if (it) {
loadingDialog.show(
(requireActivity() as AudioContentPlaylistCreateActivity).screenWidth,
""
)
} else {
loadingDialog.dismiss()
}
}
viewModel.orderList.observe(viewLifecycleOwner) {
if (viewModel.page == 2) {
adapter.items.clear()
}
adapter.items.addAll(it)
adapter.notifyDataSetChanged()
}
viewModel.totalCount.observe(viewLifecycleOwner) {
binding.tvContentCount.text = "${it}"
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="17dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="새로운 콘텐츠 추가"
android:textColor="@color/color_eeeeee"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="13dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="닫기"
android:textColor="@color/color_eeeeee"
app:layout_constraintBottom_toBottomOf="@+id/tv_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_title" />
<TextView
android:id="@+id/tv_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_marginTop="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="전체"
android:textColor="@color/white"
android:textSize="14.7sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
<TextView
android:id="@+id/tv_content_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_909090"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/tv_all"
app:layout_constraintStart_toEndOf="@+id/tv_all"
app:layout_constraintTop_toTopOf="@+id/tv_all"
tools:text="40개" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_content"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_all" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_cover"
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_theme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:background="@drawable/bg_round_corner_2_6_28312b"
android:fontFamily="@font/gmarket_sans_medium"
android:padding="2.6dp"
android:textColor="@color/color_3bac6a"
android:textSize="10sp"
app:layout_constraintStart_toEndOf="@+id/iv_cover"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="SmallSp"
tools:text="커버곡" />
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:background="@drawable/bg_round_corner_2_6_222222"
android:fontFamily="@font/gmarket_sans_medium"
android:padding="2.6dp"
android:textColor="@color/color_777777"
android:textSize="10sp"
app:layout_constraintBottom_toBottomOf="@+id/tv_theme"
app:layout_constraintStart_toEndOf="@+id/tv_theme"
app:layout_constraintTop_toTopOf="@+id/tv_theme"
tools:ignore="SmallSp"
tools:text="00:30:20" />
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_marginTop="2.6dp"
android:layout_marginEnd="40dp"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:maxLines="2"
android:textColor="@color/color_d2d2d2"
android:textSize="12sp"
app:layout_constraintEnd_toStartOf="@+id/iv_add"
app:layout_constraintStart_toEndOf="@+id/iv_cover"
app:layout_constraintTop_toBottomOf="@+id/tv_theme"
tools:text="안녕하세요 오늘은 커버곡을 들려드릴께요....안녕하세요 오늘은 커버곡을 들려드릴께요...." />
<ImageView
android:id="@+id/iv_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_playlist_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>