feat(live): 온에어 라이브 화면을 연결한다
This commit is contained in:
@@ -113,6 +113,7 @@
|
|||||||
<activity android:name=".main.MainActivity" />
|
<activity android:name=".main.MainActivity" />
|
||||||
<activity android:name=".v2.main.MainV2Activity" />
|
<activity android:name=".v2.main.MainV2Activity" />
|
||||||
<activity android:name=".v2.creator.channel.CreatorChannelActivity" />
|
<activity android:name=".v2.creator.channel.CreatorChannelActivity" />
|
||||||
|
<activity android:name=".v2.live.onair.HomeOnAirLiveActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".v2.main.chat.dm.DmChatRoomActivity"
|
android:name=".v2.main.chat.dm.DmChatRoomActivity"
|
||||||
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
|
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
|
||||||
|
|||||||
@@ -0,0 +1,311 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.live.onair
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||||
|
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.common.ToastMessage
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityHomeOnAirLiveBinding
|
||||||
|
import kr.co.vividnext.sodalive.live.LiveViewModel
|
||||||
|
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse
|
||||||
|
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
|
||||||
|
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
|
||||||
|
import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
|
||||||
|
import kr.co.vividnext.sodalive.mypage.MyPageViewModel
|
||||||
|
import kr.co.vividnext.sodalive.mypage.auth.Auth
|
||||||
|
import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
|
||||||
|
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
|
||||||
|
import kr.co.vividnext.sodalive.settings.ContentSettingsActivity
|
||||||
|
import kr.co.vividnext.sodalive.settings.language.LanguageManager
|
||||||
|
import kr.co.vividnext.sodalive.settings.language.LocaleHelper
|
||||||
|
import kr.co.vividnext.sodalive.splash.SplashActivity
|
||||||
|
import kr.co.vividnext.sodalive.user.login.LoginActivity
|
||||||
|
import kr.co.vividnext.sodalive.v2.live.onair.model.HomeOnAirLivePageUiState
|
||||||
|
import kr.co.vividnext.sodalive.v2.live.onair.model.canEnterHomeOnAirLiveRoom
|
||||||
|
import kr.co.vividnext.sodalive.v2.live.onair.ui.HomeOnAirLiveAdapter
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
@UnstableApi
|
||||||
|
class HomeOnAirLiveActivity : BaseActivity<ActivityHomeOnAirLiveBinding>(
|
||||||
|
ActivityHomeOnAirLiveBinding::inflate
|
||||||
|
) {
|
||||||
|
private val viewModel: HomeOnAirLiveViewModel by viewModel()
|
||||||
|
private val liveViewModel: LiveViewModel by inject()
|
||||||
|
private val myPageViewModel: MyPageViewModel by inject()
|
||||||
|
private val loadingDialog: LoadingDialog by lazy { LoadingDialog(this, layoutInflater) }
|
||||||
|
private val adapter = HomeOnAirLiveAdapter { enterLiveRoom(it.roomId) }
|
||||||
|
private var isPageLoading = false
|
||||||
|
private var isLiveEntryLoading = false
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
bindData()
|
||||||
|
viewModel.loadFirstPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
binding.toolbar.tvBack.setText(R.string.live_now)
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
binding.rvHomeOnAirLive.apply {
|
||||||
|
layoutManager = LinearLayoutManager(this@HomeOnAirLiveActivity)
|
||||||
|
adapter = this@HomeOnAirLiveActivity.adapter
|
||||||
|
addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
if (dy > 0 && !recyclerView.canScrollVertically(1)) {
|
||||||
|
viewModel.loadNextPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindData() {
|
||||||
|
viewModel.onAirLiveStateLiveData.observe(this) { state ->
|
||||||
|
when (state) {
|
||||||
|
HomeOnAirLivePageUiState.Loading -> Unit
|
||||||
|
HomeOnAirLivePageUiState.Empty -> showEmpty()
|
||||||
|
is HomeOnAirLivePageUiState.Error -> showEmpty()
|
||||||
|
is HomeOnAirLivePageUiState.Content -> {
|
||||||
|
binding.rvHomeOnAirLive.isVisible = true
|
||||||
|
binding.tvHomeOnAirLiveEmpty.isVisible = false
|
||||||
|
adapter.submitItems(state.content.items)
|
||||||
|
state.content.paginationErrorMessage?.let { message ->
|
||||||
|
Toast.makeText(applicationContext, message, Toast.LENGTH_LONG).show()
|
||||||
|
viewModel.consumePaginationErrorMessage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewModel.isLoading.observe(this) { isLoading ->
|
||||||
|
isPageLoading = isLoading
|
||||||
|
updateLoadingDialog()
|
||||||
|
}
|
||||||
|
viewModel.toastLiveData.observe(this) { toastMessage ->
|
||||||
|
toastMessage?.let(::showToast)
|
||||||
|
}
|
||||||
|
liveViewModel.isLoading.observe(this) { isLoading ->
|
||||||
|
isLiveEntryLoading = isLoading
|
||||||
|
updateLoadingDialog()
|
||||||
|
}
|
||||||
|
liveViewModel.toastLiveData.observe(this) { message ->
|
||||||
|
message?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showEmpty() {
|
||||||
|
binding.rvHomeOnAirLive.isVisible = false
|
||||||
|
binding.tvHomeOnAirLiveEmpty.isVisible = true
|
||||||
|
adapter.submitItems(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enterLiveRoom(roomId: Long) {
|
||||||
|
ensureLoginAndAdultAuth(isAdult = false) {
|
||||||
|
liveViewModel.getRoomDetail(roomId) { roomDetail ->
|
||||||
|
if (!canEnterHomeOnAirLiveRoom(roomDetail)) {
|
||||||
|
Toast.makeText(applicationContext, R.string.common_error_unknown, Toast.LENGTH_LONG).show()
|
||||||
|
return@getRoomDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureLoginAndAdultAuth(isAdult = roomDetail.isAdult) {
|
||||||
|
enterLiveRoom(roomId, roomDetail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enterLiveRoom(roomId: Long, roomDetail: GetRoomDetailResponse) {
|
||||||
|
startService(
|
||||||
|
Intent(applicationContext, AudioContentPlayService::class.java).apply {
|
||||||
|
action = AudioContentPlayService.MusicAction.STOP.name
|
||||||
|
}
|
||||||
|
)
|
||||||
|
startService(
|
||||||
|
Intent(applicationContext, AudioContentPlayerService::class.java).apply {
|
||||||
|
action = "STOP_SERVICE"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val onEnterRoomSuccess = {
|
||||||
|
runOnUiThread {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, LiveRoomActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_ROOM_ID, roomId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roomDetail.manager.id == SharedPreferenceManager.userId) {
|
||||||
|
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||||
|
} else if (roomDetail.price == 0 || roomDetail.isPaid) {
|
||||||
|
if (roomDetail.isPrivateRoom) {
|
||||||
|
showPasswordDialog(roomId, can = 0, onEnterRoomSuccess = onEnterRoomSuccess)
|
||||||
|
} else {
|
||||||
|
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showPaidLiveEntryDialog(
|
||||||
|
roomId = roomId,
|
||||||
|
beginDateTimeUtc = roomDetail.beginDateTimeUtc,
|
||||||
|
price = roomDetail.price,
|
||||||
|
isPrivateRoom = roomDetail.isPrivateRoom,
|
||||||
|
onEnterRoomSuccess = onEnterRoomSuccess
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ensureLoginAndAdultAuth(isAdult: Boolean, onAuthed: () -> Unit) {
|
||||||
|
if (SharedPreferenceManager.token.isBlank()) {
|
||||||
|
showLoginActivity()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAdult) {
|
||||||
|
val isKoreanCountry = SharedPreferenceManager.countryCode.ifBlank { "KR" } == "KR"
|
||||||
|
if (isKoreanCountry && !SharedPreferenceManager.isAuth) {
|
||||||
|
SodaDialog(
|
||||||
|
activity = this,
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = getString(R.string.auth_title),
|
||||||
|
desc = getString(R.string.auth_desc_live),
|
||||||
|
confirmButtonTitle = getString(R.string.auth_go),
|
||||||
|
confirmButtonClick = { startAuthFlow() },
|
||||||
|
cancelButtonTitle = getString(R.string.cancel),
|
||||||
|
cancelButtonClick = {},
|
||||||
|
descGravity = Gravity.CENTER
|
||||||
|
).show(screenWidth)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SharedPreferenceManager.isAdultContentVisible) {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, ContentSettingsActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_SHOW_SENSITIVE_CONTENT_GUIDE, true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAuthed()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showLoginActivity() {
|
||||||
|
if (SharedPreferenceManager.token.isBlank()) {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, LoginActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_DATA, intent.extras)
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startAuthFlow() {
|
||||||
|
Auth.auth(this, this) { json ->
|
||||||
|
val bootpayResponse = Gson().fromJson(json, BootpayResponse::class.java)
|
||||||
|
val request = AuthVerifyRequest(receiptId = bootpayResponse.data.receiptId)
|
||||||
|
runOnUiThread {
|
||||||
|
myPageViewModel.authVerify(request) {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, SplashActivity::class.java).apply {
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showPasswordDialog(roomId: Long, can: Int, onEnterRoomSuccess: () -> Unit) {
|
||||||
|
LiveRoomPasswordDialog(
|
||||||
|
activity = this,
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
can = can,
|
||||||
|
confirmButtonClick = { password ->
|
||||||
|
liveViewModel.enterRoom(
|
||||||
|
roomId = roomId,
|
||||||
|
onSuccess = onEnterRoomSuccess,
|
||||||
|
password = password
|
||||||
|
)
|
||||||
|
}
|
||||||
|
).show(screenWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showPaidLiveEntryDialog(
|
||||||
|
roomId: Long,
|
||||||
|
beginDateTimeUtc: String,
|
||||||
|
price: Int,
|
||||||
|
isPrivateRoom: Boolean,
|
||||||
|
onEnterRoomSuccess: () -> Unit
|
||||||
|
) {
|
||||||
|
if (isPrivateRoom) {
|
||||||
|
showPasswordDialog(roomId, can = price, onEnterRoomSuccess = onEnterRoomSuccess)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val locale = Locale(LanguageManager.getEffectiveLanguage(this))
|
||||||
|
val wrappedContext = LocaleHelper.wrap(this)
|
||||||
|
val beginDate = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).apply {
|
||||||
|
timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
}.parse(beginDateTimeUtc) ?: return
|
||||||
|
val now = Date()
|
||||||
|
val dateFormat = SimpleDateFormat("yyyy-MM-dd, HH:mm", locale)
|
||||||
|
val diffTime = now.time - beginDate.time
|
||||||
|
val hours = (diffTime / (1000 * 60 * 60)).toInt()
|
||||||
|
val mins = (diffTime / (1000 * 60)).toInt() % 60
|
||||||
|
|
||||||
|
LivePaymentDialog(
|
||||||
|
activity = this,
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = wrappedContext.getString(R.string.live_paid_title),
|
||||||
|
startDateTime = if (hours >= 1) dateFormat.format(beginDate) else null,
|
||||||
|
nowDateTime = if (hours >= 1) dateFormat.format(now) else null,
|
||||||
|
desc = wrappedContext.getString(R.string.live_paid_desc, price),
|
||||||
|
desc2 = if (hours >= 1) wrappedContext.getString(R.string.live_paid_warning, hours, mins) else null,
|
||||||
|
confirmButtonTitle = wrappedContext.getString(R.string.live_paid_confirm),
|
||||||
|
confirmButtonClick = { liveViewModel.enterRoom(roomId, onEnterRoomSuccess) },
|
||||||
|
cancelButtonTitle = wrappedContext.getString(R.string.cancel),
|
||||||
|
cancelButtonClick = {}
|
||||||
|
).show(screenWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showToast(toastMessage: ToastMessage) {
|
||||||
|
toastMessage.message?.let { message -> showToast(message) }
|
||||||
|
?: toastMessage.resId?.let { resId -> showToast(getString(resId)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateLoadingDialog() {
|
||||||
|
if (isPageLoading || isLiveEntryLoading) {
|
||||||
|
loadingDialog.show(screenWidth)
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newIntent(context: Context): Intent = Intent(context, HomeOnAirLiveActivity::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user