feat: 라이브 30분 연속 청취시 트래킹 API 호출 기능 추가

This commit is contained in:
2025-05-17 16:57:12 +09:00
parent 1720173a16
commit 9260d271a7
8 changed files with 88 additions and 4 deletions

View File

@@ -155,6 +155,8 @@ import kr.co.vividnext.sodalive.settings.terms.TermsRepository
import kr.co.vividnext.sodalive.settings.terms.TermsViewModel
import kr.co.vividnext.sodalive.tracking.AdTrackingApi
import kr.co.vividnext.sodalive.tracking.AdTrackingRepository
import kr.co.vividnext.sodalive.tracking.UserEventApi
import kr.co.vividnext.sodalive.tracking.UserEventRepository
import kr.co.vividnext.sodalive.user.UserApi
import kr.co.vividnext.sodalive.user.UserRepository
import kr.co.vividnext.sodalive.user.UserViewModel
@@ -213,6 +215,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
single { ApiBuilder().build(get(), CanTempApi::class.java) }
single { ApiBuilder().build(get(), AuthApi::class.java) }
single { ApiBuilder().build(get(), UserApi::class.java) }
single { ApiBuilder().build(get(), UserEventApi::class.java) }
single { ApiBuilder().build(get(), MenuApi::class.java) }
single { ApiBuilder().build(get(), LiveApi::class.java) }
single { ApiBuilder().build(get(), TermsApi::class.java) }
@@ -251,7 +254,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { LiveRoomCreateViewModel(get()) }
viewModel { LiveTagViewModel(get()) }
viewModel { LiveRoomEditViewModel(get()) }
viewModel { LiveRoomViewModel(get(), get(), get(), get()) }
viewModel { LiveRoomViewModel(get(), get(), get(), get(), get()) }
viewModel { LiveRoomDonationMessageViewModel(get()) }
viewModel { ExplorerViewModel(get()) }
viewModel { UserProfileViewModel(get(), get(), get()) }
@@ -369,6 +372,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
factory { OriginalAudioDramaContentAllRepository(get()) }
factory { AdTrackingRepository(get()) }
factory { SearchRepository(get()) }
factory { UserEventRepository(get()) }
}
private val moduleList = listOf(

View File

@@ -58,6 +58,9 @@ import io.agora.rtm.RtmChannelMember
import io.agora.rtm.RtmClientListener
import io.agora.rtm.RtmMessage
import io.agora.rtm.RtmMessageType
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.launch
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.agora.Agora
@@ -100,6 +103,7 @@ import kr.co.vividnext.sodalive.report.ReportType
import kr.co.vividnext.sodalive.report.UserReportDialog
import kr.co.vividnext.sodalive.settings.notification.MemberRole
import org.koin.android.ext.android.inject
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.random.Random
@@ -1888,6 +1892,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
startNoChatting()
}
setHeartButtonPosition()
startPeriodicPlaybackValidation()
},
rtmChannelJoinFail = {
agoraConnectFail()
@@ -2303,6 +2308,24 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
}
}
private fun startPeriodicPlaybackValidation() {
compositeDisposable.add(
Observable.interval(0, 30, TimeUnit.MINUTES)
.flatMapSingle {
viewModel.trackLiveContinuousListen30()
.subscribeOn(Schedulers.io())
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ response ->
Logger.e("성공: $response")
}, { error ->
Logger.e("실패: ${error.message}")
}
)
)
}
companion object {
private const val NO_CHATTING_TIME = 180L
}

View File

@@ -6,10 +6,12 @@ import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.Utils
import kr.co.vividnext.sodalive.live.LiveRepository
@@ -28,6 +30,8 @@ import kr.co.vividnext.sodalive.live.roulette.SpinRouletteRequest
import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.report.ReportRequest
import kr.co.vividnext.sodalive.report.ReportType
import kr.co.vividnext.sodalive.tracking.UserEventRepository
import kr.co.vividnext.sodalive.tracking.UserEventType
import kr.co.vividnext.sodalive.user.UserRepository
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
@@ -40,7 +44,8 @@ class LiveRoomViewModel(
private val repository: LiveRepository,
private val userRepository: UserRepository,
private val reportRepository: ReportRepository,
private val rouletteRepository: RouletteRepository
private val rouletteRepository: RouletteRepository,
private val userEventRepository: UserEventRepository
) : BaseViewModel() {
private val _roomInfoLiveData = MutableLiveData<GetRoomInfoResponse>()
val roomInfoLiveData: LiveData<GetRoomInfoResponse>
@@ -1124,6 +1129,13 @@ class LiveRoomViewModel(
)
}
fun trackLiveContinuousListen30(): Single<ApiResponse<Any>> {
return userEventRepository.trackEvent(
eventType = UserEventType.LIVE_CONTINUOUS_LISTEN_30,
token = "Bearer ${SharedPreferenceManager.token}"
)
}
private fun calculatePercentages(options: List<RouletteItem>): List<RoulettePreviewItem> {
val updatedOptions = options.map { option ->
RoulettePreviewItem(

View File

@@ -0,0 +1,15 @@
package kr.co.vividnext.sodalive.tracking
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.common.ApiResponse
import retrofit2.http.Body
import retrofit2.http.Header
import retrofit2.http.POST
interface UserEventApi {
@POST("/user-action")
fun trackEvent(
@Body request: UserEventRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<Any>>
}

View File

@@ -0,0 +1,13 @@
package kr.co.vividnext.sodalive.tracking
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.common.ApiResponse
class UserEventRepository(private val api: UserEventApi) {
fun trackEvent(eventType: UserEventType, token: String): Single<ApiResponse<Any>> {
return api.trackEvent(
request = UserEventRequest(actionType = eventType),
authHeader = token
)
}
}

View File

@@ -0,0 +1,15 @@
package kr.co.vividnext.sodalive.tracking
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
@Keep
data class UserEventRequest(
@SerializedName("actionType") val actionType: UserEventType
)
@Keep
enum class UserEventType {
@SerializedName("LIVE_CONTINUOUS_LISTEN_30")
LIVE_CONTINUOUS_LISTEN_30
}