Loading app/src/main/java/foundation/e/apps/data/di/bindings/LoginBindingModule.kt 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * Copyright (C) 2026 e Foundation * * 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 <https://www.gnu.org/licenses/>. */ package foundation.e.apps.data.di.bindings import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import foundation.e.apps.data.login.microg.MicrogLoginManager import foundation.e.apps.data.login.repository.AppLoginRepository import foundation.e.apps.data.login.repository.AuthenticatorRepository import foundation.e.apps.domain.login.LoginRepository import foundation.e.apps.login.MicrogAccountFetcher import foundation.e.apps.login.PlayStoreAuthManager import foundation.e.apps.login.StoreAuthCoordinator import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) interface LoginBindingModule { @Binds @Singleton fun bindLoginRepository( appLoginRepository: AppLoginRepository, ): LoginRepository @Binds @Singleton fun bindPlayStoreAuthManager( authenticatorRepository: AuthenticatorRepository, ): PlayStoreAuthManager @Binds @Singleton fun bindStoreAuthCoordinator( authenticatorRepository: AuthenticatorRepository, ): StoreAuthCoordinator @Binds @Singleton fun bindMicrogAccountFetcher( microgLoginManager: MicrogLoginManager, ): MicrogAccountFetcher } app/src/main/java/foundation/e/apps/data/install/updates/UpdatesWorker.kt +20 −35 Original line number Diff line number Diff line Loading @@ -21,28 +21,28 @@ import foundation.e.apps.data.event.AppEvent import foundation.e.apps.data.event.EventBus import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository import foundation.e.apps.data.install.workmanager.AppInstallProcessor import foundation.e.apps.data.login.repository.AuthenticatorRepository import foundation.e.apps.data.updates.UpdatesManagerRepository import foundation.e.apps.domain.model.User import foundation.e.apps.domain.preferences.AppPreferencesRepository import foundation.e.apps.domain.preferences.SessionRepository import foundation.e.apps.login.PlayStoreAuthManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import timber.log.Timber @Suppress("LongParameterList") @HiltWorker @Suppress("LongParameterList") class UpdatesWorker @AssistedInject constructor( @Assisted private val context: Context, @Assisted private val params: WorkerParameters, private val updatesManagerRepository: UpdatesManagerRepository, private val blockedAppRepository: BlockedAppRepository, private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, private val sessionRepository: SessionRepository, private val appPreferencesRepository: AppPreferencesRepository, private val authenticatorRepository: AuthenticatorRepository, private val playStoreAuthManager: PlayStoreAuthManager, private val appInstallProcessor: AppInstallProcessor, private val blockedAppRepository: BlockedAppRepository, private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, ) : CoroutineWorker(context, params) { companion object { Loading Loading @@ -154,36 +154,19 @@ class UpdatesWorker @AssistedInject constructor( @VisibleForTesting suspend fun getAvailableUpdates(): Pair<List<Application>, ResultStatus> { loadSettings() val appsNeededToUpdate = mutableListOf<Application>() val user = getUser() val authData = authenticatorRepository.getValidatedAuthData().data val resultStatus: ResultStatus if (user in listOf(User.ANONYMOUS, User.GOOGLE) && authData != null) { /* * Signifies valid Google user and valid auth data to update * apps from Google Play store. * The user check will be more useful in No-Google mode. */ val (apps, status) = updatesManagerRepository.getUpdates() appsNeededToUpdate.addAll(apps) resultStatus = status } else if (user == User.NO_GOOGLE) { /* * If authData is null, update apps from cleanapk only. */ val (apps, status) = updatesManagerRepository.getUpdatesOSS() appsNeededToUpdate.addAll(apps) resultStatus = status } else { /* * If user in UNAVAILABLE, don't do anything. */ val authData = playStoreAuthManager.getValidatedAuthData().data val canUsePlayStoreUpdates = (user == User.ANONYMOUS || user == User.GOOGLE) && authData != null return when { canUsePlayStoreUpdates -> updatesManagerRepository.getUpdates() user == User.NO_GOOGLE -> updatesManagerRepository.getUpdatesOSS() else -> { Timber.e("Update is aborted for unavailable user!") resultStatus = ResultStatus.UNKNOWN Pair(emptyList(), ResultStatus.UNKNOWN) } } return Pair(appsNeededToUpdate, resultStatus) } @VisibleForTesting Loading Loading @@ -224,9 +207,11 @@ class UpdatesWorker @AssistedInject constructor( // returns list of Pair(app, status(success|failed)) @VisibleForTesting suspend fun startUpdateProcess(appsNeededToUpdate: List<Application>): List<Pair<Application, Boolean>> { suspend fun startUpdateProcess( appsNeededToUpdate: List<Application> ): List<Pair<Application, Boolean>> { val response = mutableListOf<Pair<Application, Boolean>>() val authData = authenticatorRepository.getValidatedAuthData() val authData = playStoreAuthManager.getValidatedAuthData() val isNotLoggedIntoPersonalAccount = !authData.isValidData() || authData.data?.isAnonymous == true for (fusedApp in appsNeededToUpdate) { Loading app/src/main/java/foundation/e/apps/data/install/workmanager/InstallWorkManager.kt +0 −4 Original line number Diff line number Diff line Loading @@ -37,10 +37,6 @@ object InstallWorkManager { return operation } fun cancelWork(context: Context, tag: String) { WorkManager.getInstance(context).cancelAllWorkByTag(tag) } fun checkWorkIsAlreadyAvailable(context: Context, tag: String): Boolean { val works = WorkManager.getInstance(context).getWorkInfosByTag(tag) try { Loading app/src/main/java/foundation/e/apps/data/login/cleanapk/CleanApkAuthenticator.kt +3 −7 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import foundation.e.apps.data.login.core.StoreAuthResult import foundation.e.apps.data.login.core.StoreAuthenticator import foundation.e.apps.data.login.core.StoreType import foundation.e.apps.domain.model.LoginState import foundation.e.apps.domain.model.User import foundation.e.apps.domain.preferences.AppPreferencesRepository import foundation.e.apps.domain.preferences.SessionRepository import javax.inject.Inject Loading @@ -40,11 +39,8 @@ class CleanApkAuthenticator @Inject constructor( ) : StoreAuthenticator { override val storeType: StoreType = StoreType.CLEAN_APK private val user: User get() = sessionRepository.getUser() override fun isStoreActive(): Boolean { if (sessionRepository.getLoginState() == LoginState.UNAVAILABLE) { override suspend fun isStoreActive(): Boolean { if (sessionRepository.awaitLoginState() == LoginState.UNAVAILABLE) { /* * UNAVAILABLE login state means first login is not completed. */ Loading @@ -57,7 +53,7 @@ class CleanApkAuthenticator @Inject constructor( return StoreAuthResult( authObject = AuthObject.CleanApk( ResultSupreme.Success(Unit), user, sessionRepository.awaitUser(), ) ) } Loading app/src/main/java/foundation/e/apps/data/login/core/StoreAuthenticator.kt +1 −1 Original line number Diff line number Diff line Loading @@ -24,5 +24,5 @@ interface StoreAuthenticator { val storeType: StoreType suspend fun login(): StoreAuthResult suspend fun logout() fun isStoreActive(): Boolean suspend fun isStoreActive(): Boolean } Loading
app/src/main/java/foundation/e/apps/data/di/bindings/LoginBindingModule.kt 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * Copyright (C) 2026 e Foundation * * 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 <https://www.gnu.org/licenses/>. */ package foundation.e.apps.data.di.bindings import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import foundation.e.apps.data.login.microg.MicrogLoginManager import foundation.e.apps.data.login.repository.AppLoginRepository import foundation.e.apps.data.login.repository.AuthenticatorRepository import foundation.e.apps.domain.login.LoginRepository import foundation.e.apps.login.MicrogAccountFetcher import foundation.e.apps.login.PlayStoreAuthManager import foundation.e.apps.login.StoreAuthCoordinator import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) interface LoginBindingModule { @Binds @Singleton fun bindLoginRepository( appLoginRepository: AppLoginRepository, ): LoginRepository @Binds @Singleton fun bindPlayStoreAuthManager( authenticatorRepository: AuthenticatorRepository, ): PlayStoreAuthManager @Binds @Singleton fun bindStoreAuthCoordinator( authenticatorRepository: AuthenticatorRepository, ): StoreAuthCoordinator @Binds @Singleton fun bindMicrogAccountFetcher( microgLoginManager: MicrogLoginManager, ): MicrogAccountFetcher }
app/src/main/java/foundation/e/apps/data/install/updates/UpdatesWorker.kt +20 −35 Original line number Diff line number Diff line Loading @@ -21,28 +21,28 @@ import foundation.e.apps.data.event.AppEvent import foundation.e.apps.data.event.EventBus import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository import foundation.e.apps.data.install.workmanager.AppInstallProcessor import foundation.e.apps.data.login.repository.AuthenticatorRepository import foundation.e.apps.data.updates.UpdatesManagerRepository import foundation.e.apps.domain.model.User import foundation.e.apps.domain.preferences.AppPreferencesRepository import foundation.e.apps.domain.preferences.SessionRepository import foundation.e.apps.login.PlayStoreAuthManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import timber.log.Timber @Suppress("LongParameterList") @HiltWorker @Suppress("LongParameterList") class UpdatesWorker @AssistedInject constructor( @Assisted private val context: Context, @Assisted private val params: WorkerParameters, private val updatesManagerRepository: UpdatesManagerRepository, private val blockedAppRepository: BlockedAppRepository, private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, private val sessionRepository: SessionRepository, private val appPreferencesRepository: AppPreferencesRepository, private val authenticatorRepository: AuthenticatorRepository, private val playStoreAuthManager: PlayStoreAuthManager, private val appInstallProcessor: AppInstallProcessor, private val blockedAppRepository: BlockedAppRepository, private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, ) : CoroutineWorker(context, params) { companion object { Loading Loading @@ -154,36 +154,19 @@ class UpdatesWorker @AssistedInject constructor( @VisibleForTesting suspend fun getAvailableUpdates(): Pair<List<Application>, ResultStatus> { loadSettings() val appsNeededToUpdate = mutableListOf<Application>() val user = getUser() val authData = authenticatorRepository.getValidatedAuthData().data val resultStatus: ResultStatus if (user in listOf(User.ANONYMOUS, User.GOOGLE) && authData != null) { /* * Signifies valid Google user and valid auth data to update * apps from Google Play store. * The user check will be more useful in No-Google mode. */ val (apps, status) = updatesManagerRepository.getUpdates() appsNeededToUpdate.addAll(apps) resultStatus = status } else if (user == User.NO_GOOGLE) { /* * If authData is null, update apps from cleanapk only. */ val (apps, status) = updatesManagerRepository.getUpdatesOSS() appsNeededToUpdate.addAll(apps) resultStatus = status } else { /* * If user in UNAVAILABLE, don't do anything. */ val authData = playStoreAuthManager.getValidatedAuthData().data val canUsePlayStoreUpdates = (user == User.ANONYMOUS || user == User.GOOGLE) && authData != null return when { canUsePlayStoreUpdates -> updatesManagerRepository.getUpdates() user == User.NO_GOOGLE -> updatesManagerRepository.getUpdatesOSS() else -> { Timber.e("Update is aborted for unavailable user!") resultStatus = ResultStatus.UNKNOWN Pair(emptyList(), ResultStatus.UNKNOWN) } } return Pair(appsNeededToUpdate, resultStatus) } @VisibleForTesting Loading Loading @@ -224,9 +207,11 @@ class UpdatesWorker @AssistedInject constructor( // returns list of Pair(app, status(success|failed)) @VisibleForTesting suspend fun startUpdateProcess(appsNeededToUpdate: List<Application>): List<Pair<Application, Boolean>> { suspend fun startUpdateProcess( appsNeededToUpdate: List<Application> ): List<Pair<Application, Boolean>> { val response = mutableListOf<Pair<Application, Boolean>>() val authData = authenticatorRepository.getValidatedAuthData() val authData = playStoreAuthManager.getValidatedAuthData() val isNotLoggedIntoPersonalAccount = !authData.isValidData() || authData.data?.isAnonymous == true for (fusedApp in appsNeededToUpdate) { Loading
app/src/main/java/foundation/e/apps/data/install/workmanager/InstallWorkManager.kt +0 −4 Original line number Diff line number Diff line Loading @@ -37,10 +37,6 @@ object InstallWorkManager { return operation } fun cancelWork(context: Context, tag: String) { WorkManager.getInstance(context).cancelAllWorkByTag(tag) } fun checkWorkIsAlreadyAvailable(context: Context, tag: String): Boolean { val works = WorkManager.getInstance(context).getWorkInfosByTag(tag) try { Loading
app/src/main/java/foundation/e/apps/data/login/cleanapk/CleanApkAuthenticator.kt +3 −7 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import foundation.e.apps.data.login.core.StoreAuthResult import foundation.e.apps.data.login.core.StoreAuthenticator import foundation.e.apps.data.login.core.StoreType import foundation.e.apps.domain.model.LoginState import foundation.e.apps.domain.model.User import foundation.e.apps.domain.preferences.AppPreferencesRepository import foundation.e.apps.domain.preferences.SessionRepository import javax.inject.Inject Loading @@ -40,11 +39,8 @@ class CleanApkAuthenticator @Inject constructor( ) : StoreAuthenticator { override val storeType: StoreType = StoreType.CLEAN_APK private val user: User get() = sessionRepository.getUser() override fun isStoreActive(): Boolean { if (sessionRepository.getLoginState() == LoginState.UNAVAILABLE) { override suspend fun isStoreActive(): Boolean { if (sessionRepository.awaitLoginState() == LoginState.UNAVAILABLE) { /* * UNAVAILABLE login state means first login is not completed. */ Loading @@ -57,7 +53,7 @@ class CleanApkAuthenticator @Inject constructor( return StoreAuthResult( authObject = AuthObject.CleanApk( ResultSupreme.Success(Unit), user, sessionRepository.awaitUser(), ) ) } Loading
app/src/main/java/foundation/e/apps/data/login/core/StoreAuthenticator.kt +1 −1 Original line number Diff line number Diff line Loading @@ -24,5 +24,5 @@ interface StoreAuthenticator { val storeType: StoreType suspend fun login(): StoreAuthResult suspend fun logout() fun isStoreActive(): Boolean suspend fun isStoreActive(): Boolean }