Loading app/src/main/java/foundation/e/apps/MainActivity.kt +37 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.LoginViewModel import foundation.e.apps.data.login.exceptions.GPlayValidationException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.install.updates.UpdatesNotifier import foundation.e.apps.ui.MainActivityViewModel Loading @@ -52,6 +53,7 @@ import foundation.e.apps.ui.setup.signin.SignInViewModel import foundation.e.apps.utils.SystemInfoProvider import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import javax.inject.Inject import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter Loading @@ -65,6 +67,11 @@ class MainActivity : AppCompatActivity() { private val TAG = MainActivity::class.java.simpleName private lateinit var viewModel: MainActivityViewModel private var isShowingDialog = false @Inject lateinit var preferenceManagerModule: PreferenceManagerModule override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Loading Loading @@ -207,6 +214,10 @@ class MainActivity : AppCompatActivity() { observeInvalidAuth() } launch { observeTooManyRequests() } launch { observeSignatureMissMatchError() } Loading Loading @@ -284,6 +295,32 @@ class MainActivity : AppCompatActivity() { } } private suspend fun observeTooManyRequests() { EventBus.events.filter { appEvent -> appEvent is AppEvent.TooManyRequests }.collectLatest { if (isShowingDialog) return@collectLatest ApplicationDialogFragment( title = getString(R.string.too_many_requests), message = getString(R.string.too_many_requests_desc), positiveButtonText = getString(R.string.ok), positiveButtonAction = { preferenceManagerModule.disableGplay() loginViewModel.startLoginFlow() }, cancelButtonText = getString(R.string.logout), cancelButtonAction = { loginViewModel.logout() }, cancellable = false, onDismissListener = { isShowingDialog = false }, ).show(supportFragmentManager, TAG) isShowingDialog = true } } private fun setupBottomNavItemSelectedListener( bottomNavigationView: BottomNavigationView, navHostFragment: NavHostFragment, Loading app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +8 −2 Original line number Diff line number Diff line Loading @@ -195,12 +195,18 @@ class GPlayHttpClient @Inject constructor( code = response.code Timber.d("$TAG: Url: ${response.request.url}\nStatus: $code") if (code == 401) { MainScope().launch { when (code) { 401 -> MainScope().launch { EventBus.invokeEvent( AppEvent.InvalidAuthEvent(AuthObject.GPlayAuth::class.java.simpleName) ) } 429 -> MainScope().launch { EventBus.invokeEvent( AppEvent.TooManyRequests() ) } } // TODO: exception will be thrown for all apis when all gplay api implementation Loading app/src/main/java/foundation/e/apps/data/login/LoginViewModel.kt +3 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import foundation.e.apps.data.enums.User import foundation.e.apps.ui.parentFragment.LoadingViewModel import kotlinx.coroutines.launch import javax.inject.Inject import okhttp3.Cache /** * ViewModel to handle all login related operations. Loading @@ -33,6 +34,7 @@ import javax.inject.Inject @HiltViewModel class LoginViewModel @Inject constructor( private val loginSourceRepository: LoginSourceRepository, private val cache: Cache, ) : ViewModel() { /** Loading Loading @@ -127,6 +129,7 @@ class LoginViewModel @Inject constructor( */ fun logout() { viewModelScope.launch { cache.evictAll() loginSourceRepository.logout() authObjects.postValue(listOf()) } Loading app/src/main/java/foundation/e/apps/data/preference/PreferenceManagerModule.kt +2 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,8 @@ class PreferenceManagerModule @Inject constructor( fun isPWASelected() = preferenceManager.getBoolean(PREFERENCE_SHOW_PWA, true) fun isGplaySelected() = preferenceManager.getBoolean(PREFERENCE_SHOW_GPLAY, true) fun disableGplay() = preferenceManager.edit().putBoolean(PREFERENCE_SHOW_GPLAY, false).apply() fun autoUpdatePreferred(): Boolean { return preferenceManager.getBoolean("updateInstallAuto", false) } Loading app/src/main/java/foundation/e/apps/ui/application/subFrags/ApplicationDialogFragment.kt +13 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package foundation.e.apps.ui.application.subFrags import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import android.text.Html import android.text.SpannableString Loading @@ -41,6 +42,8 @@ class ApplicationDialogFragment() : DialogFragment() { private var positiveButtonAction: (() -> Unit)? = null private var cancelButtonText: String? = null private var cancelButtonAction: (() -> Unit)? = null private var cancellable: Boolean = true private var onDismissListener: (() -> Unit)? = null constructor( drawable: Int = -1, Loading @@ -50,6 +53,8 @@ class ApplicationDialogFragment() : DialogFragment() { positiveButtonAction: (() -> Unit)? = null, cancelButtonText: String = "", cancelButtonAction: (() -> Unit)? = null, cancellable: Boolean = true, onDismissListener: (() -> Unit)? = null, ) : this() { this.drawable = drawable this.title = title Loading @@ -58,6 +63,8 @@ class ApplicationDialogFragment() : DialogFragment() { this.positiveButtonAction = positiveButtonAction this.cancelButtonText = cancelButtonText this.cancelButtonAction = cancelButtonAction this.cancellable = cancellable this.onDismissListener = onDismissListener } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { Loading @@ -70,6 +77,7 @@ class ApplicationDialogFragment() : DialogFragment() { positiveButtonAction?.invoke() this.dismiss() } .setCancelable(cancellable) if (cancelButtonText?.isNotEmpty() == true) { materialAlertDialogBuilder.setNegativeButton(cancelButtonText) { _, _ -> cancelButtonAction?.invoke() Loading @@ -91,6 +99,11 @@ class ApplicationDialogFragment() : DialogFragment() { } } override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) onDismissListener?.invoke() } private fun TextView.removeUnderlineFromLinks() { val spannable = SpannableString(text) for (urlSpan in spannable.getSpans(0, spannable.length, URLSpan::class.java)) { Loading Loading
app/src/main/java/foundation/e/apps/MainActivity.kt +37 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.login.AuthObject import foundation.e.apps.data.login.LoginViewModel import foundation.e.apps.data.login.exceptions.GPlayValidationException import foundation.e.apps.data.preference.PreferenceManagerModule import foundation.e.apps.databinding.ActivityMainBinding import foundation.e.apps.install.updates.UpdatesNotifier import foundation.e.apps.ui.MainActivityViewModel Loading @@ -52,6 +53,7 @@ import foundation.e.apps.ui.setup.signin.SignInViewModel import foundation.e.apps.utils.SystemInfoProvider import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import javax.inject.Inject import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter Loading @@ -65,6 +67,11 @@ class MainActivity : AppCompatActivity() { private val TAG = MainActivity::class.java.simpleName private lateinit var viewModel: MainActivityViewModel private var isShowingDialog = false @Inject lateinit var preferenceManagerModule: PreferenceManagerModule override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Loading Loading @@ -207,6 +214,10 @@ class MainActivity : AppCompatActivity() { observeInvalidAuth() } launch { observeTooManyRequests() } launch { observeSignatureMissMatchError() } Loading Loading @@ -284,6 +295,32 @@ class MainActivity : AppCompatActivity() { } } private suspend fun observeTooManyRequests() { EventBus.events.filter { appEvent -> appEvent is AppEvent.TooManyRequests }.collectLatest { if (isShowingDialog) return@collectLatest ApplicationDialogFragment( title = getString(R.string.too_many_requests), message = getString(R.string.too_many_requests_desc), positiveButtonText = getString(R.string.ok), positiveButtonAction = { preferenceManagerModule.disableGplay() loginViewModel.startLoginFlow() }, cancelButtonText = getString(R.string.logout), cancelButtonAction = { loginViewModel.logout() }, cancellable = false, onDismissListener = { isShowingDialog = false }, ).show(supportFragmentManager, TAG) isShowingDialog = true } } private fun setupBottomNavItemSelectedListener( bottomNavigationView: BottomNavigationView, navHostFragment: NavHostFragment, Loading
app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +8 −2 Original line number Diff line number Diff line Loading @@ -195,12 +195,18 @@ class GPlayHttpClient @Inject constructor( code = response.code Timber.d("$TAG: Url: ${response.request.url}\nStatus: $code") if (code == 401) { MainScope().launch { when (code) { 401 -> MainScope().launch { EventBus.invokeEvent( AppEvent.InvalidAuthEvent(AuthObject.GPlayAuth::class.java.simpleName) ) } 429 -> MainScope().launch { EventBus.invokeEvent( AppEvent.TooManyRequests() ) } } // TODO: exception will be thrown for all apis when all gplay api implementation Loading
app/src/main/java/foundation/e/apps/data/login/LoginViewModel.kt +3 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import foundation.e.apps.data.enums.User import foundation.e.apps.ui.parentFragment.LoadingViewModel import kotlinx.coroutines.launch import javax.inject.Inject import okhttp3.Cache /** * ViewModel to handle all login related operations. Loading @@ -33,6 +34,7 @@ import javax.inject.Inject @HiltViewModel class LoginViewModel @Inject constructor( private val loginSourceRepository: LoginSourceRepository, private val cache: Cache, ) : ViewModel() { /** Loading Loading @@ -127,6 +129,7 @@ class LoginViewModel @Inject constructor( */ fun logout() { viewModelScope.launch { cache.evictAll() loginSourceRepository.logout() authObjects.postValue(listOf()) } Loading
app/src/main/java/foundation/e/apps/data/preference/PreferenceManagerModule.kt +2 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,8 @@ class PreferenceManagerModule @Inject constructor( fun isPWASelected() = preferenceManager.getBoolean(PREFERENCE_SHOW_PWA, true) fun isGplaySelected() = preferenceManager.getBoolean(PREFERENCE_SHOW_GPLAY, true) fun disableGplay() = preferenceManager.edit().putBoolean(PREFERENCE_SHOW_GPLAY, false).apply() fun autoUpdatePreferred(): Boolean { return preferenceManager.getBoolean("updateInstallAuto", false) } Loading
app/src/main/java/foundation/e/apps/ui/application/subFrags/ApplicationDialogFragment.kt +13 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package foundation.e.apps.ui.application.subFrags import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import android.text.Html import android.text.SpannableString Loading @@ -41,6 +42,8 @@ class ApplicationDialogFragment() : DialogFragment() { private var positiveButtonAction: (() -> Unit)? = null private var cancelButtonText: String? = null private var cancelButtonAction: (() -> Unit)? = null private var cancellable: Boolean = true private var onDismissListener: (() -> Unit)? = null constructor( drawable: Int = -1, Loading @@ -50,6 +53,8 @@ class ApplicationDialogFragment() : DialogFragment() { positiveButtonAction: (() -> Unit)? = null, cancelButtonText: String = "", cancelButtonAction: (() -> Unit)? = null, cancellable: Boolean = true, onDismissListener: (() -> Unit)? = null, ) : this() { this.drawable = drawable this.title = title Loading @@ -58,6 +63,8 @@ class ApplicationDialogFragment() : DialogFragment() { this.positiveButtonAction = positiveButtonAction this.cancelButtonText = cancelButtonText this.cancelButtonAction = cancelButtonAction this.cancellable = cancellable this.onDismissListener = onDismissListener } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { Loading @@ -70,6 +77,7 @@ class ApplicationDialogFragment() : DialogFragment() { positiveButtonAction?.invoke() this.dismiss() } .setCancelable(cancellable) if (cancelButtonText?.isNotEmpty() == true) { materialAlertDialogBuilder.setNegativeButton(cancelButtonText) { _, _ -> cancelButtonAction?.invoke() Loading @@ -91,6 +99,11 @@ class ApplicationDialogFragment() : DialogFragment() { } } override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) onDismissListener?.invoke() } private fun TextView.removeUnderlineFromLinks() { val spannable = SpannableString(text) for (urlSpan in spannable.getSpans(0, spannable.length, URLSpan::class.java)) { Loading