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>
|
||||||
|
|||||||