From fdd3e3b685b50f8028355b360d7163cbfde73d2f Mon Sep 17 00:00:00 2001 From: dev-12 Date: Tue, 18 Nov 2025 14:11:29 +0530 Subject: [PATCH 1/2] fix: prevent purchase screen trigger for restricted apps Previously, when an app was unavailable due to age verification, minimum age requirements, or geo-restrictions, the API returned a purchase needed error. This misleading error code caused App Lounge to open the purchase screen, even for free apps or apps where payment was not the issue --- .../workmanager/AppInstallProcessor.kt | 21 ++++++++++++---- .../java/foundation/e/apps/ui/MainActivity.kt | 14 +++++++++++ .../e/apps/ui/error/AppUnavailableDialog.kt | 24 +++++++++++++++++++ .../e/apps/utils/eventBus/AppEvent.kt | 1 + .../res/navigation/navigation_resource.xml | 12 ++++++++++ app/src/main/res/values/strings.xml | 3 +++ 6 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/ui/error/AppUnavailableDialog.kt diff --git a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt index ea6df6cbf..c4e7ea8b1 100644 --- a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt +++ b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt @@ -23,16 +23,16 @@ import com.aurora.gplayapi.exceptions.InternalException import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.ResultSupreme -import foundation.e.apps.data.enums.ResultStatus -import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.enums.Type import foundation.e.apps.data.application.ApplicationRepository import foundation.e.apps.data.application.UpdatesDao import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Source +import foundation.e.apps.data.enums.Status +import foundation.e.apps.data.enums.Type import foundation.e.apps.data.enums.User +import foundation.e.apps.data.install.AppManager import foundation.e.apps.data.install.models.AppInstall -import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.playstore.utils.GplayHttpRequestException import foundation.e.apps.data.preference.AppLoungeDataStore import foundation.e.apps.domain.ValidateAppAgeLimitUseCase @@ -67,6 +67,9 @@ class AppInstallProcessor @Inject constructor( @Inject lateinit var downloadManager: DownloadManagerUtils + @Inject + lateinit var appManager: AppManager + private var isItUpdateWork = false companion object { @@ -202,6 +205,10 @@ class AppInstallProcessor @Inject constructor( try { updateFusedDownloadWithAppDownloadLink(appInstall) } catch (e: InternalException.AppNotPurchased) { + if (appInstall.isFree) { + handleAppRestricted(appInstall) + return false + } appInstallComponents.appManagerWrapper.addFusedDownloadPurchaseNeeded(appInstall) EventBus.invokeEvent(AppEvent.AppPurchaseEvent(appInstall)) return false @@ -225,6 +232,12 @@ class AppInstallProcessor @Inject constructor( return true } + private suspend fun handleAppRestricted(appInstall: AppInstall) { + EventBus.invokeEvent(AppEvent.AppRestrictedOrUnavailable(appInstall)) + appManager.addDownload(appInstall) + appManager.updateUnavailable(appInstall) + } + private suspend fun handleUpdateDownloadError( appInstall: AppInstall, message: String, diff --git a/app/src/main/java/foundation/e/apps/ui/MainActivity.kt b/app/src/main/java/foundation/e/apps/ui/MainActivity.kt index d1453ea05..c543c5865 100644 --- a/app/src/main/java/foundation/e/apps/ui/MainActivity.kt +++ b/app/src/main/java/foundation/e/apps/ui/MainActivity.kt @@ -56,6 +56,7 @@ import foundation.e.apps.data.login.exceptions.GPlayValidationException import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.install.updates.UpdatesNotifier import foundation.e.apps.ui.application.subFrags.ApplicationDialogFragment +import foundation.e.apps.ui.error.AppUnavailableDialogDirections import foundation.e.apps.ui.purchase.AppPurchaseFragmentDirections import foundation.e.apps.ui.settings.SettingsFragment import foundation.e.apps.ui.setup.signin.SignInViewModel @@ -227,6 +228,10 @@ class MainActivity : AppCompatActivity() { observeInvalidAuth() } + launch { + observeAppUnavailable() + } + launch { observeTooManyRequests() } @@ -508,6 +513,15 @@ class MainActivity : AppCompatActivity() { } } + private suspend fun observeAppUnavailable() { + EventBus.events.filterIsInstance() + .collectLatest { event -> + val appName = event.appInstall.name + val action = AppUnavailableDialogDirections.actionGlobalAppUnavailable(appName) + findNavController(R.id.fragment).navigate(action) + } + } + private fun validatedAuthObject(appEvent: AppEvent) { val data = appEvent.data as String if (data.isNotBlank()) { diff --git a/app/src/main/java/foundation/e/apps/ui/error/AppUnavailableDialog.kt b/app/src/main/java/foundation/e/apps/ui/error/AppUnavailableDialog.kt new file mode 100644 index 000000000..ebe1ace6d --- /dev/null +++ b/app/src/main/java/foundation/e/apps/ui/error/AppUnavailableDialog.kt @@ -0,0 +1,24 @@ +package foundation.e.apps.ui.error + +import android.app.Dialog +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import foundation.e.apps.R + +class AppUnavailableDialog : DialogFragment() { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.app_unavailable_title) + .setMessage(R.string.app_unavailable_description) + .setCancelable(false) + .setPositiveButton( + android.R.string.ok, + { dialog, _ -> + dialog.dismiss() + } + ) + .create() + } +} diff --git a/app/src/main/java/foundation/e/apps/utils/eventBus/AppEvent.kt b/app/src/main/java/foundation/e/apps/utils/eventBus/AppEvent.kt index c7ca28c07..d3097d45e 100644 --- a/app/src/main/java/foundation/e/apps/utils/eventBus/AppEvent.kt +++ b/app/src/main/java/foundation/e/apps/utils/eventBus/AppEvent.kt @@ -34,6 +34,7 @@ sealed class AppEvent(val data: Any) { class ErrorMessageEvent(stringResourceId: Int) : AppEvent(stringResourceId) class ErrorMessageDialogEvent(stringResourceId: Int) : AppEvent(stringResourceId) class AppPurchaseEvent(appInstall: AppInstall) : AppEvent(appInstall) + class AppRestrictedOrUnavailable(val appInstall: AppInstall) : AppEvent(appInstall) class NoInternetEvent(isInternetAvailable: Boolean) : AppEvent(isInternetAvailable) class TooManyRequests : AppEvent(Unit) class AgeLimitRestrictionEvent( diff --git a/app/src/main/res/navigation/navigation_resource.xml b/app/src/main/res/navigation/navigation_resource.xml index 330939045..774666361 100644 --- a/app/src/main/res/navigation/navigation_resource.xml +++ b/app/src/main/res/navigation/navigation_resource.xml @@ -252,4 +252,16 @@ android:id="@+id/action_global_appPurchaseFragment" app:destination="@id/appPurchaseFragment" /> + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 80132cd98..b128a2bad 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -230,4 +230,7 @@ An error occurred while loading Common apps. Only Open Source apps and PWA are available for now. An error occurred while loading PWA and Open Source apps. Only Common apps are available for now. + + App Unavailable + This app is not available for installation. This is typically due to content restrictions based on your location (region) or your account\'s age settings (including age verification and age/content rating) -- GitLab From 7896d508beb3f899a30b284cd20c3650c0934085 Mon Sep 17 00:00:00 2001 From: dev-12 Date: Wed, 19 Nov 2025 13:35:54 +0530 Subject: [PATCH 2/2] add French, German, Italian, and Spanish translations --- app/src/main/res/values-de/strings.xml | 4 ++++ app/src/main/res/values-es/strings.xml | 4 ++++ app/src/main/res/values-fr/strings.xml | 4 ++++ app/src/main/res/values-it/strings.xml | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 0b4a06dd6..fa8ab59ab 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -196,4 +196,8 @@ Quelloffene Apps und PWA nicht verfügbar Beim Laden der allgemeinen Apps ist ein Fehler aufgetreten. Nur quelloffene Apps und PWA sind momentan verfügbar. Beim Laden von PWA und quelloffenen Apps ist ein Fehler aufgetreten. Nur allgemeine Apps sind momentan verfügbar. + + + App nicht verfügbar + Diese App kann nicht installiert werden. Dies liegt in der Regel an Inhaltsbeschränkungen basierend auf Ihrem Standort (Region) oder den Alterseinstellungen Ihres Kontos (einschließlich Altersüberprüfung und Alters-/Inhaltsfreigabe). diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 9e85cd5ca..97c5da93b 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -197,4 +197,8 @@ Hubo un error al cargar las aplicaciones PWA y de código abierto. Solo aplicaciones comunes están disponibles por ahora. App Lounge se cerrará durante la instalación de la actualización. Por favor, abstente de hacer nada en hasta que la actualización (descarga + instalación) haya terminado. Podrás usarla en un par de minutos como máximo. ¡Advertencia de actualización! + + + Aplicación no disponible + Esta aplicación no está disponible para su instalación. Esto se debe generalmente a restricciones de contenido basadas en tu ubicación (región) o en la configuración de edad de tu cuenta (incluida la verificación de edad y la clasificación por edad/contenido). diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 622fffdb4..5f3f5dba1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -196,4 +196,8 @@ Une erreur est survenue lors du chargement des applications communes. Seules les applications Open Source et PWA sont disponibles pour l’instant. Une erreur est survenue lors du chargement des applications PWA et Open Source. Seules les applications communes sont disponibles pour l\'instant. App Lounge sera fermé pendant l\'installation de la mise à jour. Veuillez ne rien faire tant que la mise à jour (téléchargement + installation) n\'est pas terminée. Vous pourrez y accéder dans quelques minutes au maximum. + + + Application indisponible + Cette application n\'est pas disponible à l\'installation. Cela est généralement dû à des restrictions de contenu basées sur votre emplacement (région) ou les paramètres d\'âge de votre compte (y compris la vérification de l\'âge et la classification par âge/contenu). \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 04a0c11a7..5570e503e 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -197,4 +197,8 @@ Si è verificato un errore durante il caricamento delle app PWA e Open Source. Solo le app comuni sono disponibili per ora. Sto raccogliendo la valutazione di tutte le app che hai installato. L\'applicazione potrebbe contenere nudità, bestemmie, insulti, violenza, estrema sessualità, politicamente scorretto o altri argomenti potenzialmente disturbanti. Questo è rilevante specialmente in ambienti tipo lavoro, scuola, ambienti religiosi e familiari. + + + App non disponibile + Questa app non è disponibile per l\'installazione. Ciò è generalmente dovuto a restrizioni di contenuto basate sulla tua posizione (regione) o sulle impostazioni di età del tuo account (incluse verifica dell\'età e classificazione per età/contenuto). -- GitLab