Experiment with stashing
This commit is contained in:
committed by
Aayush Gupta
parent
2325b6e4a3
commit
6f425fe641
9
app/src/main/java/com/aurora/store/Aliases.kt
Normal file
9
app/src/main/java/com/aurora/store/Aliases.kt
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.aurora.store
|
||||
|
||||
import com.aurora.gplayapi.data.models.StreamBundle
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.gplayapi.helpers.contracts.StreamContract
|
||||
import com.aurora.gplayapi.helpers.contracts.TopChartsContract
|
||||
|
||||
typealias TopChartStash = Map<TopChartsContract.Type, Map<TopChartsContract.Chart, StreamCluster>>
|
||||
typealias HomeStash = MutableMap<StreamContract.Category, StreamBundle>
|
||||
@@ -21,6 +21,10 @@ package com.aurora.store.data.model
|
||||
|
||||
|
||||
sealed class ViewState {
|
||||
inline fun <reified T> ViewState.getDataAs(): T {
|
||||
return (this as? Success<*>)?.data as T
|
||||
}
|
||||
|
||||
data object Loading : ViewState()
|
||||
data object Empty : ViewState()
|
||||
data class Error(val error: String?) : ViewState()
|
||||
@@ -34,7 +38,7 @@ sealed class AuthState {
|
||||
data object SignedIn : AuthState()
|
||||
data object SignedOut : AuthState()
|
||||
data object Valid : AuthState()
|
||||
data object Fetching: AuthState()
|
||||
data object Verifying: AuthState()
|
||||
data object Fetching : AuthState()
|
||||
data object Verifying : AuthState()
|
||||
data class Failed(val status: String) : AuthState()
|
||||
}
|
||||
|
||||
@@ -28,8 +28,10 @@ import com.aurora.gplayapi.data.models.StreamBundle
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.gplayapi.helpers.contracts.StreamContract.Category
|
||||
import com.aurora.gplayapi.helpers.contracts.StreamContract.Type
|
||||
import com.aurora.store.HomeStash
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.model.ViewState
|
||||
import com.aurora.store.data.ViewState.Loading.getDataAs
|
||||
import com.aurora.store.databinding.FragmentForYouBinding
|
||||
import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener
|
||||
import com.aurora.store.view.epoxy.controller.GenericCarouselController
|
||||
@@ -43,10 +45,10 @@ class ForYouFragment : BaseFragment(R.layout.fragment_for_you),
|
||||
private var _binding: FragmentForYouBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var category: Category = Category.APPLICATION
|
||||
private val viewModel: StreamViewModel by activityViewModels()
|
||||
|
||||
private lateinit var streamBundle: StreamBundle
|
||||
private var category: Category = Category.APPLICATION
|
||||
private var streamBundle: StreamBundle? = StreamBundle()
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@@ -84,6 +86,13 @@ class ForYouFragment : BaseFragment(R.layout.fragment_for_you),
|
||||
}
|
||||
|
||||
binding.recycler.setController(genericCarouselController)
|
||||
binding.recycler.addOnScrollListener(
|
||||
object : EndlessRecyclerOnScrollListener() {
|
||||
override fun onLoadMore(currentPage: Int) {
|
||||
viewModel.observe(category, Type.HOME)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
||||
when (it) {
|
||||
@@ -92,17 +101,9 @@ class ForYouFragment : BaseFragment(R.layout.fragment_for_you),
|
||||
}
|
||||
|
||||
is ViewState.Success<*> -> {
|
||||
if (!::streamBundle.isInitialized) {
|
||||
binding.recycler.addOnScrollListener(
|
||||
object : EndlessRecyclerOnScrollListener() {
|
||||
override fun onLoadMore(currentPage: Int) {
|
||||
viewModel.observe(category, Type.HOME)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
val stash = it.getDataAs<HomeStash>()
|
||||
streamBundle = stash[category]
|
||||
|
||||
streamBundle = it.data as StreamBundle
|
||||
genericCarouselController.setData(streamBundle)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,12 +21,15 @@ package com.aurora.store.view.ui.commons
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import com.aurora.Constants
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.gplayapi.helpers.contracts.TopChartsContract.Chart
|
||||
import com.aurora.gplayapi.helpers.contracts.TopChartsContract.Type
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.TopChartStash
|
||||
import com.aurora.store.data.ViewState
|
||||
import com.aurora.store.data.ViewState.Empty.getDataAs
|
||||
import com.aurora.store.databinding.FragmentTopContainerBinding
|
||||
import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener
|
||||
import com.aurora.store.view.epoxy.views.AppProgressViewModel_
|
||||
@@ -41,7 +44,9 @@ class TopChartFragment : BaseFragment(R.layout.fragment_top_container) {
|
||||
private var _binding: FragmentTopContainerBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val viewModel: TopChartViewModel by viewModels()
|
||||
private val viewModel: TopChartViewModel by activityViewModels()
|
||||
|
||||
private var streamCluster: StreamCluster? = StreamCluster()
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@@ -59,42 +64,52 @@ class TopChartFragment : BaseFragment(R.layout.fragment_top_container) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
_binding = FragmentTopContainerBinding.bind(view)
|
||||
|
||||
var chartType = 0
|
||||
var chartCategory = 0
|
||||
var type = 0
|
||||
var category = 0
|
||||
val bundle = arguments
|
||||
|
||||
if (bundle != null) {
|
||||
chartType = bundle.getInt(Constants.TOP_CHART_TYPE, 0)
|
||||
chartCategory = bundle.getInt(Constants.TOP_CHART_CATEGORY, 0)
|
||||
type = bundle.getInt(Constants.TOP_CHART_TYPE, 0)
|
||||
category = bundle.getInt(Constants.TOP_CHART_CATEGORY, 0)
|
||||
}
|
||||
|
||||
when (chartType) {
|
||||
0 -> when (chartCategory) {
|
||||
0 -> viewModel.getStreamCluster(Type.APPLICATION, Chart.TOP_SELLING_FREE)
|
||||
1 -> viewModel.getStreamCluster(Type.APPLICATION, Chart.TOP_GROSSING)
|
||||
2 -> viewModel.getStreamCluster(Type.APPLICATION, Chart.MOVERS_SHAKERS)
|
||||
3 -> viewModel.getStreamCluster(Type.APPLICATION, Chart.TOP_SELLING_PAID)
|
||||
}
|
||||
|
||||
1 -> when (chartCategory) {
|
||||
0 -> viewModel.getStreamCluster(Type.GAME, Chart.TOP_SELLING_FREE)
|
||||
1 -> viewModel.getStreamCluster(Type.GAME, Chart.TOP_GROSSING)
|
||||
2 -> viewModel.getStreamCluster(Type.GAME, Chart.MOVERS_SHAKERS)
|
||||
3 -> viewModel.getStreamCluster(Type.GAME, Chart.TOP_SELLING_PAID)
|
||||
}
|
||||
val chartType = when (type) {
|
||||
1 -> Type.GAME
|
||||
else -> Type.APPLICATION
|
||||
}
|
||||
|
||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
||||
updateController(it)
|
||||
val chartCategory = when (category) {
|
||||
1 -> Chart.TOP_GROSSING
|
||||
2 -> Chart.MOVERS_SHAKERS
|
||||
3 -> Chart.TOP_SELLING_PAID
|
||||
else -> Chart.TOP_SELLING_FREE
|
||||
}
|
||||
|
||||
binding.recycler.addOnScrollListener(object : EndlessRecyclerOnScrollListener() {
|
||||
override fun onLoadMore(currentPage: Int) {
|
||||
viewModel.nextCluster()
|
||||
viewModel.nextCluster(chartType, chartCategory)
|
||||
}
|
||||
})
|
||||
|
||||
updateController(null)
|
||||
|
||||
viewModel.getStreamCluster(chartType, chartCategory)
|
||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
||||
when (it) {
|
||||
is ViewState.Loading, is ViewState.Error -> {
|
||||
updateController(null)
|
||||
}
|
||||
|
||||
is ViewState.Success<*> -> {
|
||||
val stash = it.getDataAs<TopChartStash>()
|
||||
streamCluster = stash[chartType]?.get(chartCategory)
|
||||
|
||||
updateController(streamCluster)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.aurora.gplayapi.helpers.StreamHelper
|
||||
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.HomeStash
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.util.Log
|
||||
@@ -55,7 +56,7 @@ class StreamViewModel @Inject constructor(
|
||||
|
||||
val liveData: MutableLiveData<ViewState> = MutableLiveData()
|
||||
|
||||
private var streamBundleMap: MutableMap<StreamContract.Category, StreamBundle> = mutableMapOf(
|
||||
private var stash: HomeStash = mutableMapOf(
|
||||
StreamContract.Category.APPLICATION to StreamBundle(),
|
||||
StreamContract.Category.GAME to StreamBundle()
|
||||
)
|
||||
@@ -77,7 +78,7 @@ class StreamViewModel @Inject constructor(
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
supervisorScope {
|
||||
if (targetBundle(category).streamClusters.isNotEmpty()) {
|
||||
liveData.postValue(ViewState.Success(targetBundle(category)))
|
||||
liveData.postValue(ViewState.Success(stash))
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -100,7 +101,7 @@ class StreamViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
//Post updated to UI
|
||||
liveData.postValue(ViewState.Success(targetBundle(category)))
|
||||
liveData.postValue(ViewState.Success(stash))
|
||||
} else {
|
||||
Log.i("End of Bundle")
|
||||
}
|
||||
@@ -119,7 +120,7 @@ class StreamViewModel @Inject constructor(
|
||||
val newCluster =
|
||||
contract().nextStreamCluster(streamCluster.clusterNextPageUrl)
|
||||
updateCluster(category, streamCluster.id, newCluster)
|
||||
liveData.postValue(ViewState.Success(targetBundle(category)))
|
||||
liveData.postValue(ViewState.Success(stash))
|
||||
} else {
|
||||
Log.i("End of cluster")
|
||||
streamCluster.clusterNextPageUrl = String()
|
||||
@@ -143,8 +144,9 @@ class StreamViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun targetBundle(category: StreamContract.Category): StreamBundle {
|
||||
val streamBundle = streamBundleMap[category]
|
||||
// stash is initialized with empty StreamBundle so this will never return null or throw an exception
|
||||
val streamBundle = stash.getValue(category)
|
||||
|
||||
return streamBundle!!
|
||||
return streamBundle
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.gplayapi.helpers.TopChartsHelper
|
||||
import com.aurora.gplayapi.helpers.contracts.TopChartsContract
|
||||
import com.aurora.gplayapi.helpers.web.WebTopChartsHelper
|
||||
import com.aurora.store.TopChartStash
|
||||
import com.aurora.store.data.ViewState
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@@ -50,11 +52,22 @@ class TopChartViewModel @Inject constructor(
|
||||
private val webTopChartsHelper: TopChartsContract = WebTopChartsHelper()
|
||||
.using(HttpClient.getPreferredClient(context))
|
||||
|
||||
val liveData: MutableLiveData<StreamCluster> = MutableLiveData()
|
||||
var streamCluster: StreamCluster = StreamCluster()
|
||||
private val dummyChart = mapOf(
|
||||
TopChartsContract.Chart.TOP_GROSSING to StreamCluster(),
|
||||
TopChartsContract.Chart.TOP_SELLING_FREE to StreamCluster(),
|
||||
TopChartsContract.Chart.TOP_SELLING_PAID to StreamCluster(),
|
||||
TopChartsContract.Chart.MOVERS_SHAKERS to StreamCluster(),
|
||||
)
|
||||
|
||||
private var stash: TopChartStash = mapOf(
|
||||
TopChartsContract.Type.APPLICATION to dummyChart,
|
||||
TopChartsContract.Type.GAME to dummyChart
|
||||
)
|
||||
|
||||
val liveData: MutableLiveData<ViewState> = MutableLiveData()
|
||||
|
||||
private fun contract(): TopChartsContract {
|
||||
return if(authProvider.isAnonymous){
|
||||
return if (authProvider.isAnonymous) {
|
||||
webTopChartsHelper
|
||||
} else {
|
||||
topChartsHelper
|
||||
@@ -63,34 +76,56 @@ class TopChartViewModel @Inject constructor(
|
||||
|
||||
fun getStreamCluster(type: TopChartsContract.Type, chart: TopChartsContract.Chart) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
if (targetCluster(type, chart).clusterAppList.isNotEmpty()) {
|
||||
liveData.postValue(ViewState.Success(stash))
|
||||
}
|
||||
|
||||
try {
|
||||
streamCluster = contract().getCluster(type.value, chart.value)
|
||||
liveData.postValue(streamCluster)
|
||||
val cluster = contract().getCluster(type.value, chart.value)
|
||||
updateCluster(type, chart, cluster)
|
||||
liveData.postValue(ViewState.Success(stash))
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun nextCluster() {
|
||||
fun nextCluster(type: TopChartsContract.Type, chart: TopChartsContract.Chart) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
supervisorScope {
|
||||
try {
|
||||
if (streamCluster.hasNext()) {
|
||||
val target = targetCluster(type, chart)
|
||||
if (target.hasNext()) {
|
||||
val newCluster = topChartsHelper.getNextStreamCluster(
|
||||
streamCluster.clusterNextPageUrl
|
||||
target.clusterNextPageUrl
|
||||
)
|
||||
|
||||
streamCluster.apply {
|
||||
clusterAppList.addAll(newCluster.clusterAppList)
|
||||
clusterNextPageUrl = newCluster.clusterNextPageUrl
|
||||
}
|
||||
updateCluster(type, chart, newCluster)
|
||||
|
||||
liveData.postValue(streamCluster)
|
||||
} else {
|
||||
liveData.postValue(ViewState.Success(stash))
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCluster(
|
||||
type: TopChartsContract.Type,
|
||||
chart: TopChartsContract.Chart,
|
||||
newCluster: StreamCluster
|
||||
) {
|
||||
targetCluster(type, chart).apply {
|
||||
clusterAppList.addAll(newCluster.clusterAppList)
|
||||
clusterNextPageUrl = newCluster.clusterNextPageUrl
|
||||
}
|
||||
}
|
||||
|
||||
private fun targetCluster(
|
||||
type: TopChartsContract.Type,
|
||||
chart: TopChartsContract.Chart
|
||||
): StreamCluster {
|
||||
// Stash is initialized with empty clusters so this will never return null or throw an exception
|
||||
val cluster = stash.getValue(type).getValue(chart)
|
||||
return cluster
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user