feat: 라이브 30분 연속 청취시 트래킹 API 호출 기능 추가
This commit is contained in:
		@@ -35,8 +35,8 @@ android {
 | 
				
			|||||||
        applicationId "kr.co.vividnext.sodalive"
 | 
					        applicationId "kr.co.vividnext.sodalive"
 | 
				
			||||||
        minSdk 23
 | 
					        minSdk 23
 | 
				
			||||||
        targetSdk 34
 | 
					        targetSdk 34
 | 
				
			||||||
        versionCode 165
 | 
					        versionCode 167
 | 
				
			||||||
        versionName "1.36.0"
 | 
					        versionName "1.37.0"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    buildTypes {
 | 
					    buildTypes {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							@@ -237,3 +237,5 @@
 | 
				
			|||||||
-dontwarn org.bouncycastle.jsse.**
 | 
					-dontwarn org.bouncycastle.jsse.**
 | 
				
			||||||
-dontwarn org.conscrypt.*
 | 
					-dontwarn org.conscrypt.*
 | 
				
			||||||
-dontwarn org.openjsse.**
 | 
					-dontwarn org.openjsse.**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-keep interface kr.co.vividnext.sodalive.tracking.UserEventApi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.settings.terms.TermsViewModel
 | 
				
			||||||
import kr.co.vividnext.sodalive.tracking.AdTrackingApi
 | 
					import kr.co.vividnext.sodalive.tracking.AdTrackingApi
 | 
				
			||||||
import kr.co.vividnext.sodalive.tracking.AdTrackingRepository
 | 
					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.UserApi
 | 
				
			||||||
import kr.co.vividnext.sodalive.user.UserRepository
 | 
					import kr.co.vividnext.sodalive.user.UserRepository
 | 
				
			||||||
import kr.co.vividnext.sodalive.user.UserViewModel
 | 
					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(), CanTempApi::class.java) }
 | 
				
			||||||
        single { ApiBuilder().build(get(), AuthApi::class.java) }
 | 
					        single { ApiBuilder().build(get(), AuthApi::class.java) }
 | 
				
			||||||
        single { ApiBuilder().build(get(), UserApi::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(), MenuApi::class.java) }
 | 
				
			||||||
        single { ApiBuilder().build(get(), LiveApi::class.java) }
 | 
					        single { ApiBuilder().build(get(), LiveApi::class.java) }
 | 
				
			||||||
        single { ApiBuilder().build(get(), TermsApi::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 { LiveRoomCreateViewModel(get()) }
 | 
				
			||||||
        viewModel { LiveTagViewModel(get()) }
 | 
					        viewModel { LiveTagViewModel(get()) }
 | 
				
			||||||
        viewModel { LiveRoomEditViewModel(get()) }
 | 
					        viewModel { LiveRoomEditViewModel(get()) }
 | 
				
			||||||
        viewModel { LiveRoomViewModel(get(), get(), get(), get()) }
 | 
					        viewModel { LiveRoomViewModel(get(), get(), get(), get(), get()) }
 | 
				
			||||||
        viewModel { LiveRoomDonationMessageViewModel(get()) }
 | 
					        viewModel { LiveRoomDonationMessageViewModel(get()) }
 | 
				
			||||||
        viewModel { ExplorerViewModel(get()) }
 | 
					        viewModel { ExplorerViewModel(get()) }
 | 
				
			||||||
        viewModel { UserProfileViewModel(get(), get(), get()) }
 | 
					        viewModel { UserProfileViewModel(get(), get(), get()) }
 | 
				
			||||||
@@ -369,6 +372,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
				
			|||||||
        factory { OriginalAudioDramaContentAllRepository(get()) }
 | 
					        factory { OriginalAudioDramaContentAllRepository(get()) }
 | 
				
			||||||
        factory { AdTrackingRepository(get()) }
 | 
					        factory { AdTrackingRepository(get()) }
 | 
				
			||||||
        factory { SearchRepository(get()) }
 | 
					        factory { SearchRepository(get()) }
 | 
				
			||||||
 | 
					        factory { UserEventRepository(get()) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val moduleList = listOf(
 | 
					    private val moduleList = listOf(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,6 +58,9 @@ import io.agora.rtm.RtmChannelMember
 | 
				
			|||||||
import io.agora.rtm.RtmClientListener
 | 
					import io.agora.rtm.RtmClientListener
 | 
				
			||||||
import io.agora.rtm.RtmMessage
 | 
					import io.agora.rtm.RtmMessage
 | 
				
			||||||
import io.agora.rtm.RtmMessageType
 | 
					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 kotlinx.coroutines.launch
 | 
				
			||||||
import kr.co.vividnext.sodalive.R
 | 
					import kr.co.vividnext.sodalive.R
 | 
				
			||||||
import kr.co.vividnext.sodalive.agora.Agora
 | 
					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.report.UserReportDialog
 | 
				
			||||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
 | 
					import kr.co.vividnext.sodalive.settings.notification.MemberRole
 | 
				
			||||||
import org.koin.android.ext.android.inject
 | 
					import org.koin.android.ext.android.inject
 | 
				
			||||||
 | 
					import java.util.concurrent.TimeUnit
 | 
				
			||||||
import java.util.regex.Pattern
 | 
					import java.util.regex.Pattern
 | 
				
			||||||
import kotlin.random.Random
 | 
					import kotlin.random.Random
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1888,6 +1892,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
 | 
				
			|||||||
                    startNoChatting()
 | 
					                    startNoChatting()
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                setHeartButtonPosition()
 | 
					                setHeartButtonPosition()
 | 
				
			||||||
 | 
					                startPeriodicPlaybackValidation()
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            rtmChannelJoinFail = {
 | 
					            rtmChannelJoinFail = {
 | 
				
			||||||
                agoraConnectFail()
 | 
					                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 {
 | 
					    companion object {
 | 
				
			||||||
        private const val NO_CHATTING_TIME = 180L
 | 
					        private const val NO_CHATTING_TIME = 180L
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,12 @@ import androidx.lifecycle.MutableLiveData
 | 
				
			|||||||
import com.google.gson.Gson
 | 
					import com.google.gson.Gson
 | 
				
			||||||
import com.orhanobut.logger.Logger
 | 
					import com.orhanobut.logger.Logger
 | 
				
			||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
 | 
					import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
 | 
				
			||||||
 | 
					import io.reactivex.rxjava3.core.Single
 | 
				
			||||||
import io.reactivex.rxjava3.schedulers.Schedulers
 | 
					import io.reactivex.rxjava3.schedulers.Schedulers
 | 
				
			||||||
import kotlinx.coroutines.sync.Mutex
 | 
					import kotlinx.coroutines.sync.Mutex
 | 
				
			||||||
import kotlinx.coroutines.sync.withLock
 | 
					import kotlinx.coroutines.sync.withLock
 | 
				
			||||||
import kr.co.vividnext.sodalive.base.BaseViewModel
 | 
					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.SharedPreferenceManager
 | 
				
			||||||
import kr.co.vividnext.sodalive.common.Utils
 | 
					import kr.co.vividnext.sodalive.common.Utils
 | 
				
			||||||
import kr.co.vividnext.sodalive.live.LiveRepository
 | 
					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.ReportRepository
 | 
				
			||||||
import kr.co.vividnext.sodalive.report.ReportRequest
 | 
					import kr.co.vividnext.sodalive.report.ReportRequest
 | 
				
			||||||
import kr.co.vividnext.sodalive.report.ReportType
 | 
					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 kr.co.vividnext.sodalive.user.UserRepository
 | 
				
			||||||
import okhttp3.MediaType.Companion.toMediaType
 | 
					import okhttp3.MediaType.Companion.toMediaType
 | 
				
			||||||
import okhttp3.MultipartBody
 | 
					import okhttp3.MultipartBody
 | 
				
			||||||
@@ -40,7 +44,8 @@ class LiveRoomViewModel(
 | 
				
			|||||||
    private val repository: LiveRepository,
 | 
					    private val repository: LiveRepository,
 | 
				
			||||||
    private val userRepository: UserRepository,
 | 
					    private val userRepository: UserRepository,
 | 
				
			||||||
    private val reportRepository: ReportRepository,
 | 
					    private val reportRepository: ReportRepository,
 | 
				
			||||||
    private val rouletteRepository: RouletteRepository
 | 
					    private val rouletteRepository: RouletteRepository,
 | 
				
			||||||
 | 
					    private val userEventRepository: UserEventRepository
 | 
				
			||||||
) : BaseViewModel() {
 | 
					) : BaseViewModel() {
 | 
				
			||||||
    private val _roomInfoLiveData = MutableLiveData<GetRoomInfoResponse>()
 | 
					    private val _roomInfoLiveData = MutableLiveData<GetRoomInfoResponse>()
 | 
				
			||||||
    val roomInfoLiveData: LiveData<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> {
 | 
					    private fun calculatePercentages(options: List<RouletteItem>): List<RoulettePreviewItem> {
 | 
				
			||||||
        val updatedOptions = options.map { option ->
 | 
					        val updatedOptions = options.map { option ->
 | 
				
			||||||
            RoulettePreviewItem(
 | 
					            RoulettePreviewItem(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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>>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user