diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml
index 1c47dd40dcc33a8fd69a95f4af2d2506e2aabbb8..8968baf74f8cfd197142ee194b0594f790ee78a6 100644
--- a/app/detekt-baseline.xml
+++ b/app/detekt-baseline.xml
@@ -12,12 +12,10 @@
LongParameterList:AppManagerImpl.kt$AppManagerImpl$( @Named("cacheDir") private val cacheDir: String, private val downloadManager: DownloadManager, private val notificationManager: NotificationManager, private val appInstallRepository: AppInstallRepository, private val pwaManager: PwaManager, private val appLoungePackageManager: AppLoungePackageManager, @Named("download") private val downloadNotificationChannel: NotificationChannel, @Named("update") private val updateNotificationChannel: NotificationChannel, @ApplicationContext private val context: Context )
LongParameterList:ApplicationDialogFragment.kt$ApplicationDialogFragment$( title: String, message: String, @DrawableRes drawableResId: Int = -1, drawable: Drawable? = null, positiveButtonText: String = "", positiveButtonAction: (() -> Unit)? = null, cancelButtonText: String = "", cancelButtonAction: (() -> Unit)? = null, cancelable: Boolean = true, onDismissListener: (() -> Unit)? = null, )
LongParameterList:ApplicationListRVAdapter.kt$ApplicationListRVAdapter$( private val applicationInstaller: ApplicationInstaller, private val privacyInfoViewModel: PrivacyInfoViewModel, private val appInfoFetchViewModel: AppInfoFetchViewModel, private val mainActivityViewModel: MainActivityViewModel, private val currentDestinationId: Int, private var lifecycleOwner: LifecycleOwner?, private var paidAppHandler: ((Application) -> Unit)? = null )
- LongParameterList:CleanApkRetrofit.kt$CleanApkRetrofit$( @Query("keyword") keyword: String, @Query("source") source: String = APP_SOURCE_FOSS, @Query("type") type: String = APP_TYPE_ANY, @Query("nres") nres: Int = 20, @Query("page") page: Int = 1, @Query("by") by: String? = null, )
LongParameterList:EglExtensionProvider.kt$EglExtensionProvider$( egl10: EGL10, eglDisplay: EGLDisplay, eglConfig: EGLConfig?, ai: IntArray, ai1: IntArray?, set: MutableSet<String> )
- LongParameterList:MainActivityViewModel.kt$MainActivityViewModel$( private val appLoungeDataStore: AppLoungeDataStore, private val applicationRepository: ApplicationRepository, private val appManagerWrapper: AppManagerWrapper, private val appLoungePackageManager: AppLoungePackageManager, private val pwaManager: PwaManager, private val ecloudRepository: EcloudRepository, private val blockedAppRepository: BlockedAppRepository, private val gPlayContentRatingRepository: GPlayContentRatingRepository, private val fDroidAntiFeatureRepository: FDroidAntiFeatureRepository, private val appInstallProcessor: AppInstallProcessor, private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, )
+ LongParameterList:MainActivityViewModel.kt$MainActivityViewModel$( private val appLoungeDataStore: AppLoungeDataStore, private val applicationRepository: ApplicationRepository, private val appManagerWrapper: AppManagerWrapper, private val appLoungePackageManager: AppLoungePackageManager, private val pwaManager: PwaManager, private val blockedAppRepository: BlockedAppRepository, private val gPlayContentRatingRepository: GPlayContentRatingRepository, private val fDroidAntiFeatureRepository: FDroidAntiFeatureRepository, private val appInstallProcessor: AppInstallProcessor, private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, private val reportFaultyTokenUseCase: ReportFaultyTokenUseCase, )
LongParameterList:UpdatesManagerImpl.kt$UpdatesManagerImpl$( @ApplicationContext private val context: Context, private val appLoungePackageManager: AppLoungePackageManager, private val applicationRepository: ApplicationRepository, private val faultyAppRepository: FaultyAppRepository, private val appLoungePreference: AppLoungePreference, private val fDroidRepository: FDroidRepository, private val blockedAppRepository: BlockedAppRepository, private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, )
LongParameterList:UpdatesWorker.kt$UpdatesWorker$( @Assisted private val context: Context, @Assisted private val params: WorkerParameters, private val updatesManagerRepository: UpdatesManagerRepository, private val appLoungeDataStore: AppLoungeDataStore, private val authenticatorRepository: AuthenticatorRepository, private val appInstallProcessor: AppInstallProcessor, private val blockedAppRepository: BlockedAppRepository, private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, )
- NoWildcardImports:SystemAppsUpdatesRepository.kt$import foundation.e.apps.data.gitlab.UpdatableSystemAppsApi.*
ProtectedMemberInFinalClass:ApplicationListFragment.kt$ApplicationListFragment$// protected to avoid SyntheticAccessor protected val args: ApplicationListFragmentArgs by navArgs()
ProtectedMemberInFinalClass:ApplicationListFragment.kt$ApplicationListFragment$// protected to avoid SyntheticAccessor protected val viewModel: ApplicationListViewModel by viewModels()
ProtectedMemberInFinalClass:GoogleSignInFragment.kt$GoogleSignInFragment$// protected to avoid SyntheticAccessor protected val viewModel: LoginViewModel by lazy { ViewModelProvider(requireActivity())[LoginViewModel::class.java] }
@@ -32,8 +30,6 @@
ReturnCount:DownloadManager.kt$DownloadManager$fun getSizeRequired(downloadId: Long): Long
ReturnCount:DownloadManager.kt$DownloadManager$private fun sanitizeStatus(downloadId: Long, status: Int, reason: Int): Int
ReturnCount:Extensions.kt$fun Context.isNetworkAvailable(): Boolean
- ReturnCount:PlayStoreAuthenticator.kt$PlayStoreAuthenticator$override suspend fun validateAuthData(): ResultSupreme<AuthData?>
- ReturnCount:PlayStoreAuthenticator.kt$PlayStoreAuthenticator$private suspend fun getAuthDataWithGoogleAccount(): ResultSupreme<AuthData?>
ReturnCount:PrivacyInfoViewModel.kt$PrivacyInfoViewModel$fun shouldRequestExodusReport(application: Application?): Boolean
ReturnCount:StorageNotificationManager.kt$StorageNotificationManager$private fun getSpaceMissing(appInstall: AppInstall, downloadId: Long? = null): Long
ReturnCount:SystemAppsUpdatesRepository.kt$SystemAppsUpdatesRepository$private suspend fun getApplication( packageName: String, releaseType: OsReleaseType, sdkLevel: Int, device: String, ): Application?
@@ -52,11 +48,9 @@
SwallowedException:ApplicationViewModel.kt$ApplicationViewModel$e: Exception
SwallowedException:ApplicationViewModel.kt$ApplicationViewModel$e: InternalException.AppNotFound
SwallowedException:GPlayHttpClient.kt$GPlayHttpClient$e: Exception
- SwallowedException:NativeDeviceInfoProviderModule.kt$NativeDeviceInfoProviderModule$e: Exception
SwallowedException:NativeGsfVersionProvider.kt$NativeGsfVersionProvider$e: PackageManager.NameNotFoundException
SwallowedException:UpdatesManagerImpl.kt$UpdatesManagerImpl$e: Exception
TooGenericExceptionCaught:AgeRatingProvider.kt$AgeRatingProvider$e: Exception
- TooGenericExceptionCaught:AnonymousLoginManager.kt$AnonymousLoginManager$e: Exception
TooGenericExceptionCaught:ApiCaller.kt$e: Exception
TooGenericExceptionCaught:ApkSignatureManager.kt$ApkSignatureManager$e: Exception
TooGenericExceptionCaught:AppInfoFetchViewModel.kt$AppInfoFetchViewModel$e: Exception
@@ -74,12 +68,10 @@
TooGenericExceptionCaught:EcloudRepository.kt$EcloudRepository$e: Exception
TooGenericExceptionCaught:FileManager.kt$FileManager$e: Exception
TooGenericExceptionCaught:GPlayHttpClient.kt$GPlayHttpClient$e: Exception
- TooGenericExceptionCaught:GoogleLoginManager.kt$GoogleLoginManager$e: Exception
TooGenericExceptionCaught:InstallWorkManager.kt$InstallWorkManager$e: Exception
TooGenericExceptionCaught:LocaleChangedBroadcastReceiver.kt$LocaleChangedBroadcastReceiver$ex: Exception
TooGenericExceptionCaught:NativeDeviceInfoProviderModule.kt$NativeDeviceInfoProviderModule$e: Exception
TooGenericExceptionCaught:NetworkHandler.kt$e: Exception
- TooGenericExceptionCaught:PlayStoreAuthenticator.kt$PlayStoreAuthenticator$e: Exception
TooGenericExceptionCaught:PlayStoreRepository.kt$PlayStoreRepository$exception: Exception
TooGenericExceptionCaught:PwaManager.kt$PwaManager$e: Exception
TooGenericExceptionCaught:PwaPlayerStatusReceiver.kt$PwaPlayerStatusReceiver$e: Exception
@@ -87,8 +79,6 @@
TooGenericExceptionCaught:UpdatesManagerImpl.kt$UpdatesManagerImpl$e: Exception
TooGenericExceptionCaught:UpdatesWorker.kt$UpdatesWorker$e: Throwable
TooGenericExceptionThrown:AnonymousLoginManager.kt$AnonymousLoginManager$throw Exception( "Error fetching Anonymous credentials\n" + "Network code: ${response.code}\n" + "Success: ${response.isSuccessful}" + response.errorString.run { if (isNotBlank()) "\nError message: $this" else "" } )
- TooGenericExceptionThrown:PlayStoreLoginWrapper.kt$PlayStoreLoginWrapper$throw Exception("Validation network code: ${response.code}")
- TooGenericExceptionThrown:PlayStoreLoginWrapper.kt$PlayStoreLoginWrapper$throw Exception(error)
TooManyFunctions:AppLoungePackageManager.kt$AppLoungePackageManager
TooManyFunctions:AppManager.kt$AppManager
TooManyFunctions:AppManagerImpl.kt$AppManagerImpl : AppManager
diff --git a/app/src/main/java/foundation/e/apps/domain/login/ReportFaultyTokenUseCase.kt b/app/src/main/java/foundation/e/apps/domain/login/ReportFaultyTokenUseCase.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8b6d49f68d5afe815e40cf0c402bebb7f767a2e2
--- /dev/null
+++ b/app/src/main/java/foundation/e/apps/domain/login/ReportFaultyTokenUseCase.kt
@@ -0,0 +1,39 @@
+package foundation.e.apps.domain.login
+
+import foundation.e.apps.data.ecloud.EcloudRepository
+import foundation.e.apps.data.login.core.AuthObject
+import foundation.e.apps.data.login.exceptions.GPlayValidationException
+import foundation.e.apps.utils.SystemInfoProvider
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+import javax.inject.Inject
+
+class ReportFaultyTokenUseCase @Inject constructor(
+ private val ecloudRepository: EcloudRepository
+) {
+ suspend operator fun invoke(authObjects: List) {
+ val gPlayAuthObject = authObjects.firstOrNull { it is AuthObject.GPlayAuth } as? AuthObject.GPlayAuth
+ if (gPlayAuthObject == null) {
+ return
+ }
+
+ val result = gPlayAuthObject.result
+ val exception = result.exception
+ val shouldUploadFaultyToken = exception is GPlayValidationException
+
+ if (shouldUploadFaultyToken) {
+ val email = result.otherPayload.toString()
+ val buildInfo = SystemInfoProvider.getAppBuildInfo()
+ withContext(Dispatchers.IO) {
+ ecloudRepository.uploadFaultyEmail(email, buildInfo)
+ }
+ }
+
+ if (!shouldUploadFaultyToken) {
+ exception?.let {
+ Timber.e(it, "Login failed! message: ${it.localizedMessage}")
+ }
+ }
+ }
+}
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 a78392e8b22d16cba10782a30f8a45a091072d66..f0fd66815ac6696c9abe2c7524edf96877ec9aba 100644
--- a/app/src/main/java/foundation/e/apps/ui/MainActivity.kt
+++ b/app/src/main/java/foundation/e/apps/ui/MainActivity.kt
@@ -39,7 +39,6 @@ import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.NavigationUI
import androidx.navigation.ui.setupWithNavController
-import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.exceptions.InternalException
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.snackbar.Snackbar
@@ -50,9 +49,7 @@ import foundation.e.apps.contract.ParentalControlContract.COLUMN_LOGIN_TYPE
import foundation.e.apps.data.Constants
import foundation.e.apps.data.enums.User
import foundation.e.apps.data.install.models.AppInstall
-import foundation.e.apps.data.login.core.AuthObject
import foundation.e.apps.data.login.core.StoreType
-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
@@ -61,7 +58,6 @@ import foundation.e.apps.ui.purchase.AppPurchaseFragmentDirections
import foundation.e.apps.ui.settings.SettingsFragment
import foundation.e.apps.ui.setup.signin.SignInViewModel
import foundation.e.apps.utils.ParentalControlAuthenticator
-import foundation.e.apps.utils.SystemInfoProvider
import foundation.e.apps.utils.eventBus.AppEvent
import foundation.e.apps.utils.eventBus.EventBus
import kotlinx.coroutines.Dispatchers
@@ -378,41 +374,22 @@ class MainActivity : AppCompatActivity() {
}
private fun observeAuthObjects(navController: NavController) {
- loginViewModel.authObjects.distinctUntilChanged().observe(this) {
- when {
- it == null -> return@observe
- it.isEmpty() -> {
- // No auth type defined means user has not logged in yet
- // Pop back stack to prevent showing TOSFragment on pressing back button.
- navController.popBackStack()
- navController.navigate(R.id.signInFragment)
- if (viewModel.gPlayLoginRequested) viewModel.closeAfterLogin = true
- return@observe
- }
-
- else -> {}
+ viewModel.uiState.distinctUntilChanged().observe(this) { state ->
+ if (state.navigateToSignIn) {
+ navController.popBackStack()
+ navController.navigate(R.id.signInFragment)
+ viewModel.onNavigateToSignInHandled()
}
- val gPlayAuthObject = it.find { it is AuthObject.GPlayAuth }
-
- gPlayAuthObject?.result?.run {
- if (isSuccess()) {
- viewModel.gPlayAuthData = data as AuthData
- } else if (exception is GPlayValidationException) {
- val email = otherPayload.toString()
- viewModel.uploadFaultyTokenToEcloud(
- email,
- SystemInfoProvider.getAppBuildInfo()
- )
- } else if (exception != null) {
- Timber.e(exception, "Login failed! message: ${exception?.localizedMessage}")
- }
- }
-
- if (viewModel.closeAfterLogin && it.isNotEmpty() && it.all { it.result.isSuccess() }) {
+ if (state.finishAfterLogin) {
+ viewModel.onFinishAfterLoginHandled()
finishAndRemoveTask()
}
}
+
+ loginViewModel.authObjects.distinctUntilChanged().observe(this) {
+ viewModel.handleAuthObjects(it)
+ }
}
private suspend fun observeSuccessfulLogin() {
diff --git a/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt b/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt
index dce959d2d8bab32cc0c17925d3ee3d2e65f46819..399eeb87f793ecfd57ab54ed30126975c8485f86 100644
--- a/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt
+++ b/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt
@@ -20,31 +20,30 @@ package foundation.e.apps.ui
import android.content.Context
import android.content.Intent
-import android.net.ConnectivityManager
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
-import com.aurora.gplayapi.data.models.AuthData
import dagger.hilt.android.lifecycle.HiltViewModel
import foundation.e.apps.R
import foundation.e.apps.data.application.ApplicationRepository
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.blockedApps.BlockedAppRepository
-import foundation.e.apps.data.ecloud.EcloudRepository
-import foundation.e.apps.data.enums.User
-import foundation.e.apps.data.enums.isInitialized
-import foundation.e.apps.data.enums.isUnFiltered
-import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository
-import foundation.e.apps.data.install.AppManagerWrapper
-import foundation.e.apps.data.install.models.AppInstall
-import foundation.e.apps.data.login.state.LoginState
-import foundation.e.apps.data.parentalcontrol.fdroid.FDroidAntiFeatureRepository
-import foundation.e.apps.data.parentalcontrol.googleplay.GPlayContentRatingRepository
-import foundation.e.apps.data.preference.AppLoungeDataStore
-import foundation.e.apps.data.preference.getSync
+import foundation.e.apps.data.enums.User
+import foundation.e.apps.data.enums.isInitialized
+import foundation.e.apps.data.enums.isUnFiltered
+import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository
+import foundation.e.apps.data.install.AppManagerWrapper
+import foundation.e.apps.data.install.models.AppInstall
+import foundation.e.apps.data.login.core.AuthObject
+import foundation.e.apps.data.login.state.LoginState
+import foundation.e.apps.data.parentalcontrol.fdroid.FDroidAntiFeatureRepository
+import foundation.e.apps.data.parentalcontrol.googleplay.GPlayContentRatingRepository
+import foundation.e.apps.data.preference.AppLoungeDataStore
+import foundation.e.apps.data.preference.getSync
+import foundation.e.apps.domain.login.ReportFaultyTokenUseCase
import foundation.e.apps.install.pkg.AppLoungePackageManager
import foundation.e.apps.install.pkg.PwaManager
import foundation.e.apps.install.workmanager.AppInstallProcessor
@@ -60,13 +59,13 @@ class MainActivityViewModel @Inject constructor(
private val appManagerWrapper: AppManagerWrapper,
private val appLoungePackageManager: AppLoungePackageManager,
private val pwaManager: PwaManager,
- private val ecloudRepository: EcloudRepository,
private val blockedAppRepository: BlockedAppRepository,
private val gPlayContentRatingRepository: GPlayContentRatingRepository,
private val fDroidAntiFeatureRepository: FDroidAntiFeatureRepository,
private val appInstallProcessor: AppInstallProcessor,
private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository,
-) : ViewModel() {
+ private val reportFaultyTokenUseCase: ReportFaultyTokenUseCase,
+) : ViewModel() {
init {
updateAppWarningList()
@@ -82,8 +81,6 @@ class MainActivityViewModel @Inject constructor(
val purchaseDeclined: MutableLiveData = MutableLiveData()
lateinit var internetConnection: LiveData
- var gPlayAuthData = AuthData("", "")
-
// Downloads
val downloadList = appManagerWrapper.getDownloadLiveList()
private val _errorMessage = MutableLiveData()
@@ -92,33 +89,78 @@ class MainActivityViewModel @Inject constructor(
private val _errorMessageStringResource = MutableLiveData()
val errorMessageStringResource: LiveData = _errorMessageStringResource
+ data class MainUiState(
+ val navigateToSignIn: Boolean = false,
+ val finishAfterLogin: Boolean = false
+ )
+
+ private val _uiState = MutableLiveData(MainUiState())
+ val uiState: LiveData = _uiState
+
+ private val initialUiState = MainUiState()
+
var gPlayLoginRequested = false
var closeAfterLogin = false
- lateinit var connectivityManager: ConnectivityManager
-
var shouldIgnoreSessionError = false
fun getTocStatus(): Boolean {
return appLoungeDataStore.tocStatus.getSync()
}
- fun getUser(): User {
- return appLoungeDataStore.getUser()
- }
-
- fun getLoginState(): LoginState {
- return appLoungeDataStore.getLoginState()
- }
+ fun getUser(): User {
+ return appLoungeDataStore.getUser()
+ }
- fun getUserEmail(): String {
- return appLoungeDataStore.emailData.getSync()
+ fun getLoginState(): LoginState {
+ return appLoungeDataStore.getLoginState()
}
- fun uploadFaultyTokenToEcloud(email: String, description: String = "") {
- viewModelScope.launch {
- ecloudRepository.uploadFaultyEmail(email, description)
+ fun handleAuthObjects(authObjects: List?) {
+ if (authObjects == null) {
+ return
+ }
+
+ if (authObjects.isEmpty()) {
+ handleEmptyAuthObjects()
+ return
+ }
+
+ val shouldFinishAfterLogin = shouldFinishAfterLogin(authObjects)
+ val user = getUser()
+ if (user == User.ANONYMOUS) {
+ viewModelScope.launch {
+ reportFaultyTokenUseCase(authObjects)
+ }
+ }
+
+ if (shouldFinishAfterLogin) {
+ _uiState.value = _uiState.value?.copy(finishAfterLogin = true)
+ ?: initialUiState.copy(finishAfterLogin = true)
+ }
+ }
+
+ fun onNavigateToSignInHandled() {
+ _uiState.value = _uiState.value?.copy(navigateToSignIn = false)
+ ?: initialUiState
+ }
+
+ fun onFinishAfterLoginHandled() {
+ _uiState.value = _uiState.value?.copy(finishAfterLogin = false)
+ ?: initialUiState
+ }
+
+ private fun handleEmptyAuthObjects() {
+ if (gPlayLoginRequested) {
+ closeAfterLogin = true
}
+
+ _uiState.value = _uiState.value?.copy(navigateToSignIn = true)
+ ?: initialUiState.copy(navigateToSignIn = true)
+ }
+
+ private fun shouldFinishAfterLogin(authObjects: List): Boolean {
+ return closeAfterLogin && authObjects.all { it.result.isSuccess() }
}
/*
@@ -140,10 +182,12 @@ class MainActivityViewModel @Inject constructor(
* Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/266
*/
fun shouldShowPaidAppsSnackBar(app: Application): Boolean {
- if (!app.isFree && gPlayAuthData.isAnonymous) {
+ val authData = appLoungeDataStore.getAuthData()
+ if (!app.isFree && authData.isAnonymous) {
_errorMessageStringResource.value = R.string.paid_app_anonymous_message
return true
}
+
return false
}
@@ -205,12 +249,12 @@ class MainActivityViewModel @Inject constructor(
suspend fun updateAwaitingForPurchasedApp(packageName: String): AppInstall? {
val fusedDownload = appManagerWrapper.getFusedDownload(packageName = packageName)
- gPlayAuthData.let {
- if (!it.isAnonymous) {
- appInstallProcessor.enqueueFusedDownload(fusedDownload)
- return fusedDownload
- }
+ val authData = appLoungeDataStore.getAuthData()
+ if (!authData.isAnonymous) {
+ appInstallProcessor.enqueueFusedDownload(fusedDownload)
+ return fusedDownload
}
+
return null
}
@@ -233,17 +277,17 @@ class MainActivityViewModel @Inject constructor(
fun updateStatusOfFusedApps(
applicationList: List,
- appInstallList: List
- ) {
- applicationList.forEach {
- val downloadingItem = appInstallList.find { fusedDownload ->
- fusedDownload.source == it.source &&
- (fusedDownload.packageName == it.package_name || fusedDownload.id == it._id)
- }
- it.status =
- downloadingItem?.status ?: applicationRepository.getFusedAppInstallationStatus(it)
- }
- }
+ appInstallList: List
+ ) {
+ applicationList.forEach {
+ val downloadingItem = appInstallList.find { fusedDownload ->
+ fusedDownload.source == it.source &&
+ (fusedDownload.packageName == it.package_name || fusedDownload.id == it._id)
+ }
+ it.status =
+ downloadingItem?.status ?: applicationRepository.getFusedAppInstallationStatus(it)
+ }
+ }
fun updateAppWarningList() {
viewModelScope.launch {
diff --git a/app/src/main/java/foundation/e/apps/ui/settings/SettingsFragment.kt b/app/src/main/java/foundation/e/apps/ui/settings/SettingsFragment.kt
index 394d2824a782de1b3fe973c16e68fbaf37b67801..954fdb4fd01f004186ad2bd7be38aabd886c1c83 100644
--- a/app/src/main/java/foundation/e/apps/ui/settings/SettingsFragment.kt
+++ b/app/src/main/java/foundation/e/apps/ui/settings/SettingsFragment.kt
@@ -26,7 +26,6 @@ import android.view.View
import android.widget.Toast
import androidx.core.net.toUri
import androidx.core.view.isVisible
-import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.findNavController
import androidx.preference.CheckBoxPreference
@@ -46,10 +45,11 @@ import foundation.e.apps.data.Stores
import foundation.e.apps.data.application.UpdatesDao
import foundation.e.apps.data.enums.Source
import foundation.e.apps.data.enums.User
+import foundation.e.apps.data.preference.AppLoungeDataStore
+import foundation.e.apps.data.preference.getSync
import foundation.e.apps.databinding.CustomPreferenceBinding
import foundation.e.apps.install.updates.UpdatesWorkManager
import foundation.e.apps.ui.LoginViewModel
-import foundation.e.apps.ui.MainActivityViewModel
import foundation.e.apps.utils.SystemInfoProvider
import timber.log.Timber
import java.util.Locale
@@ -59,7 +59,6 @@ import javax.inject.Inject
class SettingsFragment : PreferenceFragmentCompat() {
private var _binding: CustomPreferenceBinding? = null
private val binding get() = _binding!!
- private val mainActivityViewModel: MainActivityViewModel by activityViewModels()
private var showAllApplications: CheckBoxPreference? = null
private var showFOSSApplications: CheckBoxPreference? = null
private var showPWAApplications: CheckBoxPreference? = null
@@ -77,8 +76,11 @@ class SettingsFragment : PreferenceFragmentCompat() {
@Inject
lateinit var clipboardManager: ClipboardManager
+ @Inject
+ lateinit var appLoungeDataStore: AppLoungeDataStore
+
private val user by lazy {
- mainActivityViewModel.getUser()
+ appLoungeDataStore.getUser()
}
private val allSourceCheckboxes by lazy {
@@ -96,8 +98,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
val updateCheckInterval =
preferenceManager.findPreference(getString(R.string.update_check_intervals))
+
val updateCheckIntervalAnonymous =
preferenceManager.findPreference(getString(R.string.update_check_intervals_anonymous))
+
val updateChangeListener = { _: Preference, newValue: Any ->
Timber.d("onCreatePreferences: updated Value: $newValue")
context?.let {
@@ -109,6 +113,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
true
}
+
updateCheckInterval?.setOnPreferenceChangeListener(updateChangeListener)
updateCheckIntervalAnonymous?.setOnPreferenceChangeListener(updateChangeListener)
configureUpdatePreferencesForUser(updateCheckInterval, updateCheckIntervalAnonymous)
@@ -129,6 +134,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
appVersionLabel,
contents
)
+
Toast.makeText(context, R.string.copied, Toast.LENGTH_SHORT).show()
true
@@ -188,8 +194,8 @@ class SettingsFragment : PreferenceFragmentCompat() {
// This is useful if a user from older App Lounge updates to this version
disableDependentCheckbox(onlyUnmeteredNetwork, autoInstallUpdate)
- mainActivityViewModel.gPlayAuthData.let { authData ->
- mainActivityViewModel.getUser().name.let { user ->
+ appLoungeDataStore.getAuthData().let { authData ->
+ appLoungeDataStore.getUser().name.let { user ->
handleUser(user, authData)
}
}
@@ -248,7 +254,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
User.GOOGLE.name -> {
if (!authData.isAnonymous) {
binding.accountType.text = authData.userProfile?.name
- binding.email.text = mainActivityViewModel.getUserEmail()
+ binding.email.text = appLoungeDataStore.emailData.getSync()
binding.avatar.load(authData.userProfile?.artwork?.url)
}
}
diff --git a/app/src/test/java/foundation/e/apps/domain/login/ReportFaultyTokenUseCaseTest.kt b/app/src/test/java/foundation/e/apps/domain/login/ReportFaultyTokenUseCaseTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f690fc2531e51b7122d9e6171acd95c9217d9ae8
--- /dev/null
+++ b/app/src/test/java/foundation/e/apps/domain/login/ReportFaultyTokenUseCaseTest.kt
@@ -0,0 +1,64 @@
+package foundation.e.apps.domain.login
+
+import com.aurora.gplayapi.data.models.AuthData
+import foundation.e.apps.data.ResultSupreme
+import foundation.e.apps.data.enums.User
+import foundation.e.apps.data.login.core.AuthObject
+import foundation.e.apps.data.login.exceptions.GPlayValidationException
+import foundation.e.apps.data.ecloud.EcloudRepository
+import foundation.e.apps.utils.SystemInfoProvider
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.mockk
+import io.mockk.mockkObject
+import io.mockk.unmockkObject
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Test
+
+class ReportFaultyTokenUseCaseTest {
+
+ private val ecloudRepository = mockk(relaxed = true)
+ private val reportFaultyTokenUseCase = ReportFaultyTokenUseCase(ecloudRepository)
+
+ @After
+ fun tearDown() {
+ unmockkObject(SystemInfoProvider)
+ }
+
+ @Test
+ fun handle_Gplay_returnsNullWhenNoGPlayAuthObject() = runTest {
+ val authObjects = listOf(
+ AuthObject.CleanApk(ResultSupreme.Success(Unit), User.ANONYMOUS)
+ )
+
+ reportFaultyTokenUseCase(authObjects)
+ }
+
+ @Test
+ fun handle_Gplay_returnsAuthDataOnSuccess() = runTest {
+ val authData = AuthData("email")
+ val authObjects = listOf(
+ AuthObject.GPlayAuth(ResultSupreme.Success(authData), User.GOOGLE)
+ )
+
+ reportFaultyTokenUseCase(authObjects)
+ coVerify(exactly = 0) { ecloudRepository.uploadFaultyEmail(any(), any()) }
+ }
+
+ @Test
+ fun handle_Gplay_uploadsFaultyTokenForAnonymousUser() = runTest {
+ mockkObject(SystemInfoProvider)
+ coEvery { ecloudRepository.uploadFaultyEmail("user@gmail.com", "build") } returns Unit
+ coEvery { SystemInfoProvider.getAppBuildInfo() } returns "build"
+ val exception = GPlayValidationException("invalid", User.ANONYMOUS, 401)
+ val result = ResultSupreme.Error("invalid", exception)
+ result.otherPayload = "user@gmail.com"
+ val authObjects = listOf(
+ AuthObject.GPlayAuth(result, User.ANONYMOUS)
+ )
+
+ reportFaultyTokenUseCase(authObjects)
+ coVerify(exactly = 1) { ecloudRepository.uploadFaultyEmail("user@gmail.com", "build") }
+ }
+}