fix(live-room): 무료 라이브 라이트 팝업 노출 조건을 추가한다
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -71,6 +71,15 @@ import com.bumptech.glide.request.target.Target
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.orbitalsonic.waterwave.WaterWaveView
|
import com.orbitalsonic.waterwave.WaterWaveView
|
||||||
import com.orhanobut.logger.Logger
|
import com.orhanobut.logger.Logger
|
||||||
|
import droom.daro.core.adunit.DaroLightPopupAdUnit
|
||||||
|
import droom.daro.core.listener.DaroLightPopupAdListener
|
||||||
|
import droom.daro.core.listener.DaroLightPopupAdLoaderListener
|
||||||
|
import droom.daro.core.model.DaroAdDisplayFailError
|
||||||
|
import droom.daro.core.model.DaroAdInfo
|
||||||
|
import droom.daro.core.model.DaroAdLoadError
|
||||||
|
import droom.daro.core.model.DaroLightPopupAd
|
||||||
|
import droom.daro.core.model.DaroLightPopupAdOptions
|
||||||
|
import droom.daro.loader.DaroLightPopupAdLoader
|
||||||
import io.agora.rtc2.ClientRoleOptions
|
import io.agora.rtc2.ClientRoleOptions
|
||||||
import io.agora.rtc2.IRtcEngineEventHandler
|
import io.agora.rtc2.IRtcEngineEventHandler
|
||||||
import io.agora.rtm.LinkStateEvent
|
import io.agora.rtm.LinkStateEvent
|
||||||
@@ -167,6 +176,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
private lateinit var roomInfoEditDialog: LiveRoomInfoEditDialog
|
private lateinit var roomInfoEditDialog: LiveRoomInfoEditDialog
|
||||||
private lateinit var roomUserProfileDialog: LiveRoomUserProfileDialog
|
private lateinit var roomUserProfileDialog: LiveRoomUserProfileDialog
|
||||||
|
|
||||||
|
private var daroLightPopupAdLoader: DaroLightPopupAdLoader? = null
|
||||||
|
private var daroLightPopupAd: DaroLightPopupAd? = null
|
||||||
|
private var hasRequestedDaroLightPopupEligibility = false
|
||||||
|
private var hasAttemptedDaroLightPopup = false
|
||||||
|
|
||||||
private var isSpeakerMute = false
|
private var isSpeakerMute = false
|
||||||
private var isMicrophoneMute = false
|
private var isMicrophoneMute = false
|
||||||
private var isSpeaker = false
|
private var isSpeaker = false
|
||||||
@@ -454,6 +468,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
// 액티비티 종료 전에 강제 음소거 상태를 원복한다.
|
// 액티비티 종료 전에 강제 음소거 상태를 원복한다.
|
||||||
clearCapturePrivacyMuteState()
|
clearCapturePrivacyMuteState()
|
||||||
|
clearDaroLightPopupLoader()
|
||||||
|
clearDaroLightPopupAd()
|
||||||
cropper.cleanup()
|
cropper.cleanup()
|
||||||
hideKeyboard {
|
hideKeyboard {
|
||||||
viewModel.quitRoom(roomId) {
|
viewModel.quitRoom(roomId) {
|
||||||
@@ -1299,6 +1315,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
|
|
||||||
isCaptureRecordingAvailable = response.isCaptureRecordingAvailable
|
isCaptureRecordingAvailable = response.isCaptureRecordingAvailable
|
||||||
syncRoomRoleState(response)
|
syncRoomRoleState(response)
|
||||||
|
requestDaroLightPopupIfEligible()
|
||||||
syncCaptureSecurityPolicy()
|
syncCaptureSecurityPolicy()
|
||||||
binding.tvChatFreezeSwitch.visibility = if (isHost) {
|
binding.tvChatFreezeSwitch.visibility = if (isHost) {
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
@@ -4275,9 +4292,112 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun requestDaroLightPopupIfEligible() {
|
||||||
|
if (hasRequestedDaroLightPopupEligibility || isHost) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hasRequestedDaroLightPopupEligibility = true
|
||||||
|
|
||||||
|
if (DARO_LIGHT_POPUP_AD_UNIT_KEY.isBlank()) {
|
||||||
|
Logger.w("Daro light popup skipped because ad unit key is blank.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.getRoomPriceForDaroLightPopup(roomId = roomId) { roomPrice ->
|
||||||
|
val resolvedRoomPrice = roomPrice ?: return@getRoomPriceForDaroLightPopup
|
||||||
|
if (
|
||||||
|
!shouldAttemptLiveRoomDaroLightPopup(
|
||||||
|
isHost = isHost,
|
||||||
|
roomPrice = resolvedRoomPrice,
|
||||||
|
hasAttemptedPopup = hasAttemptedDaroLightPopup
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return@getRoomPriceForDaroLightPopup
|
||||||
|
}
|
||||||
|
|
||||||
|
hasAttemptedDaroLightPopup = true
|
||||||
|
loadDaroLightPopup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadDaroLightPopup() {
|
||||||
|
clearDaroLightPopupLoader()
|
||||||
|
clearDaroLightPopupAd()
|
||||||
|
|
||||||
|
val adUnit = DaroLightPopupAdUnit(
|
||||||
|
key = DARO_LIGHT_POPUP_AD_UNIT_KEY,
|
||||||
|
placement = DARO_LIGHT_POPUP_PLACEMENT,
|
||||||
|
options = DaroLightPopupAdOptions()
|
||||||
|
)
|
||||||
|
|
||||||
|
daroLightPopupAdLoader = DaroLightPopupAdLoader(
|
||||||
|
context = this,
|
||||||
|
adUnit = adUnit
|
||||||
|
).apply {
|
||||||
|
setListener(object : DaroLightPopupAdLoaderListener {
|
||||||
|
override fun onAdLoadSuccess(ad: DaroLightPopupAd, adInfo: DaroAdInfo) {
|
||||||
|
if (isFinishing || isDestroyed) {
|
||||||
|
ad.destroy()
|
||||||
|
clearDaroLightPopupLoader()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
daroLightPopupAd = ad
|
||||||
|
ad.setListener(object : DaroLightPopupAdListener {
|
||||||
|
override fun onAdImpression(adInfo: DaroAdInfo) = Unit
|
||||||
|
|
||||||
|
override fun onAdClicked(adInfo: DaroAdInfo) = Unit
|
||||||
|
|
||||||
|
override fun onShown(adInfo: DaroAdInfo) = Unit
|
||||||
|
|
||||||
|
override fun onFailedToShow(
|
||||||
|
adInfo: DaroAdInfo,
|
||||||
|
error: DaroAdDisplayFailError
|
||||||
|
) {
|
||||||
|
Logger.w(
|
||||||
|
"Daro light popup failed to show. message=${error.message}"
|
||||||
|
)
|
||||||
|
clearDaroLightPopupLoader()
|
||||||
|
clearDaroLightPopupAd()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(adInfo: DaroAdInfo) {
|
||||||
|
clearDaroLightPopupLoader()
|
||||||
|
clearDaroLightPopupAd()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ad.show(this@LiveRoomActivity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAdLoadFail(err: DaroAdLoadError) {
|
||||||
|
Logger.w(
|
||||||
|
"Daro light popup load failed. code=${err.code}, message=${err.message}"
|
||||||
|
)
|
||||||
|
clearDaroLightPopupLoader()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearDaroLightPopupLoader() {
|
||||||
|
val adLoader = daroLightPopupAdLoader ?: return
|
||||||
|
daroLightPopupAdLoader = null
|
||||||
|
adLoader.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearDaroLightPopupAd() {
|
||||||
|
val ad = daroLightPopupAd ?: return
|
||||||
|
daroLightPopupAd = null
|
||||||
|
ad.destroy()
|
||||||
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val DARO_LIGHT_POPUP_AD_UNIT_KEY = "59082e9e-de1b-4f5d-bbc3-8b4124d110d8"
|
||||||
|
private const val DARO_LIGHT_POPUP_PLACEMENT = "LiveRoomFreeListener"
|
||||||
private const val NO_CHATTING_TIME = 180L
|
private const val NO_CHATTING_TIME = 180L
|
||||||
var isForeground: Boolean = false
|
var isForeground: Boolean = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package kr.co.vividnext.sodalive.live.room
|
||||||
|
|
||||||
|
internal fun shouldAttemptLiveRoomDaroLightPopup(
|
||||||
|
isHost: Boolean,
|
||||||
|
roomPrice: Int,
|
||||||
|
hasAttemptedPopup: Boolean
|
||||||
|
): Boolean {
|
||||||
|
return !isHost && roomPrice == 0 && !hasAttemptedPopup
|
||||||
|
}
|
||||||
@@ -296,6 +296,28 @@ class LiveRoomViewModel(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getRoomPriceForDaroLightPopup(roomId: Long, onResult: (Int?) -> Unit) {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getRoomDetail(roomId, token = "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
onResult(it.data.price)
|
||||||
|
} else {
|
||||||
|
Logger.w("Daro light popup room detail unavailable. roomId=$roomId")
|
||||||
|
onResult(null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ error ->
|
||||||
|
Logger.e(error.message ?: "Daro light popup room detail request failed.")
|
||||||
|
onResult(null)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun isEqualToHostId(memberId: Int): Boolean {
|
fun isEqualToHostId(memberId: Int): Boolean {
|
||||||
return memberId == roomInfoResponse.creatorId.toInt()
|
return memberId == roomInfoResponse.creatorId.toInt()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package kr.co.vividnext.sodalive.live.room
|
||||||
|
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class LiveRoomDaroLightPopupPolicyTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `비방장 무료 라이브에서 아직 시도하지 않았으면 라이트 팝업을 노출한다`() {
|
||||||
|
assertTrue(
|
||||||
|
shouldAttemptLiveRoomDaroLightPopup(
|
||||||
|
isHost = false,
|
||||||
|
roomPrice = 0,
|
||||||
|
hasAttemptedPopup = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `방장이면 무료 라이브여도 라이트 팝업을 노출하지 않는다`() {
|
||||||
|
assertFalse(
|
||||||
|
shouldAttemptLiveRoomDaroLightPopup(
|
||||||
|
isHost = true,
|
||||||
|
roomPrice = 0,
|
||||||
|
hasAttemptedPopup = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `유료 라이브면 비방장이어도 라이트 팝업을 노출하지 않는다`() {
|
||||||
|
assertFalse(
|
||||||
|
shouldAttemptLiveRoomDaroLightPopup(
|
||||||
|
isHost = false,
|
||||||
|
roomPrice = 100,
|
||||||
|
hasAttemptedPopup = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `이미 시도한 액티비티 인스턴스에서는 다시 노출하지 않는다`() {
|
||||||
|
assertFalse(
|
||||||
|
shouldAttemptLiveRoomDaroLightPopup(
|
||||||
|
isHost = false,
|
||||||
|
roomPrice = 0,
|
||||||
|
hasAttemptedPopup = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user