diff --git a/app/src/main/java/com/woka/audiobooks/views/AudioBooksActivity.kt b/app/src/main/java/com/woka/audiobooks/views/AudioBooksActivity.kt index 73d563d..3f0a839 100644 --- a/app/src/main/java/com/woka/audiobooks/views/AudioBooksActivity.kt +++ b/app/src/main/java/com/woka/audiobooks/views/AudioBooksActivity.kt @@ -8,6 +8,7 @@ import android.graphics.drawable.InsetDrawable import android.net.Uri import android.os.Bundle import android.text.Html +import android.util.Log import android.view.WindowManager import androidx.activity.enableEdgeToEdge import androidx.activity.result.ActivityResultLauncher @@ -52,7 +53,6 @@ import com.woka.utils.WokaBaseActivity import com.woka.utils.hide import com.woka.utils.isNetworkConnected import com.woka.utils.lightStatusBar -import com.woka.utils.setVisibility import com.woka.utils.shareWokaApp import com.woka.utils.show import com.woka.utils.toast @@ -80,6 +80,8 @@ class AudioBooksActivity : WokaBaseActivity() { private var customAdLoaded = false private var shallLoadGoogleAd = false + private var isLoading = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() @@ -112,6 +114,8 @@ class AudioBooksActivity : WokaBaseActivity() { customAdLoaded = false + isLoading = false + initLaunchers() initViews() @@ -156,6 +160,27 @@ class AudioBooksActivity : WokaBaseActivity() { rvContinueListen.adapter = continueAudioAdapter (rvContinueListen.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false + + + nestedScrollView.viewTreeObserver?.addOnScrollChangedListener { + if (nestedScrollView.childCount == 0) return@addOnScrollChangedListener + + nestedScrollView.getChildAt(0)?.let {child -> + val v = nestedScrollView + + val scrolledHeight = v.scrollY + v.height + val totalHeight = child.measuredHeight + + val percentageScrolled = (scrolledHeight.toFloat()/totalHeight.toFloat()) * 100 + + if (percentageScrolled >= 60) { + if (!isLoading && !viewModel.lastPage && isNetworkConnected()){ + isLoading = true + viewModel.loadAudioSongs() + } + } + } + } } } @@ -196,12 +221,6 @@ class AudioBooksActivity : WokaBaseActivity() { ClicksHelper.upsertClickEvent(ContentType.OTHERS) } - - loadMoreBtn.setOnClickListener { - viewModel.loadAudioSongs() - - ClicksHelper.upsertClickEvent(ContentType.OTHERS) - } } } @@ -256,6 +275,8 @@ class AudioBooksActivity : WokaBaseActivity() { viewModel.audioBookLiveData.observe(this) { when (it) { is ApiResult.Error -> { + isLoading = false + binding.shimmer.hide() if (audioBookAdapter.currentList.size == 0) { // none of the data is yet loaded @@ -267,12 +288,12 @@ class AudioBooksActivity : WokaBaseActivity() { } else { // error in loading more binding.loadMoreProgress.hide() - binding.loadMoreBtn.text = getString(R.string.retry) - binding.loadMoreBtn.show() } } is ApiResult.Loading -> { + isLoading = true + if (audioBookAdapter.currentList.size == 0) { // loading first data binding.shimmer.show() @@ -280,13 +301,14 @@ class AudioBooksActivity : WokaBaseActivity() { } else { // loading more data binding.loadMoreProgress.show() - binding.loadMoreBtn.hide() } } is ApiResult.Success -> { it.data?.let { newList -> if (newList.isNotEmpty()) { + isLoading = false + binding.rvAudioBooks.show() binding.listenTxt.show() binding.trailerView.show() @@ -295,8 +317,9 @@ class AudioBooksActivity : WokaBaseActivity() { binding.shimmer.hide() binding.loadMoreProgress.hide() - binding.loadMoreBtn.text = getString(R.string.load_more) - binding.loadMoreBtn.setVisibility(!viewModel.lastPage) +// +// binding.loadMoreBtn.text = getString(R.string.load_more) +// binding.loadMoreBtn.setVisibility(!viewModel.lastPage) if (audioBookAdapter.currentList.isEmpty()) { // first data load @@ -306,6 +329,10 @@ class AudioBooksActivity : WokaBaseActivity() { loadTrailerData(newList[0]) audioBookAdapter.submitList(newList) + + if (!customAdLoaded && shallLoadGoogleAd){ + loadGoogleAds() + } } else { // loaded more data audioBookAdapter.notifyItemRangeInserted( @@ -313,10 +340,6 @@ class AudioBooksActivity : WokaBaseActivity() { newList.size ) } - - if (!customAdLoaded && shallLoadGoogleAd){ - loadGoogleAds() - } } } } diff --git a/app/src/main/java/com/woka/karaoke/views/KaraokeActivity.kt b/app/src/main/java/com/woka/karaoke/views/KaraokeActivity.kt index ad00eee..26cce63 100644 --- a/app/src/main/java/com/woka/karaoke/views/KaraokeActivity.kt +++ b/app/src/main/java/com/woka/karaoke/views/KaraokeActivity.kt @@ -9,6 +9,7 @@ import android.graphics.drawable.InsetDrawable import android.net.Uri import android.os.Bundle import android.text.Html +import android.util.Log import android.view.WindowManager import androidx.activity.enableEdgeToEdge import androidx.activity.result.ActivityResultLauncher @@ -51,7 +52,6 @@ import com.woka.utils.WokaBaseActivity import com.woka.utils.hide import com.woka.utils.isNetworkConnected import com.woka.utils.lightStatusBar -import com.woka.utils.setVisibility import com.woka.utils.shareWokaApp import com.woka.utils.show import com.woka.utils.toast @@ -80,6 +80,8 @@ class KaraokeActivity : WokaBaseActivity() { private var customAdLoaded = false private var shallLoadGoogleAd = false + private var isLoading = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityKaraokeBinding.inflate(layoutInflater) @@ -114,6 +116,8 @@ class KaraokeActivity : WokaBaseActivity() { customAdLoaded = false + isLoading = false + initLaunchers() initViews() @@ -158,6 +162,27 @@ class KaraokeActivity : WokaBaseActivity() { rvContinueSing.adapter = continueKaraokeAdapter (rvContinueSing.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false + + nestedScrollView.viewTreeObserver?.addOnScrollChangedListener { + if (nestedScrollView.childCount == 0) return@addOnScrollChangedListener + + nestedScrollView.getChildAt(0)?.let {child -> + val v = nestedScrollView + + val scrolledHeight = v.scrollY + v.height + val totalHeight = child.measuredHeight + + val percentageScrolled = (scrolledHeight.toFloat()/totalHeight.toFloat()) * 100 + + if (percentageScrolled >= 60) { + if (!isLoading && !viewModel.lastPage && isNetworkConnected()){ + Log.d("infinite_scroll", "LOAD MORE") + isLoading = true + viewModel.loadKaraokeSongs() + } + } + } + } } } @@ -205,12 +230,6 @@ class KaraokeActivity : WokaBaseActivity() { ClicksHelper.upsertClickEvent(ContentType.OTHERS) } - - loadMoreBtn.setOnClickListener { - viewModel.loadKaraokeSongs() - - ClicksHelper.upsertClickEvent(ContentType.OTHERS) - } } } @@ -483,6 +502,8 @@ class KaraokeActivity : WokaBaseActivity() { viewModel.karaokeLiveData.observe(this) { when (it) { is ApiResult.Error -> { + isLoading = false + binding.shimmer.hide() if (karaokeAdapter.currentList.size == 0) { // none of the data is yet loaded @@ -494,12 +515,12 @@ class KaraokeActivity : WokaBaseActivity() { } else { // error in loading more binding.loadMoreProgress.hide() - binding.loadMoreBtn.text = getString(R.string.retry) - binding.loadMoreBtn.show() } } is ApiResult.Loading -> { + isLoading = true + if (karaokeAdapter.currentList.size == 0) { // loading first data binding.shimmer.show() @@ -507,13 +528,14 @@ class KaraokeActivity : WokaBaseActivity() { } else { // loading more data binding.loadMoreProgress.show() - binding.loadMoreBtn.hide() } } is ApiResult.Success -> { it.data?.let { newList -> if (newList.isNotEmpty()) { + isLoading = false + binding.rvKaraoke.show() binding.singTxt.show() binding.trailerView.show() @@ -522,8 +544,6 @@ class KaraokeActivity : WokaBaseActivity() { binding.shimmer.hide() binding.loadMoreProgress.hide() - binding.loadMoreBtn.text = getString(R.string.load_more) - binding.loadMoreBtn.setVisibility(!viewModel.lastPage) if (karaokeAdapter.currentList.isEmpty()) { // first data load @@ -533,6 +553,10 @@ class KaraokeActivity : WokaBaseActivity() { loadTrailerData(newList[0]) karaokeAdapter.submitList(newList) + + if (!customAdLoaded && shallLoadGoogleAd){ + loadGoogleAds() + } } else { // loaded more data karaokeAdapter.notifyItemRangeInserted( @@ -540,10 +564,6 @@ class KaraokeActivity : WokaBaseActivity() { newList.size ) } - - if (!customAdLoaded && shallLoadGoogleAd){ - loadGoogleAds() - } } } } @@ -654,7 +674,10 @@ class KaraokeActivity : WokaBaseActivity() { AdSize.LARGE_BANNER ) adView.adUnitId = KARAOKE_BANNER_AD + + binding.toolbarAdsContainer.removeAllViews() binding.toolbarAdsContainer.addView(adView) + adView.loadAd(AdRequest.Builder().build()) // full ad at masila image diff --git a/app/src/main/java/com/woka/shop/views/fragments/shop/ShopFragment1.kt b/app/src/main/java/com/woka/shop/views/fragments/shop/ShopFragment1.kt index deb82c3..2e02433 100644 --- a/app/src/main/java/com/woka/shop/views/fragments/shop/ShopFragment1.kt +++ b/app/src/main/java/com/woka/shop/views/fragments/shop/ShopFragment1.kt @@ -80,13 +80,15 @@ class ShopFragment1 : Fragment() { adapter.onCategoryClickListener = { id, _ -> if (id == -1){ // ad clicked - AdClicksHelper.addClick(adId) - startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse(adLink) + adLink?.let {link -> + AdClicksHelper.addClick(adId) + startActivity( + Intent( + Intent.ACTION_VIEW, + Uri.parse(link) + ) ) - ) + } }else{ // normal click findNavController().navigate( diff --git a/app/src/main/java/com/woka/shop/views/fragments/shop/ShopFragment3.kt b/app/src/main/java/com/woka/shop/views/fragments/shop/ShopFragment3.kt index 30fd430..0c6b3c9 100644 --- a/app/src/main/java/com/woka/shop/views/fragments/shop/ShopFragment3.kt +++ b/app/src/main/java/com/woka/shop/views/fragments/shop/ShopFragment3.kt @@ -1,6 +1,7 @@ package com.woka.shop.views.fragments.shop import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -8,8 +9,10 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.OnScrollListener import com.google.android.material.tabs.TabLayout -import com.woka.R import com.woka.database.helpers.ClicksHelper import com.woka.database.models.ContentType import com.woka.databinding.FragmentShop3Binding @@ -17,6 +20,7 @@ import com.woka.networking.ApiResult import com.woka.shop.adapters.ShopProductAdapter import com.woka.shop.viewmodels.ShopViewModel import com.woka.utils.hide +import com.woka.utils.isNetworkConnected import com.woka.utils.setVisibility import com.woka.utils.show @@ -41,6 +45,7 @@ class ShopFragment3 : Fragment(), TabLayout.OnTabSelectedListener { binding = FragmentShop3Binding.inflate(inflater, container, false) viewModel = ViewModelProvider(requireActivity())[ShopViewModel::class.java] productAdapter = ShopProductAdapter() + loadMoreProducts = false return binding.root } @@ -70,6 +75,40 @@ class ShopFragment3 : Fragment(), TabLayout.OnTabSelectedListener { rvProducts.itemAnimator = null viewModel.onTitleChange?.invoke(categoryName) + + + // pagination + rvProducts.addOnScrollListener(object : OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + + (recyclerView.layoutManager as GridLayoutManager?)?.let {layoutManager -> + + val visibleItemCount = layoutManager.childCount + val totalItemCount = layoutManager.itemCount + val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition() + + val subCategoryId = categoryTabs.getTabAt(categoryTabs.selectedTabPosition)?.tag + + if ((viewModel.productPagingData["${superCategoryId}_${categoryId}_$subCategoryId"]?.nextPageToLoad?:0) > 0 + && !loadMoreProducts + && viewModel.productPagingData["${superCategoryId}_${categoryId}_$subCategoryId"]?.lastPage == false + && context?.isNetworkConnected() == true) { + if (visibleItemCount + firstVisibleItemPosition >= totalItemCount + && firstVisibleItemPosition >= 0 + ) { + Log.d("infinite_scroll", "LOAD MORE ${!loadMoreProducts}") + loadMoreProducts = true + viewModel.loadMoreProducts( + superCategoryId, + categoryId, + "$subCategoryId" + ) + } + } + } + } + }) } } @@ -81,14 +120,6 @@ class ShopFragment3 : Fragment(), TabLayout.OnTabSelectedListener { ClicksHelper.upsertClickEvent(ContentType.OTHERS) } - prodLoadMoreBtn.setOnClickListener { - loadMoreProducts = true - val subCategoryId = categoryTabs.getTabAt(categoryTabs.selectedTabPosition)?.tag?.toString() - viewModel.loadMoreProducts(superCategoryId, categoryId, subCategoryId) - - ClicksHelper.upsertClickEvent(ContentType.OTHERS) - } - productAdapter.onProductClicked = { findNavController().navigate(ShopFragment3Directions.actionShopFragment3ToProductFragment(it)) @@ -149,33 +180,19 @@ class ShopFragment3 : Fragment(), TabLayout.OnTabSelectedListener { viewModel.productListingLiveData.observe(viewLifecycleOwner){ when (it) { is ApiResult.Error -> { - binding.productShimmer.hide() - if (loadMoreProducts) { - // load more - binding.prodLoadMoreBtn.text = getString(R.string.retry) - binding.prodLoadMoreBtn.show() - } else { - // first time load - binding.rvProducts.hide() - binding.productShimmer.hide() - binding.prodLoadMoreBtn.hide() + if (!loadMoreProducts){ + rvProducts.hide() } + loadMoreProducts = false } is ApiResult.Loading -> { - binding.productShimmer.show() - binding.prodLoadMoreBtn.hide() binding.rvProducts.setVisibility(loadMoreProducts) } is ApiResult.Success -> { it.data?.let { productList -> binding.rvProducts.show() - binding.productShimmer.hide() - - binding.prodLoadMoreBtn.text = getString(R.string.load_more) - val subCategoryId = categoryTabs.getTabAt(categoryTabs.selectedTabPosition)?.tag - binding.prodLoadMoreBtn.setVisibility(viewModel.productPagingData["${superCategoryId}_${categoryId}_$subCategoryId"]?.lastPage == false) if (loadMoreProducts) { // loaded more data @@ -196,6 +213,8 @@ class ShopFragment3 : Fragment(), TabLayout.OnTabSelectedListener { } } } + + loadMoreProducts = false } } } diff --git a/app/src/main/java/com/woka/webseries/viewmodel/WebSeriesViewModel.kt b/app/src/main/java/com/woka/webseries/viewmodel/WebSeriesViewModel.kt index 2c5dfa2..5374de8 100644 --- a/app/src/main/java/com/woka/webseries/viewmodel/WebSeriesViewModel.kt +++ b/app/src/main/java/com/woka/webseries/viewmodel/WebSeriesViewModel.kt @@ -183,44 +183,37 @@ class WebSeriesViewModel : ViewModel() { val episodeListingLiveData: LiveData>> get() = _episodeListingLiveData - var episodePagingData = HashMap() - - // episode data for every season. where {key -> "showId_seasonId"} - private var episodeDataMap = HashMap>() - // episodes playlist, where {key -> "showId_seasonId_categoryId"} val episodesPlaylistMap = HashMap() - 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) - } + private var episodesList = ArrayList() + var episodesNextPageToLoad = 0 + var episodesLastPage = false + + fun resetEpisodesPagingData(){ + episodesList = ArrayList() + episodesNextPageToLoad = 0 + episodesLastPage = false } - fun loadMoreEpisodes(showId: String, seasonId: Int) { + fun loadEpisodes(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 + episodesNextPageToLoad, + 10 )) { is ApiResult.Error -> { + if (episodesNextPageToLoad == 0){ + // error while loading the first page + // which means no data available + episodesLastPage = true + } _episodeListingLiveData.postValue( ApiResult.Error( response.errorMessage, @@ -236,13 +229,11 @@ class WebSeriesViewModel : ViewModel() { is ApiResult.Success -> { response.data?.let { data -> data.result?.filterNotNull()?.let { newList -> - val currentList = episodeDataMap.getOrDefault(key, ArrayList()) - currentList.addAll(newList) - episodeDataMap[key] = currentList + episodesList.addAll(newList) - pagingData.lastPage = episodeDataMap[key]?.size == data.total_records - pagingData.nextPageToLoad++ - _episodeListingLiveData.postValue(ApiResult.Success(episodeDataMap[key])) + episodesLastPage = episodesList.size == data.total_records + episodesNextPageToLoad++ + _episodeListingLiveData.postValue(ApiResult.Success(episodesList)) val currentPlayListEng = episodesPlaylistMap["${key}_1"] ?: VideoPlayList( diff --git a/app/src/main/java/com/woka/webseries/views/fragments/WebSeriesFragment.kt b/app/src/main/java/com/woka/webseries/views/fragments/WebSeriesFragment.kt index 5ae2113..8447eae 100644 --- a/app/src/main/java/com/woka/webseries/views/fragments/WebSeriesFragment.kt +++ b/app/src/main/java/com/woka/webseries/views/fragments/WebSeriesFragment.kt @@ -8,6 +8,7 @@ import android.graphics.drawable.InsetDrawable import android.net.Uri import android.os.Bundle import android.text.Html +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -50,6 +51,7 @@ import com.woka.players.views.PlayerActivity.Companion.EXTRA_PLAY_LIST import com.woka.userPreference.UserType import com.woka.utils.NoSignInDialog 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 @@ -157,15 +159,6 @@ class WebSeriesFragment : Fragment() { ClicksHelper.upsertClickEvent(ContentType.OTHERS) } - loadMoreBtn.setOnClickListener { - catSpinnerAdapter.selectedCategoryType?.let { - loadingMore = true - viewModel.loadMoreWebSeries(it) - } - - ClicksHelper.upsertClickEvent(ContentType.OTHERS) - } - trailerBtn.setOnClickListener { activity.let { it?.startActivity(Intent(it, PlayerActivity::class.java).apply { @@ -216,6 +209,34 @@ class WebSeriesFragment : Fragment() { ((rvWebSeries.itemAnimator) as SimpleItemAnimator).supportsChangeAnimations = false ((rvContinueWatch.itemAnimator) as SimpleItemAnimator).supportsChangeAnimations = false + + nestedScrollView.viewTreeObserver?.addOnScrollChangedListener { + if (nestedScrollView.childCount == 0) return@addOnScrollChangedListener + + nestedScrollView.getChildAt(0)?.let {child -> + val v = nestedScrollView + + val scrolledHeight = v.scrollY + v.height + val totalHeight = child.measuredHeight + + val percentageScrolled = (scrolledHeight.toFloat()/totalHeight.toFloat()) * 100 + + if (percentageScrolled >= 80) { + catSpinnerAdapter.selectedCategoryType?.let { categoryType -> + if ((viewModel.categoryPagingData[categoryType]?.nextPageToLoad?:0) > 0 + && !loadingMore + && viewModel.categoryPagingData[categoryType]?.lastPage == false + && context?.isNetworkConnected() == true){ + Log.d("infinite_scroll", "LOAD MORE") + catSpinnerAdapter.selectedCategoryType?.let { + loadingMore = true + viewModel.loadMoreWebSeries(it) + } + } + } + } + } + } } } @@ -335,19 +356,17 @@ class WebSeriesFragment : Fragment() { binding.shimmerShowData.hide() if (loadingMore) { // load more - binding.loadMoreBtn.text = getString(R.string.retry) - binding.loadMoreBtn.show() } else { // first time load binding.rvWebSeries.hide() binding.shimmerShowData.hide() - binding.loadMoreBtn.hide() } + + loadingMore = false } is ApiResult.Loading -> { binding.shimmerShowData.show() - binding.loadMoreBtn.hide() binding.rvWebSeries.setVisibility(loadingMore) } @@ -358,11 +377,6 @@ class WebSeriesFragment : Fragment() { binding.rvWebSeries.show() binding.shimmerShowData.hide() - binding.loadMoreBtn.text = getString(R.string.load_more) - binding.loadMoreBtn.setVisibility( - viewModel.categoryPagingData[categoryType]?.lastPage == false - ) - if (loadingMore) { // loaded more data showAdapter.notifyItemRangeInserted( @@ -373,6 +387,8 @@ class WebSeriesFragment : Fragment() { // new category data load showAdapter.submitListShowList(showList, categoryType) } + + loadingMore = false } } } diff --git a/app/src/main/java/com/woka/webseries/views/fragments/WebShowFragment.kt b/app/src/main/java/com/woka/webseries/views/fragments/WebShowFragment.kt index 9a5ead7..08f4110 100644 --- a/app/src/main/java/com/woka/webseries/views/fragments/WebShowFragment.kt +++ b/app/src/main/java/com/woka/webseries/views/fragments/WebShowFragment.kt @@ -9,6 +9,7 @@ import android.graphics.drawable.ColorDrawable import android.graphics.drawable.InsetDrawable import android.os.Bundle import android.text.Html +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -17,6 +18,7 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.navArgs +import androidx.recyclerview.widget.SimpleItemAnimator import com.google.android.material.tabs.TabLayout import com.jwplayer.pub.api.media.playlists.PlaylistItem import com.woka.R @@ -34,7 +36,6 @@ import com.woka.utils.NoSignInDialog import com.woka.utils.hide import com.woka.utils.isNetworkConnected import com.woka.utils.lightStatusBar -import com.woka.utils.setVisibility import com.woka.utils.shareWokaApp import com.woka.utils.show import com.woka.utils.toast @@ -70,11 +71,13 @@ class WebShowFragment : Fragment(), TabLayout.OnTabSelectedListener { private lateinit var episodeDialogBinding: DialogEpisodeBinding private lateinit var episodeDialog: Dialog - private var loadMoreEpisodes = false private var showDataChanged: Boolean = false private lateinit var noSignInDialog: NoSignInDialog + private var isLoadingMoreEpisodes = false + private var showEpisodesShimmer = true + override fun onAttach(context: Context) { super.onAttach(context) episodeAdapter = EpisodeAdapter(context) @@ -93,6 +96,11 @@ class WebShowFragment : Fragment(), TabLayout.OnTabSelectedListener { it.window.setBackgroundDrawableResource(R.color.web_show_bg) it.window.lightStatusBar(true) } + + showDataChanged = false + isLoadingMoreEpisodes = false + showEpisodesShimmer = true + return binding.root } @@ -151,10 +159,35 @@ class WebShowFragment : Fragment(), TabLayout.OnTabSelectedListener { rvEpisodes.adapter = episodeAdapter episodeAdapter.onEpisodeClicked = ::onEpisodeClicked episodeAdapter.onEpisodePlayClicked = ::onEpisodePlayClicked + ((rvEpisodes.itemAnimator) as SimpleItemAnimator).supportsChangeAnimations = false rvTeaser.adapter = teaserAdapter teaserAdapter.onEpisodeClicked = ::onTeaserClicked teaserAdapter.onEpisodePlayClicked = ::onTeaserPlayClicked + + nestedScrollView.viewTreeObserver?.addOnScrollChangedListener { + if (nestedScrollView.childCount == 0) return@addOnScrollChangedListener + + nestedScrollView.getChildAt(0)?.let {child -> + val v = nestedScrollView + + val scrolledHeight = v.scrollY + v.height + val totalHeight = child.measuredHeight + + val percentageScrolled = (scrolledHeight.toFloat()/totalHeight.toFloat()) * 100 + + if (percentageScrolled >= 80) { + if (viewModel.episodesNextPageToLoad > 0 + && !isLoadingMoreEpisodes + && !viewModel.episodesLastPage + && context?.isNetworkConnected() == true){ + Log.d("infinite_scroll", "LOAD MORE") + isLoadingMoreEpisodes = true + viewModel.loadEpisodes("${showData.id}", selectedSeasonId) + } + } + } + } } } @@ -177,13 +210,6 @@ class WebShowFragment : Fragment(), TabLayout.OnTabSelectedListener { ClicksHelper.upsertClickEvent(ContentType.SERIES, showData.id, categoryId) } - epLoadMoreBtn.setOnClickListener { - loadMoreEpisodes = true - viewModel.loadMoreEpisodes("${showData.id}", selectedSeasonId) - - ClicksHelper.upsertClickEvent(ContentType.OTHERS) - } - likeSeason.setOnClickListener { if (activity?.isNetworkConnected() == false) { toast(getString(R.string.no_internet)) @@ -377,45 +403,58 @@ class WebShowFragment : Fragment(), TabLayout.OnTabSelectedListener { 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.loadMoreProgress.hide() + + if (!isLoadingMoreEpisodes){ + // loading new data binding.rvEpisodes.hide() binding.seasonMediaType.hide() binding.epShimmer.hide() - binding.epLoadMoreBtn.hide() } + + isLoadingMoreEpisodes = false } is ApiResult.Loading -> { - binding.epShimmer.show() - binding.epLoadMoreBtn.hide() - binding.rvEpisodes.setVisibility(loadMoreEpisodes) - binding.seasonMediaType.setVisibility(loadMoreEpisodes) + + if (!isLoadingMoreEpisodes){ + // loading new data + if (showEpisodesShimmer){ + binding.epShimmer.show() + showEpisodesShimmer = false + } + }else { + // loading more data + binding.loadMoreProgress.show() + binding.rvEpisodes.show() + binding.seasonMediaType.show() + } } is ApiResult.Success -> { it.data?.let { episodeList -> + binding.rvEpisodes.show() binding.seasonMediaType.show() binding.epShimmer.hide() + binding.loadMoreProgress.hide() - binding.epLoadMoreBtn.text = getString(R.string.load_more) - binding.epLoadMoreBtn.setVisibility(viewModel.episodePagingData["${showData.id}_$selectedSeasonId"]?.lastPage == false) - - if (loadMoreEpisodes) { - // loaded more data - episodeAdapter.notifyItemRangeInserted( - episodeAdapter.currentList.size, - episodeList.size - ) - } else { - // new category data load + if (!isLoadingMoreEpisodes){ + // loading new data episodeAdapter.submitList(episodeList) + }else{ + // loading more data + try { + episodeAdapter.notifyItemRangeInserted( + episodeAdapter.currentList.size, + episodeList.size + ) + } catch (e: Exception) { + // do nothing + } } + + isLoadingMoreEpisodes = false } } } @@ -617,7 +656,7 @@ class WebShowFragment : Fragment(), TabLayout.OnTabSelectedListener { seasonData.id?.let { selectedSeasonId = it - loadMoreEpisodes = false + viewModel.resetEpisodesPagingData() viewModel.loadEpisodes("${showData.id}", it) viewModel.loadTeasers("${showData.id}", it) } diff --git a/app/src/main/java/com/woka/wokagames/views/GamesActivity.kt b/app/src/main/java/com/woka/wokagames/views/GamesActivity.kt index d174cd0..30969ff 100644 --- a/app/src/main/java/com/woka/wokagames/views/GamesActivity.kt +++ b/app/src/main/java/com/woka/wokagames/views/GamesActivity.kt @@ -9,6 +9,7 @@ import android.graphics.drawable.InsetDrawable import android.net.Uri import android.os.Bundle import android.text.Html +import android.util.Log import android.view.WindowManager import androidx.activity.enableEdgeToEdge import androidx.core.view.ViewCompat @@ -42,7 +43,6 @@ import com.woka.utils.WokaBaseActivity import com.woka.utils.hide import com.woka.utils.isNetworkConnected import com.woka.utils.lightStatusBar -import com.woka.utils.setVisibility import com.woka.utils.shareWokaApp import com.woka.utils.show import com.woka.utils.toast @@ -73,6 +73,8 @@ class GamesActivity : WokaBaseActivity() { private var customAdLoaded = false private var shallLoadGoogleAd = false + private var isLoading = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityGamesBinding.inflate(layoutInflater) @@ -103,6 +105,8 @@ class GamesActivity : WokaBaseActivity() { customAdLoaded = false + isLoading = false + initViews() initGameDialog() @@ -133,6 +137,27 @@ class GamesActivity : WokaBaseActivity() { rvGames.adapter = gameAdapter (rvGames.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false + + nestedScrollView.viewTreeObserver?.addOnScrollChangedListener { + if (nestedScrollView.childCount == 0) return@addOnScrollChangedListener + + nestedScrollView.getChildAt(0)?.let {child -> + val v = nestedScrollView + + val scrolledHeight = v.scrollY + v.height + val totalHeight = child.measuredHeight + + val percentageScrolled = (scrolledHeight.toFloat()/totalHeight.toFloat()) * 100 + + if (percentageScrolled >= 80) { + if (!isLoading && !viewModel.lastPage && isNetworkConnected()){ + Log.d("infinite_scroll", "LOAD MORE") + isLoading = true + viewModel.loadGames() + } + } + } + } } } @@ -176,12 +201,6 @@ class GamesActivity : WokaBaseActivity() { ClicksHelper.upsertClickEvent(ContentType.OTHERS) } - - loadMoreBtn.setOnClickListener { - viewModel.loadGames() - - ClicksHelper.upsertClickEvent(ContentType.OTHERS) - } } } @@ -420,6 +439,8 @@ class GamesActivity : WokaBaseActivity() { viewModel.gamesLiveData.observe(this){ when(it){ is ApiResult.Error -> { + isLoading = false + binding.shimmer.hide() if (gameAdapter.currentList.size == 0) { // none of the data is yet loaded @@ -431,11 +452,11 @@ class GamesActivity : WokaBaseActivity() { } else { // error in loading more binding.loadMoreProgress.hide() - binding.loadMoreBtn.text = getString(R.string.retry) - binding.loadMoreBtn.show() } } is ApiResult.Loading -> { + isLoading = true + if (gameAdapter.currentList.size == 0) { // loading first data binding.shimmer.show() @@ -443,12 +464,13 @@ class GamesActivity : WokaBaseActivity() { } else { // loading more data binding.loadMoreProgress.show() - binding.loadMoreBtn.hide() } } is ApiResult.Success -> { it.data?.let {newList -> if (newList.isNotEmpty()){ + isLoading = false + binding.rvGames.show() binding.listenTxt.show() binding.trailerView.show() @@ -457,13 +479,18 @@ class GamesActivity : WokaBaseActivity() { binding.shimmer.hide() binding.loadMoreProgress.hide() - binding.loadMoreBtn.text = getString(R.string.load_more) - binding.loadMoreBtn.setVisibility(!viewModel.lastPage) +// +// binding.loadMoreBtn.text = getString(R.string.load_more) +// binding.loadMoreBtn.setVisibility(!viewModel.lastPage) if (gameAdapter.currentList.isEmpty()){ // first data load loadTrailerData(newList[0]) gameAdapter.submitList(newList) + + if (!customAdLoaded && shallLoadGoogleAd){ + loadGoogleAds() + } }else{ // loaded more data gameAdapter.notifyItemRangeInserted( @@ -471,10 +498,6 @@ class GamesActivity : WokaBaseActivity() { newList.size ) } - - if (!customAdLoaded && shallLoadGoogleAd){ - loadGoogleAds() - } } } } diff --git a/app/src/main/res/layout/activity_audio_books.xml b/app/src/main/res/layout/activity_audio_books.xml index 5f0c07d..01eaefd 100644 --- a/app/src/main/res/layout/activity_audio_books.xml +++ b/app/src/main/res/layout/activity_audio_books.xml @@ -261,6 +261,7 @@ -