diff --git a/app/build.gradle b/app/build.gradle
index a7c3aae..19c2a95 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -47,8 +47,8 @@ android {
}
}
-ext.jwPlayerVersion = '4.6.0'
-ext.exoplayerVersion = '2.19.1'
+ext.jwPlayerVersion = '4.17.0'
+ext.exoplayerVersion = '1.1.1'
dependencies {
implementation "com.facebook.shimmer:shimmer:0.5.0"
@@ -83,6 +83,11 @@ dependencies {
implementation "com.jwplayer:jwplayer-core:$jwPlayerVersion"
implementation "com.jwplayer:jwplayer-common:$jwPlayerVersion"
+ // exoplayer2
+ implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1'
+ implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1'
+ implementation 'com.google.android.exoplayer:exoplayer-hls:2.19.1'
+
implementation libs.androidx.core.ktx
implementation libs.androidx.appcompat
implementation libs.material
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9c3775b..205593b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,10 +15,18 @@
android:supportsRtl="true"
android:theme="@style/Theme.Woka"
tools:targetApi="31">
+
+ android:screenOrientation="portrait" />
? = null
+ private var playIndex: Int = 0
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ binding = ActivityPlayerBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
+ val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
+ v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
+ insets
+ }
+
+ val windowInsetsController =
+ WindowCompat.getInsetsController(window, window.decorView)
+ windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
+
+ playList = intent.getParcelableArrayListExtra(EXTRA_PLAY_LIST)
+ playIndex = intent.getIntExtra(EXTRA_EPISODE_INDEX, 0)
+
+ setUpPlayer()
+
+ }
+
+ private fun setUpPlayer() {
+ if (playList == null) return
+ player = binding.playerView.getPlayer(this)
+
+ player.setFullscreenHandler(this)
+
+ player.setFullscreen(true, false)
+
+ // to keep up the screen om when video is being played
+ KeepScreenOnHandler(player, window)
+
+ val config = PlayerConfig.Builder()
+ .playlist(playList)
+ .build()
+
+ player.setup(config)
+ player.playlistItem(playIndex)
+ }
+
+ override fun onFullscreenRequested() {}
+
+ override fun onFullscreenExitRequested() {
+ player.stop()
+ val windowInsetsController =
+ WindowCompat.getInsetsController(window, window.decorView)
+ windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
+
+ finish()
+ }
+
+ override fun onAllowRotationChanged(allowRotation: Boolean) {}
+ override fun onAllowFullscreenPortraitChanged(allowFullscreenPortrait: Boolean) {}
+
+ override fun updateLayoutParams(layoutParams: ViewGroup.LayoutParams?) {}
+
+ override fun setUseFullscreenLayoutFlags(flags: Boolean) {}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/utils/AdiImageView.kt b/app/src/main/java/com/woka/utils/AdiImageView.kt
index 2569950..cc45540 100644
--- a/app/src/main/java/com/woka/utils/AdiImageView.kt
+++ b/app/src/main/java/com/woka/utils/AdiImageView.kt
@@ -15,6 +15,7 @@ import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.woka.R
+import kotlin.reflect.KFunction
class AdiImageView: FrameLayout {
@@ -29,6 +30,9 @@ class AdiImageView: FrameLayout {
private var progressView: ProgressBar? = null
private var cardView: CardView? = null
+ // variables
+ var onLoadSuccessListener: (() -> Unit)? = null
+
constructor(context: Context?) : super(context!!)
constructor(context: Context?, attrs: AttributeSet?) : super(
context!!, attrs
@@ -93,6 +97,7 @@ class AdiImageView: FrameLayout {
isFirstResource: Boolean
): Boolean {
progressView?.hide()
+ onLoadSuccessListener?.invoke()
return false
}
})
diff --git a/app/src/main/java/com/woka/webseries/WebSeriesApiService.kt b/app/src/main/java/com/woka/webseries/WebSeriesApiService.kt
index ba4cb92..ce67eb8 100644
--- a/app/src/main/java/com/woka/webseries/WebSeriesApiService.kt
+++ b/app/src/main/java/com/woka/webseries/WebSeriesApiService.kt
@@ -2,7 +2,9 @@ package com.woka.webseries
import com.woka.networking.ApiResponse
import com.woka.webseries.models.WebSeriesResponse
+import com.woka.webseries.models.episodedata.EpisodeResponseData
import com.woka.webseries.models.seasondata.SeasonDataResponse
+import com.woka.webseries.models.teaserdata.TeaserResponseData
import okhttp3.FormBody
import retrofit2.Response
import retrofit2.http.Body
@@ -15,4 +17,10 @@ interface WebSeriesApiService {
@POST("season_listing")
suspend fun seasonListing(@Body formBody: FormBody): Response>
+
+ @POST("episode_listing")
+ suspend fun episodeListing(@Body formBody: FormBody): Response>
+
+ @POST("teaser_listing")
+ suspend fun teaserListing(@Body formBody: FormBody): Response>
}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/WebSeriesRepository.kt b/app/src/main/java/com/woka/webseries/WebSeriesRepository.kt
index 9178dd0..e214cf7 100644
--- a/app/src/main/java/com/woka/webseries/WebSeriesRepository.kt
+++ b/app/src/main/java/com/woka/webseries/WebSeriesRepository.kt
@@ -2,6 +2,7 @@ package com.woka.webseries
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
+import com.jwplayer.pub.api.media.playlists.PlaylistItem
import com.woka.home.mylist.MyFavApiService
import com.woka.home.mylist.MyListRepository
import com.woka.home.mylist.models.BookmarkedShowData
@@ -12,8 +13,11 @@ import com.woka.networking.RetrofitHelper
import com.woka.webseries.models.ContinueEpisodeResponse
import com.woka.webseries.models.ShowData
import com.woka.webseries.models.WebSeriesResponse
+import com.woka.webseries.models.episodedata.EpisodeData
+import com.woka.webseries.models.episodedata.EpisodeResponseData
import com.woka.webseries.models.seasondata.SeasonData
import com.woka.webseries.models.seasondata.SeasonDataResponse
+import com.woka.webseries.models.teaserdata.TeaserResponseData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -54,6 +58,10 @@ object WebSeriesRepository {
var continueWatchData: ContinueEpisodeResponse? = null
+ init {
+ loadContinueWatchData()
+ }
+
/*
flag to load a new data whenever necessary
for eg. when user has signed in with new account and the apps hold the older repository
@@ -65,15 +73,174 @@ object WebSeriesRepository {
val seasonDataLiveData: LiveData>
get() = _seasonDataLiveData
- private var seasonDataMap = HashMap()
+ // seasons data for every show. where {key -> "showId_categoryId"}
+ var seasonDataMap = HashMap()
- init {
- loadContinueWatchData()
+ // episode listing data
+ private val _episodeDataLiveData = MutableLiveData>()
+ val episodeDataLiveData: LiveData>
+ get() = _episodeDataLiveData
+
+ // episode data for every season. where {key -> "showId_seasonId"}
+ private var episodeDataMap = HashMap()
+ // episodes playlist, where {key -> "showId_seasonId_categoryId"}
+ var episodesPlaylistMap = HashMap>()
+
+ // teaser listing data
+ private val _teaserDataLiveData = MutableLiveData>()
+ val teaserDataLiveData: LiveData>
+ get() = _teaserDataLiveData
+
+ // teaser data for every season. where {key -> "showId_seasonId"}
+ private var teaserDataMap = HashMap()
+ // teasers playlist, where {key -> "showId_seasonId_categoryId"}
+ var teasersPlaylistMap = HashMap>()
+
+ fun loadTeaserData(showId: Int, seasonId: Int){
+ if (teaserDataMap.containsKey("${showId}_${seasonId}")){
+ _teaserDataLiveData.postValue(ApiResult.Success(data = teaserDataMap["${showId}_${seasonId}"]))
+ return
+ }
+ CoroutineScope(Dispatchers.IO).launch {
+ _teaserDataLiveData.postValue(ApiResult.Loading())
+ val response = RetrofitHelper.handleApiCall {
+ apiService.teaserListing(
+ FormBody.Builder()
+ .add("watch_show_master_id", "$showId")
+ .add("season_master_id", "$seasonId")
+ .build()
+ )
+ }
+
+ when (response){
+ is ApiResult.Error -> {
+ _teaserDataLiveData.postValue(response)
+ }
+ is ApiResult.Loading -> {}
+ is ApiResult.Success -> {
+ response.data?.let {teaserData ->
+ teaserDataMap["${showId}_${seasonId}"] = teaserData
+ }
+
+ _teaserDataLiveData.postValue(response)
+
+ // creating a playable playlist
+ teaserDataMap["${showId}_${seasonId}"]?.result?.filterNotNull()?.let {
+ val hindiPlayList = ArrayList()
+ val englishPlayList = ArrayList()
+
+ for (teaser in it){
+ teaser.content_more_details?.let {moreDetailsList ->
+ if (moreDetailsList.isNotEmpty()){
+ if (moreDetailsList.size > 1){
+ moreDetailsList[1]?.let {moreDetail ->
+ hindiPlayList.add(
+ PlaylistItem.Builder()
+ .file(moreDetail.content_hd_url)
+ .title(moreDetail.title)
+ .image(teaser.thumbnail_path)
+ .build()
+ )
+ }
+ }
+
+ moreDetailsList[0]?.let {moreDetail ->
+ englishPlayList.add(
+ PlaylistItem.Builder()
+ .file(moreDetail.content_hd_url)
+ .title(moreDetail.title)
+ .image(teaser.thumbnail_path)
+ .build()
+ )
+ }
+ }
+ }
+ }
+
+ teasersPlaylistMap["${showId}_${seasonId}_18"] = hindiPlayList
+ teasersPlaylistMap["${showId}_${seasonId}_1"] = englishPlayList
+ }
+ }
+ }
+ }
+ }
+
+ fun loadEpisodeData(showId: Int, seasonId: Int){
+ if (episodeDataMap.containsKey("${showId}_${seasonId}")){
+ _episodeDataLiveData.postValue(ApiResult.Success(data = episodeDataMap["${showId}_${seasonId}"]))
+ return
+ }
+ CoroutineScope(Dispatchers.IO).launch {
+ _episodeDataLiveData.postValue(ApiResult.Loading())
+ val response = RetrofitHelper.handleApiCall {
+ apiService.episodeListing(
+ FormBody.Builder()
+ .add("watch_show_master_id", "$showId")
+ .add("season_master_id", "$seasonId")
+ .build()
+ )
+ }
+
+ when (response){
+ is ApiResult.Error -> {
+ _episodeDataLiveData.postValue(response)
+ }
+ is ApiResult.Loading -> {}
+ is ApiResult.Success -> {
+ response.data?.let {episodeData ->
+ episodeDataMap["${showId}_${seasonId}"] = episodeData
+ }
+
+ _episodeDataLiveData.postValue(response)
+
+ // creating a playable playlist
+ episodeDataMap["${showId}_${seasonId}"]?.result?.filterNotNull()?.let {
+ val hindiPlayList = ArrayList()
+ val englishPlayList = ArrayList()
+
+ for (episode in it){
+ episode.content_more_details?.let {moreDetailsList ->
+ if (moreDetailsList.isNotEmpty()){
+ if (moreDetailsList.size > 1){
+ moreDetailsList[1]?.let {moreDetail ->
+ hindiPlayList.add(
+ PlaylistItem.Builder()
+ .file(moreDetail.content_hd_url)
+ .title(moreDetail.title)
+ .image(episode.thumbnail_path)
+ .build()
+ )
+ }
+ }
+
+ moreDetailsList[0]?.let {moreDetail ->
+ englishPlayList.add(
+ PlaylistItem.Builder()
+ .file(moreDetail.content_hd_url)
+ .title(moreDetail.title)
+ .image(episode.thumbnail_path)
+ .build()
+ )
+ }
+ }
+ }
+ }
+
+ episodesPlaylistMap["${showId}_${seasonId}_18"] = hindiPlayList
+ episodesPlaylistMap["${showId}_${seasonId}_1"] = englishPlayList
+ }
+ }
+ }
+ }
+ }
+
+ fun clearEpisodeData(){
+ _episodeDataLiveData.postValue(ApiResult.Loading())
}
fun loadSeasonListing(showId: Int, categoryId: String){
- if (seasonDataMap.containsKey(showId)){
- _seasonDataLiveData.postValue(ApiResult.Success(data = seasonDataMap[showId]))
+ if (seasonDataMap.containsKey("${showId}_${categoryId}")){
+ _seasonDataLiveData.postValue(ApiResult.Success(data = seasonDataMap["${showId}_${categoryId}"]))
return
}
CoroutineScope(Dispatchers.IO).launch {
@@ -92,7 +259,7 @@ object WebSeriesRepository {
is ApiResult.Loading -> {}
is ApiResult.Success -> {
response.data?.let {seasonList ->
- seasonDataMap[showId] = seasonList
+ seasonDataMap["${showId}_${categoryId}"] = seasonList
}
_seasonDataLiveData.postValue(ApiResult.Success(response.data))
diff --git a/app/src/main/java/com/woka/webseries/adapters/EpisodeAdapter.kt b/app/src/main/java/com/woka/webseries/adapters/EpisodeAdapter.kt
new file mode 100644
index 0000000..f14a38c
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/adapters/EpisodeAdapter.kt
@@ -0,0 +1,79 @@
+package com.woka.webseries.adapters;
+
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.AsyncDifferConfig
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.woka.WokaApp.Companion.userPrefs
+import com.woka.databinding.EpisodeViewHolderBinding
+import com.woka.webseries.models.episodedata.EpisodeData
+import java.util.concurrent.Executors
+
+class EpisodeAdapter private constructor(val context: Context,
+ config: AsyncDifferConfig
+): ListAdapter(config) {
+
+ inner class EpisodeViewHolder(val binding: EpisodeViewHolderBinding): RecyclerView.ViewHolder(binding.root)
+
+ companion object{
+
+ private val DIFF_UTIL = object : DiffUtil.ItemCallback(){
+ override fun areItemsTheSame(oldItem: EpisodeData, newItem: EpisodeData): Boolean = oldItem.id == newItem.id
+ override fun areContentsTheSame(oldItem: EpisodeData, newItem: EpisodeData): Boolean {
+ return oldItem == newItem
+ }
+ }
+
+ private val DIFF_CONFIG = AsyncDifferConfig.Builder(DIFF_UTIL)
+ .setBackgroundThreadExecutor(Executors.newSingleThreadExecutor())
+ .build()
+ }
+
+ constructor(context: Context): this(context, DIFF_CONFIG)
+
+ var onEpisodeClicked: ((position: Int) -> Unit)? = null
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EpisodeViewHolder {
+ return EpisodeViewHolder(
+ EpisodeViewHolderBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ )
+ }
+
+ override fun onBindViewHolder(holder: EpisodeViewHolder, position: Int) {
+ val episode = getItem(holder.absoluteAdapterPosition)
+
+ holder.binding.apply {
+ episode.thumbnail_path?.let {
+ epImage.loadImage(it)
+ }
+ epDuration.text = "${episode.episode_duration}"
+ episode.content_more_details?.let {moreDetailsList ->
+ if (moreDetailsList.isNotEmpty()){
+ if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1){
+ moreDetailsList[1]?.let {moreDetail ->
+ epTitle.text = moreDetail.title
+ }
+ }else{
+ moreDetailsList[0]?.let {moreDetail ->
+ epTitle.text = moreDetail.title
+ }
+ }
+ }
+ }
+
+ card.setOnClickListener {
+ episode.id?.let { episodeId ->
+ onEpisodeClicked?.invoke(holder.absoluteAdapterPosition)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/adapters/TeaserAdapter.kt b/app/src/main/java/com/woka/webseries/adapters/TeaserAdapter.kt
new file mode 100644
index 0000000..55e069b
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/adapters/TeaserAdapter.kt
@@ -0,0 +1,77 @@
+package com.woka.webseries.adapters;
+
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.AsyncDifferConfig
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.woka.WokaApp.Companion.userPrefs
+import com.woka.databinding.EpisodeViewHolderBinding
+import com.woka.webseries.models.teaserdata.TeaserData
+import java.util.concurrent.Executors
+
+class TeaserAdapter private constructor(val context: Context,
+ config: AsyncDifferConfig
+): ListAdapter(config) {
+
+ inner class EpisodeViewHolder(val binding: EpisodeViewHolderBinding): RecyclerView.ViewHolder(binding.root)
+
+ companion object{
+
+ private val DIFF_UTIL = object : DiffUtil.ItemCallback(){
+ override fun areItemsTheSame(oldItem: TeaserData, newItem: TeaserData): Boolean = oldItem.id == newItem.id
+ override fun areContentsTheSame(oldItem: TeaserData, newItem: TeaserData): Boolean {
+ return oldItem == newItem
+ }
+ }
+
+ private val DIFF_CONFIG = AsyncDifferConfig.Builder(DIFF_UTIL)
+ .setBackgroundThreadExecutor(Executors.newSingleThreadExecutor())
+ .build()
+ }
+
+ constructor(context: Context): this(context, DIFF_CONFIG)
+
+ var onEpisodeClicked: ((position: Int) -> Unit)? = null
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EpisodeViewHolder {
+ return EpisodeViewHolder(
+ EpisodeViewHolderBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ )
+ }
+
+ override fun onBindViewHolder(holder: EpisodeViewHolder, position: Int) {
+ val episode = getItem(holder.absoluteAdapterPosition)
+
+ holder.binding.apply {
+ episode.thumbnail_path?.let {
+ epImage.loadImage(it)
+ }
+ epDuration.text = "${episode.teaser_duration}"
+ episode.content_more_details?.let {moreDetailsList ->
+ if (moreDetailsList.isNotEmpty()){
+ if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1){
+ moreDetailsList[1]?.let {moreDetail ->
+ epTitle.text = moreDetail.title
+ }
+ }else{
+ moreDetailsList[0]?.let {moreDetail ->
+ epTitle.text = moreDetail.title
+ }
+ }
+ }
+ }
+
+ card.setOnClickListener {
+ onEpisodeClicked?.invoke(holder.absoluteAdapterPosition)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/models/episodedata/ContentMoreDetail.kt b/app/src/main/java/com/woka/webseries/models/episodedata/ContentMoreDetail.kt
new file mode 100644
index 0000000..d716c12
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/models/episodedata/ContentMoreDetail.kt
@@ -0,0 +1,13 @@
+package com.woka.webseries.models.episodedata
+
+data class ContentMoreDetail(
+ val content_hd_url: String?,
+ val content_id: Int?,
+ val content_sd_url: String?,
+ val description: String?,
+ val id: Int?,
+ val language_master_id: Int?,
+ val post_type: Int?,
+ val tags_keywords: String?,
+ val title: String?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/models/episodedata/EpisodeData.kt b/app/src/main/java/com/woka/webseries/models/episodedata/EpisodeData.kt
new file mode 100644
index 0000000..78b7c73
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/models/episodedata/EpisodeData.kt
@@ -0,0 +1,20 @@
+package com.woka.webseries.models.episodedata
+
+data class EpisodeData(
+ val content_more_details: List?,
+ val episode_description: String?,
+ val episode_duration: String?,
+ val episode_number: Int?,
+ val episode_title: String?,
+ val episode_url: String?,
+ val id: Int?,
+ val language_master_id: Int?,
+ val release_date: String?,
+ val season_data: SeasonData?,
+ val season_master_id: Int?,
+ val tags_keyword: String?,
+ val thumbnail_img_url: String?,
+ val thumbnail_path: String?,
+ val user_video_view: List?,
+ val watch_shows_master_id: Int?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/models/episodedata/EpisodeResponseData.kt b/app/src/main/java/com/woka/webseries/models/episodedata/EpisodeResponseData.kt
new file mode 100644
index 0000000..72b7535
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/models/episodedata/EpisodeResponseData.kt
@@ -0,0 +1,6 @@
+package com.woka.webseries.models.episodedata
+
+data class EpisodeResponseData(
+ val result: List?,
+ val total_records: Int?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/models/episodedata/SeasonData.kt b/app/src/main/java/com/woka/webseries/models/episodedata/SeasonData.kt
new file mode 100644
index 0000000..58a254b
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/models/episodedata/SeasonData.kt
@@ -0,0 +1,7 @@
+package com.woka.webseries.models.episodedata
+
+data class SeasonData(
+ val id: Int?,
+ val season_number: String?,
+ val watch_shows_master_id: Int?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/models/teaserdata/ContentMoreDetail.kt b/app/src/main/java/com/woka/webseries/models/teaserdata/ContentMoreDetail.kt
new file mode 100644
index 0000000..f002955
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/models/teaserdata/ContentMoreDetail.kt
@@ -0,0 +1,13 @@
+package com.woka.webseries.models.teaserdata
+
+data class ContentMoreDetail(
+ val content_hd_url: String?,
+ val content_id: Int?,
+ val content_sd_url: String?,
+ val description: String?,
+ val id: Int?,
+ val language_master_id: Int?,
+ val post_type: Int?,
+ val tags_keywords: String?,
+ val title: String?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/models/teaserdata/SeasonData.kt b/app/src/main/java/com/woka/webseries/models/teaserdata/SeasonData.kt
new file mode 100644
index 0000000..58762c7
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/models/teaserdata/SeasonData.kt
@@ -0,0 +1,7 @@
+package com.woka.webseries.models.teaserdata
+
+data class SeasonData(
+ val id: Int?,
+ val season_number: String?,
+ val watch_shows_master_id: Int?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/models/teaserdata/TeaserData.kt b/app/src/main/java/com/woka/webseries/models/teaserdata/TeaserData.kt
new file mode 100644
index 0000000..c422645
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/models/teaserdata/TeaserData.kt
@@ -0,0 +1,21 @@
+package com.woka.webseries.models.teaserdata
+
+data class TeaserData(
+ val content_more_details: List?,
+ val id: Int?,
+ val language_master_id: Int?,
+ val release_date: String?,
+ val season_data: SeasonData?,
+ val season_master_id: Int?,
+ val serial_number: Int?,
+ val tags_keyword: String?,
+ val teaser_description: String?,
+ val teaser_duration: String?,
+ val teaser_number: Int?,
+ val teaser_title: String?,
+ val teaser_url: String?,
+ val thumbnail_img_url: String?,
+ val thumbnail_path: String?,
+ val user_video_view: List?,
+ val watch_shows_master_id: Int?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/models/teaserdata/TeaserResponseData.kt b/app/src/main/java/com/woka/webseries/models/teaserdata/TeaserResponseData.kt
new file mode 100644
index 0000000..b7f2987
--- /dev/null
+++ b/app/src/main/java/com/woka/webseries/models/teaserdata/TeaserResponseData.kt
@@ -0,0 +1,6 @@
+package com.woka.webseries.models.teaserdata
+
+data class TeaserResponseData(
+ val result: List?,
+ val total_records: Int?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/webseries/views/SeasonActivity.kt b/app/src/main/java/com/woka/webseries/views/SeasonActivity.kt
index e47253a..487fb36 100644
--- a/app/src/main/java/com/woka/webseries/views/SeasonActivity.kt
+++ b/app/src/main/java/com/woka/webseries/views/SeasonActivity.kt
@@ -3,20 +3,30 @@ package com.woka.webseries.views
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
+import android.text.Html
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
-import com.bumptech.glide.Glide
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
+import com.jwplayer.pub.api.media.playlists.PlaylistItem
import com.woka.R
+import com.woka.WokaApp.Companion.userPrefs
import com.woka.databinding.ActivitySeasonBinding
import com.woka.networking.ApiResult
+import com.woka.players.PlayerActivity
+import com.woka.players.PlayerActivity.Companion.EXTRA_EPISODE_INDEX
+import com.woka.players.PlayerActivity.Companion.EXTRA_PLAY_LIST
+import com.woka.utils.ProgressView
+import com.woka.utils.hide
import com.woka.utils.isNetworkConnected
import com.woka.utils.lightStatusBar
+import com.woka.utils.show
import com.woka.utils.toast
import com.woka.webseries.WebSeriesRepository
+import com.woka.webseries.adapters.EpisodeAdapter
+import com.woka.webseries.adapters.TeaserAdapter
import com.woka.webseries.models.ShowData
import kotlin.math.max
@@ -36,6 +46,13 @@ class SeasonActivity : AppCompatActivity(), OnTabSelectedListener {
private var showPosition: Int = -1
+ private lateinit var progressView: ProgressView
+
+ private lateinit var episodeAdapter: EpisodeAdapter
+ private lateinit var teaserAdapter: TeaserAdapter
+
+ private var selectedSeasonId = -1
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
@@ -61,6 +78,12 @@ class SeasonActivity : AppCompatActivity(), OnTabSelectedListener {
return
}
+ episodeAdapter = EpisodeAdapter(this)
+ teaserAdapter = TeaserAdapter(this)
+
+ progressView = ProgressView(this)
+ progressView.show(getString(R.string.please_wait))
+
WebSeriesRepository.webSeriesData[categoryId]?.show_data?.let {
for (show in it){
if (showId == show?.id){
@@ -77,17 +100,16 @@ class SeasonActivity : AppCompatActivity(), OnTabSelectedListener {
setObservers()
WebSeriesRepository.loadSeasonListing(showId, categoryId!!)
+ }
+ override fun onDestroy() {
+ super.onDestroy()
+ WebSeriesRepository.clearEpisodeData()
}
private fun initViews() {
if (showData != null && categoryId != null) {
binding.apply {
- showData!!.thumbnail_path?.let {
- Glide.with(applicationContext)
- .load(it)
- .into(image)
- }
likeCount.text = "${showData!!.likes_count}"
@@ -95,6 +117,15 @@ class SeasonActivity : AppCompatActivity(), OnTabSelectedListener {
likeSeason.isSelected = showData!!.is_liked?:false
+ binding.seasonsTab.addOnTabSelectedListener(this@SeasonActivity)
+
+ image.onLoadSuccessListener = {playTrailer.show()}
+
+ rvEpisodes.adapter = episodeAdapter
+ episodeAdapter.onEpisodeClicked = ::onEpisodeClicked
+
+ rvTeaser.adapter = teaserAdapter
+ teaserAdapter.onEpisodeClicked = ::onTeaserClicked
}
}
}
@@ -161,10 +192,16 @@ class SeasonActivity : AppCompatActivity(), OnTabSelectedListener {
private fun setObservers(){
WebSeriesRepository.seasonDataLiveData.observe(this){
+ binding.seasonsTab.removeAllTabs()
when(it){
- is ApiResult.Error -> {}
- is ApiResult.Loading -> {}
+ is ApiResult.Error -> {
+ progressView.hide()
+ }
+ is ApiResult.Loading -> {
+ progressView.show()
+ }
is ApiResult.Success -> {
+ progressView.hide()
it.data?.result?.let {seasonList ->
for (season in seasonList){
if (season == null) continue
@@ -174,9 +211,131 @@ class SeasonActivity : AppCompatActivity(), OnTabSelectedListener {
}
}
}
+
+ WebSeriesRepository.episodeDataLiveData.observe(this){
+ when(it){
+ is ApiResult.Error -> {
+ binding.epShimmer.hide()
+ binding.rvEpisodes.hide()
+ binding.seasonMediaType.hide()
+ }
+ is ApiResult.Loading -> {
+ binding.epShimmer.show()
+ binding.rvEpisodes.hide()
+ binding.seasonMediaType.hide()
+ }
+ is ApiResult.Success -> {
+ it.data?.result?.filterNotNull()?.let {episodeList ->
+
+ if (episodeList.isNotEmpty()){
+ episodeAdapter.submitList(episodeList){
+ binding.epShimmer.hide()
+ binding.rvEpisodes.show()
+ binding.seasonMediaType.show()
+ }
+ }else{
+ binding.epShimmer.hide()
+ binding.seasonMediaType.hide()
+ binding.rvEpisodes.hide()
+ }
+ }
+ }
+ }
+ }
+
+ WebSeriesRepository.teaserDataLiveData.observe(this){
+ when(it){
+ is ApiResult.Error -> {
+ binding.rvTeaser.hide()
+ binding.teaserTxt.hide()
+ }
+ is ApiResult.Loading -> {
+ binding.rvTeaser.hide()
+ binding.teaserTxt.hide()
+ }
+ is ApiResult.Success -> {
+ it.data?.result?.filterNotNull()?.let {episodeList ->
+
+ if (episodeList.isNotEmpty()){
+ teaserAdapter.submitList(episodeList){
+ binding.rvTeaser.show()
+ binding.teaserTxt.show()
+ }
+ }else{
+ binding.teaserTxt.hide()
+ binding.rvTeaser.hide()
+ }
+ }
+ }
+ }
+ }
}
- override fun onTabSelected(p0: TabLayout.Tab?) {}
+ private fun loadSeasonData() {
+ binding.apply {
+ if (seasonsTab.selectedTabPosition >= 0){
+ WebSeriesRepository.seasonDataMap["${showId}_${categoryId}"]?.result?.let {seasonList ->
+ if (seasonsTab.selectedTabPosition < seasonList.size){
+ seasonList[seasonsTab.selectedTabPosition]?.let {seasonData ->
+
+ // loading episode data
+ seasonData.id?.let {
+ selectedSeasonId = it
+ WebSeriesRepository.loadEpisodeData(showId, it)
+ WebSeriesRepository.loadTeaserData(showId, it)
+ }
+
+ seasonYear.text = "${seasonData.release_year}"
+ val noOfEpisodes = "${seasonData.no_of_episodes} ${seasonData.media_type}"
+ episodeNumber.text = noOfEpisodes
+
+ seasonMediaType.text = "${seasonData.media_type}"
+
+ seasonData.thumbnail_path?.let {
+ image.loadImage(it)
+ }
+
+ seasonData.season_more_details?.let {moreDetailsList ->
+ if (moreDetailsList.isNotEmpty()){
+ if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1){
+ moreDetailsList[1]?.let {moreDetails ->
+ seasonTitle.text = moreDetails.title?.uppercase()
+ seasonDescription.text = Html.fromHtml(moreDetails.description?.replace("
", " "), Html.FROM_HTML_MODE_LEGACY)
+ }
+ }else{
+ moreDetailsList[0]?.let {moreDetails ->
+ seasonTitle.text = moreDetails.title?.uppercase()
+ seasonDescription.text = Html.fromHtml(moreDetails.description?.replace("
", " "), Html.FROM_HTML_MODE_LEGACY)
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun onEpisodeClicked(position: Int){
+ startActivity(Intent(this, PlayerActivity::class.java).apply {
+ putParcelableArrayListExtra(EXTRA_PLAY_LIST, WebSeriesRepository.episodesPlaylistMap["${showId}_${selectedSeasonId}_$categoryId"])
+ putExtra(EXTRA_EPISODE_INDEX, position)
+ })
+ }
+
+ private fun onTeaserClicked(position: Int){
+ startActivity(Intent(this, PlayerActivity::class.java).apply {
+ putParcelableArrayListExtra(EXTRA_PLAY_LIST, WebSeriesRepository.teasersPlaylistMap["${showId}_${selectedSeasonId}_$categoryId"])
+ putExtra(EXTRA_EPISODE_INDEX, position)
+ })
+ }
+
+ override fun onTabSelected(p0: TabLayout.Tab?) {
+ binding.playTrailer.hide()
+ loadSeasonData()
+ }
override fun onTabUnselected(p0: TabLayout.Tab?) {}
diff --git a/app/src/main/res/drawable/season_tab_bg.xml b/app/src/main/res/drawable/season_tab_bg.xml
index efc0c84..2027107 100644
--- a/app/src/main/res/drawable/season_tab_bg.xml
+++ b/app/src/main/res/drawable/season_tab_bg.xml
@@ -1,23 +1,18 @@
- -
-
-
-
-
-
-
-
-
+
+
+
+
+
+ -
+
+
- -
-
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_player.xml b/app/src/main/res/layout/activity_player.xml
new file mode 100644
index 0000000..3eeac5d
--- /dev/null
+++ b/app/src/main/res/layout/activity_player.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_season.xml b/app/src/main/res/layout/activity_season.xml
index 20a146c..6956159 100644
--- a/app/src/main/res/layout/activity_season.xml
+++ b/app/src/main/res/layout/activity_season.xml
@@ -1,5 +1,5 @@
-
-
-
-
+ app:isHapticEnabled="true">
+ app:tabSelectedTextColor="@color/white"
+ app:tabTextColor="@color/color_primary" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_web_series.xml b/app/src/main/res/layout/activity_web_series.xml
index e49132a..138d26b 100644
--- a/app/src/main/res/layout/activity_web_series.xml
+++ b/app/src/main/res/layout/activity_web_series.xml
@@ -272,10 +272,9 @@
diff --git a/app/src/main/res/layout/episode_view_holder.xml b/app/src/main/res/layout/episode_view_holder.xml
new file mode 100644
index 0000000..516daaa
--- /dev/null
+++ b/app/src/main/res/layout/episode_view_holder.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/spinner_view_holder.xml b/app/src/main/res/layout/spinner_view_holder.xml
index 690fa32..37eb2c9 100644
--- a/app/src/main/res/layout/spinner_view_holder.xml
+++ b/app/src/main/res/layout/spinner_view_holder.xml
@@ -4,8 +4,6 @@
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
- android:paddingVertical="15dp"
- android:paddingHorizontal="15dp"
xmlns:ools="http://schemas.android.com/apk/res-auto">
@@ -19,6 +17,8 @@
android:textColor="@color/black"
android:textSize="@dimen/_12ssp"
+ android:layout_margin="15dp"
+
android:textAlignment="textStart"
ools:layout_constraintStart_toStartOf="parent"
@@ -36,6 +36,8 @@
android:contentDescription="@string/image"
android:src="@drawable/ic_tick"
+ android:layout_marginEnd="15dp"
+
ools:layout_constraintEnd_toEndOf="parent"
ools:layout_constraintTop_toTopOf="parent"
ools:layout_constraintBottom_toBottomOf="parent"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 933db6c..0a17f55 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -181,4 +181,6 @@
ADD
RATE
SHARE
+ Couldn\'t play video
+ Teasers
\ No newline at end of file