MVVM for web series activity

new fragment for WebShowFragment

load more api integration for episodes and teasers

caching data in same viewmodel
This commit is contained in:
2024-07-17 21:02:20 +05:30
parent c593a7550c
commit 2e2c9cb853
21 changed files with 1408 additions and 87 deletions

View File

@@ -10,6 +10,7 @@ import android.content.Intent.ACTION_TIME_TICK
import android.content.IntentFilter
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -30,9 +31,11 @@ import com.woka.userdata.userDataModels.UserDataResponse
import com.woka.networking.ApiResult
import com.woka.players.views.LiveStreamPlayerActivity
import com.woka.userPreference.UserType
import com.woka.utils.TAG
import com.woka.utils.hide
import com.woka.utils.scaleAnimate
import com.woka.utils.show
import com.woka.utils.toast
import com.woka.webseries.views.SeriesActivity
import com.woka.webseries.views.WebSeriesActivity
import com.woka.wokagames.views.GamesActivity
@@ -441,6 +444,16 @@ class Home1Fragment : Fragment(), Listener {
}
companion object {
fun newInstance() = Home1Fragment()
private var instance: Home1Fragment? = null
private val any = Any()
fun getInstance(): Home1Fragment{
return synchronized(any){
if (instance == null){
instance = Home1Fragment()
}
return@synchronized instance!!
}
}
}
}

View File

@@ -2,6 +2,7 @@ package com.woka.home.fragments
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
@@ -16,8 +17,10 @@ import com.woka.userdata.userDataModels.UserDataResponse
import com.woka.networking.ApiResult
import com.woka.players.views.LiveStreamPlayerActivity
import com.woka.userPreference.UserType
import com.woka.utils.TAG
import com.woka.utils.hide
import com.woka.utils.show
import com.woka.utils.toast
class Home2Fragment : Fragment() {
@@ -141,6 +144,15 @@ class Home2Fragment : Fragment() {
}
companion object {
fun newInstance() = Home2Fragment()
private var instance: Home2Fragment? = null
private val any = Any()
fun getInstance(): Home2Fragment{
return synchronized(any){
if (instance == null){
instance = Home2Fragment()
}
return@synchronized instance!! }
}
}
}

View File

@@ -8,6 +8,7 @@ import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.InsetDrawable
import android.os.Bundle
import android.text.Html
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
@@ -41,6 +42,7 @@ import com.woka.karaoke.models.listing.KaraokeData
import com.woka.networking.ApiResult
import com.woka.players.models.VideoPlayList
import com.woka.players.views.PlayerActivity
import com.woka.utils.TAG
import com.woka.utils.hide
import com.woka.utils.isNetworkConnected
import com.woka.utils.show
@@ -732,6 +734,16 @@ class MyListFragment : Fragment() {
}
companion object {
fun newInstance() = MyListFragment()
private var instance: MyListFragment? = null
private val any = Any()
fun getInstance(): MyListFragment{
return synchronized(any){
if (instance == null){
instance = MyListFragment()
}
return@synchronized instance!!
}
}
}
}

View File

