diff --git a/app/src/main/java/com/woka/WokaApp.kt b/app/src/main/java/com/woka/WokaApp.kt index d07320e..0d10196 100644 --- a/app/src/main/java/com/woka/WokaApp.kt +++ b/app/src/main/java/com/woka/WokaApp.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.app.Application import com.jwplayer.pub.api.license.LicenseUtil import com.woka.database.AppDatabase +import com.woka.streamingurls.StreamingUrlRepository import com.woka.userPreference.UserPreference class WokaApp: Application() { @@ -20,5 +21,7 @@ class WokaApp: Application() { LicenseUtil().setLicenseKey(this, "LkYoNusv+gSIVJIrXa5Bf59iBNlUMxeg82PM/l8JWk+cD4BE") appDatabase = AppDatabase.getInstance(applicationContext) + + StreamingUrlRepository.loadLiveStreamingUrls() } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/database/AppDatabase.kt b/app/src/main/java/com/woka/database/AppDatabase.kt index f82e4f2..4d2a830 100644 --- a/app/src/main/java/com/woka/database/AppDatabase.kt +++ b/app/src/main/java/com/woka/database/AppDatabase.kt @@ -25,7 +25,9 @@ abstract class AppDatabase : RoomDatabase(){ Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, DATABASE_NAME - ).build() + ) + .fallbackToDestructiveMigration() + .build() } abstract fun clicksDao(): ClicksDao diff --git a/app/src/main/java/com/woka/database/dao/ClicksDao.kt b/app/src/main/java/com/woka/database/dao/ClicksDao.kt index ebb86fa..95ac2c5 100644 --- a/app/src/main/java/com/woka/database/dao/ClicksDao.kt +++ b/app/src/main/java/com/woka/database/dao/ClicksDao.kt @@ -1,12 +1,43 @@ package com.woka.database.dao +import android.util.Log import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Transaction import com.woka.database.models.clicks.ClickEvent +import com.woka.database.models.clicks.ContentType +import com.woka.utils.TAG + +/* + clickId will always in the following format + ${post_type}_${post_id}_${category_id} + */ @Dao interface ClicksDao { - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun addClickEvent(vararg clickEvent: ClickEvent) + + @Query("UPDATE click_events SET clicks_count = clicks_count + 1 WHERE id = :clickId") + suspend fun updateAndGetRowCount(clickId: String): Int + + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insert(vararg clickEvent: ClickEvent) + + @Transaction + suspend fun upsertClickEvent(contentType: ContentType, postId: Int = 0, categoryId: Int = 0){ + val clickId = "${contentType.id}_${postId}_${categoryId}" + + val count = updateAndGetRowCount(clickId) + if (count == 0){ + insert( + ClickEvent( + clickId, + postId, + contentType.id, + categoryId + ) + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/database/helpers/ClicksHelper.kt b/app/src/main/java/com/woka/database/helpers/ClicksHelper.kt new file mode 100644 index 0000000..a33dc76 --- /dev/null +++ b/app/src/main/java/com/woka/database/helpers/ClicksHelper.kt @@ -0,0 +1,18 @@ +package com.woka.database.helpers + +import com.woka.WokaApp.Companion.appDatabase +import com.woka.database.dao.ClicksDao +import com.woka.database.models.clicks.ContentType +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +object ClicksHelper { + private val clicksDao: ClicksDao? = appDatabase?.clicksDao() + + fun upsertClickEvent(contentType: ContentType, postId: Int = 0, categoryId: Int = 0){ + CoroutineScope(Dispatchers.IO).launch { + clicksDao?.upsertClickEvent(contentType, postId, categoryId) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/woka/database/models/clicks/ClickEvent.kt b/app/src/main/java/com/woka/database/models/clicks/ClickEvent.kt index d400d10..dac25fd 100644 --- a/app/src/main/java/com/woka/database/models/clicks/ClickEvent.kt +++ b/app/src/main/java/com/woka/database/models/clicks/ClickEvent.kt @@ -8,10 +8,10 @@ private const val DB_TABLE_NAME = "click_events" @Entity(tableName = DB_TABLE_NAME) data class ClickEvent( - @PrimaryKey(autoGenerate = true) - @ColumnInfo(name = "id") val clickId: Int = 0, - @ColumnInfo(name = "post_id") val postId: String, - @ColumnInfo(name = "post_type") val postType: String, - @ColumnInfo(name = "categoryId") val categoryId: String?, - @ColumnInfo(name = "clicks_count") val clickCount: Int, + @PrimaryKey + @ColumnInfo(name = "id") val clickId: String, + @ColumnInfo(name = "post_id") val postId: Int, + @ColumnInfo(name = "post_type") val postType: Int, + @ColumnInfo(name = "categoryId") val categoryId: Int, + @ColumnInfo(name = "clicks_count") val clickCount: Int = 1, ) \ No newline at end of file diff --git a/app/src/main/java/com/woka/database/models/clicks/ContentType.kt b/app/src/main/java/com/woka/database/models/clicks/ContentType.kt new file mode 100644 index 0000000..c9298cd --- /dev/null +++ b/app/src/main/java/com/woka/database/models/clicks/ContentType.kt @@ -0,0 +1,20 @@ +package com.woka.database.models.clicks + +enum class ContentType(val id: Int) { + SERIES(1), + SEASON(2), + EPISODE(3), + VIDEO(4), + PAINT(5), + GAME(6), + AUDIO(7), + KARAOKE_VIDEO(8), + SHOP_PRODUCT(9), + PARENTAL_VIDEO(10), + ARTICLE(11), + LIVE_TV(12), + FM(13), + TEASER(14), + OTHERS(15), + HOME(16) +} diff --git a/app/src/main/java/com/woka/home/fragments/Home1Fragment.kt b/app/src/main/java/com/woka/home/fragments/Home1Fragment.kt index 48e190f..ddfb8ca 100644 --- a/app/src/main/java/com/woka/home/fragments/Home1Fragment.kt +++ b/app/src/main/java/com/woka/home/fragments/Home1Fragment.kt @@ -16,15 +16,10 @@ import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope -import androidx.media3.common.Player.Listener import com.bumptech.glide.Glide import com.woka.R -import com.woka.WokaApp -import com.woka.WokaApp.Companion.appDatabase import com.woka.WokaApp.Companion.userPrefs import com.woka.audiobooks.views.AudioBooksActivity -import com.woka.database.models.clicks.ClickEvent import com.woka.databinding.FragmentHome1Binding import com.woka.home.models.TimePeriod import com.woka.home.viewmodels.HomeViewModel @@ -34,19 +29,18 @@ import com.woka.karaoke.views.KaraokeActivity import com.woka.networking.ApiResult import com.woka.players.views.LiveStreamPlayerActivity import com.woka.shop.views.ShopActivity +import com.woka.streamingurls.StreamingUrlRepository import com.woka.userPreference.UserType import com.woka.userdata.userDataModels.UserDataResponse +import com.woka.utils.ProgressView import com.woka.utils.hide import com.woka.utils.scaleAnimate import com.woka.utils.show import com.woka.webseries.views.WebSeriesActivity import com.woka.wokagames.views.GamesActivity -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -class Home1Fragment : Fragment(), Listener { +class Home1Fragment : Fragment() { private lateinit var binding: FragmentHome1Binding private lateinit var viewModel: HomeViewModel @@ -60,14 +54,15 @@ class Home1Fragment : Fragment(), Listener { private var star1Animator: ValueAnimator? = null private var star2Animator: ValueAnimator? = null + private lateinit var progressView: ProgressView + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { binding = FragmentHome1Binding.inflate(inflater, container, false) - activity?.let { - viewModel = ViewModelProvider(it)[HomeViewModel::class.java] - } + viewModel = ViewModelProvider(requireActivity())[HomeViewModel::class.java] + progressView = ProgressView(requireContext()) initViews() @@ -116,11 +111,9 @@ class Home1Fragment : Fragment(), Listener { binding.playerView.hide() } } - private fun initPlayerView() { binding.playerView.player = viewModel.player binding.playerView.useController = false - viewModel.player?.addListener(this) } private fun setObservers() { @@ -154,15 +147,64 @@ class Home1Fragment : Fragment(), Listener { } } } + activity?.registerReceiver(minuteReceiver, IntentFilter(ACTION_TIME_TICK)) + + viewModel.playerReadyCallback = { + initPlayerView() + } + + StreamingUrlRepository.liveStreamLiveData.observe(viewLifecycleOwner){ + when (it){ + is ApiResult.Error -> { + progressView.hide() + binding.liveTv.setOnClickListener { + StreamingUrlRepository.loadLiveStreamingUrls() + } + } + is ApiResult.Loading -> { + progressView.show() + } + is ApiResult.Success -> { + it.data?.live_data?.let {urls -> + if (urls.isNotEmpty()){ + urls.first()?.let {liveData -> + progressView.hide() + binding.liveTv.setOnClickListener { + activity?.let {activity -> + startActivity(Intent(activity, LiveStreamPlayerActivity::class.java).apply { + putExtra( + LiveStreamPlayerActivity.EXTRA_LIVE_STREAM_ID, + liveData.id + ) + putExtra(LiveStreamPlayerActivity.EXTRA_LIVE_STREAM_URL, + liveData.live_url?.hd_url_en) + }) + } + } + } + } + } + + it.data?.live_fm_data?.let {fmData -> + binding.fmButton.setOnClickListener { + activity?.let {activity -> + startActivity(Intent(activity, FMActivity::class.java).apply { + putExtra(FMActivity.EXTRA_FM_URL, fmData.live_fm_url) + putExtra(FMActivity.EXTRA_FM_ID, fmData.id) + }) + } + } + } + } + } + } } private fun clickEvents() { binding.apply { blackImage.setOnClickListener { - activity?.let { - startActivity(Intent(it, LiveStreamPlayerActivity::class.java)) - } + liveTv.performClick() } more.setOnClickListener { @@ -174,33 +216,9 @@ class Home1Fragment : Fragment(), Listener { } } - fmButton.setOnClickListener { - activity?.let { - startActivity(Intent(it, FMActivity::class.java)) - } - } - - liveTv.setOnClickListener { - activity?.let { - startActivity(Intent(it, LiveStreamPlayerActivity::class.java)) - } - } - webSeries.setOnClickListener { activity?.let { startActivity(Intent(it, WebSeriesActivity::class.java)) - lifecycleScope.launch { - CoroutineScope(Dispatchers.IO).launch { - appDatabase?.clicksDao()?.addClickEvent( - ClickEvent( - postId = "2", - postType = "3", - categoryId = "1", - clickCount = 1 - ) - ) - } - } } } @@ -233,7 +251,6 @@ class Home1Fragment : Fragment(), Listener { override fun onDestroyView() { super.onDestroyView() activity?.unregisterReceiver(minuteReceiver) - viewModel.player?.removeListener(this) } private fun updateUserData(data: UserDataResponse?) { 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 2d19540..5ca45b5 100644 --- a/app/src/main/java/com/woka/home/fragments/Home2Fragment.kt +++ b/app/src/main/java/com/woka/home/fragments/Home2Fragment.kt @@ -20,8 +20,10 @@ import com.woka.networking.ApiResult import com.woka.players.models.VideoPlayList import com.woka.players.views.LiveStreamPlayerActivity import com.woka.players.views.PlayerActivity +import com.woka.streamingurls.StreamingUrlRepository import com.woka.userPreference.UserType import com.woka.userdata.userDataModels.UserDataResponse +import com.woka.utils.ProgressView import com.woka.utils.hide import com.woka.utils.show import com.woka.webseries.views.WebSeriesActivity @@ -33,15 +35,16 @@ class Home2Fragment : Fragment() { private lateinit var viewModel: HomeViewModel + private lateinit var progressView: ProgressView + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { binding = FragmentHome2Binding.inflate(inflater, container, false) - activity?.let { - viewModel = ViewModelProvider(it)[HomeViewModel::class.java] - } + viewModel = ViewModelProvider(requireActivity())[HomeViewModel::class.java] + progressView = ProgressView(requireContext()) iniViews() @@ -88,21 +91,7 @@ class Home2Fragment : Fragment() { private fun clickEvents(){ binding.apply { playerCard.setOnClickListener { - activity?.let { - startActivity(Intent(it, LiveStreamPlayerActivity::class.java)) - } - } - - liveTv.setOnClickListener { - activity?.let { - startActivity(Intent(it, LiveStreamPlayerActivity::class.java)) - } - } - - wokaFm.setOnClickListener { - activity?.let { - startActivity(Intent(it, FMActivity::class.java)) - } + liveTv.performClick() } webSeries.setOnClickListener { @@ -181,6 +170,52 @@ class Home2Fragment : Fragment() { } } + + viewModel.playerReadyCallback = { + initPlayerView() + } + + StreamingUrlRepository.liveStreamLiveData.observe(viewLifecycleOwner){ + when (it){ + is ApiResult.Error -> { + progressView.hide() + binding.liveTv.setOnClickListener { + StreamingUrlRepository.loadLiveStreamingUrls() + } + } + is ApiResult.Loading -> { + progressView.show() + } + is ApiResult.Success -> { + it.data?.live_data?.let {urls -> + if (urls.isNotEmpty()){ + urls.first()?.let {liveData -> + progressView.hide() + binding.liveTv.setOnClickListener { + activity?.let {activity -> + startActivity(Intent(activity, LiveStreamPlayerActivity::class.java).apply { + putExtra(LiveStreamPlayerActivity.EXTRA_LIVE_STREAM_ID, liveData.id) + putExtra(LiveStreamPlayerActivity.EXTRA_LIVE_STREAM_URL, liveData.live_url?.hd_url_en) + }) + } + } + } + } + } + + it.data?.live_fm_data?.let {fmData -> + binding.wokaFm.setOnClickListener { + activity?.let {activity -> + startActivity(Intent(activity, FMActivity::class.java).apply { + putExtra(FMActivity.EXTRA_FM_URL, fmData.live_fm_url) + putExtra(FMActivity.EXTRA_FM_ID, fmData.id) + }) + } + } + } + } + } + } } private fun updateUserData(data: UserDataResponse?) { 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 4d7bd01..0c46b0f 100644 --- a/app/src/main/java/com/woka/home/viewmodels/HomeViewModel.kt +++ b/app/src/main/java/com/woka/home/viewmodels/HomeViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.media3.common.MediaItem import androidx.media3.common.Player +import androidx.media3.common.Player.Listener import androidx.media3.exoplayer.ExoPlayer import com.woka.home.views.BottomNavigation.Companion.HOME import com.woka.networking.ApiResult @@ -30,14 +31,34 @@ class HomeViewModel : ViewModel() { val deActivateLiveData: LiveData?> get() = _deActivateLiveData + var playerReadyCallback: (() -> Unit)? = null + var player: Player? = null - fun initPlayer(context: Context) { + fun initPlayer(context: Context, liveUrl: String) { player = ExoPlayer.Builder(context).build() player?.volume = 0f - player?.setMediaItem(MediaItem.fromUri("https://d3volyx7jx7oal.cloudfront.net/master.m3u8")) + player?.addListener(object : Listener{ + override fun onPlaybackStateChanged(playbackState: Int) { + super.onPlaybackStateChanged(playbackState) + when (playbackState){ + + Player.STATE_BUFFERING -> {} + + Player.STATE_ENDED -> {} + + Player.STATE_IDLE -> {} + + Player.STATE_READY -> { + playerReadyCallback?.invoke() + } + } + } + }) + + player?.setMediaItem(MediaItem.fromUri(liveUrl)) player?.playWhenReady = true player?.prepare() } diff --git a/app/src/main/java/com/woka/home/views/ExploreWokaActivity.kt b/app/src/main/java/com/woka/home/views/ExploreWokaActivity.kt index 5284eba..93a5a65 100644 --- a/app/src/main/java/com/woka/home/views/ExploreWokaActivity.kt +++ b/app/src/main/java/com/woka/home/views/ExploreWokaActivity.kt @@ -14,8 +14,11 @@ import com.woka.audiobooks.views.AudioBooksActivity import com.woka.databinding.ActivityExploreWokaBinding import com.woka.karaoke.views.KaraokeActivity import com.woka.modules.blogs.view.BlogsActivity +import com.woka.networking.ApiResult import com.woka.players.views.LiveStreamPlayerActivity import com.woka.shop.views.ShopActivity +import com.woka.streamingurls.StreamingUrlRepository +import com.woka.utils.ProgressView import com.woka.utils.WokaBaseActivity import com.woka.utils.lightStatusBar import com.woka.webseries.views.WebSeriesActivity @@ -25,6 +28,8 @@ class ExploreWokaActivity : WokaBaseActivity() { private lateinit var binding: ActivityExploreWokaBinding + private lateinit var progressView: ProgressView + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) with(window){ @@ -42,11 +47,15 @@ class ExploreWokaActivity : WokaBaseActivity() { insets } + progressView = ProgressView(this) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S){ binding.root.setBackgroundColor(ContextCompat.getColor(this, R.color.black_50)) } clickEvents() + + setObservers() } private fun clickEvents() { @@ -59,14 +68,6 @@ class ExploreWokaActivity : WokaBaseActivity() { finish() } - liveTv.setOnClickListener { - startActivity(Intent(this@ExploreWokaActivity, LiveStreamPlayerActivity::class.java)) - } - - wokaFm.setOnClickListener { - startActivity(Intent(this@ExploreWokaActivity, FMActivity::class.java)) - } - webSeries.setOnClickListener { startActivity(Intent(this@ExploreWokaActivity, WebSeriesActivity::class.java)) } @@ -93,4 +94,44 @@ class ExploreWokaActivity : WokaBaseActivity() { } } + + private fun setObservers(){ + StreamingUrlRepository.liveStreamLiveData.observe(this){ + when (it){ + is ApiResult.Error -> { + progressView.hide() + binding.liveTv.setOnClickListener { + StreamingUrlRepository.loadLiveStreamingUrls() + } + } + is ApiResult.Loading -> { + progressView.show() + } + is ApiResult.Success -> { + it.data?.live_data?.let {urls -> + if (urls.isNotEmpty()){ + urls.first()?.let {liveData -> + progressView.hide() + binding.liveTv.setOnClickListener { + startActivity(Intent(this, LiveStreamPlayerActivity::class.java).apply { + putExtra(LiveStreamPlayerActivity.EXTRA_LIVE_STREAM_ID, liveData.id) + putExtra(LiveStreamPlayerActivity.EXTRA_LIVE_STREAM_URL, liveData.live_url?.hd_url_en) + }) + } + } + } + } + + it.data?.live_fm_data?.let {fmData -> + binding.wokaFm.setOnClickListener { + startActivity(Intent(this, FMActivity::class.java).apply { + putExtra(FMActivity.EXTRA_FM_URL, fmData.live_fm_url) + putExtra(FMActivity.EXTRA_FM_ID, fmData.id) + }) + } + } + } + } + } + } } \ No newline at end of file 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 96d0507..18143ab 100644 --- a/app/src/main/java/com/woka/home/views/FMActivity.kt +++ b/app/src/main/java/com/woka/home/views/FMActivity.kt @@ -8,29 +8,36 @@ import androidx.activity.enableEdgeToEdge import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.media3.common.MediaItem +import androidx.media3.common.PlaybackException import androidx.media3.common.Player import androidx.media3.exoplayer.ExoPlayer import com.woka.R +import com.woka.database.helpers.ClicksHelper +import com.woka.database.models.clicks.ContentType import com.woka.databinding.ActivityFmactivityBinding import com.woka.utils.TAG import com.woka.utils.WokaBaseActivity import com.woka.utils.hide import com.woka.utils.show -import com.woka.utils.toast import kotlin.math.max import kotlin.math.min -import kotlin.math.round class FMActivity : WokaBaseActivity() { companion object { - private const val FM_URL = "https://stream.rcast.net/71643" + const val EXTRA_FM_URL = "extra_fm_url" + const val EXTRA_FM_ID = "extra_fm_id" private const val VOLUME_STEP = 0.2f } private lateinit var binding: ActivityFmactivityBinding private lateinit var player: ExoPlayer + private var fmUrl: String = "" + private var fmId: Int = -1 + + private val clickHelper = ClicksHelper + @SuppressLint("SetJavaScriptEnabled") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -45,6 +52,15 @@ class FMActivity : WokaBaseActivity() { window.navigationBarColor = Color.BLACK + intent.getStringExtra(EXTRA_FM_URL)?.let { + fmUrl = it + } + + fmId = intent.getIntExtra(EXTRA_FM_ID, -1) + upsertClickEvent() + + Log.d(TAG, "onCreate: $fmUrl $fmId") + player = ExoPlayer.Builder(this).build() initPlayer() @@ -58,13 +74,16 @@ class FMActivity : WokaBaseActivity() { super.onDestroy() player.stop() player.release() + + upsertClickEvent() } private fun initPlayer() { + binding.retryBtn.hide() binding.playBtn.hide() binding.progressBar.show() - player.setMediaItem(MediaItem.fromUri(FM_URL)) + player.setMediaItem(MediaItem.fromUri(fmUrl)) player.playWhenReady = true player.volume = 0.6f player.prepare() @@ -81,6 +100,8 @@ class FMActivity : WokaBaseActivity() { playBtn.setOnClickListener { if (player.isPlaying) player.pause() else player.play() + + upsertClickEvent() } volumeDown.setOnClickListener { @@ -91,6 +112,8 @@ class FMActivity : WokaBaseActivity() { player.volume = max(0.0f, player.volume - VOLUME_STEP) updateVolumeButtons() + + upsertClickEvent() } volumeUp.setOnClickListener { @@ -101,14 +124,32 @@ class FMActivity : WokaBaseActivity() { player.volume = min(1.0f, player.volume + VOLUME_STEP) updateVolumeButtons() + + upsertClickEvent() + } + + retryBtn.setOnClickListener { + initPlayer() } } } + private fun upsertClickEvent(){ + if (fmId == -1) return + + clickHelper.upsertClickEvent( + ContentType.FM, + fmId, + 0 + ) + } + private fun setObservers() { player.addListener(object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { super.onIsPlayingChanged(isPlaying) + binding.retryBtn.hide() + binding.progressBar.hide() binding.playBtn.show() binding.playBtn.setImageResource( @@ -119,6 +160,13 @@ class FMActivity : WokaBaseActivity() { } ) } + + override fun onPlayerError(error: PlaybackException) { + super.onPlayerError(error) + binding.playBtn.hide() + binding.retryBtn.show() + binding.progressBar.hide() + } }) } 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 061dfca..652392e 100644 --- a/app/src/main/java/com/woka/home/views/HomeActivity.kt +++ b/app/src/main/java/com/woka/home/views/HomeActivity.kt @@ -51,6 +51,7 @@ import com.woka.onboard.views.OnboardActivity.Companion.ADD_CHILD_INTENT import com.woka.onboard.views.OnboardActivity.Companion.LOG_IN_INTENT import com.woka.onboard.views.OnboardActivity.Companion.ONBOARD_ACTIVITY_INTENT import com.woka.shop.views.MyOrdersActivity +import com.woka.streamingurls.StreamingUrlRepository import com.woka.userPreference.UserType import com.woka.userdata.userDataModels.UserDataResponse import com.woka.utils.DecisionDialog @@ -108,8 +109,6 @@ class HomeActivity : WokaBaseActivity(), if (userPrefs?.userLiveData?.isInitialized == false){ userPrefs?.loadUserData() } - - viewModel.initPlayer(applicationContext) } override fun onResume() { @@ -203,6 +202,26 @@ class HomeActivity : WokaBaseActivity(), } } } + + StreamingUrlRepository.liveStreamLiveData.observe(this){ + when (it){ + is ApiResult.Error -> { + progressView.hide() + toast(it.errorMessage) + } + is ApiResult.Loading -> {progressView.show()} + is ApiResult.Success -> { + progressView.hide() + it.data?.live_data?.let {urls -> + if (urls.isNotEmpty()){ + urls.first()?.live_url?.hd_url_en?.let {liveUrl -> + viewModel.initPlayer(applicationContext, liveUrl) + } + } + } + } + } + } } private fun initViews() { @@ -495,7 +514,11 @@ class HomeActivity : WokaBaseActivity(), , ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) } MY_LIST -> { - unregisterReceiver(minuteReceiver) + try { + unregisterReceiver(minuteReceiver) + }catch (e: Exception){ + // do nothing + } supportFragmentManager.beginTransaction() .replace(R.id.fc_home, MyListFragment.getInstance()) 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 16b9abb..4de6fda 100644 --- a/app/src/main/java/com/woka/players/views/LiveStreamPlayerActivity.kt +++ b/app/src/main/java/com/woka/players/views/LiveStreamPlayerActivity.kt @@ -17,6 +17,8 @@ import com.jwplayer.pub.api.events.EventType import com.jwplayer.pub.api.events.listeners.VideoPlayerEvents import com.jwplayer.pub.api.fullscreen.FullscreenHandler import com.jwplayer.pub.api.media.playlists.PlaylistItem +import com.woka.database.helpers.ClicksHelper +import com.woka.database.models.clicks.ContentType import com.woka.databinding.ActivityLiveStreamPlayerBinding import com.woka.players.KeepScreenOnHandler import com.woka.players.models.PlayBackState @@ -25,6 +27,11 @@ import com.woka.utils.show class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { + companion object{ + const val EXTRA_LIVE_STREAM_URL = "extra_live_stream_url" + const val EXTRA_LIVE_STREAM_ID = "extra_live_stream_id" + } + private lateinit var binding: ActivityLiveStreamPlayerBinding private lateinit var player: JWPlayer @@ -35,6 +42,11 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { private var playbackState: PlayBackState? = null + private val clickHelper = ClicksHelper + + private var liveStreamUrl: String = "" + private var liveTvId: Int = -1 + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() @@ -50,6 +62,12 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { WindowCompat.getInsetsController(window, window.decorView) windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) + intent.getStringExtra(EXTRA_LIVE_STREAM_URL)?.let { + liveStreamUrl = it + } + + liveTvId = intent.getIntExtra(EXTRA_LIVE_STREAM_ID, -1) + networkCallback = object : NetworkCallback(){ override fun onAvailable(network: Network) { super.onAvailable(network) @@ -88,7 +106,7 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { KeepScreenOnHandler(player, window) val playlistItem = PlaylistItem.Builder() - .file("https://d3volyx7jx7oal.cloudfront.net/master.m3u8") + .file(liveStreamUrl) .mediaId("YR5pnlIM") .build() val playlist: MutableList = ArrayList() @@ -105,9 +123,13 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { playbackState = PlayBackState.PLAY binding.playerView.show() binding.errorView.hide() + + upsertClickEvent() }) player.addListener(EventType.PAUSE, VideoPlayerEvents.OnPauseListener { playbackState = PlayBackState.PAUSED + + upsertClickEvent() }) player.addListener(EventType.ERROR, VideoPlayerEvents.OnErrorListener { playbackState = PlayBackState.STOPPED @@ -142,6 +164,16 @@ class LiveStreamPlayerActivity : AppCompatActivity(), FullscreenHandler { } } + private fun upsertClickEvent(){ + if (liveTvId == -1) return + + clickHelper.upsertClickEvent( + ContentType.LIVE_TV, + liveTvId, + 0 + ) + } + override fun onFullscreenRequested() {} override fun onFullscreenExitRequested() { diff --git a/app/src/main/java/com/woka/streamingurls/StreamingApiService.kt b/app/src/main/java/com/woka/streamingurls/StreamingApiService.kt new file mode 100644 index 0000000..b78f709 --- /dev/null +++ b/app/src/main/java/com/woka/streamingurls/StreamingApiService.kt @@ -0,0 +1,12 @@ +package com.woka.streamingurls + +import com.woka.networking.ApiResponse +import com.woka.streamingurls.models.LiveStreamingResponse +import retrofit2.Response +import retrofit2.http.GET + +interface StreamingApiService { + + @GET("live_streaming") + suspend fun liveStreaming(): Response> +} \ No newline at end of file diff --git a/app/src/main/java/com/woka/streamingurls/StreamingUrlRepository.kt b/app/src/main/java/com/woka/streamingurls/StreamingUrlRepository.kt new file mode 100644 index 0000000..d9791c8 --- /dev/null +++ b/app/src/main/java/com/woka/streamingurls/StreamingUrlRepository.kt @@ -0,0 +1,34 @@ +package com.woka.streamingurls + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.woka.networking.ApiResult +import com.woka.networking.RetrofitHelper +import com.woka.networking.RetrofitHelper.handleApiCall +import com.woka.streamingurls.models.LiveStreamingResponse +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +object StreamingUrlRepository { + + private val apiService = RetrofitHelper.getRetrofit().create(StreamingApiService::class.java) + + private val _liveStreamLiveData = MutableLiveData>() + val liveStreamLiveData: LiveData> + get() = _liveStreamLiveData + + fun loadLiveStreamingUrls(){ + if (_liveStreamLiveData.isInitialized && _liveStreamLiveData.value is ApiResult.Success){ + return + } + + CoroutineScope(Dispatchers.IO).launch { + _liveStreamLiveData.postValue( + handleApiCall { + apiService.liveStreaming() + } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/woka/streamingurls/models/LiveData.kt b/app/src/main/java/com/woka/streamingurls/models/LiveData.kt new file mode 100644 index 0000000..f85ffac --- /dev/null +++ b/app/src/main/java/com/woka/streamingurls/models/LiveData.kt @@ -0,0 +1,7 @@ +package com.woka.streamingurls.models + +data class LiveData( + val id: Int?, + val live_url: LiveUrl?, + val name: Name? +) \ No newline at end of file diff --git a/app/src/main/java/com/woka/streamingurls/models/LiveFmData.kt b/app/src/main/java/com/woka/streamingurls/models/LiveFmData.kt new file mode 100644 index 0000000..7524778 --- /dev/null +++ b/app/src/main/java/com/woka/streamingurls/models/LiveFmData.kt @@ -0,0 +1,7 @@ +package com.woka.streamingurls.models + +data class LiveFmData( + val id: Int?, + val live_fm_url: String?, + val title: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/woka/streamingurls/models/LiveStreamingResponse.kt b/app/src/main/java/com/woka/streamingurls/models/LiveStreamingResponse.kt new file mode 100644 index 0000000..dab8e77 --- /dev/null +++ b/app/src/main/java/com/woka/streamingurls/models/LiveStreamingResponse.kt @@ -0,0 +1,6 @@ +package com.woka.streamingurls.models + +data class LiveStreamingResponse( + val live_data: List?, + val live_fm_data: LiveFmData? +) \ No newline at end of file diff --git a/app/src/main/java/com/woka/streamingurls/models/LiveUrl.kt b/app/src/main/java/com/woka/streamingurls/models/LiveUrl.kt new file mode 100644 index 0000000..e99da09 --- /dev/null +++ b/app/src/main/java/com/woka/streamingurls/models/LiveUrl.kt @@ -0,0 +1,8 @@ +package com.woka.streamingurls.models + +data class LiveUrl( + val hd_url_en: String?, + val hd_url_hin: String?, + val sd_url_en: String?, + val sd_url_hin: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/woka/streamingurls/models/Name.kt b/app/src/main/java/com/woka/streamingurls/models/Name.kt new file mode 100644 index 0000000..ebf1d35 --- /dev/null +++ b/app/src/main/java/com/woka/streamingurls/models/Name.kt @@ -0,0 +1,6 @@ +package com.woka.streamingurls.models + +data class Name( + val title_en: String?, + val title_hin: String? +) \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_play_retry.xml b/app/src/main/res/drawable/ic_play_retry.xml new file mode 100644 index 0000000..354c064 --- /dev/null +++ b/app/src/main/res/drawable/ic_play_retry.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/layout/activity_fmactivity.xml b/app/src/main/res/layout/activity_fmactivity.xml index 622a6fe..eaece9d 100644 --- a/app/src/main/res/layout/activity_fmactivity.xml +++ b/app/src/main/res/layout/activity_fmactivity.xml @@ -123,6 +123,17 @@ android:scaleType="fitXY" app:tint="@color/white" /> + + @@ -53,7 +53,7 @@ android:fontFamily="@font/exo_2_bold" android:textAlignment="center" android:maxLines="1" - android:textSize="12sp" + android:textSize="@dimen/_11ssp" android:ellipsize="end" android:layout_marginTop="5dp" @@ -82,8 +82,8 @@ android:gravity="center">