diff --git a/app/src/main/java/com/woka/WokaApp.kt b/app/src/main/java/com/woka/WokaApp.kt index 5c09f96..94d55ba 100644 --- a/app/src/main/java/com/woka/WokaApp.kt +++ b/app/src/main/java/com/woka/WokaApp.kt @@ -2,7 +2,6 @@ package com.woka import android.annotation.SuppressLint import android.app.Application -import android.util.Log import com.jwplayer.pub.api.license.LicenseUtil import com.onesignal.OneSignal import com.woka.database.AppDatabase @@ -10,7 +9,6 @@ import com.woka.streamingurls.StreamingUrlRepository import com.woka.userPreference.UserPreference import com.woka.utils.JW_PLAYER_LICENSE import com.woka.utils.ONESIGNAL_APP_ID -import com.woka.utils.TAG import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/woka/audiobooks/views/AudioBooksActivity.kt b/app/src/main/java/com/woka/audiobooks/views/AudioBooksActivity.kt index 81641a2..ca2911b 100644 --- a/app/src/main/java/com/woka/audiobooks/views/AudioBooksActivity.kt +++ b/app/src/main/java/com/woka/audiobooks/views/AudioBooksActivity.kt @@ -29,7 +29,7 @@ import com.woka.databinding.ActivityAudioBooksBinding import com.woka.databinding.DialogModuleShowerBinding import com.woka.networking.ApiResult import com.woka.players.models.VideoPlayList -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import com.woka.players.views.PlayerActivity import com.woka.userPreference.UserType import com.woka.utils.NoSignInDialog @@ -377,7 +377,7 @@ class AudioBooksActivity : WokaBaseActivity() { .build() ) }, - mutableListOf(VideoViewRequestData( + mutableListOf(VideoViewData( audioBookData.id, ContentType.AUDIO )) diff --git a/app/src/main/java/com/woka/database/helpers/RemoteSync.kt b/app/src/main/java/com/woka/database/helpers/RemoteSync.kt index 1d20627..3c79852 100644 --- a/app/src/main/java/com/woka/database/helpers/RemoteSync.kt +++ b/app/src/main/java/com/woka/database/helpers/RemoteSync.kt @@ -7,11 +7,8 @@ import com.woka.database.remote.models.RemoteClickEvent import com.woka.networking.ApiResult import com.woka.networking.RetrofitHelper import com.woka.networking.RetrofitHelper.handleApiCall -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -private const val SYNC_BATCH_COUNT = 10 +private const val SYNC_BATCH_COUNT = 15 object RemoteSync { @@ -20,47 +17,45 @@ object RemoteSync { private val clicksDao = appDatabase?.clicksDao() private val apiService = RetrofitHelper.getRetrofit().create(RemoteApiService::class.java) - fun syncClickEvents(){ - CoroutineScope(Dispatchers.IO).launch { - Log.d(TAG, "syncClickEvents: CLICK EVENTS SYNC CALLED") + suspend fun syncClickEvents(){ + Log.d(TAG, "syncClickEvents: CLICK EVENTS SYNC CALLED") - var roundCount = 0 + var roundCount = 0 - while (true){ - val clicksBatch = clicksDao?.getClickEventBatch(SYNC_BATCH_COUNT) + while (true){ + val clicksBatch = clicksDao?.getClickEventBatch(SYNC_BATCH_COUNT) - if (clicksDao == null || clicksBatch.isNullOrEmpty()){ - Log.d(TAG, "syncClickEvents: RECEIVED BATCH IS EMPTY") - break - } - - Log.d(TAG, "syncClickEvents: BATCH COUNT FROM DATABASE ${clicksBatch.size}") - when (val response = handleApiCall{ apiService.sendClickEvents(clicksBatch.map { RemoteClickEvent(it) })}){ - is ApiResult.Error -> { - Log.e(TAG, "syncClickEvents: BATCH SYNC FAILED due to ${response.errorMessage}", response.error) - break - } - is ApiResult.Loading -> {} - is ApiResult.Success -> { - Log.d(TAG, "syncClickEvents: BATCH SYNC IS SUCCESSFUL") - - Log.d(TAG, "syncClickEvents: DELETING SYNCED DATA FROM LOCAL DATABASE") - val deleteCount = clicksDao.deleteClickEvents(clicksBatch) - Log.d(TAG, "syncClickEvents: $deleteCount ENTRIES ARE DELETED FROM LOCAL DATABASE") - - if (deleteCount <= 0){ - Log.e(TAG, "syncClickEvents: NO ENTRIES WERE DELETED FROM LOCAL DATABASE") - } - - roundCount++ - } - } - - Log.d(TAG, "syncClickEvents: \n") + if (clicksDao == null || clicksBatch.isNullOrEmpty()){ + Log.d(TAG, "syncClickEvents: RECEIVED BATCH IS EMPTY") + break } - Log.d(TAG, "syncClickEvents: NUMBER OF ROUND : $roundCount") + Log.d(TAG, "syncClickEvents: BATCH COUNT FROM DATABASE ${clicksBatch.size}") + when (val response = handleApiCall{ apiService.sendClickEvents(clicksBatch.map { RemoteClickEvent(it) })}){ + is ApiResult.Error -> { + Log.e(TAG, "syncClickEvents: BATCH SYNC FAILED due to ${response.errorMessage}", response.error) + break + } + is ApiResult.Loading -> {} + is ApiResult.Success -> { + Log.d(TAG, "syncClickEvents: BATCH SYNC IS SUCCESSFUL") + + Log.d(TAG, "syncClickEvents: DELETING SYNCED DATA FROM LOCAL DATABASE") + val deleteCount = clicksDao.deleteClickEvents(clicksBatch) + Log.d(TAG, "syncClickEvents: $deleteCount ENTRIES ARE DELETED FROM LOCAL DATABASE") + + if (deleteCount <= 0){ + Log.e(TAG, "syncClickEvents: NO ENTRIES WERE DELETED FROM LOCAL DATABASE") + } + + roundCount++ + } + } + + Log.d(TAG, "syncClickEvents: \n") } + + Log.d(TAG, "syncClickEvents: NUMBER OF ROUND : $roundCount") } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/database/models/videoview/VideoViewEvent.kt b/app/src/main/java/com/woka/database/models/videoview/VideoViewEvent.kt index 1d21565..e482240 100644 --- a/app/src/main/java/com/woka/database/models/videoview/VideoViewEvent.kt +++ b/app/src/main/java/com/woka/database/models/videoview/VideoViewEvent.kt @@ -14,4 +14,4 @@ data class VideoViewEvent( @ColumnInfo(name = "post_type") val postType: Int, @ColumnInfo(name = "categoryId") val categoryId: Int, @ColumnInfo(name = "total_watch_duration") val watchDuration: Long -) +) \ No newline at end of file diff --git a/app/src/main/java/com/woka/home/fragments/Home2Fragment.kt b/app/src/main/java/com/woka/home/fragments/Home2Fragment.kt index f250f78..56f00ec 100644 --- a/app/src/main/java/com/woka/home/fragments/Home2Fragment.kt +++ b/app/src/main/java/com/woka/home/fragments/Home2Fragment.kt @@ -20,7 +20,7 @@ import com.woka.home.views.FMActivity import com.woka.karaoke.views.KaraokeActivity import com.woka.networking.ApiResult import com.woka.players.models.VideoPlayList -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import com.woka.players.views.LiveStreamPlayerActivity import com.woka.players.views.PlayerActivity import com.woka.shop.views.ShopActivity @@ -155,7 +155,7 @@ class Home2Fragment : Fragment() { .build() ) }, - mutableListOf(VideoViewRequestData( + mutableListOf(VideoViewData( 0, ContentType.TEASER )) diff --git a/app/src/main/java/com/woka/home/fragments/MyListFragment.kt b/app/src/main/java/com/woka/home/fragments/MyListFragment.kt index ef5b348..3361b19 100644 --- a/app/src/main/java/com/woka/home/fragments/MyListFragment.kt +++ b/app/src/main/java/com/woka/home/fragments/MyListFragment.kt @@ -51,7 +51,7 @@ import com.woka.karaoke.player.KaraokePlayerData import com.woka.networking.ApiResult import com.woka.onboard.views.OnboardActivity import com.woka.players.models.VideoPlayList -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import com.woka.players.views.PlayerActivity import com.woka.userPreference.UserType import com.woka.userdata.UserRepository @@ -795,7 +795,7 @@ class MyListFragment : Fragment() { ) }, mutableListOf( - VideoViewRequestData( + VideoViewData( audioBookData.id, ContentType.AUDIO ) diff --git a/app/src/main/java/com/woka/home/mylist/view/fragments/FavAudioFragment.kt b/app/src/main/java/com/woka/home/mylist/view/fragments/FavAudioFragment.kt index e3d8eea..741ac55 100644 --- a/app/src/main/java/com/woka/home/mylist/view/fragments/FavAudioFragment.kt +++ b/app/src/main/java/com/woka/home/mylist/view/fragments/FavAudioFragment.kt @@ -28,7 +28,7 @@ import com.woka.home.mylist.MyListRepository import com.woka.home.mylist.viewmodel.FavoriteViewModel import com.woka.networking.ApiResult import com.woka.players.models.VideoPlayList -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import com.woka.players.views.PlayerActivity import com.woka.utils.hide import com.woka.utils.isNetworkConnected @@ -346,7 +346,7 @@ class FavAudioFragment : Fragment() { ) }, mutableListOf( - VideoViewRequestData( + VideoViewData( audioBookData.id, ContentType.AUDIO ) diff --git a/app/src/main/java/com/woka/home/viewmodels/HomeViewModel.kt b/app/src/main/java/com/woka/home/viewmodels/HomeViewModel.kt index 0f25523..5063834 100644 --- a/app/src/main/java/com/woka/home/viewmodels/HomeViewModel.kt +++ b/app/src/main/java/com/woka/home/viewmodels/HomeViewModel.kt @@ -11,6 +11,7 @@ import androidx.media3.common.PlaybackException import androidx.media3.common.Player import androidx.media3.common.Player.Listener import androidx.media3.exoplayer.ExoPlayer +import com.woka.database.helpers.RemoteSync import com.woka.home.views.BottomNavigation.Companion.HOME import com.woka.networking.ApiResult import com.woka.userdata.UserRepository @@ -97,6 +98,7 @@ class HomeViewModel : ViewModel() { fun logout() { viewModelScope.launch { _logoutLiveData.postValue(ApiResult.Loading()) + RemoteSync.syncClickEvents() _logoutLiveData.postValue(UserRepository.logout()) } } diff --git a/app/src/main/java/com/woka/home/views/FMActivity.kt b/app/src/main/java/com/woka/home/views/FMActivity.kt index cb512dc..dbaf28e 100644 --- a/app/src/main/java/com/woka/home/views/FMActivity.kt +++ b/app/src/main/java/com/woka/home/views/FMActivity.kt @@ -15,6 +15,8 @@ import com.woka.R import com.woka.database.helpers.ClicksHelper import com.woka.database.models.ContentType import com.woka.databinding.ActivityFmactivityBinding +import com.woka.userdata.UserRepository +import com.woka.userdata.userDataModels.VideoViewRequestData import com.woka.utils.TAG import com.woka.utils.WokaBaseActivity import com.woka.utils.hide @@ -38,6 +40,9 @@ class FMActivity : WokaBaseActivity() { private val clickHelper = ClicksHelper + private var playbackStartTime: Long = 0 + private var totalPlaybackDuration: Long = 0 + @SuppressLint("SetJavaScriptEnabled") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -66,6 +71,32 @@ class FMActivity : WokaBaseActivity() { clickEvents() setObservers() + + playbackStartTime = System.currentTimeMillis() + } + + override fun onStop() { + super.onStop() + if (playbackStartTime > 0) { + val elapsed = System.currentTimeMillis() - playbackStartTime + totalPlaybackDuration += elapsed + playbackStartTime = 0 + } + + val playingDurationInSecs = Math.round(totalPlaybackDuration/1000.0) + + if (fmId > 0 && playingDurationInSecs > 0) { + UserRepository.userVideoView( + VideoViewRequestData( + fmId, + ContentType.FM.id, + playingDurationInSecs + ) + ) + + totalPlaybackDuration = 0 + playbackStartTime = System.currentTimeMillis() + } } override fun onDestroy() { diff --git a/app/src/main/java/com/woka/home/views/HomeActivity.kt b/app/src/main/java/com/woka/home/views/HomeActivity.kt index 7e81f58..fda6eec 100644 --- a/app/src/main/java/com/woka/home/views/HomeActivity.kt +++ b/app/src/main/java/com/woka/home/views/HomeActivity.kt @@ -22,11 +22,13 @@ import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import com.bumptech.glide.Glide import com.woka.BuildConfig import com.woka.R import com.woka.WokaApp.Companion.userPrefs import com.woka.database.helpers.ClicksHelper +import com.woka.database.helpers.RemoteSync import com.woka.database.models.ContentType import com.woka.databinding.ActivityHomeBinding import com.woka.home.fragments.Home1Fragment @@ -69,6 +71,7 @@ import com.woka.utils.lightStatusBar import com.woka.utils.setVisibility import com.woka.utils.show import com.woka.utils.toast +import kotlinx.coroutines.launch import kotlin.math.min class HomeActivity : WokaBaseActivity(), @@ -137,8 +140,12 @@ class HomeActivity : WokaBaseActivity(), decisionDialog.message = getString(R.string.do_you_want_to_exit_from_the_woka_app) decisionDialog.setPositiveButton(getString(R.string.yes)){ - @Suppress("DEPRECATION") - super.onBackPressed() + lifecycleScope.launch { + RemoteSync.syncClickEvents() + + @Suppress("DEPRECATION") + super.onBackPressed() + } } decisionDialog.setNegativeButton(getString(R.string.no)) diff --git a/app/src/main/java/com/woka/home/views/MoreHomeActivity.kt b/app/src/main/java/com/woka/home/views/MoreHomeActivity.kt index 8cf82d6..0befde0 100644 --- a/app/src/main/java/com/woka/home/views/MoreHomeActivity.kt +++ b/app/src/main/java/com/woka/home/views/MoreHomeActivity.kt @@ -28,7 +28,7 @@ import com.woka.modules.wokasongs.WokaSongsAdapter import com.woka.modules.wokasongs.WokaSongsRepository import com.woka.networking.ApiResult import com.woka.players.models.VideoPlayList -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import com.woka.players.views.PlayerActivity import com.woka.utils.WokaBaseActivity import com.woka.utils.hide @@ -140,7 +140,7 @@ class MoreHomeActivity : WokaBaseActivity() { ) }, mutableListOf( - VideoViewRequestData( + VideoViewData( 0, ContentType.TEASER ) diff --git a/app/src/main/java/com/woka/karaoke/player/KaraokePlayerActivity.kt b/app/src/main/java/com/woka/karaoke/player/KaraokePlayerActivity.kt index 63911e4..31bbd27 100644 --- a/app/src/main/java/com/woka/karaoke/player/KaraokePlayerActivity.kt +++ b/app/src/main/java/com/woka/karaoke/player/KaraokePlayerActivity.kt @@ -35,6 +35,8 @@ import com.woka.database.helpers.ClicksHelper import com.woka.database.models.ContentType import com.woka.databinding.ActivityKaraokePlayerrBinding import com.woka.players.models.PlayBackState +import com.woka.userdata.UserRepository +import com.woka.userdata.userDataModels.VideoViewRequestData import com.woka.utils.TAG import com.woka.utils.WokaBaseActivity import com.woka.utils.hide @@ -93,6 +95,11 @@ class KaraokePlayerActivity : WokaBaseActivity() { private lateinit var permissionLauncher: ActivityResultLauncher private lateinit var storagePermissionLauncher: ActivityResultLauncher + // user video view params + private var playbackStartTime: Long = 0 + private var totalPlaybackDuration: Long = 0 + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() @@ -150,6 +157,36 @@ class KaraokePlayerActivity : WokaBaseActivity() { } + override fun onStop() { + super.onStop() + if (playbackStartTime > 0) { + val elapsed = System.currentTimeMillis() - playbackStartTime + totalPlaybackDuration += elapsed + playbackStartTime = 0 + } + + val playingDurationInSecs = Math.round(totalPlaybackDuration/1000.0) + + karaokePlayerData?.id?.let { + if (it > 0 && playingDurationInSecs > 0) { + UserRepository.userVideoView( + VideoViewRequestData( + it, + ContentType.KARAOKE_VIDEO.id, + playingDurationInSecs + ) + ) + + totalPlaybackDuration = 0 + } + } + } + + override fun onStart() { + super.onStart() + playbackStartTime = System.currentTimeMillis() + } + override fun onDestroy() { super.onDestroy() window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) @@ -300,7 +337,7 @@ class KaraokePlayerActivity : WokaBaseActivity() { RecordingState.PLAYING_AUDIO -> { - recordBtn.text = getString(R.string.stop_recording) + recordBtn.text = getString(R.string.start_recording) recordBtn.setCompoundDrawablesWithIntrinsicBounds( R.drawable.ic_rec_mic, 0, diff --git a/app/src/main/java/com/woka/networking/RetrofitHelper.kt b/app/src/main/java/com/woka/networking/RetrofitHelper.kt index 750857a..4854d13 100644 --- a/app/src/main/java/com/woka/networking/RetrofitHelper.kt +++ b/app/src/main/java/com/woka/networking/RetrofitHelper.kt @@ -48,7 +48,7 @@ object RetrofitHelper { chain.proceed(request.build()) }) - clientBuilder.callTimeout(10, TimeUnit.SECONDS) + clientBuilder.callTimeout(20, TimeUnit.SECONDS) retrofit = Retrofit.Builder() .baseUrl(BuildConfig.WOKA_STAGINNG_BASE_URL) diff --git a/app/src/main/java/com/woka/players/PlayerApiService.kt b/app/src/main/java/com/woka/players/PlayerApiService.kt index da74cb5..d6b1bda 100644 --- a/app/src/main/java/com/woka/players/PlayerApiService.kt +++ b/app/src/main/java/com/woka/players/PlayerApiService.kt @@ -1,7 +1,7 @@ package com.woka.players import com.woka.networking.ApiResponse -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import retrofit2.Response import retrofit2.http.Body import retrofit2.http.POST @@ -9,6 +9,6 @@ import retrofit2.http.POST interface PlayerApiService { @POST("user_video_view") - suspend fun userVideoView(@Body requestData: VideoViewRequestData): Response> + suspend fun userVideoView(@Body requestData: VideoViewData): Response> } \ No newline at end of file diff --git a/app/src/main/java/com/woka/players/models/VideoPlayList.kt b/app/src/main/java/com/woka/players/models/VideoPlayList.kt index fa923f2..f2ef18b 100644 --- a/app/src/main/java/com/woka/players/models/VideoPlayList.kt +++ b/app/src/main/java/com/woka/players/models/VideoPlayList.kt @@ -7,5 +7,5 @@ import kotlinx.parcelize.Parcelize @Parcelize data class VideoPlayList( val playlist: ArrayList, - val videoViewRequestDataList: MutableList + val videoViewRequestDataList: MutableList ): Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/woka/players/models/VideoViewRequestData.kt b/app/src/main/java/com/woka/players/models/VideoViewData.kt similarity index 79% rename from app/src/main/java/com/woka/players/models/VideoViewRequestData.kt rename to app/src/main/java/com/woka/players/models/VideoViewData.kt index 2163139..f99cf2e 100644 --- a/app/src/main/java/com/woka/players/models/VideoViewRequestData.kt +++ b/app/src/main/java/com/woka/players/models/VideoViewData.kt @@ -5,9 +5,9 @@ import com.woka.database.models.ContentType import kotlinx.parcelize.Parcelize @Parcelize -data class VideoViewRequestData( +data class VideoViewData( val id: Int?, val contentType: ContentType, - val categoryId: String? = null, + var categoryId: String? = null, var watchedDuration: String? = null ) : Parcelable diff --git a/app/src/main/java/com/woka/players/views/LiveStreamPlayerActivity.kt b/app/src/main/java/com/woka/players/views/LiveStreamPlayerActivity.kt index 76c6599..4a30896 100644 --- a/app/src/main/java/com/woka/players/views/LiveStreamPlayerActivity.kt +++ b/app/src/main/java/com/woka/players/views/LiveStreamPlayerActivity.kt @@ -22,12 +22,14 @@ import com.woka.database.models.ContentType import com.woka.databinding.ActivityLiveStreamPlayerBinding import com.woka.players.KeepScreenOnHandler import com.woka.players.models.PlayBackState +import com.woka.userdata.UserRepository +import com.woka.userdata.userDataModels.VideoViewRequestData import com.woka.utils.hide import com.woka.utils.show class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { - companion object{ + companion object { const val EXTRA_LIVE_STREAM_URL = "extra_live_stream_url" const val EXTRA_LIVE_STREAM_ID = "extra_live_stream_id" @@ -75,11 +77,11 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { liveTvId = intent.getIntExtra(EXTRA_LIVE_STREAM_ID, -1) - networkCallback = object : NetworkCallback(){ + networkCallback = object : NetworkCallback() { override fun onAvailable(network: Network) { super.onAvailable(network) runOnUiThread { - if (playbackState == PlayBackState.STOPPED){ + if (playbackState == PlayBackState.STOPPED) { binding.playerView.show() binding.errorView.hide() configureAndPlay() @@ -98,14 +100,32 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { } - override fun onPause() { - super.onPause() - player.pause() + override fun onStop() { + super.onStop() + if (playbackStartTime > 0) { + val elapsed = System.currentTimeMillis() - playbackStartTime + totalPlaybackDuration += elapsed + playbackStartTime = 0 + } + + val playingDurationInSecs = Math.round(totalPlaybackDuration/1000.0) + + if (liveTvId > 0 && playingDurationInSecs > 0) { + UserRepository.userVideoView( + VideoViewRequestData( + liveTvId, + ContentType.LIVE_TV.id, + playingDurationInSecs + ) + ) + + totalPlaybackDuration = 0 + } } - override fun onResume() { - super.onResume() - player.pause() + override fun onStart() { + super.onStart() + playbackStartTime = System.currentTimeMillis() } override fun onDestroy() { @@ -116,7 +136,7 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { ) } - private fun setUpPlayer(){ + private fun setUpPlayer() { player = binding.playerView.getPlayer(this) // to keep up the screen om when video is being played @@ -130,48 +150,35 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { playlist.add(playlistItem) playerConfig = PlayerConfig.Builder() - .playlist(playlist) - .autostart(true) - .build() + .playlist(playlist) + .autostart(true) + .build() } - private fun addListeners(){ + private fun addListeners() { player.addListener(EventType.PLAY, VideoPlayerEvents.OnPlayListener { playbackState = PlayBackState.PLAY binding.playerView.show() binding.errorView.hide() errorRetryCount = ERROR_RETRY_COUNT - playbackStartTime = System.currentTimeMillis() upsertClickEvent() }) player.addListener(EventType.PAUSE, VideoPlayerEvents.OnPauseListener { playbackState = PlayBackState.PAUSED - if (playbackStartTime > 0) { - val elapsed = System.currentTimeMillis() - playbackStartTime - totalPlaybackDuration += elapsed - playbackStartTime = 0 - } - upsertClickEvent() }) player.addListener(EventType.ERROR, VideoPlayerEvents.OnErrorListener { playbackState = PlayBackState.STOPPED - if (errorRetryCount > 0){ + if (errorRetryCount > 0) { errorRetryCount-- configureAndPlay() - }else{ + } else { binding.playerView.hide() binding.errorView.show() } - - if (playbackStartTime > 0) { - val elapsed = System.currentTimeMillis() - playbackStartTime - totalPlaybackDuration += elapsed - playbackStartTime = 0 - } }) (getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager).registerNetworkCallback( @@ -187,7 +194,7 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { player.setup(playerConfig) } - private fun clickEvents(){ + private fun clickEvents() { binding.apply { retryBtn.setOnClickListener { binding.playerView.show() @@ -201,7 +208,7 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { } } - private fun upsertClickEvent(){ + private fun upsertClickEvent() { if (liveTvId == -1) return clickHelper.upsertClickEvent( diff --git a/app/src/main/java/com/woka/players/views/PlayerActivity.kt b/app/src/main/java/com/woka/players/views/PlayerActivity.kt index 0b0dc17..b8b0c28 100644 --- a/app/src/main/java/com/woka/players/views/PlayerActivity.kt +++ b/app/src/main/java/com/woka/players/views/PlayerActivity.kt @@ -24,10 +24,13 @@ import com.woka.databinding.ActivityPlayerBinding import com.woka.players.KeepScreenOnHandler import com.woka.players.models.PlayBackState import com.woka.players.models.VideoPlayList -import com.woka.utils.TAG +import com.woka.userdata.UserRepository +import com.woka.userdata.userDataModels.VideoViewRequestData import com.woka.utils.hide import com.woka.utils.show +private const val TAG = "PlayerActivity_TAG" + class PlayerActivity : AppCompatActivity(), FullscreenHandler { companion object{ @@ -46,6 +49,9 @@ class PlayerActivity : AppCompatActivity(), FullscreenHandler { private var playingIndex: Int = 0 private var seekPosition: Double = 0.0 + private var playbackStartTime: Long = 0 + private var totalPlaybackDuration: Long = 0 + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() @@ -96,6 +102,41 @@ class PlayerActivity : AppCompatActivity(), FullscreenHandler { ) } + override fun onStop() { + super.onStop() + videoPlayList?.videoViewRequestDataList?.let {playlistData -> + if (playingIndex >= 0 && playingIndex < playlistData.size){ + with(playlistData[playingIndex]){ + + // user video view + if (playbackStartTime > 0) { + val elapsed = System.currentTimeMillis() - playbackStartTime + totalPlaybackDuration += elapsed + playbackStartTime = 0 + } + + val playingDurationInSecs = Math.round(totalPlaybackDuration/1000.0) + + id?.let {id -> + if (id > 0 && playingDurationInSecs > 0) { + UserRepository.userVideoView( + VideoViewRequestData( + id, + contentType.id, + playingDurationInSecs, + categoryId + ) + ) + + totalPlaybackDuration = 0 + Log.d(TAG, "onStop: API DONE $playingDurationInSecs") + } + } + } + } + } + } + private fun clickEvents(){ binding.apply { retryBtn.setOnClickListener { @@ -155,6 +196,9 @@ class PlayerActivity : AppCompatActivity(), FullscreenHandler { } } } + + Log.d(TAG, "addListeners: PLAY") + playbackStartTime = System.currentTimeMillis() }) player.addListener(EventType.PAUSE, VideoPlayerEvents.OnPauseListener { playbackState = PlayBackState.PAUSED @@ -172,6 +216,14 @@ class PlayerActivity : AppCompatActivity(), FullscreenHandler { } } } + + if (playbackStartTime > 0) { + val elapsed = System.currentTimeMillis() - playbackStartTime + totalPlaybackDuration += elapsed + playbackStartTime = 0 + } + + Log.d(TAG, "addListeners: PAUSE ${Math.round(totalPlaybackDuration/1000.0)}") }) player.addListener(EventType.ERROR, VideoPlayerEvents.OnErrorListener { if (player.position != 0.0){ @@ -180,26 +232,58 @@ class PlayerActivity : AppCompatActivity(), FullscreenHandler { playbackState = PlayBackState.STOPPED binding.playerView.hide() binding.errorView.show() - }) - player.addListener(EventType.PLAYLIST_ITEM, VideoPlayerEvents.OnPlaylistItemListener { - playingIndex = it.index - - videoPlayList?.videoViewRequestDataList?.let {playlistData -> - if (playingIndex >= 0 && playingIndex < playlistData.size){ - with(playlistData[playingIndex]){ - ClicksHelper.upsertClickEvent( - contentType, - id, - categoryId - ) - } - } + if (playbackStartTime > 0) { + val elapsed = System.currentTimeMillis() - playbackStartTime + totalPlaybackDuration += elapsed + playbackStartTime = 0 } }) - player.addListener(EventType.SEEK, VideoPlayerEvents.OnSeekListener { - Log.d(TAG, "addListeners: ") + player.addListener(EventType.PLAYLIST_ITEM, VideoPlayerEvents.OnPlaylistItemListener { + if (playingIndex != it.index){ + videoPlayList?.videoViewRequestDataList?.let {playlistData -> + if (playingIndex >= 0 && playingIndex < playlistData.size){ + with(playlistData[playingIndex]){ + + // user video view + if (playbackStartTime > 0) { + val elapsed = System.currentTimeMillis() - playbackStartTime + totalPlaybackDuration += elapsed + playbackStartTime = 0 + } + + val playingDurationInSecs = Math.round(totalPlaybackDuration/1000.0) + + id?.let {id -> + if (id > 0 && playingDurationInSecs > 0) { + UserRepository.userVideoView( + VideoViewRequestData( + id, + contentType.id, + playingDurationInSecs, + categoryId + ) + ) + } + } + + // resetting data for new video + totalPlaybackDuration = 0 + Log.d(TAG, "onStop: API DONE $playingDurationInSecs") + + // clicks event + ClicksHelper.upsertClickEvent( + contentType, + id, + categoryId + ) + } + } + } + } + + playingIndex = it.index }) (getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager).registerNetworkCallback( diff --git a/app/src/main/java/com/woka/userdata/UserApiService.kt b/app/src/main/java/com/woka/userdata/UserApiService.kt index 408f9f7..dfaf06e 100644 --- a/app/src/main/java/com/woka/userdata/UserApiService.kt +++ b/app/src/main/java/com/woka/userdata/UserApiService.kt @@ -4,6 +4,7 @@ import com.woka.home.mylist.models.MyListResponse import com.woka.home.notifications.models.NotificationData import com.woka.networking.ApiResponse import com.woka.userdata.userDataModels.UserDataResponse +import com.woka.userdata.userDataModels.VideoViewRequestData import okhttp3.FormBody import retrofit2.Response import retrofit2.http.Body @@ -29,4 +30,7 @@ interface UserApiService { @POST("v2/favourite_listing") suspend fun getMyFavList(@Body formBody: FormBody): Response> + + @POST("user_video_view") + suspend fun userVideoView(@Body videoViewRequestData: VideoViewRequestData): Response> } \ No newline at end of file diff --git a/app/src/main/java/com/woka/userdata/UserRepository.kt b/app/src/main/java/com/woka/userdata/UserRepository.kt index 2bde242..e9bc666 100644 --- a/app/src/main/java/com/woka/userdata/UserRepository.kt +++ b/app/src/main/java/com/woka/userdata/UserRepository.kt @@ -2,10 +2,14 @@ package com.woka.userdata import com.woka.home.mylist.models.MyListResponse import com.woka.home.notifications.models.NotificationData -import com.woka.userdata.userDataModels.UserDataResponse import com.woka.networking.ApiResult import com.woka.networking.RetrofitHelper import com.woka.networking.RetrofitHelper.handleApiCall +import com.woka.userdata.userDataModels.UserDataResponse +import com.woka.userdata.userDataModels.VideoViewRequestData +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import okhttp3.FormBody object UserRepository { @@ -61,4 +65,12 @@ object UserRepository { ) } } + + fun userVideoView(videoViewRequestData: VideoViewRequestData){ + CoroutineScope(Dispatchers.IO).launch { + handleApiCall { + userApiService.userVideoView(videoViewRequestData) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/userdata/userDataModels/VideoViewRequestData.kt b/app/src/main/java/com/woka/userdata/userDataModels/VideoViewRequestData.kt new file mode 100644 index 0000000..d02da52 --- /dev/null +++ b/app/src/main/java/com/woka/userdata/userDataModels/VideoViewRequestData.kt @@ -0,0 +1,9 @@ +package com.woka.userdata.userDataModels + +data class VideoViewRequestData( + val post_id: Int, + val post_type: Int, + val total_watched_duration: Long, + val category_id: String? = null, + val device_type: Int = 1 +) diff --git a/app/src/main/java/com/woka/webseries/viewmodel/WebSeriesViewModel.kt b/app/src/main/java/com/woka/webseries/viewmodel/WebSeriesViewModel.kt index eda9416..2c5dfa2 100644 --- a/app/src/main/java/com/woka/webseries/viewmodel/WebSeriesViewModel.kt +++ b/app/src/main/java/com/woka/webseries/viewmodel/WebSeriesViewModel.kt @@ -9,7 +9,7 @@ import com.woka.database.models.ContentType import com.woka.modules.categorymodels.CategoriesResponse import com.woka.networking.ApiResult import com.woka.players.models.VideoPlayList -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import com.woka.utils.PagingData import com.woka.webseries.WebSeriesRepository import com.woka.webseries.models.ContinueEpisodeResponse @@ -269,9 +269,10 @@ class WebSeriesViewModel : ViewModel() { ) currentPlayListHin.videoViewRequestDataList.add( - VideoViewRequestData( + VideoViewData( episode.id, - ContentType.EPISODE + ContentType.EPISODE, + "18" ) ) } @@ -287,9 +288,10 @@ class WebSeriesViewModel : ViewModel() { ) currentPlayListEng.videoViewRequestDataList.add( - VideoViewRequestData( + VideoViewData( episode.id, - ContentType.EPISODE + ContentType.EPISODE, + "1" ) ) } @@ -376,9 +378,10 @@ class WebSeriesViewModel : ViewModel() { ) currentPlayListHin.videoViewRequestDataList.add( - VideoViewRequestData( + VideoViewData( teaser.id, - ContentType.TEASER + ContentType.EPISODE, + "18" ) ) } @@ -394,9 +397,10 @@ class WebSeriesViewModel : ViewModel() { ) currentPlayListEng.videoViewRequestDataList.add( - VideoViewRequestData( + VideoViewData( teaser.id, - ContentType.TEASER + ContentType.EPISODE, + "1" ) ) } diff --git a/app/src/main/java/com/woka/webseries/views/fragments/WebSeriesFragment.kt b/app/src/main/java/com/woka/webseries/views/fragments/WebSeriesFragment.kt index c8a6248..64acd73 100644 --- a/app/src/main/java/com/woka/webseries/views/fragments/WebSeriesFragment.kt +++ b/app/src/main/java/com/woka/webseries/views/fragments/WebSeriesFragment.kt @@ -27,7 +27,7 @@ import com.woka.databinding.DialogContinueEpisodeBinding import com.woka.databinding.FragmentWebSeriesBinding import com.woka.networking.ApiResult import com.woka.players.models.VideoPlayList -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import com.woka.players.views.PlayerActivity import com.woka.players.views.PlayerActivity.Companion.EXTRA_PLAY_INDEX import com.woka.players.views.PlayerActivity.Companion.EXTRA_PLAY_LIST @@ -144,7 +144,7 @@ class WebSeriesFragment : Fragment() { ) }, mutableListOf( - VideoViewRequestData( + VideoViewData( 0, ContentType.TEASER ) @@ -256,7 +256,7 @@ class WebSeriesFragment : Fragment() { binding.categorySpinner.setSelection(viewModel.selectedCategoryPos) loadShowData() - if (userPrefs?.userType != UserType.GUEST && !viewModel.continueWatchLiveData.isInitialized) { + if (userPrefs?.userType != UserType.GUEST) { viewModel.loadContinueWatching() } } @@ -277,7 +277,7 @@ class WebSeriesFragment : Fragment() { if (continueWatchList.isNotEmpty()) { binding.rvContinueWatch.show() binding.continueWatchTxt.show() - continueWatchAdapter.submitList(continueWatchList.reversed()) + continueWatchAdapter.submitList(continueWatchList) } else { binding.rvContinueWatch.hide() binding.continueWatchTxt.hide() @@ -450,7 +450,7 @@ class WebSeriesFragment : Fragment() { ) videoPlayList.videoViewRequestDataList.add( - VideoViewRequestData( + VideoViewData( episodeData.id, ContentType.EPISODE, "18" @@ -468,7 +468,7 @@ class WebSeriesFragment : Fragment() { ) videoPlayList.videoViewRequestDataList.add( - VideoViewRequestData( + VideoViewData( episodeData.id, ContentType.EPISODE, "1" diff --git a/app/src/main/java/com/woka/webseries/views/fragments/WebShowFragment.kt b/app/src/main/java/com/woka/webseries/views/fragments/WebShowFragment.kt index 9b4a520..5a8baff 100644 --- a/app/src/main/java/com/woka/webseries/views/fragments/WebShowFragment.kt +++ b/app/src/main/java/com/woka/webseries/views/fragments/WebShowFragment.kt @@ -27,7 +27,7 @@ import com.woka.databinding.DialogEpisodeBinding import com.woka.databinding.FragmentWebShowBinding import com.woka.networking.ApiResult import com.woka.players.models.VideoPlayList -import com.woka.players.models.VideoViewRequestData +import com.woka.players.models.VideoViewData import com.woka.players.views.PlayerActivity import com.woka.userPreference.UserType import com.woka.utils.NoSignInDialog @@ -285,9 +285,10 @@ class WebShowFragment : Fragment(), TabLayout.OnTabSelectedListener { } val videoPlayList = VideoPlayList(ArrayList(), mutableListOf( - VideoViewRequestData( + VideoViewData( seasonData.id, - ContentType.SEASON + ContentType.EPISODE, + categoryId ) )) videoPlayList.playlist.add(playlistItem.build()) diff --git a/app/src/main/java/com/woka/wokagames/playerr/GamePlayerActivity.kt b/app/src/main/java/com/woka/wokagames/playerr/GamePlayerActivity.kt index 7fdbc40..2dcccf3 100644 --- a/app/src/main/java/com/woka/wokagames/playerr/GamePlayerActivity.kt +++ b/app/src/main/java/com/woka/wokagames/playerr/GamePlayerActivity.kt @@ -14,6 +14,8 @@ import com.woka.R import com.woka.database.helpers.ClicksHelper import com.woka.database.models.ContentType import com.woka.databinding.ActivityGamePlayerBinding +import com.woka.userdata.UserRepository +import com.woka.userdata.userDataModels.VideoViewRequestData import com.woka.utils.DecisionDialog import com.woka.utils.WokaBaseActivity @@ -30,6 +32,9 @@ class GamePlayerActivity : WokaBaseActivity() { private var clicksCount = 0 + private var playbackStartTime: Long = 0 + private var totalPlaybackDuration: Long = 0 + @SuppressLint("ClickableViewAccessibility") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -64,14 +69,36 @@ class GamePlayerActivity : WokaBaseActivity() { } } - override fun onStart() { - super.onStart() - window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) - } - override fun onStop() { super.onStop() window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + if (playbackStartTime > 0) { + val elapsed = System.currentTimeMillis() - playbackStartTime + totalPlaybackDuration += elapsed + playbackStartTime = 0 + } + + val playingDurationInSecs = Math.round(totalPlaybackDuration/1000.0) + + gamePlayerData?.id?.let { + if (it > 0 && playingDurationInSecs > 0) { + UserRepository.userVideoView( + VideoViewRequestData( + it, + ContentType.GAME.id, + playingDurationInSecs + ) + ) + + totalPlaybackDuration = 0 + } + } + } + + override fun onStart() { + super.onStart() + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + playbackStartTime = System.currentTimeMillis() } override fun onResume() { @@ -89,6 +116,20 @@ class GamePlayerActivity : WokaBaseActivity() { binding.webView.destroy() ClicksHelper.upsertClickEvent(ContentType.GAME, gamePlayerData?.id, null, clicksCount) + + val playingDurationInSecs = totalPlaybackDuration / 1000 + + gamePlayerData?.id?.let { + if (it > 0 && playingDurationInSecs > 0) { + UserRepository.userVideoView( + VideoViewRequestData( + it, + ContentType.GAME.id, + playingDurationInSecs + ) + ) + } + } } @SuppressLint("SetJavaScriptEnabled") diff --git a/app/src/main/res/layout/layout_bottom_nav.xml b/app/src/main/res/layout/layout_bottom_nav.xml index d604f06..f7da534 100644 --- a/app/src/main/res/layout/layout_bottom_nav.xml +++ b/app/src/main/res/layout/layout_bottom_nav.xml @@ -41,6 +41,7 @@ android:layout_height="@dimen/_20ssp" android:contentDescription="@string/image" android:src="@drawable/ic_home_bn" + android:scaleType="fitXY" app:tint="@android:color/darker_gray" />