Loading app/src/main/java/foundation/e/apps/feature/auth/session/SessionStateHolder.kt +50 −13 Original line number Diff line number Diff line Loading @@ -52,9 +52,10 @@ class SessionStateHolder @Inject constructor( } private val refreshMutex = Mutex() private val faultyTokenReportMutex = Mutex() private val faultyTokenReportLock = Any() private var inFlightRefresh: InFlightRefresh? = null private var faultyTokenReportVersion: Long = 0 private var latestFaultyTokenReport: FaultyTokenReportPayload? = null private val _activeSessions = MutableStateFlow<List<AuthSession>>(emptyList()) Loading Loading @@ -146,7 +147,7 @@ class SessionStateHolder @Inject constructor( private fun publishRefreshOutcome(authRefreshOutcome: AuthRefreshOutcome) { val authRefreshSnapshot = authRefreshOutcome.snapshot latestFaultyTokenReport = authRefreshOutcome.faultyTokenReport replaceFaultyTokenReport(authRefreshOutcome.faultyTokenReport) _activeSessions.value = authRefreshSnapshot.activeSessions _authRefreshState.value = AuthRefreshState.Completed(authRefreshSnapshot) _authRefreshSnapshot.value = authRefreshSnapshot Loading Loading @@ -204,26 +205,20 @@ class SessionStateHolder @Inject constructor( } override suspend fun reportFaultyTokenIfNeeded() { val faultyTokenReport = faultyTokenReportMutex.withLock { latestFaultyTokenReport?.also { latestFaultyTokenReport = null } } ?: return val consumedFaultyTokenReport = consumeFaultyTokenReport() ?: return val reportFailure = runCatching { faultyTokenReporter.report(faultyTokenReport) faultyTokenReporter.report(consumedFaultyTokenReport.payload) }.exceptionOrNull() if (reportFailure != null) { faultyTokenReportMutex.withLock { latestFaultyTokenReport = latestFaultyTokenReport ?: faultyTokenReport } restoreFaultyTokenReport(consumedFaultyTokenReport) throw reportFailure } } override fun clearLoadedSessions() { latestFaultyTokenReport = null clearFaultyTokenReport() _activeSessions.value = emptyList() _authRefreshState.value = AuthRefreshState.Pending _authRefreshSnapshot.value = null Loading @@ -231,17 +226,59 @@ class SessionStateHolder @Inject constructor( override fun markLoggedOut() { val loggedOutSnapshot = AuthRefreshSnapshot(emptyList()) latestFaultyTokenReport = null clearFaultyTokenReport() _activeSessions.value = emptyList() _authRefreshState.value = AuthRefreshState.Completed(loggedOutSnapshot) _authRefreshSnapshot.value = loggedOutSnapshot } private fun replaceFaultyTokenReport(payload: FaultyTokenReportPayload?) { synchronized(faultyTokenReportLock) { faultyTokenReportVersion += 1 latestFaultyTokenReport = payload } } private fun consumeFaultyTokenReport(): ConsumedFaultyTokenReport? { return synchronized(faultyTokenReportLock) { latestFaultyTokenReport?.let { payload -> latestFaultyTokenReport = null ConsumedFaultyTokenReport( payload = payload, version = faultyTokenReportVersion, ) } } } private fun restoreFaultyTokenReport(consumedFaultyTokenReport: ConsumedFaultyTokenReport) { synchronized(faultyTokenReportLock) { if ( faultyTokenReportVersion == consumedFaultyTokenReport.version && latestFaultyTokenReport == null ) { latestFaultyTokenReport = consumedFaultyTokenReport.payload } } } private fun clearFaultyTokenReport() { synchronized(faultyTokenReportLock) { faultyTokenReportVersion += 1 latestFaultyTokenReport = null } } private data class InFlightRefresh( val storesToReset: List<AuthStore>, val completion: CompletableDeferred<Unit>, ) private data class ConsumedFaultyTokenReport( val payload: FaultyTokenReportPayload, val version: Long, ) private sealed interface RefreshRequest { data class StartNew(val refresh: InFlightRefresh) : RefreshRequest data class JoinExisting(val completion: CompletableDeferred<Unit>) : RefreshRequest Loading app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt +1 −2 Original line number Diff line number Diff line Loading @@ -40,7 +40,6 @@ import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Source import foundation.e.apps.data.install.pkg.AppLoungePackageManager import foundation.e.apps.data.install.pkg.PwaManager import foundation.e.apps.data.login.core.StoreType import foundation.e.apps.databinding.FragmentApplicationBinding import foundation.e.apps.domain.auth.AuthRefreshSnapshot import foundation.e.apps.domain.auth.AuthSession Loading Loading @@ -185,7 +184,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { loadFailureDialogs.handleFailuresCommon( failures = listOf( playStoreFailure.toLegacyLoadFailure( storeType = StoreType.PLAY_STORE, authStore = AuthStore.PLAY_STORE, loginMode = sessionRepository.awaitLoginIntent().toPlayStoreLoginModeOrNull(), ), ), Loading app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt +2 −2 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ import foundation.e.apps.data.login.exceptions.CleanApkException import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.ui.parentFragment.LegacyLoadFailure import foundation.e.apps.ui.parentFragment.toLegacyLoadFailure import foundation.e.apps.ui.parentFragment.toLegacyStoreType import foundation.e.apps.ui.parentFragment.toLegacyAuthStore import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import javax.inject.Inject Loading Loading @@ -72,7 +72,7 @@ class ApplicationListViewModel @Inject constructor( } if (!result.isSuccess()) { val loadFailure = result.toLegacyLoadFailure(sourceType.toLegacyStoreType()) { isTimeout, message -> val loadFailure = result.toLegacyLoadFailure(sourceType.toLegacyAuthStore()) { isTimeout, message -> if (isCleanApk) { CleanApkException(isTimeout, message) } else { Loading app/src/main/java/foundation/e/apps/ui/categories/CategoriesViewModel.kt +2 −2 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ import foundation.e.apps.data.enums.Source import foundation.e.apps.data.login.exceptions.CleanApkException import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.ui.parentFragment.LegacyLoadFailure import foundation.e.apps.ui.parentFragment.toLegacyStoreType import foundation.e.apps.ui.parentFragment.toLegacyAuthStore import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow Loading Loading @@ -92,7 +92,7 @@ class CategoriesViewModel @Inject constructor( exceptions.add( LegacyLoadFailure.fromException( exception = error, storeType = data.source.toLegacyStoreType(), authStore = data.source.toLegacyAuthStore(), ) ) continue Loading app/src/main/java/foundation/e/apps/ui/parentFragment/LegacyLoadFailure.kt +53 −35 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ import java.net.HttpURLConnection data class LegacyLoadFailure( val exception: Exception, val kind: LegacyLoadFailureKind, val storeType: StoreType? = null, val authStore: AuthStore? = null, val authError: AuthError? = null, val loginMode: PlayStoreLoginMode? = null, val storesToResetOnRetry: List<AuthStore> = emptyList(), Loading @@ -55,13 +55,13 @@ data class LegacyLoadFailure( companion object { fun fromException( exception: Exception, storeType: StoreType? = null, authStore: AuthStore? = null, authError: AuthError? = null, loginMode: PlayStoreLoginMode? = (exception as? GPlayLoginException)?.loginMode, ): LegacyLoadFailure { val kind = resolveKind( exception = exception, storeType = storeType, authStore = authStore, authError = authError, ) val dialogSpec = resolveDialogSpec( Loading @@ -72,7 +72,7 @@ data class LegacyLoadFailure( return LegacyLoadFailure( exception = exception, kind = kind, storeType = storeType, authStore = authStore, authError = authError, loginMode = loginMode, storesToResetOnRetry = resolveStoresToResetOnRetry( Loading @@ -94,77 +94,82 @@ enum class LegacyLoadFailureKind { } fun ResultSupreme<*>.toLegacyLoadFailure( storeType: StoreType, authStore: AuthStore, fallbackException: (isTimeout: Boolean, message: String) -> Exception, ): LegacyLoadFailure { val resolvedMessage = message.ifBlank { "Data load error" } val resolvedException = exception ?: fallbackException(isTimeout(), resolvedMessage) val resolvedAuthError = when { this is ResultSupreme.Timeout || exception != null -> toAuthError(storeType) this is ResultSupreme.Timeout || exception != null -> toAuthError(authStore.toStoreType()) else -> null } return LegacyLoadFailure.fromException( exception = resolvedException, storeType = storeType, authStore = authStore, authError = resolvedAuthError, ) } fun Source.toLegacyStoreType(): StoreType { fun Source.toLegacyAuthStore(): AuthStore { return when (this) { Source.PLAY_STORE -> StoreType.PLAY_STORE Source.OPEN_SOURCE, Source.PWA, Source.SYSTEM_APP -> StoreType.CLEAN_APK Source.PLAY_STORE -> AuthStore.PLAY_STORE Source.OPEN_SOURCE, Source.PWA, Source.SYSTEM_APP -> AuthStore.OPEN_SOURCE } } fun AuthError.toLegacyLoadFailure( storeType: StoreType, authStore: AuthStore, loginMode: PlayStoreLoginMode?, ): LegacyLoadFailure { return LegacyLoadFailure.fromException( exception = toLegacyException(storeType, loginMode), storeType = storeType, exception = toLegacyException(authStore, loginMode), authStore = authStore, authError = this, loginMode = loginMode, ) } private fun AuthError.toLegacyException( storeType: StoreType, authStore: AuthStore, loginMode: PlayStoreLoginMode?, ): Exception { return when (this) { is AuthError.InvalidToken -> toValidationException(loginMode) is AuthError.NetworkFailure -> toNetworkException(storeType, loginMode) is AuthError.InvalidToken -> toInvalidTokenException(authStore, loginMode) is AuthError.NetworkFailure -> toNetworkException(authStore, loginMode) is AuthError.LoginRequired -> toLoginRequiredException(loginMode) is AuthError.RateLimited -> toStoreException(storeType) is AuthError.Unknown -> toStoreException(storeType) is AuthError.RateLimited -> toStoreException(authStore) is AuthError.Unknown -> toStoreException(authStore) } } private fun AuthError.toValidationException( private fun AuthError.InvalidToken.toInvalidTokenException( authStore: AuthStore, loginMode: PlayStoreLoginMode?, ): GPlayValidationException { val message = when (this) { is AuthError.InvalidToken -> message.orEmpty() else -> "" ): Exception { return when (authStore) { AuthStore.PLAY_STORE -> toValidationException(loginMode) AuthStore.OPEN_SOURCE -> CleanApkException(false, message) } } private fun AuthError.InvalidToken.toValidationException( loginMode: PlayStoreLoginMode?, ): GPlayValidationException { return GPlayValidationException( message = message, message = message.orEmpty(), loginMode = loginMode, networkCode = HttpURLConnection.HTTP_UNAUTHORIZED, ) } private fun AuthError.NetworkFailure.toNetworkException( storeType: StoreType, authStore: AuthStore, loginMode: PlayStoreLoginMode?, ): Exception { return when (storeType) { StoreType.PLAY_STORE -> GPlayLoginException(isTimeout, message, loginMode) StoreType.CLEAN_APK -> CleanApkException(isTimeout, message) return when (authStore) { AuthStore.PLAY_STORE -> GPlayLoginException(isTimeout, message, loginMode) AuthStore.OPEN_SOURCE -> CleanApkException(isTimeout, message) } } Loading @@ -177,27 +182,33 @@ private fun AuthError.LoginRequired.toLoginRequiredException( } } private fun AuthError.toStoreException(storeType: StoreType): Exception { private fun AuthError.toStoreException(authStore: AuthStore): Exception { val message = when (this) { is AuthError.RateLimited -> message is AuthError.Unknown -> message else -> null } return when (storeType) { StoreType.PLAY_STORE -> GPlayException(false, message) StoreType.CLEAN_APK -> CleanApkException(false, message) return when (authStore) { AuthStore.PLAY_STORE -> GPlayException(false, message) AuthStore.OPEN_SOURCE -> CleanApkException(false, message) } } private fun resolveKind( exception: Exception, storeType: StoreType?, authStore: AuthStore?, authError: AuthError?, ): LegacyLoadFailureKind { return when { authError is AuthError.RateLimited -> LegacyLoadFailureKind.RATE_LIMITED authError is AuthError.InvalidToken -> LegacyLoadFailureKind.SIGN_IN authError is AuthError.InvalidToken -> { if (authError.store == AuthStore.PLAY_STORE) { LegacyLoadFailureKind.SIGN_IN } else { LegacyLoadFailureKind.DATA_LOAD } } authError is AuthError.LoginRequired -> { if (authError.store == AuthStore.PLAY_STORE) { LegacyLoadFailureKind.SIGN_IN Loading @@ -208,7 +219,7 @@ private fun resolveKind( authError is AuthError.NetworkFailure -> { if (authError.isTimeout) { LegacyLoadFailureKind.TIMEOUT } else if (storeType == StoreType.PLAY_STORE) { } else if (authStore == AuthStore.PLAY_STORE) { LegacyLoadFailureKind.SIGN_IN } else { LegacyLoadFailureKind.DATA_LOAD Loading @@ -221,6 +232,13 @@ private fun resolveKind( } } private fun AuthStore.toStoreType(): StoreType { return when (this) { AuthStore.PLAY_STORE -> StoreType.PLAY_STORE AuthStore.OPEN_SOURCE -> StoreType.CLEAN_APK } } private fun resolveDialogSpec( exception: Exception, kind: LegacyLoadFailureKind, Loading Loading
app/src/main/java/foundation/e/apps/feature/auth/session/SessionStateHolder.kt +50 −13 Original line number Diff line number Diff line Loading @@ -52,9 +52,10 @@ class SessionStateHolder @Inject constructor( } private val refreshMutex = Mutex() private val faultyTokenReportMutex = Mutex() private val faultyTokenReportLock = Any() private var inFlightRefresh: InFlightRefresh? = null private var faultyTokenReportVersion: Long = 0 private var latestFaultyTokenReport: FaultyTokenReportPayload? = null private val _activeSessions = MutableStateFlow<List<AuthSession>>(emptyList()) Loading Loading @@ -146,7 +147,7 @@ class SessionStateHolder @Inject constructor( private fun publishRefreshOutcome(authRefreshOutcome: AuthRefreshOutcome) { val authRefreshSnapshot = authRefreshOutcome.snapshot latestFaultyTokenReport = authRefreshOutcome.faultyTokenReport replaceFaultyTokenReport(authRefreshOutcome.faultyTokenReport) _activeSessions.value = authRefreshSnapshot.activeSessions _authRefreshState.value = AuthRefreshState.Completed(authRefreshSnapshot) _authRefreshSnapshot.value = authRefreshSnapshot Loading Loading @@ -204,26 +205,20 @@ class SessionStateHolder @Inject constructor( } override suspend fun reportFaultyTokenIfNeeded() { val faultyTokenReport = faultyTokenReportMutex.withLock { latestFaultyTokenReport?.also { latestFaultyTokenReport = null } } ?: return val consumedFaultyTokenReport = consumeFaultyTokenReport() ?: return val reportFailure = runCatching { faultyTokenReporter.report(faultyTokenReport) faultyTokenReporter.report(consumedFaultyTokenReport.payload) }.exceptionOrNull() if (reportFailure != null) { faultyTokenReportMutex.withLock { latestFaultyTokenReport = latestFaultyTokenReport ?: faultyTokenReport } restoreFaultyTokenReport(consumedFaultyTokenReport) throw reportFailure } } override fun clearLoadedSessions() { latestFaultyTokenReport = null clearFaultyTokenReport() _activeSessions.value = emptyList() _authRefreshState.value = AuthRefreshState.Pending _authRefreshSnapshot.value = null Loading @@ -231,17 +226,59 @@ class SessionStateHolder @Inject constructor( override fun markLoggedOut() { val loggedOutSnapshot = AuthRefreshSnapshot(emptyList()) latestFaultyTokenReport = null clearFaultyTokenReport() _activeSessions.value = emptyList() _authRefreshState.value = AuthRefreshState.Completed(loggedOutSnapshot) _authRefreshSnapshot.value = loggedOutSnapshot } private fun replaceFaultyTokenReport(payload: FaultyTokenReportPayload?) { synchronized(faultyTokenReportLock) { faultyTokenReportVersion += 1 latestFaultyTokenReport = payload } } private fun consumeFaultyTokenReport(): ConsumedFaultyTokenReport? { return synchronized(faultyTokenReportLock) { latestFaultyTokenReport?.let { payload -> latestFaultyTokenReport = null ConsumedFaultyTokenReport( payload = payload, version = faultyTokenReportVersion, ) } } } private fun restoreFaultyTokenReport(consumedFaultyTokenReport: ConsumedFaultyTokenReport) { synchronized(faultyTokenReportLock) { if ( faultyTokenReportVersion == consumedFaultyTokenReport.version && latestFaultyTokenReport == null ) { latestFaultyTokenReport = consumedFaultyTokenReport.payload } } } private fun clearFaultyTokenReport() { synchronized(faultyTokenReportLock) { faultyTokenReportVersion += 1 latestFaultyTokenReport = null } } private data class InFlightRefresh( val storesToReset: List<AuthStore>, val completion: CompletableDeferred<Unit>, ) private data class ConsumedFaultyTokenReport( val payload: FaultyTokenReportPayload, val version: Long, ) private sealed interface RefreshRequest { data class StartNew(val refresh: InFlightRefresh) : RefreshRequest data class JoinExisting(val completion: CompletableDeferred<Unit>) : RefreshRequest Loading
app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt +1 −2 Original line number Diff line number Diff line Loading @@ -40,7 +40,6 @@ import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.Source import foundation.e.apps.data.install.pkg.AppLoungePackageManager import foundation.e.apps.data.install.pkg.PwaManager import foundation.e.apps.data.login.core.StoreType import foundation.e.apps.databinding.FragmentApplicationBinding import foundation.e.apps.domain.auth.AuthRefreshSnapshot import foundation.e.apps.domain.auth.AuthSession Loading Loading @@ -185,7 +184,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { loadFailureDialogs.handleFailuresCommon( failures = listOf( playStoreFailure.toLegacyLoadFailure( storeType = StoreType.PLAY_STORE, authStore = AuthStore.PLAY_STORE, loginMode = sessionRepository.awaitLoginIntent().toPlayStoreLoginModeOrNull(), ), ), Loading
app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt +2 −2 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ import foundation.e.apps.data.login.exceptions.CleanApkException import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.ui.parentFragment.LegacyLoadFailure import foundation.e.apps.ui.parentFragment.toLegacyLoadFailure import foundation.e.apps.ui.parentFragment.toLegacyStoreType import foundation.e.apps.ui.parentFragment.toLegacyAuthStore import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import javax.inject.Inject Loading Loading @@ -72,7 +72,7 @@ class ApplicationListViewModel @Inject constructor( } if (!result.isSuccess()) { val loadFailure = result.toLegacyLoadFailure(sourceType.toLegacyStoreType()) { isTimeout, message -> val loadFailure = result.toLegacyLoadFailure(sourceType.toLegacyAuthStore()) { isTimeout, message -> if (isCleanApk) { CleanApkException(isTimeout, message) } else { Loading
app/src/main/java/foundation/e/apps/ui/categories/CategoriesViewModel.kt +2 −2 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ import foundation.e.apps.data.enums.Source import foundation.e.apps.data.login.exceptions.CleanApkException import foundation.e.apps.data.login.exceptions.GPlayException import foundation.e.apps.ui.parentFragment.LegacyLoadFailure import foundation.e.apps.ui.parentFragment.toLegacyStoreType import foundation.e.apps.ui.parentFragment.toLegacyAuthStore import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow Loading Loading @@ -92,7 +92,7 @@ class CategoriesViewModel @Inject constructor( exceptions.add( LegacyLoadFailure.fromException( exception = error, storeType = data.source.toLegacyStoreType(), authStore = data.source.toLegacyAuthStore(), ) ) continue Loading
app/src/main/java/foundation/e/apps/ui/parentFragment/LegacyLoadFailure.kt +53 −35 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ import java.net.HttpURLConnection data class LegacyLoadFailure( val exception: Exception, val kind: LegacyLoadFailureKind, val storeType: StoreType? = null, val authStore: AuthStore? = null, val authError: AuthError? = null, val loginMode: PlayStoreLoginMode? = null, val storesToResetOnRetry: List<AuthStore> = emptyList(), Loading @@ -55,13 +55,13 @@ data class LegacyLoadFailure( companion object { fun fromException( exception: Exception, storeType: StoreType? = null, authStore: AuthStore? = null, authError: AuthError? = null, loginMode: PlayStoreLoginMode? = (exception as? GPlayLoginException)?.loginMode, ): LegacyLoadFailure { val kind = resolveKind( exception = exception, storeType = storeType, authStore = authStore, authError = authError, ) val dialogSpec = resolveDialogSpec( Loading @@ -72,7 +72,7 @@ data class LegacyLoadFailure( return LegacyLoadFailure( exception = exception, kind = kind, storeType = storeType, authStore = authStore, authError = authError, loginMode = loginMode, storesToResetOnRetry = resolveStoresToResetOnRetry( Loading @@ -94,77 +94,82 @@ enum class LegacyLoadFailureKind { } fun ResultSupreme<*>.toLegacyLoadFailure( storeType: StoreType, authStore: AuthStore, fallbackException: (isTimeout: Boolean, message: String) -> Exception, ): LegacyLoadFailure { val resolvedMessage = message.ifBlank { "Data load error" } val resolvedException = exception ?: fallbackException(isTimeout(), resolvedMessage) val resolvedAuthError = when { this is ResultSupreme.Timeout || exception != null -> toAuthError(storeType) this is ResultSupreme.Timeout || exception != null -> toAuthError(authStore.toStoreType()) else -> null } return LegacyLoadFailure.fromException( exception = resolvedException, storeType = storeType, authStore = authStore, authError = resolvedAuthError, ) } fun Source.toLegacyStoreType(): StoreType { fun Source.toLegacyAuthStore(): AuthStore { return when (this) { Source.PLAY_STORE -> StoreType.PLAY_STORE Source.OPEN_SOURCE, Source.PWA, Source.SYSTEM_APP -> StoreType.CLEAN_APK Source.PLAY_STORE -> AuthStore.PLAY_STORE Source.OPEN_SOURCE, Source.PWA, Source.SYSTEM_APP -> AuthStore.OPEN_SOURCE } } fun AuthError.toLegacyLoadFailure( storeType: StoreType, authStore: AuthStore, loginMode: PlayStoreLoginMode?, ): LegacyLoadFailure { return LegacyLoadFailure.fromException( exception = toLegacyException(storeType, loginMode), storeType = storeType, exception = toLegacyException(authStore, loginMode), authStore = authStore, authError = this, loginMode = loginMode, ) } private fun AuthError.toLegacyException( storeType: StoreType, authStore: AuthStore, loginMode: PlayStoreLoginMode?, ): Exception { return when (this) { is AuthError.InvalidToken -> toValidationException(loginMode) is AuthError.NetworkFailure -> toNetworkException(storeType, loginMode) is AuthError.InvalidToken -> toInvalidTokenException(authStore, loginMode) is AuthError.NetworkFailure -> toNetworkException(authStore, loginMode) is AuthError.LoginRequired -> toLoginRequiredException(loginMode) is AuthError.RateLimited -> toStoreException(storeType) is AuthError.Unknown -> toStoreException(storeType) is AuthError.RateLimited -> toStoreException(authStore) is AuthError.Unknown -> toStoreException(authStore) } } private fun AuthError.toValidationException( private fun AuthError.InvalidToken.toInvalidTokenException( authStore: AuthStore, loginMode: PlayStoreLoginMode?, ): GPlayValidationException { val message = when (this) { is AuthError.InvalidToken -> message.orEmpty() else -> "" ): Exception { return when (authStore) { AuthStore.PLAY_STORE -> toValidationException(loginMode) AuthStore.OPEN_SOURCE -> CleanApkException(false, message) } } private fun AuthError.InvalidToken.toValidationException( loginMode: PlayStoreLoginMode?, ): GPlayValidationException { return GPlayValidationException( message = message, message = message.orEmpty(), loginMode = loginMode, networkCode = HttpURLConnection.HTTP_UNAUTHORIZED, ) } private fun AuthError.NetworkFailure.toNetworkException( storeType: StoreType, authStore: AuthStore, loginMode: PlayStoreLoginMode?, ): Exception { return when (storeType) { StoreType.PLAY_STORE -> GPlayLoginException(isTimeout, message, loginMode) StoreType.CLEAN_APK -> CleanApkException(isTimeout, message) return when (authStore) { AuthStore.PLAY_STORE -> GPlayLoginException(isTimeout, message, loginMode) AuthStore.OPEN_SOURCE -> CleanApkException(isTimeout, message) } } Loading @@ -177,27 +182,33 @@ private fun AuthError.LoginRequired.toLoginRequiredException( } } private fun AuthError.toStoreException(storeType: StoreType): Exception { private fun AuthError.toStoreException(authStore: AuthStore): Exception { val message = when (this) { is AuthError.RateLimited -> message is AuthError.Unknown -> message else -> null } return when (storeType) { StoreType.PLAY_STORE -> GPlayException(false, message) StoreType.CLEAN_APK -> CleanApkException(false, message) return when (authStore) { AuthStore.PLAY_STORE -> GPlayException(false, message) AuthStore.OPEN_SOURCE -> CleanApkException(false, message) } } private fun resolveKind( exception: Exception, storeType: StoreType?, authStore: AuthStore?, authError: AuthError?, ): LegacyLoadFailureKind { return when { authError is AuthError.RateLimited -> LegacyLoadFailureKind.RATE_LIMITED authError is AuthError.InvalidToken -> LegacyLoadFailureKind.SIGN_IN authError is AuthError.InvalidToken -> { if (authError.store == AuthStore.PLAY_STORE) { LegacyLoadFailureKind.SIGN_IN } else { LegacyLoadFailureKind.DATA_LOAD } } authError is AuthError.LoginRequired -> { if (authError.store == AuthStore.PLAY_STORE) { LegacyLoadFailureKind.SIGN_IN Loading @@ -208,7 +219,7 @@ private fun resolveKind( authError is AuthError.NetworkFailure -> { if (authError.isTimeout) { LegacyLoadFailureKind.TIMEOUT } else if (storeType == StoreType.PLAY_STORE) { } else if (authStore == AuthStore.PLAY_STORE) { LegacyLoadFailureKind.SIGN_IN } else { LegacyLoadFailureKind.DATA_LOAD Loading @@ -221,6 +232,13 @@ private fun resolveKind( } } private fun AuthStore.toStoreType(): StoreType { return when (this) { AuthStore.PLAY_STORE -> StoreType.PLAY_STORE AuthStore.OPEN_SOURCE -> StoreType.CLEAN_APK } } private fun resolveDialogSpec( exception: Exception, kind: LegacyLoadFailureKind, Loading