diff --git a/.gitignore b/.gitignore index 069a2329f..6452a1e7a 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,6 @@ app/nightly/* #Exclude signing configurations & keystore signing.properties *.keystore + + +.kotlin/* \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/data/model/State.kt b/app/src/main/java/com/aurora/store/data/model/State.kt index 274738a37..d56183e9e 100644 --- a/app/src/main/java/com/aurora/store/data/model/State.kt +++ b/app/src/main/java/com/aurora/store/data/model/State.kt @@ -21,20 +21,20 @@ package com.aurora.store.data.model sealed class ViewState { - object Loading : ViewState() - object Empty : ViewState() + data object Loading : ViewState() + data object Empty : ViewState() data class Error(val error: String?) : ViewState() data class Status(val status: String?) : ViewState() data class Success(val data: T) : ViewState() } sealed class AuthState { - object Available : AuthState() - object Unavailable : AuthState() - object SignedIn : AuthState() - object SignedOut : AuthState() - object Valid : AuthState() - object Fetching: AuthState() - object Verifying: AuthState() + data object Available : AuthState() + data object Unavailable : AuthState() + data object SignedIn : AuthState() + data object SignedOut : AuthState() + data object Valid : AuthState() + data object Fetching: AuthState() + data object Verifying: AuthState() data class Failed(val status: String) : AuthState() } 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 f18086d2f..743c8e875 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 @@ -21,7 +21,7 @@ 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.App import com.aurora.gplayapi.data.models.StreamBundle @@ -33,7 +33,7 @@ import com.aurora.store.data.model.ViewState import com.aurora.store.databinding.FragmentForYouBinding import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener import com.aurora.store.view.epoxy.controller.GenericCarouselController -import com.aurora.store.viewmodel.homestream.BaseClusterViewModel +import com.aurora.store.viewmodel.homestream.StreamViewModel import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -43,7 +43,8 @@ class ForYouFragment : BaseFragment(R.layout.fragment_for_you), private var _binding: FragmentForYouBinding? = null private val binding get() = _binding!! - private val viewModel: BaseClusterViewModel by viewModels() + private var category: Category = Category.APPLICATION + private val viewModel: StreamViewModel by activityViewModels() private lateinit var streamBundle: StreamBundle @@ -71,35 +72,31 @@ class ForYouFragment : BaseFragment(R.layout.fragment_for_you), } when (pageType) { - 0 -> viewModel.getStreamBundle(Category.APPLICATION, Type.HOME) - 1 -> viewModel.getStreamBundle(Category.GAME, Type.HOME) + 0 -> { + category = Category.APPLICATION + viewModel.getStreamBundle(category, Type.HOME) + } + + 1 -> { + category = Category.GAME + viewModel.getStreamBundle(category, Type.HOME) + } } binding.recycler.setController(genericCarouselController) viewModel.liveData.observe(viewLifecycleOwner) { when (it) { - is ViewState.Empty -> { - } - is ViewState.Loading -> { genericCarouselController.setData(null) } - is ViewState.Error -> { - - } - - is ViewState.Status -> { - - } - is ViewState.Success<*> -> { if (!::streamBundle.isInitialized) { binding.recycler.addOnScrollListener( object : EndlessRecyclerOnScrollListener() { override fun onLoadMore(currentPage: Int) { - viewModel.observe() + viewModel.observe(category, Type.HOME) } } ) @@ -108,6 +105,8 @@ class ForYouFragment : BaseFragment(R.layout.fragment_for_you), streamBundle = it.data as StreamBundle genericCarouselController.setData(streamBundle) } + + else -> {} } } } @@ -123,7 +122,7 @@ class ForYouFragment : BaseFragment(R.layout.fragment_for_you), } 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/viewmodel/homestream/BaseClusterViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt similarity index 70% rename from app/src/main/java/com/aurora/store/viewmodel/homestream/BaseClusterViewModel.kt rename to app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt index 6785246cf..9ede9de7f 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/homestream/BaseClusterViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt @@ -42,7 +42,7 @@ import javax.inject.Inject @HiltViewModel @SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 -class BaseClusterViewModel @Inject constructor( +class StreamViewModel @Inject constructor( @ApplicationContext private val context: Context, private val authProvider: AuthProvider ) : ViewModel() { @@ -54,10 +54,11 @@ class BaseClusterViewModel @Inject constructor( .using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() - var streamBundle: StreamBundle = StreamBundle() - lateinit var type: StreamContract.Type - lateinit var category: StreamContract.Category + private var streamBundleMap: MutableMap = mutableMapOf( + StreamContract.Category.APPLICATION to StreamBundle(), + StreamContract.Category.GAME to StreamBundle() + ) fun contract(): StreamContract { return if (authProvider.isAnonymous) { @@ -68,33 +69,38 @@ class BaseClusterViewModel @Inject constructor( } fun getStreamBundle(category: StreamContract.Category, type: StreamContract.Type) { - this.type = type - this.category = category liveData.postValue(ViewState.Loading) - observe() + observe(category, type) } - fun observe() { + fun observe(category: StreamContract.Category, type: StreamContract.Type) { viewModelScope.launch(Dispatchers.IO) { supervisorScope { + if (targetBundle(category).streamClusters.isNotEmpty()) { + liveData.postValue(ViewState.Success(targetBundle(category))) + } + try { - if (!streamBundle.hasCluster() || streamBundle.hasNext()) { + if (!targetBundle(category).hasCluster() || targetBundle(category).hasNext()) { //Fetch new stream bundle - val newBundle = if (streamBundle.streamClusters.isEmpty()) { + val newBundle = if (targetBundle(category).streamClusters.isEmpty()) { contract().fetch(type, category) } else { - contract().nextStreamBundle(category, streamBundle.streamNextPageUrl) + contract().nextStreamBundle( + category, + targetBundle((category)).streamNextPageUrl + ) } //Update old bundle - streamBundle.apply { + targetBundle(category).apply { streamClusters.putAll(newBundle.streamClusters) streamNextPageUrl = newBundle.streamNextPageUrl } //Post updated to UI - liveData.postValue(ViewState.Success(streamBundle)) + liveData.postValue(ViewState.Success(targetBundle(category))) } else { Log.i("End of Bundle") } @@ -105,15 +111,15 @@ class BaseClusterViewModel @Inject constructor( } } - 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(streamCluster.id, newCluster) - liveData.postValue(ViewState.Success(streamBundle)) + updateCluster(category, streamCluster.id, newCluster) + liveData.postValue(ViewState.Success(targetBundle(category))) } else { Log.i("End of cluster") streamCluster.clusterNextPageUrl = String() @@ -125,10 +131,20 @@ class BaseClusterViewModel @Inject constructor( } } - private fun updateCluster(clusterID: Int, newCluster: StreamCluster) { - streamBundle.streamClusters[clusterID]?.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 = streamBundleMap[category] + + return streamBundle!! + } }