From b7279ded30c03284c5c90fad5a6b694dec8d260e Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Wed, 25 Oct 2023 00:07:58 +0600 Subject: [PATCH 1/4] refactor: homepage --- .../e/apps/data/fused/FusedAPIRepository.kt | 5 - .../foundation/e/apps/data/fused/FusedApi.kt | 8 -- .../e/apps/data/fused/FusedApiImpl.kt | 42 +-------- .../foundation/e/apps/ui/home/HomeFragment.kt | 10 -- .../e/apps/ui/home/HomeViewModel.kt | 57 ++++++++++-- .../e/apps/fused/FusedApiImplTest.kt | 85 ----------------- .../e/apps/home/HomeViewModelTest.kt | 92 +++++++++++++++++++ 7 files changed, 144 insertions(+), 155 deletions(-) create mode 100644 app/src/test/java/foundation/e/apps/home/HomeViewModelTest.kt diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt index f88f197e5..7ccac199e 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt @@ -135,11 +135,6 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedApi) return fusedAPIImpl.getFusedAppInstallationStatus(fusedApp) } - fun isHomeDataUpdated( - newHomeData: List, - oldHomeData: List - ) = fusedAPIImpl.isHomeDataUpdated(newHomeData, oldHomeData) - fun isAnyFusedAppUpdated( newFusedApps: List, oldFusedApps: List diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApi.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApi.kt index 6e9e473e1..7af8c96ae 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApi.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApi.kt @@ -141,14 +141,6 @@ interface FusedApi { */ fun getFusedAppInstallationStatus(fusedApp: FusedApp): Status - /** - * @return true, if any change is found, otherwise false - */ - fun isHomeDataUpdated( - newHomeData: List, - oldHomeData: List - ): Boolean - /** * @return returns true if there is changes in data, otherwise false */ diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt index 1b3162982..290b33399 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt @@ -34,7 +34,6 @@ import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.cleanapk.CleanApkDownloadInfoFetcher -import foundation.e.apps.data.cleanapk.CleanApkRetrofit import foundation.e.apps.data.cleanapk.data.app.Application import foundation.e.apps.data.cleanapk.data.categories.Categories import foundation.e.apps.data.cleanapk.data.home.Home @@ -59,9 +58,9 @@ import foundation.e.apps.data.fused.data.Ratings import foundation.e.apps.data.fused.utils.CategoryType import foundation.e.apps.data.fused.utils.CategoryUtils import foundation.e.apps.data.fusedDownload.models.FusedDownload -import foundation.e.apps.data.playstore.PlayStoreRepository import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.login.AuthObject +import foundation.e.apps.data.playstore.PlayStoreRepository import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.install.pkg.PWAManagerModule import foundation.e.apps.install.pkg.PkgManagerModule @@ -1285,45 +1284,6 @@ class FusedApiImpl @Inject constructor( return list } - /** - * @return true, if any change is found, otherwise false - */ - override fun isHomeDataUpdated( - newHomeData: List, - oldHomeData: List - ): Boolean { - if (newHomeData.size != oldHomeData.size) { - return true - } - - oldHomeData.forEach { - val fusedHome = newHomeData[oldHomeData.indexOf(it)] - if (!it.title.contentEquals(fusedHome.title) || areFusedAppsUpdated(it, fusedHome)) { - return true - } - } - return false - } - - private fun areFusedAppsUpdated( - oldFusedHome: FusedHome, - newFusedHome: FusedHome, - ): Boolean { - val fusedAppDiffUtil = HomeChildFusedAppDiffUtil() - if (oldFusedHome.list.size != newFusedHome.list.size) { - return true - } - - oldFusedHome.list.forEach { oldFusedApp -> - val indexOfOldFusedApp = oldFusedHome.list.indexOf(oldFusedApp) - val fusedApp = newFusedHome.list[indexOfOldFusedApp] - if (!fusedAppDiffUtil.areContentsTheSame(oldFusedApp, fusedApp)) { - return true - } - } - return false - } - /** * @return returns true if there is changes in data, otherwise false */ diff --git a/app/src/main/java/foundation/e/apps/ui/home/HomeFragment.kt b/app/src/main/java/foundation/e/apps/ui/home/HomeFragment.kt index f1c538a56..f20ba7f7b 100644 --- a/app/src/main/java/foundation/e/apps/ui/home/HomeFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/home/HomeFragment.kt @@ -94,10 +94,6 @@ class HomeFragment : TimeoutFragment(R.layout.fragment_home), FusedAPIInterface return@observe } - if (!isHomeDataUpdated(it)) { - return@observe - } - homeParentRVAdapter?.setData(it.data!!) } } @@ -140,12 +136,6 @@ class HomeFragment : TimeoutFragment(R.layout.fragment_home), FusedAPIInterface ).show(childFragmentManager, "HomeFragment") } - private fun isHomeDataUpdated(homeScreenResult: ResultSupreme>) = - homeParentRVAdapter?.currentList?.isEmpty() == true || homeViewModel.isHomeDataUpdated( - homeScreenResult.data!!, - homeParentRVAdapter?.currentList as List - ) - override fun onTimeout( exception: Exception, predefinedDialog: AlertDialog.Builder diff --git a/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt b/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt index 7714c2b9c..8950d8216 100644 --- a/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt @@ -18,6 +18,7 @@ package foundation.e.apps.ui.home +import androidx.annotation.VisibleForTesting import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope @@ -30,6 +31,7 @@ import foundation.e.apps.data.fused.data.FusedHome import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.exceptions.CleanApkException import foundation.e.apps.data.login.exceptions.GPlayException +import foundation.e.apps.ui.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.ui.parentFragment.LoadingViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -47,6 +49,8 @@ class HomeViewModel @Inject constructor( */ var homeScreenData: MutableLiveData>> = MutableLiveData() + var currentHomes: List? = null + fun loadData( authObjectList: List, lifecycleOwner: LifecycleOwner, @@ -72,9 +76,17 @@ class HomeViewModel @Inject constructor( ) { viewModelScope.launch { fusedAPIRepository.getHomeScreenData(authData).observe(lifecycleOwner) { - homeScreenData.postValue(it) - if (it.isSuccess()) return@observe + if (it.isSuccess() && !hasAnyChange(it.data!!)) { + this@HomeViewModel.currentHomes = it.data + homeScreenData.postValue(ResultSupreme.Error("No change is found!")) + return@observe + } + + homeScreenData.postValue(it) + if (it.isSuccess()) { + return@observe + } val exception = if (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) @@ -93,10 +105,43 @@ class HomeViewModel @Inject constructor( } } - fun isHomeDataUpdated( - newHomeData: List, - oldHomeData: List - ) = fusedAPIRepository.isHomeDataUpdated(newHomeData, oldHomeData) + @VisibleForTesting + fun hasAnyChange( + newHomes: List, + ) = currentHomes.isNullOrEmpty() || newHomes.size != currentHomes!!.size || compareWithNewData(newHomes) + + private fun compareWithNewData(newHomes: List): Boolean { + currentHomes!!.forEach { + val fusedHome = newHomes[currentHomes!!.indexOf(it)] + if (!it.title.contentEquals(fusedHome.title) || areFusedAppsUpdated(it, fusedHome)) { + return true + } + } + + return false + } + + private fun areFusedAppsUpdated( + oldHome: FusedHome, + newHome: FusedHome, + ) = oldHome.list.size != newHome.list.size || hasAppListsAnyChange(oldHome, newHome) + + private fun hasAppListsAnyChange( + oldHome: FusedHome, + newHome: FusedHome, + ): Boolean { + val fusedAppDiffUtil = HomeChildFusedAppDiffUtil() + + oldHome.list.forEach { oldFusedApp -> + val indexOfOldFusedApp = oldHome.list.indexOf(oldFusedApp) + val fusedApp = newHome.list[indexOfOldFusedApp] + if (!fusedAppDiffUtil.areContentsTheSame(oldFusedApp, fusedApp)) { + return true + } + } + + return false + } fun isAnyAppInstallStatusChanged(currentList: List?): Boolean { if (currentList == null) { diff --git a/app/src/test/java/foundation/e/apps/fused/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/fused/FusedApiImplTest.kt index 6cd386df4..a96e47163 100644 --- a/app/src/test/java/foundation/e/apps/fused/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/fused/FusedApiImplTest.kt @@ -341,91 +341,6 @@ class FusedApiImplTest { assertFalse("hasInstallStatusUpdated", isAppStatusUpdated) } - @Test - fun isHomeDataUpdated() { - val oldAppList = mutableListOf( - FusedApp( - _id = "111", - status = Status.INSTALLATION_ISSUE, - name = "Demo One", - package_name = "foundation.e.demoone", - latest_version_code = 123 - ), - FusedApp( - _id = "112", - status = Status.INSTALLED, - name = "Demo Two", - package_name = "foundation.e.demotwo", - latest_version_code = 123 - ), - FusedApp( - _id = "113", - status = Status.UNAVAILABLE, - name = "Demo Three", - package_name = "foundation.e.demothree", - latest_version_code = 123 - ) - ) - - val newAppList = mutableListOf( - FusedApp( - _id = "111", - status = Status.INSTALLATION_ISSUE, - name = "Demo One", - package_name = "foundation.e.demoone", - latest_version_code = 123 - ), - FusedApp( - _id = "112", - status = Status.UNAVAILABLE, - name = "Demo Two", - package_name = "foundation.e.demotwo", - latest_version_code = 123 - ), - FusedApp( - _id = "113", - status = Status.UNAVAILABLE, - name = "Demo Three", - package_name = "foundation.e.demothree", - latest_version_code = 123 - ) - ) - - val oldHomeData = - listOf(FusedHome("Top Free Apps", oldAppList), FusedHome("Top Free Games", oldAppList)) - var newHomeData = - listOf(FusedHome("Top Free Apps", oldAppList), FusedHome("Top Free Games", oldAppList)) - var isHomeDataUpdated = fusedAPIImpl.isHomeDataUpdated(newHomeData, oldHomeData) - assertFalse("isHomeDataUpdated/NO", isHomeDataUpdated) - newHomeData = - listOf(FusedHome("Top Free Apps", oldAppList), FusedHome("Top Free Games", newAppList)) - - isHomeDataUpdated = fusedAPIImpl.isHomeDataUpdated(newHomeData, oldHomeData) - assertTrue("isHomeDataUpdated/YES", isHomeDataUpdated) - } - - @Test - fun isHomeDataUpdatedWhenBothAreEmpty() { - val oldHomeData = listOf() - val newHomeData = listOf() - val isHomeDataUpdated = fusedAPIImpl.isHomeDataUpdated(oldHomeData, newHomeData) - assertFalse("isHomeDataUpdated", isHomeDataUpdated) - } - - @Test - fun `is home data updated when fusedapp list size is not same`() { - val oldAppList = mutableListOf(FusedApp(), FusedApp(), FusedApp()) - val newAppList = mutableListOf(FusedApp(), FusedApp()) - - val oldHomeData = - listOf(FusedHome("Top Free Apps", oldAppList), FusedHome("Top Free Games", oldAppList)) - var newHomeData = - listOf(FusedHome("Top Free Apps", oldAppList), FusedHome("Top Free Games", newAppList)) - - val isHomeDataUpdated = fusedAPIImpl.isHomeDataUpdated(newHomeData, oldHomeData) - assertTrue("isHomeDataUpdated/YES", isHomeDataUpdated) - } - @Test fun getFusedAppInstallationStatusWhenPWA() { val fusedApp = FusedApp( diff --git a/app/src/test/java/foundation/e/apps/home/HomeViewModelTest.kt b/app/src/test/java/foundation/e/apps/home/HomeViewModelTest.kt new file mode 100644 index 000000000..36e9b4e9c --- /dev/null +++ b/app/src/test/java/foundation/e/apps/home/HomeViewModelTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright MURENA SAS 2023 + * Apps Quickly and easily install Android apps onto your device! + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +package foundation.e.apps.home + +import foundation.e.apps.data.enums.Status +import foundation.e.apps.data.fused.FusedAPIRepository +import foundation.e.apps.data.fused.data.FusedApp +import foundation.e.apps.data.fused.data.FusedHome +import foundation.e.apps.ui.home.HomeViewModel +import org.junit.Assert.assertFalse +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +class HomeViewModelTest { + + @Mock + private lateinit var fusedAPIRepository: FusedAPIRepository + + private lateinit var homeViewModel: HomeViewModel + + @Before + fun setup() { + MockitoAnnotations.openMocks(this) + homeViewModel = HomeViewModel(fusedAPIRepository) + } + + @Test + fun `test hasAnyChange when app list sizes are not same`() { + val oldAppList = mutableListOf(FusedApp("123"), FusedApp("124"), FusedApp("125")) + val newAppList = mutableListOf(FusedApp("123"), FusedApp("124")) + + val oldHomeData = + listOf(FusedHome("Top Free Apps", oldAppList), FusedHome("Top Free Games", oldAppList)) + var newHomeData = + listOf(FusedHome("Top Free Apps", newAppList), FusedHome("Top Free Games", newAppList)) + + homeViewModel.currentHomes = oldHomeData + + val hasAnyChange = homeViewModel.hasAnyChange(newHomeData) + assert(hasAnyChange) + } + + @Test + fun `test hasAnyChange when contents are same`() { + val oldAppList = mutableListOf(FusedApp("123"), FusedApp("124"), FusedApp("125")) + val newAppList = mutableListOf(FusedApp("123"), FusedApp("124"), FusedApp("125")) + + val oldHomeData = + listOf(FusedHome("Top Free Apps", oldAppList), FusedHome("Top Free Games", oldAppList)) + var newHomeData = + listOf(FusedHome("Top Free Apps", newAppList), FusedHome("Top Free Games", newAppList)) + + homeViewModel.currentHomes = oldHomeData + + val hasAnyChange = homeViewModel.hasAnyChange(newHomeData) + assertFalse(hasAnyChange) + } + + @Test + fun `test hasAnyChange when contents are not same`() { + val oldAppList = mutableListOf(FusedApp("123"), FusedApp("124"), FusedApp("125")) + val newAppList = mutableListOf(FusedApp("123"), FusedApp("124", status = Status.INSTALLED), FusedApp("125")) + + val oldHomeData = + listOf(FusedHome("Top Free Apps", oldAppList), FusedHome("Top Free Games", oldAppList)) + var newHomeData = + listOf(FusedHome("Top Free Apps", newAppList), FusedHome("Top Free Games", newAppList)) + + homeViewModel.currentHomes = oldHomeData + + val hasAnyChange = homeViewModel.hasAnyChange(newHomeData) + assert(hasAnyChange) + } +} \ No newline at end of file -- GitLab From 49c099b50f435d1986e1439b298426830aeed6dd Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Wed, 1 Nov 2023 19:14:20 +0600 Subject: [PATCH 2/4] refactoring: homepage --- .../java/foundation/e/apps/MainActivity.kt | 4 +- .../e/apps/data/fused/ApplicationApiImpl.kt | 10 +-- .../foundation/e/apps/data/fused/data/Home.kt | 5 +- .../e/apps/install/pkg/PkgManagerModule.kt | 7 +- .../foundation/e/apps/ui/home/HomeFragment.kt | 6 +- .../e/apps/ui/home/HomeViewModel.kt | 67 ++++++++++++++----- .../e/apps/ui/home/model/FusedHomeDiffUtil.kt | 3 +- 7 files changed, 71 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/MainActivity.kt b/app/src/main/java/foundation/e/apps/MainActivity.kt index 5b94937da..a0042b283 100644 --- a/app/src/main/java/foundation/e/apps/MainActivity.kt +++ b/app/src/main/java/foundation/e/apps/MainActivity.kt @@ -40,8 +40,8 @@ import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.login.AuthObject -import foundation.e.apps.data.login.PlayStoreAuthenticator import foundation.e.apps.data.login.LoginViewModel +import foundation.e.apps.data.login.PlayStoreAuthenticator import foundation.e.apps.data.login.exceptions.GPlayValidationException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.databinding.ActivityMainBinding @@ -105,7 +105,7 @@ class MainActivity : AppCompatActivity() { } } - viewModel.setupConnectivityManager(this) + viewModel.setupConnectivityManager(this.applicationContext) viewModel.internetConnection.observe(this) { isInternetAvailable -> hasInternet = isInternetAvailable diff --git a/app/src/main/java/foundation/e/apps/data/fused/ApplicationApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/ApplicationApiImpl.kt index 10633a5e8..597d84ddb 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/ApplicationApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/ApplicationApiImpl.kt @@ -27,16 +27,13 @@ import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.Artwork import com.aurora.gplayapi.data.models.AuthData -import com.aurora.gplayapi.data.models.Category as GplayapiCategory import com.aurora.gplayapi.data.models.SearchBundle import com.aurora.gplayapi.data.models.StreamCluster import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.cleanapk.CleanApkDownloadInfoFetcher -import foundation.e.apps.data.cleanapk.data.app.Application as CleanApkApplication import foundation.e.apps.data.cleanapk.data.categories.Categories -import foundation.e.apps.data.cleanapk.data.home.Home as CleanApkHome import foundation.e.apps.data.cleanapk.data.home.HomeScreen import foundation.e.apps.data.cleanapk.data.search.Search import foundation.e.apps.data.cleanapk.repositories.CleanApkRepository @@ -77,6 +74,9 @@ import timber.log.Timber import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton +import com.aurora.gplayapi.data.models.Category as GplayapiCategory +import foundation.e.apps.data.cleanapk.data.app.Application as CleanApkApplication +import foundation.e.apps.data.cleanapk.data.home.Home as CleanApkHome typealias FusedHomeDeferred = Deferred>> @@ -134,9 +134,11 @@ class ApplicationApiImpl @Inject constructor( resultGplay?.await()?.let { emit(it) } + resultOpenSource?.await()?.let { emit(it) } + resultPWA?.await()?.let { emit(it) } @@ -1311,7 +1313,7 @@ class ApplicationApiImpl @Inject constructor( return@forEach } val currentAppStatus = - pkgManagerModule.getPackageStatus(it.package_name, it.latest_version_code) + getFusedAppInstallationStatus(it) if (it.status != currentAppStatus) { return true } diff --git a/app/src/main/java/foundation/e/apps/data/fused/data/Home.kt b/app/src/main/java/foundation/e/apps/data/fused/data/Home.kt index 8585a07a5..e37b51ef9 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/data/Home.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/data/Home.kt @@ -18,8 +18,11 @@ package foundation.e.apps.data.fused.data +import java.util.UUID + data class Home( val title: String = String(), val list: List = emptyList(), - var source: String = String() + var source: String = String(), + var id: String = UUID.randomUUID().toString() ) diff --git a/app/src/main/java/foundation/e/apps/install/pkg/PkgManagerModule.kt b/app/src/main/java/foundation/e/apps/install/pkg/PkgManagerModule.kt index 46a456351..0365cf1a0 100644 --- a/app/src/main/java/foundation/e/apps/install/pkg/PkgManagerModule.kt +++ b/app/src/main/java/foundation/e/apps/install/pkg/PkgManagerModule.kt @@ -56,7 +56,12 @@ class PkgManagerModule @Inject constructor( fun isInstalled(packageName: String): Boolean { return try { - packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0L)) + } else { + packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA) + } + true } catch (e: PackageManager.NameNotFoundException) { false diff --git a/app/src/main/java/foundation/e/apps/ui/home/HomeFragment.kt b/app/src/main/java/foundation/e/apps/ui/home/HomeFragment.kt index e114bad7c..d9c68f8a4 100644 --- a/app/src/main/java/foundation/e/apps/ui/home/HomeFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/home/HomeFragment.kt @@ -29,11 +29,9 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.R -import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.enums.Status import foundation.e.apps.data.fused.ApplicationInstaller import foundation.e.apps.data.fused.data.Application -import foundation.e.apps.data.fused.data.Home import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.data.login.exceptions.GPlayLoginException @@ -253,9 +251,7 @@ class HomeFragment : TimeoutFragment(R.layout.fragment_home), ApplicationInstall updateProgressOfDownloadingAppItemViews(homeParentRVAdapter, it) } - if (homeViewModel.isAnyAppInstallStatusChanged(homeParentRVAdapter?.currentList)) { - repostAuthObjects() - } + homeViewModel.checkAnyChangeInAppStatus() } override fun onPause() { diff --git a/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt b/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt index 0509eb325..9e99f80c0 100644 --- a/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt @@ -26,7 +26,6 @@ import com.aurora.gplayapi.data.models.AuthData import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.fused.ApplicationRepository -import foundation.e.apps.data.fused.data.Application import foundation.e.apps.data.fused.data.Home import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.exceptions.CleanApkException @@ -34,6 +33,7 @@ import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.ui.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.ui.parentFragment.LoadingViewModel import kotlinx.coroutines.launch +import java.util.UUID import javax.inject.Inject @HiltViewModel @@ -76,15 +76,8 @@ class HomeViewModel @Inject constructor( ) { viewModelScope.launch { applicationRepository.getHomeScreenData(authData).observe(lifecycleOwner) { - homeScreenData.postValue(it) + postHomeResult(it) - if (it.isSuccess() && !hasAnyChange(it.data!!)) { - this@HomeViewModel.currentHomes = it.data - homeScreenData.postValue(ResultSupreme.Error("No change is found!")) - return@observe - } - - homeScreenData.postValue(it) if (it.isSuccess()) { return@observe } @@ -106,15 +99,31 @@ class HomeViewModel @Inject constructor( } } + private fun postHomeResult(homeResult: ResultSupreme>) { + if (shouldUpdateResult(homeResult)) { + homeScreenData.value = homeResult + this@HomeViewModel.currentHomes = homeResult.data?.map { home -> home.copy() } + } else { // homeResult is success, but not change is found + homeScreenData.value = ResultSupreme.Error("No change is found in homepage") + } + } + + private fun shouldUpdateResult(homeResult: ResultSupreme>) = + (homeResult.isSuccess() && hasAnyChange(homeResult.data!!)) || !homeResult.isSuccess() + @VisibleForTesting fun hasAnyChange( newHomes: List, - ) = currentHomes.isNullOrEmpty() || newHomes.size != currentHomes!!.size || compareWithNewData(newHomes) + ) = currentHomes.isNullOrEmpty() || newHomes.size != currentHomes!!.size || compareWithNewData( + newHomes + ) private fun compareWithNewData(newHomes: List): Boolean { currentHomes!!.forEach { val fusedHome = newHomes[currentHomes!!.indexOf(it)] - if (!it.title.contentEquals(fusedHome.title) || areFusedAppsUpdated(it, fusedHome)) { + if (!it.title.contentEquals(fusedHome.title) || it.id.contentEquals(fusedHome.id) + || areFusedAppsUpdated(it, fusedHome) + ) { return true } } @@ -144,13 +153,37 @@ class HomeViewModel @Inject constructor( return false } - fun isAnyAppInstallStatusChanged(currentList: List?): Boolean { - if (currentList == null) { - return false + fun checkAnyChangeInAppStatus() { + if (this.currentHomes == null) { + return } - val appList = mutableListOf() - currentList.forEach { appList.addAll(it.list) } - return applicationRepository.isAnyAppInstallStatusChanged(appList) + val fusedHomes: MutableList = mutableListOf() + checkForChangesInAppStatus(fusedHomes) + + if (fusedHomes.isNotEmpty() && hasAnyChange(fusedHomes)) { + homeScreenData.value = ResultSupreme.Success(fusedHomes) + } + } + + private fun checkForChangesInAppStatus(fusedHomes: MutableList) { + var home: Home? = null + this.currentHomes?.forEach { + + it.list.forEach { application -> + val status = + applicationRepository.getFusedAppInstallationStatus(application) + + if (application.status != status) { + application.status = status + home = it.copy() + // Setting a new id, so that recyclerview can find that this item is changed + home?.id = UUID.randomUUID().toString() + } + } + + fusedHomes.add(home ?: it) + home = null + } } } diff --git a/app/src/main/java/foundation/e/apps/ui/home/model/FusedHomeDiffUtil.kt b/app/src/main/java/foundation/e/apps/ui/home/model/FusedHomeDiffUtil.kt index 2ca4d87b2..e99529198 100644 --- a/app/src/main/java/foundation/e/apps/ui/home/model/FusedHomeDiffUtil.kt +++ b/app/src/main/java/foundation/e/apps/ui/home/model/FusedHomeDiffUtil.kt @@ -27,6 +27,7 @@ class FusedHomeDiffUtil : DiffUtil.ItemCallback() { override fun areContentsTheSame(oldItem: Home, newItem: Home): Boolean { return oldItem.title.contentEquals(newItem.title) && - oldItem.list == newItem.list + oldItem.list == newItem.list && + oldItem.id == newItem.id } } -- GitLab From 6ae3b10c8faf76982987354e0421eb14982f8ed0 Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Thu, 2 Nov 2023 13:06:45 +0600 Subject: [PATCH 3/4] refactor: HomeViewModel --- .../foundation/e/apps/ui/home/HomeViewModel.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt b/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt index 39ce4a81d..b69329943 100644 --- a/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt @@ -41,6 +41,7 @@ class HomeViewModel @Inject constructor( private val applicationRepository: ApplicationRepository, ) : LoadingViewModel() { + /* * Hold list of applications, as well as application source type. * Source type may change from user selected preference in case of timeout. @@ -102,10 +103,12 @@ class HomeViewModel @Inject constructor( private fun postHomeResult(homeResult: ResultSupreme>) { if (shouldUpdateResult(homeResult)) { homeScreenData.value = homeResult - this@HomeViewModel.currentHomes = homeResult.data?.map { home -> home.copy() } - } else { // homeResult is success, but not change is found - homeScreenData.value = ResultSupreme.Error("No change is found in homepage") + currentHomes = homeResult.data?.map { home -> home.copy() } + return } + + // homeResult is success, but not change is found + homeScreenData.value = ResultSupreme.Error("No change is found in homepage") } private fun shouldUpdateResult(homeResult: ResultSupreme>) = @@ -121,7 +124,8 @@ class HomeViewModel @Inject constructor( private fun compareWithNewData(newHomes: List): Boolean { currentHomes!!.forEach { val fusedHome = newHomes[currentHomes!!.indexOf(it)] - if (!it.title.contentEquals(fusedHome.title) || it.id.contentEquals(fusedHome.id) + + if (!it.title.contentEquals(fusedHome.title) || !it.id.contentEquals(fusedHome.id) || areFusedAppsUpdated(it, fusedHome) ) { return true @@ -145,6 +149,7 @@ class HomeViewModel @Inject constructor( oldHome.list.forEach { oldFusedApp -> val indexOfOldFusedApp = oldHome.list.indexOf(oldFusedApp) val fusedApp = newHome.list[indexOfOldFusedApp] + if (!fusedAppDiffUtil.areContentsTheSame(oldFusedApp, fusedApp)) { return true } @@ -163,6 +168,7 @@ class HomeViewModel @Inject constructor( if (fusedHomes.isNotEmpty() && hasAnyChange(fusedHomes)) { homeScreenData.value = ResultSupreme.Success(fusedHomes) + currentHomes = fusedHomes } } -- GitLab From 38e2e5063e0f3fa846cf713de5018b9f4942d6df Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Thu, 2 Nov 2023 13:23:14 +0600 Subject: [PATCH 4/4] fixed: unit test and minor refactor --- .../java/foundation/e/apps/ui/home/HomeViewModel.kt | 5 ++--- .../java/foundation/e/apps/home/HomeViewModelTest.kt | 12 ++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt b/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt index b69329943..c7261da58 100644 --- a/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/home/HomeViewModel.kt @@ -103,11 +103,10 @@ class HomeViewModel @Inject constructor( private fun postHomeResult(homeResult: ResultSupreme>) { if (shouldUpdateResult(homeResult)) { homeScreenData.value = homeResult - currentHomes = homeResult.data?.map { home -> home.copy() } + currentHomes = homeResult.data return } - // homeResult is success, but not change is found homeScreenData.value = ResultSupreme.Error("No change is found in homepage") } @@ -122,7 +121,7 @@ class HomeViewModel @Inject constructor( ) private fun compareWithNewData(newHomes: List): Boolean { - currentHomes!!.forEach { + currentHomes?.forEach { val fusedHome = newHomes[currentHomes!!.indexOf(it)] if (!it.title.contentEquals(fusedHome.title) || !it.id.contentEquals(fusedHome.id) diff --git a/app/src/test/java/foundation/e/apps/home/HomeViewModelTest.kt b/app/src/test/java/foundation/e/apps/home/HomeViewModelTest.kt index 2727608c5..7930a3b48 100644 --- a/app/src/test/java/foundation/e/apps/home/HomeViewModelTest.kt +++ b/app/src/test/java/foundation/e/apps/home/HomeViewModelTest.kt @@ -48,9 +48,9 @@ class HomeViewModelTest { val newAppList = mutableListOf(Application("123"), Application("124")) val oldHomeData = - listOf(Home("Top Free Apps", oldAppList), Home("Top Free Games", oldAppList)) + listOf(Home("Top Free Apps", oldAppList, id = "123"), Home("Top Free Games", oldAppList, id = "124")) var newHomeData = - listOf(Home("Top Free Apps", newAppList), Home("Top Free Games", newAppList)) + listOf(Home("Top Free Apps", newAppList, id = "123"), Home("Top Free Games", newAppList, id = "124")) homeViewModel.currentHomes = oldHomeData @@ -64,9 +64,9 @@ class HomeViewModelTest { val newAppList = mutableListOf(Application("123"), Application("124"), Application("125")) val oldHomeData = - listOf(Home("Top Free Apps", oldAppList), Home("Top Free Games", oldAppList)) + listOf(Home("Top Free Apps", oldAppList, id = "123"), Home("Top Free Games", oldAppList, id = "124")) var newHomeData = - listOf(Home("Top Free Apps", newAppList), Home("Top Free Games", newAppList)) + listOf(Home("Top Free Apps", newAppList, id = "123"), Home("Top Free Games", newAppList, id = "124")) homeViewModel.currentHomes = oldHomeData @@ -80,9 +80,9 @@ class HomeViewModelTest { val newAppList = mutableListOf(Application("123"), Application("124", status = Status.INSTALLED), Application("125")) val oldHomeData = - listOf(Home("Top Free Apps", oldAppList), Home("Top Free Games", oldAppList)) + listOf(Home("Top Free Apps", oldAppList, id = "123"), Home("Top Free Games", oldAppList, id = "124")) var newHomeData = - listOf(Home("Top Free Apps", newAppList), Home("Top Free Games", newAppList)) + listOf(Home("Top Free Apps", newAppList, id = "123"), Home("Top Free Games", newAppList, id = "124")) homeViewModel.currentHomes = oldHomeData -- GitLab