라이브 메인 - UI, Api 적용

This commit is contained in:
klaus 2023-07-27 06:46:26 +09:00
parent 6f86663a54
commit bad5e6612a
53 changed files with 3709 additions and 8 deletions

View File

@ -98,7 +98,7 @@ dependencies {
}
// Gson
implementation "com.google.code.gson:gson:2.9.0"
implementation "com.google.code.gson:gson:2.9.1"
// Network
implementation "com.squareup.retrofit2:retrofit:2.9.0"
@ -115,6 +115,7 @@ dependencies {
implementation "io.github.ParkSangGwon:tedpermission-normal:3.3.0"
implementation 'com.github.dhaval2404:imagepicker:2.1'
implementation 'com.github.zhpanvip:bannerviewpager:3.5.7'
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1'

View File

@ -10,11 +10,12 @@ object Constants {
const val PREF_USER_ROLE = "pref_user_role"
const val PREF_PUSH_TOKEN = "pref_push_token"
const val PREF_PROFILE_IMAGE = "pref_profile_image"
const val PREF_IS_FOLLOWED_CREATOR_LIVE = "pref_is_followed_creator_live"
const val EXTRA_DATA = "extra_data"
const val EXTRA_TERMS = "extra_terms"
const val EXTRA_USER_ID = "extra_user_id"
const val EXTRA_ROOM_ID = "extra_room_id"
const val EXTRA_USER_ID = "extra_user_id"
const val EXTRA_MESSAGE_ID = "extra_message_id"
const val EXTRA_CONTENT_ID = "extra_content_id"

View File

@ -98,4 +98,10 @@ object SharedPreferenceManager {
set(value) {
sharedPreferences[Constants.PREF_PUSH_TOKEN] = value
}
var isFollowedCreatorLive: Boolean
get() = sharedPreferences[Constants.PREF_IS_FOLLOWED_CREATOR_LIVE, false]
set(value) {
sharedPreferences[Constants.PREF_IS_FOLLOWED_CREATOR_LIVE] = value
}
}

View File

@ -4,8 +4,15 @@ import android.content.Context
import com.google.gson.GsonBuilder
import kr.co.vividnext.sodalive.BuildConfig
import kr.co.vividnext.sodalive.common.ApiBuilder
import kr.co.vividnext.sodalive.live.LiveApi
import kr.co.vividnext.sodalive.live.LiveRepository
import kr.co.vividnext.sodalive.live.LiveViewModel
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendApi
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
import kr.co.vividnext.sodalive.main.MainViewModel
import kr.co.vividnext.sodalive.network.TokenAuthenticator
import kr.co.vividnext.sodalive.settings.event.EventApi
import kr.co.vividnext.sodalive.settings.event.EventRepository
import kr.co.vividnext.sodalive.settings.terms.TermsApi
import kr.co.vividnext.sodalive.settings.terms.TermsRepository
import kr.co.vividnext.sodalive.settings.terms.TermsViewModel
@ -58,6 +65,9 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
single { ApiBuilder().build(get(), UserApi::class.java) }
single { ApiBuilder().build(get(), TermsApi::class.java) }
single { ApiBuilder().build(get(), LiveApi::class.java) }
single { ApiBuilder().build(get(), EventApi::class.java) }
single { ApiBuilder().build(get(), LiveRecommendApi::class.java) }
}
private val viewModelModule = module {
@ -66,11 +76,15 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { TermsViewModel(get()) }
viewModel { FindPasswordViewModel(get()) }
viewModel { MainViewModel(get()) }
viewModel { LiveViewModel(get(), get(), get()) }
}
private val repositoryModule = module {
factory { UserRepository(get()) }
factory { TermsRepository(get()) }
factory { LiveRepository(get()) }
factory { EventRepository(get()) }
factory { LiveRecommendRepository(get()) }
}
private val moduleList = listOf(

View File

@ -0,0 +1,21 @@
package kr.co.vividnext.sodalive.live
import com.google.gson.annotations.SerializedName
data class GetRoomListResponse(
@SerializedName("roomId") val roomId: Long,
@SerializedName("title") val title: String,
@SerializedName("content") val content: String,
@SerializedName("beginDateTime") val beginDateTime: String,
@SerializedName("numberOfParticipate") val numberOfParticipate: Int,
@SerializedName("numberOfPeople") val numberOfPeople: Int,
@SerializedName("coverImageUrl") val coverImageUrl: String,
@SerializedName("isAdult") val isAdult: Boolean,
@SerializedName("price") val price: Int,
@SerializedName("tags") val tags: List<String>,
@SerializedName("channelName") val channelName: String?,
@SerializedName("managerNickname") val managerNickname: String,
@SerializedName("managerId") val managerId: Long,
@SerializedName("isReservation") val isReservation: Boolean,
@SerializedName("isPrivateRoom") val isPrivateRoom: Boolean
)

View File

@ -0,0 +1,20 @@
package kr.co.vividnext.sodalive.live
import io.reactivex.rxjava3.core.Flowable
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query
interface LiveApi {
@GET("/live/room")
fun roomList(
@Query("timezone") timezone: String,
@Query("dateString") dateString: String?,
@Query("status") status: LiveRoomStatus,
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String
): Flowable<ApiResponse<List<GetRoomListResponse>>>
}

View File

@ -1,7 +1,403 @@
package kr.co.vividnext.sodalive.live
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.webkit.URLUtil
import android.widget.LinearLayout
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.zhpan.bannerview.BaseBannerAdapter
import com.zhpan.indicator.enums.IndicatorSlideMode
import com.zhpan.indicator.enums.IndicatorStyle
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseFragment
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.FragmentLiveBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.live.event_banner.EventBannerAdapter
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.settings.notification.MemberRole
import org.koin.android.ext.android.inject
import kotlin.math.roundToInt
class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::inflate) {
private val viewModel: LiveViewModel by inject()
private lateinit var liveNowAdapter: LiveNowAdapter
private lateinit var liveReservationAdapter: LiveReservationAdapter
private lateinit var liveRecommendChannelAdapter: LiveRecommendChannelAdapter
private lateinit var loadingDialog: LoadingDialog
private var message = ""
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupView()
setupRecommendLive()
setupRecommendChannel()
setupLiveNow()
setupLiveReservation()
setupEvent()
message = "라이브를 불러오고 있습니다."
viewModel.getSummary()
}
private fun setupView() {
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
viewModel.toastLiveData.observe(viewLifecycleOwner) {
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
}
viewModel.isLoading.observe(viewLifecycleOwner) {
if (it) {
loadingDialog.show(screenWidth, message)
} else {
loadingDialog.dismiss()
}
}
binding.ivMakeRoom.visibility =
if (SharedPreferenceManager.role == MemberRole.CREATOR.name) {
View.VISIBLE
} else {
View.GONE
}
binding.ivMakeRoom.setOnClickListener {}
binding.swipeRefreshLayout.setOnRefreshListener { refreshSummary() }
val ivHowToUseLp = binding.ivHowToUse.layoutParams as LinearLayout.LayoutParams
ivHowToUseLp.width = screenWidth
ivHowToUseLp.height = (200 * screenWidth) / 1080
binding.ivHowToUse.layoutParams = ivHowToUseLp
binding.ivHowToUse.setOnClickListener {
val url = "https://blog.naver.com/yozmlive"
if (URLUtil.isValidUrl(url)) {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
}
}
}
private fun refreshSummary() {
liveNowAdapter.clear()
liveRecommendChannelAdapter.clear()
liveReservationAdapter.clear()
message = "라이브를 불러오고 있습니다."
viewModel.getSummary()
binding.swipeRefreshLayout.isRefreshing = false
}
@SuppressLint("NotifyDataSetChanged")
private fun setupRecommendLive() {
val layoutParams = binding
.layoutRecommendLive
.pager
.layoutParams as LinearLayout.LayoutParams
val pagerWidth = screenWidth.toDouble() - 26.7f.dpToPx()
val pagerHeight = (pagerWidth * 0.53).roundToInt()
layoutParams.width = pagerWidth.roundToInt()
layoutParams.height = pagerHeight
binding
.layoutRecommendLive
.pager
.layoutParams = layoutParams
binding.layoutRecommendLive.pager.apply {
adapter = RecommendLiveAdapter(pagerWidth.roundToInt(), pagerHeight) {
} as BaseBannerAdapter<Any>
setLifecycleRegistry(lifecycle)
setScrollDuration(1000)
setInterval(4 * 1000)
}.create()
binding
.layoutRecommendLive
.pager
.setIndicatorView(binding.layoutRecommendLive.indicator2)
.setIndicatorStyle(IndicatorStyle.ROUND_RECT)
.setIndicatorSlideMode(IndicatorSlideMode.SMOOTH)
.setIndicatorVisibility(View.GONE)
.setIndicatorSliderColor(
ContextCompat.getColor(requireContext(), R.color.color_909090),
ContextCompat.getColor(requireContext(), R.color.color_9970ff)
)
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
.setIndicatorHeight(4f.dpToPx().toInt())
viewModel.recommendLiveData.observe(viewLifecycleOwner) {
if (it.isNotEmpty()) {
binding.layoutRecommendLive.root.visibility = View.VISIBLE
binding.layoutRecommendLive.pager.refreshData(it)
} else {
binding.layoutRecommendLive.root.visibility = View.GONE
}
}
}
private fun setupRecommendChannel() {
liveRecommendChannelAdapter = LiveRecommendChannelAdapter(
onClick = {},
onClickMore = {}
)
binding.layoutRecommendChannel.rvRecommendChannel.layoutManager = LinearLayoutManager(
requireContext(),
LinearLayoutManager.HORIZONTAL,
false
)
binding
.layoutRecommendChannel
.rvRecommendChannel
.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
when (parent.getChildAdapterPosition(view)) {
0 -> {
outRect.left = 0.dpToPx().toInt()
outRect.right = 8.3f.dpToPx().toInt()
}
liveRecommendChannelAdapter.itemCount - 1 -> {
outRect.left = 8.3f.dpToPx().toInt()
outRect.right = 0.dpToPx().toInt()
}
else -> {
outRect.left = 8.3f.dpToPx().toInt()
outRect.right = 8.3f.dpToPx().toInt()
}
}
}
})
binding.layoutRecommendChannel.rvRecommendChannel.adapter = liveRecommendChannelAdapter
binding.layoutRecommendChannel.ivSwitch.setOnClickListener {
viewModel.toggleIsFollowedCreatorLive()
}
viewModel.recommendChannelLiveData.observe(viewLifecycleOwner) {
binding.layoutRecommendChannel.root.visibility = View.VISIBLE
liveRecommendChannelAdapter.addItems(it)
binding.layoutRecommendChannel.rvRecommendChannel.requestLayout()
binding.layoutRecommendChannel.root.requestLayout()
}
viewModel.isFollowedCreatorLive.observe(viewLifecycleOwner) {
liveRecommendChannelAdapter.isFollowedCreatorLive = it
liveRecommendChannelAdapter.clear()
if (it) {
binding.layoutRecommendChannel.ivSwitch.setImageResource(R.drawable.btn_toggle_on_big)
binding.layoutRecommendChannel.llTitle2.visibility = View.VISIBLE
binding.layoutRecommendChannel.llTitle1.visibility = View.GONE
} else {
binding.layoutRecommendChannel.ivSwitch.setImageResource(R.drawable.btn_toggle_off_big)
binding.layoutRecommendChannel.llTitle1.visibility = View.VISIBLE
binding.layoutRecommendChannel.llTitle2.visibility = View.GONE
}
}
}
@SuppressLint("NotifyDataSetChanged")
private fun setupLiveNow() {
binding
.layoutLiveNow
.tvAllView
.setOnClickListener {}
val recyclerView = binding
.layoutLiveNow
.rvSudaNow
liveNowAdapter = LiveNowAdapter {}
recyclerView.layoutManager = LinearLayoutManager(
requireContext(),
LinearLayoutManager.HORIZONTAL,
false
)
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
when (parent.getChildAdapterPosition(view)) {
0 -> {
outRect.left = 13.3f.dpToPx().toInt()
outRect.right = 5.dpToPx().toInt()
}
liveNowAdapter.itemCount - 1 -> {
outRect.left = 5.dpToPx().toInt()
outRect.right = 13.3f.dpToPx().toInt()
}
else -> {
outRect.left = 5.dpToPx().toInt()
outRect.right = 5.dpToPx().toInt()
}
}
}
})
recyclerView.adapter = liveNowAdapter
viewModel.liveNowLiveData.observe(viewLifecycleOwner) {
if (liveNowAdapter.items.isEmpty() && it.isEmpty()) {
recyclerView.visibility = View.GONE
binding.layoutLiveNow.tvAllView.visibility = View.GONE
binding.layoutLiveNow.llNoItems.visibility = View.VISIBLE
binding.layoutLiveNow.tvMakeRoom.setOnClickListener {}
recyclerView.requestLayout()
binding.layoutLiveNow.llNoItems.requestLayout()
} else {
binding.layoutLiveNow.tvAllView.visibility = View.VISIBLE
binding.layoutLiveNow.llNoItems.visibility = View.GONE
liveNowAdapter.items.addAll(it)
liveNowAdapter.notifyDataSetChanged()
recyclerView.visibility = View.VISIBLE
recyclerView.requestLayout()
}
binding.layoutLiveNow.root.requestLayout()
}
}
@SuppressLint("NotifyDataSetChanged")
private fun setupLiveReservation() {
val recyclerView = binding
.layoutLiveReservation
.rvSudaReservation
liveReservationAdapter = LiveReservationAdapter(isMain = true) {}
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 = 0f.dpToPx().toInt()
outRect.bottom = 6.7f.dpToPx().toInt()
}
liveReservationAdapter.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 = liveReservationAdapter
viewModel.liveReservationLiveData.observe(viewLifecycleOwner) {
if (liveReservationAdapter.items.isEmpty() && it.isEmpty()) {
recyclerView.visibility = View.GONE
binding.layoutLiveReservation.tvAllView.visibility = View.GONE
binding.layoutLiveReservation.llNoItems.visibility = View.VISIBLE
binding.layoutLiveReservation.tvMakeRoom.setOnClickListener {}
recyclerView.requestLayout()
binding.layoutLiveReservation.llNoItems.requestLayout()
} else {
binding.layoutLiveReservation.tvAllView.visibility = View.VISIBLE
binding.layoutLiveReservation.llNoItems.visibility = View.GONE
liveReservationAdapter.items.addAll(it)
liveReservationAdapter.notifyDataSetChanged()
recyclerView.visibility = View.VISIBLE
recyclerView.requestLayout()
}
binding.layoutLiveReservation.root.requestLayout()
}
binding.layoutLiveReservation.tvAllView.setOnClickListener {}
}
@SuppressLint("NotifyDataSetChanged")
private fun setupEvent() {
val imageSliderLp = binding.eventBannerSlider.layoutParams
imageSliderLp.width = screenWidth
imageSliderLp.height = (screenWidth * 300) / 1000
binding.eventBannerSlider.layoutParams = imageSliderLp
binding.eventBannerSlider.apply {
adapter = EventBannerAdapter(requireContext()) {} as BaseBannerAdapter<Any>
setLifecycleRegistry(lifecycle)
setScrollDuration(800)
}.create()
binding.eventBannerSlider
.setIndicatorView(binding.indicator)
.setIndicatorStyle(IndicatorStyle.ROUND_RECT)
.setIndicatorSlideMode(IndicatorSlideMode.SMOOTH)
.setIndicatorVisibility(View.GONE)
.setIndicatorSliderColor(
ContextCompat.getColor(requireContext(), R.color.color_909090),
ContextCompat.getColor(requireContext(), R.color.color_9970ff)
)
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
.setIndicatorHeight(4f.dpToPx().toInt())
viewModel.eventLiveData.observe(viewLifecycleOwner) {
if (it.isNotEmpty()) {
binding.eventBannerSlider.visibility = View.VISIBLE
binding.eventBannerSlider.refreshData(it)
} else {
binding.eventBannerSlider.visibility = View.GONE
}
}
}
}

