라이브 방 상세 보기 추가

This commit is contained in:
klaus 2023-07-30 21:16:16 +09:00
parent 79127801c6
commit 0cbf2abf5e
25 changed files with 1044 additions and 2 deletions

View File

@ -1,10 +1,13 @@
package kr.co.vividnext.sodalive.live
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Path
import retrofit2.http.Query
interface LiveApi {
@ -17,4 +20,11 @@ interface LiveApi {
@Query("size") size: Int,
@Header("Authorization") authHeader: String
): Flowable<ApiResponse<List<GetRoomListResponse>>>
@GET("/live/room/detail/{id}")
fun getRoomDetail(
@Path("id") id: Long,
@Query("timezone") timezone: String,
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetRoomDetailResponse>>
}

View File

@ -26,6 +26,7 @@ import kr.co.vividnext.sodalive.live.now.LiveNowAdapter
import kr.co.vividnext.sodalive.live.recommend.RecommendLiveAdapter
import kr.co.vividnext.sodalive.live.recommend_channel.LiveRecommendChannelAdapter
import kr.co.vividnext.sodalive.live.reservation.LiveReservationAdapter
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
import kr.co.vividnext.sodalive.settings.notification.MemberRole
import org.koin.android.ext.android.inject
import kotlin.math.roundToInt
@ -234,7 +235,22 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
.layoutLiveNow
.rvSudaNow
liveNowAdapter = LiveNowAdapter {}
liveNowAdapter = LiveNowAdapter {
val detailFragment = LiveRoomDetailFragment(
it.roomId,
onClickParticipant = {},
onClickReservation = {},
onClickModify = {},
onClickStart = {},
onClickCancel = {}
)
if (detailFragment.isAdded) return@LiveNowAdapter
detailFragment.show(
requireActivity().supportFragmentManager,
detailFragment.tag
)
}
recyclerView.layoutManager = LinearLayoutManager(
requireContext(),
@ -300,7 +316,22 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
.layoutLiveReservation
.rvSudaReservation
liveReservationAdapter = LiveReservationAdapter(isMain = true) {}
liveReservationAdapter = LiveReservationAdapter(isMain = true) {
val detailFragment = LiveRoomDetailFragment(
it.roomId,
onClickParticipant = {},
onClickReservation = {},
onClickModify = {},
onClickStart = {},
onClickCancel = {}
)
if (detailFragment.isAdded) return@LiveReservationAdapter
detailFragment.show(
requireActivity().supportFragmentManager,
detailFragment.tag
)
}
recyclerView.layoutManager = LinearLayoutManager(
requireContext(),

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.live
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse
import java.util.TimeZone
class LiveRepository(private val api: LiveApi) {
@ -22,4 +24,12 @@ class LiveRepository(private val api: LiveApi) {
authHeader = token
)
}
fun getRoomDetail(roomId: Long, token: String): Single<ApiResponse<GetRoomDetailResponse>> {
return api.getRoomDetail(
roomId,
timezone = TimeZone.getDefault().id,
authHeader = token
)
}
}

View File

@ -0,0 +1,44 @@
package kr.co.vividnext.sodalive.live.room.detail
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
data class GetRoomDetailResponse(
@SerializedName("roomId") val roomId: Long,
@SerializedName("price") val price: Int,
@SerializedName("title") val title: String,
@SerializedName("content") val content: String,
@SerializedName("isPaid") val isPaid: Boolean,
@SerializedName("isPrivateRoom") val isPrivateRoom: Boolean,
@SerializedName("password") val password: Int?,
@SerializedName("tags") val tags: List<String>,
@SerializedName("channelName") val channelName: String?,
@SerializedName("beginDateTime") val beginDateTime: String,
@SerializedName("isNotification") val isNotification: Boolean,
@SerializedName("numberOfParticipants") val numberOfParticipants: Int,
@SerializedName("numberOfParticipantsTotal") val numberOfParticipantsTotal: Int,
@SerializedName("manager") val manager: GetRoomDetailManager,
@SerializedName("participatingUsers") val participatingUsers: List<GetRoomDetailUser>
): Parcelable
@Parcelize
data class GetRoomDetailManager(
@SerializedName("id") val id: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("introduce") val introduce: String,
@SerializedName("youtubeUrl") val youtubeUrl: String?,
@SerializedName("instagramUrl") val instagramUrl: String?,
@SerializedName("websiteUrl") val websiteUrl: String?,
@SerializedName("blogUrl") val blogUrl: String?,
@SerializedName("profileImageUrl") val profileImageUrl: String,
@SerializedName("isCreator") val isCreator: Boolean
) : Parcelable
@Parcelize
data class GetRoomDetailUser(
@SerializedName("id") val id: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("profileImageUrl") val profileImageUrl: String
) : Parcelable

View File

@ -0,0 +1,50 @@
package kr.co.vividnext.sodalive.live.room.detail
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.databinding.ItemLiveRoomDetailUserBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class LiveRoomDetailAdapter(
private val onClick: (GetRoomDetailUser) -> Unit
) : RecyclerView.Adapter<LiveRoomDetailAdapter.ViewHolder>() {
val items = mutableListOf<GetRoomDetailUser>()
inner class ViewHolder(
private val binding: ItemLiveRoomDetailUserBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetRoomDetailUser) {
binding.tvNickname.text = item.nickname
binding.ivProfile.load(item.profileImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(23.4f.dpToPx()))
}
binding.root.setOnClickListener { onClick(item) }
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ViewHolder {
return ViewHolder(
ItemLiveRoomDetailUserBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount() = items.count()
}

View File

@ -0,0 +1,324 @@
package kr.co.vividnext.sodalive.live.room.detail
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.URLUtil
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.Toast
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.CircleCropTransformation
import coil.transform.RoundedCornersTransformation
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.FragmentLiveRoomDetailBinding
import kr.co.vividnext.sodalive.databinding.ItemLiveDetailUserSummaryBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject
class LiveRoomDetailFragment(
private val roomId: Long,
private val onClickParticipant: () -> Unit,
private val onClickReservation: () -> Unit,
private val onClickModify: (GetRoomDetailResponse) -> Unit,
private val onClickStart: () -> Unit,
private val onClickCancel: () -> Unit
) : BottomSheetDialogFragment() {
private val viewModel: LiveRoomDetailViewModel by inject()
private lateinit var binding: FragmentLiveRoomDetailBinding
private var isAllProfileOpen = false
private lateinit var adapter: LiveRoomDetailAdapter
private lateinit var loadingDialog: LoadingDialog
private lateinit var roomDetail: GetRoomDetailResponse
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentLiveRoomDetailBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
val bottomSheet = dialog?.findViewById<FrameLayout>(
com.google.android.material.R.id.design_bottom_sheet
)
val behavior = BottomSheetBehavior.from<View>(bottomSheet!!)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
setupAdapter()
bindData()
viewModel.getDetail(roomId) { dismiss() }
binding.ivClose.setOnClickListener { dismiss() }
binding.tvOpenAllProfile.setOnClickListener {
isAllProfileOpen = !isAllProfileOpen
if (isAllProfileOpen) {
binding.llProfiles.visibility = View.GONE
binding.rvParticipate.visibility = View.VISIBLE
binding.tvParticipateExpression.visibility = View.VISIBLE
binding.tvOpenAllProfile.text = "닫기"
binding.tvOpenAllProfile.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_live_detail_top,
0,
0,
0
)
} else {
binding.llProfiles.visibility = View.VISIBLE
binding.rvParticipate.visibility = View.GONE
binding.tvParticipateExpression.visibility = View.GONE
binding.tvOpenAllProfile.text = "펼쳐보기"
binding.tvOpenAllProfile.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_live_detail_bottom,
0,
0,
0
)
}
}
}
private fun setupAdapter() {
val recyclerView = binding.rvParticipate
adapter = LiveRoomDetailAdapter {}
recyclerView.layoutManager = GridLayoutManager(requireContext(), 5)
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.top = 13.3f.dpToPx().toInt()
outRect.bottom = 13.3f.dpToPx().toInt()
}
})
recyclerView.adapter = adapter
}
private fun bindData() {
viewModel.isLoading.observe(viewLifecycleOwner) {
if (it) {
loadingDialog.show(resources.displayMetrics.widthPixels)
} else {
loadingDialog.dismiss()
}
}
viewModel.toastLiveData.observe(viewLifecycleOwner) {
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
}
viewModel.liveRoomDetailLiveData.observe(viewLifecycleOwner) {
roomDetail = it
setRoomDetail(it)
}
}
@SuppressLint("SetTextI18n", "NotifyDataSetChanged")
private fun setRoomDetail(response: GetRoomDetailResponse) {
binding.tvTitle.text = response.title
binding.tvDate.text = response.beginDateTime
binding.tvParticipate.text = response.numberOfParticipants.toString()
binding.tvTotal.text = "/${response.numberOfParticipantsTotal}"
binding.tvOpenAllProfile.visibility = if (response.numberOfParticipants <= 0) {
View.GONE
} else {
View.VISIBLE
}
if (response.price > 0) {
binding.tvCoin.text = response.price.toString()
binding.tvCoin.setCompoundDrawablesWithIntrinsicBounds(
0,
0,
R.drawable.ic_can,
0
)
} else {
binding.tvCoin.text = "무료"
binding.tvCoin.setCompoundDrawablesWithIntrinsicBounds(
0,
0,
0,
0
)
}
setManagerProfile(manager = response.manager)
setParticipantUserSummary(response.participatingUsers)
binding.tvTags.text = response.tags.joinToString(" ") { "#$it" }
binding.tvContent.text = response.content
if (response.channelName.isNullOrBlank()) {
binding.tvParticipateExpression.text = "예약자"
when {
response.manager.id == SharedPreferenceManager.userId -> {
binding.llStartDelete.visibility = View.VISIBLE
binding.tvReservationComplete.visibility = View.GONE
binding.tvParticipateNow.visibility = View.GONE
binding.tvReservation.visibility = View.GONE
binding.tvModify.setOnClickListener {
onClickModify(roomDetail)
dismiss()
}
binding.tvLiveStart.setOnClickListener {
onClickStart()
dismiss()
}
binding.tvLiveCancel.setOnClickListener {
onClickCancel()
dismiss()
}
}
response.isPaid -> {
binding.tvReservationComplete.visibility = View.VISIBLE
binding.tvParticipateNow.visibility = View.GONE
binding.tvReservation.visibility = View.GONE
binding.llStartDelete.visibility = View.GONE
}
else -> {
binding.tvReservationComplete.visibility = View.GONE
binding.tvParticipateNow.visibility = View.GONE
binding.tvReservation.visibility = View.VISIBLE
binding.tvReservation.setOnClickListener {
onClickReservation()
dismiss()
}
binding.llStartDelete.visibility = View.GONE
}
}
} else {
binding.tvParticipateExpression.text = "참여자"
binding.tvReservationComplete.visibility = View.GONE
binding.tvParticipateNow.visibility = View.VISIBLE
binding.tvReservation.visibility = View.GONE
binding.tvParticipateNow.setOnClickListener {
onClickParticipant()
dismiss()
}
binding.llStartDelete.visibility = View.GONE
}
adapter.items.addAll(response.participatingUsers)
adapter.notifyDataSetChanged()
}
private fun setManagerProfile(manager: GetRoomDetailManager) {
binding.tvManagerNickname.text = manager.nickname
binding.tvManagerIntroduce.text = manager.introduce
binding.ivManagerProfile.load(manager.profileImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(CircleCropTransformation())
}
if (
manager.websiteUrl.isNullOrBlank() ||
!URLUtil.isValidUrl(manager.websiteUrl)
) {
binding.ivManagerWebsite.visibility = View.GONE
} else {
binding.ivManagerWebsite.visibility = View.VISIBLE
binding.ivManagerWebsite.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(manager.websiteUrl)))
}
}
if (
manager.blogUrl.isNullOrBlank() ||
!URLUtil.isValidUrl(manager.blogUrl)
) {
binding.ivManagerBlog.visibility = View.GONE
} else {
binding.ivManagerBlog.visibility = View.VISIBLE
binding.ivManagerBlog.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(manager.blogUrl)))
}
}
if (
manager.instagramUrl.isNullOrBlank() ||
!URLUtil.isValidUrl(manager.instagramUrl)
) {
binding.ivManagerInstagram.visibility = View.GONE
} else {
binding.ivManagerInstagram.visibility = View.VISIBLE
binding.ivManagerInstagram.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(manager.instagramUrl)))
}
}
if (
manager.youtubeUrl.isNullOrBlank() ||
!URLUtil.isValidUrl(manager.youtubeUrl)
) {
binding.ivManagerYoutube.visibility = View.GONE
} else {
binding.ivManagerYoutube.visibility = View.VISIBLE
binding.ivManagerYoutube.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(manager.youtubeUrl)))
}
}
if (manager.isCreator) {
binding.tvManagerProfile.visibility = View.VISIBLE
binding.tvManagerProfile.setOnClickListener {}
} else {
binding.tvManagerProfile.visibility = View.GONE
}
}
private fun setParticipantUserSummary(participatingUsers: List<GetRoomDetailUser>) {
val userCount = if (participatingUsers.size > 10) {
10
} else {
participatingUsers.size
}
for (index in 0 until userCount) {
val user = participatingUsers[index]
val itemView = ItemLiveDetailUserSummaryBinding.inflate(layoutInflater)
itemView.ivProfile.load(user.profileImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(16.7f.dpToPx()))
}
val lp = LinearLayout.LayoutParams(33.3f.dpToPx().toInt(), 33.3f.dpToPx().toInt())
if (index > 0) {
lp.setMargins(-16.7f.dpToPx().toInt(), 0, 0, 0)
}
itemView.root.layoutParams = lp
binding.llProfiles.addView(itemView.root)
}
}
}

