Loading app/src/main/java/foundation/e/apps/data/EnabledSourceState.kt +10 −3 Original line number Diff line number Diff line Loading @@ -31,8 +31,10 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.launch import javax.inject.Inject import javax.inject.Singleton Loading @@ -58,6 +60,12 @@ class EnabledSourceState @Inject constructor( private val _enabledSourcesFlow = MutableStateFlow(emptySet<Source>()) val enabledSourcesFlow: StateFlow<Set<Source>> = _enabledSourcesFlow.asStateFlow() private val _hasHydratedCapabilities = MutableStateFlow(false) val hydratedEnabledSourcesFlow: Flow<Set<Source>> = combine(enabledSourcesFlow, _hasHydratedCapabilities) { enabledSources, hasHydrated -> enabledSources.takeIf { hasHydrated } } .filterNotNull() .distinctUntilChanged() init { coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) { Loading Loading @@ -130,8 +138,7 @@ class EnabledSourceState @Inject constructor( } internal fun EnabledSourceState.enabledStoreChanges(): Flow<Set<Source>> = enabledSourcesFlow .filter { hasHydratedCapabilities } hydratedEnabledSourcesFlow .drop(1) internal fun Source.isAccessible(capabilities: UserCapabilities): Boolean { Loading app/src/main/java/foundation/e/apps/data/application/category/CategoryApiImpl.kt +14 −2 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Source import foundation.e.apps.data.enums.isUnFiltered import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.playstore.PlayStoreRepository import javax.inject.Inject class CategoryApiImpl @Inject constructor( Loading Loading @@ -86,9 +87,14 @@ class CategoryApiImpl @Inject constructor( private suspend fun fetchGplayCategories( type: CategoryType, ): Pair<List<Category>, ResultStatus> { val playStoreRepository = awaitPlayStoreRepository() ?: return Pair( emptyList(), ResultStatus.UNKNOWN.apply { message = "Play Store unavailable" }, ) val categoryList = mutableListOf<Category>() val result = handleNetworkResult { val playResponse = appSources.gplayRepo.getCategories(type).map { gplayCategory -> val playResponse = playStoreRepository.getCategories(type).map { gplayCategory -> val category = gplayCategory.toCategory() category.drawable = CategoryUtils.provideAppsCategoryIconResource( Loading Loading @@ -154,9 +160,11 @@ class CategoryApiImpl @Inject constructor( category: String, pageUrl: String? ): ResultSupreme<Pair<List<Application>, String>> { val playStoreRepository = awaitPlayStoreRepository() ?: return ResultSupreme.Error("Play Store unavailable") return handleNetworkResult { val cluster = appSources.gplayRepo.getAppsByCategory(category, pageUrl) playStoreRepository.getAppsByCategory(category, pageUrl) val filteredApps = filterRestrictedGPlayApps(cluster.clusterAppList) val applications = (filteredApps.data ?: emptyList()).toMutableList() Loading Loading @@ -232,4 +240,8 @@ class CategoryApiImpl @Inject constructor( else -> null } private suspend fun awaitPlayStoreRepository(): PlayStoreRepository? { return enabledStoreRepositoryProvider.awaitStore(Source.PLAY_STORE) as? PlayStoreRepository } } app/src/main/java/foundation/e/apps/feature/auth/login/SignInFragment.kt +6 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ class SignInFragment : Fragment() { }, onError = ::showErrorDialog, ) systemWideGoogleLoginLauncher.restore(savedInstanceState) requireActivity().onBackPressedDispatcher.addCallback( this, object : OnBackPressedCallback(true) { Loading Loading @@ -118,6 +119,11 @@ class SignInFragment : Fragment() { dialogState = null } override fun onSaveInstanceState(outState: Bundle) { systemWideGoogleLoginLauncher.save(outState) super.onSaveInstanceState(outState) } private fun navigateToGoogleSignInFragment(): Boolean { return findNavController().safeNavigate( R.id.signInFragment, Loading app/src/main/java/foundation/e/apps/feature/auth/login/SystemWideGoogleLoginCoordinator.kt +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,12 @@ package foundation.e.apps.feature.auth.login internal class SystemWideGoogleLoginCoordinator { private var pendingAccountName: String? = null fun snapshotPendingAccountName(): String? = pendingAccountName fun restorePendingAccountName(accountName: String?) { pendingAccountName = accountName?.takeIf { it.isNotBlank() } } fun start( hasSupportedMicrog: Boolean, hasMicrogAccount: Boolean, Loading app/src/main/java/foundation/e/apps/feature/auth/login/SystemWideGoogleLoginLauncher.kt +25 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ package foundation.e.apps.feature.auth.login import android.accounts.AccountManager import android.app.Activity import android.content.Intent import android.os.Bundle import androidx.activity.result.contract.ActivityResultContracts import androidx.core.os.BundleCompat import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import foundation.e.apps.R Loading @@ -36,6 +38,11 @@ class SystemWideGoogleLoginLauncher( private val onCredentialsReady: (String, String) -> Unit, private val onError: (String) -> Unit, ) { companion object { private const val KEY_PENDING_ACCOUNT_NAME = "system_wide_google_login_pending_account_name" private const val KEY_PENDING_CONSENT_INTENT = "system_wide_google_login_pending_consent_intent" } private val coordinator = SystemWideGoogleLoginCoordinator() private var pendingConsentIntent: Intent? = null Loading Loading @@ -68,6 +75,24 @@ class SystemWideGoogleLoginLauncher( ) } fun restore(savedInstanceState: Bundle?) { if (savedInstanceState == null) return coordinator.restorePendingAccountName( savedInstanceState.getString(KEY_PENDING_ACCOUNT_NAME), ) pendingConsentIntent = BundleCompat.getParcelable( savedInstanceState, KEY_PENDING_CONSENT_INTENT, Intent::class.java, ) } fun save(outState: Bundle) { outState.putString(KEY_PENDING_ACCOUNT_NAME, coordinator.snapshotPendingAccountName()) outState.putParcelable(KEY_PENDING_CONSENT_INTENT, pendingConsentIntent) } private fun fetchSelectedAccount(accountName: String) { fragment.lifecycleScope.launch { val fetchResult = microgAccountFetcher.fetchAccount(accountName) Loading Loading
app/src/main/java/foundation/e/apps/data/EnabledSourceState.kt +10 −3 Original line number Diff line number Diff line Loading @@ -31,8 +31,10 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.launch import javax.inject.Inject import javax.inject.Singleton Loading @@ -58,6 +60,12 @@ class EnabledSourceState @Inject constructor( private val _enabledSourcesFlow = MutableStateFlow(emptySet<Source>()) val enabledSourcesFlow: StateFlow<Set<Source>> = _enabledSourcesFlow.asStateFlow() private val _hasHydratedCapabilities = MutableStateFlow(false) val hydratedEnabledSourcesFlow: Flow<Set<Source>> = combine(enabledSourcesFlow, _hasHydratedCapabilities) { enabledSources, hasHydrated -> enabledSources.takeIf { hasHydrated } } .filterNotNull() .distinctUntilChanged() init { coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) { Loading Loading @@ -130,8 +138,7 @@ class EnabledSourceState @Inject constructor( } internal fun EnabledSourceState.enabledStoreChanges(): Flow<Set<Source>> = enabledSourcesFlow .filter { hasHydratedCapabilities } hydratedEnabledSourcesFlow .drop(1) internal fun Source.isAccessible(capabilities: UserCapabilities): Boolean { Loading
app/src/main/java/foundation/e/apps/data/application/category/CategoryApiImpl.kt +14 −2 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Source import foundation.e.apps.data.enums.isUnFiltered import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.playstore.PlayStoreRepository import javax.inject.Inject class CategoryApiImpl @Inject constructor( Loading Loading @@ -86,9 +87,14 @@ class CategoryApiImpl @Inject constructor( private suspend fun fetchGplayCategories( type: CategoryType, ): Pair<List<Category>, ResultStatus> { val playStoreRepository = awaitPlayStoreRepository() ?: return Pair( emptyList(), ResultStatus.UNKNOWN.apply { message = "Play Store unavailable" }, ) val categoryList = mutableListOf<Category>() val result = handleNetworkResult { val playResponse = appSources.gplayRepo.getCategories(type).map { gplayCategory -> val playResponse = playStoreRepository.getCategories(type).map { gplayCategory -> val category = gplayCategory.toCategory() category.drawable = CategoryUtils.provideAppsCategoryIconResource( Loading Loading @@ -154,9 +160,11 @@ class CategoryApiImpl @Inject constructor( category: String, pageUrl: String? ): ResultSupreme<Pair<List<Application>, String>> { val playStoreRepository = awaitPlayStoreRepository() ?: return ResultSupreme.Error("Play Store unavailable") return handleNetworkResult { val cluster = appSources.gplayRepo.getAppsByCategory(category, pageUrl) playStoreRepository.getAppsByCategory(category, pageUrl) val filteredApps = filterRestrictedGPlayApps(cluster.clusterAppList) val applications = (filteredApps.data ?: emptyList()).toMutableList() Loading Loading @@ -232,4 +240,8 @@ class CategoryApiImpl @Inject constructor( else -> null } private suspend fun awaitPlayStoreRepository(): PlayStoreRepository? { return enabledStoreRepositoryProvider.awaitStore(Source.PLAY_STORE) as? PlayStoreRepository } }
app/src/main/java/foundation/e/apps/feature/auth/login/SignInFragment.kt +6 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ class SignInFragment : Fragment() { }, onError = ::showErrorDialog, ) systemWideGoogleLoginLauncher.restore(savedInstanceState) requireActivity().onBackPressedDispatcher.addCallback( this, object : OnBackPressedCallback(true) { Loading Loading @@ -118,6 +119,11 @@ class SignInFragment : Fragment() { dialogState = null } override fun onSaveInstanceState(outState: Bundle) { systemWideGoogleLoginLauncher.save(outState) super.onSaveInstanceState(outState) } private fun navigateToGoogleSignInFragment(): Boolean { return findNavController().safeNavigate( R.id.signInFragment, Loading
app/src/main/java/foundation/e/apps/feature/auth/login/SystemWideGoogleLoginCoordinator.kt +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,12 @@ package foundation.e.apps.feature.auth.login internal class SystemWideGoogleLoginCoordinator { private var pendingAccountName: String? = null fun snapshotPendingAccountName(): String? = pendingAccountName fun restorePendingAccountName(accountName: String?) { pendingAccountName = accountName?.takeIf { it.isNotBlank() } } fun start( hasSupportedMicrog: Boolean, hasMicrogAccount: Boolean, Loading
app/src/main/java/foundation/e/apps/feature/auth/login/SystemWideGoogleLoginLauncher.kt +25 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ package foundation.e.apps.feature.auth.login import android.accounts.AccountManager import android.app.Activity import android.content.Intent import android.os.Bundle import androidx.activity.result.contract.ActivityResultContracts import androidx.core.os.BundleCompat import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import foundation.e.apps.R Loading @@ -36,6 +38,11 @@ class SystemWideGoogleLoginLauncher( private val onCredentialsReady: (String, String) -> Unit, private val onError: (String) -> Unit, ) { companion object { private const val KEY_PENDING_ACCOUNT_NAME = "system_wide_google_login_pending_account_name" private const val KEY_PENDING_CONSENT_INTENT = "system_wide_google_login_pending_consent_intent" } private val coordinator = SystemWideGoogleLoginCoordinator() private var pendingConsentIntent: Intent? = null Loading Loading @@ -68,6 +75,24 @@ class SystemWideGoogleLoginLauncher( ) } fun restore(savedInstanceState: Bundle?) { if (savedInstanceState == null) return coordinator.restorePendingAccountName( savedInstanceState.getString(KEY_PENDING_ACCOUNT_NAME), ) pendingConsentIntent = BundleCompat.getParcelable( savedInstanceState, KEY_PENDING_CONSENT_INTENT, Intent::class.java, ) } fun save(outState: Bundle) { outState.putString(KEY_PENDING_ACCOUNT_NAME, coordinator.snapshotPendingAccountName()) outState.putParcelable(KEY_PENDING_CONSENT_INTENT, pendingConsentIntent) } private fun fetchSelectedAccount(accountName: String) { fragment.lifecycleScope.launch { val fetchResult = microgAccountFetcher.fetchAccount(accountName) Loading