Resolved migration problem with app-inspection of room database.

implement upsert transaction for ClickEvent
Verified database with debugging.

Implemented for live tv and fm.

live_streaming api integration and caching with singleton.

Implemented online url at all places of fm and live stream.
This commit is contained in:
2024-08-06 21:07:45 +05:30
parent 84fe475951
commit e15abb2a80
23 changed files with 490 additions and 96 deletions

View File

@@ -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()
}
}

View File

@@ -25,7 +25,9 @@ abstract class AppDatabase : RoomDatabase(){
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java, DATABASE_NAME
).build()
)
.fallbackToDestructiveMigration()
.build()
}
abstract fun clicksDao(): ClicksDao

View File

@@ -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
)
)
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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,
)

View File

@@ -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)
}

View File

@@ -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?) {

View File

@@ -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?) {

View File

@@ -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<ApiResult<Any>?>
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()
}

View File

@@ -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)
})
}
}
}
}
}
}
}

View File

@@ -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()
}
})
}

View File

@@ -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())

View File

@@ -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<PlaylistItem> = 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() {

View File

@@ -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<ApiResponse<LiveStreamingResponse>>
}

View File

@@ -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<ApiResult<LiveStreamingResponse>>()
val liveStreamLiveData: LiveData<ApiResult<LiveStreamingResponse>>
get() = _liveStreamLiveData
fun loadLiveStreamingUrls(){
if (_liveStreamLiveData.isInitialized && _liveStreamLiveData.value is ApiResult.Success){
return
}
CoroutineScope(Dispatchers.IO).launch {
_liveStreamLiveData.postValue(
handleApiCall {
apiService.liveStreaming()
}
)
}
}
}

View File

@@ -0,0 +1,7 @@
package com.woka.streamingurls.models
data class LiveData(
val id: Int?,
val live_url: LiveUrl?,
val name: Name?
)

View File

@@ -0,0 +1,7 @@
package com.woka.streamingurls.models
data class LiveFmData(
val id: Int?,
val live_fm_url: String?,
val title: String?
)

View File

@@ -0,0 +1,6 @@
package com.woka.streamingurls.models
data class LiveStreamingResponse(
val live_data: List<LiveData?>?,
val live_fm_data: LiveFmData?
)

View File

@@ -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?
)

View File

@@ -0,0 +1,6 @@
package com.woka.streamingurls.models
data class Name(
val title_en: String?,
val title_hin: String?
)

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#000000"
android:fillType="evenOdd"
android:pathData="M5.233,0.494C6.88,-0.113 8.681,-0.162 10.358,0.355C11.402,0.677 12.362,1.208 13.184,1.907L13.453,2.146L14.293,1.306C14.896,0.703 15.907,1.085 15.994,1.899L16,2.013L16,6L12.013,6C11.161,6 10.715,5.015 11.229,4.377L11.306,4.293L12.037,3.561C11.389,2.972 10.616,2.528 9.768,2.267C8.511,1.879 7.16,1.915 5.925,2.37C4.69,2.825 3.639,3.674 2.934,4.786C2.228,5.897 1.908,7.21 2.023,8.521C2.137,9.832 2.679,11.07 3.566,12.042C4.453,13.015 5.635,13.669 6.931,13.904C8.226,14.139 9.562,13.941 10.734,13.341C11.906,12.741 12.848,11.773 13.415,10.585C13.653,10.086 14.25,9.875 14.748,10.113C15.246,10.351 15.458,10.948 15.22,11.446C14.464,13.03 13.208,14.321 11.645,15.121C10.083,15.921 8.301,16.185 6.574,15.872C4.847,15.559 3.271,14.687 2.088,13.39C0.906,12.093 0.183,10.443 0.03,8.695C-0.122,6.946 0.305,5.196 1.245,3.714C2.185,2.232 3.587,1.101 5.233,0.494ZM6,5.461C6,5.095 6.375,4.862 6.695,5L6.768,5.039L10.771,7.578C11.053,7.756 11.078,8.146 10.848,8.363L10.771,8.422L6.768,10.962C6.459,11.158 6.062,10.965 6.006,10.621L6,10.539L6,5.461Z" />
</vector>

View File

@@ -123,6 +123,17 @@
android:scaleType="fitXY"
app:tint="@color/white" />
<ImageView
android:id="@+id/retry_btn"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/image"
android:src="@drawable/ic_play_retry"
android:layout_margin="12dp"
android:scaleType="fitXY"
app:tint="@color/white" />
<ProgressBar
android:id="@+id/progress_bar"
android:visibility="gone"

View File

@@ -37,8 +37,8 @@
<ImageView
android:id="@+id/home_img_bn"
android:layout_width="22sp"
android:layout_height="22sp"
android:layout_width="@dimen/_20ssp"
android:layout_height="@dimen/_20ssp"
android:contentDescription="@string/image"
android:src="@drawable/ic_home_bn"
app:tint="@android:color/darker_gray" />
@@ -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">
<ImageView
android:layout_width="36dp"
android:layout_height="22sp"
android:layout_width="@dimen/_34ssp"
android:layout_height="@dimen/_20ssp"
android:contentDescription="@string/image"
android:src="@drawable/img_woka_w"
android:scaleType="fitXY"
@@ -97,7 +97,7 @@
android:text="@string/explore_woka"
android:textColor="@color/color_primary"
android:fontFamily="@font/exo_2_bold"
android:textSize="12sp"
android:textSize="@dimen/_11ssp"
android:textAlignment="center"
android:maxLines="1"
android:ellipsize="end"
@@ -129,8 +129,8 @@
<ImageView
android:id="@+id/my_list_img_bn"
android:layout_width="22sp"
android:layout_height="22sp"
android:layout_width="@dimen/_20ssp"
android:layout_height="@dimen/_20ssp"
android:contentDescription="@string/image"
android:src="@drawable/ic_heart_filled"
app:tint="@android:color/darker_gray"
@@ -144,7 +144,7 @@
android:text="@string/my_list"
android:textColor="@android:color/darker_gray"
android:fontFamily="@font/exo_2_bold"
android:textSize="12sp"
android:textSize="@dimen/_11ssp"
android:textAlignment="center"
android:maxLines="1"
android:ellipsize="end"