Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e63900fb authored by Abhishek Aggarwal's avatar Abhishek Aggarwal
Browse files

refactor(login): move auth flows behind domain and app services

parent 458fcc5e
Loading
Loading
Loading
Loading
+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
}
+56 −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.install.updates

import foundation.e.apps.data.ResultSupreme
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.blockedApps.BlockedAppRepository
import foundation.e.apps.data.enums.ResultStatus
import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository
import foundation.e.apps.data.updates.UpdatesManagerRepository
import foundation.e.apps.domain.model.User
import javax.inject.Inject

class UpdatesCoordinator @Inject constructor(
    private val updatesManagerRepository: UpdatesManagerRepository,
    private val blockedAppRepository: BlockedAppRepository,
    private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository,
) {
    suspend fun refreshBlockedAppWarnings(): Boolean {
        return blockedAppRepository.fetchUpdateOfAppWarningList()
    }

    suspend fun refreshSystemApps(): ResultSupreme<Unit> {
        return systemAppsUpdatesRepository.fetchUpdatableSystemApps(forceRefresh = true)
    }

    suspend fun getAvailableUpdates(
        user: User,
        hasAuthenticatedPlayStoreSession: Boolean,
    ): Pair<List<Application>, ResultStatus> {
        val canUsePlayStoreUpdates =
            (user == User.ANONYMOUS || user == User.GOOGLE) && hasAuthenticatedPlayStoreSession
        return if (canUsePlayStoreUpdates) {
            updatesManagerRepository.getUpdates()
        } else if (user == User.NO_GOOGLE) {
            updatesManagerRepository.getUpdatesOSS()
        } else {
            Pair(emptyList(), ResultStatus.UNKNOWN)
        }
    }
}
+18 −17
Original line number Diff line number Diff line
@@ -15,34 +15,28 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import foundation.e.apps.data.ResultSupreme
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.blockedApps.BlockedAppRepository
import foundation.e.apps.data.enums.ResultStatus
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
class UpdatesWorker @AssistedInject constructor(
    @Assisted private val context: Context,
    @Assisted private val params: WorkerParameters,
    private val updatesManagerRepository: UpdatesManagerRepository,
    private val updatesCoordinator: UpdatesCoordinator,
    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 {
@@ -67,13 +61,12 @@ class UpdatesWorker @AssistedInject constructor(
            }

            if (isAutoUpdate) {
                check(blockedAppRepository.fetchUpdateOfAppWarningList()) {
                check(updatesCoordinator.refreshBlockedAppWarnings()) {
                    "failed to update app blocklist"
                }
            }

            val systemAppsUpdateTask =
                systemAppsUpdatesRepository.fetchUpdatableSystemApps(forceRefresh = true)
            val systemAppsUpdateTask = updatesCoordinator.refreshSystemApps()
            check(systemAppsUpdateTask.isSuccess()) { "failed to fetch system apps update!" }
            val enqueueInstall = checkForUpdates()
            check(enqueueInstall == ResultStatus.OK) {
@@ -156,7 +149,7 @@ class UpdatesWorker @AssistedInject constructor(
        loadSettings()
        val appsNeededToUpdate = mutableListOf<Application>()
        val user = getUser()
        val authData = authenticatorRepository.getValidatedAuthData().data
        val authData = playStoreAuthManager.getValidatedAuthData().data
        val resultStatus: ResultStatus

        if (user in listOf(User.ANONYMOUS, User.GOOGLE) && authData != null) {
@@ -165,14 +158,20 @@ class UpdatesWorker @AssistedInject constructor(
             * apps from Google Play store.
             * The user check will be more useful in No-Google mode.
             */
            val (apps, status) = updatesManagerRepository.getUpdates()
            val (apps, status) = updatesCoordinator.getAvailableUpdates(
                user = user,
                hasAuthenticatedPlayStoreSession = true
            )
            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()
            val (apps, status) = updatesCoordinator.getAvailableUpdates(
                user = user,
                hasAuthenticatedPlayStoreSession = false
            )
            appsNeededToUpdate.addAll(apps)
            resultStatus = status
        } else {
@@ -224,9 +223,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) {
+0 −4
Original line number Diff line number Diff line
@@ -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 {
+2 −6
Original line number Diff line number Diff line
@@ -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
@@ -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) {
        if (sessionRepository.loginState.value == LoginState.UNAVAILABLE) {
            /*
             * UNAVAILABLE login state means first login is not completed.
             */
@@ -57,7 +53,7 @@ class CleanApkAuthenticator @Inject constructor(
        return StoreAuthResult(
            authObject = AuthObject.CleanApk(
                ResultSupreme.Success(Unit),
                user,
                sessionRepository.awaitUser(),
            )
        )
    }
Loading