@@ -461,10 +461,9 @@ class HomeActivity : WokaBaseActivity(),
HOME -> {
if (userPrefs?.appTheme == Theme.THEME_TWO){
supportFragmentManager.beginTransaction()
.replace(R.id.fc_home, Home2Fragment.newInstance())
.replace(R.id.fc_home, Home2Fragment.getInstance())
.runOnCommit {
binding.notifications.show()
binding.notiCountView.show()
window.lightStatusBar()
binding.root.backgroundTintList = ColorStateList.valueOf(getColor(R.color.color_primary))
@@ -475,10 +474,9 @@ class HomeActivity : WokaBaseActivity(),
.commit()
}else{
supportFragmentManager.beginTransaction()
.replace(R.id.fc_home, Home1Fragment.newInstance())
.replace(R.id.fc_home, Home1Fragment.getInstance())
.runOnCommit {
binding.notifications.show()
binding.notiCountView.show()
window.lightStatusBar()
binding.root.backgroundTintList = null
@@ -504,7 +502,7 @@ class HomeActivity : WokaBaseActivity(),
unregisterReceiver(minuteReceiver)
supportFragmentManager.beginTransaction()
.replace(R.id.fc_home, MyListFragment.newInstance())
.replace(R.id.fc_home, MyListFragment.getInstance())
.runOnCommit {
binding.root.backgroundTintList = null

View File

@@ -35,39 +35,6 @@ object Repository {
}
}
suspend fun loadTeaserData(showId: Int, seasonId: Int): ApiResult<TeaserResponseData> {
return handleApiCall{
apiService.teaserListing(
FormBody.Builder()
.add("watch_show_master_id", "$showId")
.add("season_master_id", "$seasonId")
.build()
)
}
}
suspend fun loadEpisodeData(showId: Int, seasonId: Int): ApiResult<EpisodeResponseData> {
return handleApiCall {
apiService.episodeListing(
FormBody.Builder()
.add("watch_show_master_id", "$showId")
.add("season_master_id", "$seasonId")
.build()
)
}
}
suspend fun loadSeasonListing(showId: Int, categoryId: String): ApiResult<SeasonDataResponse> {
return handleApiCall {
apiService.seasonListing(
FormBody.Builder()
.add("watch_show_id", "$showId")
.add("category_id", categoryId)
.build()
)
}
}
suspend fun loadContinueWatchData(): ApiResult<ContinueEpisodeResponse> {
return handleApiCall {
userActionApiService.continueWatchingShowListing(
@@ -91,6 +58,47 @@ object Repository {
}
}
suspend fun teaserListing(showId: Int, seasonId: Int): ApiResult<TeaserResponseData> {
return handleApiCall{
apiService.teaserListing(
FormBody.Builder()
.add("watch_show_master_id", "$showId")
.add("season_master_id", "$seasonId")
.build()
)
}
}
suspend fun episodeListing(
showId: String,
seasonId: Int,
pageNo: Int,
quantity: Int
): ApiResult<EpisodeResponseData> {
return handleApiCall {
apiService.episodeListing(
FormBody.Builder()
.add("watch_show_master_id", showId)
.add("season_master_id", "$seasonId")
.add("api_version", "v2")
.add("start", "$pageNo")
.add("limit", "$quantity")
.build()
)
}
}
suspend fun seasonListing(showId: String, categoryId: String): ApiResult<SeasonDataResponse> {
return handleApiCall {
apiService.seasonListing(
FormBody.Builder()
.add("watch_show_id", showId)
.add("category_id", categoryId)
.build()
)
}
}
fun likeUnLikeShow(postId: String, likeIt: Boolean){
CoroutineScope(Dispatchers.IO).launch {
handleApiCall {

View File

@@ -18,7 +18,8 @@ import kotlin.math.max
class WebSeriesShowAdapter(
private val context: Context,
var onShowClicked: (ShowData, Int, String) -> Unit
private var onShowClicked: (ShowData, String) -> Unit,
private var onShowCommonDataChange: ((ShowData, String) -> Unit)? = null
): RecyclerView.Adapter<WebSeriesShowAdapter.ShowViewHolder>() {
inner class ShowViewHolder(val binding: ShowViewHolderBinding): ViewHolder(binding.root)
@@ -102,6 +103,10 @@ class WebSeriesShowAdapter(
showData.likes_count?.let {
likeCount.text = "$it"
}
categoryId?.let {
onShowCommonDataChange?.invoke(showData, it)
}
}
categoryId?.let { fav.isSelected = showData.isBookMarked(it) }
@@ -119,7 +124,13 @@ class WebSeriesShowAdapter(
it
)
showData.addAsBookMark(it)
if (showData.isBookMarked(it)){
// remove from fav
showData.removeAsBookMark(it)
}else{
// add to fav
showData.addAsBookMark(it)
}
fav.isSelected = !fav.isSelected
}
@@ -127,7 +138,7 @@ class WebSeriesShowAdapter(
root.setOnClickListener {
categoryId?.let { categoryId ->
onShowClicked(showData, holder.absoluteAdapterPosition, categoryId)
onShowClicked(showData, categoryId)
}
}
}

View File

@@ -1,6 +1,10 @@
package com.woka.webseries.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class AgeRangeData(
val age_range: String?,
val id: Int?
)
): Parcelable

View File

@@ -1,6 +1,10 @@
package com.woka.webseries.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class CategoryData(
val category_name: String?,
val id: Int?
)
): Parcelable

View File

@@ -1,5 +1,9 @@
package com.woka.webseries.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class ContentMoreDetail(
val content_id: Int?,
val description: String?,
@@ -8,4 +12,4 @@ data class ContentMoreDetail(
val post_type: Int?,
val tags_keywords: String?,
val title: String?
)
): Parcelable

View File

@@ -1,6 +1,10 @@
package com.woka.webseries.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class GenderData(
val gender_name: String?,
val id: Int?
)
): Parcelable

View File

@@ -1,9 +1,10 @@
package com.woka.webseries.models
import android.util.Log
import android.os.Parcelable
import com.woka.home.mylist.models.BookmarkedShowData
import com.woka.utils.TAG
import kotlinx.parcelize.Parcelize
@Parcelize
data class ShowData(
val age_range_data: List<AgeRangeData?>?,
val age_range_master_id: String?,
@@ -26,7 +27,7 @@ data class ShowData(
val total_episodes: Int?,
val total_seasons: Int?,
val views_count: Int?
){
): Parcelable{
constructor(bookMarkShowData: BookmarkedShowData): this(
null,

View File

@@ -1,6 +1,6 @@
package com.woka.webseries.models.episodedata
data class EpisodeResponseData(
val result: List<EpisodeData?>?,
val result: MutableList<EpisodeData?>?,
val total_records: Int?
)

View File

@@ -1,6 +1,6 @@
package com.woka.webseries.models.seasondata
data class SeasonDataResponse(
val result: List<SeasonData?>?,
val result: MutableList<SeasonData?>?,
val total_records: Int?
)

View File

@@ -1,28 +1,30 @@
package com.woka.webseries.viewmodel
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.woka.modules.categorymodels.CategoriesResponse
import com.woka.networking.ApiResult
import com.woka.utils.TAG
import com.woka.players.models.VideoPlayList
import com.woka.webseries.Repository
import com.woka.webseries.models.ContinueEpisodeResponse
import com.woka.webseries.models.ShowData
import com.woka.webseries.models.episodedata.EpisodeData
import com.woka.webseries.models.seasondata.SeasonData
import kotlinx.coroutines.launch
class ViewModel : ViewModel() {
private val repository = Repository
// categories listing
data class PagingData(
var nextPageToLoad: Int = 0, var quantityPerPage: Int = 6,
var lastPage: Boolean = false
)
// categories listing
private val _showCategoryLiveData = MutableLiveData<ApiResult<CategoriesResponse>>()
val showCategoryLiveData: LiveData<ApiResult<CategoriesResponse>>
get() = _showCategoryLiveData
@@ -108,4 +110,126 @@ class ViewModel : ViewModel() {
}
}
}
fun showCommonDataChanged(showData: ShowData, categoryId: String) {
for (cat in webSeriesData.keys){
if (cat == categoryId) continue
webSeriesData[cat]?.let {showList ->
for (show in showList){
if (show.id == showData.id){
// updating common data between categorical lists of show
show.likes_count = showData.likes_count
show.is_liked = showData.is_liked
break
}
}
}
}
}
// seasonListing data
private val _seasonListingLiveData = MutableLiveData<ApiResult<MutableList<SeasonData>>>()
val seasonListingLiveData: LiveData<ApiResult<MutableList<SeasonData>>>
get() = _seasonListingLiveData
// seasons data for every show. where {key -> "showId_categoryId"}
var seasonListingMap = HashMap<String, MutableList<SeasonData>>()
fun seasonListing(showId: String, categoryId: String){
if (seasonListingMap.containsKey("${showId}_${categoryId}")){
_seasonListingLiveData.postValue(ApiResult.Success(seasonListingMap["${showId}_${categoryId}"]))
return
}
viewModelScope.launch {
when (val response = repository.seasonListing(showId, categoryId)){
is ApiResult.Error -> {_seasonListingLiveData.postValue(ApiResult.Error(response.errorMessage, response.error))}
is ApiResult.Loading -> {}
is ApiResult.Success -> {
response.data?.result?.filterNotNull()?.toMutableList()?.let {
seasonListingMap["${showId}_${categoryId}"] = it
_seasonListingLiveData.postValue(ApiResult.Success(it))
}
}
}
}
}
fun clearSeasonLiveData() {
_seasonListingLiveData.postValue(ApiResult.Loading())
}
// episode listing data
private val _episodeListingLiveData = MutableLiveData<ApiResult<MutableList<EpisodeData>>>()
val episodeListingLiveData: LiveData<ApiResult<MutableList<EpisodeData>>>
get() = _episodeListingLiveData
var episodePagingData = HashMap<String, PagingData>()
// episode data for every season. where {key -> "showId_seasonId"}
private var episodeDataMap = HashMap<String, MutableList<EpisodeData>>()
// episodes playlist, where {key -> "showId_seasonId_categoryId"}
val episodesPlaylistMap = HashMap<String, VideoPlayList>()
fun loadEpisodes(showId: String, seasonId: Int){
val key = "${showId}_$seasonId"
if (episodeDataMap.containsKey(key) && episodeDataMap[key]?.isNotEmpty() == true){
_episodeListingLiveData.postValue(ApiResult.Success(episodeDataMap[key]))
}else{
loadMoreEpisodes(showId, seasonId)
}
}
fun loadMoreEpisodes(showId: String, seasonId: Int) {
viewModelScope.launch {
_episodeListingLiveData.postValue(ApiResult.Loading())
val key = "${showId}_$seasonId"
val pagingData = if (episodePagingData.containsKey(key)){
episodePagingData[key]!!
}else{
val pagingData = PagingData()
episodePagingData[key] = pagingData
pagingData
}
when (val response = repository.episodeListing(showId, seasonId, pagingData.nextPageToLoad, pagingData.quantityPerPage)) {
is ApiResult.Error -> {
_episodeListingLiveData.postValue(
ApiResult.Error(
response.errorMessage,
response.error
)
)
}
is ApiResult.Loading -> {
_episodeListingLiveData.postValue(ApiResult.Loading())
}
is ApiResult.Success -> {
response.data?.let { data ->
data.result?.filterNotNull()?.let { newList ->
val currentList = episodeDataMap.getOrDefault(key, ArrayList())
currentList.addAll(newList)
episodeDataMap[key] = currentList
pagingData.lastPage = episodeDataMap[key]?.size == data.total_records
_episodeListingLiveData.postValue(ApiResult.Success(episodeDataMap[key]))
pagingData.nextPageToLoad++
}
}
}
}
}
}
fun clearEpisodeListingLiveData(){
_episodeListingLiveData.postValue(ApiResult.Loading())
}
}

View File

@@ -48,11 +48,10 @@ class SeasonActivity : WokaBaseActivity(), OnTabSelectedListener {
}
private lateinit var binding: ActivitySeasonBinding
private var showId: Int = -1
private var categoryId: String? = null
private var showData: ShowData? = null
private var showPosition: Int = -1
private lateinit var progressView: ProgressView

View File

@@ -29,9 +29,6 @@ class SeriesActivity : WokaBaseActivity() {
supportFragmentManager.beginTransaction()
.add(R.id.fcv_web_series, WebSeriesFragment.newInstance())
.runOnCommit {
window.setBackgroundDrawable(AppCompatResources.getDrawable(this, R.drawable.gradient_web_series))
}
.commit()
}
}

View File

@@ -288,11 +288,10 @@ class WebSeriesActivity : WokaBaseActivity(), Observer<ApiResult<HashMap<String,
}
}
private fun onShowClicked(showData: ShowData, position: Int, categoryId: String){
private fun onShowClicked(showData: ShowData, categoryId: String){
showIntentLauncher?.launch(Intent(this, SeasonActivity::class.java).apply {
putExtra(SeasonActivity.EXTRA_SHOW_ID, showData.id)
putExtra(SeasonActivity.EXTRA_SHOW_CATEGORY_DATA, categoryId)
putExtra(SeasonActivity.EXTRA_SHOW_POSITION, position)
})
}

View File

@@ -12,6 +12,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.AdapterView
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.SimpleItemAnimator
@@ -29,6 +30,7 @@ import com.woka.players.views.PlayerActivity.Companion.EXTRA_PLAY_INDEX
import com.woka.players.views.PlayerActivity.Companion.EXTRA_PLAY_LIST
import com.woka.userPreference.UserType
import com.woka.utils.hide
import com.woka.utils.lightStatusBar
import com.woka.utils.setVisibility
import com.woka.utils.show
import com.woka.webseries.adapters.ContinueEpisodeAdapter
@@ -37,13 +39,11 @@ import com.woka.webseries.adapters.WebSeriesShowAdapter
import com.woka.webseries.models.ContinueEpisodeData
import com.woka.webseries.models.ShowData
import com.woka.webseries.viewmodel.ViewModel
import java.util.Collections
class WebSeriesFragment private constructor(): Fragment() {
private lateinit var binding: FragmentWebSeriesBinding
private lateinit var viewModel: ViewModel
private var viewModel: ViewModel? = null
private lateinit var showAdapter: WebSeriesShowAdapter
@@ -54,6 +54,8 @@ class WebSeriesFragment private constructor(): Fragment() {
private lateinit var episodeDialogBinding: DialogContinueEpisodeBinding
private lateinit var episodeDialog: Dialog
private var loadingMore = false
companion object {
fun newInstance() = WebSeriesFragment()
}
@@ -63,7 +65,12 @@ class WebSeriesFragment private constructor(): Fragment() {
savedInstanceState: Bundle?
): View {
binding = FragmentWebSeriesBinding.inflate(inflater, container, false)
viewModel = ViewModelProvider(this)[ViewModel::class.java]
activity?.let {
it.window.setBackgroundDrawable(AppCompatResources.getDrawable(it, R.drawable.gradient_web_series))
it.window.statusBarColor = 0
it.window.lightStatusBar(false)
viewModel = ViewModelProvider(it)[ViewModel::class.java]
}
return binding.root
}
@@ -78,8 +85,8 @@ class WebSeriesFragment private constructor(): Fragment() {
setObservers()
if (!viewModel.showCategoryLiveData.isInitialized){
viewModel.loadCategories()
if (viewModel?.showCategoryLiveData?.isInitialized == false){
viewModel?.loadCategories()
}
}
@@ -93,12 +100,13 @@ class WebSeriesFragment private constructor(): Fragment() {
binding.shimmer.show()
binding.errorView.hide()
viewModel.loadCategories()
viewModel?.loadCategories()
}
loadMoreBtn.setOnClickListener {
catSpinnerAdapter?.selectedCategoryType?.let {
viewModel.loadMoreWebSeries(it)
loadingMore = true
viewModel?.loadMoreWebSeries(it)
}
}
}
@@ -107,7 +115,7 @@ class WebSeriesFragment private constructor(): Fragment() {
// adapters
activity?.let {
showAdapter = WebSeriesShowAdapter(it, ::onShowClicked)
showAdapter = WebSeriesShowAdapter(it, ::onShowClicked, ::onShowCommonDataChange)
continueWatchAdapter = ContinueEpisodeAdapter(it)
}
@@ -166,13 +174,13 @@ class WebSeriesFragment private constructor(): Fragment() {
private fun loadShowData(){
catSpinnerAdapter?.selectedCategoryType?.let {
showAdapter.submitListShowList(Collections.emptyList(), it)
viewModel.loadWebSeries(it)
loadingMore = false
viewModel?.loadWebSeries(it)
}
}
private fun setObservers(){
viewModel.showCategoryLiveData.observe(viewLifecycleOwner){
viewModel?.showCategoryLiveData?.observe(viewLifecycleOwner){
when(it){
is ApiResult.Error -> {
binding.errorView.show()
@@ -195,14 +203,16 @@ class WebSeriesFragment private constructor(): Fragment() {
binding.categorySpinner.setAdapter(catSpinnerAdapter)
loadShowData()
viewModel.loadContinueWatching()
if (userPrefs?.userType != UserType.GUEST && viewModel?.continueWatchLiveData?.isInitialized == false){
viewModel?.loadContinueWatching()
}
}
}
}
}
}
viewModel.continueWatchLiveData.observe(viewLifecycleOwner){
viewModel?.continueWatchLiveData?.observe(viewLifecycleOwner){
when (it){
is ApiResult.Error -> {
binding.rvContinueWatch.hide()
@@ -224,11 +234,11 @@ class WebSeriesFragment private constructor(): Fragment() {
}
}
viewModel.webSeriesLiveData.observe(viewLifecycleOwner){
viewModel?.webSeriesLiveData?.observe(viewLifecycleOwner){
when (it){
is ApiResult.Error -> {
binding.shimmerShowData.hide()
if (showAdapter.showList.isNotEmpty()){
if (loadingMore){
// load more
binding.loadMoreBtn.text = getString(R.string.retry)
binding.loadMoreBtn.show()
@@ -242,7 +252,7 @@ class WebSeriesFragment private constructor(): Fragment() {
is ApiResult.Loading -> {
binding.shimmerShowData.show()
binding.loadMoreBtn.hide()
binding.rvWebSeries.setVisibility(showAdapter.showList.isNotEmpty())
binding.rvWebSeries.setVisibility(loadingMore)
}
is ApiResult.Success -> {
catSpinnerAdapter?.selectedCategoryType?.let { categoryType ->
@@ -252,9 +262,9 @@ class WebSeriesFragment private constructor(): Fragment() {
binding.shimmerShowData.hide()
binding.loadMoreBtn.text = getString(R.string.load_more)
binding.loadMoreBtn.setVisibility(viewModel.categoryPagingData[categoryType]?.lastPage == false)
binding.loadMoreBtn.setVisibility(viewModel?.categoryPagingData?.get(categoryType)?.lastPage == false)
if (showAdapter.showList.isNotEmpty()){
if (loadingMore){
// loaded more data
showAdapter.notifyItemRangeInserted(
showAdapter.showList.size,
@@ -264,10 +274,6 @@ class WebSeriesFragment private constructor(): Fragment() {
// new category data load
showAdapter.submitListShowList(showList, categoryType)
}
if (userPrefs?.userType != UserType.GUEST && !viewModel.continueWatchLiveData.isInitialized){
viewModel.loadContinueWatching()
}
}
}
}
@@ -294,8 +300,18 @@ class WebSeriesFragment private constructor(): Fragment() {
}
}
private fun onShowClicked(showData: ShowData, position: Int, categoryId: String){
private fun onShowClicked(showData: ShowData, categoryId: String){
parentFragmentManager.beginTransaction()
.add(R.id.fcv_web_series, WebShowFragment.newInstance(showData, categoryId))
.hide(this)
.addToBackStack(null)
.commit()
}
// updating common data of shows across all category show list
private fun onShowCommonDataChange(showData: ShowData, categoryId: String){
// changing in viewmodel data
viewModel?.showCommonDataChanged(showData, categoryId)
}
private fun onContinueEpisodeClicked(episodeData: ContinueEpisodeData){

View File

@@ -0,0 +1,552 @@
package com.woka.webseries.views.fragments
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.InsetDrawable
import android.os.Bundle
import android.text.Html
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.tabs.TabLayout
import com.woka.R
import com.woka.WokaApp.Companion.userPrefs
import com.woka.databinding.DialogEpisodeBinding
import com.woka.databinding.FragmentWebShowBinding
import com.woka.networking.ApiResult
import com.woka.utils.hide
import com.woka.utils.isNetworkConnected
import com.woka.utils.lightStatusBar
import com.woka.utils.setVisibility
import com.woka.utils.show
import com.woka.utils.toast
import com.woka.webseries.Repository
import com.woka.webseries.adapters.EpisodeAdapter
import com.woka.webseries.adapters.TeaserAdapter
import com.woka.webseries.models.ShowData
import com.woka.webseries.models.episodedata.EpisodeData
import com.woka.webseries.models.teaserdata.TeaserData
import com.woka.webseries.viewmodel.ViewModel
private const val EXTRA_SHOW_DATA = "extra_show_id_data"
private const val EXTRA_SHOW_CATEGORY_ID = "extra_show_category_data"
class WebShowFragment private constructor(): Fragment(), TabLayout.OnTabSelectedListener {
companion object {
fun newInstance(showData: ShowData, categoryId: String) =
WebShowFragment().apply {
arguments = Bundle().apply {
putParcelable(EXTRA_SHOW_DATA, showData)
putString(EXTRA_SHOW_CATEGORY_ID, categoryId)
}
}
}
private lateinit var binding: FragmentWebShowBinding
private var viewModel: ViewModel? = null
// arguments
private var categoryId: String? = null
private var showData: ShowData? = null
// variables
private lateinit var episodeAdapter: EpisodeAdapter
private lateinit var teaserAdapter: TeaserAdapter
private var selectedSeasonId = -1
private lateinit var episodeDialogBinding: DialogEpisodeBinding
private lateinit var episodeDialog: Dialog
private var loadMoreEpisodes = false
override fun onAttach(context: Context) {
super.onAttach(context)
episodeAdapter = EpisodeAdapter(context)
teaserAdapter = TeaserAdapter(context)
episodeDialog = Dialog(context)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
showData = it.getParcelable(EXTRA_SHOW_DATA)
categoryId = it.getString(EXTRA_SHOW_CATEGORY_ID)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentWebShowBinding.inflate(inflater, container, false)
viewModel = ViewModelProvider(this)[ViewModel::class.java]
activity?.let {
it.window.setBackgroundDrawableResource(R.color.web_show_bg)
it.window.lightStatusBar(true)
viewModel = ViewModelProvider(it)[ViewModel::class.java]
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
initEpisodeDialog()
clickEvents()
setObservers()
binding.seasonProgressView.show()
viewModel?.seasonListing("${showData?.id}", "$categoryId")
}
override fun onDestroyView() {
super.onDestroyView()
activity?.let {
it.window.setBackgroundDrawable(AppCompatResources.getDrawable(it, R.drawable.gradient_web_series))
it.window.statusBarColor = 0
it.window.lightStatusBar(false)
}
viewModel?.clearSeasonLiveData()
viewModel?.clearEpisodeListingLiveData()
}
// initializations
private fun initViews() {
if (showData != null && categoryId != null) {
binding.apply {
likeCount.text = "${showData!!.likes_count}"
favSeason.isSelected = showData!!.isBookMarked(categoryId!!)
likeSeason.isSelected = showData!!.is_liked ?: false
binding.seasonsTab.addOnTabSelectedListener(this@WebShowFragment)
rvEpisodes.adapter = episodeAdapter
episodeAdapter.onEpisodeClicked = ::onEpisodeClicked
episodeAdapter.onEpisodePlayClicked = ::onEpisodePlayClicked
rvTeaser.adapter = teaserAdapter
teaserAdapter.onEpisodeClicked = ::onTeaserClicked
teaserAdapter.onEpisodePlayClicked = ::onTeaserPlayClicked
}
}
}
private fun clickEvents() {
if (showData == null || categoryId == null) return
binding.apply {
backBtn.setOnClickListener {
activity?.onBackPressedDispatcher?.onBackPressed()
}
watchCard.setOnClickListener {
playTrailer.performClick()
}
epLoadMoreBtn.setOnClickListener {
loadMoreEpisodes = true
viewModel?.loadMoreEpisodes("${showData?.id}", selectedSeasonId)
}
likeSeason.setOnClickListener {
if (activity?.isNetworkConnected() == false) {
toast(getString(R.string.no_internet))
return@setOnClickListener
}
Repository.likeUnLikeShow("${showData?.id}", showData?.is_liked == false)
likeSeason.isSelected = !likeSeason.isSelected
likeCount.text = "${showData?.likes_count}"
}
favSeason.setOnClickListener {
if (activity?.isNetworkConnected() == false) {
toast(getString(R.string.no_internet))
return@setOnClickListener
}
if (showData == null) return@setOnClickListener
categoryId?.let {
Repository.updateFavShow(
showData!!,
showData?.isBookMarked("$categoryId") == false,
"$categoryId"
)
favSeason.isSelected = !favSeason.isSelected
}
}
playTrailer.setOnClickListener {
// if (seasonsTab.selectedTabPosition >= 0) {
// WebSeriesRepository.seasonDataMap["${showId}_${categoryId}"]?.result?.let { seasonList ->
// if (seasonsTab.selectedTabPosition < seasonList.size) {
// seasonList[seasonsTab.selectedTabPosition]?.let { seasonData ->
//
// seasonData.season_more_details?.let { moreDetailsList ->
// if (moreDetailsList.isNotEmpty()) {
// val videoPlayList = VideoPlayList(ArrayList())
//
// val playlistItem = PlaylistItem.Builder()
//
// if (categoryId == "18" && moreDetailsList.size > 1) {
// moreDetailsList[1]?.let { seasonMoreData ->
// playlistItem.title(seasonMoreData.title)
// playlistItem.image(seasonMoreData.trailer_hd_url)
// playlistItem.file(seasonMoreData.trailer_hd_url)
// }
// } else {
// moreDetailsList[0]?.let { seasonMoreData ->
// playlistItem.title(seasonMoreData.title)
// playlistItem.image(seasonMoreData.trailer_hd_url)
// playlistItem.file(seasonMoreData.trailer_hd_url)
// }
// }
//
// videoPlayList.playlist.add(playlistItem.build())
//
// startActivity(
// Intent(this@SeasonActivity, PlayerActivity::class.java)
// .apply {
// putExtra(
// PlayerActivity.EXTRA_PLAY_LIST,
// videoPlayList
// )
// }
// )
// }
// }
// }
// }
// }
// }
}
}
}
private fun initEpisodeDialog() {
episodeDialogBinding = DialogEpisodeBinding.inflate(layoutInflater)
episodeDialog.setContentView(episodeDialogBinding.root)
try {
val back = ColorDrawable(Color.TRANSPARENT)
val inset = InsetDrawable(back, 50)
episodeDialog.window!!.setBackgroundDrawable(inset)
} catch (e: Exception) {
// do nothing
}
try {
val layoutParams = episodeDialog.window!!.attributes
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT
episodeDialog.window!!.setAttributes(layoutParams)
} catch (e: Exception) {
// do nothing
}
episodeDialogBinding.close.setOnClickListener { episodeDialog.dismiss() }
}
// callbacks
private fun setObservers(){
viewModel?.seasonListingLiveData?.observe(viewLifecycleOwner){
binding.seasonsTab.removeAllTabs()
when (it) {
is ApiResult.Error -> {
binding.seasonProgressView.hide()
}
is ApiResult.Loading -> {
binding.seasonProgressView.show()
}
is ApiResult.Success -> {
binding.seasonProgressView.hide()
it.data?.let {seasonList ->
for (season in seasonList){
binding.seasonsTab.addTab(
binding.seasonsTab.newTab().setText("${season.season_number}")
)
}
}
}
}
}
viewModel?.episodeListingLiveData?.observe(viewLifecycleOwner){
when (it){
is ApiResult.Error -> {
binding.epShimmer.hide()
if (loadMoreEpisodes){
// load more
binding.epLoadMoreBtn.text = getString(R.string.retry)
binding.epLoadMoreBtn.show()
}else{
// first time load
binding.rvEpisodes.hide()
binding.epShimmer.hide()
binding.epLoadMoreBtn.hide()
}
}
is ApiResult.Loading -> {
binding.epShimmer.show()
binding.epLoadMoreBtn.hide()
binding.rvEpisodes.setVisibility(loadMoreEpisodes)
}
is ApiResult.Success -> {
it.data?.let {episodeList ->
binding.rvEpisodes.show()
binding.epShimmer.hide()
binding.epLoadMoreBtn.text = getString(R.string.load_more)
binding.epLoadMoreBtn.setVisibility(viewModel?.episodePagingData?.get("${showData?.id}_$selectedSeasonId")?.lastPage == false)
if (loadMoreEpisodes){
// loaded more data
episodeAdapter.notifyItemRangeInserted(
episodeAdapter.currentList.size,
episodeList.size
)
}else{
// new category data load
episodeAdapter.submitList(episodeList)
}
}
}
}
}
}
private fun onEpisodeClicked(position: Int, episodeData: EpisodeData) {
episodeDialogBinding.apply {
episodeData.content_more_details?.let { moreDetailsList ->
episodeData.thumbnail_path?.let {
image.loadImage(it)
}
if (moreDetailsList.isNotEmpty()) {
if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1) {
moreDetailsList[1]?.let { data ->
title.text = data.title
description.text = Html.fromHtml(
data.description?.replace(
"<br>",
" "
), Html.FROM_HTML_MODE_LEGACY
)
val mediaType =
"${getString(R.string.episode)} ${episodeData.episode_number}"
mediaTypeNumber.text = mediaType
duration.text = episodeData.episode_duration
}
} else {
moreDetailsList[0]?.let { data ->
title.text = data.title
description.text = Html.fromHtml(
data.description?.replace(
"<br>",
" "
), Html.FROM_HTML_MODE_LEGACY
)
val mediaType =
"${getString(R.string.episode)} ${episodeData.episode_number}"
mediaTypeNumber.text = mediaType
duration.text = episodeData.episode_duration
}
}
} else {
title.text = episodeData.episode_title
description.text = Html.fromHtml(
episodeData.episode_description?.replace(
"<br>",
" "
), Html.FROM_HTML_MODE_LEGACY
)
val mediaType = "${getString(R.string.episode)} ${episodeData.episode_number}"
mediaTypeNumber.text = mediaType
duration.text = episodeData.episode_duration
}
watchCard.setOnClickListener {
onEpisodePlayClicked(position)
}
close.setOnClickListener {
episodeDialog.dismiss()
}
episodeDialog.show()
}
}
}
private fun onEpisodePlayClicked(position: Int) {
}
private fun onTeaserClicked(position: Int, teaserData: TeaserData) {
episodeDialogBinding.apply {
teaserData.content_more_details?.let { moreDetailsList ->
teaserData.thumbnail_path?.let {
image.loadImage(it)
}
if (moreDetailsList.isNotEmpty()) {
if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1) {
moreDetailsList[1]?.let { data ->
title.text = data.title
description.text = Html.fromHtml(
data.description?.replace(
"<br>",
" "
), Html.FROM_HTML_MODE_LEGACY
)
val mediaType =
"${getString(R.string.teasers)} ${teaserData.teaser_number}"
mediaTypeNumber.text = mediaType
duration.text = teaserData.teaser_duration
}
} else {
moreDetailsList[0]?.let { data ->
title.text = data.title
description.text = Html.fromHtml(
data.description?.replace(
"<br>",
" "
), Html.FROM_HTML_MODE_LEGACY
)
val mediaType =
"${getString(R.string.teasers)} ${teaserData.teaser_number}"
mediaTypeNumber.text = mediaType
duration.text = teaserData.teaser_duration
}
}
} else {
title.text = teaserData.teaser_title
description.text = Html.fromHtml(
teaserData.teaser_description?.replace(
"<br>",
" "
), Html.FROM_HTML_MODE_LEGACY
)
val mediaType = "${getString(R.string.teasers)} ${teaserData.teaser_number}"
mediaTypeNumber.text = mediaType
duration.text = teaserData.teaser_duration
}
watchCard.setOnClickListener {
onTeaserPlayClicked(position)
}
close.setOnClickListener {
episodeDialog.dismiss()
}
episodeDialog.show()
}
}
}
private fun loadSeasonData() {
binding.apply {
if (seasonsTab.selectedTabPosition >= 0) {
viewModel?.seasonListingMap?.get("${showData?.id}_${categoryId}")?.let { seasonList ->
if (seasonsTab.selectedTabPosition < seasonList.size) {
seasonList[seasonsTab.selectedTabPosition].let { seasonData ->
playTrailer.show()
detailsProgressiveView.hide()
detailsView.show()
// loading episode data
seasonData.id?.let {
selectedSeasonId = it
loadMoreEpisodes = false
viewModel?.loadEpisodes("${showData?.id}", 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(
"<br>",
" "
), Html.FROM_HTML_MODE_LEGACY
)
}
} else {
moreDetailsList[0]?.let { moreDetails ->
seasonTitle.text = moreDetails.title?.uppercase()
seasonDescription.text = Html.fromHtml(
moreDetails.description?.replace(
"<br>",
" "
), Html.FROM_HTML_MODE_LEGACY
)
}
}
}
}
}
}
}
}
}
}
private fun onTeaserPlayClicked(position: Int) {
}
// season tab selection
override fun onTabSelected(p0: TabLayout.Tab?) {
loadSeasonData()
}
override fun onTabUnselected(p0: TabLayout.Tab?) {}
override fun onTabReselected(p0: TabLayout.Tab?) {}
}

View File

@@ -0,0 +1,562 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_primary"
tools:context=".webseries.views.SeasonActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/img_season_bg"
android:orientation="vertical"
android:paddingHorizontal="15dp"
android:paddingTop="15dp"
android:paddingBottom="40dp">
<ImageView
android:id="@+id/back_btn"
android:layout_width="@dimen/_25sdp"
android:layout_height="@dimen/_25sdp"
android:contentDescription="@string/back_btn"
android:scaleType="fitXY"
android:src="@drawable/ic_arrow_back_full"
android:translationZ="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/color_primary" />
<androidx.cardview.widget.CardView
android:id="@+id/trailer_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/back_btn">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/_140sdp"
android:layout_margin="10dp">
<com.woka.utils.AdiImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/masila"
android:scaleType="fitXY"
android:src="@android:color/darker_gray"
app:imageCornerRadius="5dp"
tools:src="@drawable/img_masila_tn_small" />
<com.woka.utils.PressableCard
android:id="@+id/play_trailer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/round_25"
android:backgroundTint="@color/color_primary"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginVertical="10dp"
android:fontFamily="@font/exo_2_bold"
android:text="@string/play_trailer"
android:textColor="@color/white"
/>
</com.woka.utils.PressableCard>
</RelativeLayout>
</androidx.cardview.widget.CardView>
<com.facebook.shimmer.ShimmerFrameLayout
android:id="@+id/details_progressive_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/trailer_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginTop="15dp"
android:background="@color/black_50" />
<View
android:layout_width="200dp"
android:layout_height="30dp"
android:layout_marginTop="15dp"
android:background="@color/black_50" />
<View
android:layout_width="100dp"
android:layout_height="30dp"
android:layout_marginTop="15dp"
android:background="@color/black_50" />
<View
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginTop="15dp"
android:background="@color/black_50" />
</LinearLayout>
</com.facebook.shimmer.ShimmerFrameLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/details_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/trailer_card">
<TextView
android:id="@+id/season_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="@font/exo_2_extrabold"
android:textColor="@color/color_primary"
android:textSize="@dimen/_16ssp"
app:layout_constraintTop_toTopOf="parent"
tools:text="HIP HIPPOS ADVENTURES"
/>
<TextView
android:id="@+id/season_year"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:fontFamily="@font/exo_2"
android:textColor="@color/color_primary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/season_title"
tools:text="2022"
/>
<TextView
android:id="@+id/episode_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:layout_marginTop="5dp"
android:fontFamily="@font/exo_2"
android:textColor="@color/color_primary"
app:layout_constraintStart_toEndOf="@id/season_year"
app:layout_constraintTop_toBottomOf="@id/season_title"
tools:text="5 EPISODES"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/season_title">
<ImageView
android:layout_width="25dp"
android:layout_height="25dp"
android:contentDescription="@string/image"
android:src="@drawable/ic_like_filled" />
<TextView
android:id="@+id/like_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:layout_marginTop="2dp"
android:fontFamily="@font/exo_2_semibold"
android:textAlignment="center"
android:textColor="@color/color_primary"
android:textSize="@dimen/_14ssp"
tools:text="10"
/>
</LinearLayout>
<TextView
android:id="@+id/season_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/exo_2"
android:textColor="@color/color_primary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/season_year"
tools:text="Adventures of a powerful but dimwitted cyborg police inspector named Gadget as he investigates the criminal schemes of Dr. Claw and his organization, M.A.D"
/>
<Button
android:id="@+id/watch_card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/round_bg_25"
android:backgroundTint="#5E1FC4"
android:drawableStart="@drawable/ic_play_filled"
android:drawablePadding="15dp"
android:fontFamily="@font/exo_2_extrabold"
android:paddingVertical="10dp"
android:paddingStart="15dp"
android:paddingEnd="20dp"
android:text="@string/watch"
android:textColor="@color/white"
android:visibility="visible"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/season_description"
/>
<LinearLayout
android:id="@+id/rate_season_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:gravity="center_horizontal"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@id/watch_card"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/watch_card">
<ImageView
android:id="@+id/like_season"
android:layout_width="25dp"
android:layout_height="25dp"
android:contentDescription="@string/image"
android:src="@drawable/ic_like_selector" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:fontFamily="@font/exo_2"
android:text="@string/rate"
android:textColor="@color/color_primary" />
</LinearLayout>
<View
android:id="@+id/divider_1"
android:layout_width="0.5dp"
android:layout_height="40dp"
android:layout_marginEnd="15dp"
android:background="@color/color_primary"
app:layout_constraintBottom_toBottomOf="@id/watch_card"
app:layout_constraintEnd_toStartOf="@id/rate_season_ll"
app:layout_constraintTop_toTopOf="@id/watch_card"
/>
<LinearLayout
android:id="@+id/share_season_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:gravity="center_horizontal"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@id/watch_card"
app:layout_constraintEnd_toStartOf="@id/divider_1"
app:layout_constraintTop_toTopOf="@id/watch_card">
<ImageView
android:id="@+id/share_season"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/image"
android:src="@drawable/ic_share" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:fontFamily="@font/exo_2"
android:text="@string/share"
android:textColor="@color/color_primary" />
</LinearLayout>
<View
android:id="@+id/divider_2"
android:layout_width="0.5dp"
android:layout_height="40dp"
android:layout_marginEnd="15dp"
android:background="@color/color_primary"
app:layout_constraintBottom_toBottomOf="@id/watch_card"
app:layout_constraintEnd_toStartOf="@id/share_season_ll"
app:layout_constraintTop_toTopOf="@id/watch_card"
/>
<LinearLayout
android:id="@+id/fav_season_LL"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:gravity="center_horizontal"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@id/watch_card"
app:layout_constraintEnd_toStartOf="@id/divider_2"
app:layout_constraintTop_toTopOf="@id/watch_card">
<ImageView
android:id="@+id/fav_season"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/image"
android:src="@drawable/ic_heart_select" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:fontFamily="@font/exo_2"
android:text="@string/add"
android:textColor="@color/color_primary" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.facebook.shimmer.ShimmerFrameLayout
android:id="@+id/season_progress_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:visibility="gone"
app:shimmer_auto_start="true"
app:shimmer_base_alpha="0.6"
app:shimmer_highlight_alpha="0.5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<View
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginStart="15dp"
android:background="@drawable/round_bg_25"
android:backgroundTint="@color/white_50" />
<View
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginStart="15dp"
android:background="@drawable/round_bg_25"
android:backgroundTint="@color/white_50" />
</LinearLayout>
</com.facebook.shimmer.ShimmerFrameLayout>
<com.google.android.material.tabs.TabLayout
android:id="@+id/seasons_tab"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="5dp"
android:layout_marginTop="15dp"
app:tabBackground="@drawable/season_tab_bg"
app:tabGravity="start"
app:tabIndicatorHeight="0dp"
app:tabMode="scrollable"
app:tabPaddingEnd="25dp"
app:tabPaddingStart="25dp"
app:tabRippleColor="@android:color/transparent"
app:tabSelectedTextColor="@color/white"
app:tabTextColor="@color/color_primary" />
<TextView
android:id="@+id/season_media_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="15dp"
android:fontFamily="@font/exo_2_bold"
android:textColor="@color/white"
android:textSize="@dimen/_14ssp"
android:visibility="gone"
tools:text="Episodes" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_episodes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:orientation="vertical"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/episode_view_holder" />
<Button
android:id="@+id/ep_load_more_btn"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/load_more"
android:fontFamily="@font/exo_2_bold"
android:textColor="@color/white"
android:textSize="@dimen/_12ssp"
android:paddingHorizontal="25dp"
android:layout_marginVertical="15dp"
android:background="@drawable/round_25"
android:backgroundTint="@color/night_status"
android:layout_gravity="center_horizontal"
/>
<com.facebook.shimmer.ShimmerFrameLayout
android:id="@+id/ep_shimmer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:shimmer_auto_start="true"
app:shimmer_base_alpha="0.6"
app:shimmer_highlight_alpha="0.5">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/episode_view_holder" />
<include layout="@layout/episode_view_holder" />
<include layout="@layout/episode_view_holder" />
<include layout="@layout/episode_view_holder" />
</LinearLayout>
</ScrollView>
</com.facebook.shimmer.ShimmerFrameLayout>
<TextView
android:id="@+id/teaser_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="10dp"
android:fontFamily="@font/exo_2_bold"
android:text="@string/teasers"
android:textColor="@color/white"
android:textSize="@dimen/_14ssp"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_teaser"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:orientation="vertical"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/episode_view_holder" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -27,4 +27,5 @@
<color name="light_blue_A200">#FF40C4FF</color>
<color name="light_blue_A400">#FF00B0FF</color>
<color name="black_overlay">#66000000</color>
<color name="web_show_bg">#D3EFF8</color>
</resources>