From b490e68038109b48e7a006d7090a1ca97144f03b Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Sat, 10 Sep 2022 09:53:19 +0600 Subject: [PATCH 1/2] user is forced to select at least one app source --- .../java/foundation/e/apps/MainActivity.kt | 20 ++++++++++++++++++- .../e/apps/settings/SettingsFragment.kt | 13 ++++++++---- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-fi/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values/strings.xml | 3 ++- app/src/main/res/xml/settings_preferences.xml | 2 +- 9 files changed, 36 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/MainActivity.kt b/app/src/main/java/foundation/e/apps/MainActivity.kt index c58ac6990..a47e83fa3 100644 --- a/app/src/main/java/foundation/e/apps/MainActivity.kt +++ b/app/src/main/java/foundation/e/apps/MainActivity.kt @@ -32,6 +32,7 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.NavOptions import androidx.navigation.findNavController import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.NavigationUI import androidx.navigation.ui.setupWithNavController import com.aurora.gplayapi.exceptions.ApiException import com.google.android.material.snackbar.Snackbar @@ -41,6 +42,7 @@ import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.workmanager.InstallWorkManager import foundation.e.apps.purchase.AppPurchaseFragmentDirections +import foundation.e.apps.settings.SettingsFragment import foundation.e.apps.setup.signin.SignInViewModel import foundation.e.apps.updates.UpdatesNotifier import foundation.e.apps.utils.enums.Status @@ -73,6 +75,23 @@ class MainActivity : AppCompatActivity() { supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment val navController = navHostFragment.navController bottomNavigationView.setupWithNavController(navController) + bottomNavigationView.setOnItemSelectedListener { + val fragment = + navHostFragment.childFragmentManager.fragments.find { fragment -> fragment is SettingsFragment } + if (bottomNavigationView.selectedItemId == R.id.settingsFragment && fragment is SettingsFragment && !fragment.isAnyAppSourceSelected()) { + ApplicationDialogFragment( + title = "", + message = getString(R.string.select_one_source_of_applications), + positiveButtonText = getString(R.string.ok) + ).show(supportFragmentManager, TAG) + return@setOnItemSelectedListener false + } + + return@setOnItemSelectedListener NavigationUI.onNavDestinationSelected( + it, + navController + ) + } var hasInternet = true @@ -135,7 +154,6 @@ class MainActivity : AppCompatActivity() { if (!hasInternet) { showNoInternet() } - when (destination.id) { R.id.applicationFragment, R.id.applicationListFragment, diff --git a/app/src/main/java/foundation/e/apps/settings/SettingsFragment.kt b/app/src/main/java/foundation/e/apps/settings/SettingsFragment.kt index 07d928161..18cbb4164 100644 --- a/app/src/main/java/foundation/e/apps/settings/SettingsFragment.kt +++ b/app/src/main/java/foundation/e/apps/settings/SettingsFragment.kt @@ -55,6 +55,9 @@ class SettingsFragment : PreferenceFragmentCompat() { private val binding get() = _binding!! private val viewModel: SignInViewModel by viewModels() private val mainActivityViewModel: MainActivityViewModel by viewModels() + private var showAllApplications: CheckBoxPreference? = null + private var showFOSSApplications: CheckBoxPreference? = null + private var showPWAApplications: CheckBoxPreference? = null @Inject lateinit var gson: Gson @@ -70,10 +73,9 @@ class SettingsFragment : PreferenceFragmentCompat() { setPreferencesFromResource(R.xml.settings_preferences, rootKey) // Show applications preferences - val showAllApplications = findPreference("showAllApplications") - val showFOSSApplications = findPreference("showFOSSApplications") - val showPWAApplications = findPreference("showPWAApplications") - + showAllApplications = findPreference("showAllApplications") + showFOSSApplications = findPreference("showFOSSApplications") + showPWAApplications = findPreference("showPWAApplications") val updateCheckInterval = preferenceManager.findPreference(getString(R.string.update_check_intervals)) updateCheckInterval?.setOnPreferenceChangeListener { _, newValue -> @@ -149,6 +151,9 @@ class SettingsFragment : PreferenceFragmentCompat() { } } + fun isAnyAppSourceSelected() = + showAllApplications?.isChecked == true || showFOSSApplications?.isChecked == true || showPWAApplications?.isChecked == true + private fun backToMainActivity() { Intent(context, MainActivity::class.java).also { activity?.finish() diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 01ca821bc..01884f499 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -24,7 +24,7 @@ Benachrichtige, wenn App-Aktualisierungen verfügbar sind Zeige Anwendungen: Zeige nur quelloffene Apps an - Zeige alle Apps an + Zeige alle Apps an Zeige nur PWAs an Konto Nutzungsbedingungen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 56deca22e..e3322571c 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -36,7 +36,7 @@ Descargar e instalar actualizaciones de aplicaciones en segundo plano Mostrar aplicaciones disponibles Mostrar aplicaciones: - Mostrar todas las aplicaciones + Mostrar todas las aplicaciones Mostrar solo aplicaciones de código abierto Mostrar solo las PWA Cuenta diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index eadc7654c..bbfff2eee 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -43,7 +43,7 @@ Tili Näytä vain PWAt Näytä vain avoimen lähdekoodin sovellukset - Näytä kaikki sovellukset + Näytä kaikki sovellukset Näytä sovellukset: Näytä ilmoitus kun sovelluspäivityksiä on saatavilla Näytä saatavilla olevat päivitykset diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 76ae8d20f..488796282 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -17,7 +17,7 @@ Afficher les mises à jour disponibles Afficher une notification lorsque des mises à jour d\'applications sont disponibles Afficher les applications : - Afficher toutes les applications + Afficher toutes les applications Afficher les PWA uniquement Compte Conditions de Service diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 84af82df7..73b2157e6 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -36,7 +36,7 @@ Scarica ed installa gli aggiornamenti App in background Mostra gli aggiornamenti disponibili Mostra App: - Mostra tutte le App + Mostra tutte le App Mostra solo le App open-source Mostra solo le PWA Account diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ae79a3226..749335013 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,7 +61,7 @@ Show available updates Show a notification when app updates are available Show applications: - Show all apps + Show commercial apps Show only open-source apps Show only PWAs About @@ -191,5 +191,6 @@ Install anyway This app may not work properly! Forcing installation will allow you to download and install it, but it won\'t guarantee that it will work.<br /><br />Attempting to install unsupported apps may cause crashes or slow down the system.<br /><br />We\'re working on improving compatiblity with this application in a near future. + Please select at least one source of applications. diff --git a/app/src/main/res/xml/settings_preferences.xml b/app/src/main/res/xml/settings_preferences.xml index 28d6968b5..ecb810540 100644 --- a/app/src/main/res/xml/settings_preferences.xml +++ b/app/src/main/res/xml/settings_preferences.xml @@ -56,7 +56,7 @@ + android:title="@string/Show_commercial_apps" /> Date: Sun, 11 Sep 2022 10:24:28 +0600 Subject: [PATCH 2/2] home page header & string resource of app source in settings are updated --- .../java/foundation/e/apps/MainActivity.kt | 44 ++++++++++++------- .../e/apps/api/fused/FusedAPIImpl.kt | 2 +- .../e/apps/home/model/HomeParentRVAdapter.kt | 16 ------- .../main/res/layout/home_parent_list_item.xml | 22 +--------- app/src/main/res/values/strings.xml | 17 +++---- .../foundation/e/apps/FusedApiImplTest.kt | 29 +++++------- .../e/apps/util/LiveDataTestUtil.kt | 25 +++-------- 7 files changed, 55 insertions(+), 100 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/MainActivity.kt b/app/src/main/java/foundation/e/apps/MainActivity.kt index a47e83fa3..4c023ae44 100644 --- a/app/src/main/java/foundation/e/apps/MainActivity.kt +++ b/app/src/main/java/foundation/e/apps/MainActivity.kt @@ -29,12 +29,14 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope +import androidx.navigation.NavController import androidx.navigation.NavOptions import androidx.navigation.findNavController import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.NavigationUI import androidx.navigation.ui.setupWithNavController import com.aurora.gplayapi.exceptions.ApiException +import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.application.subFrags.ApplicationDialogFragment @@ -75,23 +77,7 @@ class MainActivity : AppCompatActivity() { supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment val navController = navHostFragment.navController bottomNavigationView.setupWithNavController(navController) - bottomNavigationView.setOnItemSelectedListener { - val fragment = - navHostFragment.childFragmentManager.fragments.find { fragment -> fragment is SettingsFragment } - if (bottomNavigationView.selectedItemId == R.id.settingsFragment && fragment is SettingsFragment && !fragment.isAnyAppSourceSelected()) { - ApplicationDialogFragment( - title = "", - message = getString(R.string.select_one_source_of_applications), - positiveButtonText = getString(R.string.ok) - ).show(supportFragmentManager, TAG) - return@setOnItemSelectedListener false - } - - return@setOnItemSelectedListener NavigationUI.onNavDestinationSelected( - it, - navController - ) - } + setupBottomNavItemSelectedListener(bottomNavigationView, navHostFragment, navController) var hasInternet = true @@ -241,6 +227,30 @@ class MainActivity : AppCompatActivity() { } } + private fun setupBottomNavItemSelectedListener( + bottomNavigationView: BottomNavigationView, + navHostFragment: NavHostFragment, + navController: NavController + ) { + bottomNavigationView.setOnItemSelectedListener { + val fragment = + navHostFragment.childFragmentManager.fragments.find { fragment -> fragment is SettingsFragment } + if (bottomNavigationView.selectedItemId == R.id.settingsFragment && fragment is SettingsFragment && !fragment.isAnyAppSourceSelected()) { + ApplicationDialogFragment( + title = "", + message = getString(R.string.select_one_source_of_applications), + positiveButtonText = getString(R.string.ok) + ).show(supportFragmentManager, TAG) + return@setOnItemSelectedListener false + } + + return@setOnItemSelectedListener NavigationUI.onNavDestinationSelected( + it, + navController + ) + } + } + private fun handleFusedDownloadQueued( it: FusedDownload, viewModel: MainActivityViewModel diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 0736a4af3..5f6d9c092 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -1224,7 +1224,7 @@ class FusedAPIImpl @Inject constructor( mapOf( "popular_apps" to context.getString(R.string.popular_apps), "popular_games" to context.getString(R.string.popular_games), - "discover" to context.getString(R.string.discover) + "discover" to context.getString(R.string.discover_pwa) ) } headings.forEach { (key, value) -> diff --git a/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt b/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt index 6dd0bf001..76b4638dd 100644 --- a/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt @@ -19,7 +19,6 @@ package foundation.e.apps.home.model import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.LinearLayoutManager @@ -27,8 +26,6 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.MainActivityViewModel -import foundation.e.apps.R -import foundation.e.apps.api.fused.FusedAPIImpl import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.fused.data.FusedHome @@ -74,19 +71,6 @@ class HomeParentRVAdapter( holder.binding.titleTV.text = fusedHome.title - when (fusedHome.source) { - FusedAPIImpl.APP_TYPE_OPEN -> { - holder.binding.categoryTag.visibility = View.VISIBLE - holder.binding.categoryTag.text = holder.binding.root.context.getString(R.string.open_source) - } - FusedAPIImpl.APP_TYPE_PWA -> { - holder.binding.categoryTag.visibility = View.VISIBLE - holder.binding.categoryTag.text = holder.binding.root.context.getString(R.string.pwa) - } - else -> { - holder.binding.categoryTag.visibility = View.GONE - } - } holder.binding.childRV.apply { recycledViewPool.setMaxRecycledViews(0, 0) adapter = homeChildRVAdapter diff --git a/app/src/main/res/layout/home_parent_list_item.xml b/app/src/main/res/layout/home_parent_list_item.xml index 5ecf01ecc..bcb362ac8 100644 --- a/app/src/main/res/layout/home_parent_list_item.xml +++ b/app/src/main/res/layout/home_parent_list_item.xml @@ -36,27 +36,7 @@ android:paddingEnd="10dp" android:textColor="?android:textColorPrimary" android:textSize="18sp" - android:textStyle="bold" - android:ellipsize="end" - android:lines="1" - android:layout_toStartOf="@id/categoryTag"/> - - + android:textStyle="bold" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 749335013..0c4f999c3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -62,8 +62,8 @@ Show a notification when app updates are available Show applications: Show commercial apps - Show only open-source apps - Show only PWAs + Show open source apps + Show PWAs About App Lounge version /e/ OS version @@ -127,12 +127,13 @@ Discover - Top Updated Apps - Top Updated Games - Popular Apps In Last 24 Hours - Popular Games In Last 24 Hours - Popular Apps - Popular Games + Discover PWA + Open Source Top Updated Apps + Open Source Top Updated Games + Open Source Popular Apps In Last 24 Hours + Open Source Popular Games In Last 24 Hours + PWA Popular Apps + PWA Popular Games Top Free Apps Top Free Games diff --git a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt index 474bf05a2..8400436f4 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt @@ -21,12 +21,10 @@ import android.content.Context import android.text.format.Formatter import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.Observer import com.aurora.gplayapi.Constants import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Category -import foundation.e.apps.api.ResultSupreme import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories @@ -37,13 +35,13 @@ import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.api.gplay.GPlayAPIRepository import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.util.MainCoroutineRule +import foundation.e.apps.util.getOrAwaitValue import foundation.e.apps.utils.enums.FilterLevel import foundation.e.apps.utils.enums.Origin import foundation.e.apps.utils.enums.ResultStatus import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.modules.PWAManagerModule import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -741,34 +739,27 @@ class FusedApiImplTest { latest_version_code = 123 ) ) - val searchResult = Search(apps = appList, numberOfResults = 3, success = true) + val searchResult = Search(apps = appList, numberOfResults = 1, success = true) val packageNameSearchResponse = Response.success(searchResult) - val packageResult = App("com.search.package") + val gplayPackageResult = App("com.search.package") preferenceManagerModule.isPWASelectedFake = true preferenceManagerModule.isOpenSourceelectedFake = true preferenceManagerModule.isGplaySelectedFake = true val gplayLivedata = - MutableLiveData(Pair(listOf(App("a.b.c"), App("c.d.e"), App("d.e.f")), false)) + MutableLiveData(Pair(listOf(App("a.b.c"), App("c.d.e"), App("d.e.f"), App("d.e.g")), false)) - setupMockingSearchApp(packageNameSearchResponse, authData, packageResult, gplayLivedata) + setupMockingSearchApp(packageNameSearchResponse, authData, gplayPackageResult, gplayLivedata) - val searchResultLiveData = fusedAPIImpl.getSearchResults("com.search.package", authData) - var size = -1 - val observer = Observer, Boolean>>> { - size = it.data?.first?.size ?: -2 - println("search result: $size") - } - searchResultLiveData.observeForever(observer) - delay(3000) - searchResultLiveData.removeObserver(observer) - assertEquals("getSearchResult", 1, size) + val searchResultLiveData = fusedAPIImpl.getSearchResults("com.search.package", authData).getOrAwaitValue() + val size = searchResultLiveData.data?.first?.size ?: -2 + assertEquals("getSearchResult", 8, size) } private suspend fun setupMockingSearchApp( packageNameSearchResponse: Response?, authData: AuthData, - packageResult: App, + gplayPackageResult: App, gplayLivedata: MutableLiveData, Boolean>> ) { Mockito.`when`(pwaManagerModule.getPwaStatus(any())).thenReturn(Status.UNAVAILABLE) @@ -784,7 +775,7 @@ class FusedApiImplTest { formatterMocked.`when` { Formatter.formatFileSize(any(), any()) }.thenReturn("15MB") Mockito.`when`(gPlayAPIRepository.getAppDetails(eq("com.search.package"), eq(authData))) - .thenReturn(packageResult) + .thenReturn(gplayPackageResult) Mockito.`when`(cleanApkRepository.searchApps(keyword = "com.search.package")) .thenReturn(packageNameSearchResponse) diff --git a/app/src/test/java/foundation/e/apps/util/LiveDataTestUtil.kt b/app/src/test/java/foundation/e/apps/util/LiveDataTestUtil.kt index a28ada765..679cc04e2 100644 --- a/app/src/test/java/foundation/e/apps/util/LiveDataTestUtil.kt +++ b/app/src/test/java/foundation/e/apps/util/LiveDataTestUtil.kt @@ -19,9 +19,9 @@ package foundation.e.apps.util import androidx.lifecycle.LiveData import androidx.lifecycle.Observer +import kotlinx.coroutines.delay import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit -import java.util.concurrent.TimeoutException /** * Gets the value of a [LiveData] or waits for it to have one, with a timeout. @@ -29,30 +29,19 @@ import java.util.concurrent.TimeoutException * Use this extension from host-side (JVM) tests. It's recommended to use it alongside * `InstantTaskExecutorRule` or a similar mechanism to execute tasks synchronously. */ -fun LiveData.getOrAwaitValue( +suspend fun LiveData.getOrAwaitValue( time: Long = 5, - timeUnit: TimeUnit = TimeUnit.SECONDS, afterObserve: () -> Unit = {} ): T { var data: T? = null - val latch = CountDownLatch(1) - val observer = object : Observer { - override fun onChanged(o: T?) { - data = o - latch.countDown() - this@getOrAwaitValue.removeObserver(this) - } + val observer = Observer { o -> + data = o + print("onChanged: $o") } this.observeForever(observer) - afterObserve.invoke() - - // Don't wait indefinitely if the LiveData is not set. - if (!latch.await(time, timeUnit)) { - this.removeObserver(observer) - throw TimeoutException("LiveData value was never set.") - } - + delay(time * 1000) + this.removeObserver(observer) @Suppress("UNCHECKED_CAST") return data as T } -- GitLab