From 8a12ffcd96d20f9c8ea2fcdb5d0c3aad3d18f40f Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Sat, 29 Jun 2024 04:03:01 +0530 Subject: [PATCH] Add stashing to SubCategory Streams --- .../view/ui/commons/CategoryBrowseFragment.kt | 65 +++++++---------- .../store/view/ui/commons/ForYouFragment.kt | 3 +- .../viewmodel/homestream/StreamViewModel.kt | 11 +-- .../SubCategoryClusterViewModel.kt | 69 +++++++++---------- 4 files changed, 65 insertions(+), 83 deletions(-) diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/CategoryBrowseFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/CategoryBrowseFragment.kt index 8a6172e7c..676851db1 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/CategoryBrowseFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/CategoryBrowseFragment.kt @@ -21,15 +21,16 @@ package com.aurora.store.view.ui.commons import android.os.Bundle import android.view.View -import android.widget.Toast -import androidx.fragment.app.viewModels +import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.gplayapi.helpers.contracts.StreamContract import com.aurora.store.R import com.aurora.store.data.model.ViewState +import com.aurora.store.data.model.ViewState.Loading.getDataAs import com.aurora.store.databinding.ActivityGenericRecyclerBinding import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener import com.aurora.store.view.epoxy.controller.CategoryCarouselController @@ -46,16 +47,20 @@ class CategoryBrowseFragment : BaseFragment(R.layout.activity_generic_recycler), get() = _binding!! private val args: CategoryBrowseFragmentArgs by navArgs() - private val viewModel: SubCategoryClusterViewModel by viewModels() + private val viewModel: SubCategoryClusterViewModel by activityViewModels() - private lateinit var genericCarouselController: GenericCarouselController - private lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener + private lateinit var category: StreamContract.Category + private var streamBundle: StreamBundle? = StreamBundle() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = ActivityGenericRecyclerBinding.bind(view) - genericCarouselController = CategoryCarouselController(this) + + val rawCategory = args.browseUrl.split("/").last() + category = StreamContract.Category.NONE.apply { value = rawCategory } + + val genericCarouselController = CategoryCarouselController(this) // Toolbar binding.layoutToolbarAction.apply { @@ -65,39 +70,30 @@ class CategoryBrowseFragment : BaseFragment(R.layout.activity_generic_recycler), // RecyclerView binding.recycler.setController(genericCarouselController) + binding.recycler.addOnScrollListener(object : EndlessRecyclerOnScrollListener() { + override fun onLoadMore(currentPage: Int) { + viewModel.observe(category) + } + }) viewModel.liveData.observe(viewLifecycleOwner) { when (it) { - is ViewState.Empty -> { - } - is ViewState.Loading -> { - updateController(null) - } - - is ViewState.Error -> { - + genericCarouselController.setData(null) } is ViewState.Success<*> -> { - updateController(it.data as StreamBundle) + val stash = it.getDataAs>() + streamBundle = stash[category.value] + + genericCarouselController.setData(streamBundle) } else -> {} } } - endlessRecyclerOnScrollListener = object : EndlessRecyclerOnScrollListener() { - override fun onLoadMore(currentPage: Int) { - viewModel.observe() - } - } - - endlessRecyclerOnScrollListener.disable() - binding.recycler.addOnScrollListener(endlessRecyclerOnScrollListener) - - viewModel.observeCategory(args.browseUrl) - updateController(null) + viewModel.observe(category) } override fun onDestroyView() { @@ -105,25 +101,12 @@ class CategoryBrowseFragment : BaseFragment(R.layout.activity_generic_recycler), _binding = null } - private fun updateController(streamBundle: StreamBundle?) { - if (streamBundle != null) endlessRecyclerOnScrollListener.enable() - genericCarouselController.setData(streamBundle) - } - override fun onHeaderClicked(streamCluster: StreamCluster) { - if (streamCluster.clusterBrowseUrl.isNotEmpty()) - openStreamBrowseFragment(streamCluster.clusterBrowseUrl) - else - Toast.makeText( - requireContext(), - getString(R.string.toast_page_unavailable), - Toast.LENGTH_SHORT - ) - .show() + } override fun onClusterScrolled(streamCluster: StreamCluster) { - viewModel.observeCluster(streamCluster) + viewModel.observeCluster(category, streamCluster) } override fun onAppClick(app: App) { diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt index 98952c98d..00c98a55e 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt @@ -118,8 +118,7 @@ class ForYouFragment : BaseFragment(R.layout.fragment_for_you), } override fun onHeaderClicked(streamCluster: StreamCluster) { - if (streamCluster.clusterBrowseUrl.isNotEmpty()) - openStreamBrowseFragment(streamCluster.clusterBrowseUrl, streamCluster.clusterTitle) + } override fun onClusterScrolled(streamCluster: StreamCluster) { diff --git a/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt index a5083028f..a67d3f6dd 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt @@ -77,25 +77,26 @@ class StreamViewModel @Inject constructor( fun observe(category: StreamContract.Category, type: StreamContract.Type) { viewModelScope.launch(Dispatchers.IO) { supervisorScope { - if (targetBundle(category).streamClusters.isNotEmpty()) { + val bundle = targetBundle(category) + if (bundle.streamClusters.isNotEmpty()) { liveData.postValue(ViewState.Success(stash)) } try { - if (!targetBundle(category).hasCluster() || targetBundle(category).hasNext()) { + if (!bundle.hasCluster() || bundle.hasNext()) { //Fetch new stream bundle - val newBundle = if (targetBundle(category).streamClusters.isEmpty()) { + val newBundle = if (bundle.streamClusters.isEmpty()) { contract().fetch(type, category) } else { contract().nextStreamBundle( category, - targetBundle((category)).streamNextPageUrl + bundle.streamNextPageUrl ) } //Update old bundle - targetBundle(category).apply { + bundle.apply { streamClusters.putAll(newBundle.streamClusters) streamNextPageUrl = newBundle.streamNextPageUrl } diff --git a/app/src/main/java/com/aurora/store/viewmodel/subcategory/SubCategoryClusterViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/subcategory/SubCategoryClusterViewModel.kt index d32edf782..6553e87d6 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/subcategory/SubCategoryClusterViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/subcategory/SubCategoryClusterViewModel.kt @@ -31,7 +31,6 @@ import com.aurora.store.data.model.ViewState import com.aurora.gplayapi.helpers.contracts.StreamContract import com.aurora.gplayapi.helpers.web.WebStreamHelper import com.aurora.store.data.network.HttpClient -import com.aurora.store.data.providers.AuthProvider import com.aurora.store.util.Log import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext @@ -50,76 +49,64 @@ class SubCategoryClusterViewModel @Inject constructor( .using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() - var streamBundle: StreamBundle = StreamBundle() - private lateinit var homeUrl: String - private lateinit var type: StreamContract.Type - private lateinit var category: StreamContract.Category - - init { - liveData.postValue(ViewState.Loading) - } + private var stash: MutableMap = mutableMapOf() private fun getCategoryStreamBundle( + category: StreamContract.Category, nextPageUrl: String ): StreamBundle { - return if (streamBundle.streamClusters.isEmpty()) - contract.fetch(type, category) + return if (targetBundle(category).streamClusters.isEmpty()) + contract.fetch(StreamContract.Type.HOME, category) else contract.nextStreamBundle(category, nextPageUrl) } - fun observeCategory(homeUrl: String) { - this.homeUrl = homeUrl - - val rawCategory = homeUrl.split("/").last() - - type = StreamContract.Type.HOME - category = StreamContract.Category.NONE.apply { - value = rawCategory - } - - observe() - } - - fun observe() { + fun observe(category: StreamContract.Category) { + liveData.postValue(ViewState.Loading) viewModelScope.launch(Dispatchers.IO) { supervisorScope { + val bundle = targetBundle(category) + + if (bundle.streamClusters.isNotEmpty()) { + liveData.postValue(ViewState.Success(stash)) + } + try { - if (!streamBundle.hasCluster() || streamBundle.hasNext()) { + if (!bundle.hasCluster() || bundle.hasNext()) { //Fetch new stream bundle val newBundle = getCategoryStreamBundle( - streamBundle.streamNextPageUrl + category, + bundle.streamNextPageUrl ) //Update old bundle - streamBundle.apply { + bundle.apply { streamClusters.putAll(newBundle.streamClusters) streamNextPageUrl = newBundle.streamNextPageUrl } //Post updated to UI - liveData.postValue(ViewState.Success(streamBundle)) + liveData.postValue(ViewState.Success(stash)) } else { Log.i("End of Bundle") } } catch (e: Exception) { - e.printStackTrace() liveData.postValue(ViewState.Error(e.message)) } } } } - fun observeCluster(streamCluster: StreamCluster) { + fun observeCluster(category: StreamContract.Category, streamCluster: StreamCluster) { viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { if (streamCluster.hasNext()) { val newCluster = contract.nextStreamCluster(streamCluster.clusterNextPageUrl) - updateCluster(newCluster) - liveData.postValue(ViewState.Success(streamBundle)) + updateCluster(category, streamCluster.id, newCluster) + liveData.postValue(ViewState.Success(stash)) } else { Log.i("End of cluster") streamCluster.clusterNextPageUrl = String() @@ -131,10 +118,22 @@ class SubCategoryClusterViewModel @Inject constructor( } } - private fun updateCluster(newCluster: StreamCluster) { - streamBundle.streamClusters[newCluster.id]?.apply { + private fun updateCluster( + category: StreamContract.Category, + clusterID: Int, + newCluster: StreamCluster + ) { + targetBundle(category).streamClusters[clusterID]?.apply { clusterAppList.addAll(newCluster.clusterAppList) clusterNextPageUrl = newCluster.clusterNextPageUrl } } + + private fun targetBundle(category: StreamContract.Category): StreamBundle { + val streamBundle = stash.getOrPut(category.value) { + StreamBundle() + } + + return streamBundle + } }