feat: 메인 홈
- 라이브 UI 추가
@@ -207,4 +207,6 @@ dependencies {
 | 
				
			|||||||
    implementation "com.kakao.sdk:v2-common:2.21.0"
 | 
					    implementation "com.kakao.sdk:v2-common:2.21.0"
 | 
				
			||||||
    implementation "com.kakao.sdk:v2-auth:2.21.0"
 | 
					    implementation "com.kakao.sdk:v2-auth:2.21.0"
 | 
				
			||||||
    implementation "com.kakao.sdk:v2-user:2.21.0"
 | 
					    implementation "com.kakao.sdk:v2-user:2.21.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    implementation 'io.github.glailton.expandabletextview:expandabletextview:1.0.4'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,6 +81,9 @@ import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllVi
 | 
				
			|||||||
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListViewModel
 | 
					import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListViewModel
 | 
				
			||||||
import kr.co.vividnext.sodalive.following.FollowingCreatorRepository
 | 
					import kr.co.vividnext.sodalive.following.FollowingCreatorRepository
 | 
				
			||||||
import kr.co.vividnext.sodalive.following.FollowingCreatorViewModel
 | 
					import kr.co.vividnext.sodalive.following.FollowingCreatorViewModel
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.home.HomeApi
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.home.HomeRepository
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.home.HomeViewModel
 | 
				
			||||||
import kr.co.vividnext.sodalive.live.LiveApi
 | 
					import kr.co.vividnext.sodalive.live.LiveApi
 | 
				
			||||||
import kr.co.vividnext.sodalive.live.LiveRepository
 | 
					import kr.co.vividnext.sodalive.live.LiveRepository
 | 
				
			||||||
import kr.co.vividnext.sodalive.live.LiveViewModel
 | 
					import kr.co.vividnext.sodalive.live.LiveViewModel
 | 
				
			||||||
@@ -240,6 +243,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
				
			|||||||
        single { ApiBuilder().build(get(), AdTrackingApi::class.java) }
 | 
					        single { ApiBuilder().build(get(), AdTrackingApi::class.java) }
 | 
				
			||||||
        single { ApiBuilder().build(get(), SearchApi::class.java) }
 | 
					        single { ApiBuilder().build(get(), SearchApi::class.java) }
 | 
				
			||||||
        single { ApiBuilder().build(get(), PointStatusApi::class.java) }
 | 
					        single { ApiBuilder().build(get(), PointStatusApi::class.java) }
 | 
				
			||||||
 | 
					        single { ApiBuilder().build(get(), HomeApi::class.java) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val viewModelModule = module {
 | 
					    private val viewModelModule = module {
 | 
				
			||||||
@@ -336,6 +340,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
				
			|||||||
        viewModel { AlarmContentAllViewModel(get()) }
 | 
					        viewModel { AlarmContentAllViewModel(get()) }
 | 
				
			||||||
        viewModel { SearchViewModel(get()) }
 | 
					        viewModel { SearchViewModel(get()) }
 | 
				
			||||||
        viewModel { PointStatusViewModel(get()) }
 | 
					        viewModel { PointStatusViewModel(get()) }
 | 
				
			||||||
 | 
					        viewModel { HomeViewModel(get()) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val repositoryModule = module {
 | 
					    private val repositoryModule = module {
 | 
				
			||||||
@@ -379,6 +384,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
				
			|||||||
        factory { SearchRepository(get()) }
 | 
					        factory { SearchRepository(get()) }
 | 
				
			||||||
        factory { UserEventRepository(get()) }
 | 
					        factory { UserEventRepository(get()) }
 | 
				
			||||||
        factory { PointStatusRepository(get()) }
 | 
					        factory { PointStatusRepository(get()) }
 | 
				
			||||||
 | 
					        factory { HomeRepository(get()) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val moduleList = listOf(
 | 
					    private val moduleList = listOf(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.annotation.Keep
 | 
				
			||||||
 | 
					import com.google.gson.annotations.SerializedName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Keep
 | 
				
			||||||
 | 
					data class AudioContentMainItem(
 | 
				
			||||||
 | 
					    @SerializedName("contentId") val contentId: Long,
 | 
				
			||||||
 | 
					    @SerializedName("creatorId") val creatorId: Long,
 | 
				
			||||||
 | 
					    @SerializedName("title") val title: String,
 | 
				
			||||||
 | 
					    @SerializedName("coverImageUrl") val coverImageUrl: String,
 | 
				
			||||||
 | 
					    @SerializedName("creatorNickname") val creatorNickname: String,
 | 
				
			||||||
 | 
					    @SerializedName("isPointAvailable") val isPointAvailable: Boolean
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.annotation.Keep
 | 
				
			||||||
 | 
					import com.google.gson.annotations.SerializedName
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.main.v2.GetContentCurationResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audition.GetAuditionListItem
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.explorer.GetExplorerSectionCreatorResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.live.GetRoomListResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.settings.event.GetEventResponse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Keep
 | 
				
			||||||
 | 
					data class GetHomeResponse(
 | 
				
			||||||
 | 
					    @SerializedName("liveList") val liveList: List<GetRoomListResponse>,
 | 
				
			||||||
 | 
					    @SerializedName("creatorRanking") val creatorRanking: List<GetExplorerSectionCreatorResponse>,
 | 
				
			||||||
 | 
					    @SerializedName("latestContentThemeList") val latestContentThemeList: List<String>,
 | 
				
			||||||
 | 
					    @SerializedName("latestContentList") val latestContentList: List<AudioContentMainItem>,
 | 
				
			||||||
 | 
					    @SerializedName("bannerList") val bannerList: List<GetAudioContentBannerResponse>,
 | 
				
			||||||
 | 
					    @SerializedName("eventBannerList") val eventBannerList: GetEventResponse,
 | 
				
			||||||
 | 
					    @SerializedName("originalAudioDramaList") val originalAudioDramaList: List<GetSeriesListResponse.SeriesListItem>,
 | 
				
			||||||
 | 
					    @SerializedName("auditionList") val auditionList: List<GetAuditionListItem>,
 | 
				
			||||||
 | 
					    @SerializedName("dayOfWeekSeriesList") val dayOfWeekSeriesList: List<GetSeriesListResponse.SeriesListItem>,
 | 
				
			||||||
 | 
					    @SerializedName("contentRanking") val contentRanking: List<GetAudioContentRankingItem>,
 | 
				
			||||||
 | 
					    @SerializedName("recommendChannelList") val recommendChannelList: List<RecommendChannelResponse>,
 | 
				
			||||||
 | 
					    @SerializedName("freeContentList") val freeContentList: List<AudioContentMainItem>,
 | 
				
			||||||
 | 
					    @SerializedName("curationList") val curationList: List<GetContentCurationResponse>
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										35
									
								
								app/src/main/java/kr/co/vividnext/sodalive/home/HomeApi.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import io.reactivex.rxjava3.core.Single
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.common.ApiResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.settings.ContentType
 | 
				
			||||||
 | 
					import retrofit2.http.GET
 | 
				
			||||||
 | 
					import retrofit2.http.Header
 | 
				
			||||||
 | 
					import retrofit2.http.Query
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface HomeApi {
 | 
				
			||||||
 | 
					    @GET("/api/home")
 | 
				
			||||||
 | 
					    fun getHomeData(
 | 
				
			||||||
 | 
					        @Query("timezone") timezone: String,
 | 
				
			||||||
 | 
					        @Query("isAdultContentVisible") isAdultContentVisible: Boolean,
 | 
				
			||||||
 | 
					        @Query("contentType") contentType: ContentType,
 | 
				
			||||||
 | 
					        @Header("Authorization") authHeader: String
 | 
				
			||||||
 | 
					    ): Single<ApiResponse<GetHomeResponse>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @GET("/api/home/latest-content")
 | 
				
			||||||
 | 
					    fun getLatestContentByTheme(
 | 
				
			||||||
 | 
					        @Query("theme") theme: String,
 | 
				
			||||||
 | 
					        @Query("isAdultContentVisible") isAdultContentVisible: Boolean,
 | 
				
			||||||
 | 
					        @Query("contentType") contentType: ContentType,
 | 
				
			||||||
 | 
					        @Header("Authorization") authHeader: String
 | 
				
			||||||
 | 
					    ): Single<ApiResponse<List<AudioContentMainItem>>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @GET("/api/home/day-of-week-series")
 | 
				
			||||||
 | 
					    fun getDayOfWeekSeriesList(
 | 
				
			||||||
 | 
					        @Query("dayOfWeek") dayOfWeek: SeriesPublishedDaysOfWeek,
 | 
				
			||||||
 | 
					        @Query("isAdultContentVisible") isAdultContentVisible: Boolean,
 | 
				
			||||||
 | 
					        @Query("contentType") contentType: ContentType,
 | 
				
			||||||
 | 
					        @Header("Authorization") authHeader: String
 | 
				
			||||||
 | 
					    ): Single<ApiResponse<List<GetSeriesListResponse.SeriesListItem>>>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										343
									
								
								app/src/main/java/kr/co/vividnext/sodalive/home/HomeFragment.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,343 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.content.Intent
 | 
				
			||||||
 | 
					import android.content.SharedPreferences
 | 
				
			||||||
 | 
					import android.graphics.Rect
 | 
				
			||||||
 | 
					import android.os.Bundle
 | 
				
			||||||
 | 
					import android.os.Handler
 | 
				
			||||||
 | 
					import android.os.Looper
 | 
				
			||||||
 | 
					import android.text.SpannableString
 | 
				
			||||||
 | 
					import android.text.Spanned
 | 
				
			||||||
 | 
					import android.text.style.ForegroundColorSpan
 | 
				
			||||||
 | 
					import android.view.View
 | 
				
			||||||
 | 
					import android.widget.Toast
 | 
				
			||||||
 | 
					import androidx.annotation.OptIn
 | 
				
			||||||
 | 
					import androidx.core.content.ContextCompat
 | 
				
			||||||
 | 
					import androidx.media3.common.util.UnstableApi
 | 
				
			||||||
 | 
					import androidx.recyclerview.widget.LinearLayoutManager
 | 
				
			||||||
 | 
					import androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.R
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.box.AudioContentBoxActivity
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.base.BaseFragment
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.common.Constants
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.common.LoadingDialog
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.databinding.FragmentHomeBinding
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.live.LiveViewModel
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.main.MainActivity
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.settings.notification.MemberRole
 | 
				
			||||||
 | 
					import org.koin.android.ext.android.inject
 | 
				
			||||||
 | 
					import java.text.SimpleDateFormat
 | 
				
			||||||
 | 
					import java.util.Date
 | 
				
			||||||
 | 
					import java.util.Locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::inflate) {
 | 
				
			||||||
 | 
					    private val viewModel: HomeViewModel by inject()
 | 
				
			||||||
 | 
					    private val liveViewModel: LiveViewModel by inject()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private lateinit var loadingDialog: LoadingDialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private lateinit var liveAdapter: HomeLiveAdapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val handler = Handler(Looper.getMainLooper())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val preferenceChangeListener =
 | 
				
			||||||
 | 
					        SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
 | 
				
			||||||
 | 
					            // 특정 키에 대한 값이 변경될 때 UI 업데이트
 | 
				
			||||||
 | 
					            if (key == Constants.PREF_USER_ROLE) {
 | 
				
			||||||
 | 
					                if (
 | 
				
			||||||
 | 
					                    sharedPreferences.getString(
 | 
				
			||||||
 | 
					                        key,
 | 
				
			||||||
 | 
					                        MemberRole.USER.name
 | 
				
			||||||
 | 
					                    ) == MemberRole.CREATOR.name
 | 
				
			||||||
 | 
					                ) {
 | 
				
			||||||
 | 
					                    binding.llUploadContent.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					                    binding.llUploadContent.setOnClickListener {
 | 
				
			||||||
 | 
					                        startActivity(
 | 
				
			||||||
 | 
					                            Intent(
 | 
				
			||||||
 | 
					                                requireActivity(),
 | 
				
			||||||
 | 
					                                AudioContentUploadActivity::class.java
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    binding.llUploadContent.visibility = View.GONE
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
				
			||||||
 | 
					        super.onViewCreated(view, savedInstanceState)
 | 
				
			||||||
 | 
					        SharedPreferenceManager.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
 | 
				
			||||||
 | 
					        setupView()
 | 
				
			||||||
 | 
					        bindData()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        viewModel.fetchData()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onDestroyView() {
 | 
				
			||||||
 | 
					        SharedPreferenceManager.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)
 | 
				
			||||||
 | 
					        super.onDestroyView()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun setupView() {
 | 
				
			||||||
 | 
					        loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (SharedPreferenceManager.role == MemberRole.CREATOR.name) {
 | 
				
			||||||
 | 
					            binding.llUploadContent.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					            binding.llUploadContent.setOnClickListener {
 | 
				
			||||||
 | 
					                startActivity(
 | 
				
			||||||
 | 
					                    Intent(
 | 
				
			||||||
 | 
					                        requireActivity(),
 | 
				
			||||||
 | 
					                        AudioContentUploadActivity::class.java
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            binding.llUploadContent.visibility = View.GONE
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (SharedPreferenceManager.token.isNotBlank()) {
 | 
				
			||||||
 | 
					            binding.llShortIcon.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            binding.ivSearch.setOnClickListener {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            binding.ivCharge.setOnClickListener {
 | 
				
			||||||
 | 
					                startActivity(
 | 
				
			||||||
 | 
					                    Intent(
 | 
				
			||||||
 | 
					                        requireContext(),
 | 
				
			||||||
 | 
					                        CanChargeActivity::class.java
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            binding.ivStorage.setOnClickListener {
 | 
				
			||||||
 | 
					                startActivity(
 | 
				
			||||||
 | 
					                    Intent(
 | 
				
			||||||
 | 
					                        requireContext(),
 | 
				
			||||||
 | 
					                        AudioContentBoxActivity::class.java
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            binding.llShortIcon.visibility = View.GONE
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setupLiveView()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @OptIn(UnstableApi::class)
 | 
				
			||||||
 | 
					    private fun setupLiveView() {
 | 
				
			||||||
 | 
					        val spSectionTitle = SpannableString(binding.tvLiveTitle.text)
 | 
				
			||||||
 | 
					        spSectionTitle.setSpan(
 | 
				
			||||||
 | 
					            ForegroundColorSpan(
 | 
				
			||||||
 | 
					                ContextCompat.getColor(
 | 
				
			||||||
 | 
					                    requireContext(),
 | 
				
			||||||
 | 
					                    R.color.color_3bb9f1
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            2,
 | 
				
			||||||
 | 
					            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        binding.tvLiveTitle.text = spSectionTitle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        liveAdapter = HomeLiveAdapter {
 | 
				
			||||||
 | 
					            if (SharedPreferenceManager.token.isNotBlank()) {
 | 
				
			||||||
 | 
					                val detailFragment = LiveRoomDetailFragment(
 | 
				
			||||||
 | 
					                    it.roomId,
 | 
				
			||||||
 | 
					                    onClickParticipant = { enterLiveRoom(it.roomId) },
 | 
				
			||||||
 | 
					                    onClickReservation = {},
 | 
				
			||||||
 | 
					                    onClickModify = {},
 | 
				
			||||||
 | 
					                    onClickStart = {},
 | 
				
			||||||
 | 
					                    onClickCancel = {}
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                if (detailFragment.isAdded) return@HomeLiveAdapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                detailFragment.show(
 | 
				
			||||||
 | 
					                    requireActivity().supportFragmentManager,
 | 
				
			||||||
 | 
					                    detailFragment.tag
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                (requireActivity() as MainActivity).showLoginActivity()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val recyclerView = binding.rvLive
 | 
				
			||||||
 | 
					        recyclerView.layoutManager = LinearLayoutManager(
 | 
				
			||||||
 | 
					            context,
 | 
				
			||||||
 | 
					            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 = 0
 | 
				
			||||||
 | 
					                        outRect.right = 16f.dpToPx().toInt()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    liveAdapter.itemCount - 1 -> {
 | 
				
			||||||
 | 
					                        outRect.left = 16f.dpToPx().toInt()
 | 
				
			||||||
 | 
					                        outRect.right = 0
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    else -> {
 | 
				
			||||||
 | 
					                        outRect.left = 16f.dpToPx().toInt()
 | 
				
			||||||
 | 
					                        outRect.right = 16f.dpToPx().toInt()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        recyclerView.adapter = liveAdapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        viewModel.liveListLiveData.observe(viewLifecycleOwner) {
 | 
				
			||||||
 | 
					            if (it.isNotEmpty()) {
 | 
				
			||||||
 | 
					                binding.llLive.visibility = View.VISIBLE
 | 
				
			||||||
 | 
					                liveAdapter.addItems(it)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                binding.llLive.visibility = View.GONE
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun bindData() {
 | 
				
			||||||
 | 
					        viewModel.isLoading.observe(viewLifecycleOwner) {
 | 
				
			||||||
 | 
					            if (it) {
 | 
				
			||||||
 | 
					                loadingDialog.show(screenWidth)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                loadingDialog.dismiss()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        viewModel.toastLiveData.observe(viewLifecycleOwner) {
 | 
				
			||||||
 | 
					            it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @UnstableApi
 | 
				
			||||||
 | 
					    fun enterLiveRoom(roomId: Long) {
 | 
				
			||||||
 | 
					        requireContext().startService(
 | 
				
			||||||
 | 
					            Intent(requireContext(), AudioContentPlayService::class.java).apply {
 | 
				
			||||||
 | 
					                action = AudioContentPlayService.MusicAction.STOP.name
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        requireContext().startService(
 | 
				
			||||||
 | 
					            Intent(requireContext(), AudioContentPlayerService::class.java).apply {
 | 
				
			||||||
 | 
					                action = "STOP_SERVICE"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val onEnterRoomSuccess = {
 | 
				
			||||||
 | 
					            requireActivity().runOnUiThread {
 | 
				
			||||||
 | 
					                val intent = Intent(requireContext(), LiveRoomActivity::class.java)
 | 
				
			||||||
 | 
					                intent.putExtra(Constants.EXTRA_ROOM_ID, roomId)
 | 
				
			||||||
 | 
					                startActivity(intent)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        liveViewModel.getRoomDetail(roomId) {
 | 
				
			||||||
 | 
					            if (it.channelName != null) {
 | 
				
			||||||
 | 
					                if (it.manager.id == SharedPreferenceManager.userId) {
 | 
				
			||||||
 | 
					                    handler.postDelayed({
 | 
				
			||||||
 | 
					                        liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
 | 
				
			||||||
 | 
					                    }, 300)
 | 
				
			||||||
 | 
					                } else if (it.price == 0 || it.isPaid) {
 | 
				
			||||||
 | 
					                    if (it.isPrivateRoom) {
 | 
				
			||||||
 | 
					                        LiveRoomPasswordDialog(
 | 
				
			||||||
 | 
					                            activity = requireActivity(),
 | 
				
			||||||
 | 
					                            layoutInflater = layoutInflater,
 | 
				
			||||||
 | 
					                            can = 0,
 | 
				
			||||||
 | 
					                            confirmButtonClick = { password ->
 | 
				
			||||||
 | 
					                                liveViewModel.enterRoom(
 | 
				
			||||||
 | 
					                                    roomId = roomId,
 | 
				
			||||||
 | 
					                                    onSuccess = onEnterRoomSuccess,
 | 
				
			||||||
 | 
					                                    password = password
 | 
				
			||||||
 | 
					                                )
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        ).show(screenWidth)
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        handler.postDelayed({
 | 
				
			||||||
 | 
					                            liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
 | 
				
			||||||
 | 
					                        }, 300)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    val beginDateFormat = SimpleDateFormat("yyyy.MM.dd EEE hh:mm a", Locale.ENGLISH)
 | 
				
			||||||
 | 
					                    val beginDate = beginDateFormat.parse(it.beginDateTime)!!
 | 
				
			||||||
 | 
					                    val now = Date()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    val dateFormat = SimpleDateFormat("yyyy-MM-dd, HH:mm", Locale.getDefault())
 | 
				
			||||||
 | 
					                    val diffTime: Long = now.time - beginDate.time
 | 
				
			||||||
 | 
					                    val hours = (diffTime / (1000 * 60 * 60)).toInt()
 | 
				
			||||||
 | 
					                    val mins = (diffTime / (1000 * 60)).toInt() % 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (it.isPrivateRoom) {
 | 
				
			||||||
 | 
					                        LiveRoomPasswordDialog(
 | 
				
			||||||
 | 
					                            activity = requireActivity(),
 | 
				
			||||||
 | 
					                            layoutInflater = layoutInflater,
 | 
				
			||||||
 | 
					                            can = it.price,
 | 
				
			||||||
 | 
					                            confirmButtonClick = { password ->
 | 
				
			||||||
 | 
					                                handler.postDelayed({
 | 
				
			||||||
 | 
					                                    liveViewModel.enterRoom(
 | 
				
			||||||
 | 
					                                        roomId = roomId,
 | 
				
			||||||
 | 
					                                        onSuccess = onEnterRoomSuccess,
 | 
				
			||||||
 | 
					                                        password = password
 | 
				
			||||||
 | 
					                                    )
 | 
				
			||||||
 | 
					                                }, 300)
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        ).show(screenWidth)
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        LivePaymentDialog(
 | 
				
			||||||
 | 
					                            activity = requireActivity(),
 | 
				
			||||||
 | 
					                            layoutInflater = layoutInflater,
 | 
				
			||||||
 | 
					                            title = "유료 라이브 입장",
 | 
				
			||||||
 | 
					                            startDateTime = if (hours >= 1) {
 | 
				
			||||||
 | 
					                                dateFormat.format(beginDate)
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                                null
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            nowDateTime = if (hours >= 1) {
 | 
				
			||||||
 | 
					                                dateFormat.format(now)
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                                null
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            desc = "${it.price}캔을 차감하고\n라이브에 입장 하시겠습니까?",
 | 
				
			||||||
 | 
					                            desc2 = if (hours >= 1) {
 | 
				
			||||||
 | 
					                                "라이브를 시작한 지 ${hours}시간 ${mins}분이 지났습니다. 라이브에 입장 후 30분 이내에 라이브가 종료될 수도 있습니다."
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                                null
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            confirmButtonTitle = "결제 후 입장",
 | 
				
			||||||
 | 
					                            confirmButtonClick = {
 | 
				
			||||||
 | 
					                                handler.postDelayed({
 | 
				
			||||||
 | 
					                                    liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
 | 
				
			||||||
 | 
					                                }, 300)
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            cancelButtonTitle = "취소",
 | 
				
			||||||
 | 
					                            cancelButtonClick = {}
 | 
				
			||||||
 | 
					                        ).show(screenWidth)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.annotation.SuppressLint
 | 
				
			||||||
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.view.LayoutInflater
 | 
				
			||||||
 | 
					import android.view.ViewGroup
 | 
				
			||||||
 | 
					import androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					import com.bumptech.glide.Glide
 | 
				
			||||||
 | 
					import com.bumptech.glide.load.resource.bitmap.CircleCrop
 | 
				
			||||||
 | 
					import com.bumptech.glide.request.RequestOptions
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.databinding.ItemHomeLiveBinding
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.live.GetRoomListResponse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HomeLiveAdapter(
 | 
				
			||||||
 | 
					    private val onClick: (GetRoomListResponse) -> Unit
 | 
				
			||||||
 | 
					) : RecyclerView.Adapter<HomeLiveAdapter.ViewHolder>() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var items = mutableListOf<GetRoomListResponse>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inner class ViewHolder(
 | 
				
			||||||
 | 
					        private val context: Context,
 | 
				
			||||||
 | 
					        private val binding: ItemHomeLiveBinding
 | 
				
			||||||
 | 
					    ) : RecyclerView.ViewHolder(binding.root) {
 | 
				
			||||||
 | 
					        fun bind(item: GetRoomListResponse) {
 | 
				
			||||||
 | 
					            Glide
 | 
				
			||||||
 | 
					                .with(context)
 | 
				
			||||||
 | 
					                .load(item.coverImageUrl)
 | 
				
			||||||
 | 
					                .apply(
 | 
				
			||||||
 | 
					                    RequestOptions().transform(
 | 
				
			||||||
 | 
					                        CircleCrop()
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                .into(binding.ivProfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            binding.tvTitle.text = item.title
 | 
				
			||||||
 | 
					            binding.tvNickname.text = item.creatorNickname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            binding.root.setOnClickListener { onClick(item) }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
 | 
				
			||||||
 | 
					        parent.context,
 | 
				
			||||||
 | 
					        ItemHomeLiveBinding.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 addItems(items: List<GetRoomListResponse>) {
 | 
				
			||||||
 | 
					        this.items.addAll(items)
 | 
				
			||||||
 | 
					        notifyDataSetChanged()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.settings.ContentType
 | 
				
			||||||
 | 
					import java.util.TimeZone
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HomeRepository(private val api: HomeApi) {
 | 
				
			||||||
 | 
					    fun fetchData(token: String) = api.getHomeData(
 | 
				
			||||||
 | 
					        timezone = TimeZone.getDefault().id,
 | 
				
			||||||
 | 
					        isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
 | 
				
			||||||
 | 
					        contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
 | 
				
			||||||
 | 
					        authHeader = token
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun getLatestContentByTheme(theme: String, token: String) = api.getLatestContentByTheme(
 | 
				
			||||||
 | 
					        theme = theme,
 | 
				
			||||||
 | 
					        isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
 | 
				
			||||||
 | 
					        contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
 | 
				
			||||||
 | 
					        authHeader = token
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun getDayOfWeekSeriesList(
 | 
				
			||||||
 | 
					        dayOfWeek: SeriesPublishedDaysOfWeek, token: String
 | 
				
			||||||
 | 
					    ) = api.getDayOfWeekSeriesList(
 | 
				
			||||||
 | 
					        dayOfWeek = dayOfWeek,
 | 
				
			||||||
 | 
					        isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
 | 
				
			||||||
 | 
					        contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
 | 
				
			||||||
 | 
					        authHeader = token
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										164
									
								
								app/src/main/java/kr/co/vividnext/sodalive/home/HomeViewModel.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.lifecycle.LiveData
 | 
				
			||||||
 | 
					import androidx.lifecycle.MutableLiveData
 | 
				
			||||||
 | 
					import com.orhanobut.logger.Logger
 | 
				
			||||||
 | 
					import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
 | 
				
			||||||
 | 
					import io.reactivex.rxjava3.schedulers.Schedulers
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.main.v2.GetContentCurationResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.audition.GetAuditionListItem
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.base.BaseViewModel
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.explorer.GetExplorerSectionCreatorResponse
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.live.GetRoomListResponse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HomeViewModel(private val repository: HomeRepository) : BaseViewModel() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _isLoading = MutableLiveData(false)
 | 
				
			||||||
 | 
					    val isLoading: LiveData<Boolean>
 | 
				
			||||||
 | 
					        get() = _isLoading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val _toastLiveData = MutableLiveData<String?>()
 | 
				
			||||||
 | 
					    val toastLiveData: LiveData<String?>
 | 
				
			||||||
 | 
					        get() = _toastLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _liveListLiveData = MutableLiveData<List<GetRoomListResponse>>()
 | 
				
			||||||
 | 
					    val liveListLiveData: LiveData<List<GetRoomListResponse>>
 | 
				
			||||||
 | 
					        get() = _liveListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _creatorRankingLiveData = MutableLiveData<List<GetExplorerSectionCreatorResponse>>()
 | 
				
			||||||
 | 
					    val creatorRankingLiveData: LiveData<List<GetExplorerSectionCreatorResponse>>
 | 
				
			||||||
 | 
					        get() = _creatorRankingLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _latestContentThemeListLiveData = MutableLiveData<List<String>>()
 | 
				
			||||||
 | 
					    val latestContentThemeListLiveData: LiveData<List<String>>
 | 
				
			||||||
 | 
					        get() = _latestContentThemeListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _latestContentListLiveData = MutableLiveData<List<AudioContentMainItem>>()
 | 
				
			||||||
 | 
					    val latestContentListLiveData: LiveData<List<AudioContentMainItem>>
 | 
				
			||||||
 | 
					        get() = _latestContentListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _eventBannerListLiveData = MutableLiveData<List<GetAudioContentBannerResponse>>()
 | 
				
			||||||
 | 
					    val eventBannerListLiveData: LiveData<List<GetAudioContentBannerResponse>>
 | 
				
			||||||
 | 
					        get() = _eventBannerListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _originalAudioDramaListLiveData =
 | 
				
			||||||
 | 
					        MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
 | 
				
			||||||
 | 
					    val originalAudioDramaListLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
 | 
				
			||||||
 | 
					        get() = _originalAudioDramaListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _auditionListLiveData = MutableLiveData<List<GetAuditionListItem>>()
 | 
				
			||||||
 | 
					    val auditionListLiveData: LiveData<List<GetAuditionListItem>>
 | 
				
			||||||
 | 
					        get() = _auditionListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _dayOfWeekSeriesListLiveData =
 | 
				
			||||||
 | 
					        MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
 | 
				
			||||||
 | 
					    val dayOfWeekSeriesListLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
 | 
				
			||||||
 | 
					        get() = _dayOfWeekSeriesListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _contentRankingLiveData = MutableLiveData<List<GetAudioContentRankingItem>>()
 | 
				
			||||||
 | 
					    val contentRankingLiveData: LiveData<List<GetAudioContentRankingItem>>
 | 
				
			||||||
 | 
					        get() = _contentRankingLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _recommendChannelListLiveData = MutableLiveData<List<RecommendChannelResponse>>()
 | 
				
			||||||
 | 
					    val recommendChannelListLiveData: LiveData<List<RecommendChannelResponse>>
 | 
				
			||||||
 | 
					        get() = _recommendChannelListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _freeContentListLiveData = MutableLiveData<List<AudioContentMainItem>>()
 | 
				
			||||||
 | 
					    val freeContentListLiveData: LiveData<List<AudioContentMainItem>>
 | 
				
			||||||
 | 
					        get() = _freeContentListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var _curationListLiveData = MutableLiveData<List<GetContentCurationResponse>>()
 | 
				
			||||||
 | 
					    val curationListLiveData: LiveData<List<GetContentCurationResponse>>
 | 
				
			||||||
 | 
					        get() = _curationListLiveData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun fetchData() {
 | 
				
			||||||
 | 
					        _isLoading.value = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        compositeDisposable.add(
 | 
				
			||||||
 | 
					            repository.fetchData(token = "Bearer ${SharedPreferenceManager.token}")
 | 
				
			||||||
 | 
					                .subscribeOn(Schedulers.io())
 | 
				
			||||||
 | 
					                .observeOn(AndroidSchedulers.mainThread())
 | 
				
			||||||
 | 
					                .subscribe(
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        _isLoading.value = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        val data = it.data
 | 
				
			||||||
 | 
					                        if (it.success && data != null) {
 | 
				
			||||||
 | 
					                            _liveListLiveData.value = data.liveList
 | 
				
			||||||
 | 
					                            _creatorRankingLiveData.value = data.creatorRanking
 | 
				
			||||||
 | 
					                            _latestContentThemeListLiveData.value = data.latestContentThemeList
 | 
				
			||||||
 | 
					                            _latestContentListLiveData.value = data.latestContentList
 | 
				
			||||||
 | 
					                            _eventBannerListLiveData.value = data.bannerList
 | 
				
			||||||
 | 
					                            _originalAudioDramaListLiveData.value = data.originalAudioDramaList
 | 
				
			||||||
 | 
					                            _auditionListLiveData.value = data.auditionList
 | 
				
			||||||
 | 
					                            _dayOfWeekSeriesListLiveData.value = data.dayOfWeekSeriesList
 | 
				
			||||||
 | 
					                            _contentRankingLiveData.value = data.contentRanking
 | 
				
			||||||
 | 
					                        } 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 getLatestContentByTheme(theme: String) {
 | 
				
			||||||
 | 
					        _isLoading.value = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        compositeDisposable.add(
 | 
				
			||||||
 | 
					            repository.getLatestContentByTheme(
 | 
				
			||||||
 | 
					                theme,
 | 
				
			||||||
 | 
					                token = "Bearer ${SharedPreferenceManager.token}"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					                .subscribeOn(Schedulers.io())
 | 
				
			||||||
 | 
					                .observeOn(AndroidSchedulers.mainThread())
 | 
				
			||||||
 | 
					                .subscribe(
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        _isLoading.value = false
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        _isLoading.value = false
 | 
				
			||||||
 | 
					                        it.message?.let { message -> Logger.e(message) }
 | 
				
			||||||
 | 
					                        _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun getDayOfWeekSeriesList(dayOfWeek: SeriesPublishedDaysOfWeek) {
 | 
				
			||||||
 | 
					        _isLoading.value = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        compositeDisposable.add(
 | 
				
			||||||
 | 
					            repository.getDayOfWeekSeriesList(
 | 
				
			||||||
 | 
					                dayOfWeek,
 | 
				
			||||||
 | 
					                token = "Bearer ${SharedPreferenceManager.token}"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					                .subscribeOn(Schedulers.io())
 | 
				
			||||||
 | 
					                .observeOn(AndroidSchedulers.mainThread())
 | 
				
			||||||
 | 
					                .subscribe(
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        _isLoading.value = false
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        _isLoading.value = false
 | 
				
			||||||
 | 
					                        it.message?.let { message -> Logger.e(message) }
 | 
				
			||||||
 | 
					                        _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.annotation.Keep
 | 
				
			||||||
 | 
					import com.google.gson.annotations.SerializedName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Keep
 | 
				
			||||||
 | 
					data class RecommendChannelResponse(
 | 
				
			||||||
 | 
					    @SerializedName("channelId") val channelId: Long,
 | 
				
			||||||
 | 
					    @SerializedName("creatorNickname") val creatorNickname: String,
 | 
				
			||||||
 | 
					    @SerializedName("creatorProfileImageUrl") val creatorProfileImageUrl: String,
 | 
				
			||||||
 | 
					    @SerializedName("contentCount") val contentCount: Long,
 | 
				
			||||||
 | 
					    @SerializedName("contentList") var contentList: List<RecommendChannelContentItem>
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Keep
 | 
				
			||||||
 | 
					data class RecommendChannelContentItem(
 | 
				
			||||||
 | 
					    @SerializedName("contentId") val contentId: Long,
 | 
				
			||||||
 | 
					    @SerializedName("title") val title: String,
 | 
				
			||||||
 | 
					    @SerializedName("thumbnailImageUrl") val thumbnailImageUrl: String,
 | 
				
			||||||
 | 
					    @SerializedName("likeCount") val likeCount: Long,
 | 
				
			||||||
 | 
					    @SerializedName("commentCount") val commentCount: Long
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					package kr.co.vividnext.sodalive.home
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class SeriesPublishedDaysOfWeek {
 | 
				
			||||||
 | 
					    SUN, MON, TUE, WED, THU, FRI, SAT, RANDOM
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -31,7 +31,6 @@ import com.orhanobut.logger.Logger
 | 
				
			|||||||
import kr.co.vividnext.sodalive.R
 | 
					import kr.co.vividnext.sodalive.R
 | 
				
			||||||
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
 | 
					import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
 | 
				
			||||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
 | 
					import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
 | 
				
			||||||
import kr.co.vividnext.sodalive.audio_content.main.v2.home.AudioContentMainTabHomeFragment
 | 
					 | 
				
			||||||
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerFragment
 | 
					import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerFragment
 | 
				
			||||||
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
 | 
					import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
 | 
				
			||||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
 | 
					import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
 | 
				
			||||||
@@ -43,6 +42,7 @@ import kr.co.vividnext.sodalive.databinding.ActivityMainBinding
 | 
				
			|||||||
import kr.co.vividnext.sodalive.databinding.ItemMainTabBinding
 | 
					import kr.co.vividnext.sodalive.databinding.ItemMainTabBinding
 | 
				
			||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
 | 
					import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
 | 
				
			||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
					import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
				
			||||||
 | 
					import kr.co.vividnext.sodalive.home.HomeFragment
 | 
				
			||||||
import kr.co.vividnext.sodalive.live.LiveFragment
 | 
					import kr.co.vividnext.sodalive.live.LiveFragment
 | 
				
			||||||
import kr.co.vividnext.sodalive.message.MessageActivity
 | 
					import kr.co.vividnext.sodalive.message.MessageActivity
 | 
				
			||||||
import kr.co.vividnext.sodalive.mypage.MyPageFragment
 | 
					import kr.co.vividnext.sodalive.mypage.MyPageFragment
 | 
				
			||||||
@@ -472,7 +472,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
 | 
				
			|||||||
        if (fragment == null) {
 | 
					        if (fragment == null) {
 | 
				
			||||||
            fragment = when (currentTab) {
 | 
					            fragment = when (currentTab) {
 | 
				
			||||||
                MainViewModel.CurrentTab.LIVE -> liveFragment
 | 
					                MainViewModel.CurrentTab.LIVE -> liveFragment
 | 
				
			||||||
                MainViewModel.CurrentTab.HOME -> AudioContentMainTabHomeFragment()
 | 
					                MainViewModel.CurrentTab.HOME -> HomeFragment()
 | 
				
			||||||
                MainViewModel.CurrentTab.MY -> MyPageFragment()
 | 
					                MainViewModel.CurrentTab.MY -> MyPageFragment()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_can_circle.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_comment_dark_green.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 677 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_heart_dark_green.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 643 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_search_white.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 432 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/ic_storage.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 375 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/img_live.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-mdpi/img_text_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 2.9 KiB  | 
							
								
								
									
										5
									
								
								app/src/main/res/drawable/circle_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<shape xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:shape="oval">
 | 
				
			||||||
 | 
					    <solid android:color="@color/color_3bb9f1" />
 | 
				
			||||||
 | 
					</shape>
 | 
				
			||||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/live_button_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<shape xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:shape="rectangle">
 | 
				
			||||||
 | 
					    <solid android:color="#2A339D" />
 | 
				
			||||||
 | 
					    <stroke
 | 
				
			||||||
 | 
					        android:width="1dp"
 | 
				
			||||||
 | 
					        android:color="@color/white" />
 | 
				
			||||||
 | 
					    <corners android:radius="999dp" />
 | 
				
			||||||
 | 
					</shape>
 | 
				
			||||||
@@ -14,4 +14,20 @@
 | 
				
			|||||||
        android:font="@font/gmarket_sans_medium"
 | 
					        android:font="@font/gmarket_sans_medium"
 | 
				
			||||||
        app:font="@font/gmarket_sans_medium" />
 | 
					        app:font="@font/gmarket_sans_medium" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <font
 | 
				
			||||||
 | 
					        android:font="@font/pretendard_bold"
 | 
				
			||||||
 | 
					        app:font="@font/pretendard_bold" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <font
 | 
				
			||||||
 | 
					        android:font="@font/pretendard_light"
 | 
				
			||||||
 | 
					        app:font="@font/pretendard_light" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <font
 | 
				
			||||||
 | 
					        android:font="@font/pretendard_medium"
 | 
				
			||||||
 | 
					        app:font="@font/pretendard_medium" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <font
 | 
				
			||||||
 | 
					        android:font="@font/pretendard_regular"
 | 
				
			||||||
 | 
					        app:font="@font/pretendard_regular" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</font-family>
 | 
					</font-family>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/font/pretendard_bold.otf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/font/pretendard_light.otf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/font/pretendard_medium.otf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/font/pretendard_regular.otf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										415
									
								
								app/src/main/res/layout/fragment_home.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,415 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
				
			||||||
 | 
					    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					    android:layout_height="match_parent"
 | 
				
			||||||
 | 
					    android:background="@color/color_131313">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <androidx.core.widget.NestedScrollView
 | 
				
			||||||
 | 
					        android:layout_width="match_parent"
 | 
				
			||||||
 | 
					        android:layout_height="match_parent"
 | 
				
			||||||
 | 
					        android:clipToPadding="false"
 | 
				
			||||||
 | 
					        android:paddingVertical="13.3dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <LinearLayout
 | 
				
			||||||
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
 | 
					            android:layout_height="match_parent"
 | 
				
			||||||
 | 
					            android:orientation="vertical">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <RelativeLayout
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:paddingHorizontal="24dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <ImageView
 | 
				
			||||||
 | 
					                    android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_alignParentStart="true"
 | 
				
			||||||
 | 
					                    android:layout_centerVertical="true"
 | 
				
			||||||
 | 
					                    android:contentDescription="@null"
 | 
				
			||||||
 | 
					                    android:src="@drawable/img_text_logo" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <LinearLayout
 | 
				
			||||||
 | 
					                    android:id="@+id/ll_short_icon"
 | 
				
			||||||
 | 
					                    android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_alignParentEnd="true"
 | 
				
			||||||
 | 
					                    android:layout_centerVertical="true"
 | 
				
			||||||
 | 
					                    android:orientation="horizontal"
 | 
				
			||||||
 | 
					                    android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <ImageView
 | 
				
			||||||
 | 
					                        android:id="@+id/iv_search"
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:contentDescription="@null"
 | 
				
			||||||
 | 
					                        android:src="@drawable/ic_search_white" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <ImageView
 | 
				
			||||||
 | 
					                        android:id="@+id/iv_charge"
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                        android:contentDescription="@null"
 | 
				
			||||||
 | 
					                        android:src="@drawable/ic_can_circle" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <ImageView
 | 
				
			||||||
 | 
					                        android:id="@+id/iv_storage"
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:contentDescription="@null"
 | 
				
			||||||
 | 
					                        android:src="@drawable/ic_storage" />
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					            </RelativeLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_live"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="24dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:id="@+id/tv_live_title"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					                    android:text="지금 라이브 중"
 | 
				
			||||||
 | 
					                    android:textColor="@color/white"
 | 
				
			||||||
 | 
					                    android:textSize="26sp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_live"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_famous_creator"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:id="@+id/tv_famous_creator_title"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					                    android:text="인기 크리에이터"
 | 
				
			||||||
 | 
					                    android:textColor="@color/white"
 | 
				
			||||||
 | 
					                    android:textSize="26sp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_famous_creator"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_new_content"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <RelativeLayout
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					                        android:text="최신 콘텐츠"
 | 
				
			||||||
 | 
					                        android:textColor="@color/color_eeeeee"
 | 
				
			||||||
 | 
					                        android:textSize="26sp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:id="@+id/tv_new_content_all"
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_alignParentEnd="true"
 | 
				
			||||||
 | 
					                        android:layout_centerVertical="true"
 | 
				
			||||||
 | 
					                        android:fontFamily="@font/pretendard_regular"
 | 
				
			||||||
 | 
					                        android:text="전체보기"
 | 
				
			||||||
 | 
					                        android:textColor="@color/color_607d8b" />
 | 
				
			||||||
 | 
					                </RelativeLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_new_content_theme"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_new_content"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_banner"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <com.zhpan.bannerview.BannerViewPager
 | 
				
			||||||
 | 
					                    android:id="@+id/event_banner_slider"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <com.zhpan.indicator.IndicatorView
 | 
				
			||||||
 | 
					                    android:id="@+id/indicator_event_banner"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_gravity="center"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="6.7dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_series_original"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:id="@+id/tv_series_original"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					                    android:text="오직 보이스온에서만"
 | 
				
			||||||
 | 
					                    android:textColor="@color/white"
 | 
				
			||||||
 | 
					                    android:textSize="26sp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_series_original"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_audition"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <com.zhpan.bannerview.BannerViewPager
 | 
				
			||||||
 | 
					                    android:id="@+id/audition_slider"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <com.zhpan.indicator.IndicatorView
 | 
				
			||||||
 | 
					                    android:id="@+id/indicator_audition"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_gravity="center"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="6.7dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_series_day_of_week"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:id="@+id/tv_series_day_of_week"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					                    android:text="요일별 시리즈"
 | 
				
			||||||
 | 
					                    android:textColor="@color/white"
 | 
				
			||||||
 | 
					                    android:textSize="26sp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_series_day_of_week_day"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_series_day_of_week"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_weekly_chart"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:id="@+id/tv_weekly_chart"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					                    android:text="보온 주간 차트"
 | 
				
			||||||
 | 
					                    android:textColor="@color/white"
 | 
				
			||||||
 | 
					                    android:textSize="26sp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_weekly_chart"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_recommend_channel"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:id="@+id/tv_recommend_channel"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					                    android:text="추천 채널"
 | 
				
			||||||
 | 
					                    android:textColor="@color/white"
 | 
				
			||||||
 | 
					                    android:textSize="26sp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_recommend_channel"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:id="@+id/ll_free_content"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:id="@+id/tv_free_content"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					                    android:text="무료 콘텐츠"
 | 
				
			||||||
 | 
					                    android:textColor="@color/white"
 | 
				
			||||||
 | 
					                    android:textSize="26sp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                    android:id="@+id/rv_free_content"
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:layout_marginTop="16dp"
 | 
				
			||||||
 | 
					                    android:clipToPadding="false"
 | 
				
			||||||
 | 
					                    android:paddingHorizontal="24dp" />
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <androidx.recyclerview.widget.RecyclerView
 | 
				
			||||||
 | 
					                android:id="@+id/rv_curation"
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:clipToPadding="false"
 | 
				
			||||||
 | 
					                android:visibility="gone" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <io.github.glailton.expandabletextview.ExpandableTextView
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                android:layout_marginHorizontal="24dp"
 | 
				
			||||||
 | 
					                android:layout_marginTop="48dp"
 | 
				
			||||||
 | 
					                android:fontFamily="@font/pretendard_regular"
 | 
				
			||||||
 | 
					                android:text="
 | 
				
			||||||
 | 
					- 회사명 : 주식회사 소다라이브\n\n
 | 
				
			||||||
 | 
					- 대표자 : 이재형\n\n
 | 
				
			||||||
 | 
					- 주소 : 경기도 성남시 분당구 황새울로335번길 10, 5층 563A호\n\n
 | 
				
			||||||
 | 
					- 사업자등록번호 : 870-81-03220\n\n
 | 
				
			||||||
 | 
					- 통신판매업신고 : 제2024-성남분당B-1012호\n\n
 | 
				
			||||||
 | 
					- 고객센터 : 02.2055.1477(이용시간 10:00~19:00)\n\n
 | 
				
			||||||
 | 
					- 대표 이메일 : sodalive.official@gmail.com"
 | 
				
			||||||
 | 
					                android:textColor="@color/color_777777"
 | 
				
			||||||
 | 
					                android:textSize="11sp"
 | 
				
			||||||
 | 
					                app:animDuration="500"
 | 
				
			||||||
 | 
					                app:collapsedLines="5"
 | 
				
			||||||
 | 
					                app:ellipsizeTextColor="@color/color_777777"
 | 
				
			||||||
 | 
					                app:expandType="layout"
 | 
				
			||||||
 | 
					                app:isExpanded="false"
 | 
				
			||||||
 | 
					                app:readLessText="간략히"
 | 
				
			||||||
 | 
					                app:readMoreText="더보기"
 | 
				
			||||||
 | 
					                app:textMode="line" />
 | 
				
			||||||
 | 
					        </LinearLayout>
 | 
				
			||||||
 | 
					    </androidx.core.widget.NestedScrollView>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <LinearLayout
 | 
				
			||||||
 | 
					        android:id="@+id/ll_upload_content"
 | 
				
			||||||
 | 
					        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					        android:layout_alignParentEnd="true"
 | 
				
			||||||
 | 
					        android:layout_alignParentBottom="true"
 | 
				
			||||||
 | 
					        android:layout_marginEnd="16.7dp"
 | 
				
			||||||
 | 
					        android:layout_marginBottom="16.7dp"
 | 
				
			||||||
 | 
					        android:background="@drawable/bg_round_corner_44_3bb9f1"
 | 
				
			||||||
 | 
					        android:orientation="horizontal"
 | 
				
			||||||
 | 
					        android:padding="13.3dp"
 | 
				
			||||||
 | 
					        android:visibility="gone">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <ImageView
 | 
				
			||||||
 | 
					            android:layout_width="20dp"
 | 
				
			||||||
 | 
					            android:layout_height="20dp"
 | 
				
			||||||
 | 
					            android:layout_marginEnd="5dp"
 | 
				
			||||||
 | 
					            android:contentDescription="@null"
 | 
				
			||||||
 | 
					            android:src="@drawable/ic_thumb_play" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <TextView
 | 
				
			||||||
 | 
					            android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					            android:fontFamily="@font/pretendard_bold"
 | 
				
			||||||
 | 
					            android:text="콘텐츠 업로드"
 | 
				
			||||||
 | 
					            android:textColor="@color/white"
 | 
				
			||||||
 | 
					            android:textSize="13.3sp" />
 | 
				
			||||||
 | 
					    </LinearLayout>
 | 
				
			||||||
 | 
					</RelativeLayout>
 | 
				
			||||||
							
								
								
									
										68
									
								
								app/src/main/res/layout/item_home_live.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					<?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="282dp"
 | 
				
			||||||
 | 
					    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					    android:background="@drawable/live_button_background"
 | 
				
			||||||
 | 
					    android:gravity="center_vertical"
 | 
				
			||||||
 | 
					    android:orientation="horizontal"
 | 
				
			||||||
 | 
					    android:paddingHorizontal="14dp"
 | 
				
			||||||
 | 
					    android:paddingVertical="10dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- 프로필 이미지 컨테이너 -->
 | 
				
			||||||
 | 
					    <FrameLayout
 | 
				
			||||||
 | 
					        android:layout_width="72dp"
 | 
				
			||||||
 | 
					        android:layout_height="72dp"
 | 
				
			||||||
 | 
					        android:layout_marginEnd="16dp"
 | 
				
			||||||
 | 
					        android:background="@drawable/circle_background">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- 프로필 이미지 -->
 | 
				
			||||||
 | 
					        <ImageView
 | 
				
			||||||
 | 
					            android:id="@+id/iv_profile"
 | 
				
			||||||
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
 | 
					            android:layout_height="match_parent"
 | 
				
			||||||
 | 
					            android:layout_gravity="center"
 | 
				
			||||||
 | 
					            android:background="@drawable/circle_background"
 | 
				
			||||||
 | 
					            android:contentDescription="@null"
 | 
				
			||||||
 | 
					            android:scaleType="centerCrop" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- LIVE 배지 -->
 | 
				
			||||||
 | 
					        <ImageView
 | 
				
			||||||
 | 
					            android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					            android:layout_gravity="bottom|center_horizontal"
 | 
				
			||||||
 | 
					            android:contentDescription="@null"
 | 
				
			||||||
 | 
					            android:src="@drawable/img_live" />
 | 
				
			||||||
 | 
					    </FrameLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- 텍스트 컨테이너 -->
 | 
				
			||||||
 | 
					    <LinearLayout
 | 
				
			||||||
 | 
					        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					        android:orientation="vertical">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <TextView
 | 
				
			||||||
 | 
					            android:id="@+id/tv_nickname"
 | 
				
			||||||
 | 
					            android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					            android:ellipsize="end"
 | 
				
			||||||
 | 
					            android:fontFamily="@font/pretendard_regular"
 | 
				
			||||||
 | 
					            android:maxLines="2"
 | 
				
			||||||
 | 
					            android:textColor="@android:color/white"
 | 
				
			||||||
 | 
					            android:textSize="18sp"
 | 
				
			||||||
 | 
					            tools:text="네대로 마자로" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <TextView
 | 
				
			||||||
 | 
					            android:id="@+id/tv_title"
 | 
				
			||||||
 | 
					            android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					            android:layout_marginTop="4dp"
 | 
				
			||||||
 | 
					            android:ellipsize="end"
 | 
				
			||||||
 | 
					            android:fontFamily="@font/pretendard_regular"
 | 
				
			||||||
 | 
					            android:maxLines="2"
 | 
				
			||||||
 | 
					            android:textColor="@android:color/white"
 | 
				
			||||||
 | 
					            android:textSize="16sp"
 | 
				
			||||||
 | 
					            tools:text="네대로 마자로" />
 | 
				
			||||||
 | 
					    </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</LinearLayout>
 | 
				
			||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <color name="color_80d8ff">#80D8FF</color>
 | 
					    <color name="color_80d8ff">#80D8FF</color>
 | 
				
			||||||
    <color name="color_1313bc">#1313BC</color>
 | 
					    <color name="color_1313bc">#1313BC</color>
 | 
				
			||||||
 | 
					    <color name="color_131313">#131313</color>
 | 
				
			||||||
    <color name="color_9970ff">#9970FF</color>
 | 
					    <color name="color_9970ff">#9970FF</color>
 | 
				
			||||||
    <color name="color_eeeeee">#EEEEEE</color>
 | 
					    <color name="color_eeeeee">#EEEEEE</color>
 | 
				
			||||||
    <color name="color_777777">#777777</color>
 | 
					    <color name="color_777777">#777777</color>
 | 
				
			||||||
@@ -130,4 +131,5 @@
 | 
				
			|||||||
    <color name="color_cc777777">#CC777777</color>
 | 
					    <color name="color_cc777777">#CC777777</color>
 | 
				
			||||||
    <color name="color_ec3aa6">#EC3AA6</color>
 | 
					    <color name="color_ec3aa6">#EC3AA6</color>
 | 
				
			||||||
    <color name="color_7849bc">#7849BC</color>
 | 
					    <color name="color_7849bc">#7849BC</color>
 | 
				
			||||||
 | 
					    <color name="color_607d8b">#607D8B</color>
 | 
				
			||||||
</resources>
 | 
					</resources>
 | 
				
			||||||
 
 | 
				
			|||||||