diff --git a/app/src/main/java/com/aurora/store/data/State.kt b/app/src/main/java/com/aurora/store/data/State.kt index ec5889890..793b2fd60 100644 --- a/app/src/main/java/com/aurora/store/data/State.kt +++ b/app/src/main/java/com/aurora/store/data/State.kt @@ -28,12 +28,6 @@ sealed class ViewState { data class Success(val data: T) : ViewState() } -sealed class RequestState { - object Init : RequestState() - object Pending : RequestState() - object Complete : RequestState() -} - sealed class AuthState { object Available : AuthState() object Unavailable : AuthState() diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/CategoryFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/CategoryFragment.kt index 10a552934..192e21e85 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/CategoryFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/CategoryFragment.kt @@ -20,25 +20,23 @@ package com.aurora.store.view.ui.commons import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.lifecycle.ViewModelProvider +import androidx.fragment.app.viewModels import com.aurora.Constants import com.aurora.gplayapi.data.models.Category import com.aurora.store.R import com.aurora.store.databinding.FragmentGenericRecyclerBinding import com.aurora.store.view.epoxy.views.CategoryViewModel_ -import com.aurora.store.viewmodel.category.AppCategoryViewModel -import com.aurora.store.viewmodel.category.BaseCategoryViewModel -import com.aurora.store.viewmodel.category.GameCategoryViewModel +import com.aurora.store.viewmodel.category.CategoryViewModel import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class CategoryFragment : BaseFragment() { +class CategoryFragment : BaseFragment(R.layout.fragment_generic_recycler) { - private lateinit var B: FragmentGenericRecyclerBinding - private lateinit var VM: BaseCategoryViewModel + private var _binding: FragmentGenericRecyclerBinding? = null + private val binding get() = _binding!! + + private val viewModel: CategoryViewModel by viewModels() private var pageType = 0 @@ -53,18 +51,9 @@ class CategoryFragment : BaseFragment() { } } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - B = FragmentGenericRecyclerBinding.bind( - inflater.inflate( - R.layout.fragment_generic_recycler, - container, - false - ) - ) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + _binding = FragmentGenericRecyclerBinding.bind(view) val bundle = arguments if (bundle != null) { @@ -72,31 +61,27 @@ class CategoryFragment : BaseFragment() { } when (pageType) { - 0 -> VM = ViewModelProvider(this)[AppCategoryViewModel::class.java] - 1 -> VM = ViewModelProvider(this)[GameCategoryViewModel::class.java] + 0 -> viewModel.getCategoryList(Category.Type.APPLICATION) + 1 -> viewModel.getCategoryList(Category.Type.GAME) } - return B.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - VM.liveData.observe(viewLifecycleOwner) { - updateController(it) - } - } - - private fun updateController(categoryList: List) { - B.recycler.withModels { - setFilterDuplicates(true) - categoryList.forEach { - add( - CategoryViewModel_() - .id(it.title) - .category(it) - .click { _ -> openCategoryBrowseFragment(it) } - ) + viewModel.liveData.observe(viewLifecycleOwner) { categoryList -> + binding.recycler.withModels { + setFilterDuplicates(true) + categoryList.forEach { + add( + CategoryViewModel_() + .id(it.title) + .category(it) + .click { _ -> openCategoryBrowseFragment(it) } + ) + } } } } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/EditorChoiceFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/EditorChoiceFragment.kt index 4087acab8..4ee5e63d9 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/EditorChoiceFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/EditorChoiceFragment.kt @@ -20,27 +20,25 @@ package com.aurora.store.view.ui.commons import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.lifecycle.ViewModelProvider +import androidx.fragment.app.viewModels import com.aurora.Constants -import com.aurora.gplayapi.data.models.editor.EditorChoiceBundle import com.aurora.gplayapi.data.models.editor.EditorChoiceCluster +import com.aurora.gplayapi.helpers.StreamHelper import com.aurora.store.R import com.aurora.store.databinding.FragmentForYouBinding import com.aurora.store.view.epoxy.controller.EditorChoiceController -import com.aurora.store.viewmodel.editorschoice.AppEditorChoiceViewModel -import com.aurora.store.viewmodel.editorschoice.BaseEditorChoiceViewModel -import com.aurora.store.viewmodel.editorschoice.GameEditorChoiceViewModel +import com.aurora.store.viewmodel.editorschoice.EditorChoiceViewModel import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class EditorChoiceFragment : BaseFragment(), EditorChoiceController.Callbacks { +class EditorChoiceFragment : BaseFragment(R.layout.fragment_for_you), + EditorChoiceController.Callbacks { - private lateinit var B: FragmentForYouBinding - private lateinit var C: EditorChoiceController - private lateinit var VM: BaseEditorChoiceViewModel + private var _binding: FragmentForYouBinding? = null + private val binding get() = _binding!! + + private val viewModel: EditorChoiceViewModel by viewModels() private var pageType = 0 @@ -55,46 +53,31 @@ class EditorChoiceFragment : BaseFragment(), EditorChoiceController.Callbacks { } } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - B = FragmentForYouBinding.bind( - inflater.inflate( - R.layout.fragment_for_you, - container, - false - ) - ) - - C = EditorChoiceController(this) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + _binding = FragmentForYouBinding.bind(view) val bundle = arguments if (bundle != null) { pageType = bundle.getInt(Constants.PAGE_TYPE, 0) } + val editorChoiceController = EditorChoiceController(this) + binding.recycler.setController(editorChoiceController) + when (pageType) { - 0 -> VM = ViewModelProvider(this)[AppEditorChoiceViewModel::class.java] - 1 -> VM = ViewModelProvider(this)[GameEditorChoiceViewModel::class.java] + 0 -> viewModel.getEditorChoiceStream(StreamHelper.Category.APPLICATION) + 1 -> viewModel.getEditorChoiceStream(StreamHelper.Category.GAME) } - return B.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - B.recycler.setController(C) - - VM.liveData.observe(viewLifecycleOwner) { - updateController(it) + viewModel.liveData.observe(viewLifecycleOwner) { + editorChoiceController.setData(it) } } - private fun updateController(editorChoiceBundles: List) { - C.setData(editorChoiceBundles) + override fun onDestroyView() { + super.onDestroyView() + _binding = null } override fun onClick(editorChoiceCluster: EditorChoiceCluster) { diff --git a/app/src/main/java/com/aurora/store/view/ui/search/SearchResultsFragment.kt b/app/src/main/java/com/aurora/store/view/ui/search/SearchResultsFragment.kt index dce715da4..47e662843 100644 --- a/app/src/main/java/com/aurora/store/view/ui/search/SearchResultsFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/search/SearchResultsFragment.kt @@ -28,11 +28,7 @@ import android.view.KeyEvent import android.view.View import android.view.inputmethod.EditorInfo import android.widget.TextView -import androidx.core.view.isVisible -import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.SearchBundle @@ -124,32 +120,6 @@ class SearchResultsFragment : BaseFragment(R.layout.fragment_search_result), query = requireArguments().getString("query") query?.let { updateQuery(it) } - - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - VM.responseCode.collect { - when (it) { - 429 -> { - if (VM.liveData.value?.appList?.isEmpty() == true) { - attachErrorLayout(getString(R.string.rate_limited)) - } else { - snackbar = Snackbar.make( - binding.root, - getString(R.string.rate_limited), - Snackbar.LENGTH_INDEFINITE - ) - snackbar?.show() - } - } - - else -> { - if (binding.errorLayout.isVisible) detachErrorLayout() - if (snackbar != null && snackbar?.isShown == true) snackbar?.dismiss() - } - } - } - } - } } override fun onDestroyView() { @@ -163,19 +133,6 @@ class SearchResultsFragment : BaseFragment(R.layout.fragment_search_result), _binding = null } - private fun attachErrorLayout(message: String) { - binding.recycler.visibility = View.GONE - binding.filterFab.visibility = View.GONE - binding.errorLayout.visibility = View.VISIBLE - binding.errorMessage.text = message - } - - private fun detachErrorLayout() { - binding.recycler.visibility = View.VISIBLE - binding.filterFab.visibility = View.VISIBLE - binding.errorLayout.visibility = View.GONE - } - private fun updateController(searchBundle: SearchBundle?) { if (searchBundle == null) { shimmerAnimationVisible = true diff --git a/app/src/main/java/com/aurora/store/viewmodel/BaseAndroidViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/BaseAndroidViewModel.kt deleted file mode 100644 index 6e84c9b8c..000000000 --- a/app/src/main/java/com/aurora/store/viewmodel/BaseAndroidViewModel.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - */ - -package com.aurora.store.viewmodel - -import android.app.Application -import androidx.lifecycle.AndroidViewModel -import androidx.lifecycle.viewModelScope -import com.aurora.store.data.RequestState -import com.aurora.store.data.network.HttpClient -import com.aurora.store.util.Log -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import kotlinx.coroutines.flow.launchIn -import java.lang.reflect.Modifier - -abstract class BaseAndroidViewModel(application: Application) : AndroidViewModel(application) { - - val responseCode = HttpClient.getPreferredClient(application).responseCode - - protected val gson: Gson = GsonBuilder() - .excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC) - .create() - - protected var requestState: RequestState - - init { - Log.i("${javaClass.simpleName} Created") - - requestState = RequestState.Init - - // Start collecting response code for requests - responseCode.launchIn(viewModelScope) - } - - abstract fun observe() - - private fun redoLastNetworkTask() { - when (requestState) { - RequestState.Pending -> { - observe() - } - else -> { - - } - } - } -} diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/BaseAppsViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/BaseAppsViewModel.kt deleted file mode 100644 index cd83c11b2..000000000 --- a/app/src/main/java/com/aurora/store/viewmodel/all/BaseAppsViewModel.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - */ - -package com.aurora.store.viewmodel.all - -import android.app.Application -import android.content.pm.PackageInfo -import androidx.lifecycle.MutableLiveData -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.helpers.AppDetailsHelper -import com.aurora.store.data.network.HttpClient -import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.data.providers.BlacklistProvider -import com.aurora.store.util.PackageUtil -import com.aurora.store.viewmodel.BaseAndroidViewModel - -abstract class BaseAppsViewModel(application: Application) : BaseAndroidViewModel(application) { - - private val authData = AuthProvider - .with(application) - .getAuthData() - - private val appDetailsHelper = AppDetailsHelper(authData) - .using(HttpClient.getPreferredClient(application)) - - var blacklistProvider = BlacklistProvider - .with(application) - - val liveData: MutableLiveData> = MutableLiveData() - - var appList: MutableList = mutableListOf() - var packageInfoMap: MutableMap = mutableMapOf() - - fun getFilteredApps(): List { - val blackList = blacklistProvider.getBlackList() - - packageInfoMap.clear() - packageInfoMap = PackageUtil.getPackageInfoMap(getApplication()) - - packageInfoMap.keys.let { packages -> - /*Filter black list*/ - val filtersPackages = packages - .filter { !blackList.contains(it) } - - return appDetailsHelper - .getAppByPackageName(filtersPackages) - .filter { it.displayName.isNotEmpty() } - .map { - it.isInstalled = true - it - } - } - } -} diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/BlacklistViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/BlacklistViewModel.kt index 721d31904..d6a573517 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/all/BlacklistViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/all/BlacklistViewModel.kt @@ -19,25 +19,32 @@ package com.aurora.store.viewmodel.all -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import android.content.pm.PackageManager import androidx.core.content.pm.PackageInfoCompat import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.aurora.store.data.RequestState import com.aurora.store.data.model.Black import com.aurora.store.data.providers.BlacklistProvider import com.aurora.store.util.PackageUtil -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope import java.util.Locale +import javax.inject.Inject -class BlacklistViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class BlacklistViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private val packageManager: PackageManager = application.packageManager - private val blacklistProvider: BlacklistProvider = BlacklistProvider.with(application) + private val packageManager: PackageManager = context.packageManager + private val blacklistProvider: BlacklistProvider = BlacklistProvider.with(context) var blackList: MutableList = mutableListOf() var selected: MutableSet = mutableSetOf() @@ -45,16 +52,15 @@ class BlacklistViewModel(application: Application) : BaseAndroidViewModel(applic val liveData: MutableLiveData> = MutableLiveData() init { - requestState = RequestState.Init selected = blacklistProvider.getBlackList() observe() } - override fun observe() { + fun observe() { viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { - val packageInfoMap = PackageUtil.getPackageInfoMap(getApplication()) + val packageInfoMap = PackageUtil.getPackageInfoMap(context) packageInfoMap.values .filter { it.packageName != null @@ -72,10 +78,8 @@ class BlacklistViewModel(application: Application) : BaseAndroidViewModel(applic blackList.add(black) } liveData.postValue(blackList.sortedBy { it.displayName.lowercase(Locale.getDefault()) }) - requestState = RequestState.Complete } catch (e: Exception) { e.printStackTrace() - requestState = RequestState.Pending } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt index dacfc7801..e57c7e164 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt @@ -19,34 +19,49 @@ package com.aurora.store.viewmodel.all -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.extensions.flushAndAdd -import com.aurora.store.data.RequestState +import com.aurora.gplayapi.data.models.App import com.aurora.store.data.event.BusEvent import com.aurora.store.util.AppUtil +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.util.Locale +import javax.inject.Inject -class InstalledViewModel(application: Application) : BaseAppsViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class InstalledViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { + + private val TAG = InstalledViewModel::class.java.simpleName + + var appList: MutableList = mutableListOf() + val liveData: MutableLiveData> = MutableLiveData() init { EventBus.getDefault().register(this) - requestState = RequestState.Init + observe() } - override fun observe() { + fun observe() { viewModelScope.launch(Dispatchers.IO) { - requestState = try { - appList = AppUtil.getFilteredInstalledApps(getApplication()).toMutableList() + try { + appList = AppUtil.getFilteredInstalledApps(context).toMutableList() liveData.postValue(appList.sortedBy { it.displayName.lowercase(Locale.getDefault()) }) - RequestState.Complete - } catch (e: Exception) { - RequestState.Pending + } catch (exception: Exception) { + Log.e(TAG, "Failed to get installed apps", exception) } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/LibraryAppsViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/LibraryAppsViewModel.kt index 75c197e19..923d6e0fc 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/all/LibraryAppsViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/all/LibraryAppsViewModel.kt @@ -19,34 +19,37 @@ package com.aurora.store.viewmodel.all -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.helpers.ClusterHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class LibraryAppsViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class LibraryAppsViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private val authData: AuthData = AuthProvider.with(application).getAuthData() + private val authData: AuthData = AuthProvider.with(context).getAuthData() private val clusterHelper: ClusterHelper = - ClusterHelper(authData).using(HttpClient.getPreferredClient(application)) + ClusterHelper(authData).using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() var streamCluster: StreamCluster = StreamCluster() - init { - requestState = RequestState.Init - } - - override fun observe() { + fun observe() { viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { @@ -62,12 +65,9 @@ class LibraryAppsViewModel(application: Application) : BaseAndroidViewModel(appl updateCluster(newCluster) liveData.postValue(streamCluster) } - else -> { - requestState = RequestState.Complete - } + else -> {} } - } catch (e: Exception) { - requestState = RequestState.Pending + } catch (_: Exception) { } } } @@ -79,4 +79,4 @@ class LibraryAppsViewModel(application: Application) : BaseAndroidViewModel(appl clusterNextPageUrl = newCluster.clusterNextPageUrl } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/PurchasedViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/PurchasedViewModel.kt index 10029e9f9..d13f81433 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/all/PurchasedViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/all/PurchasedViewModel.kt @@ -19,15 +19,18 @@ package com.aurora.store.viewmodel.all -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.helpers.PurchaseHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope @@ -37,24 +40,24 @@ data class PaginatedAppList( var hasMore: Boolean ) -class PurchasedViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class PurchasedViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private val authData = AuthProvider.with(application).getAuthData() + private val authData = AuthProvider.with(context).getAuthData() - private val purchaseHelper = PurchaseHelper(authData).using(HttpClient.getPreferredClient(application)) + private val purchaseHelper = PurchaseHelper(authData).using(HttpClient.getPreferredClient(context)) private var appList: MutableList = mutableListOf() val liveData: MutableLiveData = MutableLiveData() - init { - requestState = RequestState.Init - } - - override fun observe() { + fun observe() { viewModelScope.launch(Dispatchers.IO) { supervisorScope { - requestState = try { + try { val nextAppList = purchaseHelper.getPurchaseHistory(appList.size) .filter { it.displayName.isNotEmpty() } @@ -72,11 +75,9 @@ class PurchasedViewModel(application: Application) : BaseAndroidViewModel(applic ) ) } - RequestState.Complete - } catch (e: Exception) { - RequestState.Pending + } catch (_: Exception) { } } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/UpdatesViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/UpdatesViewModel.kt index fab5f17b9..4a065709f 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/all/UpdatesViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/all/UpdatesViewModel.kt @@ -19,14 +19,18 @@ package com.aurora.store.viewmodel.all -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import android.util.Log +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.App import com.aurora.store.util.AppUtil import com.aurora.store.util.DownloadWorkerUtil import com.aurora.store.util.Preferences +import com.google.gson.Gson import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import java.util.Locale import javax.inject.Inject import kotlinx.coroutines.Dispatchers @@ -35,10 +39,12 @@ import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.launch @HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 class UpdatesViewModel @Inject constructor( - application: Application, + @ApplicationContext private val context: Context, + private val gson: Gson, private val downloadWorkerUtil: DownloadWorkerUtil -) : BaseAppsViewModel(application) { +) : ViewModel() { private val TAG = UpdatesViewModel::class.java.simpleName @@ -49,14 +55,14 @@ class UpdatesViewModel @Inject constructor( val downloadsList get() = downloadWorkerUtil.downloadsList - override fun observe() { + fun observe() { viewModelScope.launch(Dispatchers.IO) { try { val isExtendedUpdateEnabled = Preferences.getBoolean( - getApplication(), Preferences.PREFERENCE_UPDATES_EXTENDED + context, Preferences.PREFERENCE_UPDATES_EXTENDED ) val updates = - AppUtil.getUpdatableApps(getApplication(), gson, !isExtendedUpdateEnabled) + AppUtil.getUpdatableApps(context, gson, !isExtendedUpdateEnabled) .sortedBy { it.displayName.lowercase(Locale.getDefault()) } _updates.emit(updates) } catch (exception: Exception) { diff --git a/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt index 305b3e314..4235bb72d 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt @@ -19,10 +19,11 @@ package com.aurora.store.viewmodel.auth -import android.app.Application +import android.annotation.SuppressLint import android.content.Context import android.util.Log import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.Constants import com.aurora.gplayapi.data.models.AuthData @@ -33,7 +34,6 @@ import com.aurora.gplayapi.helpers.AuthValidator import com.aurora.store.AccountType import com.aurora.store.R import com.aurora.store.data.AuthState -import com.aurora.store.data.RequestState import com.aurora.store.data.event.BusEvent import com.aurora.store.data.model.InsecureAuth import com.aurora.store.data.network.HttpClient @@ -43,7 +43,9 @@ import com.aurora.store.data.providers.SpoofProvider import com.aurora.store.util.AC2DMTask import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA -import com.aurora.store.viewmodel.BaseAndroidViewModel +import com.google.gson.Gson +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope @@ -51,22 +53,24 @@ import org.greenrobot.eventbus.EventBus import java.net.ConnectException import java.net.UnknownHostException import java.util.* +import javax.inject.Inject -class AuthViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class AuthViewModel @Inject constructor( + @ApplicationContext private val context: Context, + private val gson: Gson +) : ViewModel() { private val TAG = AuthViewModel::class.java.simpleName - private val spoofProvider = SpoofProvider(getApplication()) + private val spoofProvider = SpoofProvider(context) val liveData: MutableLiveData = MutableLiveData() - init { - requestState = RequestState.Init - } - - override fun observe() { + fun observe() { if (liveData.value != AuthState.Fetching) { - val signedIn = Preferences.getBoolean(getApplication(), Constants.ACCOUNT_SIGNED_IN) + val signedIn = Preferences.getBoolean(context, Constants.ACCOUNT_SIGNED_IN) if (signedIn) { liveData.postValue(AuthState.Available) buildSavedAuthData() @@ -80,7 +84,7 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application liveData.postValue(AuthState.Fetching) viewModelScope.launch(Dispatchers.IO) { try { - var properties = NativeDeviceInfoProvider(getApplication()).getNativeDeviceProperties() + var properties = NativeDeviceInfoProvider(context).getNativeDeviceProperties() if (spoofProvider.isDeviceSpoofEnabled()) properties = spoofProvider.getSpoofDeviceProperties() @@ -88,9 +92,7 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application verifyAndSaveAuth(authData, AccountType.GOOGLE) } catch (exception: Exception) { liveData.postValue( - AuthState.Failed( - (getApplication() as Context).getString(R.string.failed_to_generate_session) - ) + AuthState.Failed(context.getString(R.string.failed_to_generate_session)) ) Log.e(TAG, "Failed to generate Session", exception) } @@ -98,12 +100,7 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application } fun buildAnonymousAuthData() { - val insecure = Preferences.getBoolean( - getApplication(), - Preferences.PREFERENCE_INSECURE_ANONYMOUS - ) - - if (insecure) { + if (Preferences.getBoolean(context, Preferences.PREFERENCE_INSECURE_ANONYMOUS)) { buildInSecureAnonymousAuthData() } else { buildSecureAnonymousAuthData() @@ -114,14 +111,13 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application liveData.postValue(AuthState.Fetching) viewModelScope.launch(Dispatchers.IO) { try { - var properties = NativeDeviceInfoProvider(getApplication()) - .getNativeDeviceProperties() + var properties = NativeDeviceInfoProvider(context).getNativeDeviceProperties() if (spoofProvider.isDeviceSpoofEnabled()) properties = spoofProvider.getSpoofDeviceProperties() val playResponse = HttpClient - .getPreferredClient(getApplication()) + .getPreferredClient(context) .postAuth( Constants.URL_DISPENSER, gson.toJson(properties).toByteArray() @@ -137,7 +133,7 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application authData.isAnonymous = true verifyAndSaveAuth(authData, AccountType.ANONYMOUS) } else { - throwError(playResponse, getApplication()) + throwError(playResponse, context) } } catch (exception: Exception) { liveData.postValue(AuthState.Failed(exception.message.toString())) @@ -150,17 +146,15 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application liveData.postValue(AuthState.Fetching) viewModelScope.launch(Dispatchers.IO) { try { - var properties = NativeDeviceInfoProvider(getApplication()) + var properties = NativeDeviceInfoProvider(context) .getNativeDeviceProperties() if (spoofProvider.isDeviceSpoofEnabled()) properties = spoofProvider.getSpoofDeviceProperties() val playResponse = HttpClient - .getPreferredClient(getApplication()) - .getAuth( - Constants.URL_DISPENSER - ) + .getPreferredClient(context) + .getAuth(Constants.URL_DISPENSER) if (playResponse.isSuccessful) { val insecureAuth = gson.fromJson( @@ -181,7 +175,7 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application authData.isAnonymous = true verifyAndSaveAuth(authData, AccountType.ANONYMOUS) } else { - throwError(playResponse, getApplication()) + throwError(playResponse, context) } } catch (exception: Exception) { liveData.postValue(AuthState.Failed(exception.message.toString())) @@ -224,18 +218,17 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application if (isValid(savedAuthData)) { liveData.postValue(AuthState.Valid) - requestState = RequestState.Complete } else { //Generate and validate new auth - val type = AccountProvider.with(getApplication()).getAccountType() + val type = AccountProvider.with(context).getAccountType() when (type) { AccountType.GOOGLE -> { val email = Preferences.getString( - getApplication(), + context, Constants.ACCOUNT_EMAIL_PLAIN ) val aasToken = Preferences.getString( - getApplication(), + context, Constants.ACCOUNT_AAS_PLAIN ) buildGoogleAuthData(email, aasToken) @@ -248,24 +241,23 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application } catch (e: Exception) { val error = when (e) { is UnknownHostException -> { - (getApplication() as Context).getString(R.string.title_no_network) + context.getString(R.string.title_no_network) } is ConnectException -> { - (getApplication() as Context).getString(R.string.server_unreachable) + context.getString(R.string.server_unreachable) } else -> { - (getApplication() as Context).getString(R.string.bad_request) + context.getString(R.string.bad_request) } } liveData.postValue(AuthState.Failed(error)) - requestState = RequestState.Pending } } } } private fun getSavedAuthData(): AuthData { - val rawAuth: String = Preferences.getString(getApplication(), PREFERENCE_AUTH_DATA) + val rawAuth: String = Preferences.getString(context, PREFERENCE_AUTH_DATA) return if (rawAuth.isNotBlank()) gson.fromJson(rawAuth, AuthData::class.java) else @@ -275,7 +267,7 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application private fun isValid(authData: AuthData): Boolean { return try { AuthValidator(authData) - .using(HttpClient.getPreferredClient(getApplication())) + .using(HttpClient.getPreferredClient(context)) .isValid() } catch (e: Exception) { false @@ -292,9 +284,9 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application } val versionId = - Preferences.getInteger(getApplication(), Preferences.PREFERENCE_VENDING_VERSION) + Preferences.getInteger(context, Preferences.PREFERENCE_VENDING_VERSION) if (versionId != 0) { - val resources = (getApplication() as Context).resources + val resources = context.resources authData.deviceInfoProvider?.properties?.let { it.setProperty( @@ -312,16 +304,12 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) { configAuthPref(authData, type, true) liveData.postValue(AuthState.SignedIn) - requestState = RequestState.Complete } else { configAuthPref(authData, type, false) liveData.postValue(AuthState.SignedOut) - requestState = RequestState.Pending liveData.postValue( - AuthState.Failed( - (getApplication() as Context).getString(R.string.failed_to_generate_session) - ) + AuthState.Failed(context.getString(R.string.failed_to_generate_session)) ) } } @@ -329,22 +317,14 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application private fun configAuthPref(authData: AuthData, type: AccountType, signedIn: Boolean) { if (signedIn) { //Save Auth Data - Preferences.putString( - getApplication(), - PREFERENCE_AUTH_DATA, - gson.toJson(authData) - ) + Preferences.putString(context, PREFERENCE_AUTH_DATA, gson.toJson(authData)) } //Save Auth Type - Preferences.putString( - getApplication(), - Constants.ACCOUNT_TYPE, - type.name // ANONYMOUS OR GOOGLE - ) + Preferences.putString(context, Constants.ACCOUNT_TYPE, type.name) //Save Auth Status - Preferences.putBoolean(getApplication(), Constants.ACCOUNT_SIGNED_IN, signedIn) + Preferences.putBoolean(context, Constants.ACCOUNT_SIGNED_IN, signedIn) } @Throws(Exception::class) diff --git a/app/src/main/java/com/aurora/store/viewmodel/browse/ExpandedStreamBrowseViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/browse/ExpandedStreamBrowseViewModel.kt index 1f9dbc1ee..20dd9b19f 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/browse/ExpandedStreamBrowseViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/browse/ExpandedStreamBrowseViewModel.kt @@ -19,34 +19,37 @@ package com.aurora.store.viewmodel.browse -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.helpers.ExpandedBrowseHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider import com.aurora.store.util.Log -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class ExpandedStreamBrowseViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class ExpandedStreamBrowseViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private val authData: AuthData = AuthProvider.with(application).getAuthData() + private val authData: AuthData = AuthProvider.with(context).getAuthData() private val streamHelper: ExpandedBrowseHelper = ExpandedBrowseHelper(authData) - .using(HttpClient.getPreferredClient(application)) + .using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() var streamCluster: StreamCluster = StreamCluster() - override fun observe() { - requestState = RequestState.Init - } - fun getInitialCluster(expandedStreamUrl: String) { viewModelScope.launch(Dispatchers.IO) { supervisorScope { @@ -57,10 +60,8 @@ class ExpandedStreamBrowseViewModel(application: Application) : BaseAndroidViewM streamHelper.getExpandedBrowseClusters(browseResponse.browseTab.listUrl) liveData.postValue(streamCluster) } else { - requestState = RequestState.Complete } - } catch (e: Exception) { - requestState = RequestState.Pending + } catch (_: Exception) { } } } @@ -84,10 +85,8 @@ class ExpandedStreamBrowseViewModel(application: Application) : BaseAndroidViewM if (!streamCluster.hasNext()) { Log.i("End of Bundle") - requestState = RequestState.Complete } } catch (e: Exception) { - requestState = RequestState.Pending } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt index a54dcb67f..d4de25a64 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt @@ -19,26 +19,33 @@ package com.aurora.store.viewmodel.browse -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.helpers.StreamHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider import com.aurora.store.util.Log -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class StreamBrowseViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class StreamBrowseViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private val authData: AuthData = AuthProvider.with(application).getAuthData() + private val authData: AuthData = AuthProvider.with(context).getAuthData() private val streamHelper: StreamHelper = StreamHelper(authData) - .using(HttpClient.getPreferredClient(application)) + .using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() var streamCluster: StreamCluster = StreamCluster() @@ -49,12 +56,7 @@ class StreamBrowseViewModel(application: Application) : BaseAndroidViewModel(app } } - private fun getInitialCluster( - browseUrl: String - ): StreamCluster { - - requestState = RequestState.Init - + private fun getInitialCluster(browseUrl: String): StreamCluster { val browseResponse = streamHelper.getBrowseStreamResponse(browseUrl) if (browseResponse.contentsUrl.isNotEmpty()) @@ -86,16 +88,10 @@ class StreamBrowseViewModel(application: Application) : BaseAndroidViewModel(app liveData.postValue(streamCluster) } else { Log.i("End of Bundle") - requestState = RequestState.Complete } - } catch (e: Exception) { - requestState = RequestState.Pending + } catch (_: Exception) { } } } } - - override fun observe() { - requestState = RequestState.Init - } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/category/BaseCategoryViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/category/BaseCategoryViewModel.kt deleted file mode 100644 index a6c295327..000000000 --- a/app/src/main/java/com/aurora/store/viewmodel/category/BaseCategoryViewModel.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - */ - -package com.aurora.store.viewmodel.category - -import android.app.Application -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.viewModelScope -import com.aurora.gplayapi.data.models.AuthData -import com.aurora.gplayapi.data.models.Category -import com.aurora.gplayapi.helpers.CategoryHelper -import com.aurora.store.data.RequestState -import com.aurora.store.data.network.HttpClient -import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -abstract class BaseCategoryViewModel(application: Application) : BaseAndroidViewModel(application) { - - private val authData: AuthData = AuthProvider - .with(application) - .getAuthData() - - private val streamHelper: CategoryHelper = CategoryHelper(authData) - .using(HttpClient.getPreferredClient(application)) - - val liveData: MutableLiveData> = MutableLiveData() - - lateinit var type: Category.Type - - override fun observe() { - viewModelScope.launch(Dispatchers.IO) { - try { - liveData.postValue(streamHelper.getAllCategoriesList(type)) - requestState = RequestState.Complete - } catch (e: Exception) { - requestState = RequestState.Pending - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/viewmodel/category/CategoryViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/category/CategoryViewModel.kt index 00bdb0205..bcfe6a371 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/category/CategoryViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/category/CategoryViewModel.kt @@ -19,24 +19,47 @@ package com.aurora.store.viewmodel.category -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Category -import com.aurora.store.data.RequestState +import com.aurora.gplayapi.helpers.CategoryHelper +import com.aurora.store.data.network.HttpClient +import com.aurora.store.data.providers.AuthProvider +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch -class AppCategoryViewModel(application: Application) : BaseCategoryViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class CategoryViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - init { - type = Category.Type.APPLICATION - requestState = RequestState.Init - observe() + private val TAG = CategoryViewModel::class.java.simpleName + + private val authData: AuthData = AuthProvider + .with(context) + .getAuthData() + + private val streamHelper: CategoryHelper = CategoryHelper(authData) + .using(HttpClient.getPreferredClient(context)) + + val liveData: MutableLiveData> = MutableLiveData() + + fun getCategoryList(type: Category.Type) { + viewModelScope.launch(Dispatchers.IO) { + try { + liveData.postValue(streamHelper.getAllCategoriesList(type)) + } catch (exception: Exception) { + Log.e(TAG, "Failed fetching list of categories", exception) + } + } } } - -class GameCategoryViewModel(application: Application) : BaseCategoryViewModel(application) { - - init { - type = Category.Type.GAME - requestState = RequestState.Init - observe() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/viewmodel/details/DetailsClusterViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/details/DetailsClusterViewModel.kt index 7d6c36b85..8ceaba2ac 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/details/DetailsClusterViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/details/DetailsClusterViewModel.kt @@ -19,28 +19,35 @@ package com.aurora.store.viewmodel.details -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.helpers.AppDetailsHelper import com.aurora.gplayapi.helpers.StreamHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.ViewState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider import com.aurora.store.util.Log -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class DetailsClusterViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class DetailsClusterViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private var authData: AuthData = AuthProvider.with(application).getAuthData() - private var appDetailsHelper = AppDetailsHelper(authData).using(HttpClient.getPreferredClient(application)) + private var authData: AuthData = AuthProvider.with(context).getAuthData() + private var appDetailsHelper = AppDetailsHelper(authData).using(HttpClient.getPreferredClient(context)) private var streamHelper = StreamHelper(authData) val liveData: MutableLiveData = MutableLiveData() @@ -49,21 +56,13 @@ class DetailsClusterViewModel(application: Application) : BaseAndroidViewModel(a lateinit var type: StreamHelper.Type lateinit var category: StreamHelper.Category - override fun observe() { - - } - - fun getStreamBundle( - streamUrl: String - ) { + fun getStreamBundle(streamUrl: String) { viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { streamBundle = appDetailsHelper.getDetailsStream(streamUrl) liveData.postValue(ViewState.Success(streamBundle)) - requestState = RequestState.Complete } catch (e: Exception) { - requestState = RequestState.Pending liveData.postValue(ViewState.Error(e.message)) } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/details/DevProfileViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/details/DevProfileViewModel.kt index 918ed86ee..fecad1770 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/details/DevProfileViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/details/DevProfileViewModel.kt @@ -19,8 +19,10 @@ package com.aurora.store.viewmodel.details -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamBundle @@ -28,20 +30,25 @@ import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.data.models.details.DevStream import com.aurora.gplayapi.helpers.AppDetailsHelper import com.aurora.gplayapi.helpers.StreamHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.ViewState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider import com.aurora.store.util.Log -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class DevProfileViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class DevProfileViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private var authData: AuthData = AuthProvider.with(application).getAuthData() - private var appDetailsHelper = AppDetailsHelper(authData).using(HttpClient.getPreferredClient(application)) + private var authData: AuthData = AuthProvider.with(context).getAuthData() + private var appDetailsHelper = AppDetailsHelper(authData).using(HttpClient.getPreferredClient(context)) private var streamHelper = StreamHelper(authData) val liveData: MutableLiveData = MutableLiveData() @@ -51,22 +58,14 @@ class DevProfileViewModel(application: Application) : BaseAndroidViewModel(appli lateinit var type: StreamHelper.Type lateinit var category: StreamHelper.Category - override fun observe() { - - } - - fun getStreamBundle( - devId: String - ) { + fun getStreamBundle(devId: String) { viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { devStream = appDetailsHelper.getDeveloperStream(devId) streamBundle = devStream.streamBundle liveData.postValue(ViewState.Success(devStream)) - requestState = RequestState.Complete } catch (e: Exception) { - requestState = RequestState.Pending liveData.postValue(ViewState.Error(e.message)) } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/editorschoice/BaseEditorChoiceViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/editorschoice/BaseEditorChoiceViewModel.kt deleted file mode 100644 index 786a924af..000000000 --- a/app/src/main/java/com/aurora/store/viewmodel/editorschoice/BaseEditorChoiceViewModel.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - */ - -package com.aurora.store.viewmodel.editorschoice - -import android.app.Application -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.viewModelScope -import com.aurora.gplayapi.data.models.AuthData -import com.aurora.gplayapi.data.models.editor.EditorChoiceBundle -import com.aurora.gplayapi.helpers.StreamHelper -import com.aurora.store.data.RequestState -import com.aurora.store.data.network.HttpClient -import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.supervisorScope - -open class BaseEditorChoiceViewModel(application: Application) : BaseAndroidViewModel(application) { - - private val authData: AuthData = AuthProvider - .with(application) - .getAuthData() - - private val streamHelper: StreamHelper = StreamHelper(authData) - .using(HttpClient.getPreferredClient(application)) - - lateinit var category: StreamHelper.Category - - val liveData: MutableLiveData> = MutableLiveData() - - override fun observe() { - viewModelScope.launch(Dispatchers.IO) { - supervisorScope { - try { - val editorChoiceBundle = streamHelper.getEditorChoiceStream(category) - liveData.postValue(editorChoiceBundle) - requestState = RequestState.Complete - } catch (e: Exception) { - requestState = RequestState.Pending - } - } - } - } -} diff --git a/app/src/main/java/com/aurora/store/viewmodel/editorschoice/EditorBrowseViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/editorschoice/EditorBrowseViewModel.kt index 157de9bd4..dd7ca3598 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/editorschoice/EditorBrowseViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/editorschoice/EditorBrowseViewModel.kt @@ -19,42 +19,40 @@ package com.aurora.store.viewmodel.editorschoice -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.helpers.StreamHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class EditorBrowseViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class EditorBrowseViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private val authData: AuthData = AuthProvider.with(application).getAuthData() + private val authData: AuthData = AuthProvider.with(context).getAuthData() private val streamHelper: StreamHelper = StreamHelper(authData) - .using(HttpClient.getPreferredClient(application)) + .using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData> = MutableLiveData() val appList: MutableList = mutableListOf() - override fun observe() { - requestState = RequestState.Init - } - - fun getEditorStreamBundle( - browseUrl: String - ) { + fun getEditorStreamBundle(browseUrl: String) { viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { - - requestState = RequestState.Init - val browseResponse = streamHelper.getBrowseStreamResponse(browseUrl) val listResponse = streamHelper.getNextStreamResponse(browseResponse.browseTab.listUrl) @@ -68,10 +66,8 @@ class EditorBrowseViewModel(application: Application) : BaseAndroidViewModel(app } liveData.postValue(appList) - requestState = RequestState.Complete - } catch (e: Exception) { - requestState = RequestState.Pending + } catch (_: Exception) { } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/editorschoice/EditorChoiceViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/editorschoice/EditorChoiceViewModel.kt index 695657d21..a93826efb 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/editorschoice/EditorChoiceViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/editorschoice/EditorChoiceViewModel.kt @@ -19,20 +19,51 @@ package com.aurora.store.viewmodel.editorschoice -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.editor.EditorChoiceBundle import com.aurora.gplayapi.helpers.StreamHelper +import com.aurora.store.data.network.HttpClient +import com.aurora.store.data.providers.AuthProvider +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope -class AppEditorChoiceViewModel(application: Application) : BaseEditorChoiceViewModel(application) { - init { - category = StreamHelper.Category.APPLICATION - observe() - } -} - - -class GameEditorChoiceViewModel(application: Application) : BaseEditorChoiceViewModel(application) { - init { - category = StreamHelper.Category.GAME - observe() +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class EditorChoiceViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { + + private val TAG = EditorChoiceViewModel::class.java.simpleName + + private val authData: AuthData = AuthProvider + .with(context) + .getAuthData() + + private val streamHelper: StreamHelper = StreamHelper(authData) + .using(HttpClient.getPreferredClient(context)) + + val liveData: MutableLiveData> = MutableLiveData() + + fun getEditorChoiceStream(category: StreamHelper.Category) { + viewModelScope.launch(Dispatchers.IO) { + supervisorScope { + try { + val editorChoiceBundle = streamHelper.getEditorChoiceStream(category) + liveData.postValue(editorChoiceBundle) + } catch (exception: Exception) { + Log.e(TAG, "Failed fetching list of categories", exception) + } + } + } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/homestream/BaseClusterViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/homestream/BaseClusterViewModel.kt index 5dec724b7..bf34afd52 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/homestream/BaseClusterViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/homestream/BaseClusterViewModel.kt @@ -19,29 +19,36 @@ package com.aurora.store.viewmodel.homestream -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.helpers.StreamHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.ViewState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider import com.aurora.store.util.Log -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class BaseClusterViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class BaseClusterViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - var authData: AuthData = AuthProvider.with(application).getAuthData() + var authData: AuthData = AuthProvider.with(context).getAuthData() var streamHelper: StreamHelper = - StreamHelper(authData).using(HttpClient.getPreferredClient(application)) + StreamHelper(authData).using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() var streamBundle: StreamBundle = StreamBundle() @@ -56,7 +63,7 @@ class BaseClusterViewModel(application: Application) : BaseAndroidViewModel(appl observe() } - override fun observe() { + fun observe() { viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { @@ -79,10 +86,8 @@ class BaseClusterViewModel(application: Application) : BaseAndroidViewModel(appl liveData.postValue(ViewState.Success(streamBundle)) } else { Log.i("End of Bundle") - requestState = RequestState.Complete } } catch (e: Exception) { - requestState = RequestState.Pending liveData.postValue(ViewState.Error(e.message)) } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/review/ReviewViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/review/ReviewViewModel.kt index 7af1c867a..e62ff00c0 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/review/ReviewViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/review/ReviewViewModel.kt @@ -19,29 +19,36 @@ package com.aurora.store.viewmodel.review -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Review import com.aurora.gplayapi.data.models.ReviewCluster import com.aurora.gplayapi.helpers.ReviewsHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class ReviewViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class ReviewViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { var authData: AuthData = AuthProvider - .with(application) + .with(context) .getAuthData() var reviewsHelper: ReviewsHelper = ReviewsHelper(authData) - .using(HttpClient.getPreferredClient(application)) + .using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() @@ -53,8 +60,7 @@ class ReviewViewModel(application: Application) : BaseAndroidViewModel(applicati try { reviewsCluster = reviewsHelper.getReviews(packageName, filter) liveData.postValue(reviewsCluster) - } catch (e: Exception) { - requestState = RequestState.Pending + } catch (_: Exception) { } } } @@ -72,14 +78,9 @@ class ReviewViewModel(application: Application) : BaseAndroidViewModel(applicati } liveData.postValue(reviewsCluster) - } catch (e: Exception) { - requestState = RequestState.Pending + } catch (_: Exception) { } } } } - - override fun observe() { - - } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/aurora/store/viewmodel/sale/AppSalesViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/sale/AppSalesViewModel.kt index 3620fe083..3aed1176e 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/sale/AppSalesViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/sale/AppSalesViewModel.kt @@ -19,26 +19,33 @@ package com.aurora.store.viewmodel.sale -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.helpers.AppSalesHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel import com.aurora.store.viewmodel.all.PaginatedAppList +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class AppSalesViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class AppSalesViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private val authData: AuthData = AuthProvider.with(application).getAuthData() + private val authData: AuthData = AuthProvider.with(context).getAuthData() private val appSalesHelper: AppSalesHelper = - AppSalesHelper(authData).using(HttpClient.getPreferredClient(application)) + AppSalesHelper(authData).using(HttpClient.getPreferredClient(context)) private var page: Int = 0 private val appList: MutableList = mutableListOf() @@ -46,14 +53,13 @@ class AppSalesViewModel(application: Application) : BaseAndroidViewModel(applica val liveData: MutableLiveData = MutableLiveData() init { - requestState = RequestState.Init observe() } - override fun observe() { + fun observe() { viewModelScope.launch(Dispatchers.IO) { supervisorScope { - requestState = try { + try { val nextAppList = getSearchResults() if (nextAppList.isEmpty()) { @@ -73,16 +79,13 @@ class AppSalesViewModel(application: Application) : BaseAndroidViewModel(applica ) } - RequestState.Complete - } catch (e: Exception) { - RequestState.Pending + } catch (_: Exception) { } } } } - private fun getSearchResults( - ): List { + private fun getSearchResults(): List { return try { appSalesHelper.getAppsOnSale(page = page++, offer = 100) } catch (e: Exception) { diff --git a/app/src/main/java/com/aurora/store/viewmodel/search/SearchResultViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/search/SearchResultViewModel.kt index 176473af6..562cad72b 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/search/SearchResultViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/search/SearchResultViewModel.kt @@ -19,33 +19,40 @@ package com.aurora.store.viewmodel.search -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import android.util.Log import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.extensions.flushAndAdd import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.SearchBundle import com.aurora.gplayapi.helpers.SearchHelper import com.aurora.gplayapi.helpers.WebSearchHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class SearchResultViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class SearchResultViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { private val TAG = SearchResultViewModel::class.java.simpleName private val authData: AuthData = AuthProvider - .with(application) + .with(context) .getAuthData() private val webSearchHelper: WebSearchHelper = WebSearchHelper(authData) private val searchHelper: SearchHelper = SearchHelper(authData) - .using(HttpClient.getPreferredClient(application)) + .using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() @@ -87,7 +94,7 @@ class SearchResultViewModel(application: Application) : BaseAndroidViewModel(app viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { - if (nextSubBundleSet.isNotEmpty() && responseCode.value != 429) { + if (nextSubBundleSet.isNotEmpty()) { val newSearchBundle = helper().next(nextSubBundleSet) if (newSearchBundle.appList.isNotEmpty()) { searchBundle.apply { @@ -99,13 +106,9 @@ class SearchResultViewModel(application: Application) : BaseAndroidViewModel(app } } } catch (e: Exception) { - Log.d(TAG, "Response code: ${responseCode.value}", e) + Log.d(TAG, "Failed to get next bundle", e) } } } } - - override fun observe() { - requestState = RequestState.Init - } } 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 96e90d6da..3d69c31b4 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 @@ -19,28 +19,35 @@ package com.aurora.store.viewmodel.subcategory -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.helpers.CategoryHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.ViewState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider import com.aurora.store.util.Log -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class SubCategoryClusterViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class SubCategoryClusterViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - var authData: AuthData = AuthProvider.with(application).getAuthData() + var authData: AuthData = AuthProvider.with(context).getAuthData() var categoryHelper: CategoryHelper = CategoryHelper(authData) - .using(HttpClient.getPreferredClient(application)) + .using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() var streamBundle: StreamBundle = StreamBundle() @@ -65,7 +72,7 @@ class SubCategoryClusterViewModel(application: Application) : BaseAndroidViewMod observe() } - override fun observe() { + fun observe() { viewModelScope.launch(Dispatchers.IO) { supervisorScope { try { @@ -85,11 +92,9 @@ class SubCategoryClusterViewModel(application: Application) : BaseAndroidViewMod liveData.postValue(ViewState.Success(streamBundle)) } else { Log.i("End of Bundle") - requestState = RequestState.Complete } } catch (e: Exception) { e.printStackTrace() - requestState = RequestState.Pending liveData.postValue(ViewState.Error(e.message)) } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/topchart/TopChartViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/topchart/TopChartViewModel.kt index e1ef8eba9..c0e200e44 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/topchart/TopChartViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/topchart/TopChartViewModel.kt @@ -19,25 +19,32 @@ package com.aurora.store.viewmodel.topchart -import android.app.Application +import android.annotation.SuppressLint +import android.content.Context import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.helpers.TopChartsHelper -import com.aurora.store.data.RequestState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.viewmodel.BaseAndroidViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope -class TopChartViewModel(application: Application) : BaseAndroidViewModel(application) { +@HiltViewModel +@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 +class TopChartViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { - private val authData: AuthData = AuthProvider.with(application).getAuthData() + private val authData: AuthData = AuthProvider.with(context).getAuthData() private val topChartsHelper: TopChartsHelper = - TopChartsHelper(authData).using(HttpClient.getPreferredClient(application)) + TopChartsHelper(authData).using(HttpClient.getPreferredClient(context)) val liveData: MutableLiveData = MutableLiveData() var streamCluster: StreamCluster = StreamCluster() @@ -47,14 +54,11 @@ class TopChartViewModel(application: Application) : BaseAndroidViewModel(applica try { streamCluster = topChartsHelper.getCluster(type, chart) liveData.postValue(streamCluster) - } catch (e: Exception) { - requestState = RequestState.Pending + } catch (_: Exception) { } } } - override fun observe() {} - fun nextCluster() { viewModelScope.launch(Dispatchers.IO) { supervisorScope { @@ -71,10 +75,8 @@ class TopChartViewModel(application: Application) : BaseAndroidViewModel(applica liveData.postValue(streamCluster) } else { - requestState = RequestState.Complete } - } catch (e: Exception) { - requestState = RequestState.Pending + } catch (_: Exception) { } } } diff --git a/app/src/main/res/layout/fragment_search_result.xml b/app/src/main/res/layout/fragment_search_result.xml index 5f2e313de..32e65799a 100644 --- a/app/src/main/res/layout/fragment_search_result.xml +++ b/app/src/main/res/layout/fragment_search_result.xml @@ -42,30 +42,6 @@ app:itemSpacing="@dimen/margin_normal" /> - - - - - - -