View File

@ -0,0 +1,66 @@
package kr.co.vividnext.sodalive.live.room.detail
import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.google.firebase.dynamiclinks.ShortDynamicLink
import com.google.firebase.dynamiclinks.ktx.androidParameters
import com.google.firebase.dynamiclinks.ktx.dynamicLinks
import com.google.firebase.dynamiclinks.ktx.iosParameters
import com.google.firebase.dynamiclinks.ktx.shortLinkAsync
import com.google.firebase.ktx.Firebase
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.live.LiveRepository
class LiveRoomDetailViewModel(private val repository: LiveRepository) : BaseViewModel() {
private val _liveRoomDetailLiveData = MutableLiveData<GetRoomDetailResponse>()
val liveRoomDetailLiveData: MutableLiveData<GetRoomDetailResponse>
get() = _liveRoomDetailLiveData
private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?>
get() = _toastLiveData
private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean>
get() = _isLoading
fun getDetail(roomId: Long, onFailure: () -> Unit) {
if (!_isLoading.value!!) {
_isLoading.value = true
}
compositeDisposable.add(
repository.getRoomDetail(roomId, token = "Bearer ${SharedPreferenceManager.token}")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
_liveRoomDetailLiveData.postValue(it.data!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
onFailure()
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
onFailure()
}
)
)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_525252" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_525252" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_ff5c49" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_ff5c49" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_9970ff" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_9970ff" />
<corners android:radius="16.7dp" />
<stroke
android:width="1dp"
android:color="@color/color_9970ff" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<corners android:radius="5.3dp" />
<stroke
android:width="1dp"
android:color="@color/color_dd4500" />
</shape>

View File

@ -0,0 +1,430 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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"
tools:background="@color/color_222222">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:paddingHorizontal="16.7dp"
android:paddingTop="13.3dp"
android:src="@drawable/ic_close_white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_close">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="6.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp"
tools:text="🧸여자들이 좋아하는 남자 스타일은?" />
<RelativeLayout
android:id="@+id/rl_date_and_coin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="16.7dp">
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_bbbbbb"
android:textSize="12sp"
tools:text="2021.06.20 SUN 10p.m" />
<TextView
android:id="@+id/tv_coin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:drawablePadding="6.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:textColor="@color/color_eeeeee"
android:textSize="15.3sp"
app:drawableEndCompat="@drawable/ic_coin_w"
tools:ignore="RelativeOverlap"
tools:text="300" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@+id/tv_coin"
android:layout_marginTop="8dp"
android:background="@color/color_88909090" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="16.7dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rl_date_and_coin">
<TextView
android:id="@+id/tv_participate_expression"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center_vertical"
android:text="참여자"
android:textColor="@color/color_eeeeee"
android:textSize="12sp"
android:visibility="gone" />
<LinearLayout
android:id="@+id/ll_profiles"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginEnd="23.7dp"
android:layout_toStartOf="@+id/ll_participate"
android:gravity="center_vertical"
android:orientation="horizontal" />
<LinearLayout
android:id="@+id/ll_participate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:gravity="center">
<TextView
android:id="@+id/tv_participate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_9970ff"
android:textSize="12sp"
tools:text="14" />
<TextView
android:id="@+id/tv_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_bbbbbb"
android:textSize="12sp"
tools:text="/20" />
</LinearLayout>
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_participate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="16.7dp"
android:visibility="gone" />
<TextView
android:id="@+id/tv_open_all_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="13.3dp"
android:drawablePadding="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="펼쳐보기"
android:textColor="@color/color_bbbbbb"
android:textSize="12sp"
app:drawableStartCompat="@drawable/ic_live_detail_bottom" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="13.3dp"
android:background="@color/color_88909090" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_111111"
android:paddingHorizontal="13.3dp"
android:paddingVertical="20dp">
<ImageView
android:id="@+id/iv_manager_profile"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerVertical="true"
android:contentDescription="@null"
tools:src="@drawable/ic_launcher_background" />
<LinearLayout
android:id="@+id/ll_manager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_toStartOf="@+id/ll_sns"
android:layout_toEndOf="@+id/iv_manager_profile"
android:orientation="vertical">
<TextView
android:id="@+id/tv_manager_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp"
tools:text="사냥꾼1004" />
<TextView
android:id="@+id/tv_manager_introduce"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:lines="3"
android:textColor="@color/color_777777"
android:textSize="12sp"
tools:text="매주 일요일 밤 12시 사냥꾼의 연애상담소를 오픈합니다. 많은 관심 부탁드립니다~매주 일요일 밤 12시 사냥꾼의 연애상담소를 오픈합니다. 많은 관심 부탁드립니다~" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_sns"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:gravity="end|center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_manager_website"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_website_purple" />
<ImageView
android:id="@+id/iv_manager_blog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:contentDescription="@null"
android:src="@drawable/ic_blog_purple" />
<ImageView
android:id="@+id/iv_manager_instagram"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:contentDescription="@null"
android:src="@drawable/ic_instagram_purple" />
<ImageView
android:id="@+id/iv_manager_youtube"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:contentDescription="@null"
android:src="@drawable/ic_youtube_play_purple" />
</LinearLayout>
<TextView
android:id="@+id/tv_manager_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="21dp"
android:background="@drawable/bg_round_corner_16_7_9970ff"
android:drawablePadding="3.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="8.7dp"
android:paddingVertical="10dp"
android:text="채널보기"
android:textColor="@color/white"
android:textSize="12sp"
app:drawableStartCompat="@drawable/ic_thumb_play" />
</LinearLayout>
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/color_88909090" />
<TextView
android:id="@+id/tv_tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="26.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_9970ff"
android:textSize="13.3sp"
tools:text="#연애 #연애상담 #소개팅 #연애팁 #남자 #여자" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="16.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:lineSpacingExtra="3.3sp"
android:textColor="@color/color_777777"
android:textSize="13.3sp"
tools:text="🎈결정하기 힘든 일이겠지만 황제처럼 자신의 주장을 고수하며 혼자 힘으로 일어서라고 말하고 있네요. 그만큼 능력도 자신감도 있으시네요. 당신만의 카리스마를 발휘해 보세요.❤️\n\n
🔔결정하기 힘든 일이겠지만 황제처럼 자신의 주장을 고수하며 혼자 힘으로 일어서라고 말하고 있네요. 그만큼 능력도 자신감도 있으시네요. 당신만의 카리스마를 발휘해 보세요.👩‍❤️‍💋‍👨" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="40dp"
android:background="@color/color_88909090" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="26.7dp">
<LinearLayout
android:id="@+id/ll_start_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<TextView
android:id="@+id/tv_modify"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_10_transparent_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingHorizontal="27dp"
android:paddingVertical="16dp"
android:text="수정"
android:textColor="@color/white"
android:textSize="18.3sp" />
<TextView
android:id="@+id/tv_live_start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="2"
android:background="@drawable/bg_round_corner_10_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="시작하기"
android:textColor="@color/white"
android:textSize="18.3sp" />
</LinearLayout>
<TextView
android:id="@+id/tv_live_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="16dp"
android:background="@drawable/bg_round_corner_5_3_transparent_dd4500"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:padding="5.3dp"
android:text="예약삭제"
android:textColor="@color/color_ff5c49"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="40dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_reservation_complete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:background="@drawable/bg_round_corner_10_525252"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="예약완료"
android:textColor="@color/color_777777"
android:textSize="18.3sp"
android:visibility="gone" />
<TextView
android:id="@+id/tv_reservation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:background="@drawable/bg_round_corner_10_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="예약하기"
android:textColor="@color/white"
android:textSize="18.3sp"
android:visibility="gone" />
<TextView
android:id="@+id/tv_participate_now"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:background="@drawable/bg_round_corner_10_ff5c49"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="지금 참여하기"
android:textColor="@color/white"
android:textSize="18.3sp"
android:visibility="gone" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/iv_profile"
android:layout_width="33.3dp"
android:layout_height="33.3dp"
android:contentDescription="@null"
tools:src="@mipmap/ic_launcher" />

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="46.7dp"
android:layout_height="46.7dp"
android:contentDescription="@null"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:lines="1"
android:textColor="@color/color_bbbbbb"
android:textSize="12sp"
tools:text="932sld23932sld23" />
</LinearLayout>

View File

@ -33,4 +33,6 @@
<color name="color_339970ff">#339970FF</color>
<color name="color_7fe2e2e2">#7FE2E2E2</color>
<color name="color_4d9970ff">#4D9970FF</color>
<color name="color_525252">#525252</color>
<color name="color_dd4500">#DD4500</color>
</resources>