View File

@ -0,0 +1,25 @@
package kr.co.vividnext.sodalive.live
import io.reactivex.rxjava3.core.Flowable
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
import java.util.TimeZone
class LiveRepository(private val api: LiveApi) {
fun roomList(
dateString: String? = null,
status: LiveRoomStatus,
page: Int,
size: Int,
token: String
): Flowable<ApiResponse<List<GetRoomListResponse>>> {
return api.roomList(
timezone = TimeZone.getDefault().id,
dateString = dateString,
status = status,
page = page - 1,
size = size,
authHeader = token
)
}
}

View File

@ -0,0 +1,13 @@
package kr.co.vividnext.sodalive.live
import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse
import kr.co.vividnext.sodalive.settings.event.GetEventResponse
data class LiveSummary(
@SerializedName("liveNow") val liveNow: ApiResponse<List<GetRoomListResponse>>,
@SerializedName("liveReservation") val liveReservation: ApiResponse<List<GetRoomListResponse>>,
@SerializedName("event") val event: ApiResponse<GetEventResponse>,
@SerializedName("recommendLive") val recommendLive: ApiResponse<List<GetRecommendLiveResponse>>,
)

View File

@ -0,0 +1,241 @@
package kr.co.vividnext.sodalive.live
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Flowable
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.recommend.GetRecommendLiveResponse
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
import kr.co.vividnext.sodalive.live.recommend_channel.GetRecommendChannelResponse
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
import kr.co.vividnext.sodalive.settings.event.EventItem
import kr.co.vividnext.sodalive.settings.event.EventRepository
class LiveViewModel(
private val repository: LiveRepository,
private val eventRepository: EventRepository,
private val liveRecommendRepository: LiveRecommendRepository
) : BaseViewModel() {
private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean>
get() = _isLoading
private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?>
get() = _toastLiveData
private val _recommendLiveData = MutableLiveData<List<GetRecommendLiveResponse>>()
val recommendLiveData: LiveData<List<GetRecommendLiveResponse>>
get() = _recommendLiveData
private val _isFollowedCreatorLive = MutableLiveData(
SharedPreferenceManager.isFollowedCreatorLive
)
val isFollowedCreatorLive: LiveData<Boolean>
get() = _isFollowedCreatorLive
private val _recommendChannelLiveData = MutableLiveData<List<GetRecommendChannelResponse>>()
val recommendChannelLiveData: LiveData<List<GetRecommendChannelResponse>>
get() = _recommendChannelLiveData
private val _liveNowLiveData = MutableLiveData<List<GetRoomListResponse>>()
val liveNowLiveData: LiveData<List<GetRoomListResponse>>
get() = _liveNowLiveData
private val _liveReservationLiveData = MutableLiveData<List<GetRoomListResponse>>()
val liveReservationLiveData: LiveData<List<GetRoomListResponse>>
get() = _liveReservationLiveData
private val _eventLiveData = MutableLiveData<List<EventItem>>()
val eventLiveData: LiveData<List<EventItem>>
get() = _eventLiveData
var page = 1
var isLast = false
private val pageSize = 10
fun toggleIsFollowedCreatorLive() {
val isOn = !_isFollowedCreatorLive.value!!
SharedPreferenceManager.isFollowedCreatorLive = isOn
_isFollowedCreatorLive.value = isOn
if (_isFollowedCreatorLive.value!!) {
getFollowedChannelList()
} else {
getRecommendChannelList()
}
}
private fun getFollowedChannelList() {
compositeDisposable.add(
liveRecommendRepository.getFollowingChannelList(
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
_recommendChannelLiveData.postValue(it.data!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
private fun getRecommendChannelList() {
compositeDisposable.add(
liveRecommendRepository.getRecommendChannelList(
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
_recommendChannelLiveData.postValue(it.data!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun getSummary() {
if (!_isLoading.value!!) {
if (_isFollowedCreatorLive.value!!) {
getFollowedChannelList()
} else {
getRecommendChannelList()
}
val liveNow = repository.roomList(
status = LiveRoomStatus.NOW,
page = 1,
size = pageSize,
token = "Bearer ${SharedPreferenceManager.token}"
)
val liveReservation = repository.roomList(
status = LiveRoomStatus.RESERVATION,
page = 1,
size = pageSize,
token = "Bearer ${SharedPreferenceManager.token}"
)
val event = eventRepository.getEvents(
0,
5,
token = "Bearer ${SharedPreferenceManager.token}"
)
val recommendLive = liveRecommendRepository.getRecommendLive(
token = "Bearer ${SharedPreferenceManager.token}"
)
_isLoading.postValue(true)
compositeDisposable.add(
Flowable.combineLatest(
liveNow,
liveReservation,
event,
recommendLive,
) { t1, t2, t3, t4 -> LiveSummary(t1, t2, t3, t4) }
.subscribe(
{
val now = it.liveNow
if (now.success && now.data != null) {
_liveNowLiveData.postValue(now.data!!)
if (now.data.isNotEmpty()) {
page += 1
} else {
isLast = true
}
} else {
if (now.message != null) {
_toastLiveData.postValue(now.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
val reservation = it.liveReservation
if (reservation.success && reservation.data != null) {
_liveReservationLiveData.postValue(reservation.data!!)
if (reservation.data.isNotEmpty()) {
page += 1
} else {
isLast = true
}
} else {
if (reservation.message != null) {
_toastLiveData.postValue(reservation.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
val eventResponse = it.event
if (eventResponse.success && eventResponse.data != null) {
val data = eventResponse.data
_eventLiveData.postValue(data.eventList)
} else {
_eventLiveData.postValue(emptyList())
}
val recommendLiveResponse = it.recommendLive
if (
recommendLiveResponse.success &&
recommendLiveResponse.data != null
) {
val data = recommendLiveResponse.data
_recommendLiveData.postValue(data!!)
} else {
_recommendLiveData.postValue(emptyList())
}
_isLoading.postValue(false)
},
{
_isLoading.postValue(false)
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
}
}

View File

@ -0,0 +1,38 @@
package kr.co.vividnext.sodalive.live.event_banner
import android.content.Context
import android.widget.ImageView
import coil.load
import com.zhpan.bannerview.BaseBannerAdapter
import com.zhpan.bannerview.BaseViewHolder
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.settings.event.EventItem
class EventBannerAdapter(
private val context: Context,
private val itemClick: (EventItem) -> Unit
) : BaseBannerAdapter<EventItem>() {
override fun bindData(
holder: BaseViewHolder<EventItem>,
data: EventItem,
position: Int,
pageSize: Int
) {
val ivThumbnail = holder.findViewById<ImageView>(R.id.iv_thumbnail)
ivThumbnail.load(data.thumbnailImageUrl) {
crossfade(true)
val layoutParams = ivThumbnail.layoutParams
val screenWidth = context.resources.displayMetrics.widthPixels
layoutParams.width = screenWidth
layoutParams.height = (screenWidth * 300) / 1000
ivThumbnail.layoutParams = layoutParams
}
ivThumbnail.setOnClickListener { itemClick(data) }
}
override fun getLayoutId(viewType: Int): Int {
return R.layout.item_event_slider
}
}

View File

@ -0,0 +1,76 @@
package kr.co.vividnext.sodalive.live.now
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
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.ItemLiveNowBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.live.GetRoomListResponse
class LiveNowAdapter(
private val onClick: (GetRoomListResponse) -> Unit
) : RecyclerView.Adapter<LiveNowAdapter.ViewHolder>() {
var items = mutableListOf<GetRoomListResponse>()
inner class ViewHolder(
private val binding: ItemLiveNowBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetRoomListResponse) {
binding.ivCover.load(item.coverImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
}
binding.tvManager.text = item.managerNickname
binding.tvNumberOfMembers.text = "${item.numberOfParticipate}"
binding.ivLock.visibility = if (item.isPrivateRoom) {
View.VISIBLE
} else {
View.GONE
}
if (item.price > 0) {
binding.tvPrice.text = "유료"
binding.tvPrice.setBackgroundResource(R.drawable.bg_round_corner_10_881609)
} else {
binding.tvPrice.text = "무료"
binding.tvPrice.setBackgroundResource(R.drawable.bg_round_corner_10_643bc8)
}
binding.iv19.visibility = if (item.isAdult) {
View.VISIBLE
} else {
View.GONE
}
binding.root.setOnClickListener { onClick(item) }
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
ItemLiveNowBinding.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,10 @@
package kr.co.vividnext.sodalive.live.recommend
import com.google.gson.annotations.SerializedName
data class GetRecommendLiveResponse(
@SerializedName("imageUrl")
val imageUrl: String,
@SerializedName("creatorId")
val creatorId: Long
)

View File

@ -0,0 +1,25 @@
package kr.co.vividnext.sodalive.live.recommend
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.recommend_channel.GetRecommendChannelResponse
import retrofit2.http.GET
import retrofit2.http.Header
interface LiveRecommendApi {
@GET("/live/recommend")
fun getRecommendLive(
@Header("Authorization") authHeader: String
): Flowable<ApiResponse<List<GetRecommendLiveResponse>>>
@GET("/live/recommend/channel")
fun getRecommendChannelList(
@Header("Authorization") authHeader: String
): Flowable<ApiResponse<List<GetRecommendChannelResponse>>>
@GET("/live/following/channel")
fun getFollowingChannelList(
@Header("Authorization") authHeader: String
): Single<ApiResponse<List<GetRecommendChannelResponse>>>
}

View File

@ -0,0 +1,7 @@
package kr.co.vividnext.sodalive.live.recommend
class LiveRecommendRepository(private val api: LiveRecommendApi) {
fun getRecommendLive(token: String) = api.getRecommendLive(authHeader = token)
fun getRecommendChannelList(token: String) = api.getRecommendChannelList(authHeader = token)
fun getFollowingChannelList(token: String) = api.getFollowingChannelList(authHeader = token)
}

View File

@ -0,0 +1,41 @@
package kr.co.vividnext.sodalive.live.recommend
import android.widget.FrameLayout
import android.widget.ImageView
import coil.load
import coil.transform.RoundedCornersTransformation
import com.zhpan.bannerview.BaseBannerAdapter
import com.zhpan.bannerview.BaseViewHolder
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.extensions.dpToPx
class RecommendLiveAdapter(
private val itemWidth: Int,
private val itemHeight: Int,
private val onClick: (Long) -> Unit
) : BaseBannerAdapter<GetRecommendLiveResponse>() {
override fun bindData(
holder: BaseViewHolder<GetRecommendLiveResponse>,
data: GetRecommendLiveResponse,
position: Int,
pageSize: Int
) {
val ivRecommendLive = holder.findViewById<ImageView>(R.id.iv_recommend_live)
val layoutParams = ivRecommendLive.layoutParams as FrameLayout.LayoutParams
layoutParams.width = itemWidth
layoutParams.height = itemHeight
ivRecommendLive.load(data.imageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(5.3f.dpToPx()))
}
ivRecommendLive.layoutParams = layoutParams
ivRecommendLive.setOnClickListener { onClick(data.creatorId) }
}
override fun getLayoutId(viewType: Int): Int {
return R.layout.item_recommend_live
}
}

View File

@ -0,0 +1,14 @@
package kr.co.vividnext.sodalive.live.recommend_channel
import com.google.gson.annotations.SerializedName
data class GetRecommendChannelResponse(
@SerializedName("creatorId")
val creatorId: Long,
@SerializedName("nickname")
val nickname: String,
@SerializedName("profileImageUrl")
val profileImageUrl: String,
@SerializedName("isOnAir")
val isOnAir: Boolean
)

View File

@ -0,0 +1,142 @@
package kr.co.vividnext.sodalive.live.recommend_channel
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemRecommendChannelBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class LiveRecommendChannelAdapter(
private val onClick: (Long) -> Unit,
private val onClickMore: () -> Unit,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var isFollowedCreatorLive = false
private val items = mutableListOf<GetRecommendChannelResponse>()
class FooterViewHolder(
private val binding: ItemRecommendChannelBinding,
private val onClickItem: () -> Unit
) : RecyclerView.ViewHolder(binding.root) {
fun bind() {
binding.ivRecommendChannel.setImageResource(R.drawable.btn_item_more)
binding.tvRecommendChannelNickname.text = "더보기"
val layoutParams = binding.ivRecommendChannel.layoutParams as FrameLayout.LayoutParams
layoutParams.width = 60f.dpToPx().toInt()
layoutParams.height = 60f.dpToPx().toInt()
binding.ivRecommendChannel.layoutParams = layoutParams
binding.ivRecommendChannelBg.layoutParams = layoutParams
binding.tvRecommendChannel.visibility = View.GONE
binding.ivRecommendChannelBg.visibility = View.GONE
binding.root.setOnClickListener { onClickItem() }
}
companion object {
const val VIEW_TYPE = 1
}
}
class ViewHolder(
private val binding: ItemRecommendChannelBinding,
private val onClickItem: (Long) -> Unit
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetRecommendChannelResponse) {
binding.ivRecommendChannel.load(item.profileImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(30f.dpToPx()))
}
binding.tvRecommendChannelNickname.text = item.nickname
val layoutParams = binding.ivRecommendChannel.layoutParams as FrameLayout.LayoutParams
layoutParams.width = 60f.dpToPx().toInt()
layoutParams.height = 60f.dpToPx().toInt()
binding.ivRecommendChannel.layoutParams = layoutParams
binding.ivRecommendChannelBg.layoutParams = layoutParams
if (item.isOnAir) {
binding.tvRecommendChannel.visibility = View.VISIBLE
binding.ivRecommendChannelBg.visibility = View.VISIBLE
} else {
binding.tvRecommendChannel.visibility = View.GONE
binding.ivRecommendChannelBg.visibility = View.GONE
}
binding.root.setOnClickListener { onClickItem(item.creatorId) }
}
companion object {
const val VIEW_TYPE = 0
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == FooterViewHolder.VIEW_TYPE) {
FooterViewHolder(
ItemRecommendChannelBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
),
onClickItem = onClickMore
)
} else {
ViewHolder(
ItemRecommendChannelBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
),
onClickItem = onClick
)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is FooterViewHolder) {
holder.bind()
} else {
(holder as ViewHolder).bind(items[position])
}
}
override fun getItemCount(): Int {
return if (isFollowedCreatorLive) {
items.size + 1
} else {
items.size
}
}
override fun getItemViewType(position: Int): Int {
return if (position == items.size) {
FooterViewHolder.VIEW_TYPE
} else {
ViewHolder.VIEW_TYPE
}
}
@SuppressLint("NotifyDataSetChanged")
fun clear() {
items.clear()
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun addItems(items: List<GetRecommendChannelResponse>) {
this.items.addAll(items)
notifyDataSetChanged()
}
}

View File

@ -0,0 +1,146 @@
package kr.co.vividnext.sodalive.live.reservation
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
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.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ItemLiveReservationBinding
import kr.co.vividnext.sodalive.databinding.ItemMyLiveReservationBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat
import kr.co.vividnext.sodalive.live.GetRoomListResponse
class LiveReservationAdapter(
private val isMain: Boolean = false,
private val onClick: (GetRoomListResponse) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var items = mutableListOf<GetRoomListResponse>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == 1) {
MyLiveViewHolder(
ItemMyLiveReservationBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
} else {
ViewHolder(
ItemLiveReservationBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = items[position]
if (isMyLive(item)) {
(holder as MyLiveViewHolder).bind(item, position)
} else {
(holder as ViewHolder).bind(item)
}
}
override fun getItemCount() = items.count()
override fun getItemViewType(position: Int): Int {
return if (isMyLive(items[position])) {
1
} else {
0
}
}
private fun isMyLive(item: GetRoomListResponse) =
item.managerId == SharedPreferenceManager.userId && isMain
@SuppressLint("NotifyDataSetChanged")
fun clear() {
items.clear()
notifyDataSetChanged()
}
inner class ViewHolder(
private val binding: ItemLiveReservationBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetRoomListResponse) {
binding.ivCover.load(item.coverImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
}
binding.tvDate.text = item.beginDateTime
binding.tvNickname.text = item.managerNickname
binding.tvTitle.text = item.title
binding.root.setOnClickListener { onClick(item) }
binding.ivLock.visibility = if (item.isPrivateRoom) {
View.VISIBLE
} else {
View.GONE
}
if (item.isReservation) {
binding.tvPrice.visibility = View.GONE
binding.tvCompleteReservation.visibility = View.VISIBLE
} else {
binding.tvPrice.visibility = View.VISIBLE
binding.tvCompleteReservation.visibility = View.GONE
binding.tvPrice.text = if (item.price <= 0) {
"무료"
} else {
"${item.price.moneyFormat()}코인"
}
}
binding.iv19.visibility = if (item.isAdult) {
View.VISIBLE
} else {
View.GONE
}
}
}
inner class MyLiveViewHolder(
private val binding: ItemMyLiveReservationBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetRoomListResponse, position: Int) {
binding.tvMyLive.visibility = if (position == 0) {
View.VISIBLE
} else {
View.GONE
}
binding.ivCover.load(item.coverImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(4f.dpToPx()))
}
binding.tvDate.text = item.beginDateTime
binding.tvNickname.text = item.managerNickname
binding.tvTitle.text = item.title
binding.root.setOnClickListener { onClick(item) }
binding.ivLock.visibility = if (item.isPrivateRoom) {
View.VISIBLE
} else {
View.GONE
}
binding.iv19.visibility = if (item.isAdult) {
View.VISIBLE
} else {
View.GONE
}
}
}
}

View File

@ -0,0 +1,8 @@
package kr.co.vividnext.sodalive.live.room
import com.google.gson.annotations.SerializedName
enum class LiveRoomStatus {
@SerializedName("NOW") NOW,
@SerializedName("RESERVATION") RESERVATION
}

View File

@ -0,0 +1,20 @@
package kr.co.vividnext.sodalive.settings.event
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.common.ApiResponse
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query
interface EventApi {
@GET("/event")
fun getEvents(
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String
): Flowable<ApiResponse<GetEventResponse>>
@GET("/event/popup")
fun getEventPopup(@Header("Authorization") authHeader: String): Single<ApiResponse<EventItem>>
}

View File

@ -0,0 +1,11 @@
package kr.co.vividnext.sodalive.settings.event
class EventRepository(private val api: EventApi) {
fun getEvents(
page: Int,
size: Int,
token: String
) = api.getEvents(page, size, authHeader = token)
fun getEventPopup(token: String) = api.getEventPopup(authHeader = token)
}

View File

@ -0,0 +1,19 @@
package kr.co.vividnext.sodalive.settings.event
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
data class GetEventResponse(
@SerializedName("totalCount") val totalCount: Int,
@SerializedName("eventList") val eventList: List<EventItem>
)
@Parcelize
data class EventItem(
@SerializedName("id") val id: Long,
@SerializedName("thumbnailImageUrl") val thumbnailImageUrl: String,
@SerializedName("detailImageUrl") val detailImageUrl: String? = null,
@SerializedName("popupImageUrl") val popupImageUrl: String? = null,
@SerializedName("link") val link: String? = null
) : Parcelable

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

File diff suppressed because it is too large Load Diff

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_533d89" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_533d89" />
</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_643bc8" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_643bc8" />
</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_881609" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_881609" />
</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="33.3dp" />
<stroke
android:width="3dp"
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_2b2635" />
<corners android:radius="4.7dp" />
<stroke
android:width="1dp"
android:color="@color/color_2b2635" />
</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="4.7dp" />
<stroke
android:width="1dp"
android:color="@color/color_9970ff" />
</shape>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:type="linear"
android:startColor="#cc000000"
android:endColor="#19000000"
android:angle="90" />
</shape>

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -4,13 +4,83 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/layout_recommend_live"
layout="@layout/layout_recommend_live"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp" />
<ImageView
android:id="@+id/iv_how_to_use"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21.3dp"
android:contentDescription="@null"
android:src="@drawable/img_how_to_use" />
<include
android:id="@+id/layout_recommend_channel"
layout="@layout/layout_live_recommend_channel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="40dp" />
<include
android:id="@+id/layout_live_now"
layout="@layout/layout_live_now"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp" />
<com.zhpan.bannerview.BannerViewPager
android:id="@+id/event_banner_slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp" />
<com.zhpan.indicator.IndicatorView
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="6.7dp" />
<include
android:id="@+id/layout_live_reservation"
layout="@layout/layout_live_reservation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ImageView
android:id="@+id/iv_make_room"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16.7dp"
android:layout_marginBottom="16.7dp"
android:contentDescription="@null"
android:src="@drawable/btn_make_live"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:text="라이브"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:scaleType="centerCrop" />
</FrameLayout>

View File

@ -0,0 +1,97 @@
<?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="133.3dp"
android:layout_height="176.7dp"
android:background="@color/black">
<ImageView
android:id="@+id/iv_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:scaleType="centerCrop"
tools:src="@drawable/ic_launcher_background" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="@drawable/gradient_live_room_item"
/>
<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3.3dp"
android:layout_marginTop="3.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="7.3dp"
android:paddingVertical="4dp"
android:textColor="@color/white"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:background="@drawable/bg_round_corner_10_881609"
tools:text="유료" />
<ImageView
android:id="@+id/iv_19"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3.3dp"
android:layout_marginEnd="3.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_19"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3.3dp"
android:layout_marginEnd="3.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_lock"
android:visibility="gone"
app:layout_constraintEnd_toStartOf="@+id/iv_19"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_number_of_members"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:layout_marginBottom="6.7dp"
android:gravity="center_vertical|start"
android:textColor="@color/white"
android:textSize="13.3sp"
app:drawableStartCompat="@drawable/ic_avatar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_manager"
app:layout_constraintStart_toStartOf="parent"
tools:text="12" />
<TextView
android:id="@+id/tv_manager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:layout_marginBottom="6.7dp"
android:ellipsize="end"
android:ems="4"
android:gravity="end"
android:maxLines="1"
android:textColor="@color/white"
android:textSize="13.3sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="자입니다sss" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,127 @@
<?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="131dp"
tools:background="@color/black">
<ImageView
android:id="@+id/iv_cover"
android:layout_width="80dp"
android:layout_height="116.7dp"
android:contentDescription="@null"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_19"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3.3dp"
android:layout_marginTop="3.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_19"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/ll_room_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="13.3dp"
android:orientation="vertical"
app:layout_constraintEnd_toStartOf="@+id/iv_lock"
app:layout_constraintStart_toEndOf="@+id/iv_cover"
app:layout_constraintTop_toTopOf="@+id/iv_cover"
app:layout_goneMarginEnd="20dp">
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_ffd300"
android:textSize="9.3sp"
tools:ignore="SmallSp"
tools:text="2021.06.20 SUN 10:00 PM" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp"
tools:text="사냥꾼 1004" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:maxLines="2"
android:textColor="@color/color_e2e2e2"
android:textSize="15.3sp"
tools:text="여자들이 좋아하는 남자 스타일은?" />
</LinearLayout>
<ImageView
android:id="@+id/iv_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="13.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_lock"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_cover" />
<LinearLayout
android:id="@+id/ll_price"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:gravity="start|center_vertical"
app:layout_constraintBottom_toBottomOf="@+id/iv_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_cover">
<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_7fe2e2e2"
android:textSize="12sp"
tools:text="300코인" />
<TextView
android:id="@+id/tv_complete_reservation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_round_corner_10_533d89"
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="7.5dp"
android:paddingVertical="4.3dp"
android:text="예약완료"
android:textColor="@color/color_d2d2d2"
android:textSize="11.3sp"
android:visibility="gone" />
</LinearLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/color_88909090"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:background="@color/black">
<TextView
android:id="@+id/tv_my_live"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:drawablePadding="8dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="내가 개설한 라이브"
android:textColor="@color/color_9970ff"
android:textSize="16sp"
app:drawableStartCompat="@drawable/ic_mic_colored" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_round_corner_8_transparent_9970ff"
android:orientation="horizontal"
android:padding="1dp">
<FrameLayout
android:id="@+id/ll_cover"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_cover"
android:layout_width="80dp"
android:layout_height="116.7dp"
android:contentDescription="@null"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_19"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3.3dp"
android:layout_marginTop="3.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_19"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="30dp"
android:layout_toStartOf="@+id/iv_lock"
android:layout_toEndOf="@+id/ll_cover"
android:orientation="vertical">
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_ffd300"
android:textSize="9.3sp"
tools:ignore="SmallSp"
tools:text="2021.06.20 SUN 10:00 PM" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="4dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp"
tools:text="사냥꾼 1004" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:maxLines="2"
android:textColor="@color/color_e2e2e2"
android:textSize="15.3sp"
tools:text="여자들이 좋아하는 남자 스타일은?" />
</LinearLayout>
<ImageView
android:id="@+id/iv_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginTop="13.3dp"
android:layout_marginEnd="13.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_lock"
android:visibility="gone" />
</RelativeLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="13dp"
android:background="@color/color_88909090" />
</LinearLayout>

View File

@ -0,0 +1,53 @@
<?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="60dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:layout_width="60dp"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_recommend_channel"
android:layout_width="60dp"
android:layout_height="60dp"
android:contentDescription="@null" />
<ImageView
android:id="@+id/iv_recommend_channel_bg"
android:layout_width="60dp"
android:layout_height="60dp"
android:contentDescription="@null"
android:src="@drawable/bg_round_corner_33_3_transparent_9970ff" />
<TextView
android:id="@+id/tv_recommend_channel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:background="@drawable/bg_round_corner_6_7_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:paddingHorizontal="5.7dp"
android:paddingVertical="2.7dp"
android:text="LIVE"
android:textColor="@color/white"
android:textSize="8.7sp"
tools:ignore="SmallSp" />
</FrameLayout>
<TextView
android:id="@+id/tv_recommend_channel_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="11.3dp"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:lines="1"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp"
tools:text="검은사신" />
</LinearLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_recommend_live"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:scaleType="centerCrop" />
</FrameLayout>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="13.3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="지금 "
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="라이브중"
android:textColor="@color/color_ff5c49"
android:textSize="18.3sp" />
</LinearLayout>
<TextView
android:id="@+id/tv_all_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_light"
android:text="전체보기"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_suda_now"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="28.3dp"
android:visibility="gone" />
<LinearLayout
android:id="@+id/ll_no_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="28.3dp"
android:background="@drawable/bg_round_corner_4_7_2b2635"
android:gravity="center"
android:orientation="vertical"
android:paddingVertical="16.7dp"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_no_item" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="🙀지금 참여가능한 라이브가 없습니다.\n직접 라이브를 만들어 보세요!"
android:textColor="@color/color_bbbbbb"
android:textSize="10.7sp"
tools:ignore="SmallSp" />
<TextView
android:id="@+id/tv_make_room"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_round_corner_4_7_9970ff"
android:drawablePadding="8.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingHorizontal="51.7dp"
android:paddingVertical="8.3dp"
android:text="라이브 만들기"
android:textColor="@color/white"
android:textSize="13.3sp"
app:drawableStartCompat="@drawable/ic_plus_no_bg" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/ll_title_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"
android:layout_centerVertical="true"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="추천 "
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="채널"
android:textColor="@color/color_9970ff"
android:textSize="18.3sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_title_2"
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="팔로잉 "
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="채널"
android:textColor="@color/color_9970ff"
android:textSize="18.3sp" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="6.7dp"
android:layout_toStartOf="@+id/iv_switch"
android:fontFamily="@font/gmarket_sans_medium"
android:text="팔로잉 채널"
android:textColor="@color/color_777777"
android:textSize="13.3sp" />
<ImageView
android:id="@+id/iv_switch"
android:layout_width="33.3dp"
android:layout_height="20dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/btn_toggle_off_big" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_recommend_channel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21.3dp" />
</LinearLayout>

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="13.3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="지금 "
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="예약중"
android:textColor="@color/color_9970ff"
android:textSize="18.3sp" />
</LinearLayout>
<TextView
android:id="@+id/tv_all_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_light"
android:text="전체보기"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_suda_reservation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="28.3dp"
android:nestedScrollingEnabled="false"
android:visibility="gone" />
<LinearLayout
android:id="@+id/ll_no_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginVertical="28.3dp"
android:background="@drawable/bg_round_corner_4_7_2b2635"
android:gravity="center"
android:orientation="vertical"
android:paddingVertical="16.7dp"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_no_item" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="지금 예약중인 라이브가 없습니다.\n직접 라이브를 만들어 보세요!"
android:textColor="@color/color_bbbbbb"
android:textSize="10.7sp"
tools:ignore="SmallSp" />
<TextView
android:id="@+id/tv_make_room"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_round_corner_4_7_9970ff"
android:drawablePadding="8.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingHorizontal="51.7dp"
android:paddingVertical="8.3dp"
android:text="라이브 만들기"
android:textColor="@color/white"
android:textSize="13.3sp"
app:drawableStartCompat="@drawable/ic_plus_no_bg" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="추천 "
android:textColor="@color/color_ff5c49"
android:textSize="18.3sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="라이브"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
</LinearLayout>
<com.zhpan.bannerview.BannerViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="26.7dp" />
<com.zhpan.indicator.IndicatorView
android:id="@+id/indicator2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="6.7dp" />
</LinearLayout>

View File

@ -13,8 +13,17 @@
<color name="color_a0e2ff">#A0E2FF</color>
<color name="color_ecfaff">#ECFAFF</color>
<color name="color_111111">#111111</color>
<color name="color_ff5c49">#FF5C49</color>
<color name="color_2b2635">#2b2635</color>
<color name="color_ffd300">#FFD300</color>
<color name="color_e2e2e2">#E2E2E2</color>
<color name="color_d2d2d2">#D2D2D2</color>
<color name="color_533d89">#533D89</color>
<color name="color_643bc8">#643BC8</color>
<color name="color_881609">#881609</color>
<color name="color_b3909090">#B3909090</color>
<color name="color_88909090">#88909090</color>
<color name="color_339970ff">#339970FF</color>
<color name="color_7fe2e2e2">#7FE2E2E2</color>
</resources>